Merge "ViewModel+Binder for NotificationStackScrollLayout" into udc-dev

This commit is contained in:
Steve Elliott
2023-04-19 21:20:25 +00:00
committed by Android (Google) Code Review
7 changed files with 159 additions and 52 deletions

View File

@@ -33,12 +33,9 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.NotificationIconContainer
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import com.android.systemui.util.kotlin.getValue
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
/**
* Controller class for [NotificationShelf]. This implementation serves as a temporary wrapper
@@ -47,39 +44,12 @@ import kotlinx.coroutines.flow.onEach
* removed, this class can go away and the ViewBinder can be used directly.
*/
@CentralSurfacesScope
class NotificationShelfViewBinderWrapperControllerImpl
@Inject
constructor(
private val shelf: NotificationShelf,
private val viewModel: NotificationShelfViewModel,
featureFlags: FeatureFlags,
private val falsingManager: FalsingManager,
hostControllerLazy: Lazy<NotificationStackScrollLayoutController>,
private val notificationIconAreaController: NotificationIconAreaController,
) : NotificationShelfController {
private val hostController: NotificationStackScrollLayoutController by hostControllerLazy
class NotificationShelfViewBinderWrapperControllerImpl @Inject constructor() :
NotificationShelfController {
override val view: NotificationShelf
get() = unsupported
init {
shelf.apply {
setRefactorFlagEnabled(featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR))
useRoundnessSourceTypes(featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES))
setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM))
}
}
fun init() {
NotificationShelfViewBinder.bind(viewModel, shelf, falsingManager)
hostController.setShelf(shelf)
hostController.setOnNotificationRemovedListener { child, _ ->
view.requestRoundnessResetFor(child)
}
notificationIconAreaController.setShelfIcons(shelf.shelfIcons)
}
override val intrinsicHeight: Int
get() = unsupported
@@ -99,21 +69,32 @@ constructor(
get() = NotificationShelfController.throwIllegalFlagStateError(expected = true)
}
/** Binds a [NotificationShelf] to its backend. */
/** Binds a [NotificationShelf] to its [view model][NotificationShelfViewModel]. */
object NotificationShelfViewBinder {
fun bind(
viewModel: NotificationShelfViewModel,
shelf: NotificationShelf,
viewModel: NotificationShelfViewModel,
falsingManager: FalsingManager,
featureFlags: FeatureFlags,
notificationIconAreaController: NotificationIconAreaController,
) {
ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager)
shelf.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.canModifyColorOfNotifications
.onEach(shelf::setCanModifyColorOfNotifications)
.launchIn(this)
viewModel.isClickable.onEach(shelf::setCanInteract).launchIn(this)
registerViewListenersWhileAttached(shelf, viewModel)
shelf.apply {
setRefactorFlagEnabled(true)
useRoundnessSourceTypes(featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES))
setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM))
// TODO(278765923): Replace with eventual NotificationIconContainerViewBinder#bind()
notificationIconAreaController.setShelfIcons(shelfIcons)
repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.canModifyColorOfNotifications.collect(
::setCanModifyColorOfNotifications
)
}
launch { viewModel.isClickable.collect(::setCanInteract) }
registerViewListenersWhileAttached(shelf, viewModel)
}
}
}
}

View File

@@ -2839,6 +2839,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* @param listener callback for notification removed
*/
public void setOnNotificationRemovedListener(OnNotificationRemovedListener listener) {
NotificationShelfController.assertRefactorFlagDisabled(mAmbientState.getFeatureFlags());
mOnNotificationRemovedListener = listener;
}
@@ -2852,10 +2853,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
if (!mChildTransferInProgress) {
onViewRemovedInternal(expandableView, this);
}
if (mOnNotificationRemovedListener != null) {
mOnNotificationRemovedListener.onNotificationRemoved(
expandableView,
mChildTransferInProgress);
if (mAmbientState.getFeatureFlags().isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
mShelf.requestRoundnessResetFor(expandableView);
} else {
if (mOnNotificationRemovedListener != null) {
mOnNotificationRemovedListener.onNotificationRemoved(
expandableView,
mChildTransferInProgress);
}
}
}

View File

