From 44b2673848a4fce9b61a95671f8943ac7d5d357b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 23 Sep 2020 15:57:20 +0200 Subject: [PATCH] PIN: Add a setting to hide notification content when PIN code is configured --- CHANGES.md | 2 +- .../NotificationDrawerManager.kt | 117 ++++++++++++++---- .../notifications/NotificationUtils.kt | 2 +- .../features/settings/VectorPreferences.kt | 9 ++ .../settings/VectorSettingsPinFragment.kt | 14 ++- vector/src/main/res/values/strings.xml | 9 ++ .../src/main/res/xml/vector_settings_pin.xml | 8 ++ 7 files changed, 136 insertions(+), 25 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5badc27512..f64db24a9d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,7 +12,7 @@ Improvements 🙌: - Use cache for user color - Allow using an outdated homeserver, at user's risk (#1972) - Restore small logo on login screens and fix scrolling issue on those screens - - PIN Code Improvements. Add more settings (#1985) + - PIN Code Improvements: Add more settings: biometrics, grace period, notification content (#1985) Bugfix 🐛: - Long message cannot be sent/takes infinite time & blocks other messages #1397 diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt index e689f9df3f..7399f595b3 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt @@ -27,9 +27,9 @@ import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.resources.StringProvider import im.vector.app.features.settings.VectorPreferences +import me.gujun.android.span.span import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.content.ContentUrlResolver -import me.gujun.android.span.span import timber.log.Timber import java.io.File import java.io.FileOutputStream @@ -72,6 +72,8 @@ class NotificationDrawerManager @Inject constructor(private val context: Context private val currentSession: Session? get() = activeSessionDataSource.currentValue?.orNull() + private var useCompleteNotificationFormat = vectorPreferences.useCompleteNotificationFormat() + /** Should be called as soon as a new event is ready to be displayed. The notification corresponding to this event will not be displayed until @@ -243,8 +245,8 @@ class NotificationDrawerManager @Inject constructor(private val context: Context roomEvents.add(event) } } - is InviteNotifiableEvent -> invitationEvents.add(event) - is SimpleNotifiableEvent -> simpleEvents.add(event) + is InviteNotifiableEvent -> invitationEvents.add(event) + is SimpleNotifiableEvent -> simpleEvents.add(event) else -> Timber.w("Type not handled") } } @@ -253,6 +255,16 @@ class NotificationDrawerManager @Inject constructor(private val context: Context var globalLastMessageTimestamp = 0L + val newSettings = vectorPreferences.useCompleteNotificationFormat() + if (newSettings != useCompleteNotificationFormat) { + // Settings has changed, remove all current notifications + notificationUtils.cancelAllNotifications() + useCompleteNotificationFormat = newSettings + } + + var simpleNotificationRoomCounter = 0 + var simpleNotificationMessageCounter = 0 + // events have been grouped by roomId for ((roomId, events) in roomIdToEventMap) { // Build the notification for the room @@ -263,6 +275,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context continue } + simpleNotificationRoomCounter++ val roomName = events[0].roomName ?: events[0].senderName ?: "" val roomEventGroupInfo = RoomEventGroupInfo( @@ -303,6 +316,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context roomEventGroupInfo.hasSmartReplyError = true } else { if (!event.isRedacted) { + simpleNotificationMessageCounter++ style.addMessage(event.body, event.timestamp, senderPerson) } } @@ -361,16 +375,18 @@ class NotificationDrawerManager @Inject constructor(private val context: Context stringProvider.getString(R.string.notification_ticker_text_group, roomName, events.last().senderName, events.last().description) } - val notification = notificationUtils.buildMessagesListNotification( - style, - roomEventGroupInfo, - largeBitmap, - lastMessageTimestamp, - myUserDisplayName, - tickerText) + if (useCompleteNotificationFormat) { + val notification = notificationUtils.buildMessagesListNotification( + style, + roomEventGroupInfo, + largeBitmap, + lastMessageTimestamp, + myUserDisplayName, + tickerText) - // is there an id for this room? - notificationUtils.showNotificationMessage(roomId, ROOM_MESSAGES_NOTIFICATION_ID, notification) + // is there an id for this room? + notificationUtils.showNotificationMessage(roomId, ROOM_MESSAGES_NOTIFICATION_ID, notification) + } hasNewEvent = true summaryIsNoisy = summaryIsNoisy || roomEventGroupInfo.shouldBing @@ -383,8 +399,10 @@ class NotificationDrawerManager @Inject constructor(private val context: Context for (event in invitationEvents) { // We build a invitation notification if (firstTime || !event.hasBeenDisplayed) { - val notification = notificationUtils.buildRoomInvitationNotification(event, session.myUserId) - notificationUtils.showNotificationMessage(event.roomId, ROOM_INVITATION_NOTIFICATION_ID, notification) + if (useCompleteNotificationFormat) { + val notification = notificationUtils.buildRoomInvitationNotification(event, session.myUserId) + notificationUtils.showNotificationMessage(event.roomId, ROOM_INVITATION_NOTIFICATION_ID, notification) + } event.hasBeenDisplayed = true // we can consider it as displayed hasNewEvent = true summaryIsNoisy = summaryIsNoisy || event.noisy @@ -396,8 +414,10 @@ class NotificationDrawerManager @Inject constructor(private val context: Context for (event in simpleEvents) { // We build a simple notification if (firstTime || !event.hasBeenDisplayed) { - val notification = notificationUtils.buildSimpleEventNotification(event, session.myUserId) - notificationUtils.showNotificationMessage(event.eventId, ROOM_EVENT_NOTIFICATION_ID, notification) + if (useCompleteNotificationFormat) { + val notification = notificationUtils.buildSimpleEventNotification(event, session.myUserId) + notificationUtils.showNotificationMessage(event.eventId, ROOM_EVENT_NOTIFICATION_ID, notification) + } event.hasBeenDisplayed = true // we can consider it as displayed hasNewEvent = true summaryIsNoisy = summaryIsNoisy || event.noisy @@ -421,19 +441,72 @@ class NotificationDrawerManager @Inject constructor(private val context: Context if (eventList.isEmpty() || eventList.all { it.isRedacted }) { notificationUtils.cancelNotificationMessage(null, SUMMARY_NOTIFICATION_ID) } else { + // FIXME roomIdToEventMap.size is not correct, this is the number of rooms val nbEvents = roomIdToEventMap.size + simpleEvents.size val sumTitle = stringProvider.getQuantityString(R.plurals.notification_compat_summary_title, nbEvents, nbEvents) summaryInboxStyle.setBigContentTitle(sumTitle) // TODO get latest event? .setSummaryText(stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages, nbEvents, nbEvents)) - val notification = notificationUtils.buildSummaryListNotification( - summaryInboxStyle, - sumTitle, - noisy = hasNewEvent && summaryIsNoisy, - lastMessageTimestamp = globalLastMessageTimestamp) + if (useCompleteNotificationFormat) { + val notification = notificationUtils.buildSummaryListNotification( + summaryInboxStyle, + sumTitle, + noisy = hasNewEvent && summaryIsNoisy, + lastMessageTimestamp = globalLastMessageTimestamp) - notificationUtils.showNotificationMessage(null, SUMMARY_NOTIFICATION_ID, notification) + notificationUtils.showNotificationMessage(null, SUMMARY_NOTIFICATION_ID, notification) + } else { + // Add the simple events as message (?) + simpleNotificationMessageCounter += simpleEvents.size + val numberOfInvitations = invitationEvents.size + + val privacyTitle = if (numberOfInvitations > 0) { + val invitationsStr = stringProvider.getQuantityString(R.plurals.notification_invitations, numberOfInvitations, numberOfInvitations) + if (simpleNotificationMessageCounter > 0) { + // Invitation and message + val messageStr = stringProvider.getQuantityString(R.plurals.room_new_messages_notification, simpleNotificationMessageCounter, simpleNotificationMessageCounter) + if (simpleNotificationRoomCounter > 1) { + // In several rooms + val roomStr = stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages_in_room_rooms, simpleNotificationRoomCounter, simpleNotificationRoomCounter) + stringProvider.getString( + R.string.notification_unread_notified_messages_in_room_and_invitation, + messageStr, + roomStr, + invitationsStr + ) + } else { + // In one room + stringProvider.getString( + R.string.notification_unread_notified_messages_and_invitation, + messageStr, + invitationsStr + ) + } + } else { + // Only invitation + invitationsStr + } + } else { + // No invitation, only messages + val messageStr = stringProvider.getQuantityString(R.plurals.room_new_messages_notification, simpleNotificationMessageCounter, simpleNotificationMessageCounter) + if (simpleNotificationRoomCounter > 1) { + // In several rooms + val roomStr = stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages_in_room_rooms, simpleNotificationMessageCounter, simpleNotificationMessageCounter) + stringProvider.getString(R.string.notification_unread_notified_messages_in_room, messageStr, roomStr) + } else { + // In one room + messageStr + } + } + val notification = notificationUtils.buildSummaryListNotification( + style = null, + compatSummary = privacyTitle, + noisy = hasNewEvent && summaryIsNoisy, + lastMessageTimestamp = globalLastMessageTimestamp) + + notificationUtils.showNotificationMessage(null, SUMMARY_NOTIFICATION_ID, notification) + } if (hasNewEvent && summaryIsNoisy) { try { diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 2b070e540e..9d89168bb8 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -772,7 +772,7 @@ class NotificationUtils @Inject constructor(private val context: Context, /** * Build the summary notification */ - fun buildSummaryListNotification(style: NotificationCompat.InboxStyle, + fun buildSummaryListNotification(style: NotificationCompat.InboxStyle?, compatSummary: String, noisy: Boolean, lastMessageTimestamp: Long): Notification { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index d5f7749506..9ccb8d7031 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -168,6 +168,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { const val SETTINGS_SECURITY_USE_PIN_CODE_FLAG = "SETTINGS_SECURITY_USE_PIN_CODE_FLAG" private const val SETTINGS_SECURITY_USE_BIOMETRICS_FLAG = "SETTINGS_SECURITY_USE_BIOMETRICS_FLAG" private const val SETTINGS_SECURITY_USE_GRACE_PERIOD_FLAG = "SETTINGS_SECURITY_USE_GRACE_PERIOD_FLAG" + const val SETTINGS_SECURITY_USE_COMPLETE_NOTIFICATIONS_FLAG = "SETTINGS_SECURITY_USE_COMPLETE_NOTIFICATIONS_FLAG" // other const val SETTINGS_MEDIA_SAVING_PERIOD_KEY = "SETTINGS_MEDIA_SAVING_PERIOD_KEY" @@ -856,6 +857,14 @@ class VectorPreferences @Inject constructor(private val context: Context) { return defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_GRACE_PERIOD_FLAG, true) } + /** + * Return true if Pin code is disabled, or if user set the settings to see full notification content + */ + fun useCompleteNotificationFormat(): Boolean { + return !useFlagPinCode() + || defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_COMPLETE_NOTIFICATIONS_FLAG, true) + } + fun backgroundSyncTimeOut(): Int { return tryOrNull { // The xml pref is saved as a string so use getString and parse diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt index f8353c31af..4a6965618e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt @@ -22,6 +22,7 @@ import androidx.preference.Preference import androidx.preference.SwitchPreference import im.vector.app.R import im.vector.app.features.navigation.Navigator +import im.vector.app.features.notifications.NotificationDrawerManager import im.vector.app.features.pin.PinActivity import im.vector.app.features.pin.PinCodeStore import im.vector.app.features.pin.PinMode @@ -30,7 +31,8 @@ import javax.inject.Inject class VectorSettingsPinFragment @Inject constructor( private val pinCodeStore: PinCodeStore, - private val navigator: Navigator + private val navigator: Navigator, + private val notificationDrawerManager: NotificationDrawerManager ) : VectorSettingsBaseFragment() { override var titleRes = R.string.settings_security_application_protection_screen_title @@ -40,8 +42,18 @@ class VectorSettingsPinFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_SECURITY_USE_PIN_CODE_FLAG)!! } + private val useCompleteNotificationPref by lazy { + findPreference(VectorPreferences.SETTINGS_SECURITY_USE_COMPLETE_NOTIFICATIONS_FLAG)!! + } + override fun bindPref() { refreshPinCodeStatus() + + useCompleteNotificationPref.setOnPreferenceChangeListener { _, _ -> + // Refresh the drawer for an immediate effect of this change + notificationDrawerManager.refreshNotificationDrawer() + true + } } private fun refreshPinCodeStatus() { diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 9004339bb4..3795aa8336 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1154,6 +1154,10 @@ 1 room %d rooms + + 1 invitation + %d invitations + %1$s: 1 message @@ -1165,6 +1169,8 @@ %1$s in %2$s" + %1$s in %2$s and %3$s" + %1$s and %2$s" New Event Room New Messages @@ -2574,6 +2580,9 @@ Use biometrics Depending on your device, you will be able to unlock using fingerprints, face recognition, iris recognition, etc. PIN code is the only way to unlock the application. + Display complete notifications + Show full notification details, including rooms details and message contents. + Only display number of unread messages in a simple notification. Enable grace period PIN code will be asked after 2 minutes not using the application. PIN code will be requested every time you put the application to foreground. diff --git a/vector/src/main/res/xml/vector_settings_pin.xml b/vector/src/main/res/xml/vector_settings_pin.xml index c0d480a563..27eb275b09 100644 --- a/vector/src/main/res/xml/vector_settings_pin.xml +++ b/vector/src/main/res/xml/vector_settings_pin.xml @@ -15,6 +15,14 @@ android:summaryOn="@string/settings_security_pin_code_use_biometrics_summary_on" android:title="@string/settings_security_pin_code_use_biometrics_title" /> + +