From e032bdddce6907c0db55b317ff408966a75d05db Mon Sep 17 00:00:00 2001 From: darthpaul Date: Sun, 19 Sep 2021 23:22:45 +0100 Subject: [PATCH 01/11] ref: separate notification form CallActivity - create CallNotificationManager to handle notifications, to ensure separation of concerns - create helper class CallContactAvatarHelper to get contact's avatar. It is needed by the CallActivity and CallNotificationManager --- .../dialer/activities/CallActivity.kt | 146 +++--------------- .../dialer/helpers/CallContactAvatarHelper.kt | 49 ++++++ .../dialer/helpers/CallNotificationManager.kt | 96 ++++++++++++ 3 files changed, 163 insertions(+), 128 deletions(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallContactAvatarHelper.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt 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 58bdaa7e0..95334fc11 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt @@ -1,50 +1,44 @@ package com.simplemobiletools.dialer.activities import android.annotation.SuppressLint -import android.app.* +import android.app.KeyguardManager import android.content.Context -import android.content.Intent -import android.graphics.* +import android.graphics.Bitmap import android.media.AudioManager -import android.net.Uri import android.os.Bundle import android.os.Handler -import android.os.Looper import android.os.PowerManager -import android.provider.MediaStore import android.telecom.Call import android.telecom.CallAudioState -import android.util.Size import android.view.WindowManager -import android.widget.RemoteViews -import androidx.core.app.NotificationCompat import com.simplemobiletools.commons.extensions.* -import com.simplemobiletools.commons.helpers.* +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.ACCEPT_CALL +import com.simplemobiletools.dialer.helpers.CallContactAvatarHelper import com.simplemobiletools.dialer.helpers.CallManager -import com.simplemobiletools.dialer.helpers.DECLINE_CALL +import com.simplemobiletools.dialer.helpers.CallNotificationManager import com.simplemobiletools.dialer.models.CallContact -import com.simplemobiletools.dialer.receivers.CallActionReceiver +import java.util.Timer +import java.util.TimerTask import kotlinx.android.synthetic.main.activity_call.* import kotlinx.android.synthetic.main.dialpad.* -import java.util.* class CallActivity : SimpleActivity() { - private val CALL_NOTIFICATION_ID = 1 - private var isSpeakerOn = false private var isMicrophoneOn = true private var isCallEnded = false private var callDuration = 0 private var callContact: CallContact? = null - private var callContactAvatar: Bitmap? = null private var proximityWakeLock: PowerManager.WakeLock? = null private var callTimer = Timer() + private val callContactAvatarHelper by lazy { CallContactAvatarHelper(this) } + private val callNotificationManager by lazy { CallNotificationManager(this) } override fun onCreate(savedInstanceState: Bundle?) { supportActionBar?.hide() @@ -58,10 +52,10 @@ class CallActivity : SimpleActivity() { CallManager.getCallContact(applicationContext) { contact -> callContact = contact - callContactAvatar = getCallContactAvatar() + val avatar = callContactAvatarHelper.getCallContactAvatar(contact) runOnUiThread { - setupNotification() - updateOtherPersonsInfo() + callNotificationManager.setupNotification() + updateOtherPersonsInfo(avatar) checkCalledSIMCard() } } @@ -74,7 +68,7 @@ class CallActivity : SimpleActivity() { override fun onDestroy() { super.onDestroy() - notificationManager.cancel(CALL_NOTIFICATION_ID) + callNotificationManager.cancelNotification() CallManager.unregisterCallback(callCallback) callTimer.cancel() if (proximityWakeLock?.isHeld == true) { @@ -180,7 +174,7 @@ class CallActivity : SimpleActivity() { } } - private fun updateOtherPersonsInfo() { + private fun updateOtherPersonsInfo(avatar: Bitmap?) { if (callContact == null) { return } @@ -192,8 +186,8 @@ class CallActivity : SimpleActivity() { caller_number_label.beGone() } - if (callContactAvatar != null) { - caller_avatar.setImageBitmap(callContactAvatar) + if (avatar != null) { + caller_avatar.setImageBitmap(avatar) } } @@ -236,8 +230,6 @@ class CallActivity : SimpleActivity() { if (statusTextId != 0) { call_status_label.text = getString(statusTextId) } - - setupNotification() } private fun acceptCall() { @@ -348,106 +340,4 @@ class CallActivity : SimpleActivity() { proximityWakeLock!!.acquire(10 * MINUTE_SECONDS * 1000L) } } - - @SuppressLint("NewApi") - private fun setupNotification() { - val callState = CallManager.getState() - val channelId = "simple_dialer_call" - if (isOreoPlus()) { - val importance = NotificationManager.IMPORTANCE_DEFAULT - val name = "call_notification_channel" - - NotificationChannel(channelId, name, importance).apply { - setSound(null, null) - notificationManager.createNotificationChannel(this) - } - } - - val openAppIntent = Intent(this, CallActivity::class.java) - openAppIntent.flags = Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT - val openAppPendingIntent = PendingIntent.getActivity(this, 0, openAppIntent, 0) - - val acceptCallIntent = Intent(this, CallActionReceiver::class.java) - acceptCallIntent.action = ACCEPT_CALL - val acceptPendingIntent = PendingIntent.getBroadcast(this, 0, acceptCallIntent, PendingIntent.FLAG_CANCEL_CURRENT) - - val declineCallIntent = Intent(this, CallActionReceiver::class.java) - declineCallIntent.action = DECLINE_CALL - val declinePendingIntent = PendingIntent.getBroadcast(this, 1, declineCallIntent, PendingIntent.FLAG_CANCEL_CURRENT) - - val callerName = if (callContact != null && callContact!!.name.isNotEmpty()) callContact!!.name else getString(R.string.unknown_caller) - val contentTextId = when (callState) { - Call.STATE_RINGING -> R.string.is_calling - Call.STATE_DIALING -> R.string.dialing - Call.STATE_DISCONNECTED -> R.string.call_ended - Call.STATE_DISCONNECTING -> R.string.call_ending - else -> R.string.ongoing_call - } - - val collapsedView = RemoteViews(packageName, R.layout.call_notification).apply { - setText(R.id.notification_caller_name, callerName) - setText(R.id.notification_call_status, getString(contentTextId)) - setVisibleIf(R.id.notification_accept_call, callState == Call.STATE_RINGING) - - setOnClickPendingIntent(R.id.notification_decline_call, declinePendingIntent) - setOnClickPendingIntent(R.id.notification_accept_call, acceptPendingIntent) - - if (callContactAvatar != null) { - setImageViewBitmap(R.id.notification_thumbnail, getCircularBitmap(callContactAvatar!!)) - } - } - - val builder = NotificationCompat.Builder(this, channelId) - .setSmallIcon(R.drawable.ic_phone_vector) - .setContentIntent(openAppPendingIntent) - .setPriority(NotificationCompat.PRIORITY_DEFAULT) - .setCategory(Notification.CATEGORY_CALL) - .setCustomContentView(collapsedView) - .setOngoing(true) - .setSound(null) - .setUsesChronometer(callState == Call.STATE_ACTIVE) - .setChannelId(channelId) - .setStyle(NotificationCompat.DecoratedCustomViewStyle()) - - val notification = builder.build() - notificationManager.notify(CALL_NOTIFICATION_ID, notification) - } - - @SuppressLint("NewApi") - private fun getCallContactAvatar(): Bitmap? { - var bitmap: Bitmap? = null - if (callContact?.photoUri?.isNotEmpty() == true) { - val photoUri = Uri.parse(callContact!!.photoUri) - try { - bitmap = if (isQPlus()) { - val tmbSize = resources.getDimension(R.dimen.list_avatar_size).toInt() - contentResolver.loadThumbnail(photoUri, Size(tmbSize, tmbSize), null) - } else { - MediaStore.Images.Media.getBitmap(contentResolver, photoUri) - - } - - bitmap = getCircularBitmap(bitmap!!) - } catch (ignored: Exception) { - return null - } - } - - return bitmap - } - - private fun getCircularBitmap(bitmap: Bitmap): Bitmap { - val output = Bitmap.createBitmap(bitmap.width, bitmap.width, Bitmap.Config.ARGB_8888) - val canvas = Canvas(output) - val paint = Paint() - val rect = Rect(0, 0, bitmap.width, bitmap.height) - val radius = bitmap.width / 2.toFloat() - - paint.isAntiAlias = true - canvas.drawARGB(0, 0, 0, 0) - canvas.drawCircle(radius, radius, radius, paint) - paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) - canvas.drawBitmap(bitmap, rect, rect, paint) - return output - } } diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallContactAvatarHelper.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallContactAvatarHelper.kt new file mode 100644 index 000000000..151b265ab --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallContactAvatarHelper.kt @@ -0,0 +1,49 @@ +package com.simplemobiletools.dialer.helpers + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.* +import android.net.Uri +import android.provider.MediaStore +import android.util.Size +import com.simplemobiletools.commons.helpers.isQPlus +import com.simplemobiletools.dialer.R +import com.simplemobiletools.dialer.models.CallContact + +class CallContactAvatarHelper(private val context: Context) { + @SuppressLint("NewApi") + fun getCallContactAvatar(callContact: CallContact?): Bitmap? { + var bitmap: Bitmap? = null + if (callContact?.photoUri?.isNotEmpty() == true) { + val photoUri = Uri.parse(callContact.photoUri) + try { + val contentResolver = context.contentResolver + bitmap = if (isQPlus()) { + val tmbSize = context.resources.getDimension(R.dimen.list_avatar_size).toInt() + contentResolver.loadThumbnail(photoUri, Size(tmbSize, tmbSize), null) + } else { + MediaStore.Images.Media.getBitmap(contentResolver, photoUri) + } + bitmap = getCircularBitmap(bitmap!!) + } catch (ignored: Exception) { + return null + } + } + return bitmap + } + + fun getCircularBitmap(bitmap: Bitmap): Bitmap { + val output = Bitmap.createBitmap(bitmap.width, bitmap.width, Bitmap.Config.ARGB_8888) + val canvas = Canvas(output) + val paint = Paint() + val rect = Rect(0, 0, bitmap.width, bitmap.height) + val radius = bitmap.width / 2.toFloat() + + paint.isAntiAlias = true + canvas.drawARGB(0, 0, 0, 0) + canvas.drawCircle(radius, radius, radius, paint) + paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) + canvas.drawBitmap(bitmap, rect, rect, paint) + return output + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt new file mode 100644 index 000000000..1d37b00ed --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt @@ -0,0 +1,96 @@ +package com.simplemobiletools.dialer.helpers + +import android.annotation.SuppressLint +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.telecom.Call +import android.widget.RemoteViews +import androidx.core.app.NotificationCompat +import com.simplemobiletools.commons.extensions.notificationManager +import com.simplemobiletools.commons.extensions.setText +import com.simplemobiletools.commons.extensions.setVisibleIf +import com.simplemobiletools.commons.helpers.isOreoPlus +import com.simplemobiletools.dialer.R +import com.simplemobiletools.dialer.activities.CallActivity +import com.simplemobiletools.dialer.receivers.CallActionReceiver + +class CallNotificationManager(private val context: Context) { + private val CALL_NOTIFICATION_ID = 1 + private val notificationManager = context.notificationManager + private val callContactAvatarHelper = CallContactAvatarHelper(context) + + @SuppressLint("NewApi") + fun setupNotification() { + CallManager.getCallContact(context.applicationContext) { callContact -> + val callContactAvatar = callContactAvatarHelper.getCallContactAvatar(callContact) + val callState = CallManager.getState() + val channelId = "simple_dialer_call" + if (isOreoPlus()) { + val importance = NotificationManager.IMPORTANCE_DEFAULT + val name = "call_notification_channel" + + NotificationChannel(channelId, name, importance).apply { + setSound(null, null) + notificationManager.createNotificationChannel(this) + } + } + + val openAppIntent = Intent(context, CallActivity::class.java) + openAppIntent.flags = Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT + val openAppPendingIntent = PendingIntent.getActivity(context, 0, openAppIntent, 0) + + val acceptCallIntent = Intent(context, CallActionReceiver::class.java) + acceptCallIntent.action = ACCEPT_CALL + val acceptPendingIntent = PendingIntent.getBroadcast(context, 0, acceptCallIntent, PendingIntent.FLAG_CANCEL_CURRENT) + + val declineCallIntent = Intent(context, CallActionReceiver::class.java) + declineCallIntent.action = DECLINE_CALL + val declinePendingIntent = PendingIntent.getBroadcast(context, 1, declineCallIntent, PendingIntent.FLAG_CANCEL_CURRENT) + + val callerName = if (callContact != null && callContact.name.isNotEmpty()) callContact.name else context.getString(R.string.unknown_caller) + val contentTextId = when (callState) { + Call.STATE_RINGING -> R.string.is_calling + Call.STATE_DIALING -> R.string.dialing + Call.STATE_DISCONNECTED -> R.string.call_ended + Call.STATE_DISCONNECTING -> R.string.call_ending + else -> R.string.ongoing_call + } + + val collapsedView = RemoteViews(context.packageName, R.layout.call_notification).apply { + setText(R.id.notification_caller_name, callerName) + setText(R.id.notification_call_status, context.getString(contentTextId)) + setVisibleIf(R.id.notification_accept_call, callState == Call.STATE_RINGING) + + setOnClickPendingIntent(R.id.notification_decline_call, declinePendingIntent) + setOnClickPendingIntent(R.id.notification_accept_call, acceptPendingIntent) + + if (callContactAvatar != null) { + setImageViewBitmap(R.id.notification_thumbnail, callContactAvatarHelper.getCircularBitmap(callContactAvatar)) + } + } + + val builder = NotificationCompat.Builder(context, channelId) + .setSmallIcon(R.drawable.ic_phone_vector) + .setContentIntent(openAppPendingIntent) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setCategory(Notification.CATEGORY_CALL) + .setCustomContentView(collapsedView) + .setOngoing(true) + .setSound(null) + .setUsesChronometer(callState == Call.STATE_ACTIVE) + .setChannelId(channelId) + .setStyle(NotificationCompat.DecoratedCustomViewStyle()) + + val notification = builder.build() + notificationManager.notify(CALL_NOTIFICATION_ID, notification) + } + } + + fun cancelNotification() { + notificationManager.cancel(CALL_NOTIFICATION_ID) + } +} From 288b50da7fb1726e8ea11de3cfcd5d9ac928aeea Mon Sep 17 00:00:00 2001 From: darthpaul Date: Sun, 19 Sep 2021 23:33:09 +0100 Subject: [PATCH 02/11] ref: handle notification in CallService - remove notification handling from CallActivity - handle notification in CallService, including adding a Call.Callback method to update notification when the call state changes --- .../dialer/activities/CallActivity.kt | 4 ---- .../dialer/services/CallService.kt | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) 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 95334fc11..619b319b0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt @@ -22,7 +22,6 @@ 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.helpers.CallNotificationManager import com.simplemobiletools.dialer.models.CallContact import java.util.Timer import java.util.TimerTask @@ -38,7 +37,6 @@ class CallActivity : SimpleActivity() { private var proximityWakeLock: PowerManager.WakeLock? = null private var callTimer = Timer() private val callContactAvatarHelper by lazy { CallContactAvatarHelper(this) } - private val callNotificationManager by lazy { CallNotificationManager(this) } override fun onCreate(savedInstanceState: Bundle?) { supportActionBar?.hide() @@ -54,7 +52,6 @@ class CallActivity : SimpleActivity() { callContact = contact val avatar = callContactAvatarHelper.getCallContactAvatar(contact) runOnUiThread { - callNotificationManager.setupNotification() updateOtherPersonsInfo(avatar) checkCalledSIMCard() } @@ -68,7 +65,6 @@ class CallActivity : SimpleActivity() { override fun onDestroy() { super.onDestroy() - callNotificationManager.cancelNotification() CallManager.unregisterCallback(callCallback) callTimer.cancel() if (proximityWakeLock?.isHeld == true) { 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 c53d9a131..ecf98650a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt @@ -5,8 +5,17 @@ import android.telecom.Call import android.telecom.InCallService import com.simplemobiletools.dialer.activities.CallActivity import com.simplemobiletools.dialer.helpers.CallManager +import com.simplemobiletools.dialer.helpers.CallNotificationManager class CallService : InCallService() { + private val callNotificationManager by lazy { CallNotificationManager(this) } + private val callListener = object : Call.Callback() { + override fun onStateChanged(call: Call, state: Int) { + super.onStateChanged(call, state) + callNotificationManager.setupNotification() + } + } + override fun onCallAdded(call: Call) { super.onCallAdded(call) val intent = Intent(this, CallActivity::class.java) @@ -14,11 +23,20 @@ class CallService : InCallService() { startActivity(intent) CallManager.call = call CallManager.inCallService = this + CallManager.registerCallback(callListener) + callNotificationManager.setupNotification() } override fun onCallRemoved(call: Call) { super.onCallRemoved(call) CallManager.call = null CallManager.inCallService = null + callNotificationManager.cancelNotification() + } + + override fun onDestroy() { + super.onDestroy() + CallManager.registerCallback(callListener) + callNotificationManager.cancelNotification() } } From dd6316ae811475fa27fbaa5b10fbc0f2abcf0685 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Sun, 19 Sep 2021 23:51:47 +0100 Subject: [PATCH 03/11] ref: only end call if state is STATE_CONNECTING or STATE_DIALING --- .../com/simplemobiletools/dialer/activities/CallActivity.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 619b319b0..bcbfd834e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt @@ -70,8 +70,6 @@ class CallActivity : SimpleActivity() { if (proximityWakeLock?.isHeld == true) { proximityWakeLock!!.release() } - - endCall() } override fun onBackPressed() { @@ -82,7 +80,8 @@ class CallActivity : SimpleActivity() { super.onBackPressed() } - if (CallManager.getState() == Call.STATE_DIALING) { + val callState = CallManager.getState() + if (callState == Call.STATE_CONNECTING || callState == Call.STATE_DIALING) { endCall() } } From bdab26838e35ca84dbd61c7b5189021e6956ad25 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Mon, 20 Sep 2021 00:02:53 +0100 Subject: [PATCH 04/11] fix: launch CallActivity when call is picked from notification - add CallActivity.getStartIntent method to get the start intent for CallActivity and update in CallNotificationManager and CallService where the CallActivity is started - in CallActionReceiver, start the CallActivity before answering the call --- .../simplemobiletools/dialer/activities/CallActivity.kt | 9 +++++++++ .../dialer/helpers/CallNotificationManager.kt | 3 +-- .../dialer/receivers/CallActionReceiver.kt | 6 +++++- .../com/simplemobiletools/dialer/services/CallService.kt | 5 +---- 4 files changed, 16 insertions(+), 7 deletions(-) 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 bcbfd834e..5d8b4a216 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt @@ -3,6 +3,7 @@ package com.simplemobiletools.dialer.activities import android.annotation.SuppressLint import android.app.KeyguardManager import android.content.Context +import android.content.Intent import android.graphics.Bitmap import android.media.AudioManager import android.os.Bundle @@ -29,6 +30,14 @@ import kotlinx.android.synthetic.main.activity_call.* import kotlinx.android.synthetic.main.dialpad.* 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 + return openAppIntent + } + } + private var isSpeakerOn = false private var isMicrophoneOn = true private var isCallEnded = false 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 1d37b00ed..b6fda71c1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt @@ -39,8 +39,7 @@ class CallNotificationManager(private val context: Context) { } } - val openAppIntent = Intent(context, CallActivity::class.java) - openAppIntent.flags = Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT + val openAppIntent = CallActivity.getStartIntent(context) val openAppPendingIntent = PendingIntent.getActivity(context, 0, openAppIntent, 0) val acceptCallIntent = Intent(context, CallActionReceiver::class.java) diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/receivers/CallActionReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/receivers/CallActionReceiver.kt index 10c0cb138..57887c6f9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/receivers/CallActionReceiver.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/receivers/CallActionReceiver.kt @@ -3,6 +3,7 @@ package com.simplemobiletools.dialer.receivers import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import com.simplemobiletools.dialer.activities.CallActivity import com.simplemobiletools.dialer.helpers.ACCEPT_CALL import com.simplemobiletools.dialer.helpers.CallManager import com.simplemobiletools.dialer.helpers.DECLINE_CALL @@ -10,7 +11,10 @@ import com.simplemobiletools.dialer.helpers.DECLINE_CALL class CallActionReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { - ACCEPT_CALL -> CallManager.accept() + ACCEPT_CALL -> { + context.startActivity(CallActivity.getStartIntent(context)) + CallManager.accept() + } DECLINE_CALL -> CallManager.reject() } } 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 ecf98650a..0896ae284 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt @@ -1,6 +1,5 @@ package com.simplemobiletools.dialer.services -import android.content.Intent import android.telecom.Call import android.telecom.InCallService import com.simplemobiletools.dialer.activities.CallActivity @@ -18,9 +17,7 @@ class CallService : InCallService() { override fun onCallAdded(call: Call) { super.onCallAdded(call) - val intent = Intent(this, CallActivity::class.java) - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - startActivity(intent) + startActivity(CallActivity.getStartIntent(this)) CallManager.call = call CallManager.inCallService = this CallManager.registerCallback(callListener) From 2f9341dd33ed127d3fb743815913e021223858b4 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Mon, 20 Sep 2021 00:27:03 +0100 Subject: [PATCH 05/11] fix: add CallDurationHelper to keep track of call duration --- .../com/simplemobiletools/dialer/App.kt | 2 ++ .../dialer/activities/CallActivity.kt | 33 ++++++------------- .../dialer/helpers/CallDurationHelper.kt | 32 ++++++++++++++++++ .../dialer/services/CallService.kt | 9 +++++ 4 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallDurationHelper.kt diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/App.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/App.kt index 4f23dadaf..410409f2b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/App.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/App.kt @@ -2,8 +2,10 @@ package com.simplemobiletools.dialer import android.app.Application import com.simplemobiletools.commons.extensions.checkUseEnglish +import com.simplemobiletools.dialer.helpers.CallDurationHelper class App : Application() { + val callDurationHelper by lazy { CallDurationHelper() } override fun onCreate() { super.onCreate() checkUseEnglish() 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 5d8b4a216..4d6b3657f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt @@ -16,6 +16,7 @@ import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.MINUTE_SECONDS import com.simplemobiletools.commons.helpers.isOreoMr1Plus import com.simplemobiletools.commons.helpers.isOreoPlus +import com.simplemobiletools.dialer.App import com.simplemobiletools.dialer.R import com.simplemobiletools.dialer.extensions.addCharacter import com.simplemobiletools.dialer.extensions.audioManager @@ -24,8 +25,6 @@ import com.simplemobiletools.dialer.extensions.getHandleToUse import com.simplemobiletools.dialer.helpers.CallContactAvatarHelper import com.simplemobiletools.dialer.helpers.CallManager import com.simplemobiletools.dialer.models.CallContact -import java.util.Timer -import java.util.TimerTask import kotlinx.android.synthetic.main.activity_call.* import kotlinx.android.synthetic.main.dialpad.* @@ -41,11 +40,11 @@ class CallActivity : SimpleActivity() { private var isSpeakerOn = false private var isMicrophoneOn = true private var isCallEnded = false - private var callDuration = 0 private var callContact: CallContact? = null private var proximityWakeLock: PowerManager.WakeLock? = null - private var callTimer = Timer() + private var callDuration = 0 private val callContactAvatarHelper by lazy { CallContactAvatarHelper(this) } + private val callDurationHelper by lazy { (application as App).callDurationHelper } override fun onCreate(savedInstanceState: Bundle?) { supportActionBar?.hide() @@ -75,7 +74,6 @@ class CallActivity : SimpleActivity() { override fun onDestroy() { super.onDestroy() CallManager.unregisterCallback(callCallback) - callTimer.cancel() if (proximityWakeLock?.isHeld == true) { proximityWakeLock!!.release() } @@ -221,10 +219,6 @@ class CallActivity : SimpleActivity() { Call.STATE_SELECT_PHONE_ACCOUNT -> showPhoneAccountPicker() } - if (state == Call.STATE_DISCONNECTED || state == Call.STATE_DISCONNECTING) { - callTimer.cancel() - } - val statusTextId = when (state) { Call.STATE_RINGING -> R.string.is_calling Call.STATE_DIALING -> R.string.dialing @@ -254,9 +248,13 @@ class CallActivity : SimpleActivity() { initProximitySensor() incoming_call_holder.beGone() ongoing_call_holder.beVisible() - try { - callTimer.scheduleAtFixedRate(getCallTimerUpdateTask(), 1000, 1000) - } catch (ignored: Exception) { + callDurationHelper.onDurationChange { + callDuration = it + runOnUiThread { + if (!isCallEnded) { + call_status_label.text = callDuration.getFormattedDuration() + } + } } } @@ -298,17 +296,6 @@ class CallActivity : SimpleActivity() { } } - private fun getCallTimerUpdateTask() = object : TimerTask() { - override fun run() { - callDuration++ - runOnUiThread { - if (!isCallEnded) { - call_status_label.text = callDuration.getFormattedDuration() - } - } - } - } - private val callCallback = object : Call.Callback() { override fun onStateChanged(call: Call, state: Int) { super.onStateChanged(call, state) diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallDurationHelper.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallDurationHelper.kt new file mode 100644 index 000000000..6f8e15599 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallDurationHelper.kt @@ -0,0 +1,32 @@ +package com.simplemobiletools.dialer.helpers + +import java.util.Timer +import java.util.TimerTask + +class CallDurationHelper { + private var callTimer = Timer() + private var callDuration = 0 + private var callback: ((durationSecs: Int) -> Unit)? = null + + fun onDurationChange(callback: (durationSecs: Int) -> Unit) { + this.callback = callback + } + + fun start() { + try { + callTimer.scheduleAtFixedRate(getTimerUpdateTask(), 1000, 1000) + } catch (ignored: Exception) { + } + } + + fun cancel() { + callTimer.cancel() + } + + private fun getTimerUpdateTask() = object : TimerTask() { + override fun run() { + callDuration++ + callback?.invoke(callDuration) + } + } +} 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 0896ae284..e72d8c41c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt @@ -2,16 +2,24 @@ package com.simplemobiletools.dialer.services import android.telecom.Call import android.telecom.InCallService +import com.simplemobiletools.dialer.App import com.simplemobiletools.dialer.activities.CallActivity import com.simplemobiletools.dialer.helpers.CallManager import com.simplemobiletools.dialer.helpers.CallNotificationManager class CallService : InCallService() { private val callNotificationManager by lazy { CallNotificationManager(this) } + private val callDurationHelper by lazy { (application as App).callDurationHelper } + private val callListener = object : Call.Callback() { override fun onStateChanged(call: Call, state: Int) { super.onStateChanged(call, state) callNotificationManager.setupNotification() + if (state == Call.STATE_ACTIVE) { + callDurationHelper.start() + }else if (state == Call.STATE_DISCONNECTED || state == Call.STATE_DISCONNECTING) { + callDurationHelper.cancel() + } } } @@ -35,5 +43,6 @@ class CallService : InCallService() { super.onDestroy() CallManager.registerCallback(callListener) callNotificationManager.cancelNotification() + callDurationHelper.cancel() } } From 865cf4b8ae43b6b1909c29bb1fc7b2c5f7bad3c1 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Mon, 20 Sep 2021 00:33:13 +0100 Subject: [PATCH 06/11] fix: recreate timer on each start and reset callDuration --- .../dialer/helpers/CallDurationHelper.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallDurationHelper.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallDurationHelper.kt index 6f8e15599..129f9b839 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallDurationHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallDurationHelper.kt @@ -4,7 +4,7 @@ import java.util.Timer import java.util.TimerTask class CallDurationHelper { - private var callTimer = Timer() + private var callTimer: Timer? = null private var callDuration = 0 private var callback: ((durationSecs: Int) -> Unit)? = null @@ -14,13 +14,15 @@ class CallDurationHelper { fun start() { try { - callTimer.scheduleAtFixedRate(getTimerUpdateTask(), 1000, 1000) + callDuration = 0 + callTimer = Timer() + callTimer?.scheduleAtFixedRate(getTimerUpdateTask(), 1000, 1000) } catch (ignored: Exception) { } } fun cancel() { - callTimer.cancel() + callTimer?.cancel() } private fun getTimerUpdateTask() = object : TimerTask() { From 32e184dd67fe6fc9f18e145c060f84d615e5b75a Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Wed, 22 Sep 2021 23:23:35 +0200 Subject: [PATCH 07/11] removing a space --- .../com/simplemobiletools/dialer/activities/CallActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4d6b3657f..c33d974ce 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/activities/CallActivity.kt @@ -44,7 +44,7 @@ class CallActivity : SimpleActivity() { private var proximityWakeLock: PowerManager.WakeLock? = null private var callDuration = 0 private val callContactAvatarHelper by lazy { CallContactAvatarHelper(this) } - private val callDurationHelper by lazy { (application as App).callDurationHelper } + private val callDurationHelper by lazy { (application as App).callDurationHelper } override fun onCreate(savedInstanceState: Bundle?) { supportActionBar?.hide() From 683fa0a1db32da15c10b3254c771367050798188 Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Wed, 22 Sep 2021 23:24:07 +0200 Subject: [PATCH 08/11] fixing some spaces --- .../com/simplemobiletools/dialer/services/CallService.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 e72d8c41c..b8f42f8e2 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt @@ -9,7 +9,7 @@ import com.simplemobiletools.dialer.helpers.CallNotificationManager class CallService : InCallService() { private val callNotificationManager by lazy { CallNotificationManager(this) } - private val callDurationHelper by lazy { (application as App).callDurationHelper } + private val callDurationHelper by lazy { (application as App).callDurationHelper } private val callListener = object : Call.Callback() { override fun onStateChanged(call: Call, state: Int) { @@ -17,7 +17,7 @@ class CallService : InCallService() { callNotificationManager.setupNotification() if (state == Call.STATE_ACTIVE) { callDurationHelper.start() - }else if (state == Call.STATE_DISCONNECTED || state == Call.STATE_DISCONNECTING) { + } else if (state == Call.STATE_DISCONNECTED || state == Call.STATE_DISCONNECTING) { callDurationHelper.cancel() } } From 11c6bc9dee9aec76c4ec68c14dbad359244d3fd5 Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Wed, 22 Sep 2021 23:36:04 +0200 Subject: [PATCH 09/11] removing some magic numbers --- .../dialer/helpers/CallNotificationManager.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 b6fda71c1..2fd1b9c91 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/CallNotificationManager.kt @@ -20,6 +20,8 @@ import com.simplemobiletools.dialer.receivers.CallActionReceiver class CallNotificationManager(private val context: Context) { private val CALL_NOTIFICATION_ID = 1 + private val ACCEPT_CALL_CODE = 0 + private val DECLINE_CALL_CODE = 1 private val notificationManager = context.notificationManager private val callContactAvatarHelper = CallContactAvatarHelper(context) @@ -44,11 +46,11 @@ class CallNotificationManager(private val context: Context) { val acceptCallIntent = Intent(context, CallActionReceiver::class.java) acceptCallIntent.action = ACCEPT_CALL - val acceptPendingIntent = PendingIntent.getBroadcast(context, 0, acceptCallIntent, PendingIntent.FLAG_CANCEL_CURRENT) + val acceptPendingIntent = PendingIntent.getBroadcast(context, ACCEPT_CALL_CODE, acceptCallIntent, PendingIntent.FLAG_CANCEL_CURRENT) val declineCallIntent = Intent(context, CallActionReceiver::class.java) declineCallIntent.action = DECLINE_CALL - val declinePendingIntent = PendingIntent.getBroadcast(context, 1, declineCallIntent, PendingIntent.FLAG_CANCEL_CURRENT) + val declinePendingIntent = PendingIntent.getBroadcast(context, DECLINE_CALL_CODE, declineCallIntent, PendingIntent.FLAG_CANCEL_CURRENT) val callerName = if (callContact != null && callContact.name.isNotEmpty()) callContact.name else context.getString(R.string.unknown_caller) val contentTextId = when (callState) { From 3023881015668c4f17b776a9e1c0487f5dc94d88 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Fri, 24 Sep 2021 22:56:43 +0100 Subject: [PATCH 10/11] fix: do not show notification when call is ended --- .../com/simplemobiletools/dialer/services/CallService.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 b8f42f8e2..dc71a89e9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt @@ -14,7 +14,9 @@ class CallService : InCallService() { private val callListener = object : Call.Callback() { override fun onStateChanged(call: Call, state: Int) { super.onStateChanged(call, state) - callNotificationManager.setupNotification() + if(state != Call.STATE_DISCONNECTED){ + callNotificationManager.setupNotification() + } if (state == Call.STATE_ACTIVE) { callDurationHelper.start() } else if (state == Call.STATE_DISCONNECTED || state == Call.STATE_DISCONNECTING) { From 233fbcaf252e9272a500fb1ac2b1f1c91cfbe2df Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Sat, 25 Sep 2021 21:32:24 +0200 Subject: [PATCH 11/11] minor code style update --- .../com/simplemobiletools/dialer/services/CallService.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 dc71a89e9..83c5fb699 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/services/CallService.kt @@ -14,9 +14,10 @@ class CallService : InCallService() { private val callListener = object : Call.Callback() { override fun onStateChanged(call: Call, state: Int) { super.onStateChanged(call, state) - if(state != Call.STATE_DISCONNECTED){ + if (state != Call.STATE_DISCONNECTED) { callNotificationManager.setupNotification() } + if (state == Call.STATE_ACTIVE) { callDurationHelper.start() } else if (state == Call.STATE_DISCONNECTED || state == Call.STATE_DISCONNECTING) {