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

Commit fcbb49b6 authored by Steve Elliott's avatar Steve Elliott Committed by Android (Google) Code Review
Browse files

Merge "Move NIC binding to NotificationShelfViewBinder" into main

parents 0989be7c 4fc693ea
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -15,18 +15,26 @@
package com.android.systemui.common.ui

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.annotation.DimenRes
import androidx.annotation.LayoutRes
import com.android.settingslib.Utils
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.onDensityOrFontScaleChanged
import com.android.systemui.statusbar.policy.onThemeChanged
import com.android.systemui.util.kotlin.emitOnStart
import com.android.systemui.util.view.bindLatest
import javax.inject.Inject
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge

/** Configuration-aware-state-tracking utilities. */
class ConfigurationState
@@ -34,6 +42,7 @@ class ConfigurationState
constructor(
    private val configurationController: ConfigurationController,
    @Application private val context: Context,
    private val layoutInflater: LayoutInflater,
) {
    /**
     * Returns a [Flow] that emits a dimension pixel size that is kept in sync with the device
@@ -57,4 +66,65 @@ constructor(
            Utils.getColorAttrDefaultColor(context, id, defaultValue)
        }
    }

    /**
     * Returns a [Flow] that emits a [View] that is re-inflated as necessary to remain in sync with
     * the device configuration.
     *
     * @see LayoutInflater.inflate
     */
    @Suppress("UNCHECKED_CAST")
    fun <T : View> inflateLayout(
        @LayoutRes id: Int,
        root: ViewGroup?,
        attachToRoot: Boolean,
    ): Flow<T> {
        // TODO(b/305930747): This may lead to duplicate invocations if both flows emit, find a
        //  solution to only emit one event.
        return merge(
                configurationController.onThemeChanged,
                configurationController.onDensityOrFontScaleChanged,
            )
            .emitOnStart()
            .map { layoutInflater.inflate(id, root, attachToRoot) as T }
    }
}

/**
 * Perform an inflation right away, then re-inflate whenever the device configuration changes, and
 * call [onInflate] on the resulting view each time. Disposes of the [DisposableHandle] returned by
 * [onInflate] when done.
 *
 * This never completes unless cancelled, it just suspends and waits for updates.
 *
 * For parameters [resource], [root] and [attachToRoot], see [LayoutInflater.inflate].
 *
 * An example use-case of this is when a view needs to be re-inflated whenever a configuration
 * change occurs, which would require the ViewBinder to then re-bind the new view. For example, the
 * code in the parent view's binder would look like:
 * ```
 * parentView.repeatWhenAttached {
 *     configurationState
 *         .reinflateOnChange(
 *             R.layout.my_layout,
 *             parentView,
 *             attachToRoot = false,
 *             coroutineScope = lifecycleScope,
 *             configurationController.onThemeChanged,
 *         ) { view: ChildView ->
 *             ChildViewBinder.bind(view, childViewModel)
 *         }
 * }
 * ```
 *
 * In turn, the bind method (passed through [onInflate]) uses [repeatWhenAttached], which returns a
 * [DisposableHandle].
 */
suspend fun <T : View> ConfigurationState.reinflateAndBindLatest(
    @LayoutRes resource: Int,
    root: ViewGroup?,
    attachToRoot: Boolean,
    onInflate: (T) -> DisposableHandle?,
) {
    inflateLayout<T>(resource, root, attachToRoot).bindLatest(onInflate)
}
+1 −23
Original line number Diff line number Diff line
@@ -21,13 +21,10 @@ import android.view.View
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.flags.RefactorFlag
import com.android.systemui.statusbar.NotificationShelfController
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerShelfViewModel
import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.NotificationIconAreaController
@@ -53,15 +50,10 @@ constructor(
    private val dozeParameters: DozeParameters,
    private val featureFlags: FeatureFlagsClassic,
    private val screenOffAnimationController: ScreenOffAnimationController,
    private val shelfIconViewStore: ShelfNotificationIconViewStore,
    private val shelfIconsViewModel: NotificationIconContainerShelfViewModel,
    private val aodIconViewStore: AlwaysOnDisplayNotificationIconViewStore,
    private val aodIconsViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
) : NotificationIconAreaController {

    private val shelfRefactor = RefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR)

    private var shelfIcons: NotificationIconContainer? = null
    private var aodIcons: NotificationIconContainer? = null
    private var aodBindJob: DisposableHandle? = null

