kopia lustrzana https://github.com/ryukoposting/Signal-Android
Address API23 notification issues and update when conversation content changes.
rodzic
efc3e7b25d
commit
29a0b86411
|
@ -48,6 +48,7 @@ class MessageNotifierV2(context: Application) : MessageNotifier {
|
|||
@Volatile private var lastScheduledReminder: Long = 0
|
||||
@Volatile private var previousLockedStatus: Boolean = KeyCachingService.isLocked(context)
|
||||
@Volatile private var previousPrivacyPreference: NotificationPrivacyPreference = TextSecurePreferences.getNotificationPrivacy(context)
|
||||
@Volatile private var previousState: NotificationStateV2 = NotificationStateV2.EMPTY
|
||||
|
||||
private val threadReminders: MutableMap<Long, Reminder> = ConcurrentHashMap()
|
||||
private val stickyThreads: MutableMap<Long, StickyThread> = mutableMapOf()
|
||||
|
@ -167,9 +168,11 @@ class MessageNotifierV2(context: Application) : MessageNotifier {
|
|||
defaultBubbleState = defaultBubbleState,
|
||||
lastAudibleNotification = lastAudibleNotification,
|
||||
notificationConfigurationChanged = notificationConfigurationChanged,
|
||||
alertOverrides = alertOverrides
|
||||
alertOverrides = alertOverrides,
|
||||
previousState = previousState
|
||||
)
|
||||
|
||||
previousState = state
|
||||
lastAudibleNotification = System.currentTimeMillis()
|
||||
|
||||
updateReminderTimestamps(context, alertOverrides, threadsThatAlerted)
|
||||
|
@ -281,7 +284,7 @@ private fun StatusBarNotification.isMessageNotification(): Boolean {
|
|||
}
|
||||
|
||||
private fun NotificationManager.getDisplayedNotificationIds(): Result<Set<Int>> {
|
||||
if (Build.VERSION.SDK_INT < 23) {
|
||||
if (Build.VERSION.SDK_INT < 24) {
|
||||
return Result.failure(UnsupportedOperationException("SDK level too low"))
|
||||
}
|
||||
|
||||
|
@ -294,7 +297,7 @@ private fun NotificationManager.getDisplayedNotificationIds(): Result<Set<Int>>
|
|||
}
|
||||
|
||||
private fun NotificationManager.cancelOrphanedNotifications(context: Context, state: NotificationStateV2, stickyNotifications: Set<Int>) {
|
||||
if (Build.VERSION.SDK_INT < 23) {
|
||||
if (Build.VERSION.SDK_INT < 24) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||
abstract fun addMarkAsReadActionActual(state: NotificationStateV2)
|
||||
abstract fun setPriority(priority: Int)
|
||||
abstract fun setAlarms(recipient: Recipient?)
|
||||
abstract fun setTicker(ticker: CharSequence)
|
||||
abstract fun setTicker(ticker: CharSequence?)
|
||||
abstract fun addTurnOffJoinedNotificationsAction(pendingIntent: PendingIntent)
|
||||
abstract fun setAutoCancel(autoCancel: Boolean)
|
||||
abstract fun build(): Notification
|
||||
|
@ -100,8 +100,8 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
fun setWhen(notificationItem: NotificationItemV2) {
|
||||
if (notificationItem.timestamp != 0L) {
|
||||
fun setWhen(notificationItem: NotificationItemV2?) {
|
||||
if (notificationItem != null && notificationItem.timestamp != 0L) {
|
||||
setWhen(notificationItem.timestamp)
|
||||
}
|
||||
}
|
||||
|
@ -136,12 +136,12 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
fun setSummaryContentText(recipient: Recipient) {
|
||||
if (privacy.isDisplayContact) {
|
||||
fun setSummaryContentText(recipient: Recipient?) {
|
||||
if (privacy.isDisplayContact && recipient != null) {
|
||||
setContentText(context.getString(R.string.MessageNotifier_most_recent_from_s, recipient.getDisplayName(context)))
|
||||
}
|
||||
|
||||
recipient.notificationChannel?.let { channel -> setChannelId(channel) }
|
||||
recipient?.notificationChannel?.let { channel -> setChannelId(channel) }
|
||||
}
|
||||
|
||||
fun setLights() {
|
||||
|
@ -244,8 +244,8 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||
|
||||
val self: PersonCompat = PersonCompat.Builder()
|
||||
.setBot(false)
|
||||
.setName(Recipient.self().getDisplayName(context))
|
||||
.setIcon(Recipient.self().getContactDrawable(context).toLargeBitmap(context).toIconCompat())
|
||||
.setName(if (includeShortcut) Recipient.self().getDisplayName(context) else context.getString(R.string.SingleRecipientNotificationBuilder_you))
|
||||
.setIcon(if (includeShortcut) Recipient.self().getContactDrawable(context).toLargeBitmap(context).toIconCompat() else null)
|
||||
.build()
|
||||
|
||||
val messagingStyle: NotificationCompat.MessagingStyle = NotificationCompat.MessagingStyle(self)
|
||||
|
@ -332,7 +332,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||
}
|
||||
|
||||
override fun setGroup(group: String) {
|
||||
if (Build.VERSION.SDK_INT < 23) {
|
||||
if (Build.VERSION.SDK_INT < 24) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -340,7 +340,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||
}
|
||||
|
||||
override fun setGroupAlertBehavior(behavior: Int) {
|
||||
if (Build.VERSION.SDK_INT < 23) {
|
||||
if (Build.VERSION.SDK_INT < 24) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -375,7 +375,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||
builder.setContentText(contentText)
|
||||
}
|
||||
|
||||
override fun setTicker(ticker: CharSequence) {
|
||||
override fun setTicker(ticker: CharSequence?) {
|
||||
builder.setTicker(ticker)
|
||||
}
|
||||
|
||||
|
@ -489,8 +489,8 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||
override fun addMessagesActual(conversation: NotificationConversation, includeShortcut: Boolean) {
|
||||
val self: Person = Person.Builder()
|
||||
.setBot(false)
|
||||
.setName(Recipient.self().getDisplayName(context))
|
||||
.setIcon(Recipient.self().getContactDrawable(context).toLargeBitmap(context).toIcon())
|
||||
.setName(if (includeShortcut) Recipient.self().getDisplayName(context) else context.getString(R.string.SingleRecipientNotificationBuilder_you))
|
||||
.setIcon(if (includeShortcut) Recipient.self().getContactDrawable(context).toLargeBitmap(context).toIcon() else null)
|
||||
.build()
|
||||
|
||||
val messagingStyle: Notification.MessagingStyle = Notification.MessagingStyle(self)
|
||||
|
@ -598,7 +598,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||
builder.setContentText(contentText)
|
||||
}
|
||||
|
||||
override fun setTicker(ticker: CharSequence) {
|
||||
override fun setTicker(ticker: CharSequence?) {
|
||||
builder.setTicker(ticker)
|
||||
}
|
||||
|
||||
|
|
|
@ -88,14 +88,10 @@ data class NotificationConversation(
|
|||
}
|
||||
|
||||
fun getConversationTitle(context: Context): CharSequence? {
|
||||
if (isGroup) {
|
||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
||||
recipient.getDisplayName(context)
|
||||
} else {
|
||||
context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
||||
}
|
||||
if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
||||
return if (isGroup) recipient.getDisplayName(context) else null
|
||||
}
|
||||
return null
|
||||
return context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
||||
}
|
||||
|
||||
fun getWhen(): Long {
|
||||
|
@ -114,6 +110,14 @@ data class NotificationConversation(
|
|||
}
|
||||
}
|
||||
|
||||
fun hasSameContent(other: NotificationConversation?): Boolean {
|
||||
if (other == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
return messageCount == other.messageCount && notificationItems.zip(other.notificationItems).all { (item, otherItem) -> item.hasSameContent(otherItem) }
|
||||
}
|
||||
|
||||
fun getPendingIntent(context: Context): PendingIntent {
|
||||
val intent: Intent = ConversationIntents.createBuilder(context, recipient.id, threadId)
|
||||
.withStartingPosition(mostRecentNotification.getStartingPosition(context))
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package org.thoughtcrime.securesms.notifications.v2
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import com.bumptech.glide.load.MultiTransformation
|
||||
import com.bumptech.glide.load.Transformation
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
|
@ -17,6 +19,7 @@ import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto
|
|||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.notifications.NotificationIds
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil
|
||||
import org.thoughtcrime.securesms.util.BlurTransformation
|
||||
|
@ -84,3 +87,13 @@ fun Intent.makeUniqueToPreventMerging(): Intent {
|
|||
fun Recipient.getFallback(context: Context): FallbackContactPhoto {
|
||||
return GeneratedContactPhoto(getDisplayName(context), R.drawable.ic_profile_outline_40)
|
||||
}
|
||||
|
||||
fun NotificationManager.isDisplayingSummaryNotification(): Boolean {
|
||||
if (Build.VERSION.SDK_INT > 23) {
|
||||
try {
|
||||
return activeNotifications.any { notification -> notification.id == NotificationIds.MESSAGE_SUMMARY }
|
||||
} catch (e: Throwable) {
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.notifications.v2
|
|||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
@ -46,15 +45,16 @@ object NotificationFactory {
|
|||
defaultBubbleState: BubbleUtil.BubbleState,
|
||||
lastAudibleNotification: Long,
|
||||
notificationConfigurationChanged: Boolean,
|
||||
alertOverrides: Set<Long>
|
||||
alertOverrides: Set<Long>,
|
||||
previousState: NotificationStateV2
|
||||
): Set<Long> {
|
||||
if (state.isEmpty) {
|
||||
Log.d(TAG, "State is empty, bailing")
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
val nonVisibleThreadCount = state.conversations.count { it.threadId != visibleThreadId }
|
||||
return if (Build.VERSION.SDK_INT < 23) {
|
||||
val nonVisibleThreadCount: Int = state.conversations.count { it.threadId != visibleThreadId }
|
||||
return if (Build.VERSION.SDK_INT < 24) {
|
||||
notify19(
|
||||
context = context,
|
||||
state = state,
|
||||
|
@ -66,7 +66,7 @@ object NotificationFactory {
|
|||
nonVisibleThreadCount = nonVisibleThreadCount
|
||||
)
|
||||
} else {
|
||||
notify23(
|
||||
notify24(
|
||||
context = context,
|
||||
state = state,
|
||||
visibleThreadId = visibleThreadId,
|
||||
|
@ -75,7 +75,8 @@ object NotificationFactory {
|
|||
lastAudibleNotification = lastAudibleNotification,
|
||||
notificationConfigurationChanged = notificationConfigurationChanged,
|
||||
alertOverrides = alertOverrides,
|
||||
nonVisibleThreadCount = nonVisibleThreadCount
|
||||
nonVisibleThreadCount = nonVisibleThreadCount,
|
||||
previousState = previousState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -121,8 +122,8 @@ object NotificationFactory {
|
|||
return threadsThatNewlyAlerted
|
||||
}
|
||||
|
||||
@TargetApi(23)
|
||||
private fun notify23(
|
||||
@TargetApi(24)
|
||||
private fun notify24(
|
||||
context: Context,
|
||||
state: NotificationStateV2,
|
||||
visibleThreadId: Long,
|
||||
|
@ -131,7 +132,8 @@ object NotificationFactory {
|
|||
lastAudibleNotification: Long,
|
||||
notificationConfigurationChanged: Boolean,
|
||||
alertOverrides: Set<Long>,
|
||||
nonVisibleThreadCount: Int
|
||||
nonVisibleThreadCount: Int,
|
||||
previousState: NotificationStateV2
|
||||
): Set<Long> {
|
||||
val threadsThatNewlyAlerted: MutableSet<Long> = mutableSetOf()
|
||||
|
||||
|
@ -139,7 +141,7 @@ object NotificationFactory {
|
|||
if (conversation.threadId == visibleThreadId && conversation.hasNewNotifications()) {
|
||||
Log.internal().i(TAG, "Thread is visible, notifying in thread. notificationId: ${conversation.notificationId}")
|
||||
notifyInThread(context, conversation.recipient, lastAudibleNotification)
|
||||
} else if (notificationConfigurationChanged || conversation.hasNewNotifications() || alertOverrides.contains(conversation.threadId)) {
|
||||
} else if (notificationConfigurationChanged || conversation.hasNewNotifications() || alertOverrides.contains(conversation.threadId) || !conversation.hasSameContent(previousState.getConversation(conversation.threadId))) {
|
||||
if (conversation.hasNewNotifications()) {
|
||||
threadsThatNewlyAlerted += conversation.threadId
|
||||
}
|
||||
|
@ -206,7 +208,7 @@ object NotificationFactory {
|
|||
builder.addTurnOffJoinedNotificationsAction(conversation.getTurnOffJoinedNotificationsIntent(context))
|
||||
}
|
||||
|
||||
val notificationId: Int = if (Build.VERSION.SDK_INT < 23) NotificationIds.MESSAGE_SUMMARY else conversation.notificationId
|
||||
val notificationId: Int = if (Build.VERSION.SDK_INT < 24) NotificationIds.MESSAGE_SUMMARY else conversation.notificationId
|
||||
|
||||
NotificationManagerCompat.from(context).safelyNotify(context, conversation.recipient, notificationId, builder.build())
|
||||
}
|
||||
|
@ -240,7 +242,7 @@ object NotificationFactory {
|
|||
setPriority(TextSecurePreferences.getNotificationPriority(context))
|
||||
setLights()
|
||||
setAlarms(state.mostRecentSender)
|
||||
setTicker(state.mostRecentNotification.getStyledPrimaryText(context, true))
|
||||
setTicker(state.mostRecentNotification?.getStyledPrimaryText(context, true))
|
||||
}
|
||||
|
||||
Log.d(TAG, "showing summary notification")
|
||||
|
@ -313,16 +315,6 @@ object NotificationFactory {
|
|||
NotificationManagerCompat.from(context).safelyNotify(context, recipient, threadId.toInt(), builder.build())
|
||||
}
|
||||
|
||||
private fun NotificationManager.isDisplayingSummaryNotification(): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
try {
|
||||
return activeNotifications.any { notification -> notification.id == NotificationIds.MESSAGE_SUMMARY }
|
||||
} catch (e: Throwable) {
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun NotificationManagerCompat.safelyNotify(context: Context, threadRecipient: Recipient?, notificationId: Int, notification: Notification) {
|
||||
try {
|
||||
notify(notificationId, notification)
|
||||
|
|
|
@ -90,7 +90,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
|||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
||||
individualRecipient.getDisplayName(context)
|
||||
} else {
|
||||
""
|
||||
context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,6 +133,16 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
|||
}
|
||||
}
|
||||
|
||||
fun hasSameContent(other: NotificationItemV2): Boolean {
|
||||
return timestamp == other.timestamp &&
|
||||
id == other.id &&
|
||||
isMms == other.isMms &&
|
||||
individualRecipient == other.individualRecipient &&
|
||||
individualRecipient.hasSameContent(other.individualRecipient) &&
|
||||
slideDeck?.thumbnailSlide?.isInProgress == other.slideDeck?.thumbnailSlide?.isInProgress &&
|
||||
record.isRemoteDelete == other.record.isRemoteDelete
|
||||
}
|
||||
|
||||
private fun CharSequence?.trimToDisplayLength(): CharSequence {
|
||||
val text: CharSequence = this ?: ""
|
||||
return if (text.length <= AbstractNotificationBuilder.MAX_DISPLAY_LENGTH) {
|
||||
|
|
|
@ -33,16 +33,20 @@ data class NotificationStateV2(val conversations: List<NotificationConversation>
|
|||
.toSet()
|
||||
}
|
||||
|
||||
val mostRecentNotification: NotificationItemV2
|
||||
get() = notificationItems.last()
|
||||
val mostRecentNotification: NotificationItemV2?
|
||||
get() = notificationItems.lastOrNull()
|
||||
|
||||
val mostRecentSender: Recipient
|
||||
get() = mostRecentNotification.individualRecipient
|
||||
val mostRecentSender: Recipient?
|
||||
get() = mostRecentNotification?.individualRecipient
|
||||
|
||||
fun getNonVisibleConversation(visibleThreadId: Long): List<NotificationConversation> {
|
||||
return conversations.filterNot { it.threadId == visibleThreadId }
|
||||
}
|
||||
|
||||
fun getConversation(threadId: Long): NotificationConversation? {
|
||||
return conversations.firstOrNull { it.threadId == threadId }
|
||||
}
|
||||
|
||||
fun getDeleteIntent(context: Context): PendingIntent? {
|
||||
val ids = LongArray(messageCount)
|
||||
val mms = BooleanArray(ids.size)
|
||||
|
|
|
@ -1751,6 +1751,7 @@
|
|||
<string name="SingleRecipientNotificationBuilder_signal">Signal</string>
|
||||
<string name="SingleRecipientNotificationBuilder_new_message">New message</string>
|
||||
<string name="SingleRecipientNotificationBuilder_message_request">Message request</string>
|
||||
<string name="SingleRecipientNotificationBuilder_you">You</string>
|
||||
|
||||
<!-- ThumbnailView -->
|
||||
<string name="ThumbnailView_Play_video_description">Play video</string>
|
||||
|
|
Ładowanie…
Reference in New Issue