Utilize CallStyle for incoming and ongoing calls.

This commit is contained in:
Alex Hart
2023-04-18 16:26:04 -03:00
committed by Cody Henthorne
parent 8260be4bff
commit 560b2f7d6f
3 changed files with 42 additions and 44 deletions

View File

@@ -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<WebRtcEphemeralState, WebRtcEph
}
public boolean startCallCardActivityIfPossible() {
if (Build.VERSION.SDK_INT >= 29 && !ApplicationDependencies.getAppForegroundObserver().isForegrounded()) {
if (Build.VERSION.SDK_INT >= CallNotificationBuilder.API_LEVEL_CALL_STYLE) {
return false;
}

View File

@@ -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()))

View File

@@ -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.
* <p>
* 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;
}
}