@@ -91,21 +83,7 @@ constructor(
    override fun setupShelf(notificationShelfController: NotificationShelfController) =
        NotificationShelfViewBinderWrapperControllerImpl.unsupported

    override fun setShelfIcons(icons: NotificationIconContainer) {
        if (shelfRefactor.isUnexpectedlyInLegacyMode()) {
            NotificationIconContainerViewBinder.bind(
                icons,
                shelfIconsViewModel,
                configuration,
                configurationController,
                dozeParameters,
                featureFlags,
                screenOffAnimationController,
                shelfIconViewStore,
            )
            shelfIcons = icons
        }
    }
    override fun setShelfIcons(icons: NotificationIconContainer) = unsupported

    override fun onDensityOrFontScaleChanged(context: Context) = unsupported

+28 −4
Original line number Diff line number Diff line
@@ -19,19 +19,26 @@ package com.android.systemui.statusbar.notification.shelf.ui.viewbinder
import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.NotificationShelfController
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.ShelfNotificationIconViewStore
import com.android.systemui.statusbar.notification.row.ui.viewbinder.ActivatableNotificationViewBinder
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.NotificationIconContainer
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.statusbar.policy.ConfigurationController
import javax.inject.Inject
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.launch
@@ -75,14 +82,31 @@ object NotificationShelfViewBinder {
    fun bind(
        shelf: NotificationShelf,
        viewModel: NotificationShelfViewModel,
        configuration: ConfigurationState,
        configurationController: ConfigurationController,
        dozeParameters: DozeParameters,
        falsingManager: FalsingManager,
        featureFlags: FeatureFlags,
        featureFlags: FeatureFlagsClassic,
        notificationIconAreaController: NotificationIconAreaController,
        screenOffAnimationController: ScreenOffAnimationController,
        shelfIconViewStore: ShelfNotificationIconViewStore,
    ) {
        ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager)
        shelf.apply {
            // TODO(278765923): Replace with eventual NotificationIconContainerViewBinder#bind()
            if (featureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
                NotificationIconContainerViewBinder.bind(
                    shelfIcons,
                    viewModel.icons,
                    configuration,
                    configurationController,
                    dozeParameters,
                    featureFlags,
                    screenOffAnimationController,
                    shelfIconViewStore,
                )
            } else {
                notificationIconAreaController.setShelfIcons(shelfIcons)
            }
            repeatWhenAttached {
                repeatOnLifecycle(Lifecycle.State.STARTED) {
                    launch {
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.shelf.ui.viewmodel

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerShelfViewModel
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel
import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor
import javax.inject.Inject
@@ -31,6 +32,7 @@ class NotificationShelfViewModel
constructor(
    private val interactor: NotificationShelfInteractor,
    activatableViewModel: ActivatableNotificationViewModel,
    val icons: NotificationIconContainerShelfViewModel,
) : ActivatableNotificationViewModel by activatableViewModel {
    /** Is the shelf allowed to be clickable when it has content? */
    val isClickable: Flow<Boolean>
+20 −3
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import com.android.systemui.Gefingerpoken;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.common.ui.ConfigurationState;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
@@ -107,6 +108,7 @@ import com.android.systemui.statusbar.notification.collection.render.Notificatio
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import com.android.systemui.statusbar.notification.dagger.SilentHeader;
import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.ShelfNotificationIconViewStore;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -117,10 +119,12 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -212,6 +216,10 @@ public class NotificationStackScrollLayoutController {
    private final SecureSettings mSecureSettings;
    private final NotificationDismissibilityProvider mDismissibilityProvider;
    private final ActivityStarter mActivityStarter;
    private final ConfigurationState mConfigurationState;
    private final DozeParameters mDozeParameters;
    private final ScreenOffAnimationController mScreenOffAnimationController;
    private final ShelfNotificationIconViewStore mShelfIconViewStore;

    private View mLongPressedView;

@@ -674,7 +682,10 @@ public class NotificationStackScrollLayoutController {
            SecureSettings secureSettings,
            NotificationDismissibilityProvider dismissibilityProvider,
            ActivityStarter activityStarter,
            SplitShadeStateController splitShadeStateController) {
            SplitShadeStateController splitShadeStateController,
            ConfigurationState configurationState, DozeParameters dozeParameters,
            ScreenOffAnimationController screenOffAnimationController,
            ShelfNotificationIconViewStore shelfIconViewStore) {
        mView = view;
        mKeyguardTransitionRepo = keyguardTransitionRepo;
        mStackStateLogger = stackLogger;
@@ -724,6 +735,10 @@ public class NotificationStackScrollLayoutController {
        mSecureSettings = secureSettings;
        mDismissibilityProvider = dismissibilityProvider;
        mActivityStarter = activityStarter;
        mConfigurationState = configurationState;
        mDozeParameters = dozeParameters;
        mScreenOffAnimationController = screenOffAnimationController;
        mShelfIconViewStore = shelfIconViewStore;
        mView.passSplitShadeStateController(splitShadeStateController);
        updateResources();
        setUpView();
@@ -832,8 +847,10 @@ public class NotificationStackScrollLayoutController {

        mViewModel.ifPresent(
                vm -> NotificationListViewBinder
                        .bind(mView, vm, mFalsingManager, mFeatureFlags, mNotifIconAreaController,
                                mConfigurationController));
                        .bind(mView, vm, mConfigurationState, mConfigurationController,
                                mDozeParameters, mFalsingManager, mFeatureFlags,
                                mNotifIconAreaController, mScreenOffAnimationController,
                                mShelfIconViewStore));

        collectFlow(mView, mKeyguardTransitionRepo.getTransitions(),
                this::onKeyguardTransitionChanged);
Loading