Notification Minimalism Prototype
When the flag is enabled:
* Cap notifications on lock screen at 1, excluding the UMO
* Act as if LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS is Enabled
Bug: 330387368
Test: atest SystemUITests
Flag: ACONFIG com.android.systemui.notification_minimalism_prototype DEVELOPMENT
Change-Id: Ibc47fd1858b62abcab557198ebaf5f2f4587bf11
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 8da5021..21af1a2 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -25,6 +25,16 @@
}
flag {
+ name: "notification_minimalism_prototype"
+ namespace: "systemui"
+ description: "Prototype of notification minimalism; the new 'Intermediate' lockscreen customization proposal."
+ bug: "330387368"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "notification_view_flipper_pausing"
namespace: "systemui"
description: "Pause ViewFlippers inside Notification custom layouts when the shade is closed."
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 0c69a65..8531eaa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -22,6 +22,7 @@
import android.provider.Settings
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
+import com.android.systemui.Flags.notificationMinimalismPrototype
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
@@ -59,6 +60,7 @@
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -260,8 +262,11 @@
}
}
- private suspend fun trackUnseenFilterSettingChanges() {
- secureSettings
+ private fun unseenFeatureEnabled(): Flow<Boolean> {
+ if (notificationMinimalismPrototype()) {
+ return flowOf(true)
+ }
+ return secureSettings
// emit whenever the setting has changed
.observerFlow(
UserHandle.USER_ALL,
@@ -283,17 +288,20 @@
// only track the most recent emission, if events are happening faster than they can be
// consumed
.conflate()
- .collectLatest { setting ->
- // update local field and invalidate if necessary
- if (setting != unseenFilterEnabled) {
- unseenFilterEnabled = setting
- unseenNotifFilter.invalidateList("unseen setting changed")
- }
- // if the setting is enabled, then start tracking and filtering unseen notifications
- if (setting) {
- trackSeenNotifications()
- }
+ }
+
+ private suspend fun trackUnseenFilterSettingChanges() {
+ unseenFeatureEnabled().collectLatest { setting ->
+ // update local field and invalidate if necessary
+ if (setting != unseenFilterEnabled) {
+ unseenFilterEnabled = setting
+ unseenNotifFilter.invalidateList("unseen setting changed")
}
+ // if the setting is enabled, then start tracking and filtering unseen notifications
+ if (setting) {
+ trackSeenNotifications()
+ }
+ }
}
private val collectionListener =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
index 2d9c63e..1b53cbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -20,6 +20,7 @@
import android.util.Log
import android.view.View.GONE
import androidx.annotation.VisibleForTesting
+import com.android.systemui.Flags.notificationMinimalismPrototype
import com.android.systemui.res.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
@@ -66,6 +67,11 @@
*/
private var maxKeyguardNotifications by notNull<Int>()
+ /**
+ * Whether [maxKeyguardNotifications] will have 1 added to it when media is shown in the stack.
+ */
+ private var maxNotificationsExcludesMedia = false
+
/** Minimum space between two notifications, see [calculateGapAndDividerHeight]. */
private var dividerHeight by notNull<Float>()
@@ -168,7 +174,11 @@
log { "\n" }
val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfHeight)
+
+ // TODO: Avoid making this split shade assumption by simply checking the stack for media
val isMediaShowing = mediaDataManager.hasActiveMediaOrRecommendation()
+ val isMediaShowingInStack = isMediaShowing && !splitShadeStateController
+ .shouldUseSplitNotificationShade(resources)
log { "\tGet maxNotifWithoutSavingSpace ---" }
val maxNotifWithoutSavingSpace =
@@ -181,12 +191,11 @@
}
// How many notifications we can show at heightWithoutLockscreenConstraints
- var minCountAtHeightWithoutConstraints =
- if (isMediaShowing && !splitShadeStateController
- .shouldUseSplitNotificationShade(resources)) 2 else 1
+ val minCountAtHeightWithoutConstraints = if (isMediaShowingInStack) 2 else 1
log {
"\t---maxNotifWithoutSavingSpace=$maxNotifWithoutSavingSpace " +
"isMediaShowing=$isMediaShowing" +
+ "isMediaShowingInStack=$isMediaShowingInStack" +
"minCountAtHeightWithoutConstraints=$minCountAtHeightWithoutConstraints"
}
log { "\n" }
@@ -223,7 +232,9 @@
}
if (onLockscreen()) {
- maxNotifications = min(maxKeyguardNotifications, maxNotifications)
+ val increaseMaxForMedia = maxNotificationsExcludesMedia && isMediaShowingInStack
+ val lockscreenMax = maxKeyguardNotifications.safeIncrementIf(increaseMaxForMedia)
+ maxNotifications = min(lockscreenMax, maxNotifications)
}
// Could be < 0 if the space available is less than the shelf size. Returns 0 in this case.
@@ -276,7 +287,7 @@
height = notifsHeight + shelfHeightWithSpaceBefore
log {
"--- computeHeight(maxNotifs=$maxNotifs, shelfHeight=$shelfHeight)" +
- " -> ${height}=($notifsHeight+$shelfHeightWithSpaceBefore)" +
+ " -> $height=($notifsHeight+$shelfHeightWithSpaceBefore)" +
" | saveSpaceOnLockscreen=$saveSpaceOnLockscreen"
}
}
@@ -367,8 +378,9 @@
}
fun updateResources() {
- maxKeyguardNotifications =
- infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
+ maxKeyguardNotifications = if (notificationMinimalismPrototype()) 1
+ else infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
+ maxNotificationsExcludesMedia = notificationMinimalismPrototype()
dividerHeight =
max(1f, resources.getDimensionPixelSize(R.dimen.notification_divider_height).toFloat())
@@ -486,6 +498,13 @@
v
}
+ private fun Int.safeIncrementIf(condition: Boolean): Int =
+ if (condition && this != Int.MAX_VALUE) {
+ this + 1
+ } else {
+ this
+ }
+
/** Returns the last index where [predicate] returns true, or -1 if it was always false. */
private fun <T> Sequence<T>.lastIndexWhile(predicate: (T) -> Boolean): Int =
takeWhile(predicate).count() - 1