Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fecaa4b2 authored by Jeff DeCew's avatar Jeff DeCew Committed by Android (Google) Code Review
Browse files

Merge "Notification minimalism prototype update" into main

parents f06ff25d 5f6a4ead
Loading
Loading
Loading
Loading
+35 −28
Original line number Diff line number Diff line
@@ -18,33 +18,29 @@ package com.android.systemui.statusbar.notification

import android.content.Context
import android.provider.DeviceConfig

import com.android.internal.annotations.VisibleForTesting
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP
import com.android.systemui.statusbar.notification.stack.BUCKET_MEDIA_CONTROLS
import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
import com.android.systemui.statusbar.notification.stack.BUCKET_PRIORITY_PEOPLE
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
import com.android.systemui.statusbar.notification.stack.PriorityBucket
import com.android.systemui.util.DeviceConfigProxy
import com.android.systemui.util.Utils

import javax.inject.Inject

private var sUsePeopleFiltering: Boolean? = null

/**
 * Feature controller for the NOTIFICATIONS_USE_PEOPLE_FILTERING config.
 */
/** Feature controller for the NOTIFICATIONS_USE_PEOPLE_FILTERING config. */
@SysUISingleton
class NotificationSectionsFeatureManager @Inject constructor(
    val proxy: DeviceConfigProxy,
    val context: Context
) {
class NotificationSectionsFeatureManager
@Inject
constructor(val proxy: DeviceConfigProxy, val context: Context) {

    fun isFilteringEnabled(): Boolean {
        return usePeopleFiltering(proxy)
@@ -55,30 +51,37 @@ class NotificationSectionsFeatureManager @Inject constructor(
    }

    fun getNotificationBuckets(): IntArray {
        if (PriorityPeopleSection.isEnabled) {
        if (PriorityPeopleSection.isEnabled || NotificationMinimalismPrototype.V2.isEnabled) {
            // We don't need this list to be adaptive, it can be the superset of all features.
            return intArrayOf(
                    BUCKET_MEDIA_CONTROLS,
            return PriorityBucket.getAllInOrder()
        }
        return when {
            isFilteringEnabled() && isMediaControlsEnabled() ->
                intArrayOf(
                    BUCKET_HEADS_UP,
                    BUCKET_FOREGROUND_SERVICE,
                    BUCKET_PRIORITY_PEOPLE,
                    BUCKET_MEDIA_CONTROLS,
                    BUCKET_PEOPLE,
                    BUCKET_ALERTING,
                    BUCKET_SILENT,
                    BUCKET_SILENT
                )
        }
        return when {
            isFilteringEnabled() && isMediaControlsEnabled() ->
                intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS,
                        BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT)
            !isFilteringEnabled() && isMediaControlsEnabled() ->
                intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS,
                        BUCKET_ALERTING, BUCKET_SILENT)
                intArrayOf(
                    BUCKET_HEADS_UP,
                    BUCKET_FOREGROUND_SERVICE,
                    BUCKET_MEDIA_CONTROLS,
                    BUCKET_ALERTING,
                    BUCKET_SILENT
                )
            isFilteringEnabled() && !isMediaControlsEnabled() ->
                intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_PEOPLE,
                        BUCKET_ALERTING, BUCKET_SILENT)
            else ->
                intArrayOf(BUCKET_ALERTING, BUCKET_SILENT)
                intArrayOf(
                    BUCKET_HEADS_UP,
                    BUCKET_FOREGROUND_SERVICE,
                    BUCKET_PEOPLE,
                    BUCKET_ALERTING,
                    BUCKET_SILENT
                )
            else -> intArrayOf(BUCKET_ALERTING, BUCKET_SILENT)
        }
    }

@@ -94,8 +97,12 @@ class NotificationSectionsFeatureManager @Inject constructor(

private fun usePeopleFiltering(proxy: DeviceConfigProxy): Boolean {
    if (sUsePeopleFiltering == null) {
        sUsePeopleFiltering = proxy.getBoolean(
                DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, true)
        sUsePeopleFiltering =
            proxy.getBoolean(
                DeviceConfig.NAMESPACE_SYSTEMUI,
                NOTIFICATIONS_USE_PEOPLE_FILTERING,
                true
            )
    }

    return sUsePeopleFiltering!!
+18 −13
Original line number Diff line number Diff line
@@ -60,22 +60,27 @@ public class ColorizedFgsCoordinator implements Coordinator {
        public boolean isInSection(ListEntry entry) {
            NotificationEntry notificationEntry = entry.getRepresentativeEntry();
            if (notificationEntry != null) {
                return isColorizedForegroundService(notificationEntry) || isCall(notificationEntry);
                return isRichOngoing(notificationEntry);
            }
            return false;
        }
    };

    /** Determines if the given notification is a colorized or call notification */
    public static boolean isRichOngoing(NotificationEntry entry) {
        return isColorizedForegroundService(entry) || isCall(entry);
    }

        private boolean isColorizedForegroundService(NotificationEntry entry) {
    private static boolean isColorizedForegroundService(NotificationEntry entry) {
        Notification notification = entry.getSbn().getNotification();
        return notification.isForegroundService()
                && notification.isColorized()
                && entry.getImportance() > IMPORTANCE_MIN;
    }

        private boolean isCall(NotificationEntry entry) {
    private static boolean isCall(NotificationEntry entry) {
        Notification notification = entry.getSbn().getNotification();
        return entry.getImportance() > IMPORTANCE_MIN
                && notification.isStyle(Notification.CallStyle.class);
    }
    };
}
+39 −18
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

package com.android.systemui.statusbar.notification.collection.coordinator

import android.app.NotificationManager
import android.os.UserHandle
import android.provider.Settings
import androidx.annotation.VisibleForTesting
@@ -44,7 +45,8 @@ import com.android.systemui.statusbar.notification.collection.provider.SectionHe
import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
import com.android.systemui.statusbar.notification.stack.BUCKET_TOP_ONGOING
import com.android.systemui.statusbar.notification.stack.BUCKET_TOP_UNSEEN
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.headsUpEvents
import com.android.systemui.util.asIndenting
@@ -113,7 +115,7 @@ constructor(
    private fun attachUnseenFilter(pipeline: NotifPipeline) {
        if (NotificationMinimalismPrototype.V2.isEnabled) {
            pipeline.addPromoter(unseenNotifPromoter)
            pipeline.addOnBeforeTransformGroupsListener(::pickOutTopUnseenNotif)
            pipeline.addOnBeforeTransformGroupsListener(::pickOutTopUnseenNotifs)
        }
        pipeline.addFinalizeFilter(unseenNotifFilter)
        pipeline.addCollectionListener(collectionListener)
@@ -347,15 +349,16 @@ constructor(
            }
        }

    private fun pickOutTopUnseenNotif(list: List<ListEntry>) {
    private fun pickOutTopUnseenNotifs(list: List<ListEntry>) {
        if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return
        // Only ever elevate a top unseen notification on keyguard, not even locked shade
        if (statusBarStateController.state != StatusBarState.KEYGUARD) {
            seenNotificationsInteractor.setTopOngoingNotification(null)
            seenNotificationsInteractor.setTopUnseenNotification(null)
            return
        }
        // On keyguard pick the top-ranked unseen or ongoing notification to elevate
        seenNotificationsInteractor.setTopUnseenNotification(
        val nonSummaryEntries: Sequence<NotificationEntry> =
            list
                .asSequence()
                .flatMap {
@@ -365,7 +368,15 @@ constructor(
                        else -> error("unhandled type of $it")
                    }
                }
                .filter { shouldIgnoreUnseenCheck(it) || it in unseenNotifications }
                .filter { it.importance >= NotificationManager.IMPORTANCE_DEFAULT }
        seenNotificationsInteractor.setTopOngoingNotification(
            nonSummaryEntries
                .filter { ColorizedFgsCoordinator.isRichOngoing(it) }
                .minByOrNull { it.ranking.rank }
        )
        seenNotificationsInteractor.setTopUnseenNotification(
            nonSummaryEntries
                .filter { !ColorizedFgsCoordinator.isRichOngoing(it) && it in unseenNotifications }
                .minByOrNull { it.ranking.rank }
        )
    }
@@ -375,29 +386,39 @@ constructor(
        object : NotifPromoter("$TAG-unseen") {
            override fun shouldPromoteToTopLevel(child: NotificationEntry): Boolean =
                if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false
                else if (!NotificationMinimalismPrototype.V2.ungroupTopUnseen) false
                else
                    seenNotificationsInteractor.isTopUnseenNotification(child) &&
                        NotificationMinimalismPrototype.V2.ungroupTopUnseen
                    seenNotificationsInteractor.isTopOngoingNotification(child) ||
                        seenNotificationsInteractor.isTopUnseenNotification(child)
        }

    val unseenNotifSectioner =
        object : NotifSectioner("Unseen", BUCKET_FOREGROUND_SERVICE) {
    val topOngoingSectioner =
        object : NotifSectioner("TopOngoing", BUCKET_TOP_ONGOING) {
            override fun isInSection(entry: ListEntry): Boolean {
                if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false
                if (
                    seenNotificationsInteractor.isTopUnseenNotification(entry.representativeEntry)
                ) {
                    return true
                return entry.anyEntry { notificationEntry ->
                    seenNotificationsInteractor.isTopOngoingNotification(notificationEntry)
                }
                if (entry !is GroupEntry) {
                    return false
            }
                return entry.children.any {
                    seenNotificationsInteractor.isTopUnseenNotification(it)
        }

    val topUnseenSectioner =
        object : NotifSectioner("TopUnseen", BUCKET_TOP_UNSEEN) {
            override fun isInSection(entry: ListEntry): Boolean {
                if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false
                return entry.anyEntry { notificationEntry ->
                    seenNotificationsInteractor.isTopUnseenNotification(notificationEntry)
                }
            }
        }

    private fun ListEntry.anyEntry(predicate: (NotificationEntry?) -> Boolean) =
        when {
            predicate(representativeEntry) -> true
            this !is GroupEntry -> false
            else -> children.any(predicate)
        }

    @VisibleForTesting
    internal val unseenNotifFilter =
        object : NotifFilter("$TAG-unseen") {
+5 −2
Original line number Diff line number Diff line
@@ -116,11 +116,14 @@ constructor(
        }

        // Manually add Ordered Sections
        if (NotificationMinimalismPrototype.V2.isEnabled) {
            mOrderedSections.add(keyguardCoordinator.topOngoingSectioner) // Top Ongoing
        }
        mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp
        mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService
        if (NotificationMinimalismPrototype.V2.isEnabled) {
            mOrderedSections.add(keyguardCoordinator.unseenNotifSectioner) // Unseen (FGS)
            mOrderedSections.add(keyguardCoordinator.topUnseenSectioner) // Top Unseen
        }
        mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService
        if (PriorityPeopleSection.isEnabled) {
            mOrderedSections.add(conversationCoordinator.priorityPeopleSectioner) // Priority People
        }
+4 −0
Original line number Diff line number Diff line
@@ -42,6 +42,9 @@ class ActiveNotificationListRepository @Inject constructor() {
    /** Stats about the list of notifications attached to the shade */
    val notifStats = MutableStateFlow(NotifStats.empty)

    /** The key of the top ongoing notification */
    val topOngoingNotificationKey = MutableStateFlow<String?>(null)

    /** The key of the top unseen notification */
    val topUnseenNotificationKey = MutableStateFlow<String?>(null)
}
@@ -75,6 +78,7 @@ data class ActiveNotificationsStore(
    /** Unique key identifying an [ActiveNotificationEntryModel] in the store. */
    sealed class Key {
        data class Individual(val key: String) : Key()

        data class Group(val key: String) : Key()
    }

Loading