@@ -105,11 +105,14 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
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.CentralSurfaces;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
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.ScrimController;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -122,16 +125,17 @@ import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.Compile;
import com.android.systemui.util.settings.SecureSettings;
import kotlin.Unit;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
import kotlin.Unit;
/**
* Controller for {@link NotificationStackScrollLayout}.
*/
@@ -151,6 +155,8 @@ public class NotificationStackScrollLayoutController {
private final ConfigurationController mConfigurationController;
private final ZenModeController mZenModeController;
private final MetricsLogger mMetricsLogger;
private final Optional<NotificationListViewModel> mViewModel;
private final DumpManager mDumpManager;
private final FalsingCollector mFalsingCollector;
private final FalsingManager mFalsingManager;
@@ -175,6 +181,8 @@ public class NotificationStackScrollLayoutController {
private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private final StackStateLogger mStackStateLogger;
private final NotificationStackScrollLogger mLogger;
private final NotificationIconAreaController mNotifIconAreaController;
private final GroupExpansionManager mGroupExpansionManager;
private final NotifPipelineFlags mNotifPipelineFlags;
private final SeenNotificationsProvider mSeenNotificationsProvider;
@@ -642,6 +650,7 @@ public class NotificationStackScrollLayoutController {
KeyguardBypassController keyguardBypassController,
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
Optional<NotificationListViewModel> nsslViewModel,
MetricsLogger metricsLogger,
DumpManager dumpManager,
FalsingCollector falsingCollector,
@@ -665,6 +674,7 @@ public class NotificationStackScrollLayoutController {
StackStateLogger stackLogger,
NotificationStackScrollLogger logger,
NotificationStackSizeCalculator notificationStackSizeCalculator,
NotificationIconAreaController notifIconAreaController,
FeatureFlags featureFlags,
NotificationTargetsHelper notificationTargetsHelper,
SecureSettings secureSettings,
@@ -686,6 +696,7 @@ public class NotificationStackScrollLayoutController {
mKeyguardBypassController = keyguardBypassController;
mZenModeController = zenModeController;
mLockscreenUserManager = lockscreenUserManager;
mViewModel = nsslViewModel;
mMetricsLogger = metricsLogger;
mDumpManager = dumpManager;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
@@ -707,6 +718,7 @@ public class NotificationStackScrollLayoutController {
mVisibilityLocationProviderDelegator = visibilityLocationProviderDelegator;
mSeenNotificationsProvider = seenNotificationsProvider;
mShadeController = shadeController;
mNotifIconAreaController = notifIconAreaController;
mFeatureFlags = featureFlags;
mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
mNotificationTargetsHelper = notificationTargetsHelper;
@@ -820,6 +832,10 @@ public class NotificationStackScrollLayoutController {
mGroupExpansionManager.registerGroupExpansionChangeListener(
(changedRow, expanded) -> mView.onGroupExpandChanged(changedRow, expanded));
mViewModel.ifPresent(
vm -> NotificationListViewBinder
.bind(mView, vm, mFalsingManager, mFeatureFlags, mNotifIconAreaController));
}
private boolean isInVisibleLocation(NotificationEntry entry) {

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.stack.ui.viewbinder
import android.view.LayoutInflater
import com.android.systemui.R
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinder
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel
import com.android.systemui.statusbar.phone.NotificationIconAreaController
/** Binds a [NotificationStackScrollLayout] to its [view model][NotificationListViewModel]. */
object NotificationListViewBinder {
@JvmStatic
fun bind(
view: NotificationStackScrollLayout,
viewModel: NotificationListViewModel,
falsingManager: FalsingManager,
featureFlags: FeatureFlags,
iconAreaController: NotificationIconAreaController,
) {
val shelf =
LayoutInflater.from(view.context)
.inflate(R.layout.status_bar_notification_shelf, view, false) as NotificationShelf
NotificationShelfViewBinder.bind(
shelf,
viewModel.shelf,
falsingManager,
featureFlags,
iconAreaController
)
view.setShelf(shelf)
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
import dagger.Module
import dagger.Provides
import java.util.Optional
import javax.inject.Provider
/** ViewModel for the list of notifications. */
class NotificationListViewModel(
val shelf: NotificationShelfViewModel,
)
@Module
object NotificationListViewModelModule {
@JvmStatic
@Provides
fun maybeProvideViewModel(
featureFlags: FeatureFlags,
shelfViewModel: Provider<NotificationShelfViewModel>,
): Optional<NotificationListViewModel> =
if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
Optional.of(NotificationListViewModel(shelfViewModel.get()))
} else {
Optional.empty()
}
}

View File

@@ -55,6 +55,7 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfC
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule;
import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModelModule;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.StatusBarBoundsProvider;
@@ -87,7 +88,10 @@ import javax.inject.Named;
import javax.inject.Provider;
@Module(subcomponents = StatusBarFragmentComponent.class,
includes = { ActivatableNotificationViewModelModule.class })
includes = {
ActivatableNotificationViewModelModule.class,
NotificationListViewModelModule.class,
})
public abstract class StatusBarViewModule {
public static final String SHADE_HEADER = "large_screen_shade_header";
@@ -117,9 +121,7 @@ public abstract class StatusBarViewModule {
NotificationShelfComponent.Builder notificationShelfComponentBuilder,
NotificationShelf notificationShelf) {
if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
NotificationShelfViewBinderWrapperControllerImpl impl = newImpl.get();
impl.init();
return impl;
return newImpl.get();
} else {
NotificationShelfComponent component = notificationShelfComponentBuilder
.notificationShelf(notificationShelf)

View File

@@ -72,9 +72,11 @@ import com.android.systemui.statusbar.notification.collection.render.SectionHead
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -92,6 +94,8 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Optional;
/**
* Tests for {@link NotificationStackScrollLayoutController}.
*/
@@ -138,6 +142,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
@Mock private FeatureFlags mFeatureFlags;
@Mock private NotificationTargetsHelper mNotificationTargetsHelper;
@Mock private SecureSettings mSecureSettings;
@Mock private NotificationIconAreaController mIconAreaController;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -430,6 +435,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mKeyguardBypassController,
mZenModeController,
mNotificationLockscreenUserManager,
Optional.<NotificationListViewModel>empty(),
mMetricsLogger,
mDumpManager,
new FalsingCollectorFake(),
@@ -453,6 +459,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mStackLogger,
mLogger,
mNotificationStackSizeCalculator,
mIconAreaController,
mFeatureFlags,
mNotificationTargetsHelper,
mSecureSettings,