diff options
33 files changed, 924 insertions, 424 deletions
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java index da9a92a1f6b4..68c8c3e02a42 100644 --- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java +++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java @@ -122,6 +122,11 @@ public interface BcSmartspaceDataPlugin extends Plugin { * Set or clear device media playing */ void setMediaTarget(@Nullable SmartspaceTarget target); + + /** + * Get the index of the currently selected page. + */ + int getSelectedPage(); } /** Interface for launching Intents, which can differ on the lockscreen */ diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 54c798c7d95d..5d092d02a835 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -55,8 +55,8 @@ public class QuickStepContract { // See IStartingWindow.aidl public static final String KEY_EXTRA_SHELL_STARTING_WINDOW = "extra_shell_starting_window"; - // See ISmartspaceTransitionController.aidl - public static final String KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER = "smartspace_transition"; + // See ISysuiUnlockAnimationController.aidl + public static final String KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER = "unlock_animation"; // See IRecentTasks.aidl public static final String KEY_EXTRA_RECENT_TASKS = "recent_tasks"; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ILauncherUnlockAnimationController.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ILauncherUnlockAnimationController.aidl new file mode 100644 index 000000000000..366193c2cc41 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ILauncherUnlockAnimationController.aidl @@ -0,0 +1,44 @@ +/* + * 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.systemui.shared.system.smartspace; + +import com.android.systemui.shared.system.smartspace.SmartspaceState; + +// Methods for System UI to interface with Launcher to perform the unlock animation. +interface ILauncherUnlockAnimationController { + // Prepares Launcher for the unlock animation by setting scale/alpha/etc. to their starting + // values. + void prepareForUnlock(boolean willAnimateSmartspace, int selectedPage); + + // Set the unlock percentage. This is used when System UI is controlling each frame of the + // unlock animation, such as during a swipe to unlock touch gesture. + oneway void setUnlockAmount(float amount); + + // Play a full unlock animation from 0f to 1f. This is used when System UI is unlocking from a + // single action, such as biometric auth, and doesn't need to control individual frames. + oneway void playUnlockAnimation(boolean unlocked, long duration); + + // Set the selected page on Launcher's smartspace. + oneway void setSmartspaceSelectedPage(int selectedPage); + + // Set the visibility of Launcher's smartspace. + void setSmartspaceVisibility(int visibility); + + // Tell SystemUI the smartspace's current state. Launcher code should call this whenever the + // smartspace state may have changed. + oneway void dispatchSmartspaceStateToSysui(); +}
\ No newline at end of file diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl deleted file mode 100644 index 511df4c285b4..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.systemui.shared.system.smartspace; - -import com.android.systemui.shared.system.smartspace.SmartspaceState; - -// Methods for getting and setting the state of a SmartSpace. This is used to allow a remote process -// (such as System UI) to sync with and control a SmartSpace view hosted in another process (such as -// Launcher). -interface ISmartspaceCallback { - - // Return information about the state of the SmartSpace, including location on-screen and - // currently selected page. - SmartspaceState getSmartspaceState(); - - // Set the currently selected page of this SmartSpace. - oneway void setSelectedPage(int selectedPage); - - oneway void setVisibility(int visibility); -}
\ No newline at end of file diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl deleted file mode 100644 index 2b3e961ab3b2..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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.systemui.shared.system.smartspace; - -import com.android.systemui.shared.system.smartspace.ISmartspaceCallback; - -// Controller that keeps track of SmartSpace instances in remote processes (such as Launcher). -interface ISmartspaceTransitionController { - oneway void setSmartspace(ISmartspaceCallback callback); -}
\ No newline at end of file diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISysuiUnlockAnimationController.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISysuiUnlockAnimationController.aidl new file mode 100644 index 000000000000..cf83f62af550 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISysuiUnlockAnimationController.aidl @@ -0,0 +1,33 @@ +/* + * 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.systemui.shared.system.smartspace; + +import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController; +import com.android.systemui.shared.system.smartspace.SmartspaceState; + +// System UI unlock controller. Launcher will provide a LauncherUnlockAnimationController to this +// controller, which System UI will use to control the unlock animation within the Launcher window. +interface ISysuiUnlockAnimationController { + // Provides an implementation of the LauncherUnlockAnimationController to System UI, so that + // SysUI can use it to control the unlock animation in the launcher window. + oneway void setLauncherUnlockController(ILauncherUnlockAnimationController callback); + + // Called by Launcher whenever anything happens to change the state of its smartspace. System UI + // proactively saves this and uses it to perform the unlock animation without needing to make a + // blocking query to Launcher asking about the smartspace state. + oneway void onLauncherSmartspaceStateUpdated(in SmartspaceState state); +}
\ No newline at end of file diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt index 2d51c4d13611..d7e61d60aa55 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt @@ -28,15 +28,18 @@ import android.os.Parcelable class SmartspaceState() : Parcelable { var boundsOnScreen: Rect = Rect() var selectedPage = 0 + var visibleOnScreen = false constructor(parcel: Parcel) : this() { this.boundsOnScreen = parcel.readParcelable(Rect::javaClass.javaClass.classLoader) this.selectedPage = parcel.readInt() + this.visibleOnScreen = parcel.readBoolean() } override fun writeToParcel(dest: Parcel?, flags: Int) { dest?.writeParcelable(boundsOnScreen, 0) dest?.writeInt(selectedPage) + dest?.writeBoolean(visibleOnScreen) } override fun describeContents(): Int { @@ -44,7 +47,9 @@ class SmartspaceState() : Parcelable { } override fun toString(): String { - return "boundsOnScreen: $boundsOnScreen, selectedPage: $selectedPage" + return "boundsOnScreen: $boundsOnScreen, " + + "selectedPage: $selectedPage, " + + "visibleOnScreen: $visibleOnScreen" } companion object CREATOR : Parcelable.Creator<SmartspaceState> { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 25b551139b44..8eb528980a96 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -20,6 +20,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.keyguard.KeyguardClockSwitch.LARGE; +import static com.android.keyguard.KeyguardClockSwitch.SMALL; import android.app.WallpaperManager; import android.content.res.Resources; @@ -41,7 +42,6 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController; import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; @@ -86,6 +86,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS private AnimatableClockController mLargeClockViewController; private FrameLayout mLargeClockFrame; // centered clock + @KeyguardClockSwitch.ClockSize + private int mCurrentClockSize = SMALL; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final KeyguardBypassController mBypassController; @@ -110,7 +113,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS private View mSmartspaceView; private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; - private SmartspaceTransitionController mSmartspaceTransitionController; private boolean mOnlyClock = false; private Executor mUiExecutor; @@ -136,7 +138,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS KeyguardBypassController bypassController, LockscreenSmartspaceController smartspaceController, KeyguardUnlockAnimationController keyguardUnlockAnimationController, - SmartspaceTransitionController smartspaceTransitionController, SecureSettings secureSettings, @Main Executor uiExecutor, @Main Resources resources) { @@ -155,7 +156,22 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mSecureSettings = secureSettings; mUiExecutor = uiExecutor; mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; - mSmartspaceTransitionController = smartspaceTransitionController; + mKeyguardUnlockAnimationController.addKeyguardUnlockAnimationListener( + new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() { + @Override + public void onSmartspaceSharedElementTransitionStarted() { + // The smartspace needs to be able to translate out of bounds in order to + // end up where the launcher's smartspace is, while its container is being + // swiped off the top of the screen. + setClipChildrenForUnlock(false); + } + + @Override + public void onUnlockAnimationFinished() { + // For performance reasons, reset this once the unlock animation ends. + setClipChildrenForUnlock(true); + } + }); } /** @@ -236,7 +252,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mSmartspaceView.setPaddingRelative(startPadding, 0, endPadding, 0); updateClockLayout(); - mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView); + mKeyguardUnlockAnimationController.setLockscreenSmartspace(mSmartspaceView); } mSecureSettings.registerContentObserver( @@ -293,6 +309,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS return; } + mCurrentClockSize = clockSize; + boolean appeared = mView.switchToClock(clockSize, animate); if (animate && appeared && clockSize == LARGE) { mLargeClockViewController.animateAppear(); @@ -368,7 +386,14 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS final Set<View> excludedViews = new HashSet<>(); if (mSmartspaceView != null) { - excludedViews.add(mSmartspaceView); + excludedViews.add(mStatusArea); + } + + // Don't change the alpha of the invisible clock. + if (mCurrentClockSize == LARGE) { + excludedViews.add(mClockFrame); + } else { + excludedViews.add(mLargeClockFrame); } setChildrenAlphaExcluding(alpha, excludedViews); @@ -449,4 +474,16 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mUiExecutor.execute(() -> displayClock(KeyguardClockSwitch.SMALL, /* animate */ true)); } } + + /** + * Sets the clipChildren property on relevant views, to allow the smartspace to draw out of + * bounds during the unlock transition. + */ + private void setClipChildrenForUnlock(boolean clip) { + mView.setClipChildren(clip); + + if (mStatusArea != null) { + mStatusArea.setClipChildren(clip); + } + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 8bf890d7df50..a5fe0efc8887 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -22,7 +22,6 @@ import android.util.Slog; import com.android.keyguard.KeyguardClockSwitch.ClockSize; import com.android.systemui.communal.CommunalStateController; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; -import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.stack.AnimationProperties; @@ -55,7 +54,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private final KeyguardStateController mKeyguardStateController; - private SmartspaceTransitionController mSmartspaceTransitionController; private final Rect mClipBounds = new Rect(); @Inject @@ -69,7 +67,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV ConfigurationController configurationController, DozeParameters dozeParameters, KeyguardUnlockAnimationController keyguardUnlockAnimationController, - SmartspaceTransitionController smartspaceTransitionController, ScreenOffAnimationController screenOffAnimationController) { super(keyguardStatusView); mKeyguardSliceViewController = keyguardSliceViewController; @@ -82,7 +79,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV keyguardStateController, dozeParameters, screenOffAnimationController, /* animateYPos= */ true, /* visibleOnCommunal= */ false); mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; - mSmartspaceTransitionController = smartspaceTransitionController; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 9bc3f176e91a..b96c5aee4673 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -48,7 +48,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.Recents; import com.android.systemui.screenshot.dagger.ScreenshotModule; import com.android.systemui.settings.dagger.SettingsModule; -import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShadeWindowController; @@ -188,12 +187,6 @@ public abstract class SystemUIModule { return SystemUIFactory.getInstance(); } - @SysUISingleton - @Provides - static SmartspaceTransitionController provideSmartspaceTransitionController() { - return new SmartspaceTransitionController(); - } - // TODO: This should provided by the WM component /** Provides Optional of BubbleManager */ @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index 4be819a49772..e24df30bfe34 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -85,7 +85,7 @@ public class Flags { new BooleanFlag(400, true); public static final BooleanFlag SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED = - new BooleanFlag(401, false); + new BooleanFlag(401, true); public static final ResourceBooleanFlag SMARTSPACE = new ResourceBooleanFlag(402, R.bool.flag_smartspace); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt index 69bcf2ec8b8d..582965a12528 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt @@ -21,6 +21,8 @@ import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.content.Context import android.graphics.Matrix +import android.graphics.Rect +import android.os.Handler import android.view.RemoteAnimationTarget import android.view.SyncRtSurfaceTransactionApplier import android.view.View @@ -33,11 +35,17 @@ import com.android.systemui.animation.Interpolators import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController +import com.android.systemui.plugins.BcSmartspaceDataPlugin +import com.android.systemui.shared.system.ActivityManagerWrapper +import com.android.systemui.shared.system.QuickStepContract +import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController +import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController +import com.android.systemui.shared.system.smartspace.SmartspaceState import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.policy.KeyguardStateController import dagger.Lazy import javax.inject.Inject +import kotlin.math.min /** * Starting scale factor for the app/launcher surface behind the keyguard, when it's animating @@ -76,6 +84,25 @@ const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.25f const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.4f /** + * How long the canned unlock animation takes. This is used if we are unlocking from biometric auth, + * from a tap on the unlock icon, or from the bouncer. This is not relevant if the lockscreen is + * swiped away via a touch gesture, or when it's flinging expanded/collapsed after a swipe. + */ +const val UNLOCK_ANIMATION_DURATION_MS = 200L + +/** + * Duration for the alpha animation on the surface behind. This plays to fade in the surface during + * a swipe to unlock (and to fade it back out if the swipe is cancelled). + */ +const val SURFACE_BEHIND_SWIPE_FADE_DURATION_MS = 150L + +/** + * Start delay for the surface behind animation, used so that the lockscreen can get out of the way + * before the surface begins appearing. + */ +const val UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS = 75L + +/** * Initiates, controls, and ends the keyguard unlock animation. * * The unlock animation transitions between the keyguard (lock screen) and the app/launcher surface @@ -85,7 +112,7 @@ const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.4f * this controller will play a canned animation on the surface as well. * * The surface behind the keyguard is manipulated via a RemoteAnimation passed to - * [notifyStartKeyguardExitAnimation] by [KeyguardViewMediator]. + * [notifyStartSurfaceBehindRemoteAnimation] by [KeyguardViewMediator]. */ @SysUISingleton class KeyguardUnlockAnimationController @Inject constructor( @@ -94,10 +121,99 @@ class KeyguardUnlockAnimationController @Inject constructor( private val keyguardViewMediator: Lazy<KeyguardViewMediator>, private val keyguardViewController: KeyguardViewController, - private val smartspaceTransitionController: SmartspaceTransitionController, private val featureFlags: FeatureFlags, - private val biometricUnlockController: BiometricUnlockController -) : KeyguardStateController.Callback { + private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController> +) : KeyguardStateController.Callback, ISysuiUnlockAnimationController.Stub() { + + interface KeyguardUnlockAnimationListener { + /** + * Called when the remote unlock animation, controlled by + * [KeyguardUnlockAnimationController], first starts. + * + * [playingCannedAnimation] indicates whether we are playing a canned animation to show the + * app/launcher behind the keyguard, vs. this being a swipe to unlock where the dismiss + * amount drives the animation. + * [fromWakeAndUnlock] tells us whether we are unlocking directly from AOD - in this case, + * the lockscreen is dismissed instantly, so we shouldn't run any animations that rely on it + * being visible. + */ + @JvmDefault + fun onUnlockAnimationStarted(playingCannedAnimation: Boolean, fromWakeAndUnlock: Boolean) {} + + /** + * Called when the remote unlock animation ends, in all cases, canned or swipe-to-unlock. + * The keyguard is no longer visible in this state and the app/launcher behind the keyguard + * is now completely visible. + */ + @JvmDefault + fun onUnlockAnimationFinished() {} + + /** + * Called when we begin the smartspace shared element transition, either due to an unlock + * action (biometric, etc.) or a swipe to unlock. + * + * This transition can begin BEFORE [onUnlockAnimationStarted] is called, if we are swiping + * to unlock and the surface behind the keyguard has not yet been made visible. This is + * because the lockscreen smartspace immediately begins moving towards the launcher + * smartspace location when a swipe begins, even before we start the keyguard exit remote + * animation and show the launcher itself. + */ + @JvmDefault + fun onSmartspaceSharedElementTransitionStarted() {} + } + + /** The SmartSpace view on the lockscreen, provided by [KeyguardClockSwitchController]. */ + var lockscreenSmartspace: View? = null + + /** + * The state of the Launcher's smartspace, delivered via [onLauncherSmartspaceStateUpdated]. + * This is pushed to us from Launcher whenever their smartspace moves or its visibility changes. + * We'll animate the lockscreen smartspace to this location during an unlock. + */ + var launcherSmartspaceState: SmartspaceState? = null + + /** + * Whether a canned unlock animation is playing, vs. currently unlocking in response to a swipe + * gesture or panel fling. If we're swiping/flinging, the unlock animation is driven by the + * dismiss amount, via [onKeyguardDismissAmountChanged]. If we're using a canned animation, it's + * being driven by ValueAnimators started in [playCannedUnlockAnimation]. + */ + var playingCannedUnlockAnimation = false + + /** + * Remote callback provided by Launcher that allows us to control the Launcher's unlock + * animation and smartspace. + * + * If this is null, we will not be animating any Launchers today and should fall back to window + * animations. + */ + private var launcherUnlockController: ILauncherUnlockAnimationController? = null + + private val listeners = ArrayList<KeyguardUnlockAnimationListener>() + + /** + * Called from SystemUiProxy to pass us the launcher's unlock animation controller. If this + * doesn't happen, we won't use in-window animations or the smartspace shared element + * transition, but that's okay! + */ + override fun setLauncherUnlockController(callback: ILauncherUnlockAnimationController?) { + launcherUnlockController = callback + + // If the provided callback dies, set it to null. We'll always check whether it's null + // to avoid DeadObjectExceptions. + callback?.asBinder()?.linkToDeath({ + launcherUnlockController = null + launcherSmartspaceState = null + }, 0 /* flags */) + } + + /** + * Called from SystemUiProxy to pass us the latest state of the Launcher's smartspace. This is + * only done when the state has changed in some way. + */ + override fun onLauncherSmartspaceStateUpdated(state: SmartspaceState?) { + launcherSmartspaceState = state + } /** * Information used to start, run, and finish a RemoteAnimation on the app or launcher surface @@ -105,15 +221,16 @@ class KeyguardUnlockAnimationController @Inject constructor( * * If we're swiping to unlock, the "animation" is controlled via the gesture, tied to the * dismiss amounts received in [onKeyguardDismissAmountChanged]. It does not have a fixed - * duration, and it ends when the gesture reaches a certain threshold or is cancelled. + * duration, and it ends when the gesture reaches a certain threshold or is cancell * * If we're unlocking via biometrics, PIN entry, or from clicking a notification, a canned - * animation is started in [notifyStartKeyguardExitAnimation]. + * animation is started in [playCannedUnlockAnimation]. */ @VisibleForTesting var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null private var surfaceBehindRemoteAnimationTarget: RemoteAnimationTarget? = null private var surfaceBehindRemoteAnimationStartTime: Long = 0 + private var surfaceBehindParams: SyncRtSurfaceTransactionApplier.SurfaceParams? = null /** * Alpha value applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the @@ -125,6 +242,7 @@ class KeyguardUnlockAnimationController @Inject constructor( */ private var surfaceBehindAlpha = 1f private var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f) + private var smartspaceAnimator = ValueAnimator.ofFloat(0f, 1f) /** * Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the @@ -144,57 +262,113 @@ class KeyguardUnlockAnimationController @Inject constructor( /** Rounded corner radius to apply to the surface behind the keyguard. */ private var roundedCornerRadius = 0f - /** The SmartSpace view on the lockscreen, provided by [KeyguardClockSwitchController]. */ - public var lockscreenSmartSpace: View? = null + /** + * Whether we tried to start the SmartSpace shared element transition for this unlock swipe. + * It's possible we were unable to do so (if the Launcher SmartSpace is not available), and we + * need to keep track of that so that we don't start doing it halfway through the swipe if + * Launcher becomes available suddenly. + */ + private var attemptedSmartSpaceTransitionForThisSwipe = false /** - * Whether we are currently in the process of unlocking the keyguard, and we are performing the - * shared element SmartSpace transition. + * The original location of the lockscreen smartspace on the screen. */ - private var unlockingWithSmartSpaceTransition: Boolean = false + private val smartspaceOriginBounds = Rect() /** - * Whether we tried to start the SmartSpace shared element transition for this unlock swipe. - * It's possible we're unable to do so (if the Launcher SmartSpace is not available). + * The bounds to which the lockscreen smartspace is moving. This is set to the bounds of the + * launcher's smartspace prior to the transition starting. */ - private var attemptedSmartSpaceTransitionForThisSwipe = false + private val smartspaceDestBounds = Rect() + + /** + * From 0f to 1f, the progress of the smartspace shared element animation. 0f means the + * smartspace is at its normal position within the lock screen hierarchy, and 1f means it has + * fully animated to the location of the Launcher's smartspace. + */ + private var smartspaceUnlockProgress = 0f + + /** + * Whether we're currently unlocking, and we're talking to Launcher to perform in-window + * animations rather than simply animating the Launcher window like any other app. This can be + * true while [unlockingWithSmartspaceTransition] is false, if the smartspace is not available + * or was not ready in time. + */ + private var unlockingToLauncherWithInWindowAnimations: Boolean = false + + /** + * Whether we are currently unlocking, and the smartspace shared element transition is in + * progress. If true, we're also [unlockingToLauncherWithInWindowAnimations]. + */ + private var unlockingWithSmartspaceTransition: Boolean = false + + private val handler = Handler() init { - surfaceBehindAlphaAnimator.duration = 150 - surfaceBehindAlphaAnimator.interpolator = Interpolators.ALPHA_IN - surfaceBehindAlphaAnimator.addUpdateListener { valueAnimator: ValueAnimator -> - surfaceBehindAlpha = valueAnimator.animatedValue as Float - updateSurfaceBehindAppearAmount() - } - surfaceBehindAlphaAnimator.addListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - // If the surface alpha is 0f, it's no longer visible so we can safely be done with - // the animation. - if (surfaceBehindAlpha == 0f) { - keyguardViewMediator.get().finishSurfaceBehindRemoteAnimation( + with(surfaceBehindAlphaAnimator) { + duration = SURFACE_BEHIND_SWIPE_FADE_DURATION_MS + interpolator = Interpolators.TOUCH_RESPONSE + addUpdateListener { valueAnimator: ValueAnimator -> + surfaceBehindAlpha = valueAnimator.animatedValue as Float + updateSurfaceBehindAppearAmount() + } + addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + // If the surface alpha is 0f, it's no longer visible so we can safely be done + // with the animation even if other properties are still animating. + if (surfaceBehindAlpha == 0f) { + keyguardViewMediator.get().finishSurfaceBehindRemoteAnimation( false /* cancelled */) + } } - } - }) + }) + } - surfaceBehindEntryAnimator.duration = 450 - surfaceBehindEntryAnimator.interpolator = Interpolators.DECELERATE_QUINT - surfaceBehindEntryAnimator.addUpdateListener { valueAnimator: ValueAnimator -> - surfaceBehindAlpha = valueAnimator.animatedValue as Float - setSurfaceBehindAppearAmount(valueAnimator.animatedValue as Float) + with(surfaceBehindEntryAnimator) { + duration = UNLOCK_ANIMATION_DURATION_MS + startDelay = UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS + interpolator = Interpolators.TOUCH_RESPONSE + addUpdateListener { valueAnimator: ValueAnimator -> + surfaceBehindAlpha = valueAnimator.animatedValue as Float + setSurfaceBehindAppearAmount(valueAnimator.animatedValue as Float) + } + addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + playingCannedUnlockAnimation = false + keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( + false /* cancelled */ + ) + } + }) } - surfaceBehindEntryAnimator.addListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( - false /* cancelled */) + + with(smartspaceAnimator) { + duration = UNLOCK_ANIMATION_DURATION_MS + interpolator = Interpolators.TOUCH_RESPONSE + addUpdateListener { + smartspaceUnlockProgress = it.animatedValue as Float } - }) + addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + launcherUnlockController?.setSmartspaceVisibility(View.VISIBLE) + keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( + false /* cancelled */) + } + }) + } // Listen for changes in the dismiss amount. keyguardStateController.addCallback(this) roundedCornerRadius = - context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat() + context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat() + } + + /** + * Add a listener to be notified of various stages of the unlock animation. + */ + fun addKeyguardUnlockAnimationListener(listener: KeyguardUnlockAnimationListener) { + listeners.add(listener) } /** @@ -203,78 +377,220 @@ class KeyguardUnlockAnimationController @Inject constructor( * surface for the unlock gesture/animation. * * When we're done with it, we'll call [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation] - * to end the RemoteAnimation. + * to end the RemoteAnimation. The KeyguardViewMediator will then end the animation and let us + * know that it's over by calling [notifyFinishedKeyguardExitAnimation]. * - * [requestedShowSurfaceBehindKeyguard] denotes whether the exit animation started because of a + * [requestedShowSurfaceBehindKeyguard] indicates whether the animation started because of a * call to [KeyguardViewMediator.showSurfaceBehindKeyguard], as happens during a swipe gesture, - * as opposed to the keyguard hiding. + * as opposed to being called because the device was unlocked and the keyguard is going away. */ - fun notifyStartKeyguardExitAnimation( + fun notifyStartSurfaceBehindRemoteAnimation( target: RemoteAnimationTarget, startTime: Long, requestedShowSurfaceBehindKeyguard: Boolean ) { - if (surfaceTransactionApplier == null) { surfaceTransactionApplier = SyncRtSurfaceTransactionApplier( keyguardViewController.viewRootImpl.view) } + // New animation, new params. + surfaceBehindParams = null + surfaceBehindRemoteAnimationTarget = target surfaceBehindRemoteAnimationStartTime = startTime - // If the surface behind wasn't made visible during a swipe, we'll do a canned animation - // to animate it in. Otherwise, the swipe touch events will continue animating it. + // If we specifically requested that the surface behind be made visible, it means we are + // swiping to unlock. In that case, the surface visibility is tied to the dismiss amount, + // and we'll handle that in onKeyguardDismissAmountChanged(). If we didn't request that, the + // keyguard is being dismissed for a different reason (biometric auth, etc.) and we should + // play a canned animation to make the surface fully visible. if (!requestedShowSurfaceBehindKeyguard) { - keyguardViewController.hide(startTime, 350) - - // If we're wake and unlocking, we don't want to animate the surface since we're going - // to do the light reveal scrim from the black AOD screen. Make it visible and end the - // remote aimation. - if (biometricUnlockController.isWakeAndUnlock) { - setSurfaceBehindAppearAmount(1f) - keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( - false /* cancelled */) - } else { - // Otherwise, animate it in normally. - surfaceBehindEntryAnimator.start() - } + playCannedUnlockAnimation() } + listeners.forEach { + it.onUnlockAnimationStarted( + playingCannedUnlockAnimation /* playingCannedAnimation */, + biometricUnlockControllerLazy.get().isWakeAndUnlock /* isWakeAndUnlock */) } + // Finish the keyguard remote animation if the dismiss amount has crossed the threshold. // Check it here in case there is no more change to the dismiss amount after the last change // that starts the keyguard animation. @see #updateKeyguardViewMediatorIfThresholdsReached() finishKeyguardExitRemoteAnimationIfReachThreshold() } - fun notifyCancelKeyguardExitAnimation() { + /** + * Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and + * we should clean up all of our state. + */ + fun notifyFinishedKeyguardExitAnimation(cancelled: Boolean) { + // Cancel any pending actions. + handler.removeCallbacksAndMessages(null) + + // Make sure we made the surface behind fully visible, just in case. It should already be + // fully visible. + setSurfaceBehindAppearAmount(1f) + launcherUnlockController?.setUnlockAmount(1f) + smartspaceDestBounds.setEmpty() + + // That target is no longer valid since the animation finished, null it out. surfaceBehindRemoteAnimationTarget = null + surfaceBehindParams = null + + playingCannedUnlockAnimation = false + unlockingToLauncherWithInWindowAnimations = false + unlockingWithSmartspaceTransition = false + resetSmartspaceTransition() + + listeners.forEach { it.onUnlockAnimationFinished() } } - fun notifyFinishedKeyguardExitAnimation() { - surfaceBehindRemoteAnimationTarget = null + /** + * Play a canned unlock animation to unlock the device. This is used when we were *not* swiping + * to unlock using a touch gesture. If we were swiping to unlock, the animation will be driven + * by the dismiss amount via [onKeyguardDismissAmountChanged]. + */ + fun playCannedUnlockAnimation() { + playingCannedUnlockAnimation = true + + if (canPerformInWindowLauncherAnimations()) { + // If possible, use the neat in-window animations to unlock to the launcher. + unlockToLauncherWithInWindowAnimations() + } else if (!biometricUnlockControllerLazy.get().isWakeAndUnlock) { + // If the launcher isn't behind the keyguard, or the launcher unlock controller is not + // available, animate in the entire window. + surfaceBehindEntryAnimator.start() + } else { + setSurfaceBehindAppearAmount(1f) + keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(false) + } + + // If this is a wake and unlock, hide the lockscreen immediately. In the future, we should + // animate it out nicely instead, but to the current state of wake and unlock, not hiding it + // causes a lot of issues. + // TODO(b/210016643): Not this, it looks not-ideal! + if (biometricUnlockControllerLazy.get().isWakeAndUnlock) { + keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350) + } } - fun hideKeyguardViewAfterRemoteAnimation() { - keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350) + /** + * Unlock to the launcher, using in-window animations, and the smartspace shared element + * transition if possible. + */ + private fun unlockToLauncherWithInWindowAnimations() { + unlockingToLauncherWithInWindowAnimations = true + + // See if we can do the smartspace transition, and if so, do it! + if (prepareForSmartspaceTransition()) { + animateSmartspaceToDestination() + listeners.forEach { it.onSmartspaceSharedElementTransitionStarted() } + } + + // Tell the launcher to prepare for the animation by setting its views invisible and + // syncing the selected smartspace pages. + launcherUnlockController?.prepareForUnlock( + unlockingWithSmartspaceTransition /* willAnimateSmartspace */, + (lockscreenSmartspace as BcSmartspaceDataPlugin.SmartspaceView?)?.selectedPage ?: -1) + + // Begin the animation. + launcherUnlockController?.playUnlockAnimation( + true /* unlocked */, UNLOCK_ANIMATION_DURATION_MS) + if (!unlockingWithSmartspaceTransition) { + // If we are not unlocking with the smartspace transition, wait for the unlock animation + // to end and then finish the remote animation. If we are using the smartspace + // transition, it will finish the remote animation once it ends. + handler.postDelayed({ + keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( + false /* cancelled */) + }, UNLOCK_ANIMATION_DURATION_MS) + } + + // Wait a moment, then show the launcher surface. + setSurfaceBehindAppearAmount(1f) } /** - * Whether we are currently in the process of unlocking the keyguard, and we are performing the - * shared element SmartSpace transition. + * Animates the lockscreen smartspace all the way to the launcher's smartspace location, then + * makes the launcher smartspace visible and ends the remote animation. */ - fun isUnlockingWithSmartSpaceTransition(): Boolean { - return unlockingWithSmartSpaceTransition + private fun animateSmartspaceToDestination() { + smartspaceAnimator.start() + } + + /** + * Reset the lockscreen smartspace's position, and reset all state involving the smartspace + * transition. + */ + public fun resetSmartspaceTransition() { + unlockingWithSmartspaceTransition = false + smartspaceUnlockProgress = 0f + + lockscreenSmartspace?.post { + lockscreenSmartspace!!.translationX = 0f + lockscreenSmartspace!!.translationY = 0f + } + } + + /** + * Moves the lockscreen smartspace towards the launcher smartspace's position. + */ + private fun setSmartspaceProgressToDestinationBounds(progress: Float) { + if (smartspaceDestBounds.isEmpty) { + return + } + + val progressClamped = min(1f, progress) + + // Calculate the distance (relative to the origin) that we need to be for the current + // progress value. + val progressX = + (smartspaceDestBounds.left - smartspaceOriginBounds.left) * progressClamped + val progressY = + (smartspaceDestBounds.top - smartspaceOriginBounds.top) * progressClamped + + val lockscreenSmartspaceCurrentBounds = Rect().also { + lockscreenSmartspace!!.getBoundsOnScreen(it) + } + + // Figure out how far that is from our present location on the screen. This approach + // compensates for the fact that our parent container is also translating to animate out. + val dx = smartspaceOriginBounds.left + progressX - + lockscreenSmartspaceCurrentBounds.left + val dy = smartspaceOriginBounds.top + progressY - + lockscreenSmartspaceCurrentBounds.top + + with(lockscreenSmartspace!!) { + translationX += dx + translationY += dy + } } /** * Update the lockscreen SmartSpace to be positioned according to the current dismiss amount. As * the dismiss amount increases, we will increase our SmartSpace's progress to the destination * bounds (the location of the Launcher SmartSpace). + * + * This is used by [KeyguardClockSwitchController] to keep the smartspace position updated as + * the clock is swiped away. */ fun updateLockscreenSmartSpacePosition() { - smartspaceTransitionController.setProgressToDestinationBounds( - keyguardStateController.dismissAmount / DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD) + setSmartspaceProgressToDestinationBounds(smartspaceUnlockProgress) + } + + /** + * Asks the keyguard view to hide, using the start time from the beginning of the remote + * animation. + */ + fun hideKeyguardViewAfterRemoteAnimation() { + // Hide the keyguard, with no fade out since we animated it away during the unlock. + keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 0 /* fadeOutDuration */) + } + + private fun applyParamsToSurface(params: SyncRtSurfaceTransactionApplier.SurfaceParams) { + surfaceTransactionApplier!!.scheduleApply(params) + surfaceBehindParams = params } /** @@ -287,34 +603,56 @@ class KeyguardUnlockAnimationController @Inject constructor( return } - val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.height() - val scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR + - (1f - SURFACE_BEHIND_START_SCALE_FACTOR) * - MathUtils.clamp(amount, 0f, 1f)) + if (unlockingToLauncherWithInWindowAnimations) { + // If we're using the in-window launcher animations, and haven't yet applied alpha = 1f + // to the launcher surface, do that now so we can see the launcher animations. + if (surfaceBehindParams?.alpha?.let { it < 1f } != false) { + applyParamsToSurface( + SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( + surfaceBehindRemoteAnimationTarget!!.leash) + .withAlpha(1f) + .build()) + } - // Scale up from a point at the center-bottom of the surface. - surfaceBehindMatrix.setScale( + // If we aren't using the canned unlock animation (which would be setting the unlock + // amount in its update listener), do it here. + if (!isPlayingCannedUnlockAnimation()) { + launcherUnlockController?.setUnlockAmount(amount) + } + } else { + // Otherwise, animate in the surface's scale/transltion. + val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.height() + val scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR + + (1f - SURFACE_BEHIND_START_SCALE_FACTOR) * + MathUtils.clamp(amount, 0f, 1f)) + + // Scale up from a point at the center-bottom of the surface. + surfaceBehindMatrix.setScale( scaleFactor, scaleFactor, surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.width() / 2f, - surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y) + surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y + ) - // Translate up from the bottom. - surfaceBehindMatrix.postTranslate(0f, - surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount)) + // Translate up from the bottom. + surfaceBehindMatrix.postTranslate( + 0f, + surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount) + ) - // If we're snapping the keyguard back, immediately begin fading it out. - val animationAlpha = + // If we're snapping the keyguard back, immediately begin fading it out. + val animationAlpha = if (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount else surfaceBehindAlpha - val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( - surfaceBehindRemoteAnimationTarget!!.leash) + applyParamsToSurface( + SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( + surfaceBehindRemoteAnimationTarget!!.leash) .withMatrix(surfaceBehindMatrix) .withCornerRadius(roundedCornerRadius) .withAlpha(animationAlpha) - .build() - surfaceTransactionApplier!!.scheduleApply(params) + .build()) + } } /** @@ -326,6 +664,10 @@ class KeyguardUnlockAnimationController @Inject constructor( return } + if (playingCannedUnlockAnimation) { + return + } + // For fling animations, we want to animate the surface in over the full distance. If we're // dismissing the keyguard via a swipe gesture (or cancelling the swipe gesture), we want to // bring in the surface behind over a relatively short swipe distance (~15%), to keep the @@ -344,17 +686,19 @@ class KeyguardUnlockAnimationController @Inject constructor( } override fun onKeyguardDismissAmountChanged() { - if (!KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation) { + if (!willHandleUnlockAnimation()) { return } if (keyguardViewController.isShowing) { - updateKeyguardViewMediatorIfThresholdsReached() + showOrHideSurfaceIfDismissAmountThresholdsReached() // If the surface is visible or it's about to be, start updating its appearance to // reflect the new dismiss amount. - if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() || - keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) { + if ((keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() || + keyguardViewMediator.get() + .isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) && + !playingCannedUnlockAnimation) { updateSurfaceBehindAppearAmount() } } @@ -362,7 +706,7 @@ class KeyguardUnlockAnimationController @Inject constructor( // The end of the SmartSpace transition can occur after the keyguard is hidden (when we tell // Launcher's SmartSpace to become visible again), so update it even if the keyguard view is // no longer showing. - updateSmartSpaceTransition() + applyDismissAmountToSmartspaceTransition() } /** @@ -370,16 +714,28 @@ class KeyguardUnlockAnimationController @Inject constructor( * such as reaching the point in the dismiss swipe where we need to make the surface behind the * keyguard visible. */ - private fun updateKeyguardViewMediatorIfThresholdsReached() { + private fun showOrHideSurfaceIfDismissAmountThresholdsReached() { if (!featureFlags.isEnabled(Flags.NEW_UNLOCK_SWIPE_ANIMATION)) { return } + // If we are playing the canned unlock animation, we flung away the keyguard to hide it and + // started a canned animation to show the surface behind the keyguard. The fling will cause + // panel height/dismiss amount updates, but we should ignore those updates here since the + // surface behind is already visible and animating. + if (playingCannedUnlockAnimation) { + return + } + val dismissAmount = keyguardStateController.dismissAmount if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD && !keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) { // We passed the threshold, and we're not yet showing the surface behind the // keyguard. Animate it in. + if (canPerformInWindowLauncherAnimations()) { + launcherUnlockController?.setUnlockAmount(0f) + unlockingToLauncherWithInWindowAnimations = true + } keyguardViewMediator.get().showSurfaceBehindKeyguard() fadeInSurfaceBehind() } else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD && @@ -388,9 +744,9 @@ class KeyguardUnlockAnimationController @Inject constructor( // out. keyguardViewMediator.get().hideSurfaceBehindKeyguard() fadeOutSurfaceBehind() - } else { - finishKeyguardExitRemoteAnimationIfReachThreshold() } + + finishKeyguardExitRemoteAnimationIfReachThreshold() } /** @@ -417,6 +773,7 @@ class KeyguardUnlockAnimationController @Inject constructor( // animating it out. This will be called again after the fling ends. !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture && dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)) { + setSurfaceBehindAppearAmount(1f) keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(false /* cancelled */) } } @@ -426,31 +783,53 @@ class KeyguardUnlockAnimationController @Inject constructor( * dismiss amount, and also updates the SmartSpaceTransitionController, which will let Launcher * know if it needs to do something as a result. */ - private fun updateSmartSpaceTransition() { + private fun applyDismissAmountToSmartspaceTransition() { if (!featureFlags.isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED)) { return } + // If we are playing the canned animation, the smartspace is being animated directly between + // its original location and the location of the launcher smartspace by smartspaceAnimator. + // We can ignore the dismiss amount, which is caused by panel height changes as the panel is + // flung away. + if (playingCannedUnlockAnimation) { + return + } + val dismissAmount = keyguardStateController.dismissAmount - // If we've begun a swipe, and are capable of doing the SmartSpace transition, start it! + // If we've begun a swipe, and haven't yet tried doing the SmartSpace transition, do that + // now. if (!attemptedSmartSpaceTransitionForThisSwipe && - dismissAmount > 0f && - dismissAmount < 1f && - keyguardViewController.isShowing) { + keyguardViewController.isShowing && + dismissAmount > 0f && + dismissAmount < 1f) { attemptedSmartSpaceTransitionForThisSwipe = true - smartspaceTransitionController.prepareForUnlockTransition() - if (keyguardStateController.canPerformSmartSpaceTransition()) { - unlockingWithSmartSpaceTransition = true - smartspaceTransitionController.launcherSmartspace?.setVisibility( - View.INVISIBLE) + if (prepareForSmartspaceTransition()) { + unlockingWithSmartspaceTransition = true + + // Ensure that the smartspace is invisible if we're doing the transition, and + // visible if we aren't. + launcherUnlockController?.setSmartspaceVisibility( + if (unlockingWithSmartspaceTransition) View.INVISIBLE else View.VISIBLE) + + if (unlockingWithSmartspaceTransition) { + listeners.forEach { it.onSmartspaceSharedElementTransitionStarted() } + } } } else if (attemptedSmartSpaceTransitionForThisSwipe && - (dismissAmount == 0f || dismissAmount == 1f)) { + (dismissAmount == 0f || dismissAmount == 1f)) { attemptedSmartSpaceTransitionForThisSwipe = false - unlockingWithSmartSpaceTransition = false - smartspaceTransitionController.launcherSmartspace?.setVisibility(View.VISIBLE) + unlockingWithSmartspaceTransition = false + launcherUnlockController?.setSmartspaceVisibility(View.VISIBLE) + } + + if (unlockingWithSmartspaceTransition) { + val swipedFraction: Float = keyguardStateController.dismissAmount + val progress = swipedFraction / DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD + smartspaceUnlockProgress = progress + setSmartspaceProgressToDestinationBounds(smartspaceUnlockProgress) } } @@ -463,4 +842,121 @@ class KeyguardUnlockAnimationController @Inject constructor( surfaceBehindAlphaAnimator.cancel() surfaceBehindAlphaAnimator.reverse() } + + /** + * Prepare for the smartspace shared element transition, if possible, by figuring out where we + * are animating from/to. + * + * Return true if we'll be able to do the smartspace transition, or false if conditions are not + * right to do it right now. + */ + private fun prepareForSmartspaceTransition(): Boolean { + // Feature is disabled, so we don't want to. + if (!featureFlags.isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED)) { + return false + } + + // If our controllers are null, or we haven't received a smartspace state from Launcher yet, + // we will not be doing any smartspace transitions today. + if (launcherUnlockController == null || + lockscreenSmartspace == null || + launcherSmartspaceState == null) { + return false + } + + // If the launcher does not have a visible smartspace (either because it's paged off-screen, + // or the smartspace just doesn't exist), we can't do the transition. + if ((launcherSmartspaceState?.visibleOnScreen) != true) { + return false + } + + // If our launcher isn't underneath, then we're unlocking to an app or custom launcher, + // neither of which have a smartspace. + if (!isNexusLauncherUnderneath()) { + return false + } + + // TODO(b/213910911): Unfortunately the keyguard is hidden instantly on wake and unlock, so + // we won't have a lockscreen smartspace to animate. This is sad, and we should fix that! + if (biometricUnlockControllerLazy.get().isWakeAndUnlock) { + return false + } + + // If we can't dismiss the lock screen via a swipe, then the only way we can do the shared + // element transition is if we're doing a biometric unlock. Otherwise, it means the bouncer + // is showing, and you can't see the lockscreen smartspace, so a shared element transition + // would not make sense. + if (!keyguardStateController.canDismissLockScreen() && + !biometricUnlockControllerLazy.get().isBiometricUnlock) { + return false + } + + unlockingWithSmartspaceTransition = true + smartspaceDestBounds.setEmpty() + + // Assuming we were able to retrieve the launcher's state, start the lockscreen + // smartspace at 0, 0, and save its starting bounds. + with(lockscreenSmartspace!!) { + translationX = 0f + translationY = 0f + getBoundsOnScreen(smartspaceOriginBounds) + } + + // Set the destination bounds to the launcher smartspace's bounds, offset by any + // padding on our smartspace. + with(smartspaceDestBounds) { + set(launcherSmartspaceState!!.boundsOnScreen) + offset(-lockscreenSmartspace!!.paddingLeft, -lockscreenSmartspace!!.paddingTop) + } + + return true + } + + /** + * Whether we should be able to do the in-window launcher animations given the current state of + * the device. + */ + fun canPerformInWindowLauncherAnimations(): Boolean { + return isNexusLauncherUnderneath() && launcherUnlockController != null + } + + /** + * Whether we are currently in the process of unlocking the keyguard, and we are performing the + * shared element SmartSpace transition. + */ + fun isUnlockingWithSmartSpaceTransition(): Boolean { + return unlockingWithSmartspaceTransition + } + + /** + * Whether this animation controller will be handling the unlock. We require remote animations + * to be enabled to do this. + * + * If this is not true, nothing in this class is relevant, and the unlock will be handled in + * [KeyguardViewMediator]. + */ + fun willHandleUnlockAnimation(): Boolean { + return KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation + } + + /** + * Whether we are playing a canned unlock animation, vs. unlocking from a touch gesture such as + * a swipe. + */ + fun isPlayingCannedUnlockAnimation(): Boolean { + return playingCannedUnlockAnimation + } + + companion object { + /** + * Return whether the Google Nexus launcher is underneath the keyguard, vs. some other + * launcher or an app. If so, we can communicate with it to perform in-window/shared element + * transitions! + */ + fun isNexusLauncherUnderneath(): Boolean { + return ActivityManagerWrapper.getInstance() + .runningTask?.topActivity?.className?.equals( + QuickStepContract.LAUNCHER_ACTIVITY_CLASS_NAME) ?: false + } + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 8376681e7bd4..08e1654c8dbf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -2235,8 +2235,9 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, createInteractionJankMonitorConf("DismissPanel")); // Pass the surface and metadata to the unlock animation controller. - mKeyguardUnlockAnimationControllerLazy.get().notifyStartKeyguardExitAnimation( - apps[0], startTime, mSurfaceBehindRemoteAnimationRequested); + mKeyguardUnlockAnimationControllerLazy.get() + .notifyStartSurfaceBehindRemoteAnimation( + apps[0], startTime, mSurfaceBehindRemoteAnimationRequested); } else { mInteractionJankMonitor.begin( createInteractionJankMonitorConf("RemoteAnimationDisabled")); @@ -2373,8 +2374,10 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, finishSurfaceBehindRemoteAnimation(cancelled); mSurfaceBehindRemoteAnimationRequested = false; - mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation(); }); + + mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation( + cancelled); } /** @@ -2412,8 +2415,16 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, return mSurfaceBehindRemoteAnimationRequested; } + public boolean isAnimatingBetweenKeyguardAndSurfaceBehind() { + return mSurfaceBehindRemoteAnimationRunning; + } + /** If it's running, finishes the RemoteAnimation on the surface behind the keyguard. */ public void finishSurfaceBehindRemoteAnimation(boolean cancelled) { + if (!mSurfaceBehindRemoteAnimationRunning) { + return; + } + mSurfaceBehindRemoteAnimationRunning = false; if (mSurfaceBehindRemoteAnimationFinishedCallback != null) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 60060aaf72da..00a314943f7a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -31,9 +31,9 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHE import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING; @@ -83,6 +83,7 @@ import com.android.systemui.Dumpable; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.model.SysUiState; import com.android.systemui.navigationbar.NavigationBar; @@ -97,7 +98,6 @@ import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; @@ -161,7 +161,7 @@ public class OverviewProxyService extends CurrentUserTracker implements private final CommandQueue mCommandQueue; private final ShellTransitions mShellTransitions; private final Optional<StartingSurface> mStartingSurface; - private final SmartspaceTransitionController mSmartspaceTransitionController; + private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController; private final Optional<RecentTasks> mRecentTasks; private final UiEventLogger mUiEventLogger; @@ -503,8 +503,8 @@ public class OverviewProxyService extends CurrentUserTracker implements KEY_EXTRA_SHELL_STARTING_WINDOW, startingwindow.createExternalInterface().asBinder())); params.putBinder( - KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER, - mSmartspaceTransitionController.createExternalInterface().asBinder()); + KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER, + mSysuiUnlockAnimationController.asBinder()); mRecentTasks.ifPresent(recentTasks -> params.putBinder( KEY_EXTRA_RECENT_TASKS, recentTasks.createExternalInterface().asBinder())); @@ -570,8 +570,8 @@ public class OverviewProxyService extends CurrentUserTracker implements BroadcastDispatcher broadcastDispatcher, ShellTransitions shellTransitions, ScreenLifecycle screenLifecycle, - SmartspaceTransitionController smartspaceTransitionController, UiEventLogger uiEventLogger, + KeyguardUnlockAnimationController sysuiUnlockAnimationController, DumpManager dumpManager) { super(broadcastDispatcher); mContext = context; @@ -644,7 +644,7 @@ public class OverviewProxyService extends CurrentUserTracker implements updateEnabledState(); startConnectionToCurrentUser(); mStartingSurface = startingSurface; - mSmartspaceTransitionController = smartspaceTransitionController; + mSysuiUnlockAnimationController = sysuiUnlockAnimationController; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt deleted file mode 100644 index 89b3df0f495f..000000000000 --- a/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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.systemui.shared.system.smartspace - -import android.graphics.Rect -import android.view.View -import com.android.systemui.shared.system.ActivityManagerWrapper -import com.android.systemui.shared.system.QuickStepContract -import kotlin.math.min - -/** - * Controller that keeps track of SmartSpace instances in remote processes (such as Launcher), - * allowing System UI to query or update their state during shared-element transitions. - */ -class SmartspaceTransitionController { - - /** - * Implementation of [ISmartspaceTransitionController] that we provide to Launcher, allowing it - * to provide us with a callback to query and update the state of its Smartspace. - */ - private val ISmartspaceTransitionController = object : ISmartspaceTransitionController.Stub() { - override fun setSmartspace(callback: ISmartspaceCallback?) { - this@SmartspaceTransitionController.launcherSmartspace = callback - updateLauncherSmartSpaceState() - } - } - - /** - * Callback provided by Launcher to allow us to query and update the state of its SmartSpace. - */ - public var launcherSmartspace: ISmartspaceCallback? = null - - public var lockscreenSmartspace: View? = null - - /** - * Cached state of the Launcher SmartSpace. Retrieving the state is an IPC, so we should avoid - * unnecessary - */ - public var mLauncherSmartspaceState: SmartspaceState? = null - - /** - * The bounds of our SmartSpace when the shared element transition began. We'll interpolate - * between this and [smartspaceDestinationBounds] as the dismiss amount changes. - */ - private val smartspaceOriginBounds = Rect() - - /** The bounds of the Launcher's SmartSpace, which is where we are animating our SmartSpace. */ - - private val smartspaceDestinationBounds = Rect() - - fun createExternalInterface(): ISmartspaceTransitionController { - return ISmartspaceTransitionController - } - - /** - * Updates [mLauncherSmartspaceState] and returns it. This will trigger a binder call, so use the - * cached [mLauncherSmartspaceState] if possible. - */ - fun updateLauncherSmartSpaceState(): SmartspaceState? { - return launcherSmartspace?.smartspaceState.also { - mLauncherSmartspaceState = it - } - } - - fun prepareForUnlockTransition() { - updateLauncherSmartSpaceState().also { state -> - if (state?.boundsOnScreen != null && lockscreenSmartspace != null) { - lockscreenSmartspace!!.getBoundsOnScreen(smartspaceOriginBounds) - with(smartspaceDestinationBounds) { - set(state.boundsOnScreen) - offset(-lockscreenSmartspace!!.paddingLeft, - -lockscreenSmartspace!!.paddingTop) - } - } - } - } - - fun setProgressToDestinationBounds(progress: Float) { - if (!isSmartspaceTransitionPossible()) { - return - } - - val progressClamped = min(1f, progress) - - // Calculate the distance (relative to the origin) that we need to be for the current - // progress value. - val progressX = - (smartspaceDestinationBounds.left - smartspaceOriginBounds.left) * progressClamped - val progressY = - (smartspaceDestinationBounds.top - smartspaceOriginBounds.top) * progressClamped - - val lockscreenSmartspaceCurrentBounds = Rect().also { - lockscreenSmartspace!!.getBoundsOnScreen(it) - } - - // Figure out how far that is from our present location on the screen. This approach - // compensates for the fact that our parent container is also translating to animate out. - val dx = smartspaceOriginBounds.left + progressX - - lockscreenSmartspaceCurrentBounds.left - var dy = smartspaceOriginBounds.top + progressY - - lockscreenSmartspaceCurrentBounds.top - - with(lockscreenSmartspace!!) { - translationX = translationX + dx - translationY = translationY + dy - } - } - - /** - * Whether we're capable of performing the Smartspace shared element transition when we unlock. - * This is true if: - * - * - The Launcher registered a Smartspace with us, it's reporting non-empty bounds on screen. - * - Launcher is behind the keyguard, and the Smartspace is visible on the currently selected - * page. - */ - public fun isSmartspaceTransitionPossible(): Boolean { - val smartSpaceNullOrBoundsEmpty = mLauncherSmartspaceState?.boundsOnScreen?.isEmpty ?: true - return isLauncherUnderneath() && !smartSpaceNullOrBoundsEmpty - } - - companion object { - fun isLauncherUnderneath(): Boolean { - return ActivityManagerWrapper.getInstance() - .runningTask?.topActivity?.className?.equals( - QuickStepContract.LAUNCHER_ACTIVITY_CLASS_NAME) ?: false - } - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index 46004db3067a..267ee6d2d177 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -154,6 +154,16 @@ class NotificationShadeDepthController @Inject constructor( } /** + * We're unlocking, and should not blur as the panel expansion changes. + */ + var blursDisabledForUnlock: Boolean = false + set(value) { + if (field == value) return + field = value + scheduleUpdate() + } + + /** * Force stop blur effect when necessary. */ private var scrimsVisible: Boolean = false @@ -192,7 +202,7 @@ class NotificationShadeDepthController @Inject constructor( combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress)) var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius) - if (blursDisabledForAppLaunch) { + if (blursDisabledForAppLaunch || blursDisabledForUnlock) { shadeRadius = 0f } @@ -309,9 +319,7 @@ class NotificationShadeDepthController @Inject constructor( /** * Update blurs when pulling down the shade */ - override fun onPanelExpansionChanged( - rawFraction: Float, expanded: Boolean, tracking: Boolean - ) { + override fun onPanelExpansionChanged(rawFraction: Float, expanded: Boolean, tracking: Boolean) { val timestamp = SystemClock.elapsedRealtimeNanos() val expansion = MathUtils.saturate( (rawFraction - panelPullDownMinFraction) / (1f - panelPullDownMinFraction)) 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 dee1b334182a..8d500fa4e8b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -44,6 +44,7 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; @@ -254,6 +255,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp ); } + private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; + @Inject public BiometricUnlockController(Context context, DozeScrimController dozeScrimController, KeyguardViewMediator keyguardViewMediator, ScrimController scrimController, @@ -269,7 +272,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp WakefulnessLifecycle wakefulnessLifecycle, ScreenLifecycle screenLifecycle, AuthController authController, - StatusBarStateController statusBarStateController) { + StatusBarStateController statusBarStateController, + KeyguardUnlockAnimationController keyguardUnlockAnimationController) { mContext = context; mPowerManager = powerManager; mShadeController = shadeController; @@ -292,6 +296,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp mMetricsLogger = metricsLogger; mAuthController = authController; mStatusBarStateController = statusBarStateController; + mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; dumpManager.registerDumpable(getClass().getName(), this); } @@ -438,11 +443,15 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (!wasDeviceInteractive) { mPendingShowBouncer = true; } else { - mShadeController.animateCollapsePanels( - CommandQueue.FLAG_EXCLUDE_NONE, - true /* force */, - false /* delayed */, - BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR); + // If the keyguard unlock controller is going to handle the unlock animation, it + // will fling the panel collapsed when it's ready. + if (!mKeyguardUnlockAnimationController.willHandleUnlockAnimation()) { + mShadeController.animateCollapsePanels( + CommandQueue.FLAG_EXCLUDE_NONE, + true /* force */, + false /* delayed */, + BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR); + } mPendingShowBouncer = false; mKeyguardViewController.notifyKeyguardAuthenticated( false /* strongAuth */); 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 016b953245b2..769f68976958 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -138,6 +138,7 @@ import com.android.systemui.fragments.FragmentService; import com.android.systemui.idle.IdleHostView; import com.android.systemui.idle.IdleHostViewController; import com.android.systemui.idle.dagger.IdleViewComponent; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.media.KeyguardMediaController; import com.android.systemui.media.MediaDataManager; import com.android.systemui.media.MediaHierarchyManager; @@ -791,7 +792,8 @@ public class NotificationPanelViewController extends PanelViewController { Optional<SysUIUnfoldComponent> unfoldComponent, ControlsComponent controlsComponent, InteractionJankMonitor interactionJankMonitor, - QsFrameTranslateController qsFrameTranslateController) { + QsFrameTranslateController qsFrameTranslateController, + KeyguardUnlockAnimationController keyguardUnlockAnimationController) { super(view, featureFlags, falsingManager, @@ -806,7 +808,8 @@ public class NotificationPanelViewController extends PanelViewController { lockscreenGestureLogger, panelExpansionStateManager, ambientState, - interactionJankMonitor); + interactionJankMonitor, + keyguardUnlockAnimationController); mView = view; mVibratorHelper = vibratorHelper; mKeyguardMediaController = keyguardMediaController; @@ -925,8 +928,33 @@ public class NotificationPanelViewController extends PanelViewController { mQsFrameTranslateController = qsFrameTranslateController; updateUserSwitcherFlags(); onFinishInflate(); - mUseCombinedQSHeaders = featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS); + keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener( + new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() { + @Override + public void onUnlockAnimationFinished() { + // Make sure the clock is in the correct position after the unlock animation + // so that it's not in the wrong place when we show the keyguard again. + positionClockAndNotifications(true /* forceClockUpdate */); + } + + @Override + public void onUnlockAnimationStarted( + boolean playingCannedAnimation, boolean isWakeAndUnlock) { + // Disable blurs while we're unlocking so that panel expansion does not + // cause blurring. This will eventually be re-enabled by the panel view on + // ACTION_UP, since the user's finger might still be down after a swipe to + // unlock gesture, and we don't want that to cause blurring either. + mDepthController.setBlursDisabledForUnlock(mTracking); + + if (playingCannedAnimation && !isWakeAndUnlock) { + // Fling the panel away so it's not in the way or the surface behind the + // keyguard, which will be appearing. If we're wake and unlocking, the + // lock screen is hidden instantly so should not be flung away. + fling(0f, false, 0.7f, false); + } + } + }); } private void onFinishInflate() { @@ -3324,6 +3352,10 @@ public class NotificationPanelViewController extends PanelViewController { mAffordanceHelper.reset(true); } } + + // If we unlocked from a swipe, the user's finger might still be down after the + // unlock animation ends. We need to wait until ACTION_UP to enable blurs again. + mDepthController.setBlursDisabledForUnlock(false); } private void updateMaxHeadsUpTranslation() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 53bfd7701335..05ac2a35c777 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -55,6 +55,7 @@ import com.android.systemui.classifier.Classifier; import com.android.systemui.doze.DozeLog; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -212,6 +213,8 @@ public abstract class PanelViewController { return mAmbientState; } + private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; + public PanelViewController( PanelView view, FeatureFlags featureFlags, @@ -227,7 +230,15 @@ public abstract class PanelViewController { LockscreenGestureLogger lockscreenGestureLogger, PanelExpansionStateManager panelExpansionStateManager, AmbientState ambientState, - InteractionJankMonitor interactionJankMonitor) { + InteractionJankMonitor interactionJankMonitor, + KeyguardUnlockAnimationController keyguardUnlockAnimationController) { + mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; + keyguardStateController.addCallback(new KeyguardStateController.Callback() { + @Override + public void onKeyguardFadingAwayChanged() { + requestPanelHeightUpdate(); + } + }); mAmbientState = ambientState; mView = view; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; @@ -437,7 +448,8 @@ public abstract class PanelViewController { mUpdateFlingVelocity = vel; } } else if (!mStatusBar.isBouncerShowing() - && !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) { + && !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating() + && !mKeyguardStateController.isKeyguardGoingAway()) { boolean expands = onEmptySpaceClick(mInitialTouchX); onTrackingStopped(expands); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 5d83cc6259a0..48048b49e5b8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -809,6 +809,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump : ScrimState.SHADE_LOCKED.getBehindTint(); behindTint = ColorUtils.blendARGB(behindTint, stateTint, mQsExpansion); } + + // If the keyguard is going away, we should not be opaque. + if (mKeyguardStateController.isKeyguardGoingAway()) { + behindAlpha = 0f; + } + return new Pair<>(behindTint, behindAlpha); } @@ -1333,9 +1339,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) { mExpansionAffectsAlpha = expansionAffectsAlpha; - if (expansionAffectsAlpha) { - applyAndDispatchState(); - } } public void setKeyguardOccluded(boolean keyguardOccluded) { 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 9a9e3bc58774..ae4a19e2b212 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -2978,6 +2978,8 @@ public class StatusBar extends CoreStartable implements public void showKeyguardImpl() { mIsKeyguard = true; + // In case we're locking while a smartspace transition is in progress, reset it. + mKeyguardUnlockAnimationController.resetSmartspaceTransition(); if (mKeyguardStateController.isLaunchTransitionFadingAway()) { mNotificationPanelViewController.cancelAnimation(); onLaunchTransitionFadingEnded(); @@ -3156,6 +3158,7 @@ public class StatusBar extends CoreStartable implements // bar. mKeyguardStateController.notifyKeyguardGoingAway(true); mCommandQueue.appTransitionPending(mDisplayId, true /* forced */); + updateScrimController(); } /** @@ -3327,7 +3330,10 @@ public class StatusBar extends CoreStartable implements } private void showBouncerOrLockScreenIfKeyguard() { - if (!mKeyguardViewMediator.isHiding()) { + // If the keyguard is animating away, we aren't really the keyguard anymore and should not + // show the bouncer/lockscreen. + if (!mKeyguardViewMediator.isHiding() + && !mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) { if (mState == StatusBarState.SHADE_LOCKED && mKeyguardUpdateMonitor.isUdfpsEnrolled()) { // shade is showing while locked on the keyguard, so go back to showing the @@ -3761,17 +3767,14 @@ public class StatusBar extends CoreStartable implements public void updateScrimController() { Trace.beginSection("StatusBar#updateScrimController"); - // We don't want to end up in KEYGUARD state when we're unlocking with - // fingerprint from doze. We should cross fade directly from black. - boolean unlocking = mBiometricUnlockController.isWakeAndUnlock() - || mKeyguardStateController.isKeyguardFadingAway(); + boolean unlocking = mKeyguardStateController.isShowing() && ( + mBiometricUnlockController.isWakeAndUnlock() + || mKeyguardStateController.isKeyguardFadingAway() + || mKeyguardStateController.isKeyguardGoingAway() + || mKeyguardViewMediator.requestedShowSurfaceBehindKeyguard() + || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind()); - // Do not animate the scrim expansion when triggered by the fingerprint sensor. - boolean onKeyguardOrHidingIt = mKeyguardStateController.isShowing() - || mKeyguardStateController.isKeyguardFadingAway() - || mKeyguardStateController.isKeyguardGoingAway(); - mScrimController.setExpansionAffectsAlpha(!(mBiometricUnlockController.isBiometricUnlock() - && onKeyguardOrHidingIt)); + mScrimController.setExpansionAffectsAlpha(!unlocking); boolean launchingAffordanceWithPreview = mNotificationPanelViewController.isLaunchingAffordanceWithPreview(); @@ -3783,7 +3786,7 @@ public class StatusBar extends CoreStartable implements } else { mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED); } - } else if (mBouncerShowing) { + } else if (mBouncerShowing && !unlocking) { // Bouncer needs the front scrim when it's on top of an activity, // tapping on a notification, editing QS or being dismissed by // FLAG_DISMISS_KEYGUARD_ACTIVITY. 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 7bf1601b2fd5..050b67016d09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java @@ -50,13 +50,6 @@ public interface KeyguardStateController extends CallbackController<Callback> { boolean canDismissLockScreen(); /** - * Whether we can currently perform the shared element SmartSpace transition. This is true if - * we're on the lockscreen, it can be dismissed with a swipe, and the Launcher is underneath the - * keyguard and displaying a SmartSpace that it has registered with System UI. - */ - boolean canPerformSmartSpaceTransition(); - - /** * Whether the keyguard is allowed to rotate, or needs to be locked to the default orientation. */ boolean isKeyguardScreenRotationAllowed(); 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 05a586b1cdc2..978564fc81d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java @@ -35,7 +35,7 @@ import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; -import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -44,6 +44,8 @@ import java.util.Objects; import javax.inject.Inject; +import dagger.Lazy; + /** */ @SysUISingleton @@ -58,7 +60,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum private final LockPatternUtils mLockPatternUtils; private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback = new UpdateMonitorCallback(); - private final SmartspaceTransitionController mSmartspaceTransitionController; + private final Lazy<KeyguardUnlockAnimationController> mUnlockAnimationControllerLazy; private boolean mCanDismissLockScreen; private boolean mShowing; @@ -105,13 +107,13 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum Context context, KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils, - SmartspaceTransitionController smartspaceTransitionController, + Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController, DumpManager dumpManager) { mContext = context; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); - mSmartspaceTransitionController = smartspaceTransitionController; + mUnlockAnimationControllerLazy = keyguardUnlockAnimationController; dumpManager.registerDumpable(getClass().getSimpleName(), this); @@ -249,12 +251,6 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum } @Override - public boolean canPerformSmartSpaceTransition() { - return canDismissLockScreen() - && mSmartspaceTransitionController.isSmartspaceTransitionPossible(); - } - - @Override public boolean isKeyguardScreenRotationAllowed() { return SystemProperties.getBoolean("lockscreen.rot_override", false) || mContext.getResources().getBoolean(R.bool.config_enableLockScreenRotation); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java index 74e0f4002026..c2439df6624a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java @@ -48,7 +48,6 @@ import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController; import com.android.systemui.statusbar.phone.KeyguardBypassController; @@ -96,9 +95,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { @Mock Resources mResources; - KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; @Mock - SmartspaceTransitionController mSmartSpaceTransitionController; + KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; @Mock private ClockPlugin mClockPlugin; @Mock @@ -154,7 +152,6 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { mBypassController, mSmartspaceController, mKeyguardUnlockAnimationController, - mSmartSpaceTransitionController, mSecureSettings, mExecutor, mResources diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java index 80de24868181..217092e6e4e5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java @@ -24,7 +24,6 @@ import android.testing.AndroidTestingRunner; import com.android.systemui.SysuiTestCase; import com.android.systemui.communal.CommunalStateController; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; -import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -61,8 +60,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase { @Mock KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; @Mock - SmartspaceTransitionController mSmartSpaceTransitionController; - @Mock ScreenOffAnimationController mScreenOffAnimationController; @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor; @@ -83,7 +80,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase { mConfigurationController, mDozeParameters, mKeyguardUnlockAnimationController, - mSmartSpaceTransitionController, mScreenOffAnimationController); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt index f3043e934c8a..fb1a968acceb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt @@ -14,7 +14,6 @@ import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardViewController import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FeatureFlags -import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.policy.KeyguardStateController import junit.framework.Assert.assertEquals @@ -44,8 +43,6 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var keyguardViewController: KeyguardViewController @Mock - private lateinit var smartspaceTransitionController: SmartspaceTransitionController - @Mock private lateinit var featureFlags: FeatureFlags @Mock private lateinit var biometricUnlockController: BiometricUnlockController @@ -59,7 +56,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) keyguardUnlockAnimationController = KeyguardUnlockAnimationController( context, keyguardStateController, { keyguardViewMediator }, keyguardViewController, - smartspaceTransitionController, featureFlags, biometricUnlockController + featureFlags, { biometricUnlockController } ) `when`(keyguardViewController.viewRootImpl).thenReturn(mock(ViewRootImpl::class.java)) @@ -87,7 +84,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { fun noSurfaceAnimation_ifWakeAndUnlocking() { `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true) - keyguardUnlockAnimationController.notifyStartKeyguardExitAnimation( + keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTarget, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ @@ -118,15 +115,12 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { fun surfaceAnimation_ifNotWakeAndUnlocking() { `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(false) - keyguardUnlockAnimationController.notifyStartKeyguardExitAnimation( + keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTarget, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ ) - // Make sure the animator was started. - assertTrue(keyguardUnlockAnimationController.surfaceBehindEntryAnimator.isRunning) - // Since the animation is running, we should not have finished the remote animation. verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished( false /* cancelled */) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt index 0bce621c3b02..91e5d33d9c9e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt @@ -302,6 +302,40 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { } @Test + fun ignoreBlurForUnlock_ignores() { + notificationShadeDepthController.onPanelExpansionChanged( + rawFraction = 1f, expanded = true, tracking = false + ) + `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat()) + + notificationShadeDepthController.blursDisabledForAppLaunch = false + notificationShadeDepthController.blursDisabledForUnlock = true + + notificationShadeDepthController.updateBlurCallback.doFrame(0) + + // Since we are ignoring blurs for unlock, we should be applying blur = 0 despite setting it + // to maxBlur above. + verify(blurUtils).applyBlur(any(), eq(0), eq(false)) + } + + @Test + fun ignoreBlurForUnlock_doesNotIgnore() { + notificationShadeDepthController.onPanelExpansionChanged( + rawFraction = 1f, expanded = true, tracking = false + ) + `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat()) + + notificationShadeDepthController.blursDisabledForAppLaunch = false + notificationShadeDepthController.blursDisabledForUnlock = false + + notificationShadeDepthController.updateBlurCallback.doFrame(0) + + // Since we are not ignoring blurs for unlock (or app launch), we should apply the blur we + // returned above (maxBlur). + verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false)) + } + + @Test fun brightnessMirrorVisible_whenVisible() { notificationShadeDepthController.brightnessMirrorVisible = true verify(brightnessSpring).animateTo(eq(maxBlur), any()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt index 1961ab269267..188baaf682b0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt @@ -561,6 +561,10 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { override fun setMediaTarget(target: SmartspaceTarget?) { } + + override fun getSelectedPage(): Int { + return -1 + } }) } } 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 c3349f1d70f4..5ca1f21eb021 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 @@ -42,6 +42,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.dump.DumpManager; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; @@ -104,6 +105,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { private ScreenLifecycle mScreenLifecycle; @Mock private StatusBarStateController mStatusBarStateController; + @Mock + private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private BiometricUnlockController mBiometricUnlockController; @Before @@ -126,7 +129,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters, mMetricsLogger, mDumpManager, mPowerManager, mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle, - mAuthController, mStatusBarStateController); + mAuthController, mStatusBarStateController, mKeyguardUnlockAnimationController); mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); mBiometricUnlockController.setBiometricModeListener(mBiometricModeListener); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index 35f671bf8298..1c8b35aeaeaf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -104,6 +104,7 @@ import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentService; import com.android.systemui.idle.IdleHostViewController; import com.android.systemui.idle.dagger.IdleViewComponent; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.media.KeyguardMediaController; import com.android.systemui.media.MediaDataManager; import com.android.systemui.media.MediaHierarchyManager; @@ -362,6 +363,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { private QsFrameTranslateController mQsFrameTranslateController; @Mock private StatusBarWindowStateController mStatusBarWindowStateController; + @Mock + private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty(); private SysuiStatusBarStateController mStatusBarStateController; private NotificationPanelViewController mNotificationPanelViewController; @@ -546,7 +549,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { mSysUIUnfoldComponent, mControlsComponent, mInteractionJankMonitor, - mQsFrameTranslateController); + mQsFrameTranslateController, + mKeyguardUnlockAnimationController); mNotificationPanelViewController.initDependencies( mStatusBar, () -> {}, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index bb8bad39ab31..77065b2d4380 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -819,31 +819,27 @@ public class StatusBarTest extends SysuiTestCase { } @Test - public void testSetExpansionAffectsAlpha_onlyWhenHidingKeyguard() { + public void testSetExpansionAffectsAlpha_whenKeyguardShowingButGoingAwayForAnyReason() { mStatusBar.updateScrimController(); verify(mScrimController).setExpansionAffectsAlpha(eq(true)); clearInvocations(mScrimController); - when(mBiometricUnlockController.isBiometricUnlock()).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false); mStatusBar.updateScrimController(); verify(mScrimController).setExpansionAffectsAlpha(eq(true)); clearInvocations(mScrimController); when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true); mStatusBar.updateScrimController(); verify(mScrimController).setExpansionAffectsAlpha(eq(false)); clearInvocations(mScrimController); - reset(mKeyguardStateController); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true); mStatusBar.updateScrimController(); verify(mScrimController).setExpansionAffectsAlpha(eq(false)); - - clearInvocations(mScrimController); - reset(mKeyguardStateController); - when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true); - mStatusBar.updateScrimController(); - verify(mScrimController).setExpansionAffectsAlpha(eq(false)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java index 8ccaf9362454..4a8170fc2955 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java @@ -33,7 +33,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; -import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import org.junit.Before; import org.junit.Test; @@ -41,6 +41,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import dagger.Lazy; + @SmallTest @TestableLooper.RunWithLooper @RunWith(AndroidTestingRunner.class) @@ -52,9 +54,9 @@ public class KeyguardStateControllerTest extends SysuiTestCase { private LockPatternUtils mLockPatternUtils; private KeyguardStateController mKeyguardStateController; @Mock - private SmartspaceTransitionController mSmartSpaceTransitionController; - @Mock private DumpManager mDumpManager; + @Mock + private Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy; @Before public void setup() { @@ -63,7 +65,7 @@ public class KeyguardStateControllerTest extends SysuiTestCase { mContext, mKeyguardUpdateMonitor, mLockPatternUtils, - mSmartSpaceTransitionController, + mKeyguardUnlockAnimationControllerLazy, mDumpManager); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java index e136d00b86f8..aaea4ecdc08d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java @@ -129,11 +129,6 @@ public class FakeKeyguardStateController implements KeyguardStateController { } @Override - public boolean canPerformSmartSpaceTransition() { - return false; - } - - @Override public boolean isKeyguardScreenRotationAllowed() { return false; } |