From 560b2f7d6fa3ddb8b5c348becbf2069b7ac33e41 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Tue, 18 Apr 2023 16:26:04 -0300 Subject: [PATCH] Utilize CallStyle for incoming and ongoing calls. --- .../service/webrtc/SignalCallManager.java | 4 +- .../securesms/util/ConversationUtil.java | 1 - .../webrtc/CallNotificationBuilder.java | 81 +++++++++---------- 3 files changed, 42 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java index 1a56f0764c..33239b661a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java @@ -9,7 +9,6 @@ import android.os.ResultReceiver; import androidx.annotation.AnyThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import com.annimon.stream.Stream; @@ -61,6 +60,7 @@ import org.thoughtcrime.securesms.util.RecipientAccessList; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.rx.RxStore; +import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder; import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager; import org.thoughtcrime.securesms.webrtc.locks.LockManager; import org.webrtc.PeerConnection; @@ -413,7 +413,7 @@ private void processStateless(@NonNull Function1= 29 && !ApplicationDependencies.getAppForegroundObserver().isForegrounded()) { + if (Build.VERSION.SDK_INT >= CallNotificationBuilder.API_LEVEL_CALL_STYLE) { return false; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java index ef315c3128..c20ca32d34 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java @@ -249,7 +249,6 @@ public final class ConversationUtil { /** * @return A Person object representing the given Recipient */ - @WorkerThread public static @NonNull Person buildPersonWithoutIcon(@NonNull Context context, @NonNull Recipient recipient) { return new Person.Builder() .setKey(getShortcutId(recipient.getId())) diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java index 185e9fa436..ee8cc6151a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java @@ -6,9 +6,7 @@ import android.content.Context; import android.content.Intent; import android.os.Build; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; -import androidx.annotation.StringRes; import androidx.core.app.NotificationCompat; import org.signal.core.util.PendingIntentFlags; @@ -19,12 +17,12 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.webrtc.WebRtcCallService; +import org.thoughtcrime.securesms.util.ConversationUtil; /** * Manages the state of the WebRtc items in the Android notification bar. * * @author Moxie Marlinspike - * */ public class CallNotificationBuilder { @@ -37,6 +35,17 @@ public class CallNotificationBuilder { public static final int TYPE_ESTABLISHED = 3; public static final int TYPE_INCOMING_CONNECTING = 4; + /** + * This is the API level at which call style notifications will + * properly pop over the screen and allow a user to answer a call. + *

+ * Older API levels will still render a notification with the proper + * actions, but since we want to ensure that they are able to answer + * the call without having to open the shade, we fall back on launching + * the activity (done so in SignalCallManager). + */ + public static final int API_LEVEL_CALL_STYLE = 29; + public static Notification getCallInProgressNotification(Context context, int type, Recipient recipient) { Intent contentIntent = new Intent(context, WebRtcCallActivity.class); contentIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); @@ -45,10 +54,10 @@ public class CallNotificationBuilder { PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, contentIntent, PendingIntentFlags.mutable()); NotificationCompat.Builder builder = new NotificationCompat.Builder(context, getNotificationChannel(type)) - .setSmallIcon(R.drawable.ic_call_secure_white_24dp) - .setContentIntent(pendingIntent) - .setOngoing(true) - .setContentTitle(recipient.getDisplayName(context)); + .setSmallIcon(R.drawable.ic_call_secure_white_24dp) + .setContentIntent(pendingIntent) + .setOngoing(true) + .setContentTitle(recipient.getDisplayName(context)); if (type == TYPE_INCOMING_CONNECTING) { builder.setContentText(context.getString(R.string.CallNotificationBuilder_connecting)); @@ -56,21 +65,27 @@ public class CallNotificationBuilder { builder.setContentIntent(null); } else if (type == TYPE_INCOMING_RINGING) { builder.setContentText(context.getString(recipient.isGroup() ? R.string.NotificationBarManager__incoming_signal_group_call : R.string.NotificationBarManager__incoming_signal_call)); - builder.addAction(getServiceNotificationAction(context, WebRtcCallService.denyCallIntent(context), R.drawable.ic_close_grey600_32dp, R.string.NotificationBarManager__decline_call)); - builder.addAction(getActivityNotificationAction(context, WebRtcCallActivity.ANSWER_ACTION, R.drawable.ic_phone_grey600_32dp, recipient.isGroup() ? R.string.NotificationBarManager__join_call : R.string.NotificationBarManager__answer_call)); + builder.setStyle(NotificationCompat.CallStyle.forIncomingCall( + ConversationUtil.buildPersonWithoutIcon(context, recipient), + getServicePendingIntent(context, WebRtcCallService.denyCallIntent(context)), + getActivityPendingIntent(context, WebRtcCallActivity.ANSWER_ACTION) + )); - if (callActivityRestricted()) { - builder.setFullScreenIntent(pendingIntent, true); - builder.setPriority(NotificationCompat.PRIORITY_HIGH); - builder.setCategory(NotificationCompat.CATEGORY_CALL); - } + builder.setPriority(NotificationCompat.PRIORITY_HIGH); + builder.setCategory(NotificationCompat.CATEGORY_CALL); } else if (type == TYPE_OUTGOING_RINGING) { builder.setContentText(context.getString(R.string.NotificationBarManager__establishing_signal_call)); builder.addAction(getServiceNotificationAction(context, WebRtcCallService.hangupIntent(context), R.drawable.ic_call_end_grey600_32dp, R.string.NotificationBarManager__cancel_call)); } else { builder.setContentText(context.getString(R.string.NotificationBarManager_signal_call_in_progress)); builder.setOnlyAlertOnce(true); - builder.addAction(getServiceNotificationAction(context, WebRtcCallService.hangupIntent(context), R.drawable.ic_call_end_grey600_32dp, R.string.NotificationBarManager__end_call)); + builder.setStyle(NotificationCompat.CallStyle.forOngoingCall( + ConversationUtil.buildPersonWithoutIcon(context, recipient), + getServicePendingIntent(context, WebRtcCallService.hangupIntent(context)) + )); + + builder.setPriority(NotificationCompat.PRIORITY_HIGH); + builder.setCategory(NotificationCompat.CATEGORY_CALL); } return builder.build(); @@ -84,20 +99,6 @@ public class CallNotificationBuilder { } } - public static @NonNull Notification getStartingNotification(@NonNull Context context) { - Intent contentIntent = new Intent(context, MainActivity.class); - contentIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - - PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, contentIntent, PendingIntentFlags.mutable()); - - return new NotificationCompat.Builder(context, NotificationChannels.getInstance().CALL_STATUS).setSmallIcon(R.drawable.ic_call_secure_white_24dp) - .setContentIntent(pendingIntent) - .setOngoing(true) - .setContentTitle(context.getString(R.string.NotificationBarManager__starting_signal_call_service)) - .setPriority(NotificationCompat.PRIORITY_MIN) - .build(); - } - public static @NonNull Notification getStoppingNotification(@NonNull Context context) { Intent contentIntent = new Intent(context, MainActivity.class); contentIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); @@ -129,25 +130,23 @@ public class CallNotificationBuilder { } } - private static NotificationCompat.Action getServiceNotificationAction(Context context, Intent intent, int iconResId, int titleResId) { - PendingIntent pendingIntent = Build.VERSION.SDK_INT >= 26 ? PendingIntent.getForegroundService(context, 0, intent, PendingIntentFlags.mutable()) - : PendingIntent.getService(context, 0, intent, PendingIntentFlags.mutable()); - - return new NotificationCompat.Action(iconResId, context.getString(titleResId), pendingIntent); + private static PendingIntent getServicePendingIntent(@NonNull Context context, @NonNull Intent intent) { + return Build.VERSION.SDK_INT >= 26 ? PendingIntent.getForegroundService(context, 0, intent, PendingIntentFlags.mutable()) + : PendingIntent.getService(context, 0, intent, PendingIntentFlags.mutable()); } - private static NotificationCompat.Action getActivityNotificationAction(@NonNull Context context, @NonNull String action, - @DrawableRes int iconResId, @StringRes int titleResId) - { + private static NotificationCompat.Action getServiceNotificationAction(Context context, Intent intent, int iconResId, int titleResId) { + return new NotificationCompat.Action(iconResId, context.getString(titleResId), getServicePendingIntent(context, intent)); + } + + private static PendingIntent getActivityPendingIntent(@NonNull Context context, @NonNull String action) { Intent intent = new Intent(context, WebRtcCallActivity.class); intent.setAction(action); - PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntentFlags.mutable()); - - return new NotificationCompat.Action(iconResId, context.getString(titleResId), pendingIntent); + return PendingIntent.getActivity(context, 0, intent, PendingIntentFlags.mutable()); } private static boolean callActivityRestricted() { - return Build.VERSION.SDK_INT >= 29 && !ApplicationDependencies.getAppForegroundObserver().isForegrounded(); + return Build.VERSION.SDK_INT >= API_LEVEL_CALL_STYLE; } }