diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml index f9841005e8f72..1630244468e58 100644 --- a/packages/SystemUI/res/layout/super_notification_shade.xml +++ b/packages/SystemUI/res/layout/super_notification_shade.xml @@ -43,12 +43,6 @@ android:visibility="invisible" /> - - + + { - mKeyguardStatusViewAnimating = false; + mKeyguardStatusViewVisibilityAnimating = false; mView.setVisibility(View.INVISIBLE); }; private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = () -> { - mKeyguardStatusViewAnimating = false; + mKeyguardStatusViewVisibilityAnimating = false; mView.setVisibility(View.GONE); }; private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = () -> { - mKeyguardStatusViewAnimating = false; + mKeyguardStatusViewVisibilityAnimating = false; }; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index 0fdaae82e2d00..5c8c9f22d5852 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -96,7 +96,9 @@ public class DozeUi implements DozeMachine.Part { */ private void updateAnimateScreenOff() { if (mCanAnimateTransition) { - final boolean controlScreenOff = mDozeParameters.getAlwaysOn() && mKeyguardShowing + final boolean controlScreenOff = + mDozeParameters.getAlwaysOn() + && (mKeyguardShowing || mDozeParameters.shouldControlUnlockedScreenOff()) && !mHost.isPowerSaveActive(); mDozeParameters.setControlScreenOffAnimation(controlScreenOff); mHost.setAnimateScreenOff(controlScreenOff); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index bf87ac46cff1c..e7326698e43ea 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -92,8 +92,10 @@ import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.navigationbar.NavigationModeController; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.phone.BiometricUnlockController; +import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.StatusBar; @@ -147,7 +149,8 @@ import dagger.Lazy; * directly to the keyguard UI is posted to a {@link android.os.Handler} to ensure it is taken on the UI * thread of the keyguard. */ -public class KeyguardViewMediator extends SystemUI implements Dumpable { +public class KeyguardViewMediator extends SystemUI implements Dumpable, + StatusBarStateController.StateListener { private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000; @@ -221,6 +224,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { private boolean mBootSendUserPresent; private boolean mShuttingDown; private boolean mDozing; + private boolean mAnimatingScreenOff; private final FalsingCollector mFalsingCollector; /** High level access to the power manager for WakeLocks */ @@ -707,6 +711,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { }; private DeviceConfigProxy mDeviceConfig; + private DozeParameters mDozeParameters; /** * Injected constructor. See {@link KeyguardModule}. @@ -723,7 +728,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { TrustManager trustManager, DeviceConfigProxy deviceConfig, NavigationModeController navigationModeController, - KeyguardDisplayManager keyguardDisplayManager) { + KeyguardDisplayManager keyguardDisplayManager, + DozeParameters dozeParameters, + StatusBarStateController statusBarStateController) { super(context); mFalsingCollector = falsingCollector; mLockPatternUtils = lockPatternUtils; @@ -749,6 +756,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { QuickStepContract.isGesturalMode(navigationModeController.addListener(mode -> { mInGestureNavigationMode = QuickStepContract.isGesturalMode(mode); })); + mDozeParameters = dozeParameters; + statusBarStateController.addCallback(this); } public void userActivity() { @@ -929,6 +938,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mDeviceInteractive = false; mGoingToSleep = false; mWakeAndUnlocking = false; + mAnimatingScreenOff = mDozeParameters.shouldControlUnlockedScreenOff(); resetKeyguardDonePendingLocked(); mHideAnimationRun = false; @@ -1081,6 +1091,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { // TODO: Rename all screen off/on references to interactive/sleeping synchronized (this) { mDeviceInteractive = true; + mAnimatingScreenOff = false; cancelDoKeyguardLaterLocked(); cancelDoKeyguardForChildProfilesLocked(); if (DEBUG) Log.d(TAG, "onStartedWakingUp, seq = " + mDelayedShowingSequence); @@ -1294,6 +1305,10 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { return mHiding; } + public boolean isAnimatingScreenOff() { + return mAnimatingScreenOff; + } + /** * Handles SET_OCCLUDED message sent by setOccluded() */ @@ -2266,6 +2281,16 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { setShowingLocked(mShowing); } + @Override + public void onDozeAmountChanged(float linear, float interpolated) { + // If we were animating the screen off, and we've completed the doze animation (doze amount + // is 1f), then show the activity lock screen. + if (mAnimatingScreenOff && mDozing && linear == 1f) { + mAnimatingScreenOff = false; + setShowingLocked(mShowing); + } + } + /** * @param pulsing true when device temporarily wakes up to display an incoming notification. */ @@ -2296,7 +2321,14 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mAodShowing = aodShowing; if (notifyDefaultDisplayCallbacks) { notifyDefaultDisplayCallbacks(showing); - updateActivityLockScreenState(showing, aodShowing); + + if (!showing || !mAnimatingScreenOff) { + // Update the activity lock screen state unless we're animating in the keyguard + // for a screen off animation. In that case, we want the activity to remain visible + // until the animation completes. setShowingLocked is called again when the + // animation ends, so the activity lock screen will be shown at that time. + updateActivityLockScreenState(showing, aodShowing); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 626abfcc85fde..76281d8c0f002 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -43,6 +43,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationShadeWindowController; +import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.DeviceConfigProxy; @@ -82,7 +83,9 @@ public class KeyguardModule { @UiBackground Executor uiBgExecutor, DeviceConfigProxy deviceConfig, NavigationModeController navigationModeController, - KeyguardDisplayManager keyguardDisplayManager) { + KeyguardDisplayManager keyguardDisplayManager, + DozeParameters dozeParameters, + StatusBarStateController statusBarStateController) { return new KeyguardViewMediator( context, falsingCollector, @@ -97,7 +100,9 @@ public class KeyguardModule { trustManager, deviceConfig, navigationModeController, - keyguardDisplayManager + keyguardDisplayManager, + dozeParameters, + statusBarStateController ); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt index 1326d920fe42d..e391250dc8fd6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -96,6 +96,8 @@ class NotificationWakeUpCoordinator @Inject constructor( } } + private var animatingScreenOff = false + private var collapsedEnoughToHide: Boolean = false var pulsing: Boolean = false @@ -232,9 +234,14 @@ class NotificationWakeUpCoordinator @Inject constructor( } override fun onDozeAmountChanged(linear: Float, eased: Float) { - if (updateDozeAmountIfBypass()) { + if (overrideDozeAmountIfBypass()) { return } + + if (overrideDozeAmountIfAnimatingScreenOff(linear)) { + return + } + if (linear != 1.0f && linear != 0.0f && (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) { // Let's notify the scroller that an animation started @@ -257,7 +264,7 @@ class NotificationWakeUpCoordinator @Inject constructor( } override fun onStateChanged(newState: Int) { - updateDozeAmountIfBypass() + overrideDozeAmountIfBypass() if (bypassController.bypassEnabled && newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED && (!statusBarStateController.isDozing || shouldAnimateVisibility())) { @@ -265,6 +272,14 @@ class NotificationWakeUpCoordinator @Inject constructor( setNotificationsVisible(visible = true, increaseSpeed = false, animate = false) setNotificationsVisible(visible = false, increaseSpeed = false, animate = true) } + + // If we want to control the screen off animation, check whether we are going from SHADE to + // KEYGUARD. + if (dozeParameters.shouldControlUnlockedScreenOff()) { + animatingScreenOff = + state == StatusBarState.SHADE && newState == StatusBarState.KEYGUARD + } + this.state = newState } @@ -280,7 +295,11 @@ class NotificationWakeUpCoordinator @Inject constructor( } } - private fun updateDozeAmountIfBypass(): Boolean { + /** + * @return Whether the doze amount was overridden because bypass is enabled. If true, the + * original doze amount should be ignored. + */ + private fun overrideDozeAmountIfBypass(): Boolean { if (bypassController.bypassEnabled) { var amount = 1.0f if (statusBarStateController.state == StatusBarState.SHADE || @@ -293,6 +312,28 @@ class NotificationWakeUpCoordinator @Inject constructor( return false } + /** + * If we're playing the screen off animation, force the notification doze amount to be 1f (fully + * dozing). This is needed so that the notifications aren't briefly visible as the screen turns + * off and dozeAmount goes from 1f to 0f. + * + * @return Whether the doze amount was overridden because we are playing the screen off + * animation. If true, the original doze amount should be ignored. + */ + private fun overrideDozeAmountIfAnimatingScreenOff(linearDozeAmount: Float): Boolean { + if (animatingScreenOff) { + if (linearDozeAmount == 1f) { + animatingScreenOff = false + return false + } + + setDozeAmount(1f, 1f) + return true + } + + return false + } + private fun startVisibilityAnimation(increaseSpeed: Boolean) { if (mNotificationVisibleAmount == 0f || mNotificationVisibleAmount == 1f) { mVisibilityInterpolator = if (mNotificationsVisible) @@ -345,6 +386,8 @@ class NotificationWakeUpCoordinator @Inject constructor( override fun onDozingChanged(isDozing: Boolean) { if (isDozing) { setNotificationsVisible(visible = false, animate = false, increaseSpeed = false) + } else { + animatingScreenOff = false } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 64951448a543f..8c2fa3349e4a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -194,6 +194,16 @@ public class DozeParameters implements TunerService.Tunable, mPowerManager.setDozeAfterScreenOff(!controlScreenOffAnimation); } + /** + * Whether we want to control the screen off animation when the device is unlocked. If we do, + * we'll animate in AOD before turning off the screen, rather than simply fading to black and + * then abruptly showing AOD. + */ + public boolean shouldControlUnlockedScreenOff() { + return getAlwaysOn() && SystemProperties.getBoolean( + "persist.sysui.show_new_screen_on_transitions", false); + } + private boolean getBoolean(String propName, int resId) { return SystemProperties.getBoolean(propName, mResources.getBoolean(resId)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index 1dfd1f3ef69c2..57a64e440bf66 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -196,13 +196,15 @@ public class KeyguardClockPositionAlgorithm { } public void run(Result result) { - final int y = getClockY(mPanelExpansion); + final int y = getClockY(mPanelExpansion, mDarkAmount); result.clockY = y; + result.clockYFullyDozing = getClockY( + 1.0f /* panelExpansion */, 1.0f /* darkAmount */); result.clockAlpha = getClockAlpha(y); result.stackScrollerPadding = mBypassEnabled ? mUnlockedStackScrollerPadding : y + mKeyguardStatusHeight; result.stackScrollerPaddingExpanded = mBypassEnabled ? mUnlockedStackScrollerPadding - : getClockY(1.0f) + mKeyguardStatusHeight; + : getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight; result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount); result.clockScale = interpolate(getBurnInScale(), 1.0f, 1.0f - mDarkAmount); } @@ -259,7 +261,7 @@ public class KeyguardClockPositionAlgorithm { return (int) y; } - private int getClockY(float panelExpansion) { + private int getClockY(float panelExpansion, float darkAmount) { // Dark: Align the bottom edge of the clock at about half of the screen: float clockYDark = (mHasCustomClock ? getPreferredClockY() : getMaxClockY()) + burnInPreventionOffsetY(); @@ -273,7 +275,7 @@ public class KeyguardClockPositionAlgorithm { float clockY = MathUtils.lerp(clockYBouncer, clockYRegular, shadeExpansion); clockYDark = MathUtils.lerp(clockYBouncer, clockYDark, shadeExpansion); - float darkAmount = mBypassEnabled && !mHasCustomClock ? 1.0f : mDarkAmount; + darkAmount = mBypassEnabled && !mHasCustomClock ? 1.0f : darkAmount; if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) { // This will keep the clock at the top but out of the cutout area @@ -295,7 +297,7 @@ public class KeyguardClockPositionAlgorithm { * @return Alpha from 0 to 1. */ private float getClockAlpha(int y) { - float alphaKeyguard = Math.max(0, y / Math.max(1f, getClockY(1f))); + float alphaKeyguard = Math.max(0, y / Math.max(1f, getClockY(1f, mDarkAmount))); alphaKeyguard *= (1f - mQsExpansion); alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard); return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount); @@ -327,6 +329,11 @@ public class KeyguardClockPositionAlgorithm { */ public int clockY; + /** + * The y translation of the clock when we're fully dozing. + */ + public int clockYFullyDozing; + /** * The alpha value of the clock. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 3e0978435e28a..2254ead99c849 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -3617,6 +3617,16 @@ public class NotificationPanelViewController extends PanelViewController { int oldState = mBarState; boolean keyguardShowing = statusBarState == KEYGUARD; + if (mDozeParameters.shouldControlUnlockedScreenOff() && isDozing() && keyguardShowing) { + // This means we're doing the screen off animation - position the keyguard status + // view where it'll be on AOD, so we can animate it in. + mKeyguardStatusViewController.updatePosition( + mClockPositionResult.clockX, + mClockPositionResult.clockYFullyDozing, + mClockPositionResult.clockScale, + false); + } + mKeyguardStatusViewController.setKeyguardStatusViewVisibility( statusBarState, keyguardFadingAway, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 87a3ede629117..e07c3a536f682 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1384,7 +1384,7 @@ public class StatusBar extends SystemUI implements DemoMode, * @param why the reason for the wake up */ public void wakeUpIfDozing(long time, View where, String why) { - if (mDozing) { + if (mDozing && !mKeyguardViewMediator.isAnimatingScreenOff()) { mPowerManager.wakeUp( time, PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:" + why); mWakeUpComingFromTouch = true; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java index 4cfbe69f175f0..0074dbea11518 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java @@ -22,6 +22,7 @@ import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -50,6 +51,8 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase { ConfigurationController mConfigurationController; @Mock NotificationIconAreaController mNotificationIconAreaController; + @Mock + DozeParameters mDozeParameters; private KeyguardStatusViewController mController; @@ -64,7 +67,8 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase { mKeyguardStateController, mKeyguardUpdateMonitor, mConfigurationController, - mNotificationIconAreaController); + mNotificationIconAreaController, + mDozeParameters); } @Test 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 67d0295c82d30..00943bc53bfdd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -44,6 +44,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.navigationbar.NavigationModeController; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; @@ -73,6 +75,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock TrustManager mTrustManager; private @Mock NavigationModeController mNavigationModeController; private @Mock KeyguardDisplayManager mKeyguardDisplayManager; + private @Mock DozeParameters mDozeParameters; + private @Mock StatusBarStateController mStatusBarStateController; private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -91,7 +95,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { () -> mStatusBarKeyguardViewManager, mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor, mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController, - mKeyguardDisplayManager); + mKeyguardDisplayManager, mDozeParameters, mStatusBarStateController); mViewMediator.start(); }