[CS] Make NPVC and QuickSettingsController singletons.

Most of this change is having ShadeController rely on the
ShadeViewController interface instead of on
NotificationPanelViewController directly, which required adding some
additional methods to ShadeViewController.

Bug: 277762009
Test: verified keyguard bottom area works with MIGRATE_INDICATION_AREA
flag off and on (verified indication text updates based on events,
updates based on font changes)
Test: verify shade works: displays notifs, notifs can be expanded,
notifs can be swiped away, shade reinflated on font change, etc.
Test: verify QS works: tiles display, tiles update based on taps, etc.

Test: atest CentralSurfacesImplTest ShadeControllerImplTest
NotificationPanelViewControllerTest

Change-Id: Ib2cb857374a094402898b5179ed9fb7b4e399035
This commit is contained in:
Caitlin Shkuratov
2023-06-22 14:56:57 +00:00
parent eda7ede235
commit 8f5e6f8b8f
14 changed files with 100 additions and 74 deletions

View File

@@ -59,7 +59,7 @@ constructor(
// At startup, 2 views with the ID `R.id.keyguard_indication_area` will be available.
// Disable one of them
if (featureFlags.isEnabled(Flags.MIGRATE_INDICATION_AREA)) {
legacyParent.requireViewById<View>(R.id.keyguard_indication_area).let {
legacyParent.findViewById<View>(R.id.keyguard_indication_area)?.let {
legacyParent.removeView(it)
}
} else {

View File

@@ -117,6 +117,7 @@ import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
@@ -208,7 +209,6 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.TapAgainViewController;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
@@ -238,7 +238,7 @@ import kotlin.Unit;
import kotlinx.coroutines.CoroutineDispatcher;
@CentralSurfacesComponent.CentralSurfacesScope
@SysUISingleton
public final class NotificationPanelViewController implements ShadeSurface, Dumpable {
public static final String TAG = NotificationPanelView.class.getSimpleName();
@@ -1407,11 +1407,13 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mKeyguardBottomArea = keyguardBottomArea;
}
void setOpenCloseListener(OpenCloseListener openCloseListener) {
@Override
public void setOpenCloseListener(OpenCloseListener openCloseListener) {
mOpenCloseListener = openCloseListener;
}
void setTrackingStartedListener(TrackingStartedListener trackingStartedListener) {
@Override
public void setTrackingStartedListener(TrackingStartedListener trackingStartedListener) {
mTrackingStartedListener = trackingStartedListener;
}
@@ -3378,11 +3380,13 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
ViewGroupFadeHelper.reset(mView);
}
void addOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
@Override
public void addOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
mView.getViewTreeObserver().addOnGlobalLayoutListener(listener);
}
void removeOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
@Override
public void removeOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
mView.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
@@ -3847,8 +3851,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
return !isFullyCollapsed() && !mTracking && !mClosing;
}
/** Collapses the shade instantly without animation. */
void instantCollapse() {
@Override
public void instantCollapse() {
abortAnimations();
setExpandedFraction(0f);
if (mExpanding) {
@@ -4021,8 +4025,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mFixedDuration = NO_FIXED_DURATION;
}
/** */
boolean postToView(Runnable action) {
@Override
public boolean postToView(Runnable action) {
return mView.post(action);
}
@@ -5113,18 +5117,5 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
return super.performAccessibilityAction(host, action, args);
}
}
/** Listens for when touch tracking begins. */
interface TrackingStartedListener {
void onTrackingStarted();
}
/** Listens for when shade begins opening of finishes closing. */
interface OpenCloseListener {
/** Called when the shade finishes closing. */
void onClosingFinished();
/** Called when the shade starts opening. */
void onOpenStarted();
}
}

View File

@@ -68,6 +68,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.fragments.FragmentHostManager;
@@ -98,7 +99,6 @@ import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.LargeScreenUtils;
@@ -113,7 +113,7 @@ import javax.inject.Inject;
/** Handles QuickSettings touch handling, expansion and animation state
* TODO (b/264460656) make this dumpable
*/
@CentralSurfacesComponent.CentralSurfacesScope
@SysUISingleton
public class QuickSettingsController implements Dumpable {
public static final String TAG = "QuickSettingsController";

View File

@@ -165,8 +165,7 @@ public interface ShadeController {
NotificationShadeWindowViewController notificationShadeWindowViewController);
/** */
void setNotificationPanelViewController(
NotificationPanelViewController notificationPanelViewController);
void setShadeViewController(ShadeViewController shadeViewController);
/** Listens for shade visibility changes. */
interface ShadeVisibilityListener {

View File

@@ -70,7 +70,8 @@ public final class ShadeControllerImpl implements ShadeController {
private boolean mExpandedVisible;
private NotificationPanelViewController mNotificationPanelViewController;
// TODO(b/237661616): Rename this variable to mShadeViewController.
private ShadeViewController mNotificationPanelViewController;
private NotificationPresenter mPresenter;
private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
private ShadeVisibilityListener mShadeVisibilityListener;
@@ -426,12 +427,11 @@ public final class ShadeControllerImpl implements ShadeController {
}
@Override
public void setNotificationPanelViewController(
NotificationPanelViewController notificationPanelViewController) {
mNotificationPanelViewController = notificationPanelViewController;
public void setShadeViewController(ShadeViewController shadeViewController) {
mNotificationPanelViewController = shadeViewController;
mNotificationPanelViewController.setTrackingStartedListener(this::runPostCollapseRunnables);
mNotificationPanelViewController.setOpenCloseListener(
new NotificationPanelViewController.OpenCloseListener() {
new OpenCloseListener() {
@Override
public void onClosingFinished() {
ShadeControllerImpl.this.onClosingFinished();

View File

@@ -72,6 +72,12 @@ abstract class ShadeModule {
@ClassKey(AuthRippleController::class)
abstract fun bindAuthRippleController(controller: AuthRippleController): CoreStartable
@Binds
@SysUISingleton
abstract fun bindsShadeViewController(
notificationPanelViewController: NotificationPanelViewController
): ShadeViewController
companion object {
const val SHADE_HEADER = "large_screen_shade_header"

View File

@@ -17,6 +17,7 @@ package com.android.systemui.shade
import android.view.MotionEvent
import android.view.ViewGroup
import android.view.ViewTreeObserver
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.statusbar.RemoteInputController
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -77,6 +78,9 @@ interface ShadeViewController {
/** Collapses the shade with an animation duration in milliseconds. */
fun collapseWithDuration(animationDuration: Int)
/** Collapses the shade instantly without animation. */
fun instantCollapse()
/**
* Animate QS collapse by flinging it. If QS is expanded, it will collapse into QQS and stop. If
* in split shade, it will collapse the whole shade.
@@ -100,6 +104,9 @@ interface ShadeViewController {
/** Returns whether the shade's top level view is enabled. */
val isViewEnabled: Boolean
/** Sets a listener to be notified when the shade starts opening or finishes closing. */
fun setOpenCloseListener(openCloseListener: OpenCloseListener)
/** Returns whether status bar icons should be hidden when the shade is expanded. */
fun shouldHideStatusBarIconsWhenExpanded(): Boolean
@@ -109,6 +116,9 @@ interface ShadeViewController {
*/
fun blockExpansionForCurrentTouch()
/** Sets a listener to be notified when touch tracking begins. */
fun setTrackingStartedListener(trackingStartedListener: TrackingStartedListener)
/**
* Disables the shade header.
*
@@ -178,6 +188,15 @@ interface ShadeViewController {
/** Ensures that the touchable region is updated. */
fun updateTouchableRegion()
/** Adds a global layout listener. */
fun addOnGlobalLayoutListener(listener: ViewTreeObserver.OnGlobalLayoutListener)
/** Removes a global layout listener. */
fun removeOnGlobalLayoutListener(listener: ViewTreeObserver.OnGlobalLayoutListener)
/** Posts the given runnable to the view. */
fun postToView(action: Runnable): Boolean
// ******* Begin Keyguard Section *********
/** Animate to expanded shade after a delay in ms. Used for lockscreen to shade transition. */
fun transitionToExpandedShade(delay: Long)
@@ -337,3 +356,17 @@ interface ShadeViewStateProvider {
/** Return the fraction of the shade that's expanded, when in lockscreen. */
val lockscreenShadeDragProgress: Float
}
/** Listens for when touch tracking begins. */
interface TrackingStartedListener {
fun onTrackingStarted()
}
/** Listens for when shade begins opening or finishes closing. */
interface OpenCloseListener {
/** Called when the shade finishes closing. */
fun onClosingFinished()
/** Called when the shade starts opening. */
fun onOpenStarted()
}

View File

@@ -41,6 +41,8 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeSurface;
import com.android.systemui.shade.carrier.ShadeCarrierGroupController;
import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
@@ -273,6 +275,21 @@ public interface CentralSurfacesDependenciesModule {
return ongoingCallController;
}
/**
* {@link NotificationPanelViewController} implements two interfaces:
* - {@link com.android.systemui.shade.ShadeViewController}, which can be used by any class
* needing access to the shade.
* - {@link ShadeSurface}, which should *only* be used by {@link CentralSurfacesImpl}.
*
* Since {@link ShadeSurface} should only be accessible by {@link CentralSurfacesImpl}, it's
* *only* bound in this CentralSurfaces dependencies module.
* The {@link com.android.systemui.shade.ShadeViewController} interface is bound in
* {@link com.android.systemui.shade.ShadeModule} so others can access it.
*/
@Binds
@SysUISingleton
ShadeSurface provideShadeSurface(NotificationPanelViewController impl);
/** */
@Binds
ShadeCarrierGroupController.SlotIndexResolver provideSlotIndexResolver(

View File

@@ -182,7 +182,6 @@ import com.android.systemui.scrim.ScrimView;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.shade.CameraLauncher;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.QuickSettingsController;
@@ -497,14 +496,12 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private final Lazy<LightRevealScrimViewModel> mLightRevealScrimViewModelLazy;
/** Controller for the Shade. */
@VisibleForTesting
ShadeSurface mShadeSurface;
private final ShadeSurface mShadeSurface;
private final ShadeLogger mShadeLogger;
// settings
private QSPanelController mQSPanelController;
@VisibleForTesting
QuickSettingsController mQsController;
private final QuickSettingsController mQsController;
KeyguardIndicationController mKeyguardIndicationController;
@@ -729,9 +726,11 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
MetricsLogger metricsLogger,
ShadeLogger shadeLogger,
@UiBackground Executor uiBgExecutor,
ShadeSurface shadeSurface,
NotificationMediaManager notificationMediaManager,
NotificationLockscreenUserManager lockScreenUserManager,
NotificationRemoteInputManager remoteInputManager,
QuickSettingsController quickSettingsController,
UserSwitcherController userSwitcherController,
BatteryController batteryController,
SysuiColorExtractor colorExtractor,
@@ -830,9 +829,11 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mMetricsLogger = metricsLogger;
mShadeLogger = shadeLogger;
mUiBgExecutor = uiBgExecutor;
mShadeSurface = shadeSurface;
mMediaManager = notificationMediaManager;
mLockscreenUserManager = lockScreenUserManager;
mRemoteInputManager = remoteInputManager;
mQsController = quickSettingsController;
mUserSwitcherController = userSwitcherController;
mBatteryController = batteryController;
mColorExtractor = colorExtractor;
@@ -1636,13 +1637,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
// (Right now, there's a circular dependency.)
mNotificationShadeWindowController.setWindowRootView(windowRootView);
mNotificationShadeWindowViewController.setupExpandedStatusBar();
NotificationPanelViewController npvc =
mCentralSurfacesComponent.getNotificationPanelViewController();
mShadeSurface = npvc;
mShadeController.setNotificationPanelViewController(npvc);
mShadeController.setShadeViewController(mShadeSurface);
mShadeController.setNotificationShadeWindowViewController(
mNotificationShadeWindowViewController);
mQsController = mCentralSurfacesComponent.getQuickSettingsController();
mBackActionInteractor.setup(mQsController, mShadeSurface);
mPresenter = mCentralSurfacesComponent.getNotificationPresenter();
mNotificationActivityStarter = mCentralSurfacesComponent.getNotificationActivityStarter();
@@ -1843,7 +1840,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
@Override
public void onStatusBarTrackpadEvent(MotionEvent event) {
mCentralSurfacesComponent.getNotificationPanelViewController().handleExternalTouch(event);
mShadeSurface.handleExternalTouch(event);
}
private void onExpandedInvisible() {

View File

@@ -21,10 +21,8 @@ import static com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.ST
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.android.systemui.scene.ui.view.WindowRootView;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeHeaderController;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -88,14 +86,6 @@ public interface CentralSurfacesComponent {
*/
NotificationShadeWindowViewController getNotificationShadeWindowViewController();
/**
* Creates a NotificationPanelViewController.
*/
NotificationPanelViewController getNotificationPanelViewController();
/** Creates a QuickSettingsController. */
QuickSettingsController getQuickSettingsController();
/**
* Creates a StatusBarHeadsUpChangeListener.
*/

View File

@@ -21,7 +21,6 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
@@ -65,12 +64,6 @@ public abstract class StatusBarViewModule {
public static final String STATUS_BAR_FRAGMENT = "status_bar_fragment";
/** */
@Binds
@CentralSurfacesComponent.CentralSurfacesScope
abstract ShadeViewController bindsShadeViewController(
NotificationPanelViewController notificationPanelViewController);
@Binds
@IntoSet
abstract StatusBarBoundsProvider.BoundsChangeListener sysBarAttrsListenerAsBoundsListener(

View File

@@ -80,6 +80,7 @@ import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.common.ui.view.LongPressHandlingView;
@@ -91,7 +92,6 @@ import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewConfigurator;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
@@ -629,7 +629,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
mHeadsUpManager);
mNotificationPanelViewController.setTrackingStartedListener(() -> {});
mNotificationPanelViewController.setOpenCloseListener(
new NotificationPanelViewController.OpenCloseListener() {
new OpenCloseListener() {
@Override
public void onClosingFinished() {}

View File

@@ -56,7 +56,7 @@ class ShadeControllerImplTest : SysuiTestCase() {
@Mock private lateinit var windowManager: WindowManager
@Mock private lateinit var assistManager: AssistManager
@Mock private lateinit var gutsManager: NotificationGutsManager
@Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
@Mock private lateinit var shadeViewController: ShadeViewController
@Mock private lateinit var nswvc: NotificationShadeWindowViewController
@Mock private lateinit var display: Display
@@ -82,7 +82,7 @@ class ShadeControllerImplTest : SysuiTestCase() {
Lazy { gutsManager },
)
shadeController.setNotificationShadeWindowViewController(nswvc)
shadeController.setNotificationPanelViewController(notificationPanelViewController)
shadeController.setShadeViewController(shadeViewController)
}
@Test
@@ -91,9 +91,9 @@ class ShadeControllerImplTest : SysuiTestCase() {
// Trying to open it does nothing.
shadeController.animateExpandShade()
verify(notificationPanelViewController, never()).expandToNotifications()
verify(shadeViewController, never()).expandToNotifications()
shadeController.animateExpandQs()
verify(notificationPanelViewController, never()).expand(ArgumentMatchers.anyBoolean())
verify(shadeViewController, never()).expand(ArgumentMatchers.anyBoolean())
}
@Test
@@ -102,15 +102,15 @@ class ShadeControllerImplTest : SysuiTestCase() {
// Can now be opened.
shadeController.animateExpandShade()
verify(notificationPanelViewController).expandToNotifications()
verify(shadeViewController).expandToNotifications()
shadeController.animateExpandQs()
verify(notificationPanelViewController).expandToQs()
verify(shadeViewController).expandToQs()
}
@Test
fun cancelExpansionAndCollapseShade_callsCancelCurrentTouch() {
// GIVEN the shade is tracking a touch
whenever(notificationPanelViewController.isTracking).thenReturn(true)
whenever(shadeViewController.isTracking).thenReturn(true)
// WHEN cancelExpansionAndCollapseShade is called
shadeController.cancelExpansionAndCollapseShade()
@@ -122,7 +122,7 @@ class ShadeControllerImplTest : SysuiTestCase() {
@Test
fun cancelExpansionAndCollapseShade_doesNotCallAnimateCollapseShade_whenCollapsed() {
// GIVEN the shade is tracking a touch
whenever(notificationPanelViewController.isTracking).thenReturn(false)
whenever(shadeViewController.isTracking).thenReturn(false)
// WHEN cancelExpansionAndCollapseShade is called
shadeController.cancelExpansionAndCollapseShade()

View File

@@ -450,7 +450,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
() -> mAssistManager,
() -> mNotificationGutsManager
));
mShadeController.setNotificationPanelViewController(mNotificationPanelViewController);
mShadeController.setShadeViewController(mNotificationPanelViewController);
mShadeController.setNotificationShadeWindowViewController(
mNotificationShadeWindowViewController);
mShadeController.setNotificationPresenter(mNotificationPresenter);
@@ -490,9 +490,11 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mMetricsLogger,
mShadeLogger,
mUiBgExecutor,
mNotificationPanelViewController,
mNotificationMediaManager,
mLockscreenUserManager,
mRemoteInputManager,
mQuickSettingsController,
mUserSwitcherController,
mBatteryController,
mColorExtractor,
@@ -587,8 +589,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
// TODO: we should be able to call mCentralSurfaces.start() and have all the below values
// initialized automatically and make NPVC private.
mCentralSurfaces.mNotificationShadeWindowView = mNotificationShadeWindowView;
mCentralSurfaces.mShadeSurface = mNotificationPanelViewController;
mCentralSurfaces.mQsController = mQuickSettingsController;
mCentralSurfaces.mDozeScrimController = mDozeScrimController;
mCentralSurfaces.mPresenter = mNotificationPresenter;
mCentralSurfaces.mKeyguardIndicationController = mKeyguardIndicationController;