mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 12:38:33 +00:00
Ensure lower api levels do not try to use Uri based IconCompat.
This commit is contained in:
@@ -274,7 +274,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||||||
val self: PersonCompat = PersonCompat.Builder()
|
val self: PersonCompat = PersonCompat.Builder()
|
||||||
.setBot(false)
|
.setBot(false)
|
||||||
.setName(if (includeShortcut) Recipient.self().getDisplayName(context) else context.getString(R.string.SingleRecipientNotificationBuilder_you))
|
.setName(if (includeShortcut) Recipient.self().getDisplayName(context) else context.getString(R.string.SingleRecipientNotificationBuilder_you))
|
||||||
.setIcon(AvatarUtil.getIconWithUriForNotification(Recipient.self().id))
|
.setIcon(AvatarUtil.getIconCompat(context, Recipient.self()))
|
||||||
.setKey(ConversationUtil.getShortcutId(Recipient.self().id))
|
.setKey(ConversationUtil.getShortcutId(Recipient.self().id))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
@@ -290,7 +290,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||||||
.setBot(false)
|
.setBot(false)
|
||||||
.setName(notificationItem.getPersonName(context))
|
.setName(notificationItem.getPersonName(context))
|
||||||
.setUri(notificationItem.getPersonUri())
|
.setUri(notificationItem.getPersonUri())
|
||||||
.setIcon(notificationItem.getPersonIcon())
|
.setIcon(notificationItem.getPersonIcon(context))
|
||||||
|
|
||||||
if (includeShortcut) {
|
if (includeShortcut) {
|
||||||
personBuilder.setKey(ConversationUtil.getShortcutId(notificationItem.authorRecipient))
|
personBuilder.setKey(ConversationUtil.getShortcutId(notificationItem.authorRecipient))
|
||||||
@@ -360,7 +360,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
val bubbleMetadata = NotificationCompat.BubbleMetadata.Builder(intent, AvatarUtil.getIconCompatForShortcut(context, conversation.recipient))
|
val bubbleMetadata = NotificationCompat.BubbleMetadata.Builder(intent, AvatarUtil.getIconCompat(context, conversation.recipient))
|
||||||
.setAutoExpandBubble(bubbleState === BubbleUtil.BubbleState.SHOWN)
|
.setAutoExpandBubble(bubbleState === BubbleUtil.BubbleState.SHOWN)
|
||||||
.setDesiredHeight(600)
|
.setDesiredHeight(600)
|
||||||
.setSuppressNotification(bubbleState === BubbleUtil.BubbleState.SHOWN)
|
.setSuppressNotification(bubbleState === BubbleUtil.BubbleState.SHOWN)
|
||||||
|
|||||||
@@ -123,9 +123,9 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPersonIcon(): IconCompat? {
|
fun getPersonIcon(context: Context): IconCompat? {
|
||||||
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||||
AvatarUtil.getIconWithUriForNotification(authorRecipient.id)
|
AvatarUtil.getIconCompat(context, authorRecipient)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.signal.core.util.ThreadUtil;
|
import org.signal.core.util.ThreadUtil;
|
||||||
|
import org.signal.core.util.concurrent.SignalExecutors;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.jobs.ForegroundServiceUtil;
|
import org.thoughtcrime.securesms.jobs.ForegroundServiceUtil;
|
||||||
@@ -33,8 +34,14 @@ import org.thoughtcrime.securesms.webrtc.locks.LockManager;
|
|||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a foreground service for {@link SignalCallManager} to leverage to run in the background when necessary. Also
|
* Provide a foreground service for {@link SignalCallManager} to leverage to run in the background when necessary. Also
|
||||||
* provides devices listeners needed for during a call (i.e., bluetooth, power button).
|
* provides devices listeners needed for during a call (i.e., bluetooth, power button).
|
||||||
@@ -62,6 +69,7 @@ public final class WebRtcCallService extends Service implements SignalAudioManag
|
|||||||
private static final long FOREGROUND_SERVICE_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
|
private static final long FOREGROUND_SERVICE_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
|
||||||
|
|
||||||
private final WebSocketKeepAliveTask webSocketKeepAliveTask = new WebSocketKeepAliveTask();
|
private final WebSocketKeepAliveTask webSocketKeepAliveTask = new WebSocketKeepAliveTask();
|
||||||
|
private final Executor singleThreadExecutor = SignalExecutors.newCachedSingleThreadExecutor("signal-webrtc-in-call", ThreadUtil.PRIORITY_IMPORTANT_BACKGROUND_THREAD);
|
||||||
|
|
||||||
private SignalCallManager callManager;
|
private SignalCallManager callManager;
|
||||||
|
|
||||||
@@ -72,7 +80,9 @@ public final class WebRtcCallService extends Service implements SignalAudioManag
|
|||||||
private SignalAudioManager signalAudioManager;
|
private SignalAudioManager signalAudioManager;
|
||||||
private int lastNotificationId;
|
private int lastNotificationId;
|
||||||
private Notification lastNotification;
|
private Notification lastNotification;
|
||||||
private boolean stopping = false;
|
private long lastNotificationRequestTime;
|
||||||
|
private Disposable lastNotificationDisposable = Disposable.disposed();
|
||||||
|
private boolean stopping = false;
|
||||||
|
|
||||||
public static void update(@NonNull Context context, int type, @NonNull RecipientId recipientId, boolean isVideoCall) {
|
public static void update(@NonNull Context context, int type, @NonNull RecipientId recipientId, boolean isVideoCall) {
|
||||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||||
@@ -219,6 +229,7 @@ public final class WebRtcCallService extends Service implements SignalAudioManag
|
|||||||
private void setCallNotification() {
|
private void setCallNotification() {
|
||||||
setCallNotification(false);
|
setCallNotification(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCallNotification(boolean stopping) {
|
private void setCallNotification(boolean stopping) {
|
||||||
if (!stopping && lastNotificationId != INVALID_NOTIFICATION_ID) {
|
if (!stopping && lastNotificationId != INVALID_NOTIFICATION_ID) {
|
||||||
startForegroundCompat(lastNotificationId, lastNotification);
|
startForegroundCompat(lastNotificationId, lastNotification);
|
||||||
@@ -230,10 +241,28 @@ public final class WebRtcCallService extends Service implements SignalAudioManag
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setCallInProgressNotification(int type, @NonNull RecipientId id, boolean isVideoCall) {
|
public void setCallInProgressNotification(int type, @NonNull RecipientId id, boolean isVideoCall) {
|
||||||
|
lastNotificationDisposable.dispose();
|
||||||
|
|
||||||
|
boolean requiresAsyncNotificationLoad = Build.VERSION.SDK_INT <= 29;
|
||||||
|
|
||||||
lastNotificationId = CallNotificationBuilder.getNotificationId(type);
|
lastNotificationId = CallNotificationBuilder.getNotificationId(type);
|
||||||
lastNotification = CallNotificationBuilder.getCallInProgressNotification(this, type, Recipient.resolved(id), isVideoCall);
|
lastNotification = CallNotificationBuilder.getCallInProgressNotification(this, type, Recipient.resolved(id), isVideoCall, requiresAsyncNotificationLoad);
|
||||||
|
|
||||||
startForegroundCompat(lastNotificationId, lastNotification);
|
startForegroundCompat(lastNotificationId, lastNotification);
|
||||||
|
|
||||||
|
if (requiresAsyncNotificationLoad) {
|
||||||
|
final long requestTime = System.currentTimeMillis();
|
||||||
|
lastNotificationRequestTime = requestTime;
|
||||||
|
lastNotificationDisposable = Single
|
||||||
|
.fromCallable(() -> CallNotificationBuilder.getCallInProgressNotification(this, type, Recipient.resolved(id), isVideoCall, false))
|
||||||
|
.subscribeOn(Schedulers.from(singleThreadExecutor))
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.filter(unused -> requestTime == lastNotificationRequestTime && !stopping)
|
||||||
|
.subscribe(notification -> {
|
||||||
|
lastNotification = notification;
|
||||||
|
startForegroundCompat(lastNotificationId, lastNotification);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void startForegroundCompat(int notificationId, Notification notification) {
|
private synchronized void startForegroundCompat(int notificationId, Notification notification) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import com.bumptech.glide.request.target.CustomTarget;
|
|||||||
import com.bumptech.glide.request.target.CustomViewTarget;
|
import com.bumptech.glide.request.target.CustomViewTarget;
|
||||||
import com.bumptech.glide.request.transition.Transition;
|
import com.bumptech.glide.request.transition.Transition;
|
||||||
|
|
||||||
import org.signal.core.util.concurrent.SignalExecutors;
|
import org.signal.core.util.ThreadUtil;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||||
@@ -30,10 +30,11 @@ import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
|||||||
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
|
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequest;
|
import org.thoughtcrime.securesms.mms.GlideRequest;
|
||||||
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.providers.AvatarProvider;
|
import org.thoughtcrime.securesms.providers.AvatarProvider;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@@ -91,7 +92,7 @@ public final class AvatarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void loadIconIntoImageView(@NonNull Recipient recipient, @NonNull ImageView target, int requestedSize) {
|
public static void loadIconIntoImageView(@NonNull Recipient recipient, @NonNull ImageView target, int requestedSize) {
|
||||||
Context context = target.getContext();
|
Context context = target.getContext();
|
||||||
|
|
||||||
requestCircle(GlideApp.with(context).asDrawable(), context, recipient, requestedSize).into(target);
|
requestCircle(GlideApp.with(context).asDrawable(), context, recipient, requestedSize).into(target);
|
||||||
}
|
}
|
||||||
@@ -103,23 +104,18 @@ public final class AvatarUtil {
|
|||||||
throws ExecutionException, InterruptedException
|
throws ExecutionException, InterruptedException
|
||||||
{
|
{
|
||||||
return requestSquare(GlideApp.with(context).asBitmap(), context, recipient)
|
return requestSquare(GlideApp.with(context).asBitmap(), context, recipient)
|
||||||
.skipMemoryCache(true)
|
.skipMemoryCache(true)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
.submit(width, height)
|
.submit(width, height)
|
||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static IconCompat getIconWithUriForNotification(@NonNull RecipientId recipientId) {
|
public static @NonNull IconCompat getIconCompat(@NonNull Context context, @NonNull Recipient recipient) {
|
||||||
return IconCompat.createWithContentUri(AvatarProvider.getContentUri(recipientId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@WorkerThread
|
|
||||||
public static @NonNull IconCompat getIconCompatForShortcut(@NonNull Context context, @NonNull Recipient recipient) {
|
|
||||||
if (Build.VERSION.SDK_INT > 29) {
|
if (Build.VERSION.SDK_INT > 29) {
|
||||||
return getIconWithUriForNotification(recipient.getId());
|
return IconCompat.createWithContentUri(AvatarProvider.getContentUri(recipient.getId()));
|
||||||
} else {
|
} else {
|
||||||
return IconCompat.createWithBitmap(getBitmapForNotification(context, recipient));
|
return IconCompat.createWithBitmap(getBitmapForNotification(context, recipient, DrawableUtil.SHORTCUT_INFO_WRAPPED_SIZE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,17 +125,19 @@ public final class AvatarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static Bitmap getBitmapForNotification(@NonNull Context context, @NonNull Recipient recipient, int size) {
|
public static @NonNull Bitmap getBitmapForNotification(@NonNull Context context, @NonNull Recipient recipient, int size) {
|
||||||
|
ThreadUtil.assertNotMainThread();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AvatarTarget avatarTarget = new AvatarTarget(size);
|
AvatarTarget avatarTarget = new AvatarTarget(size);
|
||||||
|
GlideRequests glideRequests = GlideApp.with(context);
|
||||||
|
|
||||||
SignalExecutors.BOUNDED_IO.submit(() -> {
|
requestCircle(glideRequests.asBitmap(), context, recipient, size).into(avatarTarget);
|
||||||
requestCircle(GlideApp.with(context).asBitmap(), context, recipient, size).into(avatarTarget);
|
|
||||||
});
|
|
||||||
|
|
||||||
return avatarTarget.await();
|
Bitmap bitmap = avatarTarget.await();
|
||||||
|
return Objects.requireNonNullElseGet(bitmap, () -> DrawableUtil.toBitmap(getFallback(context, recipient, size), size, size));
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
return null;
|
return DrawableUtil.toBitmap(getFallback(context, recipient, size), size, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +154,7 @@ public final class AvatarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static <T> GlideRequest<T> request(@NonNull GlideRequest<T> glideRequest, @NonNull Context context, @NonNull Recipient recipient, boolean loadSelf, int targetSize, @Nullable BitmapTransformation transformation) {
|
private static <T> GlideRequest<T> request(@NonNull GlideRequest<T> glideRequest, @NonNull Context context, @NonNull Recipient recipient, boolean loadSelf, int targetSize, @Nullable BitmapTransformation transformation) {
|
||||||
|
|
||||||
final ContactPhoto photo;
|
final ContactPhoto photo;
|
||||||
if (Recipient.self().equals(recipient) && loadSelf) {
|
if (Recipient.self().equals(recipient) && loadSelf) {
|
||||||
photo = new ProfileContactPhoto(recipient);
|
photo = new ProfileContactPhoto(recipient);
|
||||||
@@ -163,10 +162,11 @@ public final class AvatarUtil {
|
|||||||
photo = recipient.getContactPhoto();
|
photo = recipient.getContactPhoto();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int size = targetSize == -1 ? DrawableUtil.SHORTCUT_INFO_WRAPPED_SIZE : targetSize;
|
||||||
final GlideRequest<T> request = glideRequest.load(photo)
|
final GlideRequest<T> request = glideRequest.load(photo)
|
||||||
.error(getFallback(context, recipient, targetSize))
|
.error(getFallback(context, recipient, size))
|
||||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||||
.override(targetSize);
|
.override(size);
|
||||||
|
|
||||||
if (recipient.shouldBlurAvatar()) {
|
if (recipient.shouldBlurAvatar()) {
|
||||||
BlurTransformation blur = new BlurTransformation(context, 0.25f, BlurTransformation.MAX_RADIUS);
|
BlurTransformation blur = new BlurTransformation(context, 0.25f, BlurTransformation.MAX_RADIUS);
|
||||||
@@ -203,7 +203,6 @@ public final class AvatarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Bitmap await() throws InterruptedException {
|
public @Nullable Bitmap await() throws InterruptedException {
|
||||||
Log.d(TAG, "AvatarTarget#await:");
|
|
||||||
if (countDownLatch.await(1, TimeUnit.SECONDS)) {
|
if (countDownLatch.await(1, TimeUnit.SECONDS)) {
|
||||||
return bitmap.get();
|
return bitmap.get();
|
||||||
} else {
|
} else {
|
||||||
@@ -212,17 +211,28 @@ public final class AvatarUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
Log.d(TAG, "AvatarTarget: onDestroy");
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadStarted(@Nullable Drawable placeholder) {
|
||||||
|
Log.d(TAG, "AvatarTarget: onLoadStarted");
|
||||||
|
super.onLoadStarted(placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
|
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
|
||||||
Log.d(TAG, "AvatarTarget#onResourceReady: " + resource.getWidth() + ", " + resource.getHeight() + ", s:" + size);
|
Log.d(TAG, "AvatarTarget: onResourceReady");
|
||||||
bitmap.set(resource);
|
bitmap.set(resource);
|
||||||
countDownLatch.countDown();
|
countDownLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadFailed(@Nullable Drawable errorDrawable) {
|
public void onLoadFailed(@Nullable Drawable errorDrawable) {
|
||||||
Log.d(TAG, "AvatarTarget#onLoadFailed:");
|
Log.d(TAG, "AvatarTarget: onLoadFailed");
|
||||||
|
|
||||||
if (errorDrawable == null) {
|
if (errorDrawable == null) {
|
||||||
throw new AssertionError("Expected an error drawable.");
|
throw new AssertionError("Expected an error drawable.");
|
||||||
}
|
}
|
||||||
@@ -234,8 +244,7 @@ public final class AvatarUtil {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadCleared(@Nullable Drawable placeholder) {
|
public void onLoadCleared(@Nullable Drawable placeholder) {
|
||||||
Log.d(TAG, "AvatarTarget#onLoadCleared:");
|
Log.d(TAG, "AvatarTarget: onLoadCleared");
|
||||||
|
|
||||||
bitmap.set(null);
|
bitmap.set(null);
|
||||||
countDownLatch.countDown();
|
countDownLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ public final class ConversationUtil {
|
|||||||
.setIntent(ConversationIntents.createBuilderSync(context, resolved.getId(), threadId).build())
|
.setIntent(ConversationIntents.createBuilderSync(context, resolved.getId(), threadId).build())
|
||||||
.setShortLabel(shortName)
|
.setShortLabel(shortName)
|
||||||
.setLongLabel(longName)
|
.setLongLabel(longName)
|
||||||
.setIcon(AvatarUtil.getIconCompatForShortcut(context, resolved))
|
.setIcon(AvatarUtil.getIconCompat(context, resolved))
|
||||||
.setPersons(persons)
|
.setPersons(persons)
|
||||||
.setCategories(Sets.newHashSet(CATEGORY_SHARE_TARGET))
|
.setCategories(Sets.newHashSet(CATEGORY_SHARE_TARGET))
|
||||||
.setActivity(activity)
|
.setActivity(activity)
|
||||||
@@ -286,11 +286,12 @@ public final class ConversationUtil {
|
|||||||
/**
|
/**
|
||||||
* @return A Compat Library Person object representing the given Recipient
|
* @return A Compat Library Person object representing the given Recipient
|
||||||
*/
|
*/
|
||||||
|
@WorkerThread
|
||||||
public static @NonNull Person buildPerson(@NonNull Context context, @NonNull Recipient recipient) {
|
public static @NonNull Person buildPerson(@NonNull Context context, @NonNull Recipient recipient) {
|
||||||
return new Person.Builder()
|
return new Person.Builder()
|
||||||
.setKey(getShortcutId(recipient.getId()))
|
.setKey(getShortcutId(recipient.getId()))
|
||||||
.setName(recipient.getDisplayName(context))
|
.setName(recipient.getDisplayName(context))
|
||||||
.setIcon(AvatarUtil.getIconWithUriForNotification(recipient.getId()))
|
.setIcon(AvatarUtil.getIconCompat(context, recipient))
|
||||||
.setUri(recipient.isSystemContact() ? recipient.getContactUri().toString() : null)
|
.setUri(recipient.isSystemContact() ? recipient.getContactUri().toString() : null)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
@@ -36,13 +37,22 @@ public class CallNotificationBuilder {
|
|||||||
public static final int TYPE_ESTABLISHED = 3;
|
public static final int TYPE_ESTABLISHED = 3;
|
||||||
public static final int TYPE_INCOMING_CONNECTING = 4;
|
public static final int TYPE_INCOMING_CONNECTING = 4;
|
||||||
|
|
||||||
|
@IntDef(value = {
|
||||||
|
TYPE_INCOMING_RINGING,
|
||||||
|
TYPE_OUTGOING_RINGING,
|
||||||
|
TYPE_ESTABLISHED,
|
||||||
|
TYPE_INCOMING_CONNECTING
|
||||||
|
})
|
||||||
|
public @interface CallNotificationType {
|
||||||
|
}
|
||||||
|
|
||||||
private enum LaunchCallScreenIntentState {
|
private enum LaunchCallScreenIntentState {
|
||||||
CONTENT(null, 0),
|
CONTENT(null, 0),
|
||||||
AUDIO(WebRtcCallActivity.ANSWER_ACTION, 1),
|
AUDIO(WebRtcCallActivity.ANSWER_ACTION, 1),
|
||||||
VIDEO(WebRtcCallActivity.ANSWER_VIDEO_ACTION, 2);
|
VIDEO(WebRtcCallActivity.ANSWER_VIDEO_ACTION, 2);
|
||||||
|
|
||||||
final @Nullable String action;
|
final @Nullable String action;
|
||||||
final int requestCode;
|
final int requestCode;
|
||||||
|
|
||||||
LaunchCallScreenIntentState(@Nullable String action, int requestCode) {
|
LaunchCallScreenIntentState(@Nullable String action, int requestCode) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
@@ -61,9 +71,25 @@ public class CallNotificationBuilder {
|
|||||||
*/
|
*/
|
||||||
public static final int API_LEVEL_CALL_STYLE = 29;
|
public static final int API_LEVEL_CALL_STYLE = 29;
|
||||||
|
|
||||||
public static Notification getCallInProgressNotification(Context context, int type, Recipient recipient, boolean isVideoCall) {
|
/**
|
||||||
PendingIntent pendingIntent = getActivityPendingIntent(context, LaunchCallScreenIntentState.CONTENT);
|
* Gets the Notification for the current in-progress call.
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, getNotificationChannel(type))
|
*
|
||||||
|
* @param context Context, normally the service requesting this notification
|
||||||
|
* @param type The type of notification desired
|
||||||
|
* @param recipient The target of the call (group, call link, or 1:1 recipient)
|
||||||
|
* @param isVideoCall Whether the call is a video call
|
||||||
|
* @param skipPersonIcon Whether to skip loading the icon for a person, used to avoid blocking the UI thread on older apis.
|
||||||
|
*/
|
||||||
|
public static Notification getCallInProgressNotification(
|
||||||
|
Context context,
|
||||||
|
@CallNotificationType int type,
|
||||||
|
Recipient recipient,
|
||||||
|
boolean isVideoCall,
|
||||||
|
boolean skipPersonIcon
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PendingIntent pendingIntent = getActivityPendingIntent(context, LaunchCallScreenIntentState.CONTENT);
|
||||||
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, getNotificationChannel(type))
|
||||||
.setSmallIcon(R.drawable.ic_call_secure_white_24dp)
|
.setSmallIcon(R.drawable.ic_call_secure_white_24dp)
|
||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
@@ -80,7 +106,9 @@ public class CallNotificationBuilder {
|
|||||||
builder.setCategory(NotificationCompat.CATEGORY_CALL);
|
builder.setCategory(NotificationCompat.CATEGORY_CALL);
|
||||||
builder.setFullScreenIntent(pendingIntent, true);
|
builder.setFullScreenIntent(pendingIntent, true);
|
||||||
|
|
||||||
Person person = ConversationUtil.buildPerson(context, recipient);
|
Person person = skipPersonIcon ? ConversationUtil.buildPersonWithoutIcon(context, recipient)
|
||||||
|
: ConversationUtil.buildPerson(context.getApplicationContext(), recipient);
|
||||||
|
|
||||||
builder.addPerson(person);
|
builder.addPerson(person);
|
||||||
|
|
||||||
if (deviceVersionSupportsIncomingCallStyle()) {
|
if (deviceVersionSupportsIncomingCallStyle()) {
|
||||||
@@ -102,7 +130,9 @@ public class CallNotificationBuilder {
|
|||||||
builder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
|
builder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
|
||||||
builder.setCategory(NotificationCompat.CATEGORY_CALL);
|
builder.setCategory(NotificationCompat.CATEGORY_CALL);
|
||||||
|
|
||||||
Person person = ConversationUtil.buildPerson(context, recipient);
|
Person person = skipPersonIcon ? ConversationUtil.buildPersonWithoutIcon(context, recipient)
|
||||||
|
: ConversationUtil.buildPerson(context.getApplicationContext(), recipient);
|
||||||
|
|
||||||
builder.addPerson(person);
|
builder.addPerson(person);
|
||||||
|
|
||||||
if (deviceVersionSupportsIncomingCallStyle()) {
|
if (deviceVersionSupportsIncomingCallStyle()) {
|
||||||
@@ -126,11 +156,11 @@ public class CallNotificationBuilder {
|
|||||||
|
|
||||||
public static @NonNull Notification getStartingNotification(@NonNull Context context) {
|
public static @NonNull Notification getStartingNotification(@NonNull Context context) {
|
||||||
return new NotificationCompat.Builder(context, NotificationChannels.getInstance().CALL_STATUS)
|
return new NotificationCompat.Builder(context, NotificationChannels.getInstance().CALL_STATUS)
|
||||||
.setSmallIcon(R.drawable.ic_call_secure_white_24dp)
|
.setSmallIcon(R.drawable.ic_call_secure_white_24dp)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setContentTitle(context.getString(R.string.NotificationBarManager__starting_signal_call_service))
|
.setContentTitle(context.getString(R.string.NotificationBarManager__starting_signal_call_service))
|
||||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull Notification getStoppingNotification(@NonNull Context context) {
|
public static @NonNull Notification getStoppingNotification(@NonNull Context context) {
|
||||||
|
|||||||
Reference in New Issue
Block a user