From 31dd235dab9bc7cb358dc95fb65f0b35a62dab84 Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 22 Sep 2022 13:02:14 +0000 Subject: [PATCH 01/23] DO NOT MERGE Use KeyguardStateController for #isShowing Remove calls that route through StatusBarKeyguardViewManager/KeyguardViewController. This was unnecessary and led to confusion. Instead, all components should directly check KeyguardStateController for #isShowing and #isOccluded. For now, this CL retains the keyguardVisibility callback in KeyguardUpdateMonitor, where keyguardVisibility is defined as when KeyguardStateController, our source of truth). Test: builds Test: atest SystemUITests Bug: 248089638 Fixes: 251880943 Change-Id: I7c6373d2fa81ab2063234aae338b1b9643038e6a (cherry picked from commit e6e7b75d3b1073918ab5a44fd00148cd5b8030f6) Merged-In: I7c6373d2fa81ab2063234aae338b1b9643038e6a --- .../keyguard/KeyguardUpdateMonitor.java | 9 +- .../keyguard/KeyguardViewController.java | 5 - .../UdfpsKeyguardViewController.java | 2 +- .../KeyguardUnlockAnimationController.kt | 6 +- .../keyguard/KeyguardViewMediator.java | 2 +- .../systemui/navigationbar/NavBarHelper.java | 10 +- .../NotificationPanelViewController.java | 2 +- .../DynamicPrivacyController.java | 16 +- .../phone/BiometricUnlockController.java | 12 +- .../CentralSurfacesCommandQueueCallbacks.java | 4 +- .../statusbar/phone/CentralSurfacesImpl.java | 36 ++--- .../phone/StatusBarKeyguardViewManager.java | 99 +++++------- .../policy/KeyguardStateController.java | 13 +- .../policy/KeyguardStateControllerImpl.java | 3 + .../keyguard/KeyguardViewMediatorTest.java | 4 +- .../navigationbar/NavBarHelperTest.java | 4 +- .../navigationbar/NavigationBarTest.java | 7 +- .../DynamicPrivacyControllerTest.java | 3 - .../phone/BiometricsUnlockControllerTest.java | 10 +- .../phone/CentralSurfacesImplTest.java | 46 +++--- .../phone/FakeKeyguardStateController.java | 145 ++++++++++++++++++ .../StatusBarKeyguardViewManagerTest.java | 19 ++- 22 files changed, 275 insertions(+), 182 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index cd9089e85ae0c..9b498bcbb58d2 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -3178,14 +3178,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Whether the keyguard is showing and not occluded. */ public boolean isKeyguardVisible() { - return isKeyguardShowing() && !mKeyguardOccluded; - } - - /** - * Whether the keyguard is showing. It may still be occluded and not visible. - */ - public boolean isKeyguardShowing() { - return mKeyguardShowing; + return mKeyguardShowing && !mKeyguardOccluded; } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java index 8293c74c5e75e..614596fef8139 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java @@ -93,11 +93,6 @@ public interface KeyguardViewController { */ void setOccluded(boolean occluded, boolean animate); - /** - * @return Whether the keyguard is showing - */ - boolean isShowing(); - /** * Dismisses the keyguard by going to the next screen or making it gone. */ diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index 24b893340ae01..ec2a55c6d0034 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -219,7 +219,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController mAssistManagerLazy; private final Lazy> mCentralSurfacesOptionalLazy; - private final KeyguardViewController mKeyguardViewController; + private final KeyguardStateController mKeyguardStateController; private final UserTracker mUserTracker; private final SystemActions mSystemActions; private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver; @@ -125,7 +125,7 @@ public final class NavBarHelper implements OverviewProxyService overviewProxyService, Lazy assistManagerLazy, Lazy> centralSurfacesOptionalLazy, - KeyguardViewController keyguardViewController, + KeyguardStateController keyguardStateController, NavigationModeController navigationModeController, UserTracker userTracker, DumpManager dumpManager) { @@ -134,7 +134,7 @@ public final class NavBarHelper implements mAccessibilityManager = accessibilityManager; mAssistManagerLazy = assistManagerLazy; mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; - mKeyguardViewController = keyguardViewController; + mKeyguardStateController = keyguardStateController; mUserTracker = userTracker; mSystemActions = systemActions; accessibilityManager.addAccessibilityServicesStateChangeListener(this); @@ -326,7 +326,7 @@ public final class NavBarHelper implements shadeWindowView = mCentralSurfacesOptionalLazy.get().get().getNotificationShadeWindowView(); } - boolean isKeyguardShowing = mKeyguardViewController.isShowing(); + boolean isKeyguardShowing = mKeyguardStateController.isShowing(); boolean imeVisibleOnShade = shadeWindowView != null && shadeWindowView.isAttachedToWindow() && shadeWindowView.getRootWindowInsets().isVisible(WindowInsets.Type.ime()); return imeVisibleOnShade diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 11103861f70b4..ad425088e0424 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -4289,7 +4289,7 @@ public final class NotificationPanelViewController extends PanelViewController { } if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyExpanded() - && mStatusBarKeyguardViewManager.isShowing()) { + && mKeyguardStateController.isShowing()) { mStatusBarKeyguardViewManager.updateKeyguardPosition(event.getX()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java index 1be4c04ef8047..b5c7ef5f76308 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification; -import android.annotation.Nullable; import android.util.ArraySet; import androidx.annotation.VisibleForTesting; @@ -25,7 +24,6 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import javax.inject.Inject; @@ -43,7 +41,6 @@ public class DynamicPrivacyController implements KeyguardStateController.Callbac private boolean mLastDynamicUnlocked; private boolean mCacheInvalid; - @Nullable private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Inject DynamicPrivacyController(NotificationLockscreenUserManager notificationLockscreenUserManager, @@ -100,7 +97,7 @@ public class DynamicPrivacyController implements KeyguardStateController.Callbac * contents aren't revealed yet? */ public boolean isInLockedDownShade() { - if (!isStatusBarKeyguardShowing() || !mKeyguardStateController.isMethodSecure()) { + if (!mKeyguardStateController.isShowing() || !mKeyguardStateController.isMethodSecure()) { return false; } int state = mStateController.getState(); @@ -113,16 +110,7 @@ public class DynamicPrivacyController implements KeyguardStateController.Callbac return true; } - private boolean isStatusBarKeyguardShowing() { - return mStatusBarKeyguardViewManager != null && mStatusBarKeyguardViewManager.isShowing(); - } - - public void setStatusBarKeyguardViewManager( - StatusBarKeyguardViewManager statusBarKeyguardViewManager) { - mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; - } - public interface Listener { void onDynamicPrivacyChanged(); } -} \ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index fe431377f854c..a2798f47be658 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -163,7 +163,6 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private PowerManager.WakeLock mWakeLock; private final com.android.systemui.shade.ShadeController mShadeController; private final KeyguardUpdateMonitor mUpdateMonitor; - private final DozeParameters mDozeParameters; private final KeyguardStateController mKeyguardStateController; private final NotificationShadeWindowController mNotificationShadeWindowController; private final SessionTracker mSessionTracker; @@ -278,7 +277,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp KeyguardStateController keyguardStateController, Handler handler, KeyguardUpdateMonitor keyguardUpdateMonitor, @Main Resources resources, - KeyguardBypassController keyguardBypassController, DozeParameters dozeParameters, + KeyguardBypassController keyguardBypassController, MetricsLogger metricsLogger, DumpManager dumpManager, PowerManager powerManager, NotificationMediaManager notificationMediaManager, @@ -294,7 +293,6 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp mPowerManager = powerManager; mShadeController = shadeController; mUpdateMonitor = keyguardUpdateMonitor; - mDozeParameters = dozeParameters; mUpdateMonitor.registerCallback(this); mMediaManager = notificationMediaManager; mLatencyTracker = latencyTracker; @@ -552,7 +550,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean deviceDreaming = mUpdateMonitor.isDreaming(); if (!mUpdateMonitor.isDeviceInteractive()) { - if (!mKeyguardViewController.isShowing() + if (!mKeyguardStateController.isShowing() && !mScreenOffAnimationController.isKeyguardShowDelayed()) { if (mKeyguardStateController.isUnlocked()) { return MODE_WAKE_AND_UNLOCK; @@ -569,7 +567,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (unlockingAllowed && deviceDreaming) { return MODE_WAKE_AND_UNLOCK_FROM_DREAM; } - if (mKeyguardViewController.isShowing()) { + if (mKeyguardStateController.isShowing()) { if (mKeyguardViewController.bouncerIsOrWillBeShowing() && unlockingAllowed) { return MODE_DISMISS_BOUNCER; } else if (unlockingAllowed) { @@ -588,7 +586,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean bypass = mKeyguardBypassController.getBypassEnabled() || mAuthController.isUdfpsFingerDown(); if (!mUpdateMonitor.isDeviceInteractive()) { - if (!mKeyguardViewController.isShowing()) { + if (!mKeyguardStateController.isShowing()) { return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE; } else if (!unlockingAllowed) { return bypass ? MODE_SHOW_BOUNCER : MODE_NONE; @@ -612,7 +610,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (unlockingAllowed && mKeyguardStateController.isOccluded()) { return MODE_UNLOCK_COLLAPSING; } - if (mKeyguardViewController.isShowing()) { + if (mKeyguardStateController.isShowing()) { if ((mKeyguardViewController.bouncerIsOrWillBeShowing() || mKeyguardBypassController.getAltBouncerShowing()) && unlockingAllowed) { return MODE_DISMISS_BOUNCER; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index 52a45d6785ca2..1e95dad6b1157 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -363,7 +363,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba mKeyguardUpdateMonitor.onCameraLaunched(); } - if (!mStatusBarKeyguardViewManager.isShowing()) { + if (!mKeyguardStateController.isShowing()) { final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext); mCentralSurfaces.startActivityDismissingKeyguard(cameraIntent, false /* onlyProvisioned */, true /* dismissShade */, @@ -420,7 +420,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for // app-side haptic experimentation. - if (!mStatusBarKeyguardViewManager.isShowing()) { + if (!mKeyguardStateController.isShowing()) { mCentralSurfaces.startActivityDismissingKeyguard(emergencyIntent, false /* onlyProvisioned */, true /* dismissShade */, true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 01a92b8bc418c..56e1bfbf3c700 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -476,7 +476,6 @@ public class CentralSurfacesImpl extends CoreStartable implements private final KeyguardStateController mKeyguardStateController; private final HeadsUpManagerPhone mHeadsUpManager; private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager; - private final DynamicPrivacyController mDynamicPrivacyController; private final FalsingCollector mFalsingCollector; private final FalsingManager mFalsingManager; private final BroadcastDispatcher mBroadcastDispatcher; @@ -779,7 +778,6 @@ public class CentralSurfacesImpl extends CoreStartable implements mHeadsUpManager = headsUpManagerPhone; mKeyguardIndicationController = keyguardIndicationController; mStatusBarTouchableRegionManager = statusBarTouchableRegionManager; - mDynamicPrivacyController = dynamicPrivacyController; mFalsingCollector = falsingCollector; mFalsingManager = falsingManager; mBroadcastDispatcher = broadcastDispatcher; @@ -1570,7 +1568,6 @@ public class CentralSurfacesImpl extends CoreStartable implements .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); mRemoteInputManager.addControllerCallback(mStatusBarKeyguardViewManager); - mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mLightBarController.setBiometricUnlockController(mBiometricUnlockController); mMediaManager.setBiometricUnlockController(mBiometricUnlockController); @@ -2082,7 +2079,7 @@ public class CentralSurfacesImpl extends CoreStartable implements // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in // the bouncer appear animation. - if (!mStatusBarKeyguardViewManager.isShowing()) { + if (!mKeyguardStateController.isShowing()) { WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); } } @@ -2519,8 +2516,8 @@ public class CentralSurfacesImpl extends CoreStartable implements }; // Do not deferKeyguard when occluded because, when keyguard is occluded, // we do not launch the activity until keyguard is done. - boolean occluded = mStatusBarKeyguardViewManager.isShowing() - && mStatusBarKeyguardViewManager.isOccluded(); + boolean occluded = mKeyguardStateController.isShowing() + && mKeyguardStateController.isOccluded(); boolean deferred = !occluded; executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShadeDirectly, willLaunchResolverActivity, deferred /* deferred */, animate); @@ -2590,8 +2587,8 @@ public class CentralSurfacesImpl extends CoreStartable implements @Override public boolean onDismiss() { if (runnable != null) { - if (mStatusBarKeyguardViewManager.isShowing() - && mStatusBarKeyguardViewManager.isOccluded()) { + if (mKeyguardStateController.isShowing() + && mKeyguardStateController.isOccluded()) { mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); } else { mMainExecutor.execute(runnable); @@ -2685,7 +2682,7 @@ public class CentralSurfacesImpl extends CoreStartable implements private void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen, boolean afterKeyguardGone) { - if (mStatusBarKeyguardViewManager.isShowing() && requiresShadeOpen) { + if (mKeyguardStateController.isShowing() && requiresShadeOpen) { mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); } dismissKeyguardThenExecute(action, null /* cancelAction */, @@ -2709,7 +2706,7 @@ public class CentralSurfacesImpl extends CoreStartable implements mBiometricUnlockController.startWakeAndUnlock( BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING); } - if (mStatusBarKeyguardViewManager.isShowing()) { + if (mKeyguardStateController.isShowing()) { mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, afterKeyguardGone); } else { @@ -2845,8 +2842,8 @@ public class CentralSurfacesImpl extends CoreStartable implements } private void logStateToEventlog() { - boolean isShowing = mStatusBarKeyguardViewManager.isShowing(); - boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded(); + boolean isShowing = mKeyguardStateController.isShowing(); + boolean isOccluded = mKeyguardStateController.isOccluded(); boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing(); boolean isSecure = mKeyguardStateController.isMethodSecure(); boolean unlocked = mKeyguardStateController.canDismissLockScreen(); @@ -3242,18 +3239,17 @@ public class CentralSurfacesImpl extends CoreStartable implements Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0); Trace.beginSection("CentralSurfaces#updateDozingState"); - boolean visibleNotOccluded = mStatusBarKeyguardViewManager.isShowing() - && !mStatusBarKeyguardViewManager.isOccluded(); + boolean keyguardVisible = mKeyguardStateController.isVisible(); // If we're dozing and we'll be animating the screen off, the keyguard isn't currently // visible but will be shortly for the animation, so we should proceed as if it's visible. - boolean visibleNotOccludedOrWillBe = - visibleNotOccluded || (mDozing && mDozeParameters.shouldDelayKeyguardShow()); + boolean keyguardVisibleOrWillBe = + keyguardVisible || (mDozing && mDozeParameters.shouldDelayKeyguardShow()); boolean wakeAndUnlock = mBiometricUnlockController.getMode() == BiometricUnlockController.MODE_WAKE_AND_UNLOCK; boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup() && !wakeAndUnlock) || (mDozing && mDozeParameters.shouldControlScreenOff() - && visibleNotOccludedOrWillBe); + && keyguardVisibleOrWillBe); mNotificationPanelViewController.setDozing(mDozing, animate); updateQsExpansionEnabled(); @@ -3934,11 +3930,7 @@ public class CentralSurfacesImpl extends CoreStartable implements @Override public boolean isKeyguardShowing() { - if (mStatusBarKeyguardViewManager == null) { - Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true"); - return true; - } - return mStatusBarKeyguardViewManager.isShowing(); + return mKeyguardStateController.isShowing(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 6e1cf13d01d79..a20ce5fa77818 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -229,8 +229,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private View mNotificationContainer; @Nullable protected KeyguardBouncer mBouncer; - protected boolean mShowing; - protected boolean mOccluded; protected boolean mRemoteInputActive; private boolean mGlobalActionsVisible = false; private boolean mLastGlobalActionsVisible = false; @@ -277,10 +275,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb new KeyguardUpdateMonitorCallback() { @Override public void onEmergencyCallAction() { - // Since we won't get a setOccluded call we have to reset the view manually such that // the bouncer goes away. - if (mOccluded) { + if (mKeyguardStateController.isOccluded()) { reset(true /* hideBouncerWhenShowing */); } } @@ -479,7 +476,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } else { mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE); } - } else if (mShowing && !hideBouncerOverDream) { + } else if (mKeyguardStateController.isShowing() && !hideBouncerOverDream) { if (!isWakeAndUnlocking() && !(mBiometricUnlockController.getMode() == MODE_DISMISS_BOUNCER) && !mCentralSurfaces.isInLaunchTransition() @@ -500,7 +497,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBouncerInteractor.show(/* isScrimmed= */false); } } - } else if (!mShowing && isBouncerInTransit()) { + } else if (!mKeyguardStateController.isShowing() && isBouncerInTransit()) { // Keyguard is not visible anymore, but expansion animation was still running. // We need to hide the bouncer, otherwise it will be stuck in transit. if (mBouncer != null) { @@ -533,9 +530,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void show(Bundle options) { Trace.beginSection("StatusBarKeyguardViewManager#show"); - mShowing = true; mNotificationShadeWindowController.setKeyguardShowing(true); - mKeyguardStateController.notifyKeyguardState(mShowing, + mKeyguardStateController.notifyKeyguardState(true, mKeyguardStateController.isOccluded()); reset(true /* hideBouncerWhenShowing */); SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, @@ -599,7 +595,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } else { mBouncerInteractor.hide(); } - if (mShowing) { + if (mKeyguardStateController.isShowing()) { // If we were showing the bouncer and then aborting, we need to also clear out any // potential actions unless we actually unlocked. cancelPostAuthActions(); @@ -616,7 +612,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void showBouncer(boolean scrimmed) { resetAlternateAuth(false); - if (mShowing && !isBouncerShowing()) { + if (mKeyguardStateController.isShowing() && !isBouncerShowing()) { if (mBouncer != null) { mBouncer.show(false /* resetSecuritySelection */, scrimmed); } else { @@ -633,7 +629,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void dismissWithAction(OnDismissAction r, Runnable cancelAction, boolean afterKeyguardGone, String message) { - if (mShowing) { + if (mKeyguardStateController.isShowing()) { try { Trace.beginSection("StatusBarKeyguardViewManager#dismissWithAction"); cancelPendingWakeupAction(); @@ -719,11 +715,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void reset(boolean hideBouncerWhenShowing) { - if (mShowing) { + if (mKeyguardStateController.isShowing()) { + final boolean isOccluded = mKeyguardStateController.isOccluded(); // Hide quick settings. - mNotificationPanelViewController.resetViews(/* animate= */ !mOccluded); + mNotificationPanelViewController.resetViews(/* animate= */ !isOccluded); // Hide bouncer and quick-quick settings. - if (mOccluded && !mDozing) { + if (isOccluded && !mDozing) { mCentralSurfaces.hideKeyguard(); if (hideBouncerWhenShowing || needsFullscreenBouncer()) { hideBouncer(false /* destroyView */); @@ -805,7 +802,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private void setDozing(boolean dozing) { if (mDozing != dozing) { mDozing = dozing; - if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) { + if (dozing || mBouncer.needsFullscreenBouncer() + || mKeyguardStateController.isOccluded()) { reset(dozing /* hideBouncerWhenShowing */); } updateStates(); @@ -838,18 +836,23 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void setOccluded(boolean occluded, boolean animate) { - final boolean isOccluding = !mOccluded && occluded; - final boolean isUnOccluding = mOccluded && !occluded; - setOccludedAndUpdateStates(occluded); + final boolean wasOccluded = mKeyguardStateController.isOccluded(); + final boolean isOccluding = !wasOccluded && occluded; + final boolean isUnOccluding = wasOccluded && !occluded; + mKeyguardStateController.notifyKeyguardState( + mKeyguardStateController.isShowing(), occluded); + updateStates(); + final boolean isShowing = mKeyguardStateController.isShowing(); + final boolean isOccluded = mKeyguardStateController.isOccluded(); - if (mShowing && isOccluding) { + if (isShowing && isOccluding) { SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED); if (mCentralSurfaces.isInLaunchTransition()) { final Runnable endRunnable = new Runnable() { @Override public void run() { - mNotificationShadeWindowController.setKeyguardOccluded(mOccluded); + mNotificationShadeWindowController.setKeyguardOccluded(isOccluded); reset(true /* hideBouncerWhenShowing */); } }; @@ -864,19 +867,19 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb // When isLaunchingActivityOverLockscreen() is true, we know for sure that the post // collapse runnables will be run. mShadeController.get().addPostCollapseAction(() -> { - mNotificationShadeWindowController.setKeyguardOccluded(mOccluded); + mNotificationShadeWindowController.setKeyguardOccluded(isOccluded); reset(true /* hideBouncerWhenShowing */); }); return; } - } else if (mShowing && isUnOccluding) { + } else if (isShowing && isUnOccluding) { SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN); } - if (mShowing) { - mMediaManager.updateMediaMetaData(false, animate && !mOccluded); + if (isShowing) { + mMediaManager.updateMediaMetaData(false, animate && !isOccluded); } - mNotificationShadeWindowController.setKeyguardOccluded(mOccluded); + mNotificationShadeWindowController.setKeyguardOccluded(isOccluded); // setDozing(false) will call reset once we stop dozing. Also, if we're going away, there's // no need to reset the keyguard views as we'll be gone shortly. Resetting now could cause @@ -886,20 +889,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb // by a FLAG_DISMISS_KEYGUARD_ACTIVITY. reset(isOccluding /* hideBouncerWhenShowing*/); } - if (animate && !mOccluded && mShowing && !bouncerIsShowing()) { + if (animate && !isOccluded && isShowing && !bouncerIsShowing()) { mCentralSurfaces.animateKeyguardUnoccluding(); } } - private void setOccludedAndUpdateStates(boolean occluded) { - mOccluded = occluded; - updateStates(); - } - - public boolean isOccluded() { - return mOccluded; - } - @Override public void startPreHideAnimation(Runnable finishRunnable) { if (bouncerIsShowing()) { @@ -930,8 +924,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void hide(long startTime, long fadeoutDuration) { Trace.beginSection("StatusBarKeyguardViewManager#hide"); - mShowing = false; - mKeyguardStateController.notifyKeyguardState(mShowing, + mKeyguardStateController.notifyKeyguardState(false, mKeyguardStateController.isOccluded()); launchPendingWakeupAction(); @@ -1080,11 +1073,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb KeyguardUpdateMonitor.getCurrentUser()) != KeyguardSecurityModel.SecurityMode.None; } - @Override - public boolean isShowing() { - return mShowing; - } - /** * Returns whether a back invocation can be handled, which depends on whether the keyguard * is currently showing (which itself is derived from multiple states). @@ -1187,8 +1175,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb }; protected void updateStates() { - boolean showing = mShowing; - boolean occluded = mOccluded; + boolean showing = mKeyguardStateController.isShowing(); + boolean occluded = mKeyguardStateController.isOccluded(); boolean bouncerShowing = bouncerIsShowing(); boolean bouncerIsOrWillBeShowing = bouncerIsOrWillBeShowing(); boolean bouncerDismissible = !isFullscreenBouncer(); @@ -1222,13 +1210,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mNotificationShadeWindowController.setBouncerShowing(bouncerShowing); mCentralSurfaces.setBouncerShowing(bouncerShowing); } - - if (occluded != mLastOccluded || mFirstUpdate) { - mKeyguardStateController.notifyKeyguardState(showing, occluded); - } - if (occluded != mLastOccluded || mShowing != showing || mFirstUpdate) { - mKeyguardUpdateManager.setKeyguardShowing(showing, occluded); - } if (bouncerIsOrWillBeShowing != mLastBouncerIsOrWillBeShowing || mFirstUpdate || bouncerShowing != mLastBouncerShowing) { mKeyguardUpdateManager.sendKeyguardBouncerChanged(bouncerIsOrWillBeShowing, @@ -1279,12 +1260,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public boolean isNavBarVisible() { boolean isWakeAndUnlockPulsing = mBiometricUnlockController != null && mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING; - boolean keyguardShowing = mShowing && !mOccluded; + boolean keyguardVisible = mKeyguardStateController.isVisible(); boolean hideWhileDozing = mDozing && !isWakeAndUnlockPulsing; - boolean keyguardWithGestureNav = (keyguardShowing && !mDozing && !mScreenOffAnimationPlaying + boolean keyguardWithGestureNav = (keyguardVisible && !mDozing && !mScreenOffAnimationPlaying || mPulsing && !mIsDocked) && mGesturalNav; - return (!keyguardShowing && !hideWhileDozing && !mScreenOffAnimationPlaying + return (!keyguardVisible && !hideWhileDozing && !mScreenOffAnimationPlaying || bouncerIsShowing() || mRemoteInputActive || keyguardWithGestureNav @@ -1416,7 +1397,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb DismissWithActionRequest request = mPendingWakeupAction; mPendingWakeupAction = null; if (request != null) { - if (mShowing) { + if (mKeyguardStateController.isShowing()) { dismissWithAction(request.dismissAction, request.cancelAction, request.afterKeyguardGone, request.message); } else if (request.dismissAction != null) { @@ -1435,10 +1416,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public boolean bouncerNeedsScrimming() { // When a dream overlay is active, scrimming will cause any expansion to immediately expand. - return (mOccluded && !mDreamOverlayStateController.isOverlayActive()) + return (mKeyguardStateController.isOccluded() + && !mDreamOverlayStateController.isOverlayActive()) || bouncerWillDismissWithAction() - || (bouncerIsShowing() - && bouncerIsScrimmed()) + || (bouncerIsShowing() && bouncerIsScrimmed()) || isFullscreenBouncer(); } @@ -1457,8 +1438,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void dump(PrintWriter pw) { pw.println("StatusBarKeyguardViewManager:"); - pw.println(" mShowing: " + mShowing); - pw.println(" mOccluded: " + mOccluded); pw.println(" mRemoteInputActive: " + mRemoteInputActive); pw.println(" mDozing: " + mDozing); pw.println(" mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java index 250d9d46de66c..1ae1eae00651a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java @@ -35,9 +35,16 @@ public interface KeyguardStateController extends CallbackController { } /** - * If the lock screen is visible. - * The keyguard is also visible when the device is asleep or in always on mode, except when - * the screen timed out and the user can unlock by quickly pressing power. + * If the keyguard is visible. This is unrelated to being locked or not. + */ + default boolean isVisible() { + return isShowing() && !isOccluded(); + } + + /** + * If the keyguard is showing. This includes when it's occluded by an activity, and when + * the device is asleep or in always on mode, except when the screen timed out and the user + * can unlock by quickly pressing power. * * This is unrelated to being locked or not. * diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java index 437d4d415275d..cc6fdccba7893 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java @@ -181,6 +181,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum if (mShowing == showing && mOccluded == occluded) return; mShowing = showing; mOccluded = occluded; + mKeyguardUpdateMonitor.setKeyguardShowing(showing, occluded); Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events", "Keyguard showing: " + showing + " occluded: " + occluded); notifyKeyguardChanged(); @@ -387,6 +388,8 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum @Override public void dump(PrintWriter pw, String[] args) { pw.println("KeyguardStateController:"); + pw.println(" mShowing: " + mShowing); + pw.println(" mOccluded: " + mOccluded); pw.println(" mSecure: " + mSecure); pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen); pw.println(" mTrustManaged: " + mTrustManaged); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 21c018a0419d5..39f3c96803c31 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -176,7 +176,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { // and the keyguard goes away mViewMediator.setShowingLocked(false); - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); mViewMediator.mUpdateCallback.onKeyguardVisibilityChanged(false); TestableLooper.get(this).processAllMessages(); @@ -201,7 +201,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { // and the keyguard goes away mViewMediator.setShowingLocked(false); - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); mViewMediator.mUpdateCallback.onKeyguardVisibilityChanged(false); TestableLooper.get(this).processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java index 80731037481a2..6c03730e056e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java @@ -39,7 +39,6 @@ import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.keyguard.KeyguardViewController; import com.android.systemui.SysuiTestCase; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; @@ -49,6 +48,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; import org.junit.Test; @@ -113,7 +113,7 @@ public class NavBarHelperTest extends SysuiTestCase { mNavBarHelper = new NavBarHelper(mContext, mAccessibilityManager, mAccessibilityButtonModeObserver, mAccessibilityButtonTargetObserver, mSystemActions, mOverviewProxyService, mAssistManagerLazy, - () -> Optional.of(mock(CentralSurfaces.class)), mock(KeyguardViewController.class), + () -> Optional.of(mock(CentralSurfaces.class)), mock(KeyguardStateController.class), mNavigationModeController, mUserTracker, mDumpManager); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java index 51f0953771cb2..0e9d2799dddb0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java @@ -72,7 +72,6 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; -import com.android.keyguard.KeyguardViewController; import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestableContext; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; @@ -194,7 +193,7 @@ public class NavigationBarTest extends SysuiTestCase { @Mock private CentralSurfaces mCentralSurfaces; @Mock - private KeyguardViewController mKeyguardViewController; + private KeyguardStateController mKeyguardStateController; @Mock private UserContextProvider mUserContextProvider; @Mock @@ -240,7 +239,7 @@ public class NavigationBarTest extends SysuiTestCase { mock(AccessibilityButtonTargetsObserver.class), mSystemActions, mOverviewProxyService, () -> mock(AssistManager.class), () -> Optional.of(mCentralSurfaces), - mKeyguardViewController, mock(NavigationModeController.class), + mKeyguardStateController, mock(NavigationModeController.class), mock(UserTracker.class), mock(DumpManager.class))); mNavigationBar = createNavBar(mContext); mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal); @@ -380,7 +379,7 @@ public class NavigationBarTest extends SysuiTestCase { // Verify navbar didn't alter and showing back icon when the keyguard is showing without // requesting IME insets visible. - doReturn(true).when(mKeyguardViewController).isShowing(); + doReturn(true).when(mKeyguardStateController).isShowing(); mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true); assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java index b719c7f9e54ee..a6381d13f7da0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java @@ -32,7 +32,6 @@ import android.testing.TestableLooper; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Assert; @@ -58,8 +57,6 @@ public class DynamicPrivacyControllerTest extends SysuiTestCase { mDynamicPrivacyController = new DynamicPrivacyController( mLockScreenUserManager, mKeyguardStateController, mock(StatusBarStateController.class)); - mDynamicPrivacyController.setStatusBarKeyguardViewManager( - mock(StatusBarKeyguardViewManager.class)); mDynamicPrivacyController.addListener(mListener); // Disable dynamic privacy by default allowNotificationsInPublic(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index cd0cc33df1a98..6fa2174150449 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -100,8 +100,6 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { @Mock private AuthController mAuthController; @Mock - private DozeParameters mDozeParameters; - @Mock private MetricsLogger mMetricsLogger; @Mock private NotificationMediaManager mNotificationMediaManager; @@ -127,7 +125,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); TestableResources res = getContext().getOrCreateTestableResources(); - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true); when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true); when(mKeyguardStateController.isUnlocked()).thenReturn(false); @@ -139,7 +137,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mBiometricUnlockController = new BiometricUnlockController(mDozeScrimController, mKeyguardViewMediator, mScrimController, mShadeController, mNotificationShadeWindowController, mKeyguardStateController, mHandler, - mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters, + mUpdateMonitor, res.getResources(), mKeyguardBypassController, mMetricsLogger, mDumpManager, mPowerManager, mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle, mAuthController, mStatusBarStateController, mKeyguardUnlockAnimationController, @@ -177,7 +175,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { public void onBiometricAuthenticated_whenFingerprintAndNotInteractive_wakeAndUnlock() { reset(mUpdateMonitor); reset(mStatusBarKeyguardViewManager); - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); when(mDozeScrimController.isPulsing()).thenReturn(true); // the value of isStrongBiometric doesn't matter here since we only care about the returned @@ -194,7 +192,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { public void onBiometricAuthenticated_whenDeviceIsAlreadyUnlocked_wakeAndUnlock() { reset(mUpdateMonitor); reset(mStatusBarKeyguardViewManager); - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); when(mKeyguardStateController.isUnlocked()).thenReturn(true); when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); when(mDozeScrimController.isPulsing()).thenReturn(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index f510e48de5a56..8539367680d61 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -516,32 +516,32 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void executeRunnableDismissingKeyguard_nullRunnable_showingAndOccluded() { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(true); mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, false, false, false); } @Test public void executeRunnableDismissingKeyguard_nullRunnable_showing() { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(false); mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, false, false, false); } @Test public void executeRunnableDismissingKeyguard_nullRunnable_notShowing() { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, false, false, false); } @Test public void executeRunnableDismissingKeyguard_dreaming_notShowing() throws RemoteException { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(true); mCentralSurfaces.executeRunnableDismissingKeyguard(() -> {}, @@ -555,8 +555,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void executeRunnableDismissingKeyguard_notDreaming_notShowing() throws RemoteException { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(false); mCentralSurfaces.executeRunnableDismissingKeyguard(() -> {}, @@ -571,10 +571,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void lockscreenStateMetrics_notShowing() { // uninteresting state, except that fingerprint must be non-zero - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); // interesting state - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(false); mCentralSurfaces.onKeyguardViewManagerStatesUpdated(); @@ -589,10 +589,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void lockscreenStateMetrics_notShowing_secure() { // uninteresting state, except that fingerprint must be non-zero - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); // interesting state - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(true); @@ -608,10 +608,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void lockscreenStateMetrics_isShowing() { // uninteresting state, except that fingerprint must be non-zero - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); // interesting state - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(false); @@ -627,10 +627,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void lockscreenStateMetrics_isShowing_secure() { // uninteresting state, except that fingerprint must be non-zero - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); // interesting state - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(true); @@ -646,10 +646,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void lockscreenStateMetrics_isShowingBouncer() { // uninteresting state, except that fingerprint must be non-zero - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); // interesting state - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true); when(mKeyguardStateController.isMethodSecure()).thenReturn(true); @@ -1053,9 +1053,9 @@ public class CentralSurfacesImplTest extends SysuiTestCase { } @Test - public void startActivityDismissingKeyguard_isShowingandIsOccluded() { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(true); + public void startActivityDismissingKeyguard_isShowingAndIsOccluded() { + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(true); mCentralSurfaces.startActivityDismissingKeyguard( new Intent(), /* onlyProvisioned = */false, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java new file mode 100644 index 0000000000000..a986777afa225 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2022 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.phone; + +import com.android.systemui.statusbar.policy.KeyguardStateController; + +/** + * Mock implementation of KeyguardStateController which tracks showing and occluded states + * based on {@link #notifyKeyguardState(boolean showing, boolean occluded)}}. + */ +public class FakeKeyguardStateController implements KeyguardStateController { + private boolean mShowing; + private boolean mOccluded; + private boolean mCanDismissLockScreen; + + @Override + public void notifyKeyguardState(boolean showing, boolean occluded) { + mShowing = showing; + mOccluded = occluded; + } + + @Override + public boolean isShowing() { + return mShowing; + } + + @Override + public boolean isOccluded() { + return mOccluded; + } + + public void setCanDismissLockScreen(boolean canDismissLockScreen) { + mCanDismissLockScreen = canDismissLockScreen; + } + + @Override + public boolean canDismissLockScreen() { + return mCanDismissLockScreen; + } + + @Override + public boolean isBouncerShowing() { + return false; + } + + @Override + public boolean isKeyguardScreenRotationAllowed() { + return false; + } + + @Override + public boolean isMethodSecure() { + return true; + } + + @Override + public boolean isTrusted() { + return false; + } + + @Override + public boolean isKeyguardGoingAway() { + return false; + } + + @Override + public boolean isKeyguardFadingAway() { + return false; + } + + @Override + public boolean isLaunchTransitionFadingAway() { + return false; + } + + @Override + public long getKeyguardFadingAwayDuration() { + return 0; + } + + @Override + public long getKeyguardFadingAwayDelay() { + return 0; + } + + @Override + public long calculateGoingToFullShadeDelay() { + return 0; + } + + @Override + public float getDismissAmount() { + return 0f; + } + + @Override + public boolean isDismissingFromSwipe() { + return false; + } + + @Override + public boolean isFlingingToDismissKeyguard() { + return false; + } + + @Override + public boolean isFlingingToDismissKeyguardDuringSwipeGesture() { + return false; + } + + @Override + public boolean isSnappingKeyguardBackAfterSwipe() { + return false; + } + + @Override + public void notifyPanelFlingStart(boolean dismiss) { + } + + @Override + public void notifyPanelFlingEnd() { + } + + @Override + public void addCallback(Callback listener) { + } + + @Override + public void removeCallback(Callback listener) { + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 04ad1f8106b0c..0708b17277159 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -68,7 +69,6 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.google.common.truth.Truth; @@ -94,7 +94,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private ViewMediatorCallback mViewMediatorCallback; @Mock private LockPatternUtils mLockPatternUtils; - @Mock private KeyguardStateController mKeyguardStateController; @Mock private CentralSurfaces mCentralSurfaces; @Mock private ViewGroup mContainer; @Mock private NotificationPanelViewController mNotificationPanelView; @@ -123,6 +122,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback; + private FakeKeyguardStateController mKeyguardStateController = + spy(new FakeKeyguardStateController()); @Mock private ViewRootImpl mViewRootImpl; @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher; @@ -180,7 +181,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mBiometricUnlockController, mNotificationContainer, mBypassController); - when(mKeyguardStateController.isOccluded()).thenReturn(false); mStatusBarKeyguardViewManager.show(null); ArgumentCaptor callbackArgumentCaptor = ArgumentCaptor.forClass(KeyguardBouncer.BouncerExpansionCallback.class); @@ -253,7 +253,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Test public void onPanelExpansionChanged_showsBouncerWhenSwiping() { - when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false); + mKeyguardStateController.setCanDismissLockScreen(false); mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT); verify(mBouncer).show(eq(false), eq(false)); @@ -340,13 +340,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { } @Test - public void setOccluded_onKeyguardOccludedChangedCalledCorrectly() { + public void setOccluded_onKeyguardOccludedChangedCalled() { clearInvocations(mKeyguardStateController); clearInvocations(mKeyguardUpdateMonitor); - // Should be false to start, so no invocations mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, false /* animated */); - verify(mKeyguardStateController, never()).notifyKeyguardState(anyBoolean(), anyBoolean()); + verify(mKeyguardStateController).notifyKeyguardState(true, false); clearInvocations(mKeyguardUpdateMonitor); clearInvocations(mKeyguardStateController); @@ -357,8 +356,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { clearInvocations(mKeyguardUpdateMonitor); clearInvocations(mKeyguardStateController); - mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */); - verify(mKeyguardStateController, never()).notifyKeyguardState(anyBoolean(), anyBoolean()); + mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, false /* animated */); + verify(mKeyguardStateController).notifyKeyguardState(true, false); } @Test @@ -426,7 +425,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true); assertTrue( "Is showing not accurate when alternative auth showing", - mStatusBarKeyguardViewManager.isShowing()); + mStatusBarKeyguardViewManager.isBouncerShowing()); } @Test From 2961725bcf910a41a5fac0f709c20f427f8b828d Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 22 Sep 2022 13:02:14 +0000 Subject: [PATCH 02/23] DO NOT MERGE Use KeyguardStateController for #isShowing Remove calls that route through StatusBarKeyguardViewManager/KeyguardViewController. This was unnecessary and led to confusion. Instead, all components should directly check KeyguardStateController for #isShowing and #isOccluded. For now, this CL retains the keyguardVisibility callback in KeyguardUpdateMonitor, where keyguardVisibility is defined as when KeyguardStateController, our source of truth). Test: builds Test: atest SystemUITests Bug: 248089638 Fixes: 251880943 Change-Id: I7c6373d2fa81ab2063234aae338b1b9643038e6a (cherry picked from commit e6e7b75d3b1073918ab5a44fd00148cd5b8030f6) Merged-In: I7c6373d2fa81ab2063234aae338b1b9643038e6a --- .../keyguard/KeyguardUpdateMonitor.java | 9 +- .../keyguard/KeyguardViewController.java | 5 - .../UdfpsKeyguardViewController.java | 2 +- .../KeyguardUnlockAnimationController.kt | 6 +- .../keyguard/KeyguardViewMediator.java | 2 +- .../systemui/navigationbar/NavBarHelper.java | 10 +- .../NotificationPanelViewController.java | 2 +- .../DynamicPrivacyController.java | 16 +- .../phone/BiometricUnlockController.java | 12 +- .../CentralSurfacesCommandQueueCallbacks.java | 4 +- .../statusbar/phone/CentralSurfacesImpl.java | 36 ++--- .../phone/StatusBarKeyguardViewManager.java | 99 +++++------- .../policy/KeyguardStateController.java | 13 +- .../policy/KeyguardStateControllerImpl.java | 3 + .../keyguard/KeyguardViewMediatorTest.java | 4 +- .../navigationbar/NavBarHelperTest.java | 4 +- .../navigationbar/NavigationBarTest.java | 7 +- .../DynamicPrivacyControllerTest.java | 3 - .../phone/BiometricsUnlockControllerTest.java | 10 +- .../phone/CentralSurfacesImplTest.java | 46 +++--- .../phone/FakeKeyguardStateController.java | 145 ++++++++++++++++++ .../StatusBarKeyguardViewManagerTest.java | 19 ++- 22 files changed, 275 insertions(+), 182 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index d58ba80685f54..8792a211ad5b1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -3178,14 +3178,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Whether the keyguard is showing and not occluded. */ public boolean isKeyguardVisible() { - return isKeyguardShowing() && !mKeyguardOccluded; - } - - /** - * Whether the keyguard is showing. It may still be occluded and not visible. - */ - public boolean isKeyguardShowing() { - return mKeyguardShowing; + return mKeyguardShowing && !mKeyguardOccluded; } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java index 8293c74c5e75e..614596fef8139 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java @@ -93,11 +93,6 @@ public interface KeyguardViewController { */ void setOccluded(boolean occluded, boolean animate); - /** - * @return Whether the keyguard is showing - */ - boolean isShowing(); - /** * Dismisses the keyguard by going to the next screen or making it gone. */ diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index 24b893340ae01..ec2a55c6d0034 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -219,7 +219,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController mAssistManagerLazy; private final Lazy> mCentralSurfacesOptionalLazy; - private final KeyguardViewController mKeyguardViewController; + private final KeyguardStateController mKeyguardStateController; private final UserTracker mUserTracker; private final SystemActions mSystemActions; private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver; @@ -125,7 +125,7 @@ public final class NavBarHelper implements OverviewProxyService overviewProxyService, Lazy assistManagerLazy, Lazy> centralSurfacesOptionalLazy, - KeyguardViewController keyguardViewController, + KeyguardStateController keyguardStateController, NavigationModeController navigationModeController, UserTracker userTracker, DumpManager dumpManager) { @@ -134,7 +134,7 @@ public final class NavBarHelper implements mAccessibilityManager = accessibilityManager; mAssistManagerLazy = assistManagerLazy; mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; - mKeyguardViewController = keyguardViewController; + mKeyguardStateController = keyguardStateController; mUserTracker = userTracker; mSystemActions = systemActions; accessibilityManager.addAccessibilityServicesStateChangeListener(this); @@ -326,7 +326,7 @@ public final class NavBarHelper implements shadeWindowView = mCentralSurfacesOptionalLazy.get().get().getNotificationShadeWindowView(); } - boolean isKeyguardShowing = mKeyguardViewController.isShowing(); + boolean isKeyguardShowing = mKeyguardStateController.isShowing(); boolean imeVisibleOnShade = shadeWindowView != null && shadeWindowView.isAttachedToWindow() && shadeWindowView.getRootWindowInsets().isVisible(WindowInsets.Type.ime()); return imeVisibleOnShade diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 11103861f70b4..ad425088e0424 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -4289,7 +4289,7 @@ public final class NotificationPanelViewController extends PanelViewController { } if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyExpanded() - && mStatusBarKeyguardViewManager.isShowing()) { + && mKeyguardStateController.isShowing()) { mStatusBarKeyguardViewManager.updateKeyguardPosition(event.getX()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java index 1be4c04ef8047..b5c7ef5f76308 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification; -import android.annotation.Nullable; import android.util.ArraySet; import androidx.annotation.VisibleForTesting; @@ -25,7 +24,6 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import javax.inject.Inject; @@ -43,7 +41,6 @@ public class DynamicPrivacyController implements KeyguardStateController.Callbac private boolean mLastDynamicUnlocked; private boolean mCacheInvalid; - @Nullable private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Inject DynamicPrivacyController(NotificationLockscreenUserManager notificationLockscreenUserManager, @@ -100,7 +97,7 @@ public class DynamicPrivacyController implements KeyguardStateController.Callbac * contents aren't revealed yet? */ public boolean isInLockedDownShade() { - if (!isStatusBarKeyguardShowing() || !mKeyguardStateController.isMethodSecure()) { + if (!mKeyguardStateController.isShowing() || !mKeyguardStateController.isMethodSecure()) { return false; } int state = mStateController.getState(); @@ -113,16 +110,7 @@ public class DynamicPrivacyController implements KeyguardStateController.Callbac return true; } - private boolean isStatusBarKeyguardShowing() { - return mStatusBarKeyguardViewManager != null && mStatusBarKeyguardViewManager.isShowing(); - } - - public void setStatusBarKeyguardViewManager( - StatusBarKeyguardViewManager statusBarKeyguardViewManager) { - mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; - } - public interface Listener { void onDynamicPrivacyChanged(); } -} \ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index fe431377f854c..a2798f47be658 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -163,7 +163,6 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private PowerManager.WakeLock mWakeLock; private final com.android.systemui.shade.ShadeController mShadeController; private final KeyguardUpdateMonitor mUpdateMonitor; - private final DozeParameters mDozeParameters; private final KeyguardStateController mKeyguardStateController; private final NotificationShadeWindowController mNotificationShadeWindowController; private final SessionTracker mSessionTracker; @@ -278,7 +277,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp KeyguardStateController keyguardStateController, Handler handler, KeyguardUpdateMonitor keyguardUpdateMonitor, @Main Resources resources, - KeyguardBypassController keyguardBypassController, DozeParameters dozeParameters, + KeyguardBypassController keyguardBypassController, MetricsLogger metricsLogger, DumpManager dumpManager, PowerManager powerManager, NotificationMediaManager notificationMediaManager, @@ -294,7 +293,6 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp mPowerManager = powerManager; mShadeController = shadeController; mUpdateMonitor = keyguardUpdateMonitor; - mDozeParameters = dozeParameters; mUpdateMonitor.registerCallback(this); mMediaManager = notificationMediaManager; mLatencyTracker = latencyTracker; @@ -552,7 +550,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean deviceDreaming = mUpdateMonitor.isDreaming(); if (!mUpdateMonitor.isDeviceInteractive()) { - if (!mKeyguardViewController.isShowing() + if (!mKeyguardStateController.isShowing() && !mScreenOffAnimationController.isKeyguardShowDelayed()) { if (mKeyguardStateController.isUnlocked()) { return MODE_WAKE_AND_UNLOCK; @@ -569,7 +567,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (unlockingAllowed && deviceDreaming) { return MODE_WAKE_AND_UNLOCK_FROM_DREAM; } - if (mKeyguardViewController.isShowing()) { + if (mKeyguardStateController.isShowing()) { if (mKeyguardViewController.bouncerIsOrWillBeShowing() && unlockingAllowed) { return MODE_DISMISS_BOUNCER; } else if (unlockingAllowed) { @@ -588,7 +586,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean bypass = mKeyguardBypassController.getBypassEnabled() || mAuthController.isUdfpsFingerDown(); if (!mUpdateMonitor.isDeviceInteractive()) { - if (!mKeyguardViewController.isShowing()) { + if (!mKeyguardStateController.isShowing()) { return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE; } else if (!unlockingAllowed) { return bypass ? MODE_SHOW_BOUNCER : MODE_NONE; @@ -612,7 +610,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (unlockingAllowed && mKeyguardStateController.isOccluded()) { return MODE_UNLOCK_COLLAPSING; } - if (mKeyguardViewController.isShowing()) { + if (mKeyguardStateController.isShowing()) { if ((mKeyguardViewController.bouncerIsOrWillBeShowing() || mKeyguardBypassController.getAltBouncerShowing()) && unlockingAllowed) { return MODE_DISMISS_BOUNCER; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index 52a45d6785ca2..1e95dad6b1157 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -363,7 +363,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba mKeyguardUpdateMonitor.onCameraLaunched(); } - if (!mStatusBarKeyguardViewManager.isShowing()) { + if (!mKeyguardStateController.isShowing()) { final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext); mCentralSurfaces.startActivityDismissingKeyguard(cameraIntent, false /* onlyProvisioned */, true /* dismissShade */, @@ -420,7 +420,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for // app-side haptic experimentation. - if (!mStatusBarKeyguardViewManager.isShowing()) { + if (!mKeyguardStateController.isShowing()) { mCentralSurfaces.startActivityDismissingKeyguard(emergencyIntent, false /* onlyProvisioned */, true /* dismissShade */, true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 01a92b8bc418c..56e1bfbf3c700 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -476,7 +476,6 @@ public class CentralSurfacesImpl extends CoreStartable implements private final KeyguardStateController mKeyguardStateController; private final HeadsUpManagerPhone mHeadsUpManager; private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager; - private final DynamicPrivacyController mDynamicPrivacyController; private final FalsingCollector mFalsingCollector; private final FalsingManager mFalsingManager; private final BroadcastDispatcher mBroadcastDispatcher; @@ -779,7 +778,6 @@ public class CentralSurfacesImpl extends CoreStartable implements mHeadsUpManager = headsUpManagerPhone; mKeyguardIndicationController = keyguardIndicationController; mStatusBarTouchableRegionManager = statusBarTouchableRegionManager; - mDynamicPrivacyController = dynamicPrivacyController; mFalsingCollector = falsingCollector; mFalsingManager = falsingManager; mBroadcastDispatcher = broadcastDispatcher; @@ -1570,7 +1568,6 @@ public class CentralSurfacesImpl extends CoreStartable implements .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); mRemoteInputManager.addControllerCallback(mStatusBarKeyguardViewManager); - mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mLightBarController.setBiometricUnlockController(mBiometricUnlockController); mMediaManager.setBiometricUnlockController(mBiometricUnlockController); @@ -2082,7 +2079,7 @@ public class CentralSurfacesImpl extends CoreStartable implements // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in // the bouncer appear animation. - if (!mStatusBarKeyguardViewManager.isShowing()) { + if (!mKeyguardStateController.isShowing()) { WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); } } @@ -2519,8 +2516,8 @@ public class CentralSurfacesImpl extends CoreStartable implements }; // Do not deferKeyguard when occluded because, when keyguard is occluded, // we do not launch the activity until keyguard is done. - boolean occluded = mStatusBarKeyguardViewManager.isShowing() - && mStatusBarKeyguardViewManager.isOccluded(); + boolean occluded = mKeyguardStateController.isShowing() + && mKeyguardStateController.isOccluded(); boolean deferred = !occluded; executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShadeDirectly, willLaunchResolverActivity, deferred /* deferred */, animate); @@ -2590,8 +2587,8 @@ public class CentralSurfacesImpl extends CoreStartable implements @Override public boolean onDismiss() { if (runnable != null) { - if (mStatusBarKeyguardViewManager.isShowing() - && mStatusBarKeyguardViewManager.isOccluded()) { + if (mKeyguardStateController.isShowing() + && mKeyguardStateController.isOccluded()) { mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); } else { mMainExecutor.execute(runnable); @@ -2685,7 +2682,7 @@ public class CentralSurfacesImpl extends CoreStartable implements private void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen, boolean afterKeyguardGone) { - if (mStatusBarKeyguardViewManager.isShowing() && requiresShadeOpen) { + if (mKeyguardStateController.isShowing() && requiresShadeOpen) { mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); } dismissKeyguardThenExecute(action, null /* cancelAction */, @@ -2709,7 +2706,7 @@ public class CentralSurfacesImpl extends CoreStartable implements mBiometricUnlockController.startWakeAndUnlock( BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING); } - if (mStatusBarKeyguardViewManager.isShowing()) { + if (mKeyguardStateController.isShowing()) { mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, afterKeyguardGone); } else { @@ -2845,8 +2842,8 @@ public class CentralSurfacesImpl extends CoreStartable implements } private void logStateToEventlog() { - boolean isShowing = mStatusBarKeyguardViewManager.isShowing(); - boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded(); + boolean isShowing = mKeyguardStateController.isShowing(); + boolean isOccluded = mKeyguardStateController.isOccluded(); boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing(); boolean isSecure = mKeyguardStateController.isMethodSecure(); boolean unlocked = mKeyguardStateController.canDismissLockScreen(); @@ -3242,18 +3239,17 @@ public class CentralSurfacesImpl extends CoreStartable implements Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0); Trace.beginSection("CentralSurfaces#updateDozingState"); - boolean visibleNotOccluded = mStatusBarKeyguardViewManager.isShowing() - && !mStatusBarKeyguardViewManager.isOccluded(); + boolean keyguardVisible = mKeyguardStateController.isVisible(); // If we're dozing and we'll be animating the screen off, the keyguard isn't currently // visible but will be shortly for the animation, so we should proceed as if it's visible. - boolean visibleNotOccludedOrWillBe = - visibleNotOccluded || (mDozing && mDozeParameters.shouldDelayKeyguardShow()); + boolean keyguardVisibleOrWillBe = + keyguardVisible || (mDozing && mDozeParameters.shouldDelayKeyguardShow()); boolean wakeAndUnlock = mBiometricUnlockController.getMode() == BiometricUnlockController.MODE_WAKE_AND_UNLOCK; boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup() && !wakeAndUnlock) || (mDozing && mDozeParameters.shouldControlScreenOff() - && visibleNotOccludedOrWillBe); + && keyguardVisibleOrWillBe); mNotificationPanelViewController.setDozing(mDozing, animate); updateQsExpansionEnabled(); @@ -3934,11 +3930,7 @@ public class CentralSurfacesImpl extends CoreStartable implements @Override public boolean isKeyguardShowing() { - if (mStatusBarKeyguardViewManager == null) { - Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true"); - return true; - } - return mStatusBarKeyguardViewManager.isShowing(); + return mKeyguardStateController.isShowing(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 6e1cf13d01d79..a20ce5fa77818 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -229,8 +229,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private View mNotificationContainer; @Nullable protected KeyguardBouncer mBouncer; - protected boolean mShowing; - protected boolean mOccluded; protected boolean mRemoteInputActive; private boolean mGlobalActionsVisible = false; private boolean mLastGlobalActionsVisible = false; @@ -277,10 +275,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb new KeyguardUpdateMonitorCallback() { @Override public void onEmergencyCallAction() { - // Since we won't get a setOccluded call we have to reset the view manually such that // the bouncer goes away. - if (mOccluded) { + if (mKeyguardStateController.isOccluded()) { reset(true /* hideBouncerWhenShowing */); } } @@ -479,7 +476,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } else { mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE); } - } else if (mShowing && !hideBouncerOverDream) { + } else if (mKeyguardStateController.isShowing() && !hideBouncerOverDream) { if (!isWakeAndUnlocking() && !(mBiometricUnlockController.getMode() == MODE_DISMISS_BOUNCER) && !mCentralSurfaces.isInLaunchTransition() @@ -500,7 +497,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBouncerInteractor.show(/* isScrimmed= */false); } } - } else if (!mShowing && isBouncerInTransit()) { + } else if (!mKeyguardStateController.isShowing() && isBouncerInTransit()) { // Keyguard is not visible anymore, but expansion animation was still running. // We need to hide the bouncer, otherwise it will be stuck in transit. if (mBouncer != null) { @@ -533,9 +530,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void show(Bundle options) { Trace.beginSection("StatusBarKeyguardViewManager#show"); - mShowing = true; mNotificationShadeWindowController.setKeyguardShowing(true); - mKeyguardStateController.notifyKeyguardState(mShowing, + mKeyguardStateController.notifyKeyguardState(true, mKeyguardStateController.isOccluded()); reset(true /* hideBouncerWhenShowing */); SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, @@ -599,7 +595,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } else { mBouncerInteractor.hide(); } - if (mShowing) { + if (mKeyguardStateController.isShowing()) { // If we were showing the bouncer and then aborting, we need to also clear out any // potential actions unless we actually unlocked. cancelPostAuthActions(); @@ -616,7 +612,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void showBouncer(boolean scrimmed) { resetAlternateAuth(false); - if (mShowing && !isBouncerShowing()) { + if (mKeyguardStateController.isShowing() && !isBouncerShowing()) { if (mBouncer != null) { mBouncer.show(false /* resetSecuritySelection */, scrimmed); } else { @@ -633,7 +629,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void dismissWithAction(OnDismissAction r, Runnable cancelAction, boolean afterKeyguardGone, String message) { - if (mShowing) { + if (mKeyguardStateController.isShowing()) { try { Trace.beginSection("StatusBarKeyguardViewManager#dismissWithAction"); cancelPendingWakeupAction(); @@ -719,11 +715,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void reset(boolean hideBouncerWhenShowing) { - if (mShowing) { + if (mKeyguardStateController.isShowing()) { + final boolean isOccluded = mKeyguardStateController.isOccluded(); // Hide quick settings. - mNotificationPanelViewController.resetViews(/* animate= */ !mOccluded); + mNotificationPanelViewController.resetViews(/* animate= */ !isOccluded); // Hide bouncer and quick-quick settings. - if (mOccluded && !mDozing) { + if (isOccluded && !mDozing) { mCentralSurfaces.hideKeyguard(); if (hideBouncerWhenShowing || needsFullscreenBouncer()) { hideBouncer(false /* destroyView */); @@ -805,7 +802,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private void setDozing(boolean dozing) { if (mDozing != dozing) { mDozing = dozing; - if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) { + if (dozing || mBouncer.needsFullscreenBouncer() + || mKeyguardStateController.isOccluded()) { reset(dozing /* hideBouncerWhenShowing */); } updateStates(); @@ -838,18 +836,23 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void setOccluded(boolean occluded, boolean animate) { - final boolean isOccluding = !mOccluded && occluded; - final boolean isUnOccluding = mOccluded && !occluded; - setOccludedAndUpdateStates(occluded); + final boolean wasOccluded = mKeyguardStateController.isOccluded(); + final boolean isOccluding = !wasOccluded && occluded; + final boolean isUnOccluding = wasOccluded && !occluded; + mKeyguardStateController.notifyKeyguardState( + mKeyguardStateController.isShowing(), occluded); + updateStates(); + final boolean isShowing = mKeyguardStateController.isShowing(); + final boolean isOccluded = mKeyguardStateController.isOccluded(); - if (mShowing && isOccluding) { + if (isShowing && isOccluding) { SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED); if (mCentralSurfaces.isInLaunchTransition()) { final Runnable endRunnable = new Runnable() { @Override public void run() { - mNotificationShadeWindowController.setKeyguardOccluded(mOccluded); + mNotificationShadeWindowController.setKeyguardOccluded(isOccluded); reset(true /* hideBouncerWhenShowing */); } }; @@ -864,19 +867,19 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb // When isLaunchingActivityOverLockscreen() is true, we know for sure that the post // collapse runnables will be run. mShadeController.get().addPostCollapseAction(() -> { - mNotificationShadeWindowController.setKeyguardOccluded(mOccluded); + mNotificationShadeWindowController.setKeyguardOccluded(isOccluded); reset(true /* hideBouncerWhenShowing */); }); return; } - } else if (mShowing && isUnOccluding) { + } else if (isShowing && isUnOccluding) { SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN); } - if (mShowing) { - mMediaManager.updateMediaMetaData(false, animate && !mOccluded); + if (isShowing) { + mMediaManager.updateMediaMetaData(false, animate && !isOccluded); } - mNotificationShadeWindowController.setKeyguardOccluded(mOccluded); + mNotificationShadeWindowController.setKeyguardOccluded(isOccluded); // setDozing(false) will call reset once we stop dozing. Also, if we're going away, there's // no need to reset the keyguard views as we'll be gone shortly. Resetting now could cause @@ -886,20 +889,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb // by a FLAG_DISMISS_KEYGUARD_ACTIVITY. reset(isOccluding /* hideBouncerWhenShowing*/); } - if (animate && !mOccluded && mShowing && !bouncerIsShowing()) { + if (animate && !isOccluded && isShowing && !bouncerIsShowing()) { mCentralSurfaces.animateKeyguardUnoccluding(); } } - private void setOccludedAndUpdateStates(boolean occluded) { - mOccluded = occluded; - updateStates(); - } - - public boolean isOccluded() { - return mOccluded; - } - @Override public void startPreHideAnimation(Runnable finishRunnable) { if (bouncerIsShowing()) { @@ -930,8 +924,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void hide(long startTime, long fadeoutDuration) { Trace.beginSection("StatusBarKeyguardViewManager#hide"); - mShowing = false; - mKeyguardStateController.notifyKeyguardState(mShowing, + mKeyguardStateController.notifyKeyguardState(false, mKeyguardStateController.isOccluded()); launchPendingWakeupAction(); @@ -1080,11 +1073,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb KeyguardUpdateMonitor.getCurrentUser()) != KeyguardSecurityModel.SecurityMode.None; } - @Override - public boolean isShowing() { - return mShowing; - } - /** * Returns whether a back invocation can be handled, which depends on whether the keyguard * is currently showing (which itself is derived from multiple states). @@ -1187,8 +1175,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb }; protected void updateStates() { - boolean showing = mShowing; - boolean occluded = mOccluded; + boolean showing = mKeyguardStateController.isShowing(); + boolean occluded = mKeyguardStateController.isOccluded(); boolean bouncerShowing = bouncerIsShowing(); boolean bouncerIsOrWillBeShowing = bouncerIsOrWillBeShowing(); boolean bouncerDismissible = !isFullscreenBouncer(); @@ -1222,13 +1210,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mNotificationShadeWindowController.setBouncerShowing(bouncerShowing); mCentralSurfaces.setBouncerShowing(bouncerShowing); } - - if (occluded != mLastOccluded || mFirstUpdate) { - mKeyguardStateController.notifyKeyguardState(showing, occluded); - } - if (occluded != mLastOccluded || mShowing != showing || mFirstUpdate) { - mKeyguardUpdateManager.setKeyguardShowing(showing, occluded); - } if (bouncerIsOrWillBeShowing != mLastBouncerIsOrWillBeShowing || mFirstUpdate || bouncerShowing != mLastBouncerShowing) { mKeyguardUpdateManager.sendKeyguardBouncerChanged(bouncerIsOrWillBeShowing, @@ -1279,12 +1260,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public boolean isNavBarVisible() { boolean isWakeAndUnlockPulsing = mBiometricUnlockController != null && mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING; - boolean keyguardShowing = mShowing && !mOccluded; + boolean keyguardVisible = mKeyguardStateController.isVisible(); boolean hideWhileDozing = mDozing && !isWakeAndUnlockPulsing; - boolean keyguardWithGestureNav = (keyguardShowing && !mDozing && !mScreenOffAnimationPlaying + boolean keyguardWithGestureNav = (keyguardVisible && !mDozing && !mScreenOffAnimationPlaying || mPulsing && !mIsDocked) && mGesturalNav; - return (!keyguardShowing && !hideWhileDozing && !mScreenOffAnimationPlaying + return (!keyguardVisible && !hideWhileDozing && !mScreenOffAnimationPlaying || bouncerIsShowing() || mRemoteInputActive || keyguardWithGestureNav @@ -1416,7 +1397,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb DismissWithActionRequest request = mPendingWakeupAction; mPendingWakeupAction = null; if (request != null) { - if (mShowing) { + if (mKeyguardStateController.isShowing()) { dismissWithAction(request.dismissAction, request.cancelAction, request.afterKeyguardGone, request.message); } else if (request.dismissAction != null) { @@ -1435,10 +1416,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public boolean bouncerNeedsScrimming() { // When a dream overlay is active, scrimming will cause any expansion to immediately expand. - return (mOccluded && !mDreamOverlayStateController.isOverlayActive()) + return (mKeyguardStateController.isOccluded() + && !mDreamOverlayStateController.isOverlayActive()) || bouncerWillDismissWithAction() - || (bouncerIsShowing() - && bouncerIsScrimmed()) + || (bouncerIsShowing() && bouncerIsScrimmed()) || isFullscreenBouncer(); } @@ -1457,8 +1438,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void dump(PrintWriter pw) { pw.println("StatusBarKeyguardViewManager:"); - pw.println(" mShowing: " + mShowing); - pw.println(" mOccluded: " + mOccluded); pw.println(" mRemoteInputActive: " + mRemoteInputActive); pw.println(" mDozing: " + mDozing); pw.println(" mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java index 250d9d46de66c..1ae1eae00651a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java @@ -35,9 +35,16 @@ public interface KeyguardStateController extends CallbackController { } /** - * If the lock screen is visible. - * The keyguard is also visible when the device is asleep or in always on mode, except when - * the screen timed out and the user can unlock by quickly pressing power. + * If the keyguard is visible. This is unrelated to being locked or not. + */ + default boolean isVisible() { + return isShowing() && !isOccluded(); + } + + /** + * If the keyguard is showing. This includes when it's occluded by an activity, and when + * the device is asleep or in always on mode, except when the screen timed out and the user + * can unlock by quickly pressing power. * * This is unrelated to being locked or not. * diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java index 437d4d415275d..cc6fdccba7893 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java @@ -181,6 +181,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum if (mShowing == showing && mOccluded == occluded) return; mShowing = showing; mOccluded = occluded; + mKeyguardUpdateMonitor.setKeyguardShowing(showing, occluded); Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events", "Keyguard showing: " + showing + " occluded: " + occluded); notifyKeyguardChanged(); @@ -387,6 +388,8 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum @Override public void dump(PrintWriter pw, String[] args) { pw.println("KeyguardStateController:"); + pw.println(" mShowing: " + mShowing); + pw.println(" mOccluded: " + mOccluded); pw.println(" mSecure: " + mSecure); pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen); pw.println(" mTrustManaged: " + mTrustManaged); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 21c018a0419d5..39f3c96803c31 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -176,7 +176,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { // and the keyguard goes away mViewMediator.setShowingLocked(false); - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); mViewMediator.mUpdateCallback.onKeyguardVisibilityChanged(false); TestableLooper.get(this).processAllMessages(); @@ -201,7 +201,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { // and the keyguard goes away mViewMediator.setShowingLocked(false); - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); mViewMediator.mUpdateCallback.onKeyguardVisibilityChanged(false); TestableLooper.get(this).processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java index 80731037481a2..6c03730e056e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java @@ -39,7 +39,6 @@ import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.keyguard.KeyguardViewController; import com.android.systemui.SysuiTestCase; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; @@ -49,6 +48,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; import org.junit.Test; @@ -113,7 +113,7 @@ public class NavBarHelperTest extends SysuiTestCase { mNavBarHelper = new NavBarHelper(mContext, mAccessibilityManager, mAccessibilityButtonModeObserver, mAccessibilityButtonTargetObserver, mSystemActions, mOverviewProxyService, mAssistManagerLazy, - () -> Optional.of(mock(CentralSurfaces.class)), mock(KeyguardViewController.class), + () -> Optional.of(mock(CentralSurfaces.class)), mock(KeyguardStateController.class), mNavigationModeController, mUserTracker, mDumpManager); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java index 51f0953771cb2..0e9d2799dddb0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java @@ -72,7 +72,6 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; -import com.android.keyguard.KeyguardViewController; import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestableContext; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; @@ -194,7 +193,7 @@ public class NavigationBarTest extends SysuiTestCase { @Mock private CentralSurfaces mCentralSurfaces; @Mock - private KeyguardViewController mKeyguardViewController; + private KeyguardStateController mKeyguardStateController; @Mock private UserContextProvider mUserContextProvider; @Mock @@ -240,7 +239,7 @@ public class NavigationBarTest extends SysuiTestCase { mock(AccessibilityButtonTargetsObserver.class), mSystemActions, mOverviewProxyService, () -> mock(AssistManager.class), () -> Optional.of(mCentralSurfaces), - mKeyguardViewController, mock(NavigationModeController.class), + mKeyguardStateController, mock(NavigationModeController.class), mock(UserTracker.class), mock(DumpManager.class))); mNavigationBar = createNavBar(mContext); mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal); @@ -380,7 +379,7 @@ public class NavigationBarTest extends SysuiTestCase { // Verify navbar didn't alter and showing back icon when the keyguard is showing without // requesting IME insets visible. - doReturn(true).when(mKeyguardViewController).isShowing(); + doReturn(true).when(mKeyguardStateController).isShowing(); mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true); assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java index b719c7f9e54ee..a6381d13f7da0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java @@ -32,7 +32,6 @@ import android.testing.TestableLooper; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Assert; @@ -58,8 +57,6 @@ public class DynamicPrivacyControllerTest extends SysuiTestCase { mDynamicPrivacyController = new DynamicPrivacyController( mLockScreenUserManager, mKeyguardStateController, mock(StatusBarStateController.class)); - mDynamicPrivacyController.setStatusBarKeyguardViewManager( - mock(StatusBarKeyguardViewManager.class)); mDynamicPrivacyController.addListener(mListener); // Disable dynamic privacy by default allowNotificationsInPublic(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index cd0cc33df1a98..6fa2174150449 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -100,8 +100,6 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { @Mock private AuthController mAuthController; @Mock - private DozeParameters mDozeParameters; - @Mock private MetricsLogger mMetricsLogger; @Mock private NotificationMediaManager mNotificationMediaManager; @@ -127,7 +125,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); TestableResources res = getContext().getOrCreateTestableResources(); - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true); when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true); when(mKeyguardStateController.isUnlocked()).thenReturn(false); @@ -139,7 +137,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mBiometricUnlockController = new BiometricUnlockController(mDozeScrimController, mKeyguardViewMediator, mScrimController, mShadeController, mNotificationShadeWindowController, mKeyguardStateController, mHandler, - mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters, + mUpdateMonitor, res.getResources(), mKeyguardBypassController, mMetricsLogger, mDumpManager, mPowerManager, mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle, mAuthController, mStatusBarStateController, mKeyguardUnlockAnimationController, @@ -177,7 +175,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { public void onBiometricAuthenticated_whenFingerprintAndNotInteractive_wakeAndUnlock() { reset(mUpdateMonitor); reset(mStatusBarKeyguardViewManager); - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); when(mDozeScrimController.isPulsing()).thenReturn(true); // the value of isStrongBiometric doesn't matter here since we only care about the returned @@ -194,7 +192,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { public void onBiometricAuthenticated_whenDeviceIsAlreadyUnlocked_wakeAndUnlock() { reset(mUpdateMonitor); reset(mStatusBarKeyguardViewManager); - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); when(mKeyguardStateController.isUnlocked()).thenReturn(true); when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); when(mDozeScrimController.isPulsing()).thenReturn(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index f510e48de5a56..8539367680d61 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -516,32 +516,32 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void executeRunnableDismissingKeyguard_nullRunnable_showingAndOccluded() { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(true); mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, false, false, false); } @Test public void executeRunnableDismissingKeyguard_nullRunnable_showing() { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(false); mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, false, false, false); } @Test public void executeRunnableDismissingKeyguard_nullRunnable_notShowing() { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, false, false, false); } @Test public void executeRunnableDismissingKeyguard_dreaming_notShowing() throws RemoteException { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(true); mCentralSurfaces.executeRunnableDismissingKeyguard(() -> {}, @@ -555,8 +555,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void executeRunnableDismissingKeyguard_notDreaming_notShowing() throws RemoteException { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(false); mCentralSurfaces.executeRunnableDismissingKeyguard(() -> {}, @@ -571,10 +571,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void lockscreenStateMetrics_notShowing() { // uninteresting state, except that fingerprint must be non-zero - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); // interesting state - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(false); mCentralSurfaces.onKeyguardViewManagerStatesUpdated(); @@ -589,10 +589,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void lockscreenStateMetrics_notShowing_secure() { // uninteresting state, except that fingerprint must be non-zero - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); // interesting state - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(true); @@ -608,10 +608,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void lockscreenStateMetrics_isShowing() { // uninteresting state, except that fingerprint must be non-zero - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); // interesting state - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(false); @@ -627,10 +627,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void lockscreenStateMetrics_isShowing_secure() { // uninteresting state, except that fingerprint must be non-zero - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); // interesting state - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(true); @@ -646,10 +646,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void lockscreenStateMetrics_isShowingBouncer() { // uninteresting state, except that fingerprint must be non-zero - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); // interesting state - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true); when(mKeyguardStateController.isMethodSecure()).thenReturn(true); @@ -1053,9 +1053,9 @@ public class CentralSurfacesImplTest extends SysuiTestCase { } @Test - public void startActivityDismissingKeyguard_isShowingandIsOccluded() { - when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); - when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(true); + public void startActivityDismissingKeyguard_isShowingAndIsOccluded() { + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(true); mCentralSurfaces.startActivityDismissingKeyguard( new Intent(), /* onlyProvisioned = */false, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java new file mode 100644 index 0000000000000..a986777afa225 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2022 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.phone; + +import com.android.systemui.statusbar.policy.KeyguardStateController; + +/** + * Mock implementation of KeyguardStateController which tracks showing and occluded states + * based on {@link #notifyKeyguardState(boolean showing, boolean occluded)}}. + */ +public class FakeKeyguardStateController implements KeyguardStateController { + private boolean mShowing; + private boolean mOccluded; + private boolean mCanDismissLockScreen; + + @Override + public void notifyKeyguardState(boolean showing, boolean occluded) { + mShowing = showing; + mOccluded = occluded; + } + + @Override + public boolean isShowing() { + return mShowing; + } + + @Override + public boolean isOccluded() { + return mOccluded; + } + + public void setCanDismissLockScreen(boolean canDismissLockScreen) { + mCanDismissLockScreen = canDismissLockScreen; + } + + @Override + public boolean canDismissLockScreen() { + return mCanDismissLockScreen; + } + + @Override + public boolean isBouncerShowing() { + return false; + } + + @Override + public boolean isKeyguardScreenRotationAllowed() { + return false; + } + + @Override + public boolean isMethodSecure() { + return true; + } + + @Override + public boolean isTrusted() { + return false; + } + + @Override + public boolean isKeyguardGoingAway() { + return false; + } + + @Override + public boolean isKeyguardFadingAway() { + return false; + } + + @Override + public boolean isLaunchTransitionFadingAway() { + return false; + } + + @Override + public long getKeyguardFadingAwayDuration() { + return 0; + } + + @Override + public long getKeyguardFadingAwayDelay() { + return 0; + } + + @Override + public long calculateGoingToFullShadeDelay() { + return 0; + } + + @Override + public float getDismissAmount() { + return 0f; + } + + @Override + public boolean isDismissingFromSwipe() { + return false; + } + + @Override + public boolean isFlingingToDismissKeyguard() { + return false; + } + + @Override + public boolean isFlingingToDismissKeyguardDuringSwipeGesture() { + return false; + } + + @Override + public boolean isSnappingKeyguardBackAfterSwipe() { + return false; + } + + @Override + public void notifyPanelFlingStart(boolean dismiss) { + } + + @Override + public void notifyPanelFlingEnd() { + } + + @Override + public void addCallback(Callback listener) { + } + + @Override + public void removeCallback(Callback listener) { + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 04ad1f8106b0c..0708b17277159 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -68,7 +69,6 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.google.common.truth.Truth; @@ -94,7 +94,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private ViewMediatorCallback mViewMediatorCallback; @Mock private LockPatternUtils mLockPatternUtils; - @Mock private KeyguardStateController mKeyguardStateController; @Mock private CentralSurfaces mCentralSurfaces; @Mock private ViewGroup mContainer; @Mock private NotificationPanelViewController mNotificationPanelView; @@ -123,6 +122,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback; + private FakeKeyguardStateController mKeyguardStateController = + spy(new FakeKeyguardStateController()); @Mock private ViewRootImpl mViewRootImpl; @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher; @@ -180,7 +181,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mBiometricUnlockController, mNotificationContainer, mBypassController); - when(mKeyguardStateController.isOccluded()).thenReturn(false); mStatusBarKeyguardViewManager.show(null); ArgumentCaptor callbackArgumentCaptor = ArgumentCaptor.forClass(KeyguardBouncer.BouncerExpansionCallback.class); @@ -253,7 +253,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Test public void onPanelExpansionChanged_showsBouncerWhenSwiping() { - when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false); + mKeyguardStateController.setCanDismissLockScreen(false); mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT); verify(mBouncer).show(eq(false), eq(false)); @@ -340,13 +340,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { } @Test - public void setOccluded_onKeyguardOccludedChangedCalledCorrectly() { + public void setOccluded_onKeyguardOccludedChangedCalled() { clearInvocations(mKeyguardStateController); clearInvocations(mKeyguardUpdateMonitor); - // Should be false to start, so no invocations mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, false /* animated */); - verify(mKeyguardStateController, never()).notifyKeyguardState(anyBoolean(), anyBoolean()); + verify(mKeyguardStateController).notifyKeyguardState(true, false); clearInvocations(mKeyguardUpdateMonitor); clearInvocations(mKeyguardStateController); @@ -357,8 +356,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { clearInvocations(mKeyguardUpdateMonitor); clearInvocations(mKeyguardStateController); - mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */); - verify(mKeyguardStateController, never()).notifyKeyguardState(anyBoolean(), anyBoolean()); + mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, false /* animated */); + verify(mKeyguardStateController).notifyKeyguardState(true, false); } @Test @@ -426,7 +425,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true); assertTrue( "Is showing not accurate when alternative auth showing", - mStatusBarKeyguardViewManager.isShowing()); + mStatusBarKeyguardViewManager.isBouncerShowing()); } @Test From 6f7bfee8f203f70ecd88e6ea3c8653ded613df32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Pomini?= Date: Thu, 27 Oct 2022 17:25:12 +0000 Subject: [PATCH 03/23] Revert "Move canvas WallpaperEngine to droidFood" This reverts commit eca2762da77b34a48ddb07fb339a8201d30a3749. Reason for revert: culprit of b/255702022 Change-Id: I0071a7a2bccf829ecc8f25ad8da6597b0a21de6f (cherry picked from commit 11063cb1ad1ad059e64b9dc6469ae7bc5b756662) Merged-In: I0071a7a2bccf829ecc8f25ad8da6597b0a21de6f --- packages/SystemUI/src/com/android/systemui/flags/Flags.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 561222f1f58d0..539913b47be1f 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -193,7 +193,7 @@ object Flags { // 802 - wallpaper rendering // TODO(b/254512923): Tracking Bug - @JvmField val USE_CANVAS_RENDERER = ReleasedFlag(802) + @JvmField val USE_CANVAS_RENDERER = UnreleasedFlag(802, teamfood = true) // 803 - screen contents translation // TODO(b/254513187): Tracking Bug From ebd57af35038e48cb721a0e2af7b30d8f5ade7fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Pomini?= Date: Thu, 27 Oct 2022 17:25:12 +0000 Subject: [PATCH 04/23] Revert "Move canvas WallpaperEngine to droidFood" This reverts commit eca2762da77b34a48ddb07fb339a8201d30a3749. Reason for revert: culprit of b/255702022 Change-Id: I0071a7a2bccf829ecc8f25ad8da6597b0a21de6f (cherry picked from commit 11063cb1ad1ad059e64b9dc6469ae7bc5b756662) Merged-In: I0071a7a2bccf829ecc8f25ad8da6597b0a21de6f --- packages/SystemUI/src/com/android/systemui/flags/Flags.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index e38f7f10b4b99..aa0ca20997742 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -193,7 +193,7 @@ object Flags { // 802 - wallpaper rendering // TODO(b/254512923): Tracking Bug - @JvmField val USE_CANVAS_RENDERER = ReleasedFlag(802) + @JvmField val USE_CANVAS_RENDERER = UnreleasedFlag(802, teamfood = true) // 803 - screen contents translation // TODO(b/254513187): Tracking Bug From d2727e6ce39b242e120a2c5a63e2fa8c082daae6 Mon Sep 17 00:00:00 2001 From: Neha Jain Date: Fri, 4 Nov 2022 22:08:36 +0000 Subject: [PATCH 05/23] Revert "Fix pip update transaction out of order" This reverts commit c3ebae4ca884a1b56930b322d171d06b675fbe4d. Reason for revert: b/257379026 Change-Id: Id5f4cf24fe2a65b70ae5f024c2fcd5f16b92bbb0 (cherry picked from commit d53696fecf3e26b70429e79ff7054ee292c4b1b9) Merged-In: Id5f4cf24fe2a65b70ae5f024c2fcd5f16b92bbb0 --- .../wm/shell/pip/PipMenuController.java | 6 --- .../wm/shell/pip/PipTaskOrganizer.java | 40 +++---------------- .../pip/phone/PhonePipMenuController.java | 12 ------ .../wm/shell/pip/tv/TvPipMenuController.java | 12 ------ 4 files changed, 5 insertions(+), 65 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java index f81c9f80830ae..16f1d1c2944c3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java @@ -23,7 +23,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.RemoteAction; @@ -70,11 +69,6 @@ public interface PipMenuController { */ void setAppActions(List appActions, RemoteAction closeAction); - /** - * Wait until the next frame to run the given Runnable. - */ - void runWithNextFrame(@NonNull Runnable runnable); - /** * Resize the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a * need to synchronize the movements on the same frame as PiP. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index 2d7c5ce6feb5d..f170e774739fc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -179,10 +179,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // This is necessary in case there was a resize animation ongoing when exit PIP // started, in which case the first resize will be skipped to let the exit // operation handle the final resize out of PIP mode. See b/185306679. - finishResizeDelayedIfNeeded(() -> { - finishResize(tx, destinationBounds, direction, animationType); - sendOnPipTransitionFinished(direction); - }); + finishResize(tx, destinationBounds, direction, animationType); + sendOnPipTransitionFinished(direction); } } @@ -198,34 +196,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } }; - /** - * Finishes resizing the PiP, delaying the operation if it has to be synced with the PiP menu. - * - * This is done to avoid a race condition between the last transaction applied in - * onAnimationUpdate and the finishResize in onAnimationEnd. finishResize creates a - * WindowContainerTransaction, which is to be applied by WmCore later. It may happen that it - * gets applied before the transaction created by the last onAnimationUpdate. As a result of - * this, the PiP surface may get scaled after the new bounds are applied by WmCore, which - * makes the PiP surface have unexpected bounds. To avoid this, we delay the finishResize - * operation until the next frame. This aligns the last onAnimationUpdate transaction with the - * WCT application. - * - * The race only happens when the PiP surface transaction has to be synced with the PiP menu - * due to the necessity for a delay when syncing the PiP surface, the PiP menu surface and - * the PiP menu contents. - */ - private void finishResizeDelayedIfNeeded(Runnable finishResizeRunnable) { - if (!shouldSyncPipTransactionWithMenu()) { - finishResizeRunnable.run(); - return; - } - mPipMenuController.runWithNextFrame(finishResizeRunnable); - } - - private boolean shouldSyncPipTransactionWithMenu() { - return mPipMenuController.isMenuVisible(); - } - @VisibleForTesting final PipTransitionController.PipTransitionCallback mPipTransitionCallback = new PipTransitionController.PipTransitionCallback() { @@ -251,7 +221,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @Override public boolean handlePipTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, Rect destinationBounds) { - if (shouldSyncPipTransactionWithMenu()) { + if (mPipMenuController.isMenuVisible()) { mPipMenuController.movePipMenu(leash, tx, destinationBounds); return true; } @@ -1253,7 +1223,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceTransactionHelper .crop(tx, mLeash, toBounds) .round(tx, mLeash, mPipTransitionState.isInPip()); - if (shouldSyncPipTransactionWithMenu()) { + if (mPipMenuController.isMenuVisible()) { mPipMenuController.resizePipMenu(mLeash, tx, toBounds); } else { tx.apply(); @@ -1295,7 +1265,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceTransactionHelper .scale(tx, mLeash, startBounds, toBounds, degrees) .round(tx, mLeash, startBounds, toBounds); - if (shouldSyncPipTransactionWithMenu()) { + if (mPipMenuController.isMenuVisible()) { mPipMenuController.movePipMenu(mLeash, tx, toBounds); } else { tx.apply(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java index 27902b2231ba7..281ea530e9e13 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java @@ -305,18 +305,6 @@ public class PhonePipMenuController implements PipMenuController { showResizeHandle); } - @Override - public void runWithNextFrame(Runnable runnable) { - if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) { - runnable.run(); - } - - mPipMenuView.getViewRootImpl().registerRtFrameCallback(frame -> { - mMainHandler.post(runnable); - }); - mPipMenuView.invalidate(); - } - /** * Move the PiP menu, which does a translation and possibly a scale transformation. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java index 7d4b43be4f731..4ce45e142c643 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java @@ -465,18 +465,6 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis return mSystemWindows.getViewSurface(v); } - @Override - public void runWithNextFrame(Runnable runnable) { - if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) { - runnable.run(); - } - - mPipMenuView.getViewRootImpl().registerRtFrameCallback(frame -> { - mMainHandler.post(runnable); - }); - mPipMenuView.invalidate(); - } - @Override public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction transaction, Rect pipDestBounds) { From cbc06e5ac96f1aec5c5da47e59f8da47915547b3 Mon Sep 17 00:00:00 2001 From: Alex Florescu Date: Mon, 12 Dec 2022 10:46:36 +0000 Subject: [PATCH 06/23] Revert "[Bouncer] refine entry for bouncer user switcher." This reverts commit 66430ca2921f899df7fcb6e47da7caec6c809b00. Reason for revert: b/261941458 Change-Id: Id77e5e37c2d6117d54dbbf17d1f4a6b5c0cffd48 (cherry picked from commit 4da665d4a4123ca2a90b22cbdd9041df1934c521) Merged-In: Id77e5e37c2d6117d54dbbf17d1f4a6b5c0cffd48 --- .../KeyguardAbsKeyInputViewController.java | 3 +- .../keyguard/KeyguardInputViewController.java | 4 +- .../com/android/keyguard/KeyguardPINView.java | 3 +- .../keyguard/KeyguardSecurityContainer.java | 25 +-- ...KeyguardAbsKeyInputViewControllerTest.java | 20 --- .../KeyguardPasswordViewControllerTest.kt | 163 ++++++++++-------- .../KeyguardPatternViewControllerTest.kt | 130 +++++++------- .../keyguard/KeyguardPinViewControllerTest.kt | 10 +- 8 files changed, 166 insertions(+), 192 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index 7da27b1d68983..860c8e3a9f77d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -260,8 +260,7 @@ public abstract class KeyguardAbsKeyInputViewController public void startAppearAnimation() { if (TextUtils.isEmpty(mMessageAreaController.getMessage())) { - mMessageAreaController.setMessage( - mView.getResources().getString(getInitialMessageResId()), - /* animate= */ false); + mMessageAreaController.setMessage(getInitialMessageResId()); } mView.startAppearAnimation(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java index 67e3400670ba9..5d86ccd5409ed 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java @@ -52,7 +52,6 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { private int mYTransOffset; private View mBouncerMessageView; @DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN; - public static final long ANIMATION_DURATION = 650; public KeyguardPINView(Context context) { this(context, null); @@ -182,7 +181,7 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { if (mAppearAnimator.isRunning()) { mAppearAnimator.cancel(); } - mAppearAnimator.setDuration(ANIMATION_DURATION); + mAppearAnimator.setDuration(650); mAppearAnimator.addUpdateListener(animation -> animate(animation.getAnimatedFraction())); mAppearAnimator.start(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 5d7a6f122e694..8f3484a0c99b8 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -36,11 +36,8 @@ import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY; import static java.lang.Integer.max; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.app.Activity; import android.app.AlertDialog; import android.app.admin.DevicePolicyManager; @@ -970,23 +967,11 @@ public class KeyguardSecurityContainer extends ConstraintLayout { } mUserSwitcherViewGroup.setAlpha(0f); - ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); - int yTrans = mView.getResources().getDimensionPixelSize(R.dimen.pin_view_trans_y_entry); - animator.setInterpolator(Interpolators.STANDARD_DECELERATE); - animator.setDuration(650); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mUserSwitcherViewGroup.setAlpha(1f); - mUserSwitcherViewGroup.setTranslationY(0f); - } - }); - animator.addUpdateListener(animation -> { - float value = (float) animation.getAnimatedValue(); - mUserSwitcherViewGroup.setAlpha(value); - mUserSwitcherViewGroup.setTranslationY(yTrans - yTrans * value); - }); - animator.start(); + ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mUserSwitcherViewGroup, View.ALPHA, + 1f); + alphaAnim.setInterpolator(Interpolators.ALPHA_IN); + alphaAnim.setDuration(500); + alphaAnim.start(); } @Override diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index 4903d31f89f46..8bbaf3dff1e50 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -19,7 +19,6 @@ package com.android.keyguard; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -88,7 +87,6 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { when(mAbsKeyInputView.isAttachedToWindow()).thenReturn(true); when(mAbsKeyInputView.requireViewById(R.id.bouncer_message_area)) .thenReturn(mKeyguardMessageArea); - when(mAbsKeyInputView.getResources()).thenReturn(getContext().getResources()); mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector, @@ -127,22 +125,4 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { verifyZeroInteractions(mKeyguardSecurityCallback); verifyZeroInteractions(mKeyguardMessageAreaController); } - - @Test - public void onPromptReasonNone_doesNotSetMessage() { - mKeyguardAbsKeyInputViewController.showPromptReason(0); - verify(mKeyguardMessageAreaController, never()).setMessage( - getContext().getResources().getString(R.string.kg_prompt_reason_restart_password), - false); - } - - @Test - public void onPromptReason_setsMessage() { - when(mAbsKeyInputView.getPromptReasonStringRes(1)).thenReturn( - R.string.kg_prompt_reason_restart_password); - mKeyguardAbsKeyInputViewController.showPromptReason(1); - verify(mKeyguardMessageAreaController).setMessage( - getContext().getResources().getString(R.string.kg_prompt_reason_restart_password), - false); - } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt index d912793993415..d20be56d6c6b3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt @@ -30,54 +30,64 @@ import com.android.systemui.util.concurrency.DelayableExecutor import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.Mockito +import org.mockito.Mockito.`when` import org.mockito.Mockito.never import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper class KeyguardPasswordViewControllerTest : SysuiTestCase() { - @Mock private lateinit var keyguardPasswordView: KeyguardPasswordView - @Mock private lateinit var passwordEntry: EditText - @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor - @Mock lateinit var securityMode: KeyguardSecurityModel.SecurityMode - @Mock lateinit var lockPatternUtils: LockPatternUtils - @Mock lateinit var keyguardSecurityCallback: KeyguardSecurityCallback - @Mock lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory - @Mock lateinit var latencyTracker: LatencyTracker - @Mock lateinit var inputMethodManager: InputMethodManager - @Mock lateinit var emergencyButtonController: EmergencyButtonController - @Mock lateinit var mainExecutor: DelayableExecutor - @Mock lateinit var falsingCollector: FalsingCollector - @Mock lateinit var keyguardViewController: KeyguardViewController - @Mock private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea - @Mock - private lateinit var mKeyguardMessageAreaController: - KeyguardMessageAreaController + @Mock + private lateinit var keyguardPasswordView: KeyguardPasswordView + @Mock + private lateinit var passwordEntry: EditText + @Mock + lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + @Mock + lateinit var securityMode: KeyguardSecurityModel.SecurityMode + @Mock + lateinit var lockPatternUtils: LockPatternUtils + @Mock + lateinit var keyguardSecurityCallback: KeyguardSecurityCallback + @Mock + lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory + @Mock + lateinit var latencyTracker: LatencyTracker + @Mock + lateinit var inputMethodManager: InputMethodManager + @Mock + lateinit var emergencyButtonController: EmergencyButtonController + @Mock + lateinit var mainExecutor: DelayableExecutor + @Mock + lateinit var falsingCollector: FalsingCollector + @Mock + lateinit var keyguardViewController: KeyguardViewController + @Mock + private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea + @Mock + private lateinit var mKeyguardMessageAreaController: + KeyguardMessageAreaController - private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController + private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController - @Before - fun setup() { - MockitoAnnotations.initMocks(this) - Mockito.`when`( - keyguardPasswordView.requireViewById( - R.id.bouncer_message_area)) - .thenReturn(mKeyguardMessageArea) - Mockito.`when`(messageAreaControllerFactory.create(mKeyguardMessageArea)) - .thenReturn(mKeyguardMessageAreaController) - Mockito.`when`(keyguardPasswordView.passwordTextViewId).thenReturn(R.id.passwordEntry) - Mockito.`when`(keyguardPasswordView.findViewById(R.id.passwordEntry)) - .thenReturn(passwordEntry) - `when`(keyguardPasswordView.resources).thenReturn(context.resources) - keyguardPasswordViewController = - KeyguardPasswordViewController( + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + Mockito.`when`( + keyguardPasswordView + .requireViewById(R.id.bouncer_message_area) + ).thenReturn(mKeyguardMessageArea) + Mockito.`when`(messageAreaControllerFactory.create(mKeyguardMessageArea)) + .thenReturn(mKeyguardMessageAreaController) + Mockito.`when`(keyguardPasswordView.passwordTextViewId).thenReturn(R.id.passwordEntry) + Mockito.`when`(keyguardPasswordView.findViewById(R.id.passwordEntry) + ).thenReturn(passwordEntry) + keyguardPasswordViewController = KeyguardPasswordViewController( keyguardPasswordView, keyguardUpdateMonitor, securityMode, @@ -90,48 +100,51 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { mainExecutor, mContext.resources, falsingCollector, - keyguardViewController) - } - - @Test - fun testFocusWhenBouncerIsShown() { - Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(true) - Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true) - keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED) - keyguardPasswordView.post { - verify(keyguardPasswordView).requestFocus() - verify(keyguardPasswordView).showKeyboard() + keyguardViewController + ) } - } - @Test - fun testDoNotFocusWhenBouncerIsHidden() { - Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(false) - Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true) - keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED) - verify(keyguardPasswordView, never()).requestFocus() - } - - @Test - fun testHideKeyboardWhenOnPause() { - keyguardPasswordViewController.onPause() - keyguardPasswordView.post { - verify(keyguardPasswordView).clearFocus() - verify(keyguardPasswordView).hideKeyboard() + @Test + fun testFocusWhenBouncerIsShown() { + Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(true) + Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true) + keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED) + keyguardPasswordView.post { + verify(keyguardPasswordView).requestFocus() + verify(keyguardPasswordView).showKeyboard() + } } - } - @Test - fun startAppearAnimation() { - keyguardPasswordViewController.startAppearAnimation() - verify(mKeyguardMessageAreaController) - .setMessage(context.resources.getString(R.string.keyguard_enter_your_password), false) - } + @Test + fun testDoNotFocusWhenBouncerIsHidden() { + Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(false) + Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true) + keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED) + verify(keyguardPasswordView, never()).requestFocus() + } - @Test - fun startAppearAnimation_withExistingMessage() { - `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.") - keyguardPasswordViewController.startAppearAnimation() - verify(mKeyguardMessageAreaController, never()).setMessage(anyString(), anyBoolean()) - } + @Test + fun testHideKeyboardWhenOnPause() { + keyguardPasswordViewController.onPause() + keyguardPasswordView.post { + verify(keyguardPasswordView).clearFocus() + verify(keyguardPasswordView).hideKeyboard() + } + } + + @Test + fun startAppearAnimation() { + keyguardPasswordViewController.startAppearAnimation() + verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_password) + } + + @Test + fun startAppearAnimation_withExistingMessage() { + `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.") + keyguardPasswordViewController.startAppearAnimation() + verify( + mKeyguardMessageAreaController, + never() + ).setMessage(R.string.keyguard_enter_your_password) + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index 85dbdb8330a3f..b3d1c8f909d8b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -30,93 +30,97 @@ import com.android.systemui.statusbar.policy.DevicePostureController import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock -import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` +import org.mockito.Mockito.never import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper class KeyguardPatternViewControllerTest : SysuiTestCase() { - @Mock private lateinit var mKeyguardPatternView: KeyguardPatternView + @Mock + private lateinit var mKeyguardPatternView: KeyguardPatternView - @Mock private lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor + @Mock + private lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor - @Mock private lateinit var mSecurityMode: KeyguardSecurityModel.SecurityMode + @Mock + private lateinit var mSecurityMode: KeyguardSecurityModel.SecurityMode - @Mock private lateinit var mLockPatternUtils: LockPatternUtils + @Mock + private lateinit var mLockPatternUtils: LockPatternUtils - @Mock private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback + @Mock + private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback - @Mock private lateinit var mLatencyTracker: LatencyTracker - private var mFalsingCollector: FalsingCollector = FalsingCollectorFake() + @Mock + private lateinit var mLatencyTracker: LatencyTracker + private var mFalsingCollector: FalsingCollector = FalsingCollectorFake() - @Mock private lateinit var mEmergencyButtonController: EmergencyButtonController + @Mock + private lateinit var mEmergencyButtonController: EmergencyButtonController - @Mock - private lateinit var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory + @Mock + private lateinit + var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory - @Mock private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea + @Mock + private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea - @Mock - private lateinit var mKeyguardMessageAreaController: - KeyguardMessageAreaController + @Mock + private lateinit var mKeyguardMessageAreaController: + KeyguardMessageAreaController - @Mock private lateinit var mLockPatternView: LockPatternView + @Mock + private lateinit var mLockPatternView: LockPatternView - @Mock private lateinit var mPostureController: DevicePostureController + @Mock + private lateinit var mPostureController: DevicePostureController - private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController + private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController - @Before - fun setup() { - MockitoAnnotations.initMocks(this) - `when`(mKeyguardPatternView.isAttachedToWindow).thenReturn(true) - `when`( - mKeyguardPatternView.requireViewById( - R.id.bouncer_message_area)) - .thenReturn(mKeyguardMessageArea) - `when`(mKeyguardPatternView.findViewById(R.id.lockPatternView)) - .thenReturn(mLockPatternView) - `when`(mKeyguardMessageAreaControllerFactory.create(mKeyguardMessageArea)) - .thenReturn(mKeyguardMessageAreaController) - `when`(mKeyguardPatternView.resources).thenReturn(context.resources) - mKeyguardPatternViewController = - KeyguardPatternViewController( + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + `when`(mKeyguardPatternView.isAttachedToWindow).thenReturn(true) + `when`(mKeyguardPatternView + .requireViewById(R.id.bouncer_message_area)) + .thenReturn(mKeyguardMessageArea) + `when`(mKeyguardPatternView.findViewById(R.id.lockPatternView)) + .thenReturn(mLockPatternView) + `when`(mKeyguardMessageAreaControllerFactory.create(mKeyguardMessageArea)) + .thenReturn(mKeyguardMessageAreaController) + mKeyguardPatternViewController = KeyguardPatternViewController( mKeyguardPatternView, - mKeyguardUpdateMonitor, - mSecurityMode, - mLockPatternUtils, - mKeyguardSecurityCallback, - mLatencyTracker, - mFalsingCollector, - mEmergencyButtonController, - mKeyguardMessageAreaControllerFactory, - mPostureController) - } + mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, + mLatencyTracker, mFalsingCollector, mEmergencyButtonController, + mKeyguardMessageAreaControllerFactory, mPostureController + ) + } - @Test - fun onPause_resetsText() { - mKeyguardPatternViewController.init() - mKeyguardPatternViewController.onPause() - verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern) - } + @Test + fun onPause_resetsText() { + mKeyguardPatternViewController.init() + mKeyguardPatternViewController.onPause() + verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern) + } - @Test - fun startAppearAnimation() { - mKeyguardPatternViewController.startAppearAnimation() - verify(mKeyguardMessageAreaController) - .setMessage(context.resources.getString(R.string.keyguard_enter_your_pattern), false) - } - @Test - fun startAppearAnimation_withExistingMessage() { - `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.") - mKeyguardPatternViewController.startAppearAnimation() - verify(mKeyguardMessageAreaController, never()).setMessage(anyString(), anyBoolean()) - } + @Test + fun startAppearAnimation() { + mKeyguardPatternViewController.startAppearAnimation() + verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern) + } + + @Test + fun startAppearAnimation_withExistingMessage() { + `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.") + mKeyguardPatternViewController.startAppearAnimation() + verify( + mKeyguardMessageAreaController, + never() + ).setMessage(R.string.keyguard_enter_your_password) + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt index cdb7bbb9f8233..8bcfe6f2b6f51 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt @@ -31,13 +31,10 @@ import com.android.systemui.statusbar.policy.DevicePostureController import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.any import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @@ -82,7 +79,6 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { keyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea::class.java)) ) .thenReturn(keyguardMessageAreaController) - `when`(keyguardPinView.resources).thenReturn(context.resources) pinViewController = KeyguardPinViewController( keyguardPinView, @@ -102,14 +98,14 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { @Test fun startAppearAnimation() { pinViewController.startAppearAnimation() - verify(keyguardMessageAreaController) - .setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false) + verify(keyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pin) } @Test fun startAppearAnimation_withExistingMessage() { Mockito.`when`(keyguardMessageAreaController.message).thenReturn("Unlock to continue.") pinViewController.startAppearAnimation() - verify(keyguardMessageAreaController, Mockito.never()).setMessage(anyString(), anyBoolean()) + verify(keyguardMessageAreaController, Mockito.never()) + .setMessage(R.string.keyguard_enter_your_password) } } From cf642348b49138ac3faf1fbeb13bb76020fae6c9 Mon Sep 17 00:00:00 2001 From: Daniel Chapin Date: Mon, 19 Dec 2022 21:41:06 +0000 Subject: [PATCH 07/23] Revert "[Bouncer] Do not send message if face auth..." This reverts commit 4dd99003610583b110496321fcf092ddd78f0531. Reason for revert: Droidfood blocking bug: 263067487 Change-Id: I5abc143b8f912c39e1224524d98d5c6621ac0d36 (cherry picked from commit a88e7e7709b94734a1fb7e94a3958cc141738214) Merged-In: I5abc143b8f912c39e1224524d98d5c6621ac0d36 --- .../KeyguardAbsKeyInputViewController.java | 1 - .../keyguard/KeyguardInputViewController.java | 1 - .../ui/binder/KeyguardBouncerViewBinder.kt | 8 ++++++++ .../ui/viewmodel/KeyguardBouncerViewModel.kt | 6 ++++++ .../statusbar/KeyguardIndicationController.java | 3 +-- .../KeyguardAbsKeyInputViewControllerTest.java | 6 ------ .../KeyguardIndicationControllerTest.java | 16 ---------------- 7 files changed, 15 insertions(+), 26 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index baaef1983e9cf..7da27b1d68983 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -103,7 +103,6 @@ public abstract class KeyguardAbsKeyInputViewController @Override public void reset() { - mMessageAreaController.setMessage("", false); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt index 3d5985c5c7aaf..f772b17a7fb6f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt @@ -104,6 +104,14 @@ object KeyguardBouncerViewBinder { } } + launch { + viewModel.showWithFullExpansion.collect { model -> + hostViewController.resetSecurityContainer() + hostViewController.showPromptReason(model.promptReason) + hostViewController.onResume() + } + } + launch { viewModel.hide.collect { hostViewController.cancelDismissAction() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt index 737c35d866c28..e5d4e4971baaf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt @@ -22,8 +22,10 @@ import com.android.systemui.keyguard.data.BouncerViewDelegate import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel +import com.android.systemui.statusbar.phone.KeyguardBouncer.EXPANSION_VISIBLE import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map /** Models UI state for the lock screen bouncer; handles user input. */ @@ -42,6 +44,10 @@ constructor( /** Observe whether bouncer is showing. */ val show: Flow = interactor.show + /** Observe visible expansion when bouncer is showing. */ + val showWithFullExpansion: Flow = + interactor.show.filter { it.expansionAmount == EXPANSION_VISIBLE } + /** Observe whether bouncer is hiding. */ val hide: Flow = interactor.hide diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 770a23604b00d..b7001e476dcf1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -930,8 +930,7 @@ public class KeyguardIndicationController { if (mStatusBarKeyguardViewManager.isBouncerShowing()) { if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) { return; // udfps affordance is highlighted, no need to show action to unlock - } else if (!mKeyguardUpdateMonitor.getIsFaceAuthenticated() - && mKeyguardUpdateMonitor.isFaceEnrolled()) { + } else if (mKeyguardUpdateMonitor.isFaceEnrolled()) { String message = mContext.getString(R.string.keyguard_retry); mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index fa9bab28d5d82..10595439200a3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -150,10 +150,4 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { getContext().getResources().getString(R.string.kg_prompt_reason_restart_password), false); } - - @Test - public void testReset() { - mKeyguardAbsKeyInputViewController.reset(); - verify(mKeyguardMessageAreaController).setMessage("", false); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java index 99b58a3a30fec..8d96932f0051f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -660,7 +660,6 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { createController(); String message = mContext.getString(R.string.keyguard_retry); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true); - when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(false); when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true); mController.setVisible(true); @@ -670,21 +669,6 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { verify(mStatusBarKeyguardViewManager).setKeyguardMessage(eq(message), any()); } - @Test - public void transientIndication_swipeUpToRetry_faceAuthenticated() { - createController(); - String message = mContext.getString(R.string.keyguard_retry); - when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true); - when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true); - when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true); - - mController.setVisible(true); - mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT, - "A message", BiometricSourceType.FACE); - - verify(mStatusBarKeyguardViewManager, never()).setKeyguardMessage(eq(message), any()); - } - @Test public void faceErrorTimeout_whenFingerprintEnrolled_doesNotShowMessage() { createController(); From 913f03e49dacd125b10c252c5eaa2ab9e15dd147 Mon Sep 17 00:00:00 2001 From: Daniel Chapin Date: Mon, 19 Dec 2022 21:41:06 +0000 Subject: [PATCH 08/23] Revert "[Bouncer] Do not send message if face auth..." This reverts commit 4dd99003610583b110496321fcf092ddd78f0531. Reason for revert: Droidfood blocking bug: 263067487 Change-Id: I5abc143b8f912c39e1224524d98d5c6621ac0d36 (cherry picked from commit a88e7e7709b94734a1fb7e94a3958cc141738214) Merged-In: I5abc143b8f912c39e1224524d98d5c6621ac0d36 --- .../KeyguardAbsKeyInputViewController.java | 1 - .../keyguard/KeyguardInputViewController.java | 1 - .../ui/binder/KeyguardBouncerViewBinder.kt | 8 ++++++++ .../ui/viewmodel/KeyguardBouncerViewModel.kt | 6 ++++++ .../statusbar/KeyguardIndicationController.java | 3 +-- .../KeyguardAbsKeyInputViewControllerTest.java | 6 ------ .../KeyguardIndicationControllerTest.java | 16 ---------------- 7 files changed, 15 insertions(+), 26 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index baaef1983e9cf..7da27b1d68983 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -103,7 +103,6 @@ public abstract class KeyguardAbsKeyInputViewController @Override public void reset() { - mMessageAreaController.setMessage("", false); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt index 3d5985c5c7aaf..f772b17a7fb6f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt @@ -104,6 +104,14 @@ object KeyguardBouncerViewBinder { } } + launch { + viewModel.showWithFullExpansion.collect { model -> + hostViewController.resetSecurityContainer() + hostViewController.showPromptReason(model.promptReason) + hostViewController.onResume() + } + } + launch { viewModel.hide.collect { hostViewController.cancelDismissAction() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt index 737c35d866c28..e5d4e4971baaf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt @@ -22,8 +22,10 @@ import com.android.systemui.keyguard.data.BouncerViewDelegate import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel +import com.android.systemui.statusbar.phone.KeyguardBouncer.EXPANSION_VISIBLE import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map /** Models UI state for the lock screen bouncer; handles user input. */ @@ -42,6 +44,10 @@ constructor( /** Observe whether bouncer is showing. */ val show: Flow = interactor.show + /** Observe visible expansion when bouncer is showing. */ + val showWithFullExpansion: Flow = + interactor.show.filter { it.expansionAmount == EXPANSION_VISIBLE } + /** Observe whether bouncer is hiding. */ val hide: Flow = interactor.hide diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 770a23604b00d..b7001e476dcf1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -930,8 +930,7 @@ public class KeyguardIndicationController { if (mStatusBarKeyguardViewManager.isBouncerShowing()) { if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) { return; // udfps affordance is highlighted, no need to show action to unlock - } else if (!mKeyguardUpdateMonitor.getIsFaceAuthenticated() - && mKeyguardUpdateMonitor.isFaceEnrolled()) { + } else if (mKeyguardUpdateMonitor.isFaceEnrolled()) { String message = mContext.getString(R.string.keyguard_retry); mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index fa9bab28d5d82..10595439200a3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -150,10 +150,4 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { getContext().getResources().getString(R.string.kg_prompt_reason_restart_password), false); } - - @Test - public void testReset() { - mKeyguardAbsKeyInputViewController.reset(); - verify(mKeyguardMessageAreaController).setMessage("", false); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java index 99b58a3a30fec..8d96932f0051f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -660,7 +660,6 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { createController(); String message = mContext.getString(R.string.keyguard_retry); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true); - when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(false); when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true); mController.setVisible(true); @@ -670,21 +669,6 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { verify(mStatusBarKeyguardViewManager).setKeyguardMessage(eq(message), any()); } - @Test - public void transientIndication_swipeUpToRetry_faceAuthenticated() { - createController(); - String message = mContext.getString(R.string.keyguard_retry); - when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true); - when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true); - when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true); - - mController.setVisible(true); - mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT, - "A message", BiometricSourceType.FACE); - - verify(mStatusBarKeyguardViewManager, never()).setKeyguardMessage(eq(message), any()); - } - @Test public void faceErrorTimeout_whenFingerprintEnrolled_doesNotShowMessage() { createController(); From 4b104cf0f669bf3a1e415383e02e7986f9629c11 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 15 Dec 2022 20:40:32 +0000 Subject: [PATCH 09/23] Revert "Implement a global maximum on number of shortcuts an app can publish" This reverts commit fa4b2dc6d8f75b84e398ef2db8134ce51fc80001. Reason for revert: bugs related to conversation shortcuts can lead to system retaining shortcuts exceeding this number, causing crashes in chat apps such as whatsapp, messages ... e.t.c Change-Id: If485dc29e4f906d2ce5ec6836b3c4c47b5f21e23 (cherry picked from commit 6ed5fbe8c664278bf3b007a4b67594fdba71c324) Merged-In: If485dc29e4f906d2ce5ec6836b3c4c47b5f21e23 --- .../android/server/pm/ShortcutPackage.java | 8 +-- .../android/server/pm/ShortcutService.java | 49 +++---------------- 2 files changed, 8 insertions(+), 49 deletions(-) diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index fa6f4eedce7c7..890c89152a7ce 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -1470,15 +1470,9 @@ class ShortcutPackage extends ShortcutPackageItem { } // Then make sure none of the activities have more than the max number of shortcuts. - int total = 0; for (int i = counts.size() - 1; i >= 0; i--) { - int count = counts.valueAt(i); - service.enforceMaxActivityShortcuts(count); - total += count; + service.enforceMaxActivityShortcuts(counts.valueAt(i)); } - - // Finally make sure that the app doesn't have more than the max number of shortcuts. - service.enforceMaxAppShortcuts(total); } /** diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 014a77b57446c..0b20683185f01 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -180,9 +180,6 @@ public class ShortcutService extends IShortcutService.Stub { @VisibleForTesting static final int DEFAULT_MAX_SHORTCUTS_PER_ACTIVITY = 15; - @VisibleForTesting - static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 60; - @VisibleForTesting static final int DEFAULT_MAX_ICON_DIMENSION_DP = 96; @@ -259,11 +256,6 @@ public class ShortcutService extends IShortcutService.Stub { */ String KEY_MAX_SHORTCUTS = "max_shortcuts"; - /** - * Key name for the max dynamic shortcuts per app. (int) - */ - String KEY_MAX_SHORTCUTS_PER_APP = "max_shortcuts_per_app"; - /** * Key name for icon compression quality, 0-100. */ @@ -336,15 +328,10 @@ public class ShortcutService extends IShortcutService.Stub { private final SparseArray mShortcutNonPersistentUsers = new SparseArray<>(); - /** - * Max number of dynamic + manifest shortcuts that each activity can have at a time. - */ - private int mMaxShortcutsPerActivity; - /** * Max number of dynamic + manifest shortcuts that each application can have at a time. */ - private int mMaxShortcutsPerApp; + private int mMaxShortcuts; /** * Max number of updating API calls that each application can make during the interval. @@ -817,12 +804,9 @@ public class ShortcutService extends IShortcutService.Stub { mMaxUpdatesPerInterval = Math.max(0, (int) parser.getLong( ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL, DEFAULT_MAX_UPDATES_PER_INTERVAL)); - mMaxShortcutsPerActivity = Math.max(0, (int) parser.getLong( + mMaxShortcuts = Math.max(0, (int) parser.getLong( ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_ACTIVITY)); - mMaxShortcutsPerApp = Math.max(0, (int) parser.getLong( - ConfigConstants.KEY_MAX_SHORTCUTS_PER_APP, DEFAULT_MAX_SHORTCUTS_PER_APP)); - final int iconDimensionDp = Math.max(1, injectIsLowRamDevice() ? (int) parser.getLong( ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM, @@ -1762,33 +1746,16 @@ public class ShortcutService extends IShortcutService.Stub { * {@link #getMaxActivityShortcuts()}. */ void enforceMaxActivityShortcuts(int numShortcuts) { - if (numShortcuts > mMaxShortcutsPerActivity) { + if (numShortcuts > mMaxShortcuts) { throw new IllegalArgumentException("Max number of dynamic shortcuts exceeded"); } } - /** - * @throws IllegalArgumentException if {@code numShortcuts} is bigger than - * {@link #getMaxAppShortcuts()}. - */ - void enforceMaxAppShortcuts(int numShortcuts) { - if (numShortcuts > mMaxShortcutsPerApp) { - throw new IllegalArgumentException("Max number of dynamic shortcuts per app exceeded"); - } - } - /** * Return the max number of dynamic + manifest shortcuts for each launcher icon. */ int getMaxActivityShortcuts() { - return mMaxShortcutsPerActivity; - } - - /** - * Return the max number of dynamic + manifest shortcuts for each launcher icon. - */ - int getMaxAppShortcuts() { - return mMaxShortcutsPerApp; + return mMaxShortcuts; } /** @@ -2221,8 +2188,6 @@ public class ShortcutService extends IShortcutService.Stub { ps.ensureNotImmutable(shortcut.getId(), /*ignoreInvisible=*/ true); fillInDefaultActivity(Arrays.asList(shortcut)); - enforceMaxAppShortcuts(ps.getShortcutCount()); - if (!shortcut.hasRank()) { shortcut.setRank(0); } @@ -2610,7 +2575,7 @@ public class ShortcutService extends IShortcutService.Stub { throws RemoteException { verifyCaller(packageName, userId); - return mMaxShortcutsPerActivity; + return mMaxShortcuts; } @Override @@ -4758,7 +4723,7 @@ public class ShortcutService extends IShortcutService.Stub { pw.print(" maxUpdatesPerInterval: "); pw.println(mMaxUpdatesPerInterval); pw.print(" maxShortcutsPerActivity: "); - pw.println(mMaxShortcutsPerActivity); + pw.println(mMaxShortcuts); pw.println(); mStatLogger.dump(pw, " "); @@ -5245,7 +5210,7 @@ public class ShortcutService extends IShortcutService.Stub { @VisibleForTesting int getMaxShortcutsForTest() { - return mMaxShortcutsPerActivity; + return mMaxShortcuts; } @VisibleForTesting From 3c90e2ea398c31ad67ff2d883071804de5fe46bd Mon Sep 17 00:00:00 2001 From: Nicolo' Mazzucato Date: Mon, 9 Jan 2023 08:04:05 +0000 Subject: [PATCH 10/23] Fix DisplayManager race condition when state is unknown The race was happening when: 1. STATE_UNKNOWN arrives to PhotonicModulator#setState. 2. Inside PhotonicModulator#setState, mStateChangeInprogress is set to true, and the setState method finishes. 3. in the run loop, in one iteration, we reach mLock.wait() (with mStateChangeInprogress still set to true, as the state changed from something to unknown). Now, setState can be executed again as the lock is not held anymore. 4. A new PhotonicModulator#setState arrives. however, mStateChangeInProgress is true, so mLock.notifyAll() is not called anymore. It was previously fixed by I903f6392cbe42031aab8ffdbfbe541463d6b5e01 making the display not going to UNKNOWN state anymore, but this cl fixes the general case and revert the changes to set the display to off in `onDisplayChanged`. Bug: 262294651 Test: Running foldable test suite for 20 times with abtd: before the fix it had high flakiness, after it had 0% flakiness. There are no tests for DisplayPowerState currently. Change-Id: I165b260d60e03c8e4707c7704847c77a225fd43d (cherry picked from commit e4fccc2d9fd7382dacb4a546858eca93127c4c50) Merged-In: I165b260d60e03c8e4707c7704847c77a225fd43d --- .../server/display/DisplayPowerController.java | 6 +++--- .../server/display/DisplayPowerState.java | 16 +++++----------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index d6e78a195be4a..f88a3372a4ac5 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -817,9 +817,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mDisplayDeviceConfig = config; loadFromDisplayDeviceConfig(token, info); - // Since the underlying display-device changed, we really don't know the - // last command that was sent to change it's state. Lets assume it is off and we - // trigger a change immediately. + /// Since the underlying display-device changed, we really don't know the + // last command that was sent to change it's state. Lets assume it is unknown so + // that we trigger a change immediately. mPowerState.resetScreenState(); } if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) { diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java index 7d1396d7e413c..2c257a17af916 100644 --- a/services/core/java/com/android/server/display/DisplayPowerState.java +++ b/services/core/java/com/android/server/display/DisplayPowerState.java @@ -340,20 +340,12 @@ final class DisplayPowerState { } /** - * Resets the screen state to {@link Display#STATE_OFF}. Even though we do not know the last - * state that was sent to the underlying display-device, we assume it is off. - * - * We do not set the screen state to {@link Display#STATE_UNKNOWN} to avoid getting in the state - * where PhotonicModulator holds onto the lock. This happens because we currently try to keep - * the mScreenState and mPendingState in sync, however if the screenState is set to - * {@link Display#STATE_UNKNOWN} here, mPendingState will get progressed to this, which will - * force the PhotonicModulator thread to wait onto the lock to take it out of that state. - * b/262294651 for more info. + * Resets the screen state to unknown. Useful when the underlying display-device changes for the + * LogicalDisplay and we do not know the last state that was sent to it. */ void resetScreenState() { - mScreenState = Display.STATE_OFF; + mScreenState = Display.STATE_UNKNOWN; mScreenReady = false; - scheduleScreenUpdate(); } private void scheduleScreenUpdate() { @@ -514,6 +506,8 @@ final class DisplayPowerState { boolean valid = state != Display.STATE_UNKNOWN && !Float.isNaN(brightnessState); boolean changed = stateChanged || backlightChanged; if (!valid || !changed) { + mStateChangeInProgress = false; + mBacklightChangeInProgress = false; try { mLock.wait(); } catch (InterruptedException ex) { From d23ffc2bb9bc554dbc8260de6968fb28eeceb593 Mon Sep 17 00:00:00 2001 From: omarmt Date: Mon, 9 Jan 2023 15:13:15 +0000 Subject: [PATCH 11/23] NotificationChildrenContainer apply the roundness on NotificationHeaderViewWrapper too Test: atest NotificationChildrenContainerTest Test: Checking the roundness behavior by disabling the parent (ExpandableNotificationRow) clipping: I override childNeedsClipping() and if (child == mChildrenContainer) return false Bug: 263822538 Change-Id: I6b08703c4fcf86ca0e939e8adf640053a297f9ca (cherry picked from commit f3895a1d3a308877e5b2dbae8181d8bc2c9a9cc3) Merged-In: I6b08703c4fcf86ca0e939e8adf640053a297f9ca --- .../stack/NotificationChildrenContainer.java | 16 ++++++++++++ .../NotificationChildrenContainerTest.java | 26 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 8d48d738f0f2e..9b93d7b9e1d0e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -1431,6 +1431,22 @@ public class NotificationChildrenContainer extends ViewGroup @Override public void applyRoundnessAndInvalidate() { boolean last = true; + if (mUseRoundnessSourceTypes) { + if (mNotificationHeaderWrapper != null) { + mNotificationHeaderWrapper.requestTopRoundness( + /* value = */ getTopRoundness(), + /* sourceType = */ FROM_PARENT, + /* animate = */ false + ); + } + if (mNotificationHeaderWrapperLowPriority != null) { + mNotificationHeaderWrapperLowPriority.requestTopRoundness( + /* value = */ getTopRoundness(), + /* sourceType = */ FROM_PARENT, + /* animate = */ false + ); + } + } for (int i = mAttachedChildren.size() - 1; i >= 0; i--) { ExpandableNotificationRow child = mAttachedChildren.get(i); if (child.getVisibility() == View.GONE) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java index ca99e24fc105a..e41929f7d5789 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java @@ -29,6 +29,7 @@ import com.android.systemui.statusbar.notification.LegacySourceType; import com.android.systemui.statusbar.notification.SourceType; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; +import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper; import org.junit.Assert; import org.junit.Before; @@ -216,4 +217,29 @@ public class NotificationChildrenContainerTest extends SysuiTestCase { Assert.assertEquals(1f, mChildrenContainer.getBottomRoundness(), 0.001f); Assert.assertEquals(1f, notificationRow.getBottomRoundness(), 0.001f); } + + @Test + public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_header() { + mChildrenContainer.useRoundnessSourceTypes(true); + + NotificationHeaderViewWrapper header = mChildrenContainer.getNotificationHeaderWrapper(); + Assert.assertEquals(0f, header.getTopRoundness(), 0.001f); + + mChildrenContainer.requestTopRoundness(1f, SourceType.from(""), false); + + Assert.assertEquals(1f, header.getTopRoundness(), 0.001f); + } + + @Test + public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_headerLowPriority() { + mChildrenContainer.useRoundnessSourceTypes(true); + mChildrenContainer.setIsLowPriority(true); + + NotificationHeaderViewWrapper header = mChildrenContainer.getNotificationHeaderWrapper(); + Assert.assertEquals(0f, header.getTopRoundness(), 0.001f); + + mChildrenContainer.requestTopRoundness(1f, SourceType.from(""), false); + + Assert.assertEquals(1f, header.getTopRoundness(), 0.001f); + } } From 835d37a84b4d467729e18ce26c2527ac18e349b0 Mon Sep 17 00:00:00 2001 From: Fabian Kozynski Date: Wed, 4 Jan 2023 14:52:07 -0500 Subject: [PATCH 12/23] Make the header INVISIBLE when alpha is 0 That way, clicks are not relayed to children. Also, make the Reset menu item surface as action if it fits, for better discoverability. Test: manual Test: atest LargeScreenShadeHeaderControllerTest Fixes: 255708561 Change-Id: I853736f48ea97560f4b9ff438832d1372e0c59cc (cherry picked from commit 6d4e7a81629afc17874c7e84e20f74c1470e2066) (cherry picked from commit 1070f0f01184653a9247e3ba401aa5672c11ad84) Merged-In: I853736f48ea97560f4b9ff438832d1372e0c59cc --- .../systemui/qs/customize/QSCustomizer.java | 5 +- .../shade/LargeScreenShadeHeaderController.kt | 8 ++- ...ScreenShadeHeaderControllerCombinedTest.kt | 1 + .../LargeScreenShadeHeaderControllerTest.kt | 54 +++++++++++++++++++ 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index 79fcc7d813721..17124901e4de2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -24,6 +24,7 @@ import android.util.AttributeSet; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.widget.LinearLayout; import android.widget.Toolbar; @@ -74,8 +75,8 @@ public class QSCustomizer extends LinearLayout { toolbar.setNavigationIcon( getResources().getDrawable(value.resourceId, mContext.getTheme())); - toolbar.getMenu().add(Menu.NONE, MENU_RESET, 0, - mContext.getString(com.android.internal.R.string.reset)); + toolbar.getMenu().add(Menu.NONE, MENU_RESET, 0, com.android.internal.R.string.reset) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); toolbar.setTitle(R.string.qs_edit); mRecyclerView = findViewById(android.R.id.list); mTransparentView = findViewById(R.id.customizer_transparent_view); diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt index 7fc0a5f6d4bf3..e406be1ea0a3d 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt @@ -175,9 +175,10 @@ class LargeScreenShadeHeaderController @Inject constructor( */ var shadeExpandedFraction = -1f set(value) { - if (visible && field != value) { + if (field != value) { header.alpha = ShadeInterpolation.getContentAlpha(value) field = value + updateVisibility() } } @@ -331,6 +332,9 @@ class LargeScreenShadeHeaderController @Inject constructor( .setDuration(duration) .alpha(if (show) 0f else 1f) .setInterpolator(if (show) Interpolators.ALPHA_OUT else Interpolators.ALPHA_IN) + .setUpdateListener { + updateVisibility() + } .start() } @@ -414,7 +418,7 @@ class LargeScreenShadeHeaderController @Inject constructor( private fun updateVisibility() { val visibility = if (!largeScreenActive && !combinedHeaders || qsDisabled) { View.GONE - } else if (qsVisible) { + } else if (qsVisible && header.alpha > 0f) { View.VISIBLE } else { View.INVISIBLE diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt index 1d30ad9293a04..f580f5e00f678 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt @@ -182,6 +182,7 @@ class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() { null } whenever(view.visibility).thenAnswer { _ -> viewVisibility } + whenever(view.alpha).thenReturn(1f) whenever(iconManagerFactory.create(any(), any())).thenReturn(iconManager) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt index b4c8f981b7605..b568122d3fed0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt @@ -1,5 +1,6 @@ package com.android.systemui.shade +import android.animation.ValueAnimator import android.app.StatusBarManager import android.content.Context import android.testing.AndroidTestingRunner @@ -30,6 +31,7 @@ import com.android.systemui.statusbar.policy.VariableDateViewController import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before @@ -37,6 +39,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers +import org.mockito.ArgumentMatchers.anyFloat import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.mock @@ -75,6 +78,7 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() { @JvmField @Rule val mockitoRule = MockitoJUnit.rule() var viewVisibility = View.GONE + var viewAlpha = 1f private lateinit var mLargeScreenShadeHeaderController: LargeScreenShadeHeaderController private lateinit var carrierIconSlots: List @@ -101,6 +105,13 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() { null } whenever(view.visibility).thenAnswer { _ -> viewVisibility } + + whenever(view.setAlpha(anyFloat())).then { + viewAlpha = it.arguments[0] as Float + null + } + whenever(view.alpha).thenAnswer { _ -> viewAlpha } + whenever(variableDateViewControllerFactory.create(any())) .thenReturn(variableDateViewController) whenever(iconManagerFactory.create(any(), any())).thenReturn(iconManager) @@ -154,6 +165,16 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() { verify(view).setAlpha(ShadeInterpolation.getContentAlpha(0.5f)) } + @Test + fun alphaChangesUpdateVisibility() { + makeShadeVisible() + mLargeScreenShadeHeaderController.shadeExpandedFraction = 0f + assertThat(viewVisibility).isEqualTo(View.INVISIBLE) + + mLargeScreenShadeHeaderController.shadeExpandedFraction = 1f + assertThat(viewVisibility).isEqualTo(View.VISIBLE) + } + @Test fun singleCarrier_enablesCarrierIconsInStatusIcons() { whenever(qsCarrierGroupController.isSingleCarrier).thenReturn(true) @@ -238,6 +259,39 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() { verify(animator).start() } + @Test + fun testShadeExpanded_true_alpha_zero_invisible() { + view.alpha = 0f + mLargeScreenShadeHeaderController.largeScreenActive = true + mLargeScreenShadeHeaderController.qsVisible = true + + assertThat(viewVisibility).isEqualTo(View.INVISIBLE) + } + + @Test + fun animatorCallsUpdateVisibilityOnUpdate() { + val animator = mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF) + whenever(view.animate()).thenReturn(animator) + + mLargeScreenShadeHeaderController.startCustomizingAnimation(show = false, 0L) + + val updateCaptor = argumentCaptor() + verify(animator).setUpdateListener(capture(updateCaptor)) + + mLargeScreenShadeHeaderController.largeScreenActive = true + mLargeScreenShadeHeaderController.qsVisible = true + + view.alpha = 1f + updateCaptor.value.onAnimationUpdate(mock()) + + assertThat(viewVisibility).isEqualTo(View.VISIBLE) + + view.alpha = 0f + updateCaptor.value.onAnimationUpdate(mock()) + + assertThat(viewVisibility).isEqualTo(View.INVISIBLE) + } + @Test fun demoMode_attachDemoMode() { val cb = argumentCaptor() From 72f7918b1ba8971c28b346667593e9881e0953e6 Mon Sep 17 00:00:00 2001 From: Lyn Han Date: Tue, 10 Jan 2023 23:07:36 +0000 Subject: [PATCH 13/23] Revert "Add dumpsys logs to debug lockscreen stack height" This reverts commit a331639790fa2bd7b2669d20b3ecfd53970965e1. Reason for revert: minimize logging for qpr2 Bug: 265067133 Change-Id: Ife9918c947ff521c7b6fb808a4c8d3ce27a02d67 (cherry picked from commit 8e50c40b0563b9dda8bf6a5d66fa2922526feb16) Merged-In: Ife9918c947ff521c7b6fb808a4c8d3ce27a02d67 --- .../stack/NotificationStackScrollLayout.java | 1 - .../stack/NotificationStackSizeCalculator.kt | 32 ++++--------------- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index ca1e397f930a4..2f543254786f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -5193,7 +5193,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable println(pw, "intrinsicPadding", mIntrinsicPadding); println(pw, "topPadding", mTopPadding); println(pw, "bottomPadding", mBottomPadding); - mNotificationStackSizeCalculator.dump(pw, args); }); pw.println(); pw.println("Contents:"); 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 25f99c69d4543..ae854e2df91ae 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 @@ -30,7 +30,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView import com.android.systemui.util.Compile import com.android.systemui.util.children -import java.io.PrintWriter import javax.inject.Inject import kotlin.math.max import kotlin.math.min @@ -54,8 +53,6 @@ constructor( @Main private val resources: Resources ) { - private lateinit var lastComputeHeightLog : String - /** * Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow shelf. * If there are exactly 1 + mMaxKeyguardNotifications, and they fit in the available space @@ -117,9 +114,7 @@ constructor( shelfIntrinsicHeight: Float ): Int { log { "\n" } - - val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight, - /* computeHeight= */ false) + val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight) var maxNotifications = stackHeightSequence.lastIndexWhile { heightResult -> @@ -162,21 +157,18 @@ constructor( shelfIntrinsicHeight: Float ): Float { log { "\n" } - lastComputeHeightLog = "" val heightPerMaxNotifications = - computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight, - /* computeHeight= */ true) + computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight) val (notificationsHeight, shelfHeightWithSpaceBefore) = heightPerMaxNotifications.elementAtOrElse(maxNotifications) { heightPerMaxNotifications.last() // Height with all notifications visible. } - lastComputeHeightLog += "\ncomputeHeight(maxNotifications=$maxNotifications," + + log { + "computeHeight(maxNotifications=$maxNotifications," + "shelfIntrinsicHeight=$shelfIntrinsicHeight) -> " + "${notificationsHeight + shelfHeightWithSpaceBefore}" + " = ($notificationsHeight + $shelfHeightWithSpaceBefore)" - log { - lastComputeHeightLog } return notificationsHeight + shelfHeightWithSpaceBefore } @@ -192,8 +184,7 @@ constructor( private fun computeHeightPerNotificationLimit( stack: NotificationStackScrollLayout, - shelfHeight: Float, - computeHeight: Boolean + shelfHeight: Float ): Sequence = sequence { log { "computeHeightPerNotificationLimit" } @@ -222,14 +213,9 @@ constructor( currentIndex = firstViewInShelfIndex) spaceBeforeShelf + shelfHeight } - - val currentLog = "computeHeight | i=$i notificationsHeight=$notifications " + - "shelfHeightWithSpaceBefore=$shelfWithSpaceBefore" - if (computeHeight) { - lastComputeHeightLog += "\n" + currentLog - } log { - currentLog + "i=$i notificationsHeight=$notifications " + + "shelfHeightWithSpaceBefore=$shelfWithSpaceBefore" } yield( StackHeight( @@ -274,10 +260,6 @@ constructor( return size } - fun dump(pw: PrintWriter, args: Array) { - pw.println("NotificationStackSizeCalculator lastComputeHeightLog = $lastComputeHeightLog") - } - private fun ExpandableView.isShowable(onLockscreen: Boolean): Boolean { if (visibility == GONE || hasNoContentHeight()) return false if (onLockscreen) { From 2a7b7d08c2c7845a8e1c86caf8608b686ea9f533 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 11 Jan 2023 18:58:41 +0000 Subject: [PATCH 14/23] Revert "Ensure that only SysUI can override pending intent launch flags" This reverts commit c4d3106e347922610f8c554de3ae238175ed393e. Reason for revert: b/264884187, b/264885689 Change-Id: I9fb0d66327f3f872a92e6b9d682d58489e81e6ba (cherry picked from commit 7bb933f48ff15d8f08d2185005b7b3e212915276) Merged-In: I9fb0d66327f3f872a92e6b9d682d58489e81e6ba --- .../com/android/server/am/PendingIntentRecord.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index 8624ee031a936..bda60ff2172b3 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -379,16 +379,11 @@ public final class PendingIntentRecord extends IIntentSender.Stub { resolvedType = key.requestResolvedType; } - // Apply any launch flags from the ActivityOptions. This is used only by SystemUI - // to ensure that we can launch the pending intent with a consistent launch mode even - // if the provided PendingIntent is immutable (ie. to force an activity to launch into - // a new task, or to launch multiple instances if supported by the app) + // Apply any launch flags from the ActivityOptions. This is to ensure that the caller + // can specify a consistent launch mode even if the PendingIntent is immutable final ActivityOptions opts = ActivityOptions.fromBundle(options); if (opts != null) { - // TODO(b/254490217): Move this check into SafeActivityOptions - if (controller.mAtmInternal.isCallerRecents(Binder.getCallingUid())) { - finalIntent.addFlags(opts.getPendingIntentLaunchFlags()); - } + finalIntent.addFlags(opts.getPendingIntentLaunchFlags()); } // Extract options before clearing calling identity From d2b4515086d810fb2928fbc9c805177e2383637d Mon Sep 17 00:00:00 2001 From: Caitlin Shkuratov Date: Thu, 12 Jan 2023 18:39:18 +0000 Subject: [PATCH 15/23] [Status Bar] Append "__external" to external icons. Bug: 255428281 Bug: 265307726 Test: manual: (1) Be in silent mode. (2) Make a phone call. (3) Mute the phone call. -> Verify that *both* silent *and* mute icons appear in the status bar. Verify that they can each be toggled independently without affecting each other. Test: atest StatusBarIconControllerImplTest (verified that all added tests would have failed without the changes in this CL) Change-Id: I54cebf7b9b96c1b333f1f2a9ca3d427e9e765790 (cherry picked from commit afd1fc252bcb0336b300da71178b716767c82f9a) Merged-In: I54cebf7b9b96c1b333f1f2a9ca3d427e9e765790 --- .../systemui/qs/external/TileServices.java | 2 +- .../phone/StatusBarIconController.java | 32 +- .../phone/StatusBarIconControllerImpl.java | 38 ++- .../phone/StatusBarIconControllerImplTest.kt | 309 ++++++++++++++++++ .../leaks/FakeStatusBarIconController.java | 4 + 5 files changed, 375 insertions(+), 10 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index 3d48fd109e393..84a18d8dd3659 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -132,7 +132,7 @@ public class TileServices extends IQSService.Stub { final String slot = tile.getComponent().getClassName(); // TileServices doesn't know how to add more than 1 icon per slot, so remove all mMainHandler.post(() -> mHost.getIconController() - .removeAllIconsForSlot(slot)); + .removeAllIconsForExternalSlot(slot)); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 1a14a03637630..24ad55d67bb09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -79,12 +79,30 @@ public interface StatusBarIconController { /** Refresh the state of an IconManager by recreating the views */ void refreshIconGroup(IconManager iconManager); - /** */ + + /** + * Adds or updates an icon for a given slot for a **tile service icon**. + * + * TODO(b/265307726): Merge with {@link #setIcon(String, StatusBarIcon)} or make this method + * much more clearly distinct from that method. + */ void setExternalIcon(String slot); - /** */ + + /** + * Adds or updates an icon for the given slot for **internal system icons**. + * + * TODO(b/265307726): Rename to `setInternalIcon`, or merge this appropriately with the + * {@link #setIcon(String, StatusBarIcon)} method. + */ void setIcon(String slot, int resourceId, CharSequence contentDescription); - /** */ + + /** + * Adds or updates an icon for the given slot for an **externally-provided icon**. + * + * TODO(b/265307726): Rename to `setExternalIcon` or something similar. + */ void setIcon(String slot, StatusBarIcon icon); + /** */ void setWifiIcon(String slot, WifiIconState state); @@ -133,9 +151,17 @@ public interface StatusBarIconController { * TAG_PRIMARY to refer to the first icon at a given slot. */ void removeIcon(String slot, int tag); + /** */ void removeAllIconsForSlot(String slot); + /** + * Removes all the icons for the given slot. + * + * Only use this for icons that have come from **an external process**. + */ + void removeAllIconsForExternalSlot(String slot); + // TODO: See if we can rename this tunable name. String ICON_HIDE_LIST = "icon_blacklist"; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java index 9fbe6cbc0e326..416bc7141eebf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java @@ -28,6 +28,8 @@ import android.util.ArraySet; import android.util.Log; import android.view.ViewGroup; +import androidx.annotation.VisibleForTesting; + import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.Dumpable; import com.android.systemui.R; @@ -63,6 +65,10 @@ public class StatusBarIconControllerImpl implements Tunable, ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController, DemoMode { private static final String TAG = "StatusBarIconController"; + // Use this suffix to prevent external icon slot names from unintentionally overriding our + // internal, system-level slot names. See b/255428281. + @VisibleForTesting + protected static final String EXTERNAL_SLOT_SUFFIX = "__external"; private final StatusBarIconList mStatusBarIconList; private final ArrayList mIconGroups = new ArrayList<>(); @@ -346,21 +352,26 @@ public class StatusBarIconControllerImpl implements Tunable, @Override public void setExternalIcon(String slot) { - int viewIndex = mStatusBarIconList.getViewIndex(slot, 0); + String slotName = createExternalSlotName(slot); + int viewIndex = mStatusBarIconList.getViewIndex(slotName, 0); int height = mContext.getResources().getDimensionPixelSize( R.dimen.status_bar_icon_drawing_size); mIconGroups.forEach(l -> l.onIconExternal(viewIndex, height)); } - //TODO: remove this (used in command queue and for 3rd party tiles?) + // Override for *both* CommandQueue.Callbacks AND StatusBarIconController. + // TODO(b/265307726): Pull out the CommandQueue callbacks into a member variable to + // differentiate between those callback methods and StatusBarIconController methods. + @Override public void setIcon(String slot, StatusBarIcon icon) { + String slotName = createExternalSlotName(slot); if (icon == null) { - removeAllIconsForSlot(slot); + removeAllIconsForSlot(slotName); return; } StatusBarIconHolder holder = StatusBarIconHolder.fromIcon(icon); - setIcon(slot, holder); + setIcon(slotName, holder); } private void setIcon(String slot, @NonNull StatusBarIconHolder holder) { @@ -406,10 +417,12 @@ public class StatusBarIconControllerImpl implements Tunable, } } - /** */ + // CommandQueue.Callbacks override + // TODO(b/265307726): Pull out the CommandQueue callbacks into a member variable to + // differentiate between those callback methods and StatusBarIconController methods. @Override public void removeIcon(String slot) { - removeAllIconsForSlot(slot); + removeAllIconsForExternalSlot(slot); } /** */ @@ -423,6 +436,11 @@ public class StatusBarIconControllerImpl implements Tunable, mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex)); } + @Override + public void removeAllIconsForExternalSlot(String slotName) { + removeAllIconsForSlot(createExternalSlotName(slotName)); + } + /** */ @Override public void removeAllIconsForSlot(String slotName) { @@ -506,4 +524,12 @@ public class StatusBarIconControllerImpl implements Tunable, public void onDensityOrFontScaleChanged() { refreshIconGroups(); } + + private String createExternalSlotName(String slot) { + if (slot.endsWith(EXTERNAL_SLOT_SUFFIX)) { + return slot; + } else { + return slot + EXTERNAL_SLOT_SUFFIX; + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt new file mode 100644 index 0000000000000..3bc288a2f8234 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt @@ -0,0 +1,309 @@ +/* + * 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.phone + +import android.os.UserHandle +import androidx.test.filters.SmallTest +import com.android.internal.statusbar.StatusBarIcon +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.phone.StatusBarIconController.TAG_PRIMARY +import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl.EXTERNAL_SLOT_SUFFIX +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.verify + +@SmallTest +class StatusBarIconControllerImplTest : SysuiTestCase() { + + private lateinit var underTest: StatusBarIconControllerImpl + + private lateinit var iconList: StatusBarIconList + private val iconGroup: StatusBarIconController.IconManager = mock() + + @Before + fun setUp() { + iconList = StatusBarIconList(arrayOf()) + underTest = + StatusBarIconControllerImpl( + context, + mock(), + mock(), + mock(), + mock(), + mock(), + iconList, + mock(), + ) + underTest.addIconGroup(iconGroup) + } + + /** Regression test for b/255428281. */ + @Test + fun internalAndExternalIconWithSameName_bothDisplayed() { + val slotName = "mute" + + // Internal + underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription") + + // External + val externalIcon = + StatusBarIcon( + "external.package", + UserHandle.ALL, + /* iconId= */ 2, + /* iconLevel= */ 0, + /* number= */ 0, + "contentDescription", + ) + underTest.setIcon(slotName, externalIcon) + + assertThat(iconList.slots).hasSize(2) + // Whichever was added last comes first + assertThat(iconList.slots[0].name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX) + assertThat(iconList.slots[1].name).isEqualTo(slotName) + assertThat(iconList.slots[0].hasIconsInSlot()).isTrue() + assertThat(iconList.slots[1].hasIconsInSlot()).isTrue() + } + + /** Regression test for b/255428281. */ + @Test + fun internalAndExternalIconWithSameName_externalRemoved_viaRemoveIcon_internalStays() { + val slotName = "mute" + + // Internal + underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription") + + // External + underTest.setIcon(slotName, createExternalIcon()) + + // WHEN the external icon is removed via #removeIcon + underTest.removeIcon(slotName) + + // THEN the external icon is removed but the internal icon remains + // Note: [StatusBarIconList] never removes slots from its list, it just sets the holder for + // the slot to null when an icon is removed. + assertThat(iconList.slots).hasSize(2) + assertThat(iconList.slots[0].name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX) + assertThat(iconList.slots[1].name).isEqualTo(slotName) + assertThat(iconList.slots[0].hasIconsInSlot()).isFalse() // Indicates removal + assertThat(iconList.slots[1].hasIconsInSlot()).isTrue() + + verify(iconGroup).onRemoveIcon(0) + } + + /** Regression test for b/255428281. */ + @Test + fun internalAndExternalIconWithSameName_externalRemoved_viaRemoveAll_internalStays() { + val slotName = "mute" + + // Internal + underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription") + + // External + underTest.setIcon(slotName, createExternalIcon()) + + // WHEN the external icon is removed via #removeAllIconsForExternalSlot + underTest.removeAllIconsForExternalSlot(slotName) + + // THEN the external icon is removed but the internal icon remains + assertThat(iconList.slots).hasSize(2) + assertThat(iconList.slots[0].name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX) + assertThat(iconList.slots[1].name).isEqualTo(slotName) + assertThat(iconList.slots[0].hasIconsInSlot()).isFalse() // Indicates removal + assertThat(iconList.slots[1].hasIconsInSlot()).isTrue() + + verify(iconGroup).onRemoveIcon(0) + } + + /** Regression test for b/255428281. */ + @Test + fun internalAndExternalIconWithSameName_externalRemoved_viaSetNull_internalStays() { + val slotName = "mute" + + // Internal + underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription") + + // External + underTest.setIcon(slotName, createExternalIcon()) + + // WHEN the external icon is removed via a #setIcon(null) + underTest.setIcon(slotName, /* icon= */ null) + + // THEN the external icon is removed but the internal icon remains + assertThat(iconList.slots).hasSize(2) + assertThat(iconList.slots[0].name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX) + assertThat(iconList.slots[1].name).isEqualTo(slotName) + assertThat(iconList.slots[0].hasIconsInSlot()).isFalse() // Indicates removal + assertThat(iconList.slots[1].hasIconsInSlot()).isTrue() + + verify(iconGroup).onRemoveIcon(0) + } + + /** Regression test for b/255428281. */ + @Test + fun internalAndExternalIconWithSameName_internalRemoved_viaRemove_externalStays() { + val slotName = "mute" + + // Internal + underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription") + + // External + underTest.setIcon(slotName, createExternalIcon()) + + // WHEN the internal icon is removed via #removeIcon + underTest.removeIcon(slotName, /* tag= */ 0) + + // THEN the external icon is removed but the internal icon remains + assertThat(iconList.slots).hasSize(2) + assertThat(iconList.slots[0].name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX) + assertThat(iconList.slots[1].name).isEqualTo(slotName) + assertThat(iconList.slots[0].hasIconsInSlot()).isTrue() + assertThat(iconList.slots[1].hasIconsInSlot()).isFalse() // Indicates removal + + verify(iconGroup).onRemoveIcon(1) + } + + /** Regression test for b/255428281. */ + @Test + fun internalAndExternalIconWithSameName_internalRemoved_viaRemoveAll_externalStays() { + val slotName = "mute" + + // Internal + underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription") + + // External + underTest.setIcon(slotName, createExternalIcon()) + + // WHEN the internal icon is removed via #removeAllIconsForSlot + underTest.removeAllIconsForSlot(slotName) + + // THEN the external icon is removed but the internal icon remains + assertThat(iconList.slots).hasSize(2) + assertThat(iconList.slots[0].name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX) + assertThat(iconList.slots[1].name).isEqualTo(slotName) + assertThat(iconList.slots[0].hasIconsInSlot()).isTrue() + assertThat(iconList.slots[1].hasIconsInSlot()).isFalse() // Indicates removal + + verify(iconGroup).onRemoveIcon(1) + } + + /** Regression test for b/255428281. */ + @Test + fun internalAndExternalIconWithSameName_internalUpdatedIndependently() { + val slotName = "mute" + + // Internal + underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription") + + // External + val startingExternalIcon = + StatusBarIcon( + "external.package", + UserHandle.ALL, + /* iconId= */ 20, + /* iconLevel= */ 0, + /* number= */ 0, + "externalDescription", + ) + underTest.setIcon(slotName, startingExternalIcon) + + // WHEN the internal icon is updated + underTest.setIcon(slotName, /* resourceId= */ 11, "newContentDescription") + + // THEN only the internal slot gets the updates + val internalSlot = iconList.slots[1] + val internalHolder = internalSlot.getHolderForTag(TAG_PRIMARY)!! + assertThat(internalSlot.name).isEqualTo(slotName) + assertThat(internalHolder.icon!!.contentDescription).isEqualTo("newContentDescription") + assertThat(internalHolder.icon!!.icon.resId).isEqualTo(11) + + // And the external slot has its own values + val externalSlot = iconList.slots[0] + val externalHolder = externalSlot.getHolderForTag(TAG_PRIMARY)!! + assertThat(externalSlot.name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX) + assertThat(externalHolder.icon!!.contentDescription).isEqualTo("externalDescription") + assertThat(externalHolder.icon!!.icon.resId).isEqualTo(20) + } + + /** Regression test for b/255428281. */ + @Test + fun internalAndExternalIconWithSameName_externalUpdatedIndependently() { + val slotName = "mute" + + // Internal + underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription") + + // External + val startingExternalIcon = + StatusBarIcon( + "external.package", + UserHandle.ALL, + /* iconId= */ 20, + /* iconLevel= */ 0, + /* number= */ 0, + "externalDescription", + ) + underTest.setIcon(slotName, startingExternalIcon) + + // WHEN the external icon is updated + val newExternalIcon = + StatusBarIcon( + "external.package", + UserHandle.ALL, + /* iconId= */ 21, + /* iconLevel= */ 0, + /* number= */ 0, + "newExternalDescription", + ) + underTest.setIcon(slotName, newExternalIcon) + + // THEN only the external slot gets the updates + val externalSlot = iconList.slots[0] + val externalHolder = externalSlot.getHolderForTag(TAG_PRIMARY)!! + assertThat(externalSlot.name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX) + assertThat(externalHolder.icon!!.contentDescription).isEqualTo("newExternalDescription") + assertThat(externalHolder.icon!!.icon.resId).isEqualTo(21) + + // And the internal slot has its own values + val internalSlot = iconList.slots[1] + val internalHolder = internalSlot.getHolderForTag(TAG_PRIMARY)!! + assertThat(internalSlot.name).isEqualTo(slotName) + assertThat(internalHolder.icon!!.contentDescription).isEqualTo("contentDescription") + assertThat(internalHolder.icon!!.icon.resId).isEqualTo(10) + } + + @Test + fun externalSlot_alreadyEndsWithSuffix_suffixNotAddedTwice() { + underTest.setIcon("myslot$EXTERNAL_SLOT_SUFFIX", createExternalIcon()) + + assertThat(iconList.slots).hasSize(1) + assertThat(iconList.slots[0].name).isEqualTo("myslot$EXTERNAL_SLOT_SUFFIX") + } + + private fun createExternalIcon(): StatusBarIcon { + return StatusBarIcon( + "external.package", + UserHandle.ALL, + /* iconId= */ 2, + /* iconLevel= */ 0, + /* number= */ 0, + "contentDescription", + ) + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java index 2d6d29a50a741..926c6c56a8620 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java @@ -97,6 +97,10 @@ public class FakeStatusBarIconController extends BaseLeakChecker public void removeAllIconsForSlot(String slot) { } + @Override + public void removeAllIconsForExternalSlot(String slot) { + } + @Override public void setIconAccessibilityLiveRegion(String slot, int mode) { } From f53c15d046b5090ce565b6ec6eb175f6d5c75242 Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Wed, 11 Jan 2023 13:03:25 +0100 Subject: [PATCH 16/23] Use the correct FGS View when animating into a dialog This CL fixes the View that is used when showing the Foreground Services dialog. Test: Click the FGS button when the Security button is also shown. Bug: 264728445 Change-Id: Id686279bbfc1e47e28da894342688d44183ebf42 (cherry picked from commit 0e7b6e534c1a818d1539e12d2febe2d26b7fa026) Merged-In: Id686279bbfc1e47e28da894342688d44183ebf42 --- .../systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt index 30f81243e8d01..19215867e6789 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt @@ -219,9 +219,9 @@ object FooterActionsViewBinder { // Small button with the number only. foregroundServicesWithTextView.isVisible = false - foregroundServicesWithNumberView.visibility = View.VISIBLE + foregroundServicesWithNumberView.isVisible = true foregroundServicesWithNumberView.setOnClickListener { - foregroundServices.onClick(Expandable.fromView(foregroundServicesWithTextView)) + foregroundServices.onClick(Expandable.fromView(foregroundServicesWithNumberView)) } foregroundServicesWithNumberHolder.number.text = foregroundServicesCount.toString() foregroundServicesWithNumberHolder.number.contentDescription = foregroundServices.text From c262d5779b447f1e0ce1e48d064b6323072a7ef9 Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Wed, 11 Jan 2023 15:48:48 +0100 Subject: [PATCH 17/23] Revisit how launch animations handle View visibility This CL refactors the way the ActivityLaunchAnimator and DialogLaunchAnimator handle the visibility of the animated View when that View implements LaunchableView. Before this CL, a View that is animated would always end up being VISIBLE, even if something made that View INVISIBLE or GONE before or during the animation. That is because our animation code would sometimes change the visibility of the View, using View.setVisibility. After this CL, when animating a LaunchableView, all the visibility changes made to the animated View are done using View.setTransitionVisibility instead. That way, a LaunchableView can track all calls to View.setVisibility only and restore the last visibility that was set on the View at the end of the animation. Doing so ensures that all calls made to View.setVisibility have the expected result once the animation is done. Bug: 264728445 Test: DialogLaunchAnimatorTest Change-Id: I5848d42ef94952ecf058d4e895164389e37e0311 (cherry picked from commit 9ecb3db788b9f6be586c0f4f90c19d6337a7cd1b) Merged-In: I5848d42ef94952ecf058d4e895164389e37e0311 --- .../animation/DialogLaunchAnimator.kt | 2 +- .../GhostedViewLaunchAnimatorController.kt | 27 ++++-- .../systemui/animation/LaunchableView.kt | 46 +++++----- .../ViewDialogLaunchAnimatorController.kt | 52 +++++++---- .../common/ui/view/LaunchableImageView.kt | 5 - .../common/ui/view/LaunchableLinearLayout.kt | 5 - .../systemui/qs/tileimpl/QSTileViewImpl.kt | 5 - .../statusbar/AlphaOptimizedFrameLayout.java | 9 -- .../animation/DialogLaunchAnimatorTest.kt | 92 +++++++++++++++++-- 9 files changed, 156 insertions(+), 87 deletions(-) diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt index 54aa3516d867f..0f81b0b8d6e07 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt @@ -791,13 +791,13 @@ private class AnimatedDialog( // Move the drawing of the source in the overlay of this dialog, then animate. We trigger a // one-off synchronization to make sure that this is done in sync between the two different // windows. + controller.startDrawingInOverlayOf(decorView) synchronizeNextDraw( then = { isSourceDrawnInDialog = true maybeStartLaunchAnimation() } ) - controller.startDrawingInOverlayOf(decorView) } /** diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt index 0028d13ffd5e1..dfac02d99c4df 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt @@ -195,14 +195,16 @@ open class GhostedViewLaunchAnimatorController @JvmOverloads constructor( backgroundDrawable = WrappedDrawable(background) backgroundView?.background = backgroundDrawable + // Delay the calls to `ghostedView.setVisibility()` during the animation. This must be + // called before `GhostView.addGhost()` is called because the latter will change the + // *transition* visibility, which won't be blocked and will affect the normal View + // visibility that is saved by `setShouldBlockVisibilityChanges()` for a later restoration. + (ghostedView as? LaunchableView)?.setShouldBlockVisibilityChanges(true) + // Create a ghost of the view that will be moving and fading out. This allows to fade out // the content before fading out the background. ghostView = GhostView.addGhost(ghostedView, launchContainer) - // The ghost was just created, so ghostedView is currently invisible. We need to make sure - // that it stays invisible as long as we are animating. - (ghostedView as? LaunchableView)?.setShouldBlockVisibilityChanges(true) - val matrix = ghostView?.animationMatrix ?: Matrix.IDENTITY_MATRIX matrix.getValues(initialGhostViewMatrixValues) @@ -297,14 +299,19 @@ open class GhostedViewLaunchAnimatorController @JvmOverloads constructor( backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha GhostView.removeGhost(ghostedView) - (ghostedView as? LaunchableView)?.setShouldBlockVisibilityChanges(false) launchContainerOverlay.remove(backgroundView) - // Make sure that the view is considered VISIBLE by accessibility by first making it - // INVISIBLE then VISIBLE (see b/204944038#comment17 for more info). - ghostedView.visibility = View.INVISIBLE - ghostedView.visibility = View.VISIBLE - ghostedView.invalidate() + if (ghostedView is LaunchableView) { + // Restore the ghosted view visibility. + ghostedView.setShouldBlockVisibilityChanges(false) + } else { + // Make the ghosted view visible. We ensure that the view is considered VISIBLE by + // accessibility by first making it INVISIBLE then VISIBLE (see b/204944038#comment17 + // for more info). + ghostedView.visibility = View.INVISIBLE + ghostedView.visibility = View.VISIBLE + ghostedView.invalidate() + } } companion object { diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt index 67b59e0e9928e..774255be4007a 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt @@ -21,15 +21,19 @@ import android.view.View /** A view that can expand/launch into an app or a dialog. */ interface LaunchableView { /** - * Set whether this view should block/postpone all visibility changes. This ensures that this - * view: + * Set whether this view should block/postpone all calls to [View.setVisibility]. This ensures + * that this view: * - remains invisible during the launch animation given that it is ghosted and already drawn * somewhere else. * - remains invisible as long as a dialog expanded from it is shown. * - restores its expected visibility once the dialog expanded from it is dismissed. * - * Note that when this is set to true, both the [normal][android.view.View.setVisibility] and - * [transition][android.view.View.setTransitionVisibility] visibility changes must be blocked. + * When `setShouldBlockVisibilityChanges(false)` is called, then visibility of the View should + * be restored to its expected value, i.e. it should have the visibility of the last call to + * `View.setVisibility()` that was made after `setShouldBlockVisibilityChanges(true)`, if any, + * or the original view visibility otherwise. + * + * Note that calls to [View.setTransitionVisibility] shouldn't be blocked. * * @param block whether we should block/postpone all calls to `setVisibility` and * `setTransitionVisibility`. @@ -46,27 +50,31 @@ class LaunchableViewDelegate( * super.setVisibility(visibility). */ private val superSetVisibility: (Int) -> Unit, - - /** - * The lambda that should set the actual transition visibility of [view], usually by calling - * super.setTransitionVisibility(visibility). - */ - private val superSetTransitionVisibility: (Int) -> Unit, -) { +) : LaunchableView { private var blockVisibilityChanges = false private var lastVisibility = view.visibility /** Call this when [LaunchableView.setShouldBlockVisibilityChanges] is called. */ - fun setShouldBlockVisibilityChanges(block: Boolean) { + override fun setShouldBlockVisibilityChanges(block: Boolean) { if (block == blockVisibilityChanges) { return } blockVisibilityChanges = block if (block) { + // Save the current visibility for later. lastVisibility = view.visibility } else { - superSetVisibility(lastVisibility) + // Restore the visibility. To avoid accessibility issues, we change the visibility twice + // which makes sure that we trigger a visibility flag change (see b/204944038#comment17 + // for more info). + if (lastVisibility == View.VISIBLE) { + superSetVisibility(View.INVISIBLE) + superSetVisibility(View.VISIBLE) + } else { + superSetVisibility(View.VISIBLE) + superSetVisibility(lastVisibility) + } } } @@ -79,16 +87,4 @@ class LaunchableViewDelegate( superSetVisibility(visibility) } - - /** Call this when [View.setTransitionVisibility] is called. */ - fun setTransitionVisibility(visibility: Int) { - if (blockVisibilityChanges) { - // View.setTransitionVisibility just sets the visibility flag, so we don't have to save - // the transition visibility separately from the normal visibility. - lastVisibility = visibility - return - } - - superSetTransitionVisibility(visibility) - } } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt index 964ef8c880982..46d5a5c0af8c0 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt @@ -34,23 +34,29 @@ internal constructor( override val sourceIdentity: Any = source override fun startDrawingInOverlayOf(viewGroup: ViewGroup) { + // Delay the calls to `source.setVisibility()` during the animation. This must be called + // before `GhostView.addGhost()` is called because the latter will change the *transition* + // visibility, which won't be blocked and will affect the normal View visibility that is + // saved by `setShouldBlockVisibilityChanges()` for a later restoration. + (source as? LaunchableView)?.setShouldBlockVisibilityChanges(true) + // Create a temporary ghost of the source (which will make it invisible) and add it // to the host dialog. GhostView.addGhost(source, viewGroup) - - // The ghost of the source was just created, so the source is currently invisible. - // We need to make sure that it stays invisible as long as the dialog is shown or - // animating. - (source as? LaunchableView)?.setShouldBlockVisibilityChanges(true) } override fun stopDrawingInOverlay() { // Note: here we should remove the ghost from the overlay, but in practice this is - // already done by the launch controllers created below. + // already done by the launch controller created below. - // Make sure we allow the source to change its visibility again. - (source as? LaunchableView)?.setShouldBlockVisibilityChanges(false) - source.visibility = View.VISIBLE + if (source is LaunchableView) { + // Make sure we allow the source to change its visibility again and restore its previous + // value. + source.setShouldBlockVisibilityChanges(false) + } else { + // We made the source invisible earlier, so let's make it visible again. + source.visibility = View.VISIBLE + } } override fun createLaunchController(): LaunchAnimator.Controller { @@ -67,10 +73,14 @@ internal constructor( override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { delegate.onLaunchAnimationEnd(isExpandingFullyAbove) - // We hide the source when the dialog is showing. We will make this view - // visible again when dismissing the dialog. This does nothing if the source - // implements [LaunchableView], as it's already INVISIBLE in that case. - source.visibility = View.INVISIBLE + // At this point the view visibility is restored by the delegate, so we delay the + // visibility changes again and make it invisible while the dialog is shown. + if (source is LaunchableView) { + source.setShouldBlockVisibilityChanges(true) + source.setTransitionVisibility(View.INVISIBLE) + } else { + source.visibility = View.INVISIBLE + } } } } @@ -90,13 +100,15 @@ internal constructor( } override fun onExitAnimationCancelled() { - // Make sure we allow the source to change its visibility again. - (source as? LaunchableView)?.setShouldBlockVisibilityChanges(false) - - // If the view is invisible it's probably because of us, so we make it visible - // again. - if (source.visibility == View.INVISIBLE) { - source.visibility = View.VISIBLE + if (source is LaunchableView) { + // Make sure we allow the source to change its visibility again. + source.setShouldBlockVisibilityChanges(false) + } else { + // If the view is invisible it's probably because of us, so we make it visible + // again. + if (source.visibility == View.INVISIBLE) { + source.visibility = View.VISIBLE + } } } diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt index f95a8ee89a2c0..7bbfec7df9d80 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt +++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt @@ -28,7 +28,6 @@ class LaunchableImageView : ImageView, LaunchableView { LaunchableViewDelegate( this, superSetVisibility = { super.setVisibility(it) }, - superSetTransitionVisibility = { super.setTransitionVisibility(it) }, ) constructor(context: Context?) : super(context) @@ -53,8 +52,4 @@ class LaunchableImageView : ImageView, LaunchableView { override fun setVisibility(visibility: Int) { delegate.setVisibility(visibility) } - - override fun setTransitionVisibility(visibility: Int) { - delegate.setTransitionVisibility(visibility) - } } diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt index c27b82aeeb47c..ddde6280f3a2b 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt @@ -28,7 +28,6 @@ class LaunchableLinearLayout : LinearLayout, LaunchableView { LaunchableViewDelegate( this, superSetVisibility = { super.setVisibility(it) }, - superSetTransitionVisibility = { super.setTransitionVisibility(it) }, ) constructor(context: Context?) : super(context) @@ -53,8 +52,4 @@ class LaunchableLinearLayout : LinearLayout, LaunchableView { override fun setVisibility(visibility: Int) { delegate.setVisibility(visibility) } - - override fun setTransitionVisibility(visibility: Int) { - delegate.setTransitionVisibility(visibility) - } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt index b355d4bb67feb..29d7fb02e6139 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt @@ -145,7 +145,6 @@ open class QSTileViewImpl @JvmOverloads constructor( private val launchableViewDelegate = LaunchableViewDelegate( this, superSetVisibility = { super.setVisibility(it) }, - superSetTransitionVisibility = { super.setTransitionVisibility(it) }, ) private var lastDisabledByPolicy = false @@ -362,10 +361,6 @@ open class QSTileViewImpl @JvmOverloads constructor( launchableViewDelegate.setVisibility(visibility) } - override fun setTransitionVisibility(visibility: Int) { - launchableViewDelegate.setTransitionVisibility(visibility) - } - // Accessibility override fun onInitializeAccessibilityEvent(event: AccessibilityEvent) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedFrameLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedFrameLayout.java index 662f70ef269ea..438b0f625fc5b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedFrameLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedFrameLayout.java @@ -36,10 +36,6 @@ public class AlphaOptimizedFrameLayout extends FrameLayout implements Launchable visibility -> { super.setVisibility(visibility); return Unit.INSTANCE; - }, - visibility -> { - super.setTransitionVisibility(visibility); - return Unit.INSTANCE; }); public AlphaOptimizedFrameLayout(Context context) { @@ -73,9 +69,4 @@ public class AlphaOptimizedFrameLayout extends FrameLayout implements Launchable public void setVisibility(int visibility) { mLaunchableViewDelegate.setVisibility(visibility); } - - @Override - public void setTransitionVisibility(int visibility) { - mLaunchableViewDelegate.setTransitionVisibility(visibility); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt index 7c1e384f8c305..cac4a0e5432c1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt @@ -12,11 +12,13 @@ import android.view.View import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.WindowManager +import android.widget.FrameLayout import android.widget.LinearLayout import androidx.test.filters.SmallTest import com.android.internal.jank.InteractionJankMonitor import com.android.internal.policy.DecorView import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import junit.framework.Assert.assertNotNull @@ -205,25 +207,74 @@ class DialogLaunchAnimatorTest : SysuiTestCase() { verify(interactionJankMonitor).end(InteractionJankMonitor.CUJ_USER_DIALOG_OPEN) } + @Test + fun testAnimationDoesNotChangeLaunchableViewVisibility_viewVisible() { + val touchSurface = createTouchSurface() + + // View is VISIBLE when starting the animation. + runOnMainThreadAndWaitForIdleSync { touchSurface.visibility = View.VISIBLE } + + // View is invisible while the dialog is shown. + val dialog = showDialogFromView(touchSurface) + assertThat(touchSurface.visibility).isEqualTo(View.INVISIBLE) + + // View is visible again when the dialog is dismissed. + runOnMainThreadAndWaitForIdleSync { dialog.dismiss() } + assertThat(touchSurface.visibility).isEqualTo(View.VISIBLE) + } + + @Test + fun testAnimationDoesNotChangeLaunchableViewVisibility_viewInvisible() { + val touchSurface = createTouchSurface() + + // View is INVISIBLE when starting the animation. + runOnMainThreadAndWaitForIdleSync { touchSurface.visibility = View.INVISIBLE } + + // View is INVISIBLE while the dialog is shown. + val dialog = showDialogFromView(touchSurface) + assertThat(touchSurface.visibility).isEqualTo(View.INVISIBLE) + + // View is invisible like it was before showing the dialog. + runOnMainThreadAndWaitForIdleSync { dialog.dismiss() } + assertThat(touchSurface.visibility).isEqualTo(View.INVISIBLE) + } + + @Test + fun testAnimationDoesNotChangeLaunchableViewVisibility_viewVisibleThenGone() { + val touchSurface = createTouchSurface() + + // View is VISIBLE when starting the animation. + runOnMainThreadAndWaitForIdleSync { touchSurface.visibility = View.VISIBLE } + + // View is INVISIBLE while the dialog is shown. + val dialog = showDialogFromView(touchSurface) + assertThat(touchSurface.visibility).isEqualTo(View.INVISIBLE) + + // Some external call makes the View GONE. It remains INVISIBLE while the dialog is shown, + // as all visibility changes should be blocked. + runOnMainThreadAndWaitForIdleSync { touchSurface.visibility = View.GONE } + assertThat(touchSurface.visibility).isEqualTo(View.INVISIBLE) + + // View is restored to GONE once the dialog is dismissed. + runOnMainThreadAndWaitForIdleSync { dialog.dismiss() } + assertThat(touchSurface.visibility).isEqualTo(View.GONE) + } + private fun createAndShowDialog( animator: DialogLaunchAnimator = dialogLaunchAnimator, ): TestDialog { val touchSurface = createTouchSurface() - return runOnMainThreadAndWaitForIdleSync { - val dialog = TestDialog(context) - animator.showFromView(dialog, touchSurface) - dialog - } + return showDialogFromView(touchSurface, animator) } private fun createTouchSurface(): View { return runOnMainThreadAndWaitForIdleSync { val touchSurfaceRoot = LinearLayout(context) - val touchSurface = View(context) + val touchSurface = TouchSurfaceView(context) touchSurfaceRoot.addView(touchSurface) // We need to attach the root to the window manager otherwise the exit animation will - // be skipped + // be skipped. ViewUtils.attachView(touchSurfaceRoot) attachedViews.add(touchSurfaceRoot) @@ -231,6 +282,17 @@ class DialogLaunchAnimatorTest : SysuiTestCase() { } } + private fun showDialogFromView( + touchSurface: View, + animator: DialogLaunchAnimator = dialogLaunchAnimator, + ): TestDialog { + return runOnMainThreadAndWaitForIdleSync { + val dialog = TestDialog(context) + animator.showFromView(dialog, touchSurface) + dialog + } + } + private fun createDialogAndShowFromDialog(animateFrom: Dialog): TestDialog { return runOnMainThreadAndWaitForIdleSync { val dialog = TestDialog(context) @@ -248,6 +310,22 @@ class DialogLaunchAnimatorTest : SysuiTestCase() { return result } + private class TouchSurfaceView(context: Context) : FrameLayout(context), LaunchableView { + private val delegate = + LaunchableViewDelegate( + this, + superSetVisibility = { super.setVisibility(it) }, + ) + + override fun setShouldBlockVisibilityChanges(block: Boolean) { + delegate.setShouldBlockVisibilityChanges(block) + } + + override fun setVisibility(visibility: Int) { + delegate.setVisibility(visibility) + } + } + private class TestDialog(context: Context) : Dialog(context) { companion object { const val DIALOG_WIDTH = 100 From 8adc88a15f1b7c7a291e0def179a42b987fef30e Mon Sep 17 00:00:00 2001 From: Anton Potapov Date: Thu, 8 Dec 2022 15:49:24 +0000 Subject: [PATCH 18/23] Fix work tile setup when adding work profile Test: Auto + manual - Add work profile -> QS tile is added - Remove work profile -> QS tile is removed - Reboot the device -> QS tile is in place - Reorder tiles, reboot the device -> order is persisted Fixes: 234639083 Change-Id: I4481a3f28f9d1f0c30618afaf78179e0033f50fb (cherry picked from commit a240e7eebe6fc81f123150a362c493a6f93b9d2c) Merged-In: I4481a3f28f9d1f0c30618afaf78179e0033f50fb --- .../src/com/android/systemui/qs/QSHost.java | 1 - .../com/android/systemui/qs/QSTileHost.java | 5 - .../systemui/qs/tiles/WorkModeTile.java | 1 - .../systemui/settings/UserTrackerImpl.kt | 3 +- .../statusbar/phone/AutoTileManager.java | 16 ++- .../settings/UserTrackerImplReceiveTest.kt | 100 ++++++++++++++++++ .../systemui/settings/UserTrackerImplTest.kt | 41 ++----- .../statusbar/phone/AutoTileManagerTest.java | 42 +++++++- 8 files changed, 159 insertions(+), 50 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java index 7cf63f678c1d8..1da30ade951bb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java @@ -36,7 +36,6 @@ public interface QSHost { void removeCallback(Callback callback); void removeTile(String tileSpec); void removeTiles(Collection specs); - void unmarkTileAsAutoAdded(String tileSpec); int indexOf(String tileSpec); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index cad296b671b30..100853caa2d7e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -427,11 +427,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener, P mMainExecutor.execute(() -> changeTileSpecs(tileSpecs -> tileSpecs.removeAll(specs))); } - @Override - public void unmarkTileAsAutoAdded(String spec) { - if (mAutoTiles != null) mAutoTiles.unmarkTileAsAutoAdded(spec); - } - /** * Add a tile to the end * diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index a6c7781d891c0..72c6bfe371ce2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -101,7 +101,6 @@ public class WorkModeTile extends QSTileImpl implements @MainThread public void onManagedProfileRemoved() { mHost.removeTile(getTileSpec()); - mHost.unmarkTileAsAutoAdded(getTileSpec()); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt index 28da38b701bc1..61390c582fd60 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt @@ -112,7 +112,7 @@ class UserTrackerImpl internal constructor( // These get called when a managed profile goes in or out of quiet mode. addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE) - + addAction(Intent.ACTION_MANAGED_PROFILE_ADDED) addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED) addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED) } @@ -129,6 +129,7 @@ class UserTrackerImpl internal constructor( Intent.ACTION_USER_INFO_CHANGED, Intent.ACTION_MANAGED_PROFILE_AVAILABLE, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE, + Intent.ACTION_MANAGED_PROFILE_ADDED, Intent.ACTION_MANAGED_PROFILE_REMOVED, Intent.ACTION_MANAGED_PROFILE_UNLOCKED -> { handleProfilesChanged() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java index 9070eadd9944f..149ec545dfa73 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java @@ -154,9 +154,7 @@ public class AutoTileManager implements UserAwareController { if (!mAutoTracker.isAdded(SAVER)) { mDataSaverController.addCallback(mDataSaverListener); } - if (!mAutoTracker.isAdded(WORK)) { - mManagedProfileController.addCallback(mProfileCallback); - } + mManagedProfileController.addCallback(mProfileCallback); if (!mAutoTracker.isAdded(NIGHT) && ColorDisplayManager.isNightDisplayAvailable(mContext)) { mNightDisplayListener.setCallback(mNightDisplayCallback); @@ -275,18 +273,18 @@ public class AutoTileManager implements UserAwareController { return mCurrentUser.getIdentifier(); } - public void unmarkTileAsAutoAdded(String tabSpec) { - mAutoTracker.setTileRemoved(tabSpec); - } - private final ManagedProfileController.Callback mProfileCallback = new ManagedProfileController.Callback() { @Override public void onManagedProfileChanged() { - if (mAutoTracker.isAdded(WORK)) return; if (mManagedProfileController.hasActiveProfile()) { + if (mAutoTracker.isAdded(WORK)) return; mHost.addTile(WORK); mAutoTracker.setTileAdded(WORK); + } else { + if (!mAutoTracker.isAdded(WORK)) return; + mHost.removeTile(WORK); + mAutoTracker.setTileRemoved(WORK); } } @@ -429,7 +427,7 @@ public class AutoTileManager implements UserAwareController { initSafetyTile(); } else if (!isSafetyCenterEnabled && mAutoTracker.isAdded(mSafetySpec)) { mHost.removeTile(mSafetySpec); - mHost.unmarkTileAsAutoAdded(mSafetySpec); + mAutoTracker.setTileRemoved(mSafetySpec); } } }; diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt new file mode 100644 index 0000000000000..3710281499b30 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt @@ -0,0 +1,100 @@ +package com.android.systemui.settings + +import android.content.Context +import android.content.Intent +import android.content.pm.UserInfo +import android.os.Handler +import android.os.UserHandle +import android.os.UserManager +import androidx.concurrent.futures.DirectExecutor +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.DumpManager +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.capture +import com.google.common.truth.Truth.assertThat +import java.util.concurrent.Executor +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(Parameterized::class) +class UserTrackerImplReceiveTest : SysuiTestCase() { + + companion object { + + @JvmStatic + @Parameterized.Parameters + fun data(): Iterable = + listOf( + Intent.ACTION_USER_INFO_CHANGED, + Intent.ACTION_MANAGED_PROFILE_AVAILABLE, + Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE, + Intent.ACTION_MANAGED_PROFILE_ADDED, + Intent.ACTION_MANAGED_PROFILE_REMOVED, + Intent.ACTION_MANAGED_PROFILE_UNLOCKED + ) + } + + private val executor: Executor = DirectExecutor.INSTANCE + + @Mock private lateinit var context: Context + @Mock private lateinit var userManager: UserManager + @Mock(stubOnly = true) private lateinit var dumpManager: DumpManager + @Mock(stubOnly = true) private lateinit var handler: Handler + + @Parameterized.Parameter lateinit var intentAction: String + @Mock private lateinit var callback: UserTracker.Callback + @Captor private lateinit var captor: ArgumentCaptor> + + private lateinit var tracker: UserTrackerImpl + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + `when`(context.user).thenReturn(UserHandle.SYSTEM) + `when`(context.createContextAsUser(ArgumentMatchers.any(), anyInt())).thenReturn(context) + + tracker = UserTrackerImpl(context, userManager, dumpManager, handler) + } + + @Test + fun `calls callback and updates profiles when an intent received`() { + tracker.initialize(0) + tracker.addCallback(callback, executor) + val profileID = tracker.userId + 10 + + `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation -> + val id = invocation.getArgument(0) + val info = UserInfo(id, "", UserInfo.FLAG_FULL) + val infoProfile = + UserInfo( + id + 10, + "", + "", + UserInfo.FLAG_MANAGED_PROFILE, + UserManager.USER_TYPE_PROFILE_MANAGED + ) + infoProfile.profileGroupId = id + listOf(info, infoProfile) + } + + tracker.onReceive(context, Intent(intentAction)) + + verify(callback, times(0)).onUserChanged(anyInt(), any()) + verify(callback, times(1)).onProfilesChanged(capture(captor)) + assertThat(captor.value.map { it.id }).containsExactly(0, profileID) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt index 52462c7186d4a..e65bbb1bea086 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt @@ -124,6 +124,16 @@ class UserTrackerImplTest : SysuiTestCase() { verify(context).registerReceiverForAllUsers( eq(tracker), capture(captor), isNull(), eq(handler)) + with(captor.value) { + assertThat(countActions()).isEqualTo(7) + assertThat(hasAction(Intent.ACTION_USER_SWITCHED)).isTrue() + assertThat(hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue() + assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)).isTrue() + assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)).isTrue() + assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_ADDED)).isTrue() + assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_REMOVED)).isTrue() + assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED)).isTrue() + } } @Test @@ -279,37 +289,6 @@ class UserTrackerImplTest : SysuiTestCase() { assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(newID) } - @Test - fun testCallbackCalledOnProfileChanged() { - tracker.initialize(0) - val callback = TestCallback() - tracker.addCallback(callback, executor) - val profileID = tracker.userId + 10 - - `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation -> - val id = invocation.getArgument(0) - val info = UserInfo(id, "", UserInfo.FLAG_FULL) - val infoProfile = UserInfo( - id + 10, - "", - "", - UserInfo.FLAG_MANAGED_PROFILE, - UserManager.USER_TYPE_PROFILE_MANAGED - ) - infoProfile.profileGroupId = id - listOf(info, infoProfile) - } - - val intent = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) - .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID)) - - tracker.onReceive(context, intent) - - assertThat(callback.calledOnUserChanged).isEqualTo(0) - assertThat(callback.calledOnProfilesChanged).isEqualTo(1) - assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(0, profileID) - } - @Test fun testCallbackCalledOnUserInfoChanged() { tracker.initialize(0) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java index 4ccbc6d45e638..091bb5455d93f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNotNull; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doReturn; @@ -74,6 +75,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import org.mockito.stubbing.Answer; import java.util.Collections; import java.util.List; @@ -115,8 +117,10 @@ public class AutoTileManagerTest extends SysuiTestCase { @Spy private PackageManager mPackageManager; private final boolean mIsReduceBrightColorsAvailable = true; - private AutoTileManager mAutoTileManager; + private AutoTileManager mAutoTileManager; // under test + private SecureSettings mSecureSettings; + private ManagedProfileController.Callback mManagedProfileCallback; @Before public void setUp() throws Exception { @@ -303,7 +307,7 @@ public class AutoTileManagerTest extends SysuiTestCase { InOrder inOrderManagedProfile = inOrder(mManagedProfileController); inOrderManagedProfile.verify(mManagedProfileController).removeCallback(any()); - inOrderManagedProfile.verify(mManagedProfileController, never()).addCallback(any()); + inOrderManagedProfile.verify(mManagedProfileController).addCallback(any()); if (ColorDisplayManager.isNightDisplayAvailable(mContext)) { InOrder inOrderNightDisplay = inOrder(mNightDisplayListener); @@ -503,6 +507,40 @@ public class AutoTileManagerTest extends SysuiTestCase { verify(mQsTileHost, times(2)).addTile(safetyComponent, true); } + @Test + public void managedProfileAdded_tileAdded() { + when(mAutoAddTracker.isAdded(eq("work"))).thenReturn(false); + mAutoTileManager = createAutoTileManager(mContext); + Mockito.doAnswer((Answer) invocation -> { + mManagedProfileCallback = invocation.getArgument(0); + return null; + }).when(mManagedProfileController).addCallback(any()); + mAutoTileManager.init(); + when(mManagedProfileController.hasActiveProfile()).thenReturn(true); + + mManagedProfileCallback.onManagedProfileChanged(); + + verify(mQsTileHost, times(1)).addTile(eq("work")); + verify(mAutoAddTracker, times(1)).setTileAdded(eq("work")); + } + + @Test + public void managedProfileRemoved_tileRemoved() { + when(mAutoAddTracker.isAdded(eq("work"))).thenReturn(true); + mAutoTileManager = createAutoTileManager(mContext); + Mockito.doAnswer((Answer) invocation -> { + mManagedProfileCallback = invocation.getArgument(0); + return null; + }).when(mManagedProfileController).addCallback(any()); + mAutoTileManager.init(); + when(mManagedProfileController.hasActiveProfile()).thenReturn(false); + + mManagedProfileCallback.onManagedProfileChanged(); + + verify(mQsTileHost, times(1)).removeTile(eq("work")); + verify(mAutoAddTracker, times(1)).setTileRemoved(eq("work")); + } + @Test public void testEmptyArray_doesNotCrash() { mContext.getOrCreateTestableResources().addOverride( From 34696dcb976697688c8238fcc7260be3d47d72c2 Mon Sep 17 00:00:00 2001 From: Anton Potapov Date: Thu, 5 Jan 2023 15:18:38 +0000 Subject: [PATCH 19/23] Fix QS header constraints so status icons are now ellipsized where there is lack of space. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously: There was a chain [date]-[space]-[status icons]-[battery]. That's why we should add bias and space to make it working. But there're several problems with this: 1) app:layout_width="WRAP_CONTENT" + app:layout_constrainedWidth=”true" != app:layout_width="0dp" + app:layout_constraintWidth_default="wrap". The first one gets view expanded like it's MATCH_PARENT. 2) I've found out that wrapping views in constraint layout 2.0.0 may not always work as expected with app:layout_constrainedWidth=”true" (the view get's stretched as it's match_parent). layout_constraintWidth_max="wrap" should've help with this, but motion layout can't parse this attribute in constraint set. That's why my solution is to reimplement the layout a little bit This behavior is reported here: https://github.com/androidx/constraintlayout/issues/713 Now: [date] and [battery] are constrained to the sides and [status icons] occupy the whole space between them. [date] is always WRAP_CONTENT because there's always some space and we want to show it. [battery] and [status icons] are wrap content with constraints restrictions to make them fill all the space left Test: manual: phone + tablet Fixes: 260364389 Change-Id: I4d54b795cc4e96f6c204f2f00aff7607572d9aa3 (cherry picked from commit 675ff0fe3756eb07baffba4bfc18b5bd2c289b01) Merged-In: I4d54b795cc4e96f6c204f2f00aff7607572d9aa3 --- .../res/layout/combined_qs_header.xml | 5 ---- packages/SystemUI/res/xml/qs_header.xml | 30 +++++-------------- .../CombinedShadeHeaderConstraintsTest.kt | 14 ++++----- 3 files changed, 12 insertions(+), 37 deletions(-) diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml index a565988c14ade..d689828764489 100644 --- a/packages/SystemUI/res/layout/combined_qs_header.xml +++ b/packages/SystemUI/res/layout/combined_qs_header.xml @@ -148,9 +148,4 @@ - \ No newline at end of file diff --git a/packages/SystemUI/res/xml/qs_header.xml b/packages/SystemUI/res/xml/qs_header.xml index eca2b2acb0792..d97031f35d6bd 100644 --- a/packages/SystemUI/res/xml/qs_header.xml +++ b/packages/SystemUI/res/xml/qs_header.xml @@ -56,13 +56,9 @@ @@ -87,39 +83,27 @@ - - - - \ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt index 88651c1292c34..f802a5e09228f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.shade import android.testing.AndroidTestingRunner +import android.view.ViewGroup import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START @@ -92,12 +93,12 @@ class CombinedShadeHeaderConstraintsTest : SysuiTestCase() { assertThat(getConstraint(R.id.clock).layout.horizontalBias).isEqualTo(0f) assertThat(getConstraint(R.id.date).layout.startToStart).isEqualTo(PARENT_ID) - assertThat(getConstraint(R.id.date).layout.horizontalBias).isEqualTo(0f) + assertThat(getConstraint(R.id.date).layout.horizontalBias).isEqualTo(0.5f) assertThat(getConstraint(R.id.batteryRemainingIcon).layout.endToEnd) .isEqualTo(PARENT_ID) assertThat(getConstraint(R.id.batteryRemainingIcon).layout.horizontalBias) - .isEqualTo(1f) + .isEqualTo(0.5f) assertThat(getConstraint(R.id.privacy_container).layout.endToEnd) .isEqualTo(R.id.end_guide) @@ -331,10 +332,8 @@ class CombinedShadeHeaderConstraintsTest : SysuiTestCase() { val views = mapOf( R.id.clock to "clock", R.id.date to "date", - R.id.statusIcons to "icons", R.id.privacy_container to "privacy", R.id.carrier_group to "carriers", - R.id.batteryRemainingIcon to "battery", ) views.forEach { (id, name) -> assertWithMessage("$name has 0 height in qqs") @@ -352,11 +351,8 @@ class CombinedShadeHeaderConstraintsTest : SysuiTestCase() { fun testCheckViewsDontChangeSizeBetweenAnimationConstraints() { val views = mapOf( R.id.clock to "clock", - R.id.date to "date", - R.id.statusIcons to "icons", R.id.privacy_container to "privacy", R.id.carrier_group to "carriers", - R.id.batteryRemainingIcon to "battery", ) views.forEach { (id, name) -> expect.withMessage("$name changes height") @@ -369,8 +365,8 @@ class CombinedShadeHeaderConstraintsTest : SysuiTestCase() { } private fun Int.fromConstraint() = when (this) { - -1 -> "MATCH_PARENT" - -2 -> "WRAP_CONTENT" + ViewGroup.LayoutParams.MATCH_PARENT -> "MATCH_PARENT" + ViewGroup.LayoutParams.WRAP_CONTENT -> "WRAP_CONTENT" else -> toString() } From 746d2338b3776118a162ed9b445d23154a572789 Mon Sep 17 00:00:00 2001 From: bkchoi Date: Thu, 12 Jan 2023 15:52:45 -0800 Subject: [PATCH 20/23] Send system user broadcasts in headless system user mode. In headless system user mode, USER_STARTING, USER_STARTED, and USER_SWITCHED broadcasts were not sent for the system user. It had caused issues for other parts of the system which are expecting such broadcast messages. For example, VpnManagerService expects USER_STARTED event for system user but was not receiving it. This change will only affect headless system user mode. No behavior changes for phones. Bug: 263439429 Bug: 242195409 Test: atest com.android.cts.devicepolicy.MixedDeviceOwnerTest Change-Id: I4a101418c10a2c959c2bfae01b95863aebd521e8 (cherry picked from commit ba0f9f3ad2de99e8f96075db4571e6bf25d6c310) Merged-In: I4a101418c10a2c959c2bfae01b95863aebd521e8 --- .../android/server/am/ActivityManagerService.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 19b5cc93932b5..5d4dc39341a17 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -8196,15 +8196,13 @@ public class ActivityManagerService extends IActivityManager.Stub t.traceEnd(); } + boolean isBootingSystemUser = currentUserId == UserHandle.USER_SYSTEM; + // Some systems - like automotive - will explicitly unlock system user then switch - // to a secondary user. Hence, we don't want to send duplicate broadcasts for - // the system user here. + // to a secondary user. // TODO(b/242195409): this workaround shouldn't be necessary once we move // the headless-user start logic to UserManager-land. - final boolean isBootingSystemUser = (currentUserId == UserHandle.USER_SYSTEM) - && !UserManager.isHeadlessSystemUserMode(); - - if (isBootingSystemUser) { + if (isBootingSystemUser && !UserManager.isHeadlessSystemUserMode()) { t.traceBegin("startHomeOnAllDisplays"); mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady"); t.traceEnd(); @@ -8216,6 +8214,10 @@ public class ActivityManagerService extends IActivityManager.Stub if (isBootingSystemUser) { + // Need to send the broadcasts for the system user here because + // UserController#startUserInternal will not send them for the system user starting, + // It checks if the user state already exists, which is always the case for the + // system user. t.traceBegin("sendUserStartBroadcast"); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); From 69cf0a56f421e7115ec03ff57f0d10405fd73203 Mon Sep 17 00:00:00 2001 From: Behnam Heydarshahi Date: Wed, 25 Jan 2023 20:53:53 +0000 Subject: [PATCH 21/23] DO NOT MERGE ANYWHERE Revert "Add flag to separate notification audio and ui" Revert submission 20180104-flag_for_b38477228 Reason for revert: b/261809910 fixing for qpr2 Reverted changes: /q/submissionid:20180104-flag_for_b38477228 Include only in tm-qpr2-release because fix forward is already submitted to tm-qpr-deb at ag/20806122 Change-Id: I35549d7b7b41632c857bdbdda02ddb7220208243 (cherry picked from commit 9fcce567af715a80929a4bbbdfdffa3410ae0d8e) Merged-In: I35549d7b7b41632c857bdbdda02ddb7220208243 --- .../android/preference/SeekBarVolumizer.java | 22 +++++--------- .../sysui/SystemUiDeviceConfigFlags.java | 5 ---- core/res/res/values/config.xml | 4 +++ core/res/res/values/symbols.xml | 1 + .../android/server/audio/AudioService.java | 29 ++----------------- 5 files changed, 14 insertions(+), 47 deletions(-) diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 36e0dc35cb8e6..16f9a12953f81 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -16,9 +16,7 @@ package android.preference; -import android.Manifest; import android.annotation.NonNull; -import android.annotation.RequiresPermission; import android.app.NotificationManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; @@ -37,7 +35,6 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.preference.VolumePreference.VolumeStore; -import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.Global; import android.provider.Settings.System; @@ -47,7 +44,6 @@ import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import com.android.internal.annotations.GuardedBy; -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.os.SomeArgs; import java.util.concurrent.TimeUnit; @@ -119,6 +115,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private final int mMaxStreamVolume; private boolean mAffectedByRingerMode; private boolean mNotificationOrRing; + private final boolean mNotifAliasRing; private final Receiver mReceiver = new Receiver(); private Handler mHandler; @@ -161,7 +158,6 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba this(context, streamType, defaultUri, callback, true /* playSample */); } - @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) public SeekBarVolumizer( Context context, int streamType, @@ -184,6 +180,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba if (mNotificationOrRing) { mRingerMode = mAudioManager.getRingerModeInternal(); } + mNotifAliasRing = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_alias_ring_notif_stream_types); mZenMode = mNotificationManager.getZenMode(); if (hasAudioProductStrategies()) { @@ -290,9 +288,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba * so that when user attempts to slide the notification seekbar out of vibrate the * seekbar doesn't wrongly snap back to 0 when the streams aren't aliased */ - if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false) - || mStreamType == AudioManager.STREAM_RING + if (mNotifAliasRing || mStreamType == AudioManager.STREAM_RING || (mStreamType == AudioManager.STREAM_NOTIFICATION && mMuted)) { mSeekBar.setProgress(0, true); } @@ -369,9 +365,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba // set the time of stop volume if ((mStreamType == AudioManager.STREAM_VOICE_CALL || mStreamType == AudioManager.STREAM_RING - || (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false) - && mStreamType == AudioManager.STREAM_NOTIFICATION) + || (!mNotifAliasRing && mStreamType == AudioManager.STREAM_NOTIFICATION) || mStreamType == AudioManager.STREAM_ALARM)) { sStopVolumeTime = java.lang.System.currentTimeMillis(); } @@ -649,10 +643,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } private void updateVolumeSlider(int streamType, int streamValue) { - final boolean streamMatch = !DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false) - && mNotificationOrRing ? isNotificationOrRing(streamType) : - streamType == mStreamType; + final boolean streamMatch = mNotifAliasRing && mNotificationOrRing + ? isNotificationOrRing(streamType) : streamType == mStreamType; if (mSeekBar != null && streamMatch && streamValue != -1) { final boolean muted = mAudioManager.isStreamMute(mStreamType) || streamValue == 0; diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index 4f7f8ba2b45c6..b916878ff4612 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -561,11 +561,6 @@ public final class SystemUiDeviceConfigFlags { public static final String TASK_MANAGER_SHOW_USER_VISIBLE_JOBS = "task_manager_show_user_visible_jobs"; - /** - * (boolean) Whether to show notification volume control slider separate from ring. - */ - public static final String VOLUME_SEPARATE_NOTIFICATION = "volume_separate_notification"; - /** * (boolean) Whether the clipboard overlay is enabled. */ diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 2f5efd12a2ba8..11629cb91b00a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2074,6 +2074,10 @@ STREAM_MUSIC as if it's on TV platform. --> false + + true + 7 diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 41281fa0d40fe..cdf625c03abd1 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -278,6 +278,7 @@ + diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index c804ef2cf8b47..96395c89af916 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -41,7 +41,6 @@ import android.annotation.SuppressLint; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityThread; import android.app.AlarmManager; import android.app.AppGlobals; import android.app.AppOpsManager; @@ -153,7 +152,6 @@ import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; import android.os.VibratorManager; -import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.System; import android.service.notification.ZenModeConfig; @@ -175,7 +173,6 @@ import android.widget.Toast; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; @@ -234,7 +231,6 @@ public class AudioService extends IAudioService.Stub AudioSystemAdapter.OnVolRangeInitRequestListener { private static final String TAG = "AS.AudioService"; - private static final boolean CONFIG_DEFAULT_VAL = false; private final AudioSystemAdapter mAudioSystem; private final SystemServerAdapter mSystemServer; @@ -989,7 +985,6 @@ public class AudioService extends IAudioService.Stub * @param looper Looper to use for the service's message handler. If this is null, an * {@link AudioSystemThread} is created as the messaging thread instead. */ - @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper, AppOpsManager appOps) { @@ -1029,12 +1024,8 @@ public class AudioService extends IAudioService.Stub mUseVolumeGroupAliases = mContext.getResources().getBoolean( com.android.internal.R.bool.config_handleVolumeAliasesUsingVolumeGroups); - mNotifAliasRing = !DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false); - - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, - ActivityThread.currentApplication().getMainExecutor(), - this::onDeviceConfigChange); + mNotifAliasRing = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_alias_ring_notif_stream_types); // Initialize volume // Priority 1 - Android Property @@ -1252,22 +1243,6 @@ public class AudioService extends IAudioService.Stub 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */); } - /** - * Separating notification volume from ring is NOT of aliasing the corresponding streams - * @param properties - */ - private void onDeviceConfigChange(DeviceConfig.Properties properties) { - Set changeSet = properties.getKeyset(); - if (changeSet.contains(SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION)) { - boolean newNotifAliasRing = !properties.getBoolean( - SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, CONFIG_DEFAULT_VAL); - if (mNotifAliasRing != newNotifAliasRing) { - mNotifAliasRing = newNotifAliasRing; - updateStreamVolumeAlias(true, TAG); - } - } - } - /** * Called by handling of MSG_INIT_STREAMS_VOLUMES */ From cbcb3ba0e5ed4c5cb8db77577b7ca37f74e68c38 Mon Sep 17 00:00:00 2001 From: Behnam Heydarshahi Date: Thu, 26 Jan 2023 21:17:04 +0000 Subject: [PATCH 22/23] DO NOT MERGE ANYWHERE Revert "Change volume ringer icon based on device config" This reverts commit 903b3025a7e5caaddae848376bd12b62e698315c. Reason for revert: b/261809910 fixing for qpr2 Change-Id: Ica3ef9df1470fd2b5e20fc8caa3bdf6647a21426 (cherry picked from commit 1bdb0b76bfa439abf6cddb11e752aec3499d8f03) Merged-In: Ica3ef9df1470fd2b5e20fc8caa3bdf6647a21426 --- .../SystemUI/res/drawable/ic_ring_volume.xml | 26 ----- .../res/drawable/ic_ring_volume_off.xml | 34 ------ .../SystemUI/res/drawable/ic_speaker_mute.xml | 25 ---- .../SystemUI/res/drawable/ic_speaker_on.xml | 25 ---- .../systemui/volume/VolumeDialogImpl.java | 108 ++---------------- .../systemui/volume/dagger/VolumeModule.java | 8 -- .../systemui/volume/VolumeDialogImplTest.java | 45 -------- 7 files changed, 8 insertions(+), 263 deletions(-) delete mode 100644 packages/SystemUI/res/drawable/ic_ring_volume.xml delete mode 100644 packages/SystemUI/res/drawable/ic_ring_volume_off.xml delete mode 100644 packages/SystemUI/res/drawable/ic_speaker_mute.xml delete mode 100644 packages/SystemUI/res/drawable/ic_speaker_on.xml diff --git a/packages/SystemUI/res/drawable/ic_ring_volume.xml b/packages/SystemUI/res/drawable/ic_ring_volume.xml deleted file mode 100644 index 343fe5d4cb698..0000000000000 --- a/packages/SystemUI/res/drawable/ic_ring_volume.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_ring_volume_off.xml b/packages/SystemUI/res/drawable/ic_ring_volume_off.xml deleted file mode 100644 index 74f30d1a44d25..0000000000000 --- a/packages/SystemUI/res/drawable/ic_ring_volume_off.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - diff --git a/packages/SystemUI/res/drawable/ic_speaker_mute.xml b/packages/SystemUI/res/drawable/ic_speaker_mute.xml deleted file mode 100644 index 4e402cf530e4b..0000000000000 --- a/packages/SystemUI/res/drawable/ic_speaker_mute.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_speaker_on.xml b/packages/SystemUI/res/drawable/ic_speaker_on.xml deleted file mode 100644 index 2a90e051b83bc..0000000000000 --- a/packages/SystemUI/res/drawable/ic_speaker_on.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index db1853d37817e..db3fd41cc95b0 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -72,7 +72,6 @@ import android.os.Message; import android.os.SystemClock; import android.os.Trace; import android.os.VibrationEffect; -import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.Global; import android.text.InputFilter; @@ -109,8 +108,6 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.graphics.drawable.BackgroundBlurDrawable; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.view.RotationPolicy; @@ -130,15 +127,11 @@ import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.util.AlphaTintDrawableWrapper; -import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.RoundedCornerProgressDrawable; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.Executor; import java.util.function.Consumer; /** @@ -195,9 +188,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private ViewGroup mDialogRowsView; private ViewGroup mRinger; - private DeviceConfigProxy mDeviceConfigProxy; - private Executor mExecutor; - /** * Container for the top part of the dialog, which contains the ringer, the ringer drawer, the * volume rows, and the ellipsis button. This does not include the live caption button. @@ -286,13 +276,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private BackgroundBlurDrawable mDialogRowsViewBackground; private final InteractionJankMonitor mInteractionJankMonitor; - private boolean mSeparateNotification; - - @VisibleForTesting - int mVolumeRingerIconDrawableId; - @VisibleForTesting - int mVolumeRingerMuteIconDrawableId; - public VolumeDialogImpl( Context context, VolumeDialogController volumeDialogController, @@ -303,8 +286,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, VolumePanelFactory volumePanelFactory, ActivityStarter activityStarter, InteractionJankMonitor interactionJankMonitor, - DeviceConfigProxy deviceConfigProxy, - Executor executor, DumpManager dumpManager) { mContext = new ContextThemeWrapper(context, R.style.volume_dialog_theme); @@ -347,50 +328,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, } initDimens(); - - mDeviceConfigProxy = deviceConfigProxy; - mExecutor = executor; - mSeparateNotification = mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false); - updateRingerModeIconSet(); - } - - /** - * If ringer and notification are the same stream (T and earlier), use notification-like bell - * icon set. - * If ringer and notification are separated, then use generic speaker icons. - */ - private void updateRingerModeIconSet() { - if (mSeparateNotification) { - mVolumeRingerIconDrawableId = R.drawable.ic_speaker_on; - mVolumeRingerMuteIconDrawableId = R.drawable.ic_speaker_mute; - } else { - mVolumeRingerIconDrawableId = R.drawable.ic_volume_ringer; - mVolumeRingerMuteIconDrawableId = R.drawable.ic_volume_ringer_mute; - } - - if (mRingerDrawerMuteIcon != null) { - mRingerDrawerMuteIcon.setImageResource(mVolumeRingerMuteIconDrawableId); - } - if (mRingerDrawerNormalIcon != null) { - mRingerDrawerNormalIcon.setImageResource(mVolumeRingerIconDrawableId); - } - } - - /** - * Change icon for ring stream (not ringer mode icon) - */ - private void updateRingRowIcon() { - Optional volumeRow = mRows.stream().filter(row -> row.stream == STREAM_RING) - .findFirst(); - if (volumeRow.isPresent()) { - VolumeRow volRow = volumeRow.get(); - volRow.iconRes = mSeparateNotification ? R.drawable.ic_ring_volume - : R.drawable.ic_volume_ringer; - volRow.iconMuteRes = mSeparateNotification ? R.drawable.ic_ring_volume_off - : R.drawable.ic_volume_ringer_mute; - volRow.setIcon(volRow.iconRes, mContext.getTheme()); - } } @Override @@ -407,9 +344,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mController.getState(); mConfigurationController.addCallback(this); - - mDeviceConfigProxy.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, - mExecutor, this::onDeviceConfigChange); } @Override @@ -417,24 +351,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mController.removeCallback(mControllerCallbackH); mHandler.removeCallbacksAndMessages(null); mConfigurationController.removeCallback(this); - mDeviceConfigProxy.removeOnPropertiesChangedListener(this::onDeviceConfigChange); - } - - /** - * Update ringer mode icon based on the config - */ - private void onDeviceConfigChange(DeviceConfig.Properties properties) { - Set changeSet = properties.getKeyset(); - if (changeSet.contains(SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION)) { - boolean newVal = properties.getBoolean( - SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false); - if (newVal != mSeparateNotification) { - mSeparateNotification = newVal; - updateRingerModeIconSet(); - updateRingRowIcon(); - - } - } } @Override @@ -641,8 +557,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mRingerDrawerNormalIcon = mDialog.findViewById(R.id.volume_drawer_normal_icon); mRingerDrawerNewSelectionBg = mDialog.findViewById(R.id.volume_drawer_selection_background); - updateRingerModeIconSet(); - setupRingerDrawer(); mODICaptionsView = mDialog.findViewById(R.id.odi_captions); @@ -666,14 +580,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, addRow(AudioManager.STREAM_MUSIC, R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true, true); if (!AudioSystem.isSingleVolume(mContext)) { - if (mSeparateNotification) { - addRow(AudioManager.STREAM_RING, R.drawable.ic_ring_volume, - R.drawable.ic_ring_volume_off, true, false); - } else { - addRow(AudioManager.STREAM_RING, R.drawable.ic_volume_ringer, - R.drawable.ic_volume_ringer, true, false); - } - + addRow(AudioManager.STREAM_RING, + R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true, false); addRow(STREAM_ALARM, R.drawable.ic_alarm, R.drawable.ic_volume_alarm_mute, true, false); addRow(AudioManager.STREAM_VOICE_CALL, @@ -1632,8 +1540,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mRingerIcon.setTag(Events.ICON_STATE_VIBRATE); break; case AudioManager.RINGER_MODE_SILENT: - mRingerIcon.setImageResource(mVolumeRingerMuteIconDrawableId); - mSelectedRingerIcon.setImageResource(mVolumeRingerMuteIconDrawableId); + mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute); + mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute); mRingerIcon.setTag(Events.ICON_STATE_MUTE); addAccessibilityDescription(mRingerIcon, RINGER_MODE_SILENT, mContext.getString(R.string.volume_ringer_hint_unmute)); @@ -1642,14 +1550,14 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, default: boolean muted = (mAutomute && ss.level == 0) || ss.muted; if (!isZenMuted && muted) { - mRingerIcon.setImageResource(mVolumeRingerMuteIconDrawableId); - mSelectedRingerIcon.setImageResource(mVolumeRingerMuteIconDrawableId); + mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute); + mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute); addAccessibilityDescription(mRingerIcon, RINGER_MODE_NORMAL, mContext.getString(R.string.volume_ringer_hint_unmute)); mRingerIcon.setTag(Events.ICON_STATE_MUTE); } else { - mRingerIcon.setImageResource(mVolumeRingerIconDrawableId); - mSelectedRingerIcon.setImageResource(mVolumeRingerIconDrawableId); + mRingerIcon.setImageResource(R.drawable.ic_volume_ringer); + mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer); if (mController.hasVibrator()) { addAccessibilityDescription(mRingerIcon, RINGER_MODE_NORMAL, mContext.getString(R.string.volume_ringer_hint_vibrate)); diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java index 0ab6c690e1e14..bd420339b948b 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java @@ -20,7 +20,6 @@ import android.content.Context; import android.media.AudioManager; import com.android.internal.jank.InteractionJankMonitor; -import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.media.dialog.MediaOutputDialogFactory; import com.android.systemui.plugins.ActivityStarter; @@ -29,14 +28,11 @@ import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.volume.VolumeComponent; import com.android.systemui.volume.VolumeDialogComponent; import com.android.systemui.volume.VolumeDialogImpl; import com.android.systemui.volume.VolumePanelFactory; -import java.util.concurrent.Executor; - import dagger.Binds; import dagger.Module; import dagger.Provides; @@ -61,8 +57,6 @@ public interface VolumeModule { VolumePanelFactory volumePanelFactory, ActivityStarter activityStarter, InteractionJankMonitor interactionJankMonitor, - DeviceConfigProxy deviceConfigProxy, - @Main Executor executor, DumpManager dumpManager) { VolumeDialogImpl impl = new VolumeDialogImpl( context, @@ -74,8 +68,6 @@ public interface VolumeModule { volumePanelFactory, activityStarter, interactionJankMonitor, - deviceConfigProxy, - executor, dumpManager); impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false); impl.setAutomute(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index c3c6975af870a..0f9988cf0595e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -18,7 +18,6 @@ package com.android.systemui.volume; import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS; -import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -29,7 +28,6 @@ import static org.mockito.Mockito.verify; import android.app.KeyguardManager; import android.media.AudioManager; import android.os.SystemClock; -import android.provider.DeviceConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.InputDevice; @@ -40,7 +38,6 @@ import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.jank.InteractionJankMonitor; import com.android.systemui.Prefs; import com.android.systemui.R; @@ -53,9 +50,6 @@ import com.android.systemui.plugins.VolumeDialogController.State; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.systemui.util.DeviceConfigProxyFake; -import com.android.systemui.util.concurrency.FakeExecutor; -import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -78,8 +72,6 @@ public class VolumeDialogImplTest extends SysuiTestCase { View mDrawerVibrate; View mDrawerMute; View mDrawerNormal; - private DeviceConfigProxyFake mDeviceConfigProxy; - private FakeExecutor mExecutor; @Mock VolumeDialogController mVolumeDialogController; @@ -108,9 +100,6 @@ public class VolumeDialogImplTest extends SysuiTestCase { getContext().addMockSystemService(KeyguardManager.class, mKeyguard); - mDeviceConfigProxy = new DeviceConfigProxyFake(); - mExecutor = new FakeExecutor(new FakeSystemClock()); - mDialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, @@ -121,8 +110,6 @@ public class VolumeDialogImplTest extends SysuiTestCase { mVolumePanelFactory, mActivityStarter, mInteractionJankMonitor, - mDeviceConfigProxy, - mExecutor, mDumpManager ); mDialog.init(0, null); @@ -141,9 +128,6 @@ public class VolumeDialogImplTest extends SysuiTestCase { VolumePrefs.SHOW_RINGER_TOAST_COUNT + 1); Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false); - - mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "false", false); } private State createShellState() { @@ -313,35 +297,6 @@ public class VolumeDialogImplTest extends SysuiTestCase { AudioManager.RINGER_MODE_NORMAL, false); } - /** - * Ideally we would look at the ringer ImageView and check its assigned drawable id, but that - * API does not exist. So we do the next best thing; we check the cached icon id. - */ - @Test - public void notificationVolumeSeparated_theRingerIconChanges() { - mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "true", false); - - mExecutor.runAllReady(); // for the config change to take effect - - // assert icon is new based on res id - assertEquals(mDialog.mVolumeRingerIconDrawableId, - R.drawable.ic_speaker_on); - assertEquals(mDialog.mVolumeRingerMuteIconDrawableId, - R.drawable.ic_speaker_mute); - } - - @Test - public void notificationVolumeNotSeparated_theRingerIconRemainsTheSame() { - mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "false", false); - - mExecutor.runAllReady(); - - assertEquals(mDialog.mVolumeRingerIconDrawableId, R.drawable.ic_volume_ringer); - assertEquals(mDialog.mVolumeRingerMuteIconDrawableId, R.drawable.ic_volume_ringer_mute); - } - /* @Test public void testContentDescriptions() { From 74caed951ff202c9af05406677ddd16ed29b2ad8 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Fri, 2 Sep 2022 13:29:39 +0000 Subject: [PATCH 23/23] Validate package name passed to setApplicationRestrictions. (Reland) This adds validation that the package name passed to setApplicationRestrictions is in the correct format. This will avoid an issue where a path could be entered resulting in a file being written to an unexpected place. Bug: 239701237 Merged-In: I1ab2b7228470f10ec26fe3a608ae540cfc9e9a96 Change-Id: I56c2fc14f906cdad80181ab577e2ebc276c151c1 (cherry picked from commit 1b9b59c63bffc675a042cba6cd666831abef2c3e) Merged-In: I56c2fc14f906cdad80181ab577e2ebc276c151c1 --- .../android/server/pm/UserManagerService.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 00fb0651adc4e..c2dd32667bc2f 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -95,6 +95,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; +import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.IntArray; import android.util.Slog; @@ -4970,6 +4971,13 @@ public class UserManagerService extends IUserManager.Stub { public void setApplicationRestrictions(String packageName, Bundle restrictions, @UserIdInt int userId) { checkSystemOrRoot("set application restrictions"); + String validationResult = validateName(packageName); + if (validationResult != null) { + if (packageName.contains("../")) { + EventLog.writeEvent(0x534e4554, "239701237", -1, ""); + } + throw new IllegalArgumentException("Invalid package name: " + validationResult); + } if (restrictions != null) { restrictions.setDefusable(true); } @@ -4996,6 +5004,39 @@ public class UserManagerService extends IUserManager.Stub { mContext.sendBroadcastAsUser(changeIntent, UserHandle.of(userId)); } + /** + * Check if the given name is valid. + * + * Note: the logic is taken from FrameworkParsingPackageUtils in master, edited to remove + * unnecessary parts. Copied here for a security fix. + * + * @param name The name to check. + * @return null if it's valid, error message if not + */ + @VisibleForTesting + static String validateName(String name) { + final int n = name.length(); + boolean front = true; + for (int i = 0; i < n; i++) { + final char c = name.charAt(i); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + front = false; + continue; + } + if (!front) { + if ((c >= '0' && c <= '9') || c == '_') { + continue; + } + if (c == '.') { + front = true; + continue; + } + } + return "bad character '" + c + "'"; + } + return null; + } + private int getUidForPackage(String packageName) { final long ident = Binder.clearCallingIdentity(); try {