diff --git a/packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt b/packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt new file mode 100644 index 0000000000000..705cf6d5df8ec --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt @@ -0,0 +1,98 @@ +/* + * 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.keyguard.mediator + +import android.os.Trace + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.ScreenLifecycle +import com.android.systemui.util.concurrency.Execution +import com.android.systemui.util.concurrency.PendingTasksContainer +import com.android.systemui.unfold.SysUIUnfoldComponent +import com.android.systemui.util.kotlin.getOrNull + +import java.util.Optional + +import javax.inject.Inject + +/** + * Coordinates screen on/turning on animations for the KeyguardViewMediator. Specifically for + * screen on events, this will invoke the onDrawn Runnable after all tasks have completed. This + * should route back to the KeyguardService, which informs the system_server that keyguard has + * drawn. + */ +@SysUISingleton +class ScreenOnCoordinator @Inject constructor( + screenLifecycle: ScreenLifecycle, + unfoldComponent: Optional, + private val execution: Execution +) : ScreenLifecycle.Observer { + + private val unfoldLightRevealAnimation = unfoldComponent.map( + SysUIUnfoldComponent::getUnfoldLightRevealOverlayAnimation).getOrNull() + private val foldAodAnimationController = unfoldComponent.map( + SysUIUnfoldComponent::getFoldAodAnimationController).getOrNull() + private val pendingTasks = PendingTasksContainer() + + private var wakeAndUnlockingTask: Runnable? = null + var wakeAndUnlocking = false + set(value) { + if (!value && field) { + // When updating the value back to false, mark the task complete in order to + // callback onDrawn + wakeAndUnlockingTask?.run() + wakeAndUnlockingTask = null + } + field = value + } + + init { + screenLifecycle.addObserver(this) + } + + /** + * When turning on, registers tasks that may need to run before invoking [onDrawn]. + */ + override fun onScreenTurningOn(onDrawn: Runnable) { + execution.assertIsMainThread() + Trace.beginSection("ScreenOnCoordinator#onScreenTurningOn") + + pendingTasks.reset() + + unfoldLightRevealAnimation?.onScreenTurningOn(pendingTasks.registerTask("unfold-reveal")) + foldAodAnimationController?.onScreenTurningOn(pendingTasks.registerTask("fold-to-aod")) + + if (wakeAndUnlocking) { + wakeAndUnlockingTask = pendingTasks.registerTask("wake-and-unlocking") + } + + pendingTasks.onTasksComplete { onDrawn.run() } + Trace.endSection() + } + + override fun onScreenTurnedOn() { + execution.assertIsMainThread() + + foldAodAnimationController?.onScreenTurnedOn() + + pendingTasks.reset() + } + + override fun onScreenTurnedOff() { + wakeAndUnlockingTask = null + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java index 5019e65c7182d..32b58c2d1bcad 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java @@ -19,7 +19,10 @@ package com.android.systemui.keyguard; import android.os.Handler; import android.os.Message; import android.os.PowerManager; +import android.os.RemoteException; +import android.util.Log; +import com.android.internal.policy.IKeyguardDrawnCallback; import com.android.systemui.dagger.SysUISingleton; import javax.inject.Inject; @@ -39,6 +42,7 @@ public class KeyguardLifecyclesDispatcher { static final int FINISHED_WAKING_UP = 5; static final int STARTED_GOING_TO_SLEEP = 6; static final int FINISHED_GOING_TO_SLEEP = 7; + private static final String TAG = "KeyguardLifecyclesDispatcher"; private final ScreenLifecycle mScreenLifecycle; private final WakefulnessLifecycle mWakefulnessLifecycle; @@ -65,12 +69,38 @@ public class KeyguardLifecyclesDispatcher { message.sendToTarget(); } + /** + * @param what Message to send. + * @param object Object to send with the message + */ + void dispatch(int what, Object object) { + mHandler.obtainMessage(what, object).sendToTarget(); + } + private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { + final Object obj = msg.obj; switch (msg.what) { case SCREEN_TURNING_ON: - mScreenLifecycle.dispatchScreenTurningOn(); + // Ensure the drawn callback is only ever called once + mScreenLifecycle.dispatchScreenTurningOn(new Runnable() { + boolean mInvoked; + @Override + public void run() { + if (obj == null) return; + if (!mInvoked) { + mInvoked = true; + try { + ((IKeyguardDrawnCallback) obj).onDrawn(); + } catch (RemoteException e) { + Log.w(TAG, "Exception calling onDrawn():", e); + } + } else { + Log.w(TAG, "KeyguardDrawnCallback#onDrawn() invoked > 1 times"); + } + } + }); break; case SCREEN_TURNED_ON: mScreenLifecycle.dispatchScreenTurnedOn(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index fb31d88701515..e88011e0d3fe4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -500,8 +500,8 @@ public class KeyguardService extends Service { public void onScreenTurningOn(IKeyguardDrawnCallback callback) { Trace.beginSection("KeyguardService.mBinder#onScreenTurningOn"); checkPermission(); - mKeyguardViewMediator.onScreenTurningOn(callback); - mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNING_ON); + mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNING_ON, + callback); Trace.endSection(); } @@ -509,7 +509,6 @@ public class KeyguardService extends Service { public void onScreenTurnedOn() { Trace.beginSection("KeyguardService.mBinder#onScreenTurnedOn"); checkPermission(); - mKeyguardViewMediator.onScreenTurnedOn(); mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNED_ON); Trace.endSection(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 7bbd8eec5924c..4658a745b6800 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -87,7 +87,6 @@ import androidx.annotation.Nullable; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.jank.InteractionJankMonitor.Configuration; import com.android.internal.policy.IKeyguardDismissCallback; -import com.android.internal.policy.IKeyguardDrawnCallback; import com.android.internal.policy.IKeyguardExitCallback; import com.android.internal.policy.IKeyguardStateCallback; import com.android.internal.util.LatencyTracker; @@ -99,6 +98,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.KeyguardViewController; import com.android.keyguard.ViewMediatorCallback; +import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.CoreStartable; import com.android.systemui.Dumpable; import com.android.systemui.animation.Interpolators; @@ -122,15 +122,11 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.unfold.FoldAodAnimationController; -import com.android.systemui.unfold.SysUIUnfoldComponent; -import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation; import com.android.systemui.util.DeviceConfigProxy; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Optional; import java.util.concurrent.Executor; import dagger.Lazy; @@ -199,7 +195,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private static final int RESET = 3; private static final int VERIFY_UNLOCK = 4; private static final int NOTIFY_FINISHED_GOING_TO_SLEEP = 5; - private static final int NOTIFY_SCREEN_TURNING_ON = 6; private static final int KEYGUARD_DONE = 7; private static final int KEYGUARD_DONE_DRAWING = 8; private static final int SET_OCCLUDED = 9; @@ -208,8 +203,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private static final int START_KEYGUARD_EXIT_ANIM = 12; private static final int KEYGUARD_DONE_PENDING_TIMEOUT = 13; private static final int NOTIFY_STARTED_WAKING_UP = 14; - private static final int NOTIFY_SCREEN_TURNED_ON = 15; - private static final int NOTIFY_SCREEN_TURNED_OFF = 16; private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17; private static final int SYSTEM_READY = 18; private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19; @@ -433,8 +426,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private boolean mShowHomeOverLockscreen; private boolean mInGestureNavigationMode; - private boolean mWakeAndUnlocking; - private Runnable mWakeAndUnlockingDrawnCallback; private CharSequence mCustomMessage; /** @@ -811,14 +802,11 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private DeviceConfigProxy mDeviceConfig; private DozeParameters mDozeParameters; - private final Optional mUnfoldLightRevealAnimation; - private final Optional mFoldAodAnimationController; - private final PendingDrawnTasksContainer mPendingDrawnTasks = new PendingDrawnTasksContainer(); - private final KeyguardStateController mKeyguardStateController; private final Lazy mKeyguardUnlockAnimationControllerLazy; private final InteractionJankMonitor mInteractionJankMonitor; private boolean mWallpaperSupportsAmbientMode; + private ScreenOnCoordinator mScreenOnCoordinator; /** * Injected constructor. See {@link KeyguardModule}. @@ -838,12 +826,12 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, NavigationModeController navigationModeController, KeyguardDisplayManager keyguardDisplayManager, DozeParameters dozeParameters, - Optional unfoldComponent, SysuiStatusBarStateController statusBarStateController, KeyguardStateController keyguardStateController, Lazy keyguardUnlockAnimationControllerLazy, ScreenOffAnimationController screenOffAnimationController, Lazy notificationShadeDepthController, + ScreenOnCoordinator screenOnCoordinator, InteractionJankMonitor interactionJankMonitor) { super(context); mFalsingCollector = falsingCollector; @@ -860,6 +848,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mKeyguardDisplayManager = keyguardDisplayManager; dumpManager.registerDumpable(getClass().getName(), this); mDeviceConfig = deviceConfig; + mScreenOnCoordinator = screenOnCoordinator; mShowHomeOverLockscreen = mDeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, @@ -874,11 +863,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, })); mDozeParameters = dozeParameters; - mUnfoldLightRevealAnimation = unfoldComponent - .map(SysUIUnfoldComponent::getUnfoldLightRevealOverlayAnimation); - mFoldAodAnimationController = unfoldComponent - .map(SysUIUnfoldComponent::getFoldAodAnimationController); - mStatusBarStateController = statusBarStateController; statusBarStateController.addCallback(this); @@ -1071,7 +1055,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, synchronized (this) { mDeviceInteractive = false; mGoingToSleep = false; - mWakeAndUnlocking = false; + mScreenOnCoordinator.setWakeAndUnlocking(false); mAnimatingScreenOff = mDozeParameters.shouldAnimateDozingChange(); resetKeyguardDonePendingLocked(); @@ -1249,20 +1233,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, Trace.endSection(); } - public void onScreenTurningOn(IKeyguardDrawnCallback callback) { - Trace.beginSection("KeyguardViewMediator#onScreenTurningOn"); - notifyScreenOn(callback); - Trace.endSection(); - } - - public void onScreenTurnedOn() { - Trace.beginSection("KeyguardViewMediator#onScreenTurnedOn"); - notifyScreenTurnedOn(); - Trace.endSection(); - } - public void onScreenTurnedOff() { - notifyScreenTurnedOff(); mUpdateMonitor.dispatchScreenTurnedOff(); } @@ -1654,24 +1625,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mHandler.sendEmptyMessage(NOTIFY_STARTED_WAKING_UP); } - private void notifyScreenOn(IKeyguardDrawnCallback callback) { - if (DEBUG) Log.d(TAG, "notifyScreenOn"); - Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_TURNING_ON, callback); - mHandler.sendMessage(msg); - } - - private void notifyScreenTurnedOn() { - if (DEBUG) Log.d(TAG, "notifyScreenTurnedOn"); - Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_TURNED_ON); - mHandler.sendMessage(msg); - } - - private void notifyScreenTurnedOff() { - if (DEBUG) Log.d(TAG, "notifyScreenTurnedOff"); - Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_TURNED_OFF); - mHandler.sendMessage(msg); - } - /** * Send message to keyguard telling it to show itself * @see #handleShow @@ -1832,21 +1785,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, case NOTIFY_FINISHED_GOING_TO_SLEEP: handleNotifyFinishedGoingToSleep(); break; - case NOTIFY_SCREEN_TURNING_ON: - Trace.beginSection( - "KeyguardViewMediator#handleMessage NOTIFY_SCREEN_TURNING_ON"); - handleNotifyScreenTurningOn((IKeyguardDrawnCallback) msg.obj); - Trace.endSection(); - break; - case NOTIFY_SCREEN_TURNED_ON: - Trace.beginSection( - "KeyguardViewMediator#handleMessage NOTIFY_SCREEN_TURNED_ON"); - handleNotifyScreenTurnedOn(); - Trace.endSection(); - break; - case NOTIFY_SCREEN_TURNED_OFF: - handleNotifyScreenTurnedOff(); - break; case NOTIFY_STARTED_WAKING_UP: Trace.beginSection( "KeyguardViewMediator#handleMessage NOTIFY_STARTED_WAKING_UP"); @@ -2075,7 +2013,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mHiding = false; mKeyguardExitAnimationRunner = null; - mWakeAndUnlocking = false; + mScreenOnCoordinator.setWakeAndUnlocking(false); mPendingLock = false; setShowingLocked(true); mKeyguardViewControllerLazy.get().show(options); @@ -2107,12 +2045,14 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, int flags = 0; if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock() - || mWakeAndUnlocking && !mWallpaperSupportsAmbientMode) { + || mScreenOnCoordinator.getWakeAndUnlocking() + && !mWallpaperSupportsAmbientMode) { flags |= WindowManagerPolicyConstants .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; } if (mKeyguardViewControllerLazy.get().isGoingToNotificationShade() - || mWakeAndUnlocking && mWallpaperSupportsAmbientMode) { + || mScreenOnCoordinator.getWakeAndUnlocking() + && mWallpaperSupportsAmbientMode) { // When the wallpaper supports ambient mode, the scrim isn't fully opaque during // wake and unlock and we should fade in the app on top of the wallpaper flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; @@ -2223,14 +2163,13 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, IRemoteAnimationRunner runner = mKeyguardExitAnimationRunner; mKeyguardExitAnimationRunner = null; - if (mWakeAndUnlocking && mWakeAndUnlockingDrawnCallback != null) { + if (mScreenOnCoordinator.getWakeAndUnlocking()) { // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report // the next draw from here so we don't have to wait for window manager to signal // this to our ViewRootImpl. mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw(); - mWakeAndUnlockingDrawnCallback.run(); - mWakeAndUnlockingDrawnCallback = null; + mScreenOnCoordinator.setWakeAndUnlocking(false); } LatencyTracker.getInstance(mContext) @@ -2354,7 +2293,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, } setShowingLocked(false); - mWakeAndUnlocking = false; + mScreenOnCoordinator.setWakeAndUnlocking(false); mDismissCallbackRegistry.notifyDismissSucceeded(); resetKeyguardDonePendingLocked(); mHideAnimationRun = false; @@ -2561,64 +2500,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, Trace.endSection(); } - private void handleNotifyScreenTurningOn(IKeyguardDrawnCallback callback) { - Trace.beginSection("KeyguardViewMediator#handleNotifyScreenTurningOn"); - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleNotifyScreenTurningOn"); - - mPendingDrawnTasks.reset(); - - if (mUnfoldLightRevealAnimation.isPresent()) { - mUnfoldLightRevealAnimation.get() - .onScreenTurningOn(mPendingDrawnTasks.registerTask("unfold-reveal")); - } - - if (mFoldAodAnimationController.isPresent()) { - mFoldAodAnimationController.get() - .onScreenTurningOn(mPendingDrawnTasks.registerTask("fold-to-aod")); - } - - if (callback != null) { - if (mWakeAndUnlocking) { - mWakeAndUnlockingDrawnCallback = - mPendingDrawnTasks.registerTask("wake-and-unlocking"); - } - } - - mPendingDrawnTasks.onTasksComplete(() -> notifyDrawn(callback)); - } - Trace.endSection(); - } - - private void handleNotifyScreenTurnedOn() { - Trace.beginSection("KeyguardViewMediator#handleNotifyScreenTurnedOn"); - synchronized (this) { - if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOn"); - - mPendingDrawnTasks.reset(); - } - Trace.endSection(); - } - - private void handleNotifyScreenTurnedOff() { - synchronized (this) { - if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOff"); - mWakeAndUnlockingDrawnCallback = null; - } - } - - private void notifyDrawn(final IKeyguardDrawnCallback callback) { - Trace.beginSection("KeyguardViewMediator#notifyDrawn"); - try { - if (callback != null) { - callback.onDrawn(); - } - } catch (RemoteException e) { - Slog.w(TAG, "Exception calling onDrawn():", e); - } - Trace.endSection(); - } - private void resetKeyguardDonePendingLocked() { mKeyguardDonePending = false; mHandler.removeMessages(KEYGUARD_DONE_PENDING_TIMEOUT); @@ -2642,7 +2523,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, public void onWakeAndUnlocking() { Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking"); - mWakeAndUnlocking = true; + mScreenOnCoordinator.setWakeAndUnlocking(true); keyguardDone(); Trace.endSection(); } @@ -2777,9 +2658,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, pw.print(" mHideAnimationRun: "); pw.println(mHideAnimationRun); pw.print(" mPendingReset: "); pw.println(mPendingReset); pw.print(" mPendingLock: "); pw.println(mPendingLock); - pw.print(" mPendingDrawnTasks: "); pw.println(mPendingDrawnTasks.getPendingCount()); - pw.print(" mWakeAndUnlocking: "); pw.println(mWakeAndUnlocking); - pw.print(" mDrawnCallback: "); pw.println(mWakeAndUnlockingDrawnCallback); + pw.print(" wakeAndUnlocking: "); pw.println(mScreenOnCoordinator.getWakeAndUnlocking()); } /** @@ -2853,7 +2732,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, } private void setShowingLocked(boolean showing, boolean forceCallbacks) { - final boolean aodShowing = mDozing && !mWakeAndUnlocking; + final boolean aodShowing = mDozing && !mScreenOnCoordinator.getWakeAndUnlocking(); final boolean notifyDefaultDisplayCallbacks = showing != mShowing || aodShowing != mAodShowing || forceCallbacks; mShowing = showing; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/Lifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/Lifecycle.java index 3da6caf319689..b870f589b746b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/Lifecycle.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/Lifecycle.java @@ -20,6 +20,7 @@ import androidx.annotation.NonNull; import java.util.ArrayList; import java.util.Objects; +import java.util.function.BiConsumer; import java.util.function.Consumer; /** @@ -42,4 +43,13 @@ public class Lifecycle { consumer.accept(mObservers.get(i)); } } + + /** + * Will dispatch the consumer to the observer, along with a single argument of type. + */ + public void dispatch(BiConsumer biConsumer, U arg) { + for (int i = 0; i < mObservers.size(); i++) { + biConsumer.accept(mObservers.get(i), arg); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java index d17c39a81daeb..e71aa854e94a4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java @@ -18,6 +18,8 @@ package com.android.systemui.keyguard; import android.os.Trace; +import androidx.annotation.NonNull; + import com.android.systemui.Dumpable; import com.android.systemui.dump.DumpManager; @@ -49,9 +51,14 @@ public class ScreenLifecycle extends Lifecycle impleme return mScreenState; } - public void dispatchScreenTurningOn() { + /** + * Dispatch screen turning on events to the registered observers + * + * @param onDrawn Invoke to notify the caller that the event has been processed + */ + public void dispatchScreenTurningOn(@NonNull Runnable onDrawn) { setScreenState(SCREEN_TURNING_ON); - dispatch(Observer::onScreenTurningOn); + dispatch(Observer::onScreenTurningOn, onDrawn); } public void dispatchScreenTurnedOn() { @@ -81,7 +88,12 @@ public class ScreenLifecycle extends Lifecycle impleme } public interface Observer { - default void onScreenTurningOn() {} + /** + * Receive the screen turning on event + * + * @param onDrawn Invoke to notify the caller that the event has been processed + */ + default void onScreenTurningOn(@NonNull Runnable onDrawn) {} default void onScreenTurnedOn() {} default void onScreenTurningOff() {} default void onScreenTurnedOff() {} 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 eecb55b3530a2..dd844e8d49abe 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -31,6 +31,7 @@ import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; +import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingModule; @@ -50,11 +51,9 @@ import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.unfold.SysUIUnfoldComponent; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.sensors.AsyncSensorManager; -import java.util.Optional; import java.util.concurrent.Executor; import dagger.Lazy; @@ -93,12 +92,12 @@ public class KeyguardModule { NavigationModeController navigationModeController, KeyguardDisplayManager keyguardDisplayManager, DozeParameters dozeParameters, - Optional unfoldComponent, SysuiStatusBarStateController statusBarStateController, KeyguardStateController keyguardStateController, Lazy keyguardUnlockAnimationController, ScreenOffAnimationController screenOffAnimationController, Lazy notificationShadeDepthController, + ScreenOnCoordinator screenOnCoordinator, InteractionJankMonitor interactionJankMonitor) { return new KeyguardViewMediator( context, @@ -117,12 +116,12 @@ public class KeyguardModule { navigationModeController, keyguardDisplayManager, dozeParameters, - unfoldComponent, statusBarStateController, keyguardStateController, keyguardUnlockAnimationController, screenOffAnimationController, notificationShadeDepthController, + screenOnCoordinator, interactionJankMonitor ); } 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 ec95d5745b846..6f8a3341ccd1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -3592,7 +3592,7 @@ public class StatusBar extends CoreStartable implements final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { @Override - public void onScreenTurningOn() { + public void onScreenTurningOn(Runnable onDrawn) { mFalsingCollector.onScreenTurningOn(); mNotificationPanelViewController.onScreenTurningOn(); } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt index fb9df01a02514..52c416bad8038 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt @@ -19,7 +19,6 @@ package com.android.systemui.unfold import android.os.PowerManager import android.provider.Settings import com.android.systemui.keyguard.KeyguardViewMediator -import com.android.systemui.keyguard.ScreenLifecycle import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.phone.ScreenOffAnimation @@ -36,12 +35,10 @@ import javax.inject.Inject */ @SysUIUnfoldScope class FoldAodAnimationController @Inject constructor( - private val screenLifecycle: ScreenLifecycle, private val keyguardViewMediatorLazy: Lazy, private val wakefulnessLifecycle: WakefulnessLifecycle, private val globalSettings: GlobalSettings -) : ScreenLifecycle.Observer, - CallbackController, +) : CallbackController, ScreenOffAnimation, WakefulnessLifecycle.Observer { @@ -58,7 +55,6 @@ class FoldAodAnimationController @Inject constructor( override fun initialize(statusBar: StatusBar, lightRevealScrim: LightRevealScrim) { this.statusBar = statusBar - screenLifecycle.addObserver(this) wakefulnessLifecycle.addObserver(this) } @@ -123,7 +119,7 @@ class FoldAodAnimationController @Inject constructor( } } - override fun onScreenTurnedOn() { + fun onScreenTurnedOn() { if (shouldPlayAnimation) { statusBar.notificationPanelViewController.startFoldToAodAnimation { // End action diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/PendingDrawnTasksContainer.kt b/packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt similarity index 78% rename from packages/SystemUI/src/com/android/systemui/keyguard/PendingDrawnTasksContainer.kt rename to packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt index a60033cf40fe9..6cd384f17803e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/PendingDrawnTasksContainer.kt +++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.keyguard +package com.android.systemui.util.concurrency import android.os.Trace import java.util.concurrent.atomic.AtomicInteger @@ -23,9 +23,9 @@ import java.util.concurrent.atomic.AtomicReference /** * Allows to wait for multiple callbacks and notify when the last one is executed */ -class PendingDrawnTasksContainer { +class PendingTasksContainer { - private var pendingDrawnTasksCount: AtomicInteger = AtomicInteger(0) + private var pendingTasksCount: AtomicInteger = AtomicInteger(0) private var completionCallback: AtomicReference = AtomicReference() /** @@ -33,19 +33,19 @@ class PendingDrawnTasksContainer { * @return a runnable that should be invoked when the task is finished */ fun registerTask(name: String): Runnable { - pendingDrawnTasksCount.incrementAndGet() + pendingTasksCount.incrementAndGet() if (ENABLE_TRACE) { - Trace.beginAsyncSection("PendingDrawnTasksContainer#$name", 0) + Trace.beginAsyncSection("PendingTasksContainer#$name", 0) } return Runnable { - if (pendingDrawnTasksCount.decrementAndGet() == 0) { + if (pendingTasksCount.decrementAndGet() == 0) { val onComplete = completionCallback.getAndSet(null) onComplete?.run() if (ENABLE_TRACE) { - Trace.endAsyncSection("PendingDrawnTasksContainer#$name", 0) + Trace.endAsyncSection("PendingTasksContainer#$name", 0) } } } @@ -57,7 +57,7 @@ class PendingDrawnTasksContainer { fun reset() { // Create new objects in case if there are pending callbacks from the previous invocations completionCallback = AtomicReference() - pendingDrawnTasksCount = AtomicInteger(0) + pendingTasksCount = AtomicInteger(0) } /** @@ -67,7 +67,7 @@ class PendingDrawnTasksContainer { fun onTasksComplete(onComplete: Runnable) { completionCallback.set(onComplete) - if (pendingDrawnTasksCount.get() == 0) { + if (pendingTasksCount.get() == 0) { val currentOnComplete = completionCallback.getAndSet(null) currentOnComplete?.run() } @@ -76,7 +76,7 @@ class PendingDrawnTasksContainer { /** * Returns current pending tasks count */ - fun getPendingCount(): Int = pendingDrawnTasksCount.get() + fun getPendingCount(): Int = pendingTasksCount.get() } private const val ENABLE_TRACE = false diff --git a/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt new file mode 100644 index 0000000000000..96e6bd15a3e29 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 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.keyguard.mediator + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest + +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.ScreenLifecycle +import com.android.systemui.unfold.FoldAodAnimationController +import com.android.systemui.unfold.SysUIUnfoldComponent +import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation +import com.android.systemui.util.concurrency.FakeExecution +import com.android.systemui.util.mockito.capture + +import java.util.Optional + +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class ScreenOnCoordinatorTest : SysuiTestCase() { + + @Mock + private lateinit var runnable: Runnable + @Mock + private lateinit var unfoldComponent: SysUIUnfoldComponent + @Mock + private lateinit var foldAodAnimationController: FoldAodAnimationController + @Mock + private lateinit var unfoldAnimation: UnfoldLightRevealOverlayAnimation + @Mock + private lateinit var screenLifecycle: ScreenLifecycle + @Captor + private lateinit var readyCaptor: ArgumentCaptor + + private lateinit var screenOnCoordinator: ScreenOnCoordinator + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + `when`(unfoldComponent.getUnfoldLightRevealOverlayAnimation()) + .thenReturn(unfoldAnimation) + `when`(unfoldComponent.getFoldAodAnimationController()) + .thenReturn(foldAodAnimationController) + + screenOnCoordinator = ScreenOnCoordinator( + screenLifecycle, + Optional.of(unfoldComponent), + FakeExecution() + ) + + // Make sure screen events are registered to observe + verify(screenLifecycle).addObserver(screenOnCoordinator) + } + + @Test + fun testUnfoldTransitionEnabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback() { + screenOnCoordinator.onScreenTurningOn(runnable) + + onUnfoldOverlayReady() + onFoldAodReady() + + // Should be called when both unfold overlay and keyguard drawn ready + verify(runnable).run() + } + + @Test + fun testUnfoldTransitionDisabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback() { + // Recreate with empty unfoldComponent + screenOnCoordinator = ScreenOnCoordinator( + screenLifecycle, + Optional.empty(), + FakeExecution() + ) + screenOnCoordinator.onScreenTurningOn(runnable) + + // Should be called when only keyguard drawn + verify(runnable).run() + } + + @Test + fun testWakeAndUnlockDelaysRunnable() { + // GIVEN wakeAndUnlocking has been set to true + screenOnCoordinator.wakeAndUnlocking = true + + // WHEN the screen turns on and two tasks have completed + screenOnCoordinator.onScreenTurningOn(runnable) + onUnfoldOverlayReady() + onFoldAodReady() + + // THEN the runnable should not have run yet + verify(runnable, never()).run() + + // WHEN the value of wakeAndUnlocking changes + screenOnCoordinator.wakeAndUnlocking = false + + // THEN the runnable should have run, as it is the last task to complete + verify(runnable).run() + } + + private fun onUnfoldOverlayReady() { + verify(unfoldAnimation).onScreenTurningOn(capture(readyCaptor)) + readyCaptor.getValue().run() + } + + private fun onFoldAodReady() { + verify(foldAodAnimationController).onScreenTurningOn(capture(readyCaptor)) + readyCaptor.getValue().run() + } +} 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 27fcb11b8dfc4..9827d21e29b07 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -34,7 +34,6 @@ import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; import android.os.PowerManager; import android.os.PowerManager.WakeLock; -import android.os.RemoteException; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -42,10 +41,10 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.internal.jank.InteractionJankMonitor; -import com.android.internal.policy.IKeyguardDrawnCallback; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollectorFake; @@ -58,9 +57,6 @@ import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.unfold.FoldAodAnimationController; -import com.android.systemui.unfold.SysUIUnfoldComponent; -import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; @@ -69,13 +65,9 @@ import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.Optional; -import java.util.function.Function; - @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest @@ -95,36 +87,25 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock NavigationModeController mNavigationModeController; private @Mock KeyguardDisplayManager mKeyguardDisplayManager; private @Mock DozeParameters mDozeParameters; - private @Mock SysUIUnfoldComponent mSysUIUnfoldComponent; - private @Mock UnfoldLightRevealOverlayAnimation mUnfoldAnimation; private @Mock SysuiStatusBarStateController mStatusBarStateController; private @Mock KeyguardStateController mKeyguardStateController; private @Mock NotificationShadeDepthController mNotificationShadeDepthController; private @Mock KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private @Mock ScreenOffAnimationController mScreenOffAnimationController; - private @Mock FoldAodAnimationController mFoldAodAnimationController; - private @Mock IKeyguardDrawnCallback mKeyguardDrawnCallback; private @Mock InteractionJankMonitor mInteractionJankMonitor; + private @Mock ScreenOnCoordinator mScreenOnCoordinator; private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); - private Optional mSysUiUnfoldComponentOptional; - private FalsingCollectorFake mFalsingCollector; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mFalsingCollector = new FalsingCollectorFake(); - mSysUiUnfoldComponentOptional = Optional.of(mSysUIUnfoldComponent); when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager); when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class)); - when(mSysUIUnfoldComponent.getUnfoldLightRevealOverlayAnimation()) - .thenReturn(mUnfoldAnimation); - when(mSysUIUnfoldComponent.getFoldAodAnimationController()) - .thenReturn(mFoldAodAnimationController); - when(mInteractionJankMonitor.begin(any(), anyInt())).thenReturn(true); when(mInteractionJankMonitor.end(anyInt())).thenReturn(true); @@ -150,33 +131,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { verify(mStatusBarKeyguardViewManager).setKeyguardGoingAwayState(eq(false)); } - @Test - @TestableLooper.RunWithLooper(setAsMainLooper = true) - public void testUnfoldTransitionEnabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback() - throws RemoteException { - mViewMediator.onScreenTurningOn(mKeyguardDrawnCallback); - TestableLooper.get(this).processAllMessages(); - onUnfoldOverlayReady(); - onFoldAodReady(); - - // Should be called when both unfold overlay and keyguard drawn ready - verify(mKeyguardDrawnCallback).onDrawn(); - } - - @Test - @TestableLooper.RunWithLooper(setAsMainLooper = true) - public void testUnfoldTransitionDisabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback() - throws RemoteException { - mSysUiUnfoldComponentOptional = Optional.empty(); - createAndStartViewMediator(); - - mViewMediator.onScreenTurningOn(mKeyguardDrawnCallback); - TestableLooper.get(this).processAllMessages(); - - // Should be called when only keyguard drawn - verify(mKeyguardDrawnCallback).onDrawn(); - } - @Test public void testIsAnimatingScreenOff() { when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true); @@ -219,20 +173,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { verify(mStatusBarKeyguardViewManager, atLeast(1)).show(null); } - private void onUnfoldOverlayReady() { - ArgumentCaptor overlayReadyCaptor = ArgumentCaptor.forClass(Runnable.class); - verify(mUnfoldAnimation).onScreenTurningOn(overlayReadyCaptor.capture()); - overlayReadyCaptor.getValue().run(); - TestableLooper.get(this).processAllMessages(); - } - - private void onFoldAodReady() { - ArgumentCaptor ready = ArgumentCaptor.forClass(Runnable.class); - verify(mFoldAodAnimationController).onScreenTurningOn(ready.capture()); - ready.getValue().run(); - TestableLooper.get(this).processAllMessages(); - } - private void createAndStartViewMediator() { mViewMediator = new KeyguardViewMediator( mContext, @@ -251,12 +191,12 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mNavigationModeController, mKeyguardDisplayManager, mDozeParameters, - mSysUiUnfoldComponentOptional, mStatusBarStateController, mKeyguardStateController, () -> mKeyguardUnlockAnimationController, mScreenOffAnimationController, () -> mNotificationShadeDepthController, + mScreenOnCoordinator, mInteractionJankMonitor); mViewMediator.start(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java index 2d1b25806dcc2..53d0dd8f0631a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java @@ -57,15 +57,16 @@ public class ScreenLifecycleTest extends SysuiTestCase { @Test public void screenTurningOn() throws Exception { - mScreen.dispatchScreenTurningOn(); + Runnable onDrawn = () -> {}; + mScreen.dispatchScreenTurningOn(onDrawn); assertEquals(ScreenLifecycle.SCREEN_TURNING_ON, mScreen.getScreenState()); - verify(mScreenObserverMock).onScreenTurningOn(); + verify(mScreenObserverMock).onScreenTurningOn(onDrawn); } @Test public void screenTurnedOn() throws Exception { - mScreen.dispatchScreenTurningOn(); + mScreen.dispatchScreenTurningOn(null); mScreen.dispatchScreenTurnedOn(); assertEquals(ScreenLifecycle.SCREEN_ON, mScreen.getScreenState()); @@ -74,7 +75,7 @@ public class ScreenLifecycleTest extends SysuiTestCase { @Test public void screenTurningOff() throws Exception { - mScreen.dispatchScreenTurningOn(); + mScreen.dispatchScreenTurningOn(null); mScreen.dispatchScreenTurnedOn(); mScreen.dispatchScreenTurningOff(); @@ -84,7 +85,7 @@ public class ScreenLifecycleTest extends SysuiTestCase { @Test public void screenTurnedOff() throws Exception { - mScreen.dispatchScreenTurningOn(); + mScreen.dispatchScreenTurningOn(null); mScreen.dispatchScreenTurnedOn(); mScreen.dispatchScreenTurningOff(); mScreen.dispatchScreenTurnedOff(); @@ -97,4 +98,4 @@ public class ScreenLifecycleTest extends SysuiTestCase { public void dump() throws Exception { mScreen.dump(null, new PrintWriter(new ByteArrayOutputStream()), new String[0]); } -} \ No newline at end of file +}