diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c67b59fa..3b25121b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -82,6 +82,12 @@
android:label="@string/speed_dial"
android:parentActivityName=".activities.SettingsActivity" />
+
+
diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt
index 9c18bde5..a7e39db9 100644
--- a/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt
@@ -18,14 +18,13 @@ import android.view.MotionEvent
import android.view.WindowManager
import android.widget.ImageView
import com.simplemobiletools.commons.extensions.*
-import com.simplemobiletools.commons.helpers.*
+import com.simplemobiletools.commons.helpers.LOWER_ALPHA
+import com.simplemobiletools.commons.helpers.MINUTE_SECONDS
+import com.simplemobiletools.commons.helpers.isOreoMr1Plus
+import com.simplemobiletools.commons.helpers.isOreoPlus
import com.simplemobiletools.dialer.R
-import com.simplemobiletools.dialer.extensions.addCharacter
-import com.simplemobiletools.dialer.extensions.audioManager
-import com.simplemobiletools.dialer.extensions.config
-import com.simplemobiletools.dialer.extensions.getHandleToUse
-import com.simplemobiletools.dialer.helpers.CallContactAvatarHelper
-import com.simplemobiletools.dialer.helpers.CallManager
+import com.simplemobiletools.dialer.extensions.*
+import com.simplemobiletools.dialer.helpers.*
import com.simplemobiletools.dialer.models.CallContact
import kotlinx.android.synthetic.main.activity_call.*
import kotlinx.android.synthetic.main.dialpad.*
@@ -34,7 +33,7 @@ class CallActivity : SimpleActivity() {
companion object {
fun getStartIntent(context: Context): Intent {
val openAppIntent = Intent(context, CallActivity::class.java)
- openAppIntent.flags = Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT or Intent.FLAG_ACTIVITY_NEW_TASK
+ openAppIntent.flags = Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
return openAppIntent
}
}
@@ -55,29 +54,36 @@ class CallActivity : SimpleActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_call)
+ if (CallManager.getPhoneState() == NoCall) {
+ finish()
+ return
+ }
+
updateTextColors(call_holder)
initButtons()
audioManager.mode = AudioManager.MODE_IN_CALL
- CallManager.getCallContact(applicationContext) { contact ->
- callContact = contact
- val avatar = callContactAvatarHelper.getCallContactAvatar(contact)
- runOnUiThread {
- updateOtherPersonsInfo(avatar)
- checkCalledSIMCard()
- }
- }
-
addLockScreenFlags()
- CallManager.registerCallback(callCallback)
- updateCallState(CallManager.getState())
+ CallManager.addListener(callCallback)
+
+ updateCallContactInfo(CallManager.getPrimaryCall())
+ }
+
+ override fun onNewIntent(intent: Intent?) {
+ super.onNewIntent(intent)
+ updateState()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ updateState()
}
override fun onDestroy() {
super.onDestroy()
- CallManager.unregisterCallback(callCallback)
+ CallManager.removeListener(callCallback)
disableProximitySensor()
}
@@ -133,6 +139,25 @@ class CallActivity : SimpleActivity() {
toggleHold()
}
+ call_add.setOnClickListener {
+ Intent(applicationContext, DialpadActivity::class.java).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
+ startActivity(this)
+ }
+ }
+
+ call_swap.setOnClickListener {
+ CallManager.swap()
+ }
+
+ call_merge.setOnClickListener {
+ CallManager.merge()
+ }
+
+ call_manage.setOnClickListener {
+ startActivity(Intent(this, ConferenceActivity::class.java))
+ }
+
call_end.setOnClickListener {
endCall()
}
@@ -153,7 +178,10 @@ class CallActivity : SimpleActivity() {
dialpad_hashtag_holder.setOnClickListener { dialpadPressed('#') }
dialpad_wrapper.setBackgroundColor(getProperBackgroundColor())
- arrayOf(call_toggle_microphone, call_toggle_speaker, call_dialpad, dialpad_close, call_sim_image).forEach {
+ arrayOf(
+ call_toggle_microphone, call_toggle_speaker, call_dialpad, dialpad_close,
+ call_sim_image, call_toggle_hold, call_add, call_swap, call_merge, call_manage
+ ).forEach {
it.applyColorFilter(getProperTextColor())
}
@@ -334,6 +362,16 @@ class CallActivity : SimpleActivity() {
if (avatar != null) {
caller_avatar.setImageBitmap(avatar)
+ } else {
+ caller_avatar.setImageDrawable(null)
+ }
+ }
+
+ private fun getContactNameOrNumber(contact: CallContact): String {
+ return contact.name.ifEmpty {
+ contact.number.ifEmpty {
+ getString(R.string.unknown_caller)
+ }
}
}
@@ -343,7 +381,7 @@ class CallActivity : SimpleActivity() {
val accounts = telecomManager.callCapablePhoneAccounts
if (accounts.size > 1) {
accounts.forEachIndexed { index, account ->
- if (account == CallManager.call?.details?.accountHandle) {
+ if (account == CallManager.getPrimaryCall()?.details?.accountHandle) {
call_sim_id.text = "${index + 1}"
call_sim_id.beVisible()
call_sim_image.beVisible()
@@ -365,7 +403,8 @@ class CallActivity : SimpleActivity() {
}
}
- private fun updateCallState(state: Int) {
+ private fun updateCallState(call: Call) {
+ val state = call.getStateCompat()
when (state) {
Call.STATE_RINGING -> callRinging()
Call.STATE_ACTIVE -> callStarted()
@@ -376,7 +415,7 @@ class CallActivity : SimpleActivity() {
val statusTextId = when (state) {
Call.STATE_RINGING -> R.string.is_calling
- Call.STATE_DIALING -> R.string.dialing
+ Call.STATE_CONNECTING, Call.STATE_DIALING -> R.string.dialing
else -> 0
}
@@ -384,9 +423,53 @@ class CallActivity : SimpleActivity() {
call_status_label.text = getString(statusTextId)
}
- val isActiveCall = state == Call.STATE_ACTIVE || state == Call.STATE_HOLDING
- call_toggle_hold.isEnabled = isActiveCall
- call_toggle_hold.alpha = if (isActiveCall) 1.0f else LOWER_ALPHA
+ call_manage.beVisibleIf(call.hasCapability(Call.Details.CAPABILITY_MANAGE_CONFERENCE))
+ setActionButtonEnabled(call_swap, state == Call.STATE_ACTIVE)
+ setActionButtonEnabled(call_merge, state == Call.STATE_ACTIVE)
+ }
+
+ private fun updateState() {
+ val phoneState = CallManager.getPhoneState()
+ if (phoneState is SingleCall) {
+ updateCallState(phoneState.call)
+ updateCallOnHoldState(null)
+ val state = phoneState.call.getStateCompat()
+ val isSingleCallActionsEnabled = (state == Call.STATE_ACTIVE || state == Call.STATE_DISCONNECTED
+ || state == Call.STATE_DISCONNECTING || state == Call.STATE_HOLDING)
+ setActionButtonEnabled(call_toggle_hold, isSingleCallActionsEnabled)
+ setActionButtonEnabled(call_add, isSingleCallActionsEnabled)
+ } else if (phoneState is TwoCalls) {
+ updateCallState(phoneState.active)
+ updateCallOnHoldState(phoneState.onHold)
+ }
+ }
+
+ private fun updateCallOnHoldState(call: Call?) {
+ val hasCallOnHold = call != null
+ if (hasCallOnHold) {
+ getCallContact(applicationContext, call) { contact ->
+ runOnUiThread {
+ on_hold_caller_name.text = getContactNameOrNumber(contact)
+ }
+ }
+ }
+ on_hold_status_holder.beVisibleIf(hasCallOnHold)
+ controls_single_call.beVisibleIf(!hasCallOnHold)
+ controls_two_calls.beVisibleIf(hasCallOnHold)
+ }
+
+ private fun updateCallContactInfo(call: Call?) {
+ getCallContact(applicationContext, call) { contact ->
+ if (call != CallManager.getPrimaryCall()) {
+ return@getCallContact
+ }
+ callContact = contact
+ val avatar = if (!call.isConference()) callContactAvatarHelper.getCallContactAvatar(contact) else null
+ runOnUiThread {
+ updateOtherPersonsInfo(avatar)
+ checkCalledSIMCard()
+ }
+ }
}
private fun acceptCall() {
@@ -407,13 +490,14 @@ class CallActivity : SimpleActivity() {
enableProximitySensor()
incoming_call_holder.beGone()
ongoing_call_holder.beVisible()
+ callDurationHandler.removeCallbacks(updateCallDurationTask)
callDurationHandler.post(updateCallDurationTask)
}
private fun showPhoneAccountPicker() {
if (callContact != null) {
getHandleToUse(intent, callContact!!.number) { handle ->
- CallManager.call?.phoneAccountSelected(handle, false)
+ CallManager.getPrimaryCall()?.phoneAccountSelected(handle, false)
}
}
}
@@ -446,16 +530,21 @@ class CallActivity : SimpleActivity() {
}
}
- private val callCallback = object : Call.Callback() {
- override fun onStateChanged(call: Call, state: Int) {
- super.onStateChanged(call, state)
- updateCallState(state)
+ private val callCallback = object : CallManagerListener {
+ override fun onStateChanged() {
+ updateState()
+ }
+
+ override fun onPrimaryCallChanged(call: Call) {
+ callDurationHandler.removeCallbacks(updateCallDurationTask)
+ updateCallContactInfo(call)
+ updateState()
}
}
private val updateCallDurationTask = object : Runnable {
override fun run() {
- callDuration = CallManager.getCallDuration()
+ callDuration = CallManager.getPrimaryCall().getCallDuration()
if (!isCallEnded) {
call_status_label.text = callDuration.getFormattedDuration()
callDurationHandler.postDelayed(this, 1000)
@@ -497,4 +586,11 @@ class CallActivity : SimpleActivity() {
proximityWakeLock!!.release()
}
}
+
+ private fun setActionButtonEnabled(button: ImageView, enabled: Boolean) {
+ button.apply {
+ isEnabled = enabled
+ alpha = if (enabled) 1.0f else LOWER_ALPHA
+ }
+ }
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/activities/ConferenceActivity.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/activities/ConferenceActivity.kt
new file mode 100644
index 00000000..f3633b23
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/dialer/activities/ConferenceActivity.kt
@@ -0,0 +1,17 @@
+package com.simplemobiletools.dialer.activities
+
+import android.os.Bundle
+import com.simplemobiletools.dialer.R
+import com.simplemobiletools.dialer.adapters.ConferenceCallsAdapter
+import com.simplemobiletools.dialer.helpers.CallManager
+import kotlinx.android.synthetic.main.activity_conference.*
+
+class ConferenceActivity : SimpleActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_conference)
+
+ conference_calls_list.adapter = ConferenceCallsAdapter(this, conference_calls_list, ArrayList(CallManager.getConferenceCalls())) {}
+ }
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/adapters/ConferenceCallsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/adapters/ConferenceCallsAdapter.kt
new file mode 100644
index 00000000..961eda02
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/dialer/adapters/ConferenceCallsAdapter.kt
@@ -0,0 +1,89 @@
+package com.simplemobiletools.dialer.adapters
+
+import android.telecom.Call
+import android.view.Menu
+import android.view.ViewGroup
+import com.bumptech.glide.Glide
+import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
+import com.simplemobiletools.commons.helpers.LOWER_ALPHA
+import com.simplemobiletools.commons.helpers.SimpleContactsHelper
+import com.simplemobiletools.commons.views.MyRecyclerView
+import com.simplemobiletools.dialer.R
+import com.simplemobiletools.dialer.activities.SimpleActivity
+import com.simplemobiletools.dialer.extensions.hasCapability
+import com.simplemobiletools.dialer.helpers.getCallContact
+import kotlinx.android.synthetic.main.item_conference_call.view.*
+
+class ConferenceCallsAdapter(
+ activity: SimpleActivity, recyclerView: MyRecyclerView, val data: ArrayList, itemClick: (Any) -> Unit
+) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) {
+
+ override fun actionItemPressed(id: Int) {}
+
+ override fun getActionMenuId(): Int = 0
+
+ override fun getIsItemSelectable(position: Int): Boolean = false
+
+ override fun getItemCount(): Int = data.size
+
+ override fun getItemKeyPosition(key: Int): Int = -1
+
+ override fun getItemSelectionKey(position: Int): Int? = null
+
+ override fun getSelectableItemCount(): Int = data.size
+
+ override fun onActionModeCreated() {}
+
+ override fun onActionModeDestroyed() {}
+
+ override fun prepareActionMode(menu: Menu) {}
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_conference_call, parent)
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val call = data[position]
+ holder.bindView(call, allowSingleClick = false, allowLongClick = false) { itemView, _ ->
+ getCallContact(itemView.context, call) { callContact ->
+ itemView.post {
+ itemView.item_conference_call_name.text = callContact.name.ifEmpty { itemView.context.getString(R.string.unknown_caller) }
+ SimpleContactsHelper(activity).loadContactImage(
+ callContact.photoUri,
+ itemView.item_conference_call_image,
+ callContact.name,
+ activity.getDrawable(R.drawable.ic_person_vector)
+ )
+ }
+ }
+ val canSeparate = call.hasCapability(Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE)
+ val canDisconnect = call.hasCapability(Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE)
+ itemView.item_conference_call_split.isEnabled = canSeparate
+ itemView.item_conference_call_split.alpha = if (canSeparate) 1.0f else LOWER_ALPHA
+ itemView.item_conference_call_split.setOnClickListener {
+ call.splitFromConference()
+ data.removeAt(position)
+ notifyItemRemoved(position)
+ if (data.size == 1) {
+ activity.finish()
+ }
+ }
+ itemView.item_conference_call_end.isEnabled = canDisconnect
+ itemView.item_conference_call_end.alpha = if (canDisconnect) 1.0f else LOWER_ALPHA
+ itemView.item_conference_call_end.setOnClickListener {
+ call.disconnect()
+ data.removeAt(position)
+ notifyItemRemoved(position)
+ if (data.size == 1) {
+ activity.finish()
+ }
+ }
+ }
+ bindViewHolder(holder)
+ }
+
+ override fun onViewRecycled(holder: ViewHolder) {
+ super.onViewRecycled(holder)
+ if (!activity.isDestroyed && !activity.isFinishing) {
+ Glide.with(activity).clear(holder.itemView.item_conference_call_image)
+ }
+ }
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/extensions/Call.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/extensions/Call.kt
index edca4412..80f1173f 100644
--- a/app/src/main/kotlin/com/simplemobiletools/dialer/extensions/Call.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/dialer/extensions/Call.kt
@@ -9,14 +9,32 @@ import com.simplemobiletools.commons.helpers.isSPlus
private val OUTGOING_CALL_STATES = arrayOf(STATE_CONNECTING, STATE_DIALING, STATE_SELECT_PHONE_ACCOUNT)
@Suppress("DEPRECATION")
-fun Call.getStateCompat(): Int {
- return if (isSPlus()) {
+fun Call?.getStateCompat(): Int {
+ return if (this == null) {
+ Call.STATE_DISCONNECTED
+ } else if (isSPlus()) {
details.state
} else {
state
}
}
+fun Call?.getCallDuration(): Int {
+ return if (this != null) {
+ val connectTimeMillis = details.connectTimeMillis
+ if (connectTimeMillis == 0L) {
+ return 0
+ }
+ ((System.currentTimeMillis() - connectTimeMillis) / 1000).toInt()
+ } else {
+ 0
+ }
+}
+
fun Call.isOutgoing(): Boolean {
return OUTGOING_CALL_STATES.contains(getStateCompat())
}
+
+fun Call.hasCapability(capability: Int): Boolean = (details.callCapabilities and capability) != 0
+
+fun Call?.isConference(): Boolean = this?.details?.hasProperty(Call.Details.PROPERTY_CONFERENCE) == true
diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallContactHelper.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallContactHelper.kt
new file mode 100644
index 00000000..9d0b4cb5
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallContactHelper.kt
@@ -0,0 +1,72 @@
+package com.simplemobiletools.dialer.helpers
+
+import android.content.Context
+import android.net.Uri
+import android.telecom.Call
+import com.simplemobiletools.commons.extensions.getMyContactsCursor
+import com.simplemobiletools.commons.extensions.getPhoneNumberTypeText
+import com.simplemobiletools.commons.helpers.MyContactsContentProvider
+import com.simplemobiletools.commons.helpers.SimpleContactsHelper
+import com.simplemobiletools.commons.helpers.ensureBackgroundThread
+import com.simplemobiletools.dialer.R
+import com.simplemobiletools.dialer.extensions.isConference
+import com.simplemobiletools.dialer.models.CallContact
+
+fun getCallContact(context: Context, call: Call?, callback: (CallContact) -> Unit) {
+ if (call.isConference()) {
+ callback(CallContact(context.getString(R.string.conference), "", "", ""))
+ return
+ }
+
+ val privateCursor = context.getMyContactsCursor(false, true)
+ ensureBackgroundThread {
+ val callContact = CallContact("", "", "", "")
+ val handle = try {
+ call?.details?.handle?.toString()
+ } catch (e: NullPointerException) {
+ null
+ }
+
+ if (handle == null) {
+ callback(callContact)
+ return@ensureBackgroundThread
+ }
+
+ val uri = Uri.decode(handle)
+ if (uri.startsWith("tel:")) {
+ val number = uri.substringAfter("tel:")
+ SimpleContactsHelper(context).getAvailableContacts(false) { contacts ->
+ val privateContacts = MyContactsContentProvider.getSimpleContacts(context, privateCursor)
+ if (privateContacts.isNotEmpty()) {
+ contacts.addAll(privateContacts)
+ }
+
+ val contactsWithMultipleNumbers = contacts.filter { it.phoneNumbers.size > 1 }
+ val numbersToContactIDMap = HashMap()
+ contactsWithMultipleNumbers.forEach { contact ->
+ contact.phoneNumbers.forEach { phoneNumber ->
+ numbersToContactIDMap[phoneNumber.value] = contact.contactId
+ numbersToContactIDMap[phoneNumber.normalizedNumber] = contact.contactId
+ }
+ }
+
+ callContact.number = number
+ val contact = contacts.firstOrNull { it.doesHavePhoneNumber(number) }
+ if (contact != null) {
+ callContact.name = contact.name
+ callContact.photoUri = contact.photoUri
+
+ if (contact.phoneNumbers.size > 1) {
+ val specificPhoneNumber = contact.phoneNumbers.firstOrNull { it.value == number }
+ if (specificPhoneNumber != null) {
+ callContact.numberLabel = context.getPhoneNumberTypeText(specificPhoneNumber.type, specificPhoneNumber.label)
+ }
+ }
+ } else {
+ callContact.name = number
+ }
+ callback(callContact)
+ }
+ }
+ }
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallManager.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallManager.kt
index f51ca7fb..57b6239c 100644
--- a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallManager.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallManager.kt
@@ -1,23 +1,120 @@
package com.simplemobiletools.dialer.helpers
-import android.content.Context
-import android.net.Uri
+import android.annotation.SuppressLint
import android.telecom.Call
import android.telecom.InCallService
import android.telecom.VideoProfile
-import com.simplemobiletools.commons.extensions.getMyContactsCursor
-import com.simplemobiletools.commons.extensions.getPhoneNumberTypeText
-import com.simplemobiletools.commons.helpers.MyContactsContentProvider
-import com.simplemobiletools.commons.helpers.SimpleContactsHelper
-import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.dialer.extensions.getStateCompat
-import com.simplemobiletools.dialer.models.CallContact
+import com.simplemobiletools.dialer.extensions.hasCapability
+import com.simplemobiletools.dialer.extensions.isConference
+import java.util.concurrent.CopyOnWriteArraySet
// inspired by https://github.com/Chooloo/call_manage
class CallManager {
companion object {
- var call: Call? = null
+ @SuppressLint("StaticFieldLeak")
var inCallService: InCallService? = null
+ private var call: Call? = null
+ private val calls = mutableListOf()
+ private val listeners = CopyOnWriteArraySet()
+
+ fun onCallAdded(call: Call) {
+ this.call = call
+ calls.add(call)
+ for (listener in listeners) {
+ listener.onPrimaryCallChanged(call)
+ }
+ call.registerCallback(object : Call.Callback() {
+ override fun onStateChanged(call: Call, state: Int) {
+ updateState()
+ }
+
+ override fun onDetailsChanged(call: Call, details: Call.Details) {
+ updateState()
+ }
+
+ override fun onConferenceableCallsChanged(call: Call, conferenceableCalls: MutableList) {
+ updateState()
+ }
+ })
+ }
+
+ fun onCallRemoved(call: Call) {
+ calls.remove(call)
+ updateState()
+ }
+
+ fun getPhoneState(): PhoneState {
+ return when (calls.size) {
+ 0 -> NoCall
+ 1 -> SingleCall(calls.first())
+ 2 -> {
+ val active = calls.find { it.getStateCompat() == Call.STATE_ACTIVE }
+ val newCall = calls.find { it.getStateCompat() == Call.STATE_CONNECTING || it.getStateCompat() == Call.STATE_DIALING }
+ val onHold = calls.find { it.getStateCompat() == Call.STATE_HOLDING }
+ if (active != null && newCall != null) {
+ TwoCalls(newCall, active)
+ } else if (newCall != null && onHold != null) {
+ TwoCalls(newCall, onHold)
+ } else if (active != null && onHold != null) {
+ TwoCalls(active, onHold)
+ } else {
+ TwoCalls(calls[0], calls[1])
+ }
+ }
+ else -> {
+ val conference = calls.find { it.isConference() }!!
+ val secondCall = if (conference.children.size + 1 != calls.size) {
+ calls.filter { !it.isConference() }
+ .subtract(conference.children.toSet())
+ .firstOrNull()
+ } else {
+ null
+ }
+ if (secondCall == null) {
+ SingleCall(conference)
+ } else {
+ val newCallState = secondCall.getStateCompat()
+ if (newCallState == Call.STATE_ACTIVE || newCallState == Call.STATE_CONNECTING || newCallState == Call.STATE_DIALING) {
+ TwoCalls(secondCall, conference)
+ } else {
+ TwoCalls(conference, secondCall)
+ }
+ }
+ }
+ }
+ }
+
+ private fun updateState() {
+ val primaryCall = when (val phoneState = getPhoneState()) {
+ is NoCall -> null
+ is SingleCall -> phoneState.call
+ is TwoCalls -> phoneState.active
+ }
+ var notify = true
+ if (primaryCall == null) {
+ call = null
+ } else if (primaryCall != call) {
+ call = primaryCall
+ for (listener in listeners) {
+ listener.onPrimaryCallChanged(primaryCall)
+ }
+ notify = false
+ }
+ if (notify) {
+ for (listener in listeners) {
+ listener.onStateChanged()
+ }
+ }
+ }
+
+ fun getPrimaryCall(): Call? {
+ return call
+ }
+
+ fun getConferenceCalls(): List {
+ return calls.find { it.isConference() }?.children ?: emptyList()
+ }
fun accept() {
call?.answer(VideoProfile.STATE_AUDIO_ONLY)
@@ -43,85 +140,46 @@ class CallManager {
return !isOnHold
}
- fun registerCallback(callback: Call.Callback) {
- call?.registerCallback(callback)
+ fun swap() {
+ if (calls.size > 1) {
+ calls.find { it.getStateCompat() == Call.STATE_HOLDING }?.unhold()
+ }
}
- fun unregisterCallback(callback: Call.Callback) {
- call?.unregisterCallback(callback)
+ fun merge() {
+ val conferenceableCalls = call!!.conferenceableCalls
+ if (conferenceableCalls.isNotEmpty()) {
+ call!!.conference(conferenceableCalls.first())
+ } else {
+ if (call!!.hasCapability(Call.Details.CAPABILITY_MERGE_CONFERENCE)) {
+ call!!.mergeConference()
+ }
+ }
}
- fun getState() = if (call == null) {
- Call.STATE_DISCONNECTED
- } else {
- call!!.getStateCompat()
+ fun addListener(listener: CallManagerListener) {
+ listeners.add(listener)
}
+ fun removeListener(listener: CallManagerListener) {
+ listeners.remove(listener)
+ }
+
+ fun getState() = getPrimaryCall()?.getStateCompat()
+
fun keypad(c: Char) {
call?.playDtmfTone(c)
call?.stopDtmfTone()
}
-
- fun getCallContact(context: Context, callback: (CallContact?) -> Unit) {
- val privateCursor = context.getMyContactsCursor(false, true)
- ensureBackgroundThread {
- val callContact = CallContact("", "", "", "")
- val handle = try {
- call?.details?.handle?.toString()
- } catch (e: NullPointerException) {
- null
- }
-
- if (handle == null) {
- callback(callContact)
- return@ensureBackgroundThread
- }
-
- val uri = Uri.decode(handle)
- if (uri.startsWith("tel:")) {
- val number = uri.substringAfter("tel:")
- SimpleContactsHelper(context).getAvailableContacts(false) { contacts ->
- val privateContacts = MyContactsContentProvider.getSimpleContacts(context, privateCursor)
- if (privateContacts.isNotEmpty()) {
- contacts.addAll(privateContacts)
- }
-
- val contactsWithMultipleNumbers = contacts.filter { it.phoneNumbers.size > 1 }
- val numbersToContactIDMap = HashMap()
- contactsWithMultipleNumbers.forEach { contact ->
- contact.phoneNumbers.forEach { phoneNumber ->
- numbersToContactIDMap[phoneNumber.value] = contact.contactId
- numbersToContactIDMap[phoneNumber.normalizedNumber] = contact.contactId
- }
- }
-
- callContact.number = number
- val contact = contacts.firstOrNull { it.doesHavePhoneNumber(number) }
- if (contact != null) {
- callContact.name = contact.name
- callContact.photoUri = contact.photoUri
-
- if (contact.phoneNumbers.size > 1) {
- val specificPhoneNumber = contact.phoneNumbers.firstOrNull { it.value == number }
- if (specificPhoneNumber != null) {
- callContact.numberLabel = context.getPhoneNumberTypeText(specificPhoneNumber.type, specificPhoneNumber.label)
- }
- }
- } else {
- callContact.name = number
- }
- callback(callContact)
- }
- }
- }
- }
-
- fun getCallDuration(): Int {
- return if (call != null) {
- ((System.currentTimeMillis() - call!!.details.connectTimeMillis) / 1000).toInt()
- } else {
- 0
- }
- }
}
}
+
+interface CallManagerListener {
+ fun onStateChanged()
+ fun onPrimaryCallChanged(call: Call)
+}
+
+sealed class PhoneState
+object NoCall : PhoneState()
+class SingleCall(val call: Call) : PhoneState()
+class TwoCalls(val active: Call, val onHold: Call) : PhoneState()
diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt
index 324123b4..ecd286c6 100644
--- a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt
@@ -28,7 +28,7 @@ class CallNotificationManager(private val context: Context) {
@SuppressLint("NewApi")
fun setupNotification() {
- CallManager.getCallContact(context.applicationContext) { callContact ->
+ getCallContact(context.applicationContext, CallManager.getPrimaryCall()) { callContact ->
val callContactAvatar = callContactAvatarHelper.getCallContactAvatar(callContact)
val callState = CallManager.getState()
val isHighPriority = context.powerManager.isInteractive && callState == Call.STATE_RINGING
diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt
index f1fd2277..43315238 100644
--- a/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt
@@ -10,6 +10,7 @@ import com.simplemobiletools.dialer.extensions.isOutgoing
import com.simplemobiletools.dialer.extensions.powerManager
import com.simplemobiletools.dialer.helpers.CallManager
import com.simplemobiletools.dialer.helpers.CallNotificationManager
+import com.simplemobiletools.dialer.helpers.NoCall
class CallService : InCallService() {
private val callNotificationManager by lazy { CallNotificationManager(this) }
@@ -25,9 +26,9 @@ class CallService : InCallService() {
override fun onCallAdded(call: Call) {
super.onCallAdded(call)
- CallManager.call = call
+ CallManager.onCallAdded(call)
CallManager.inCallService = this
- CallManager.registerCallback(callListener)
+ call.registerCallback(callListener)
val isScreenLocked = (getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager).isDeviceLocked
if (!powerManager.isInteractive || call.isOutgoing() || isScreenLocked) {
@@ -42,14 +43,22 @@ class CallService : InCallService() {
override fun onCallRemoved(call: Call) {
super.onCallRemoved(call)
- CallManager.call = null
- CallManager.inCallService = null
- callNotificationManager.cancelNotification()
+ call.unregisterCallback(callListener)
+ val wasPrimaryCall = call == CallManager.getPrimaryCall()
+ CallManager.onCallRemoved(call)
+ if (CallManager.getPhoneState() == NoCall) {
+ CallManager.inCallService = null
+ callNotificationManager.cancelNotification()
+ } else {
+ callNotificationManager.setupNotification()
+ if (wasPrimaryCall) {
+ startActivity(CallActivity.getStartIntent(this))
+ }
+ }
}
override fun onDestroy() {
super.onDestroy()
- CallManager.unregisterCallback(callListener)
callNotificationManager.cancelNotification()
}
}
diff --git a/app/src/main/res/drawable/ic_add_call_vector.xml b/app/src/main/res/drawable/ic_add_call_vector.xml
new file mode 100644
index 00000000..059b7e05
--- /dev/null
+++ b/app/src/main/res/drawable/ic_add_call_vector.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_call_merge_vector.xml b/app/src/main/res/drawable/ic_call_merge_vector.xml
new file mode 100644
index 00000000..280463cd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_call_merge_vector.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_call_split_vector.xml b/app/src/main/res/drawable/ic_call_split_vector.xml
new file mode 100644
index 00000000..5afba98d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_call_split_vector.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_call_swap_vector.xml b/app/src/main/res/drawable/ic_call_swap_vector.xml
new file mode 100644
index 00000000..35ec9c98
--- /dev/null
+++ b/app/src/main/res/drawable/ic_call_swap_vector.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_call.xml b/app/src/main/res/layout/activity_call.xml
index e846a9d7..bc436dcb 100644
--- a/app/src/main/res/layout/activity_call.xml
+++ b/app/src/main/res/layout/activity_call.xml
@@ -102,6 +102,55 @@
app:layout_constraintTop_toTopOf="@+id/call_sim_image"
tools:text="1" />
+
+
+
+
+
+
+
+
+
+
@@ -131,8 +179,8 @@
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_speaker_off_vector"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/call_dialpad"
+ app:layout_constraintStart_toEndOf="@+id/call_toggle_microphone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.6" />
@@ -146,8 +194,7 @@
android:src="@drawable/ic_dialpad_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.85"
- app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/call_toggle_speaker"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.6" />
@@ -157,11 +204,67 @@
android:layout_height="@dimen/dialpad_button_size"
android:layout_marginTop="@dimen/bigger_margin"
android:background="?attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/hold_call"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_pause_vector"
- app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintEnd_toEndOf="@+id/call_toggle_microphone"
+ app:layout_constraintStart_toStartOf="@+id/call_toggle_microphone"
+ app:layout_constraintTop_toBottomOf="@+id/call_toggle_microphone" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_conference_call.xml b/app/src/main/res/layout/item_conference_call.xml
new file mode 100644
index 00000000..0833746b
--- /dev/null
+++ b/app/src/main/res/layout/item_conference_call.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index 362e3cbf..30a463ab 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Бързо набиране
Управление на бързото набиране
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index 45824070..789e6db9 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -47,6 +47,12 @@
Trucada en espera
Reprèn la trucada
En espera
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Marcatge ràpid
Gestiona el marcatge ràpid
@@ -66,4 +72,4 @@
Haven't found some strings? There's more at
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
-->
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 10e75b2d..726b18f0 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Rychlé vytáčení
Spravujte rychlou volbu
@@ -89,4 +95,4 @@
Haven't found some strings? There's more at
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
-->
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index 3e872a25..9a8ea6e7 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Hurtigopkald
Administrér hurtigopkald
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 68d68a5a..aafddd1c 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -47,6 +47,12 @@
Anruf halten
Anruf fortsetzen
In der Warteschleife
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Kurzwahl
Kurzwahlnummern verwalten
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 3460f71a..83623ff3 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -50,6 +50,12 @@
Αναμονή Κλήσης
Συνέχιση Κλήσης
Σε Αναμονή
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Ταχεία κλήση
diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml
index 1cb048f9..55f8791f 100644
--- a/app/src/main/res/values-eo/strings.xml
+++ b/app/src/main/res/values-eo/strings.xml
@@ -51,6 +51,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Speed dial
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 034edd79..9e6776a9 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Marcado rápido
Administrar marcado rápido
diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml
index 03156089..9db88df1 100644
--- a/app/src/main/res/values-et/strings.xml
+++ b/app/src/main/res/values-et/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Kiirvalimine
Klõpsa numbrit ja seosta ta konkreetse telefoniraamatu kirjega. Hiljem saad samale numbrile pikalt vajutades alustada kõnet määratud telefoninumbrile.
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index 4b282eae..9c435086 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Pikavalinta
Pikavalinnan asetukset
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index ada667b7..d312d1b0 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -1,6 +1,6 @@
- Simple Dialer
+ Simple Téléphone
Téléphone
Veuillez faire de cette application votre application de téléphone par défaut
Veuillez permettre l\'affichage sur d\'autres applications pour un comportement fiable
@@ -47,6 +47,12 @@
Mettre l\'appel en attente
Reprendre l\'appel
En attente
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Numérotation rapide
Gérer la numérotation rapide
@@ -89,4 +95,4 @@
Haven't found some strings? There's more at
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
-->
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index 7ad2eb8d..7992fee5 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Marcación rápida
Xestionar marcacións rápidas
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
index ea8d7596..acdaf48f 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Brzo biranje
Upravljajte brzim biranjem
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 7dce2a65..dcd524d6 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Gyors tárcsázó
Gyors tárcsázó kezelése
diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml
index 12a84dcd..1cf3774a 100644
--- a/app/src/main/res/values-id/strings.xml
+++ b/app/src/main/res/values-id/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Panggilan cepat
Kelola panggilan cepat
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 5a2c2688..c827ccc9 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -47,6 +47,12 @@
Metti in attesa la chiamata
Riprendi la chiamata
In attesa
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Contatti veloci
Gestisci i contatti veloci
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index e80a3d90..f250b88f 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
スピードダイヤル
スピードダイヤルの管理
diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml
index 3965a88d..cadc4e52 100644
--- a/app/src/main/res/values-lt/strings.xml
+++ b/app/src/main/res/values-lt/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Spartusis rinkimas
Tvarkyti spartųjį rinkimą
diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml
index 421bb22f..75e69c6d 100644
--- a/app/src/main/res/values-ml/strings.xml
+++ b/app/src/main/res/values-ml/strings.xml
@@ -50,6 +50,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
സ്പീഡ് ഡയൽ
diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml
index bc8d131c..f9da0b13 100644
--- a/app/src/main/res/values-nb-rNO/strings.xml
+++ b/app/src/main/res/values-nb-rNO/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Hurtigvalg
Administrer hurtigvalg
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 566bca95..ea80b104 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -47,6 +47,12 @@
In wacht
Hervatten
In de wacht
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Snelkiesnummer
Snelkiezen beheren
@@ -67,4 +73,4 @@
Haven't found some strings? There's more at
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
-->
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 53342a16..ce1bd325 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -47,6 +47,12 @@
Wstrzymaj połączenie
Wznów połączenie
Wstrzymane
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Szybkie wybieranie
Zarządzaj szybkim wybieraniem
@@ -89,4 +95,4 @@
Haven't found some strings? There's more at
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
-->
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 1021b603..d3068e16 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Ligação rápida
Gerenciar ligações rápidas
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index e0f70658..84aff255 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Marcação rápida
Gerir marcações rápidas
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index 26191471..254b0a46 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Apelare rapidă
Gestionați apelarea rapidă
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 4f5dd650..1260d75f 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Быстрый вызов
Управление быстрым вызовом
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index bd336bc1..94f67e92 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -51,6 +51,12 @@
Podržať hovor
Obnoviť hovor
Podržaný hovor
+ Prehodiť hovory
+ Zlúčiť hovory
+ Rozdeliť call
+ Pridať hovor
+ Spravovať konferenčný hovor
+ Konferencia
Rýchle vytáčanie
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 0d1f39bf..e4d05fc8 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -47,6 +47,12 @@
Parkera samtal
Återuppta samtal
Parkerat
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Snabbuppringning
Hantera snabbuppringning
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 962cebba..a790df02 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -47,6 +47,12 @@
Aramayı beklet
Aramayı devam ettir
Beklemede
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Hızlı arama
Hızlı aramayı yönet
@@ -66,4 +72,4 @@
Bazı dizeleri bulamadınız mı? Burada daha fazlası var:
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
-->
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index fb967106..cda650ec 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -46,7 +46,13 @@
Завершити виклик
Перевести в утримання
Зняти з утримання
- Дзвінок утримується
+ Утримується
+ Поміняти
+ З\'єднати
+ Роз\'єднати
+ Додати дзвінок
+ Керувати конференц-викликом
+ Конференц-виклик
Швидкий виклик
Управління швидким викликом
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index a0626fa4..ed180af7 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -47,6 +47,12 @@
保持通话
继续通话
暂停
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
快速拨号
管理快速拨号
@@ -89,4 +95,4 @@
Haven't found some strings? There's more at
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
-->
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 6aadb180..4236c343 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -47,6 +47,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Speed dial
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 928b9370..c32cc0e8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -51,6 +51,12 @@
Hold call
Resume call
On Hold
+ Swap calls
+ Merge calls
+ Split call
+ Add call
+ Manage conference call
+ Conference
Speed dial