mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-03 23:15:44 +01:00
Fix wallpaper ANR regression while maintaining correct incoming message bubble colors.
This commit is contained in:
committed by
Cody Henthorne
parent
01705459cf
commit
629b96dd20
@@ -13,12 +13,9 @@ import org.signal.core.models.UriSerializer
|
||||
import org.signal.core.models.media.Media
|
||||
import org.thoughtcrime.securesms.badges.models.Badge
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents.ConversationScreenType
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColors
|
||||
import org.thoughtcrime.securesms.mms.SlideFactory
|
||||
import org.thoughtcrime.securesms.recipients.Recipient.Companion.resolved
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
|
||||
|
||||
@Serializable
|
||||
@Parcelize
|
||||
@@ -38,19 +35,12 @@ data class ConversationArgs(
|
||||
val giftBadge: Badge?,
|
||||
val shareDataTimestamp: Long,
|
||||
val conversationScreenType: ConversationScreenType,
|
||||
val isIncognito: Boolean = false
|
||||
val isIncognito: Boolean = false,
|
||||
val hasWallpaper: Boolean = false
|
||||
) : Parcelable {
|
||||
@IgnoredOnParcel
|
||||
val draftMediaType: SlideFactory.MediaType? = SlideFactory.MediaType.from(draftContentType)
|
||||
|
||||
@IgnoredOnParcel
|
||||
val wallpaper: ChatWallpaper?
|
||||
get() = resolved(recipientId).wallpaper
|
||||
|
||||
@IgnoredOnParcel
|
||||
val chatColors: ChatColors
|
||||
get() = resolved(recipientId).chatColors
|
||||
|
||||
fun canInitializeFromDatabase(): Boolean {
|
||||
return draftText == null && (draftMedia == null || ConversationIntents.isBubbleIntentUri(draftMedia) || ConversationIntents.isNotificationIntentUri(draftMedia)) && draftMediaType == null
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.badges.models.Badge;
|
||||
import org.signal.core.models.media.Media;
|
||||
import org.thoughtcrime.securesms.MainActivity;
|
||||
import org.thoughtcrime.securesms.badges.models.Badge;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||
import org.signal.core.models.media.Media;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||
@@ -48,6 +48,7 @@ public class ConversationIntents {
|
||||
private static final String EXTRA_SHARE_DATA_TIMESTAMP = "share_data_timestamp";
|
||||
private static final String EXTRA_CONVERSATION_TYPE = "conversation_type";
|
||||
private static final String EXTRA_INCOGNITO = "incognito";
|
||||
private static final String EXTRA_HAS_WALLPAPER = "has_wallpaper";
|
||||
private static final String INTENT_DATA = "intent_data";
|
||||
private static final String INTENT_TYPE = "intent_type";
|
||||
|
||||
@@ -75,12 +76,15 @@ public class ConversationIntents {
|
||||
}
|
||||
}
|
||||
|
||||
public static @NonNull Builder createPopUpBuilder(@NonNull Context context, @NonNull RecipientId recipientId, long threadId) {
|
||||
return new Builder(context, ConversationPopupActivity.class, recipientId, threadId, ConversationScreenType.POPUP);
|
||||
public static @NonNull Builder createPopUpBuilder(@NonNull Context context, @NonNull RecipientId recipientId, long threadId, boolean hasWallpaper) {
|
||||
return new Builder(context, ConversationPopupActivity.class, recipientId, threadId, ConversationScreenType.POPUP)
|
||||
.withHasWallpaper(hasWallpaper);
|
||||
}
|
||||
|
||||
public static @NonNull Intent createBubbleIntent(@NonNull Context context, @NonNull RecipientId recipientId, long threadId) {
|
||||
return new Builder(context, BubbleConversationActivity.class, recipientId, threadId, ConversationScreenType.BUBBLE).build();
|
||||
public static @NonNull Intent createBubbleIntent(@NonNull Context context, @NonNull RecipientId recipientId, long threadId, boolean hasWallpaper) {
|
||||
return new Builder(context, BubbleConversationActivity.class, recipientId, threadId, ConversationScreenType.BUBBLE)
|
||||
.withHasWallpaper(hasWallpaper)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,7 +160,9 @@ public class ConversationIntents {
|
||||
null,
|
||||
-1L,
|
||||
ConversationScreenType.BUBBLE,
|
||||
false);
|
||||
false,
|
||||
Boolean.parseBoolean(intentDataUri.getQueryParameter(EXTRA_HAS_WALLPAPER))
|
||||
);
|
||||
}
|
||||
|
||||
return new ConversationArgs(RecipientId.from(Objects.requireNonNull(arguments.getString(EXTRA_RECIPIENT))),
|
||||
@@ -174,7 +180,8 @@ public class ConversationIntents {
|
||||
arguments.getParcelable(EXTRA_GIFT_BADGE),
|
||||
arguments.getLong(EXTRA_SHARE_DATA_TIMESTAMP, -1L),
|
||||
ConversationScreenType.from(arguments.getInt(EXTRA_CONVERSATION_TYPE, 0)),
|
||||
arguments.getBoolean(EXTRA_INCOGNITO, false));
|
||||
arguments.getBoolean(EXTRA_INCOGNITO, false),
|
||||
arguments.getBoolean(EXTRA_HAS_WALLPAPER, false));
|
||||
}
|
||||
|
||||
public final static class Builder {
|
||||
@@ -197,6 +204,7 @@ public class ConversationIntents {
|
||||
private Badge giftBadge;
|
||||
private long shareDataTimestamp = -1L;
|
||||
private boolean incognito;
|
||||
private boolean hasWallpaper;
|
||||
private int flags;
|
||||
|
||||
private Builder(@NonNull Context context,
|
||||
@@ -226,6 +234,7 @@ public class ConversationIntents {
|
||||
giftBadge = args.getGiftBadge();
|
||||
shareDataTimestamp = args.getShareDataTimestamp();
|
||||
incognito = args.isIncognito();
|
||||
hasWallpaper = args.getHasWallpaper();
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -295,6 +304,11 @@ public class ConversationIntents {
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NonNull Builder withHasWallpaper(boolean hasWallpaper) {
|
||||
this.hasWallpaper = hasWallpaper;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NonNull Builder withFlags(int flags) {
|
||||
this.flags = flags;
|
||||
return this;
|
||||
@@ -317,7 +331,8 @@ public class ConversationIntents {
|
||||
giftBadge,
|
||||
shareDataTimestamp,
|
||||
conversationScreenType,
|
||||
incognito
|
||||
incognito,
|
||||
hasWallpaper
|
||||
);
|
||||
}
|
||||
|
||||
@@ -337,6 +352,7 @@ public class ConversationIntents {
|
||||
intent.setData(new Uri.Builder().authority(BUBBLE_AUTHORITY)
|
||||
.appendQueryParameter(EXTRA_RECIPIENT, recipientId.serialize())
|
||||
.appendQueryParameter(EXTRA_THREAD_ID, String.valueOf(threadId))
|
||||
.appendQueryParameter(EXTRA_HAS_WALLPAPER, String.valueOf(hasWallpaper))
|
||||
.build());
|
||||
|
||||
return intent;
|
||||
@@ -353,6 +369,7 @@ public class ConversationIntents {
|
||||
intent.putExtra(EXTRA_SHARE_DATA_TIMESTAMP, shareDataTimestamp);
|
||||
intent.putExtra(EXTRA_CONVERSATION_TYPE, conversationScreenType.code);
|
||||
intent.putExtra(EXTRA_INCOGNITO, incognito);
|
||||
intent.putExtra(EXTRA_HAS_WALLPAPER, hasWallpaper);
|
||||
|
||||
if (draftText != null) {
|
||||
intent.putExtra(EXTRA_TEXT, draftText);
|
||||
|
||||
@@ -480,8 +480,7 @@ class ConversationFragment :
|
||||
repository = ConversationRepository(localContext = requireContext(), isInBubble = args.conversationScreenType == ConversationScreenType.BUBBLE),
|
||||
recipientRepository = conversationRecipientRepository,
|
||||
messageRequestRepository = messageRequestRepository,
|
||||
scheduledMessagesRepository = ScheduledMessagesRepository(),
|
||||
initialChatColors = args.chatColors
|
||||
scheduledMessagesRepository = ScheduledMessagesRepository()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -687,8 +686,6 @@ class ConversationFragment :
|
||||
incognito = args.isIncognito
|
||||
)
|
||||
conversationToolbarOnScrollHelper.attach(binding.conversationItemRecycler)
|
||||
presentWallpaper(args.wallpaper)
|
||||
presentChatColors(args.chatColors)
|
||||
presentConversationTitle(viewModel.recipientSnapshot)
|
||||
presentGroupConversationSubtitle(createGroupSubtitleString(viewModel.titleViewParticipantsSnapshot))
|
||||
presentActionBarMenu()
|
||||
@@ -1683,6 +1680,11 @@ class ConversationFragment :
|
||||
presentChatColors(recipient.chatColors)
|
||||
invalidateOptionsMenu()
|
||||
updateMessageRequestAcceptedState(!viewModel.hasMessageRequestState)
|
||||
|
||||
recyclerViewColorizer.setChatColors(recipient.chatColors)
|
||||
if (adapter.onHasWallpaperChanged(hasWallpaper = recipient.wallpaper != null)) {
|
||||
conversationItemDecorations.hasWallpaper = recipient.wallpaper != null
|
||||
}
|
||||
}
|
||||
|
||||
@MainThread
|
||||
@@ -2149,7 +2151,7 @@ class ConversationFragment :
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
requestManager = Glide.with(this),
|
||||
clickListener = ConversationItemClickListener(),
|
||||
hasWallpaper = args.wallpaper != null,
|
||||
hasWallpaper = args.hasWallpaper,
|
||||
colorizer = colorizer,
|
||||
startExpirationTimeout = viewModel::startExpirationTimeout,
|
||||
chatColorsDataProvider = viewModel::chatColorsSnapshot,
|
||||
@@ -2166,7 +2168,7 @@ class ConversationFragment :
|
||||
adapter.setPagingController(viewModel.pagingController)
|
||||
|
||||
recyclerViewColorizer = RecyclerViewColorizer(binding.conversationItemRecycler)
|
||||
recyclerViewColorizer.setChatColors(args.chatColors)
|
||||
viewModel.recipientSnapshot?.chatColors?.let { recyclerViewColorizer.setChatColors(it) }
|
||||
|
||||
binding.conversationItemRecycler.adapter = ConcatAdapter(typingIndicatorAdapter, adapter)
|
||||
multiselectItemDecoration = MultiselectItemDecoration(
|
||||
@@ -2203,7 +2205,7 @@ class ConversationFragment :
|
||||
threadHeaderMarginDecoration.toolbarMargin = statusBarInset + resources.getDimensionPixelSize(R.dimen.signal_m3_toolbar_height) + 16.dp
|
||||
binding.conversationItemRecycler.addItemDecoration(threadHeaderMarginDecoration)
|
||||
|
||||
conversationItemDecorations = ConversationItemDecorations(hasWallpaper = args.wallpaper != null)
|
||||
conversationItemDecorations = ConversationItemDecorations(hasWallpaper = args.hasWallpaper)
|
||||
binding.conversationItemRecycler.addItemDecoration(conversationItemDecorations, 0)
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@ import org.thoughtcrime.securesms.banner.banners.UnauthorizedBanner
|
||||
import org.thoughtcrime.securesms.contactshare.Contact
|
||||
import org.thoughtcrime.securesms.conversation.ConversationMessage
|
||||
import org.thoughtcrime.securesms.conversation.ScheduledMessagesRepository
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColors
|
||||
import org.thoughtcrime.securesms.conversation.mutiselect.MultiselectPart
|
||||
import org.thoughtcrime.securesms.conversation.plaintext.PlaintextExportRepository
|
||||
import org.thoughtcrime.securesms.conversation.v2.data.ConversationElementKey
|
||||
@@ -112,7 +111,6 @@ import kotlin.time.Duration
|
||||
class ConversationViewModel(
|
||||
val threadId: Long,
|
||||
requestedStartingPosition: Int,
|
||||
initialChatColors: ChatColors,
|
||||
private val repository: ConversationRepository,
|
||||
recipientRepository: ConversationRecipientRepository,
|
||||
messageRequestRepository: MessageRequestRepository,
|
||||
@@ -160,7 +158,7 @@ class ConversationViewModel(
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
||||
private val chatBounds: BehaviorSubject<Rect> = BehaviorSubject.create()
|
||||
private val chatColors: RxStore<ChatColorsDrawable.ChatColorsData> = RxStore(ChatColorsDrawable.ChatColorsData(initialChatColors, null))
|
||||
private val chatColors: RxStore<ChatColorsDrawable.ChatColorsData> = RxStore(ChatColorsDrawable.ChatColorsData(null, null))
|
||||
val chatColorsSnapshot: ChatColorsDrawable.ChatColorsData get() = chatColors.state
|
||||
|
||||
@Volatile
|
||||
|
||||
@@ -252,7 +252,7 @@ open class V2ConversationItemTextOnlyViewHolder<Model : MappingModel<Model>>(
|
||||
hasProcessedSupportedPayload = true
|
||||
}
|
||||
|
||||
if (hasProcessedSupportedPayload) {
|
||||
if (hasProcessedSupportedPayload && V2Payload.WALLPAPER !in payload) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -253,13 +253,14 @@ class MainNavigationViewModel(
|
||||
}
|
||||
|
||||
private fun goToConversation(args: ConversationArgs) = viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val updatedArgs = withContext(Dispatchers.IO) {
|
||||
val wallpaper = Recipient.resolved(args.recipientId).wallpaper
|
||||
if (wallpaper?.prefetch(AppDependencies.application, 250) == false) {
|
||||
Log.w(TAG, "goToConversation: Failed to prefetch wallpaper.")
|
||||
}
|
||||
args.copy(hasWallpaper = wallpaper != null)
|
||||
}
|
||||
internalDetailLocation.emit(MainNavigationDetailLocation.Chats.Conversation(args))
|
||||
internalDetailLocation.emit(MainNavigationDetailLocation.Chats.Conversation(updatedArgs))
|
||||
}
|
||||
|
||||
fun goToCameraFirstStoryCapture() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.content.Intent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
@@ -28,6 +29,8 @@ public interface MessageNotifier {
|
||||
void cancelDelayedNotifications();
|
||||
void updateNotification(@NonNull Context context);
|
||||
void updateNotification(@NonNull Context context, @NonNull ConversationId conversationId);
|
||||
|
||||
@WorkerThread
|
||||
void forceBubbleNotification(@NonNull Context context, @NonNull ConversationId conversationId);
|
||||
void addStickyThread(@NonNull ConversationId conversationId, long earliestTimestamp);
|
||||
void removeStickyThread(@NonNull ConversationId conversationId);
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.service.notification.StatusBarNotification
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.core.content.ContextCompat
|
||||
import me.leolin.shortcutbadger.ShortcutBadger
|
||||
@@ -114,10 +115,12 @@ class DefaultMessageNotifier(context: Application) : MessageNotifier {
|
||||
executor.cancel()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun updateNotification(context: Context) {
|
||||
updateNotification(context, null, BubbleState.HIDDEN)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun updateNotification(context: Context, conversationId: ConversationId) {
|
||||
if (System.currentTimeMillis() - lastDesktopActivityTimestamp < DESKTOP_ACTIVITY_PERIOD) {
|
||||
Log.i(TAG, "Scheduling delayed notification...")
|
||||
@@ -127,10 +130,12 @@ class DefaultMessageNotifier(context: Application) : MessageNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun forceBubbleNotification(context: Context, conversationId: ConversationId) {
|
||||
updateNotification(context, conversationId, BubbleState.SHOWN)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun updateNotification(
|
||||
context: Context,
|
||||
conversationId: ConversationId?,
|
||||
|
||||
@@ -11,6 +11,7 @@ import android.text.TextUtils
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.RemoteInput
|
||||
import androidx.core.content.LocusIdCompat
|
||||
@@ -83,6 +84,8 @@ sealed class NotificationBuilder(protected val context: Context) {
|
||||
protected abstract fun addMarkAsReadActionActual(state: NotificationState)
|
||||
protected abstract fun addMessagesActual(conversation: NotificationConversation, includeShortcut: Boolean)
|
||||
protected abstract fun addMessagesActual(state: NotificationState)
|
||||
|
||||
@WorkerThread
|
||||
protected abstract fun setBubbleMetadataActual(conversation: NotificationConversation, bubbleState: BubbleUtil.BubbleState)
|
||||
protected abstract fun setLights(@ColorInt color: Int, onTime: Int, offTime: Int)
|
||||
|
||||
@@ -154,6 +157,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
||||
addMessagesActual(state)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun setBubbleMetadata(conversation: NotificationConversation, bubbleState: BubbleUtil.BubbleState) {
|
||||
if (privacy.isDisplayContact && isNotLocked) {
|
||||
setBubbleMetadataActual(conversation, bubbleState)
|
||||
@@ -360,15 +364,18 @@ sealed class NotificationBuilder(protected val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun setBubbleMetadataActual(conversation: NotificationConversation, bubbleState: BubbleUtil.BubbleState) {
|
||||
if (Build.VERSION.SDK_INT < ConversationUtil.CONVERSATION_SUPPORT_VERSION) {
|
||||
return
|
||||
}
|
||||
|
||||
val wallpaper = conversation.recipient.wallpaper
|
||||
wallpaper?.prefetch(context, 250)
|
||||
val intent: PendingIntent? = NotificationPendingIntentHelper.getActivity(
|
||||
context,
|
||||
0,
|
||||
ConversationIntents.createBubbleIntent(context, conversation.recipient.id, conversation.thread.threadId),
|
||||
ConversationIntents.createBubbleIntent(context, conversation.recipient.id, conversation.thread.threadId, wallpaper != null),
|
||||
mutable()
|
||||
)
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ data class NotificationConversation(
|
||||
}
|
||||
|
||||
fun getQuickReplyIntent(context: Context): PendingIntent? {
|
||||
val intent: Intent = ConversationIntents.createPopUpBuilder(context, recipient.id, mostRecentNotification.thread.threadId)
|
||||
val intent: Intent = ConversationIntents.createPopUpBuilder(context, recipient.id, mostRecentNotification.thread.threadId, recipient.wallpaper != null)
|
||||
.build()
|
||||
.makeUniqueToPreventMerging()
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import android.media.RingtoneManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.TransactionTooLargeException
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -50,6 +51,7 @@ object NotificationFactory {
|
||||
private val STILL_DECRYPTING_INDIVIDUAL_THROTTLE: Duration = 5.seconds
|
||||
private val GROUP_THROTTLE: Duration = 20.seconds
|
||||
|
||||
@WorkerThread
|
||||
fun notify(
|
||||
context: Context,
|
||||
state: NotificationState,
|
||||
@@ -97,6 +99,7 @@ object NotificationFactory {
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun notify19(
|
||||
context: Context,
|
||||
state: NotificationState,
|
||||
@@ -144,6 +147,7 @@ object NotificationFactory {
|
||||
return threadsThatNewlyAlerted
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@TargetApi(24)
|
||||
private fun notify24(
|
||||
context: Context,
|
||||
@@ -213,6 +217,7 @@ object NotificationFactory {
|
||||
return ((conversation.hasNewNotifications() && canAlertBasedOnTime) || alertOverride) && !conversation.mostRecentNotification.authorRecipient.isSelf
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun notifyForConversation(
|
||||
context: Context,
|
||||
conversation: NotificationConversation,
|
||||
@@ -446,6 +451,7 @@ object NotificationFactory {
|
||||
NotificationManagerCompat.from(context).safelyNotify(recipient, NotificationIds.getNotificationIdForMessageDeliveryFailed(thread), builder.build())
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@JvmStatic
|
||||
fun notifyToBubbleConversation(context: Context, recipient: Recipient, threadId: Long) {
|
||||
val builder: NotificationBuilder = NotificationBuilder.create(context)
|
||||
|
||||
Reference in New Issue
Block a user