Merge "Use Launcher smartspace instead of SysUI's for the shared element transition."
This commit is contained in:
@@ -16,17 +16,20 @@
|
||||
|
||||
package com.android.systemui.shared.system.smartspace;
|
||||
|
||||
import android.graphics.Rect;
|
||||
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);
|
||||
void prepareForUnlock(boolean animateSmartspace, in Rect lockscreenSmartspaceBounds,
|
||||
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);
|
||||
// unlock animation, such as during a swipe to unlock touch gesture. Will not apply this change
|
||||
// if the unlock amount is animating unless forceIfAnimating is true.
|
||||
oneway void setUnlockAmount(float amount, boolean forceIfAnimating);
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -58,9 +58,7 @@ import com.android.systemui.util.ViewController;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -133,14 +131,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
private final KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener
|
||||
mKeyguardUnlockAnimationListener =
|
||||
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.
|
||||
@@ -390,41 +380,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
if (mStatusArea != null) {
|
||||
PropertyAnimator.setProperty(mStatusArea, AnimatableProperty.TRANSLATION_X,
|
||||
x, props, animate);
|
||||
|
||||
// If we're unlocking with the SmartSpace shared element transition, let the controller
|
||||
// know that it should re-position our SmartSpace.
|
||||
if (mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
|
||||
mKeyguardUnlockAnimationController.updateLockscreenSmartSpacePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets an alpha value on every child view except for the smartspace. */
|
||||
public void setChildrenAlphaExcludingSmartspace(float alpha) {
|
||||
final Set<View> excludedViews = new HashSet<>();
|
||||
|
||||
if (mSmartspaceView != null) {
|
||||
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);
|
||||
}
|
||||
|
||||
/** Sets an alpha value on every child view except for the views in the provided set. */
|
||||
public void setChildrenAlphaExcluding(float alpha, Set<View> excludedViews) {
|
||||
for (int i = 0; i < mView.getChildCount(); i++) {
|
||||
final View child = mView.getChildAt(i);
|
||||
|
||||
if (!excludedViews.contains(child)) {
|
||||
child.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ public class KeyguardStatusView extends GridLayout {
|
||||
|
||||
private float mDarkAmount = 0;
|
||||
private int mTextColor;
|
||||
private float mChildrenAlphaExcludingSmartSpace = 1f;
|
||||
|
||||
public KeyguardStatusView(Context context) {
|
||||
this(context, null, 0);
|
||||
@@ -95,23 +94,6 @@ public class KeyguardStatusView extends GridLayout {
|
||||
mClockView.setTextColor(blendedTextColor);
|
||||
}
|
||||
|
||||
public void setChildrenAlphaExcludingClockView(float alpha) {
|
||||
setChildrenAlphaExcluding(alpha, Set.of(mClockView));
|
||||
}
|
||||
|
||||
/** Sets an alpha value on every view except for the views in the provided set. */
|
||||
public void setChildrenAlphaExcluding(float alpha, Set<View> excludedViews) {
|
||||
mChildrenAlphaExcludingSmartSpace = alpha;
|
||||
|
||||
for (int i = 0; i < mStatusViewContainer.getChildCount(); i++) {
|
||||
final View child = mStatusViewContainer.getChildAt(i);
|
||||
|
||||
if (!excludedViews.contains(child)) {
|
||||
child.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets a translationY value on every child view except for the media view. */
|
||||
public void setChildrenTranslationYExcludingMediaView(float translationY) {
|
||||
setChildrenTranslationYExcluding(translationY, Set.of(mMediaHostContainer));
|
||||
@@ -128,10 +110,6 @@ public class KeyguardStatusView extends GridLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public float getChildrenAlphaExcludingSmartSpace() {
|
||||
return mChildrenAlphaExcludingSmartSpace;
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, String[] args) {
|
||||
pw.println("KeyguardStatusView:");
|
||||
pw.println(" mDarkAmount: " + mDarkAmount);
|
||||
|
||||
@@ -20,7 +20,6 @@ import android.graphics.Rect;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
import com.android.systemui.statusbar.notification.AnimatableProperty;
|
||||
import com.android.systemui.statusbar.notification.PropertyAnimator;
|
||||
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
|
||||
@@ -49,10 +48,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
private final KeyguardClockSwitchController mKeyguardClockSwitchController;
|
||||
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
private final ConfigurationController mConfigurationController;
|
||||
private final DozeParameters mDozeParameters;
|
||||
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
|
||||
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
private final Rect mClipBounds = new Rect();
|
||||
|
||||
@Inject
|
||||
@@ -64,18 +60,14 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
ConfigurationController configurationController,
|
||||
DozeParameters dozeParameters,
|
||||
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
|
||||
ScreenOffAnimationController screenOffAnimationController) {
|
||||
super(keyguardStatusView);
|
||||
mKeyguardSliceViewController = keyguardSliceViewController;
|
||||
mKeyguardClockSwitchController = keyguardClockSwitchController;
|
||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||
mConfigurationController = configurationController;
|
||||
mDozeParameters = dozeParameters;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
|
||||
dozeParameters, screenOffAnimationController, /* animateYPos= */ true);
|
||||
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,14 +79,12 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
protected void onViewAttached() {
|
||||
mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
|
||||
mConfigurationController.addCallback(mConfigurationListener);
|
||||
mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewDetached() {
|
||||
mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
|
||||
mConfigurationController.removeCallback(mConfigurationListener);
|
||||
mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,24 +138,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
*/
|
||||
public void setAlpha(float alpha) {
|
||||
if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
|
||||
// If we're capable of performing the SmartSpace shared element transition, and we are
|
||||
// going to (we're swiping to dismiss vs. bringing up the PIN screen), then fade out
|
||||
// everything except for the SmartSpace.
|
||||
if (mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
|
||||
mView.setChildrenAlphaExcludingClockView(alpha);
|
||||
mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(alpha);
|
||||
} else if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
|
||||
// Otherwise, we can just set the alpha for the entire container.
|
||||
mView.setAlpha(alpha);
|
||||
|
||||
// If we previously unlocked with the shared element transition, some child views
|
||||
// might still have alpha = 0f. Set them back to 1f since we're just using the
|
||||
// parent container's alpha.
|
||||
if (mView.getChildrenAlphaExcludingSmartSpace() < 1f) {
|
||||
mView.setChildrenAlphaExcludingClockView(1f);
|
||||
mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(1f);
|
||||
}
|
||||
}
|
||||
mView.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,19 +262,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
}
|
||||
};
|
||||
|
||||
private KeyguardStateController.Callback mKeyguardStateControllerCallback =
|
||||
new KeyguardStateController.Callback() {
|
||||
@Override
|
||||
public void onKeyguardShowingChanged() {
|
||||
// If we explicitly re-show the keyguard, make sure that all the child views are
|
||||
// visible. They might have been animating out as part of the SmartSpace shared
|
||||
// element transition.
|
||||
if (mKeyguardStateController.isShowing()) {
|
||||
mView.setChildrenAlphaExcludingClockView(1f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Rect that specifies how KSV should be clipped, on its parent's coordinates.
|
||||
*/
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.content.Context
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Rect
|
||||
import android.os.Handler
|
||||
import android.provider.Settings
|
||||
import android.os.RemoteException
|
||||
import android.util.Log
|
||||
import android.view.RemoteAnimationTarget
|
||||
import android.view.SyncRtSurfaceTransactionApplier
|
||||
@@ -47,7 +47,6 @@ 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
|
||||
|
||||
const val TAG = "KeyguardUnlock"
|
||||
|
||||
@@ -77,7 +76,7 @@ const val SURFACE_BEHIND_SCALE_PIVOT_Y = 0.66f
|
||||
* The dismiss amount is the inverse of the notification panel expansion, which decreases as the
|
||||
* lock screen is swiped away.
|
||||
*/
|
||||
const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.25f
|
||||
const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.15f
|
||||
|
||||
/**
|
||||
* Dismiss amount at which to complete the keyguard exit animation and hide the keyguard.
|
||||
@@ -85,7 +84,7 @@ const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.25f
|
||||
* The dismiss amount is the inverse of the notification panel expansion, which decreases as the
|
||||
* lock screen is swiped away.
|
||||
*/
|
||||
const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.4f
|
||||
const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.3f
|
||||
|
||||
/**
|
||||
* How long the canned unlock animation takes. This is used if we are unlocking from biometric auth,
|
||||
@@ -112,7 +111,7 @@ const val CANNED_UNLOCK_START_DELAY = 100L
|
||||
* 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
|
||||
const val SURFACE_BEHIND_SWIPE_FADE_DURATION_MS = 175L
|
||||
|
||||
/**
|
||||
* Start delay for the surface behind animation, used so that the lockscreen can get out of the way
|
||||
@@ -151,12 +150,21 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
* [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.
|
||||
*
|
||||
* [unlockAnimationStartDelay] and [unlockAnimationDuration] provide the timing parameters
|
||||
* for the canned animation (if applicable) so interested parties can sync with it. If no
|
||||
* canned animation is playing, these are both 0.
|
||||
*/
|
||||
@JvmDefault
|
||||
fun onUnlockAnimationStarted(playingCannedAnimation: Boolean, fromWakeAndUnlock: Boolean) {}
|
||||
fun onUnlockAnimationStarted(
|
||||
playingCannedAnimation: Boolean,
|
||||
fromWakeAndUnlock: Boolean,
|
||||
unlockAnimationStartDelay: Long,
|
||||
unlockAnimationDuration: Long) {}
|
||||
|
||||
/**
|
||||
* Called when the remote unlock animation ends, in all cases, canned or swipe-to-unlock.
|
||||
@@ -165,19 +173,6 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
*/
|
||||
@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]. */
|
||||
@@ -259,8 +254,9 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
* animation plays.
|
||||
*/
|
||||
private var surfaceBehindAlpha = 1f
|
||||
private var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
|
||||
private var smartspaceAnimator = ValueAnimator.ofFloat(0f, 1f)
|
||||
|
||||
@VisibleForTesting
|
||||
var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
|
||||
|
||||
/**
|
||||
* Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
|
||||
@@ -281,59 +277,38 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
private var roundedCornerRadius = 0f
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Whether we decided in [prepareForInWindowLauncherAnimations] that we are able to and want to
|
||||
* play the in-window launcher unlock animations rather than simply animating the Launcher
|
||||
* window like any other app. This can be true while [willUnlockWithSmartspaceTransition] is
|
||||
* false, if the smartspace is not available or was not ready in time.
|
||||
*/
|
||||
private var attemptedSmartSpaceTransitionForThisSwipe = false
|
||||
private var willUnlockWithInWindowLauncherAnimations: Boolean = false
|
||||
|
||||
/**
|
||||
* The original location of the lockscreen smartspace on the screen.
|
||||
* Whether we decided in [prepareForInWindowLauncherAnimations] that we are able to and want to
|
||||
* play the smartspace shared element animation. If true,
|
||||
* [willUnlockWithInWindowLauncherAnimations] will also always be true since in-window
|
||||
* animations are a prerequisite for the smartspace transition.
|
||||
*/
|
||||
private val smartspaceOriginBounds = Rect()
|
||||
|
||||
/**
|
||||
* 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 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 var willUnlockWithSmartspaceTransition: Boolean = false
|
||||
|
||||
private val handler = Handler()
|
||||
|
||||
init {
|
||||
with(surfaceBehindAlphaAnimator) {
|
||||
duration = SURFACE_BEHIND_SWIPE_FADE_DURATION_MS
|
||||
interpolator = Interpolators.TOUCH_RESPONSE
|
||||
interpolator = Interpolators.LINEAR
|
||||
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 we animated the surface alpha to 0f, it means we cancelled a swipe to
|
||||
// dismiss. In this case, we should ask the KeyguardViewMediator to end the
|
||||
// remote animation to hide the surface behind the keyguard, but should *not*
|
||||
// call onKeyguardExitRemoteAnimationFinished since that will hide the keyguard
|
||||
// and unlock the device as well as hiding the surface.
|
||||
if (surfaceBehindAlpha == 0f) {
|
||||
keyguardViewMediator.get().finishSurfaceBehindRemoteAnimation(
|
||||
false /* cancelled */)
|
||||
@@ -360,21 +335,6 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -393,6 +353,74 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 &&
|
||||
!keyguardStateController.isDismissingFromSwipe &&
|
||||
// Temporarily disable for foldables since foldable launcher has two first pages,
|
||||
// which breaks the in-window animation.
|
||||
!isFoldable(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from [KeyguardStateController] to let us know that the keyguard going away state has
|
||||
* changed.
|
||||
*/
|
||||
override fun onKeyguardGoingAwayChanged() {
|
||||
if (keyguardStateController.isKeyguardGoingAway) {
|
||||
prepareForInWindowLauncherAnimations()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare for in-window Launcher unlock animations, if we're able to do so.
|
||||
*
|
||||
* The in-window animations consist of the staggered ring icon unlock animation, and optionally
|
||||
* the shared element smartspace transition.
|
||||
*/
|
||||
fun prepareForInWindowLauncherAnimations() {
|
||||
willUnlockWithInWindowLauncherAnimations = canPerformInWindowLauncherAnimations()
|
||||
|
||||
if (!willUnlockWithInWindowLauncherAnimations) {
|
||||
return
|
||||
}
|
||||
|
||||
// There are additional conditions under which we should not perform the smartspace
|
||||
// transition specifically, so check those.
|
||||
willUnlockWithSmartspaceTransition = shouldPerformSmartspaceTransition()
|
||||
|
||||
var lockscreenSmartspaceBounds = Rect()
|
||||
|
||||
// Grab the bounds of our lockscreen smartspace and send them to launcher so they can
|
||||
// position their smartspace there initially, then animate it to its resting position.
|
||||
if (willUnlockWithSmartspaceTransition) {
|
||||
lockscreenSmartspaceBounds = Rect().apply {
|
||||
lockscreenSmartspace!!.getBoundsOnScreen(this)
|
||||
offset(lockscreenSmartspace!!.paddingLeft, lockscreenSmartspace!!.paddingTop)
|
||||
}
|
||||
}
|
||||
|
||||
// Currently selected lockscreen smartspace page, or -1 if it's not available.
|
||||
val selectedPage =
|
||||
(lockscreenSmartspace as BcSmartspaceDataPlugin.SmartspaceView?)?.selectedPage ?: -1
|
||||
|
||||
try {
|
||||
|
||||
// Let the launcher know to prepare for this animation.
|
||||
launcherUnlockController?.prepareForUnlock(
|
||||
willUnlockWithSmartspaceTransition, /* willAnimateSmartspace */
|
||||
lockscreenSmartspaceBounds, /* lockscreenSmartspaceBounds */
|
||||
selectedPage, /* selectedPage */
|
||||
)
|
||||
} catch (e: RemoteException) {
|
||||
Log.e(TAG, "Remote exception in prepareForInWindowUnlockAnimations.", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from [KeyguardViewMediator] to tell us that the RemoteAnimation on the surface behind
|
||||
* the keyguard has started successfully. We can use these parameters to directly manipulate the
|
||||
@@ -404,7 +432,8 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
*
|
||||
* [requestedShowSurfaceBehindKeyguard] indicates whether the animation started because of a
|
||||
* call to [KeyguardViewMediator.showSurfaceBehindKeyguard], as happens during a swipe gesture,
|
||||
* as opposed to being called because the device was unlocked and the keyguard is going away.
|
||||
* as opposed to being called because the device was unlocked instantly by some other means
|
||||
* (fingerprint, tap, etc.) and the keyguard is going away.
|
||||
*/
|
||||
fun notifyStartSurfaceBehindRemoteAnimation(
|
||||
target: RemoteAnimationTarget,
|
||||
@@ -434,7 +463,9 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
listeners.forEach {
|
||||
it.onUnlockAnimationStarted(
|
||||
playingCannedUnlockAnimation /* playingCannedAnimation */,
|
||||
biometricUnlockControllerLazy.get().isWakeAndUnlock /* isWakeAndUnlock */) }
|
||||
biometricUnlockControllerLazy.get().isWakeAndUnlock /* isWakeAndUnlock */,
|
||||
CANNED_UNLOCK_START_DELAY /* unlockStartDelay */,
|
||||
LAUNCHER_ICONS_ANIMATION_DURATION_MS /* unlockAnimationDuration */) }
|
||||
|
||||
// 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
|
||||
@@ -442,58 +473,33 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
finishKeyguardExitRemoteAnimationIfReachThreshold()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
private 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)
|
||||
when {
|
||||
// If we're set up for in-window launcher animations, ask Launcher to play its in-window
|
||||
// canned animation.
|
||||
willUnlockWithInWindowLauncherAnimations -> unlockToLauncherWithInWindowAnimations()
|
||||
|
||||
// If we're waking and unlocking to a non-Launcher app surface (or Launcher in-window
|
||||
// animations are not available), show it immediately and end the remote animation. The
|
||||
// circular light reveal will show the app surface, and it looks weird if it's moving
|
||||
// around behind that.
|
||||
biometricUnlockControllerLazy.get().isWakeAndUnlock -> {
|
||||
setSurfaceBehindAppearAmount(1f)
|
||||
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
|
||||
false /* cancelled */)
|
||||
}
|
||||
|
||||
// Otherwise, we're doing a normal full-window unlock. Start this animator, which will
|
||||
// scale/translate the window underneath the lockscreen.
|
||||
else -> surfaceBehindEntryAnimator.start()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,205 +508,31 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
* transition if possible.
|
||||
*/
|
||||
private fun unlockToLauncherWithInWindowAnimations() {
|
||||
// See if we can do the smartspace transition, and if so, do it!
|
||||
if (prepareForSmartspaceTransition()) {
|
||||
animateSmartspaceToDestination()
|
||||
listeners.forEach { it.onSmartspaceSharedElementTransitionStarted() }
|
||||
}
|
||||
|
||||
val startDelay = Settings.Secure.getLong(
|
||||
context.contentResolver, "unlock_start_delay", CANNED_UNLOCK_START_DELAY)
|
||||
val duration = Settings.Secure.getLong(
|
||||
context.contentResolver, "unlock_duration", LAUNCHER_ICONS_ANIMATION_DURATION_MS)
|
||||
|
||||
unlockingToLauncherWithInWindowAnimations = true
|
||||
prepareLauncherWorkspaceForUnlockAnimation()
|
||||
setSurfaceBehindAppearAmount(1f)
|
||||
|
||||
// Begin the animation, waiting for the shade to animate out.
|
||||
launcherUnlockController?.playUnlockAnimation(
|
||||
true /* unlocked */,
|
||||
duration /* duration */,
|
||||
startDelay /* startDelay */)
|
||||
LAUNCHER_ICONS_ANIMATION_DURATION_MS /* duration */,
|
||||
CANNED_UNLOCK_START_DELAY /* startDelay */)
|
||||
|
||||
// Now that the Launcher surface (with its smartspace positioned identically to ours) is
|
||||
// visible, hide our smartspace.
|
||||
lockscreenSmartspace!!.visibility = View.INVISIBLE
|
||||
|
||||
// As soon as the shade has animated out of the way, finish the keyguard exit animation. The
|
||||
// in-window animations in the Launcher window will end on their own.
|
||||
handler.postDelayed({
|
||||
applyParamsToSurface(
|
||||
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
|
||||
surfaceBehindRemoteAnimationTarget!!.leash)
|
||||
.withAlpha(1f)
|
||||
.build())
|
||||
}, startDelay)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks Launcher to prepare the workspace to be unlocked. This sets up the animation and makes
|
||||
* the page invisible.
|
||||
*/
|
||||
private fun prepareLauncherWorkspaceForUnlockAnimation() {
|
||||
// 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)
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the lockscreen smartspace all the way to the launcher's smartspace location, then
|
||||
* makes the launcher smartspace visible and ends the remote animation.
|
||||
*/
|
||||
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() {
|
||||
setSmartspaceProgressToDestinationBounds(smartspaceUnlockProgress)
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the keyguard view to hide, using the start time from the beginning of the remote
|
||||
* animation.
|
||||
*/
|
||||
fun hideKeyguardViewAfterRemoteAnimation() {
|
||||
if (keyguardViewController.isShowing) {
|
||||
// Hide the keyguard, with no fade out since we animated it away during the unlock.
|
||||
keyguardViewController.hide(
|
||||
surfaceBehindRemoteAnimationStartTime,
|
||||
0 /* fadeOutDuration */
|
||||
)
|
||||
} else {
|
||||
Log.e(TAG, "#hideKeyguardViewAfterRemoteAnimation called when keyguard view is not " +
|
||||
"showing. Ignoring...")
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyParamsToSurface(params: SyncRtSurfaceTransactionApplier.SurfaceParams) {
|
||||
surfaceTransactionApplier!!.scheduleApply(params)
|
||||
surfaceBehindParams = params
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales in and translates up the surface behind the keyguard. This is used during unlock
|
||||
* animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
|
||||
* cancelled).
|
||||
*/
|
||||
fun setSurfaceBehindAppearAmount(amount: Float) {
|
||||
if (surfaceBehindRemoteAnimationTarget == null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (unlockingToLauncherWithInWindowAnimations) {
|
||||
// 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)
|
||||
|
||||
if (surfaceBehindParams?.alpha?.let { it < 1f } != false) {
|
||||
applyParamsToSurface(
|
||||
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
|
||||
surfaceBehindRemoteAnimationTarget!!.leash)
|
||||
.withAlpha(1f)
|
||||
.build())
|
||||
}
|
||||
if (keyguardViewMediator.get().isShowingAndNotOccluded &&
|
||||
!keyguardStateController.isKeyguardGoingAway) {
|
||||
Log.e(TAG, "Finish keyguard exit animation delayed Runnable ran, but we are " +
|
||||
"showing and not going away.")
|
||||
return@postDelayed
|
||||
}
|
||||
} 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
|
||||
)
|
||||
|
||||
// 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 (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount
|
||||
else surfaceBehindAlpha
|
||||
|
||||
applyParamsToSurface(
|
||||
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
|
||||
surfaceBehindRemoteAnimationTarget!!.leash)
|
||||
.withMatrix(surfaceBehindMatrix)
|
||||
.withCornerRadius(roundedCornerRadius)
|
||||
.withAlpha(animationAlpha)
|
||||
.build())
|
||||
}
|
||||
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
|
||||
false /* cancelled */)
|
||||
}, CANNED_UNLOCK_START_DELAY)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -738,7 +570,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
if (keyguardViewController.isShowing) {
|
||||
if (keyguardViewController.isShowing && !playingCannedUnlockAnimation) {
|
||||
showOrHideSurfaceIfDismissAmountThresholdsReached()
|
||||
|
||||
// If the surface is visible or it's about to be, start updating its appearance to
|
||||
@@ -750,11 +582,6 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
updateSurfaceBehindAppearAmount()
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
applyDismissAmountToSmartspaceTransition()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -775,16 +602,15 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
if (!keyguardStateController.isShowing) {
|
||||
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 (!unlockingToLauncherWithInWindowAnimations &&
|
||||
canPerformInWindowLauncherAnimations()) {
|
||||
unlockingToLauncherWithInWindowAnimations = true
|
||||
prepareLauncherWorkspaceForUnlockAnimation()
|
||||
}
|
||||
!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
|
||||
|
||||
keyguardViewMediator.get().showSurfaceBehindKeyguard()
|
||||
fadeInSurfaceBehind()
|
||||
} else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
|
||||
@@ -828,58 +654,101 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates flags related to the SmartSpace transition in response to a change in keyguard
|
||||
* dismiss amount, and also updates the SmartSpaceTransitionController, which will let Launcher
|
||||
* know if it needs to do something as a result.
|
||||
* Scales in and translates up the surface behind the keyguard. This is used during unlock
|
||||
* animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
|
||||
* cancelled).
|
||||
*/
|
||||
private fun applyDismissAmountToSmartspaceTransition() {
|
||||
if (!featureFlags.isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED)) {
|
||||
fun setSurfaceBehindAppearAmount(amount: Float) {
|
||||
if (surfaceBehindRemoteAnimationTarget == null) {
|
||||
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
|
||||
// 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
|
||||
)
|
||||
|
||||
// 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 (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount
|
||||
else surfaceBehindAlpha
|
||||
|
||||
applyParamsToSurface(
|
||||
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
|
||||
surfaceBehindRemoteAnimationTarget!!.leash)
|
||||
.withMatrix(surfaceBehindMatrix)
|
||||
.withCornerRadius(roundedCornerRadius)
|
||||
.withAlpha(animationAlpha)
|
||||
.build())
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and
|
||||
* we should clean up all of our state.
|
||||
*
|
||||
* This is generally triggered by us, calling
|
||||
* [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation].
|
||||
*/
|
||||
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. If the launcher is doing its own animation, let it continue without
|
||||
// forcing it to 1f.
|
||||
setSurfaceBehindAppearAmount(1f)
|
||||
launcherUnlockController?.setUnlockAmount(1f, false /* forceIfAnimating */)
|
||||
|
||||
// That target is no longer valid since the animation finished, null it out.
|
||||
surfaceBehindRemoteAnimationTarget = null
|
||||
surfaceBehindParams = null
|
||||
|
||||
playingCannedUnlockAnimation = false
|
||||
willUnlockWithInWindowLauncherAnimations = false
|
||||
willUnlockWithSmartspaceTransition = false
|
||||
|
||||
// The lockscreen surface is gone, so it is now safe to re-show the smartspace.
|
||||
lockscreenSmartspace!!.visibility = View.VISIBLE
|
||||
|
||||
listeners.forEach { it.onUnlockAnimationFinished() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the keyguard view to hide, using the start time from the beginning of the remote
|
||||
* animation.
|
||||
*/
|
||||
fun hideKeyguardViewAfterRemoteAnimation() {
|
||||
if (keyguardViewController.isShowing) {
|
||||
// Hide the keyguard, with no fade out since we animated it away during the unlock.
|
||||
|
||||
keyguardViewController.hide(
|
||||
surfaceBehindRemoteAnimationStartTime,
|
||||
0 /* fadeOutDuration */
|
||||
)
|
||||
} else {
|
||||
Log.e(TAG, "#hideKeyguardViewAfterRemoteAnimation called when keyguard view is not " +
|
||||
"showing. Ignoring...")
|
||||
}
|
||||
}
|
||||
|
||||
val dismissAmount = keyguardStateController.dismissAmount
|
||||
|
||||
// If we've begun a swipe, and haven't yet tried doing the SmartSpace transition, do that
|
||||
// now.
|
||||
if (!attemptedSmartSpaceTransitionForThisSwipe &&
|
||||
keyguardViewController.isShowing &&
|
||||
dismissAmount > 0f &&
|
||||
dismissAmount < 1f) {
|
||||
attemptedSmartSpaceTransitionForThisSwipe = true
|
||||
|
||||
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)) {
|
||||
attemptedSmartSpaceTransitionForThisSwipe = false
|
||||
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)
|
||||
}
|
||||
private fun applyParamsToSurface(params: SyncRtSurfaceTransactionApplier.SurfaceParams) {
|
||||
surfaceTransactionApplier!!.scheduleApply(params)
|
||||
surfaceBehindParams = params
|
||||
}
|
||||
|
||||
private fun fadeInSurfaceBehind() {
|
||||
@@ -892,14 +761,8 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
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 {
|
||||
|
||||
private fun shouldPerformSmartspaceTransition(): Boolean {
|
||||
// Feature is disabled, so we don't want to.
|
||||
if (!featureFlags.isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED)) {
|
||||
return false
|
||||
@@ -940,45 +803,22 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
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)
|
||||
// We started to swipe to dismiss, but now we're doing a fling animation to complete the
|
||||
// dismiss. In this case, the smartspace swiped away with the rest of the keyguard, so don't
|
||||
// do the shared element transition.
|
||||
if (keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture) {
|
||||
return false
|
||||
}
|
||||
|
||||
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 &&
|
||||
// Temporarily disable for foldables since foldable launcher has two first pages,
|
||||
// which breaks the in-window animation.
|
||||
!isFoldable(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
return willUnlockWithSmartspaceTransition
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2654,7 +2654,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
|
||||
}
|
||||
|
||||
/** If it's running, finishes the RemoteAnimation on the surface behind the keyguard. */
|
||||
public void finishSurfaceBehindRemoteAnimation(boolean cancelled) {
|
||||
void finishSurfaceBehindRemoteAnimation(boolean cancelled) {
|
||||
if (!mSurfaceBehindRemoteAnimationRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2954,8 +2954,6 @@ public class CentralSurfacesImpl extends CoreStartable implements
|
||||
@Override
|
||||
public void showKeyguardImpl() {
|
||||
Trace.beginSection("CentralSurfaces#showKeyguard");
|
||||
// In case we're locking while a smartspace transition is in progress, reset it.
|
||||
mKeyguardUnlockAnimationController.resetSmartspaceTransition();
|
||||
if (mKeyguardStateController.isLaunchTransitionFadingAway()) {
|
||||
mNotificationPanelViewController.cancelAnimation();
|
||||
onLaunchTransitionFadingEnded();
|
||||
|
||||
@@ -885,7 +885,10 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
|
||||
@Override
|
||||
public void onUnlockAnimationStarted(
|
||||
boolean playingCannedAnimation, boolean isWakeAndUnlock) {
|
||||
boolean playingCannedAnimation,
|
||||
boolean isWakeAndUnlock,
|
||||
long unlockAnimationStartDelay,
|
||||
long unlockAnimationDuration) {
|
||||
// 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
|
||||
@@ -902,7 +905,22 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
onTrackingStopped(false);
|
||||
instantCollapse();
|
||||
} else {
|
||||
fling(0f, false, 1f, false);
|
||||
mView.animate()
|
||||
.alpha(0f)
|
||||
.setStartDelay(0)
|
||||
// Translate up by 4%.
|
||||
.translationY(mView.getHeight() * -0.04f)
|
||||
// This start delay is to give us time to animate out before
|
||||
// the launcher icons animation starts, so use that as our
|
||||
// duration.
|
||||
.setDuration(unlockAnimationStartDelay)
|
||||
.setInterpolator(EMPHASIZED_DECELERATE)
|
||||
.withEndAction(() -> {
|
||||
instantCollapse();
|
||||
mView.setAlpha(1f);
|
||||
mView.setTranslationY(0f);
|
||||
})
|
||||
.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
import com.android.systemui.statusbar.phone.DozeParameters;
|
||||
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
@@ -55,8 +54,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
DozeParameters mDozeParameters;
|
||||
@Mock
|
||||
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||
@Mock
|
||||
ScreenOffAnimationController mScreenOffAnimationController;
|
||||
@Captor
|
||||
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
|
||||
@@ -75,7 +72,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
|
||||
mKeyguardUpdateMonitor,
|
||||
mConfigurationController,
|
||||
mDozeParameters,
|
||||
mKeyguardUnlockAnimationController,
|
||||
mScreenOffAnimationController);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user