diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index ad8ae75edc236..548fd27c55b2e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -253,6 +253,7 @@ public final class NotificationPanelViewController implements Dumpable { public static final float FLING_SPEED_UP_FACTOR = 0.6f; public static final float FLING_CLOSING_MAX_LENGTH_SECONDS = 0.6f; public static final float FLING_CLOSING_SPEED_UP_FACTOR = 0.6f; + public static final int WAKEUP_ANIMATION_DELAY_MS = 250; private static final boolean DEBUG_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG); private static final boolean SPEW_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE); private static final boolean DEBUG_DRAWABLE = false; @@ -275,6 +276,7 @@ public final class NotificationPanelViewController implements Dumpable { private static final int NO_FIXED_DURATION = -1; private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L; private static final long SHADE_OPEN_SPRING_BACK_DURATION = 400L; + /** * The factor of the usual high velocity that is needed in order to reach the maximum overshoot * when flinging. A low value will make it that most flings will reach the maximum overshoot. 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 8874f59d6c175..29b1bd9cec1a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -84,7 +84,7 @@ class NotificationWakeUpCoordinator @Inject constructor( var fullyAwake: Boolean = false var wakingUp = false - set(value) { + private set(value) { field = value willWakeUp = false if (value) { @@ -294,6 +294,21 @@ class NotificationWakeUpCoordinator @Inject constructor( } } + /** + * Notifies the wakeup coordinator that we're waking up. + * + * [requestDelayedAnimation] is used to request that we delay the start of the wakeup animation + * in order to wait for a potential fingerprint authentication to arrive, since unlocking during + * the wakeup animation looks chaotic. + */ + fun setWakingUp( + wakingUp: Boolean, + requestDelayedAnimation: Boolean, + ) { + this.wakingUp = wakingUp + // TODO(jeffdq): Delay the wakeup animation if we're pressing to unlock. + } + override fun onStateChanged(newState: Int) { logger.logOnStateChanged(newState = newState, storedState = state) if (state == StatusBarState.SHADE && newState == StatusBarState.SHADE) { @@ -500,6 +515,10 @@ class NotificationWakeUpCoordinator @Inject constructor( pw.println("canShowPulsingHuns: $canShowPulsingHuns") } + fun logClockTransitionAnimationStarting(delayWakeUpAnimation: Boolean) { + logger.logClockTransitionAnimationStarting(delayWakeUpAnimation) + } + interface WakeUpListener { /** * Called whenever the notifications are fully hidden or shown diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt index 88d9ffcdcf3e8..0634c8a00b4fb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt @@ -114,6 +114,15 @@ constructor(@NotificationLockscreenLog private val buffer: LogBuffer) { } ) } + + fun logClockTransitionAnimationStarting(delayWakeUpAnimation: Boolean) { + buffer.log( + TAG, + DEBUG, + { bool1 = delayWakeUpAnimation }, + { "clockTransitionAnimationStarting() withDelay=$bool1" } + ) + } } private const val TAG = "NotificationWakeUpCoordinator" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index 311728fff6aa9..b62450b22889b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -53,6 +53,7 @@ import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.NotificationShadeWindowViewController; import com.android.systemui.statusbar.LightRevealScrim; import com.android.systemui.statusbar.NotificationPresenter; +import com.android.systemui.util.Compile; import java.io.PrintWriter; @@ -71,6 +72,7 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn boolean DEBUG_MEDIA_FAKE_ARTWORK = false; boolean DEBUG_CAMERA_LIFT = false; boolean DEBUG_WINDOW_STATE = false; + boolean DEBUG_WAKEUP_DELAY = Compile.IS_DEBUG; // additional instrumentation for testing purposes; intended to be left on during development boolean CHATTY = DEBUG; boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true; @@ -536,6 +538,8 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn void extendDozePulse(); + boolean shouldDelayWakeUpAnimation(); + public static class KeyboardShortcutsMessage { final int mDeviceId; 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 191302547458c..1fb9c5b60b091 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -69,6 +69,7 @@ import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.graphics.Point; import android.hardware.devicestate.DeviceStateManager; +import android.hardware.fingerprint.FingerprintManager; import android.metrics.LogMaker; import android.net.Uri; import android.os.Binder; @@ -257,6 +258,7 @@ import java.util.concurrent.Executor; import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Provider; import dagger.Lazy; @@ -446,10 +448,20 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting DozeServiceHost mDozeServiceHost; - private boolean mWakeUpComingFromTouch; private LightRevealScrim mLightRevealScrim; private PowerButtonReveal mPowerButtonReveal; + private boolean mWakeUpComingFromTouch; + + /** + * Whether we should delay the wakeup animation (which shows the notifications and moves the + * clock view). This is typically done when waking up from a 'press to unlock' gesture on a + * device with a side fingerprint sensor, so that if the fingerprint scan is successful, we + * can play the unlock animation directly rather than interrupting the wakeup animation part + * way through. + */ + private boolean mShouldDelayWakeUpAnimation = false; + private final Object mQueueLock = new Object(); private final PulseExpansionHandler mPulseExpansionHandler; @@ -510,6 +522,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private final MessageRouter mMessageRouter; private final WallpaperManager mWallpaperManager; private final UserTracker mUserTracker; + private final Provider mFingerprintManager; private CentralSurfacesComponent mCentralSurfacesComponent; @@ -753,7 +766,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { Lazy cameraLauncherLazy, Lazy lightRevealScrimViewModelLazy, AlternateBouncerInteractor alternateBouncerInteractor, - UserTracker userTracker + UserTracker userTracker, + Provider fingerprintManager ) { mContext = context; mNotificationsController = notificationsController; @@ -834,6 +848,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mCameraLauncherLazy = cameraLauncherLazy; mAlternateBouncerInteractor = alternateBouncerInteractor; mUserTracker = userTracker; + mFingerprintManager = fingerprintManager; mLockscreenShadeTransitionController = lockscreenShadeTransitionController; mStartingSurfaceOptional = startingSurfaceOptional; @@ -3149,6 +3164,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } } + public boolean shouldDelayWakeUpAnimation() { + return mShouldDelayWakeUpAnimation; + } + private void updateDozingState() { Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0); Trace.beginSection("CentralSurfaces#updateDozingState"); @@ -3159,11 +3178,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { boolean keyguardVisibleOrWillBe = keyguardVisible || (mDozing && mDozeParameters.shouldDelayKeyguardShow()); - boolean wakeAndUnlock = mBiometricUnlockController.getMode() - == BiometricUnlockController.MODE_WAKE_AND_UNLOCK; - boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup() && !wakeAndUnlock) - || (mDozing && mDozeParameters.shouldControlScreenOff() - && keyguardVisibleOrWillBe); + boolean animate = (!mDozing && shouldAnimateDozeWakeup()) + || (mDozing && mDozeParameters.shouldControlScreenOff() && keyguardVisibleOrWillBe); mNotificationPanelViewController.setDozing(mDozing, animate); updateQsExpansionEnabled(); @@ -3516,7 +3532,42 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { DejankUtils.startDetectingBlockingIpcs(tag); mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> { mDeviceInteractive = true; - mWakeUpCoordinator.setWakingUp(true); + + if (shouldAnimateDozeWakeup()) { + // If this is false, the power button must be physically pressed in order to + // trigger fingerprint authentication. + final boolean touchToUnlockAnytime = Settings.Secure.getIntForUser( + mContext.getContentResolver(), + Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED, + -1, + mUserTracker.getUserId()) > 0; + + // Delay if we're waking up, not mid-doze animation (which means we are + // cancelling a sleep), from the power button, on a device with a power button + // FPS, and 'press to unlock' is required. + mShouldDelayWakeUpAnimation = + !isPulsing() + && mStatusBarStateController.getDozeAmount() == 1f + && mWakefulnessLifecycle.getLastWakeReason() + == PowerManager.WAKE_REASON_POWER_BUTTON + && mFingerprintManager.get().isPowerbuttonFps() + && mFingerprintManager.get().hasEnrolledFingerprints() + && !touchToUnlockAnytime; + if (DEBUG_WAKEUP_DELAY) { + Log.d(TAG, "mShouldDelayWakeUpAnimation=" + mShouldDelayWakeUpAnimation); + } + } else { + // If we're not animating anyway, we do not need to delay it. + mShouldDelayWakeUpAnimation = false; + if (DEBUG_WAKEUP_DELAY) { + Log.d(TAG, "mShouldDelayWakeUpAnimation CLEARED"); + } + } + + mWakeUpCoordinator.setWakingUp( + /* wakingUp= */ true, + mShouldDelayWakeUpAnimation); + if (!mKeyguardBypassController.getBypassEnabled()) { mHeadsUpManager.releaseAllImmediately(); } @@ -3543,7 +3594,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @Override public void onFinishedWakingUp() { mWakeUpCoordinator.setFullyAwake(true); - mWakeUpCoordinator.setWakingUp(false); + mWakeUpCoordinator.setWakingUp(false, false); if (mKeyguardStateController.isOccluded() && !mDozeParameters.canControlUnlockedScreenOff()) { // When the keyguard is occluded we don't use the KEYGUARD state which would @@ -4407,4 +4458,15 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } return mUserTracker.getUserHandle(); } + + /** + * Whether we want to animate the wake animation AOD to lockscreen. This is done only if the + * doze service host says we can, and also we're not wake and unlocking (in which case the + * AOD instantly hides). + */ + private boolean shouldAnimateDozeWakeup() { + return mDozeServiceHost.shouldAnimateWakeup() + && mBiometricUnlockController.getMode() + != BiometricUnlockController.MODE_WAKE_AND_UNLOCK; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt index 7a6779684fc5c..bbed2c5126eea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase; +import com.android.systemui.SysuiTestCase import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.plugins.log.LogLevel import com.android.systemui.plugins.log.LogcatEchoTracker diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt index 95591a4b321cd..d055ebe1957c1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase; +import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState 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 bf05d4e43224c..c33438a164826 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 @@ -311,6 +311,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private ViewRootImpl mViewRootImpl; @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher; @Mock private UserTracker mUserTracker; + @Mock private FingerprintManager mFingerprintManager; @Captor private ArgumentCaptor mOnBackInvokedCallback; @Mock IPowerManager mPowerManagerService; @@ -521,7 +522,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mCameraLauncherLazy, () -> mLightRevealScrimViewModel, mAlternateBouncerInteractor, - mUserTracker + mUserTracker, + () -> mFingerprintManager ) { @Override protected ViewRootImpl getViewRootImpl() {