Merge "Adds the continuous unlock animation!" into sc-dev
This commit is contained in:
@@ -145,6 +145,13 @@ public interface KeyguardViewController {
|
||||
*/
|
||||
void startPreHideAnimation(Runnable finishRunnable);
|
||||
|
||||
/**
|
||||
* Blocks the current touch gesture from affecting the expansion amount of the notification
|
||||
* panel. This is used after a completed unlock gesture to ignore further dragging before an
|
||||
* ACTION_UP.
|
||||
*/
|
||||
void blockPanelExpansionFromCurrentTouch();
|
||||
|
||||
/**
|
||||
* @return the ViewRootImpl of the View where the Keyguard is mounted.
|
||||
*/
|
||||
|
||||
@@ -70,7 +70,7 @@ public class KeyguardService extends Service {
|
||||
/**
|
||||
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
|
||||
*/
|
||||
private static boolean sEnableRemoteKeyguardAnimation =
|
||||
static boolean sEnableRemoteKeyguardAnimation =
|
||||
SystemProperties.getBoolean(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, false);
|
||||
|
||||
private final KeyguardViewMediator mKeyguardViewMediator;
|
||||
@@ -138,6 +138,7 @@ public class KeyguardService extends Service {
|
||||
|
||||
@Override // Binder interface
|
||||
public void onAnimationCancelled() {
|
||||
mKeyguardViewMediator.cancelKeyguardExitAnimation();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* 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.keyguard
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.graphics.Matrix
|
||||
import android.view.RemoteAnimationTarget
|
||||
import android.view.SyncRtSurfaceTransactionApplier
|
||||
import androidx.core.math.MathUtils
|
||||
import com.android.internal.R
|
||||
import com.android.keyguard.KeyguardViewController
|
||||
import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import dagger.Lazy
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Starting scale factor for the app/launcher surface behind the keyguard, when it's animating
|
||||
* in during keyguard exit.
|
||||
*/
|
||||
const val SURFACE_BEHIND_START_SCALE_FACTOR = 0.95f
|
||||
|
||||
/**
|
||||
* How much to translate the surface behind the keyguard at the beginning of the exit animation,
|
||||
* in terms of percentage of the surface's height.
|
||||
*/
|
||||
const val SURFACE_BEHIND_START_TRANSLATION_Y = 0.05f
|
||||
|
||||
/**
|
||||
* Y coordinate of the pivot point for the scale effect on the surface behind the keyguard. This
|
||||
* is expressed as percentage of the surface's height, so 0.66f means the surface will scale up
|
||||
* from the point at (width / 2, height * 0.66).
|
||||
*/
|
||||
const val SURFACE_BEHIND_SCALE_PIVOT_Y = 0.66f
|
||||
|
||||
/**
|
||||
* Dismiss amount at which to fade in the surface behind the keyguard. The surface will then animate
|
||||
* along with the dismiss amount until [DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD] is reached.
|
||||
*
|
||||
* 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.1f
|
||||
|
||||
/**
|
||||
* Dismiss amount at which to complete the keyguard exit animation and hide the keyguard.
|
||||
*
|
||||
* 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.3f
|
||||
|
||||
/**
|
||||
* Initiates, controls, and ends the keyguard unlock animation.
|
||||
*
|
||||
* The unlock animation transitions between the keyguard (lock screen) and the app/launcher surface
|
||||
* behind the keyguard. If the user is swiping away the keyguard, this controller will decide when
|
||||
* to animate in the surface, and synchronize its appearance with the swipe gesture. If the keyguard
|
||||
* is animating away via a canned animation (due to biometric unlock, tapping a notification, etc.)
|
||||
* 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].
|
||||
*/
|
||||
@SysUISingleton
|
||||
class KeyguardUnlockAnimationController @Inject constructor(
|
||||
context: Context,
|
||||
private val keyguardStateController: KeyguardStateController,
|
||||
private val keyguardViewMediator: Lazy<KeyguardViewMediator>,
|
||||
private val keyguardViewController: KeyguardViewController
|
||||
) : KeyguardStateController.Callback {
|
||||
|
||||
/**
|
||||
* Information used to start, run, and finish a RemoteAnimation on the app or launcher surface
|
||||
* behind the keyguard.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* If we're unlocking via biometrics, PIN entry, or from clicking a notification, a canned
|
||||
* animation is started in [notifyStartKeyguardExitAnimation].
|
||||
*/
|
||||
private var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null
|
||||
private var surfaceBehindRemoteAnimationTarget: RemoteAnimationTarget? = null
|
||||
private var surfaceBehindRemoteAnimationStartTime: Long = 0
|
||||
|
||||
/**
|
||||
* Alpha value applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
|
||||
* app/launcher behind the keyguard.
|
||||
*
|
||||
* If we're doing a swipe gesture, we fade in the surface when the swipe passes a certain
|
||||
* threshold. If we're doing a canned animation, it'll be faded in while a translate/scale
|
||||
* animation plays.
|
||||
*/
|
||||
private var surfaceBehindAlpha = 1f
|
||||
private var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
|
||||
|
||||
/**
|
||||
* Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
|
||||
* app/launcher behind the keyguard.
|
||||
*
|
||||
* This is used during the unlock animation/swipe gesture to scale and translate the surface.
|
||||
*/
|
||||
private val surfaceBehindMatrix = Matrix()
|
||||
|
||||
/**
|
||||
* Animator that animates in the surface behind the keyguard. This is used to play a canned
|
||||
* animation on the surface, if we're not doing a swipe gesture.
|
||||
*/
|
||||
private val surfaceBehindEntryAnimator = ValueAnimator.ofFloat(0f, 1f)
|
||||
|
||||
/** Rounded corner radius to apply to the surface behind the keyguard. */
|
||||
private var roundedCornerRadius = 0f
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
surfaceBehindEntryAnimator.duration = 450
|
||||
surfaceBehindEntryAnimator.interpolator = Interpolators.DECELERATE_QUINT
|
||||
surfaceBehindEntryAnimator.addUpdateListener { valueAnimator: ValueAnimator ->
|
||||
surfaceBehindAlpha = valueAnimator.animatedValue as Float
|
||||
setSurfaceBehindAppearAmount(valueAnimator.animatedValue as Float)
|
||||
}
|
||||
surfaceBehindEntryAnimator.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished()
|
||||
}
|
||||
})
|
||||
|
||||
// Listen for changes in the dismiss amount.
|
||||
keyguardStateController.addCallback(this)
|
||||
|
||||
roundedCornerRadius =
|
||||
context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* surface for the unlock gesture/animation.
|
||||
*
|
||||
* When we're done with it, we'll call [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation]
|
||||
* to end the RemoteAnimation.
|
||||
*
|
||||
* [requestedShowSurfaceBehindKeyguard] denotes whether the exit animation started because of a
|
||||
* call to [KeyguardViewMediator.showSurfaceBehindKeyguard], as happens during a swipe gesture,
|
||||
* as opposed to the keyguard hiding.
|
||||
*/
|
||||
fun notifyStartKeyguardExitAnimation(
|
||||
target: RemoteAnimationTarget,
|
||||
startTime: Long,
|
||||
requestedShowSurfaceBehindKeyguard: Boolean
|
||||
) {
|
||||
|
||||
if (surfaceTransactionApplier == null) {
|
||||
surfaceTransactionApplier = SyncRtSurfaceTransactionApplier(
|
||||
keyguardViewController.viewRootImpl.view)
|
||||
}
|
||||
|
||||
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 (!requestedShowSurfaceBehindKeyguard) {
|
||||
keyguardViewController.hide(startTime, 350)
|
||||
surfaceBehindEntryAnimator.start()
|
||||
}
|
||||
}
|
||||
|
||||
fun notifyCancelKeyguardExitAnimation() {
|
||||
surfaceBehindRemoteAnimationTarget = null
|
||||
}
|
||||
|
||||
fun notifyFinishedKeyguardExitAnimation() {
|
||||
surfaceBehindRemoteAnimationTarget = null
|
||||
}
|
||||
|
||||
fun hideKeyguardViewAfterRemoteAnimation() {
|
||||
keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 setSurfaceBehindAppearAmount(amount: Float) {
|
||||
if (surfaceBehindRemoteAnimationTarget == null) {
|
||||
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))
|
||||
|
||||
// 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
|
||||
|
||||
val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
|
||||
surfaceBehindRemoteAnimationTarget!!.leash)
|
||||
.withMatrix(surfaceBehindMatrix)
|
||||
.withCornerRadius(roundedCornerRadius)
|
||||
.withAlpha(animationAlpha)
|
||||
.build()
|
||||
surfaceTransactionApplier!!.scheduleApply(params)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the appearance amount of the surface behind the keyguard, according to the current
|
||||
* keyguard dismiss amount and the method of dismissal.
|
||||
*/
|
||||
private fun updateSurfaceBehindAppearAmount() {
|
||||
if (surfaceBehindRemoteAnimationTarget == null) {
|
||||
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
|
||||
// interaction tight.
|
||||
if (keyguardStateController.isFlingingToDismissKeyguard) {
|
||||
setSurfaceBehindAppearAmount(keyguardStateController.dismissAmount)
|
||||
} else if (keyguardStateController.isDismissingFromSwipe ||
|
||||
keyguardStateController.isSnappingKeyguardBackAfterSwipe) {
|
||||
val totalSwipeDistanceToDismiss =
|
||||
(DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD - DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD)
|
||||
val swipedDistanceSoFar: Float =
|
||||
keyguardStateController.dismissAmount - DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD
|
||||
val progress = swipedDistanceSoFar / totalSwipeDistanceToDismiss
|
||||
setSurfaceBehindAppearAmount(progress)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onKeyguardDismissAmountChanged() {
|
||||
if (!KeyguardService.sEnableRemoteKeyguardAnimation) {
|
||||
return
|
||||
}
|
||||
|
||||
val dismissAmount = keyguardStateController.dismissAmount
|
||||
|
||||
// Hide the keyguard if we're fully dismissed, or if we're swiping to dismiss and have
|
||||
// crossed the threshold to finish the dismissal.
|
||||
val reachedHideKeyguardThreshold = (dismissAmount >= 1f ||
|
||||
(keyguardStateController.isDismissingFromSwipe &&
|
||||
// Don't hide if we're flinging during a swipe, since we need to finish
|
||||
// animating it out. This will be called again after the fling ends.
|
||||
!keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
|
||||
dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
|
||||
|
||||
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.
|
||||
keyguardViewMediator.get().showSurfaceBehindKeyguard()
|
||||
fadeInSurfaceBehind()
|
||||
} else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
|
||||
keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
|
||||
// We're no longer past the threshold but we are showing the surface. Animate it out.
|
||||
keyguardViewMediator.get().hideSurfaceBehindKeyguard()
|
||||
fadeOutSurfaceBehind()
|
||||
} else if (keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
|
||||
reachedHideKeyguardThreshold) {
|
||||
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished()
|
||||
}
|
||||
|
||||
if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
|
||||
keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
|
||||
updateSurfaceBehindAppearAmount()
|
||||
}
|
||||
}
|
||||
|
||||
private fun fadeInSurfaceBehind() {
|
||||
surfaceBehindAlphaAnimator.cancel()
|
||||
surfaceBehindAlphaAnimator.start()
|
||||
}
|
||||
|
||||
private fun fadeOutSurfaceBehind() {
|
||||
surfaceBehindAlphaAnimator.cancel()
|
||||
surfaceBehindAlphaAnimator.reverse()
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.systemui.keyguard;
|
||||
|
||||
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
|
||||
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
|
||||
|
||||
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN;
|
||||
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
|
||||
@@ -72,7 +73,6 @@ import android.util.SparseIntArray;
|
||||
import android.view.IRemoteAnimationFinishedCallback;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.SyncRtSurfaceTransactionApplier;
|
||||
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
@@ -109,6 +109,7 @@ import com.android.systemui.statusbar.phone.DozeParameters;
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
||||
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.DeviceConfigProxy;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
@@ -195,6 +196,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
private static final int NOTIFY_SCREEN_TURNED_OFF = 16;
|
||||
private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17;
|
||||
private static final int SYSTEM_READY = 18;
|
||||
private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19;
|
||||
|
||||
/**
|
||||
* The default amount of time we stay awake (used for all key input)
|
||||
@@ -350,7 +352,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
private int mUnlockSoundId;
|
||||
private int mTrustedSoundId;
|
||||
private int mLockSoundStreamId;
|
||||
|
||||
/**
|
||||
* The animation used for hiding keyguard. This is used to fetch the animation timings if
|
||||
* WindowManager is not providing us with them.
|
||||
@@ -400,6 +401,29 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
private IKeyguardDrawnCallback mDrawnCallback;
|
||||
private CharSequence mCustomMessage;
|
||||
|
||||
/**
|
||||
* Whether the RemoteAnimation on the app/launcher surface behind the keyguard is 'running'.
|
||||
* Note that this does not necessarily mean the surface is currently in motion - we may be
|
||||
* 'animating' it along with the user's finger during a swipe to unlock gesture, a gesture that
|
||||
* can be paused or reversed.
|
||||
*/
|
||||
private boolean mSurfaceBehindRemoteAnimationRunning;
|
||||
|
||||
/**
|
||||
* Whether we've asked to make the app/launcher surface behind the keyguard visible, via a call
|
||||
* to {@link android.app.IActivityTaskManager#keyguardGoingAway(int)}.
|
||||
*
|
||||
* Since that's an IPC, this doesn't necessarily mean the remote animation has started yet.
|
||||
* {@link #mSurfaceBehindRemoteAnimationRunning} will be true if the call completed and the
|
||||
* animation is now running.
|
||||
*/
|
||||
private boolean mSurfaceBehindRemoteAnimationRequested = false;
|
||||
|
||||
/**
|
||||
* Callback to run to end the RemoteAnimation on the app/launcher surface behind the keyguard.
|
||||
*/
|
||||
private IRemoteAnimationFinishedCallback mSurfaceBehindRemoteAnimationFinishedCallback;
|
||||
|
||||
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
|
||||
new DeviceConfig.OnPropertiesChangedListener() {
|
||||
@Override
|
||||
@@ -735,6 +759,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
private DeviceConfigProxy mDeviceConfig;
|
||||
private DozeParameters mDozeParameters;
|
||||
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
private final Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
|
||||
|
||||
/**
|
||||
* Injected constructor. See {@link KeyguardModule}.
|
||||
*/
|
||||
@@ -752,7 +779,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
NavigationModeController navigationModeController,
|
||||
KeyguardDisplayManager keyguardDisplayManager,
|
||||
DozeParameters dozeParameters,
|
||||
StatusBarStateController statusBarStateController) {
|
||||
StatusBarStateController statusBarStateController,
|
||||
KeyguardStateController keyguardStateController,
|
||||
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationControllerLazy) {
|
||||
super(context);
|
||||
mFalsingCollector = falsingCollector;
|
||||
mLockPatternUtils = lockPatternUtils;
|
||||
@@ -780,6 +809,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
}));
|
||||
mDozeParameters = dozeParameters;
|
||||
statusBarStateController.addCallback(this);
|
||||
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
mKeyguardUnlockAnimationControllerLazy = keyguardUnlockAnimationControllerLazy;
|
||||
}
|
||||
|
||||
public void userActivity() {
|
||||
@@ -1732,6 +1764,12 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
mFalsingCollector.onSuccessfulUnlock();
|
||||
Trace.endSection();
|
||||
break;
|
||||
case CANCEL_KEYGUARD_EXIT_ANIM:
|
||||
Trace.beginSection(
|
||||
"KeyguardViewMediator#handleMessage CANCEL_KEYGUARD_EXIT_ANIM");
|
||||
handleCancelKeyguardExitAnimation();
|
||||
Trace.endSection();
|
||||
break;
|
||||
case KEYGUARD_DONE_PENDING_TIMEOUT:
|
||||
Trace.beginSection("KeyguardViewMediator#handleMessage"
|
||||
+ " KEYGUARD_DONE_PENDING_TIMEOUT");
|
||||
@@ -1943,7 +1981,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
|
||||
int flags = 0;
|
||||
if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock()
|
||||
|| (mWakeAndUnlocking && !mPulsing)) {
|
||||
|| (mWakeAndUnlocking && !mPulsing)
|
||||
|| isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
|
||||
flags |= WindowManagerPolicyConstants
|
||||
.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
|
||||
}
|
||||
@@ -1952,7 +1991,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
|
||||
}
|
||||
if (mKeyguardViewControllerLazy.get().isUnlockWithWallpaper()) {
|
||||
flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
|
||||
flags |= KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
|
||||
}
|
||||
if (mKeyguardViewControllerLazy.get().shouldSubtleWindowAnimationsForUnlock()) {
|
||||
flags |= WindowManagerPolicyConstants
|
||||
@@ -2033,8 +2072,13 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
+ " fadeoutDuration=" + fadeoutDuration);
|
||||
synchronized (KeyguardViewMediator.this) {
|
||||
|
||||
if (!mHiding) {
|
||||
// Tell ActivityManager that we canceled the keyguardExitAnimation.
|
||||
// Tell ActivityManager that we canceled the keyguard animation if
|
||||
// handleStartKeyguardExitAnimation was called but we're not hiding the keyguard, unless
|
||||
// we're animating the surface behind the keyguard and will be hiding the keyguard
|
||||
// shortly.
|
||||
if (!mHiding
|
||||
&& !mSurfaceBehindRemoteAnimationRequested
|
||||
&& !mKeyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture()) {
|
||||
setShowingLocked(mShowing, true /* force */);
|
||||
return;
|
||||
}
|
||||
@@ -2056,61 +2100,184 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
playSounds(false);
|
||||
}
|
||||
|
||||
setShowingLocked(false);
|
||||
mWakeAndUnlocking = false;
|
||||
mDismissCallbackRegistry.notifyDismissSucceeded();
|
||||
mKeyguardViewControllerLazy.get().hide(startTime, fadeoutDuration);
|
||||
if (KeyguardService.sEnableRemoteKeyguardAnimation) {
|
||||
mSurfaceBehindRemoteAnimationFinishedCallback = finishedCallback;
|
||||
mSurfaceBehindRemoteAnimationRunning = true;
|
||||
|
||||
// TODO(bc-animation): When remote animation is enabled for keyguard exit animation,
|
||||
// apps, wallpapers and finishedCallback are set to non-null. nonApps is not yet
|
||||
// supported, so it's always null.
|
||||
mContext.getMainExecutor().execute(() -> {
|
||||
if (finishedCallback == null) {
|
||||
if (apps != null && apps.length > 0) {
|
||||
// Pass the surface and metadata to the unlock animation controller.
|
||||
mKeyguardUnlockAnimationControllerLazy.get().notifyStartKeyguardExitAnimation(
|
||||
apps[0], startTime, mSurfaceBehindRemoteAnimationRequested);
|
||||
} else {
|
||||
// We weren't given any surfaces to animate, so just finish.
|
||||
onKeyguardExitRemoteAnimationFinished();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
setShowingLocked(false);
|
||||
mWakeAndUnlocking = false;
|
||||
mDismissCallbackRegistry.notifyDismissSucceeded();
|
||||
mKeyguardViewControllerLazy.get().hide(startTime, fadeoutDuration);
|
||||
|
||||
// TODO(bc-unlock): Sample animation, just to apply alpha animation on the app.
|
||||
final SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(
|
||||
mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
|
||||
final RemoteAnimationTarget primary = apps[0];
|
||||
ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
|
||||
anim.setDuration(400 /* duration */);
|
||||
anim.setInterpolator(Interpolators.LINEAR);
|
||||
anim.addUpdateListener((ValueAnimator animation) -> {
|
||||
SurfaceParams params = new SurfaceParams.Builder(primary.leash)
|
||||
.withAlpha(animation.getAnimatedFraction())
|
||||
.build();
|
||||
applier.scheduleApply(params);
|
||||
});
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
try {
|
||||
finishedCallback.onAnimationFinished();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "RemoteException");
|
||||
}
|
||||
// TODO(bc-animation): When remote animation is enabled for keyguard exit animation,
|
||||
// apps, wallpapers and finishedCallback are set to non-null. nonApps is not yet
|
||||
// supported, so it's always null.
|
||||
mContext.getMainExecutor().execute(() -> {
|
||||
if (finishedCallback == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
try {
|
||||
finishedCallback.onAnimationFinished();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "RemoteException");
|
||||
// TODO(bc-unlock): Sample animation, just to apply alpha animation on the app.
|
||||
final SyncRtSurfaceTransactionApplier applier =
|
||||
new SyncRtSurfaceTransactionApplier(
|
||||
mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
|
||||
final RemoteAnimationTarget primary = apps[0];
|
||||
ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
|
||||
anim.setDuration(400 /* duration */);
|
||||
anim.setInterpolator(Interpolators.LINEAR);
|
||||
anim.addUpdateListener((ValueAnimator animation) -> {
|
||||
SyncRtSurfaceTransactionApplier.SurfaceParams params =
|
||||
new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
|
||||
primary.leash)
|
||||
.withAlpha(animation.getAnimatedFraction())
|
||||
.build();
|
||||
applier.scheduleApply(params);
|
||||
});
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
try {
|
||||
finishedCallback.onAnimationFinished();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "RemoteException");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
try {
|
||||
finishedCallback.onAnimationFinished();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "RemoteException");
|
||||
}
|
||||
}
|
||||
});
|
||||
anim.start();
|
||||
});
|
||||
anim.start();
|
||||
});
|
||||
resetKeyguardDonePendingLocked();
|
||||
mHideAnimationRun = false;
|
||||
adjustStatusBarLocked();
|
||||
sendUserPresentBroadcast();
|
||||
resetKeyguardDonePendingLocked();
|
||||
mHideAnimationRun = false;
|
||||
adjustStatusBarLocked();
|
||||
sendUserPresentBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
Trace.endSection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we're currently animating between the keyguard and the app/launcher surface behind
|
||||
* it, or will be shortly (which happens if we started a fling to dismiss the keyguard).
|
||||
*/
|
||||
public boolean isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe() {
|
||||
return mSurfaceBehindRemoteAnimationRunning
|
||||
|| mKeyguardStateController.isFlingingToDismissKeyguard();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called if the keyguard exit animation has been cancelled and we should return to the
|
||||
* keyguard.
|
||||
*
|
||||
* This can happen due to the system cancelling the RemoteAnimation (due to a timeout), or the
|
||||
* user cancelling the unlock swipe gesture.
|
||||
*/
|
||||
private void handleCancelKeyguardExitAnimation() {
|
||||
hideSurfaceBehindKeyguard();
|
||||
mKeyguardUnlockAnimationControllerLazy.get().notifyCancelKeyguardExitAnimation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we're done running the keyguard exit animation.
|
||||
*
|
||||
* This will call {@link #mSurfaceBehindRemoteAnimationFinishedCallback} to let WM know that
|
||||
* we're done with the RemoteAnimation, actually hide the keyguard, and clean up state related
|
||||
* to the keyguard exit animation.
|
||||
*/
|
||||
public void onKeyguardExitRemoteAnimationFinished() {
|
||||
if (!mSurfaceBehindRemoteAnimationRunning && !mSurfaceBehindRemoteAnimationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Block the panel from expanding, in case we were doing a swipe to dismiss gesture.
|
||||
mKeyguardViewControllerLazy.get().blockPanelExpansionFromCurrentTouch();
|
||||
final boolean wasShowing = mShowing;
|
||||
setShowingLocked(false);
|
||||
|
||||
mWakeAndUnlocking = false;
|
||||
mDismissCallbackRegistry.notifyDismissSucceeded();
|
||||
|
||||
if (mKeyguardStateController.isDismissingFromSwipe() || !wasShowing) {
|
||||
mKeyguardUnlockAnimationControllerLazy.get().hideKeyguardViewAfterRemoteAnimation();
|
||||
}
|
||||
|
||||
finishSurfaceBehindRemoteAnimation();
|
||||
|
||||
resetKeyguardDonePendingLocked();
|
||||
mHideAnimationRun = false;
|
||||
adjustStatusBarLocked();
|
||||
sendUserPresentBroadcast();
|
||||
mSurfaceBehindRemoteAnimationRequested = false;
|
||||
mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the ActivityTaskManager that the keyguard is planning to go away, so that it makes the
|
||||
* surface behind the keyguard visible and calls {@link #handleStartKeyguardExitAnimation} with
|
||||
* the parameters needed to animate the surface.
|
||||
*/
|
||||
public void showSurfaceBehindKeyguard() {
|
||||
mSurfaceBehindRemoteAnimationRequested = true;
|
||||
|
||||
try {
|
||||
ActivityTaskManager.getService().keyguardGoingAway(
|
||||
WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS
|
||||
| WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER);
|
||||
} catch (RemoteException e) {
|
||||
mSurfaceBehindRemoteAnimationRequested = false;
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/** Hides the surface behind the keyguard by re-showing the keyguard/activity lock screen. */
|
||||
public void hideSurfaceBehindKeyguard() {
|
||||
mSurfaceBehindRemoteAnimationRequested = false;
|
||||
|
||||
if (mShowing) {
|
||||
setShowingLocked(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we have requested to show the surface behind the keyguard, even if it's not yet
|
||||
* visible due to IPC delay.
|
||||
*/
|
||||
public boolean requestedShowSurfaceBehindKeyguard() {
|
||||
return mSurfaceBehindRemoteAnimationRequested;
|
||||
}
|
||||
|
||||
/** If it's running, finishes the RemoteAnimation on the surface behind the keyguard. */
|
||||
public void finishSurfaceBehindRemoteAnimation() {
|
||||
mSurfaceBehindRemoteAnimationRunning = false;
|
||||
|
||||
if (mSurfaceBehindRemoteAnimationFinishedCallback != null) {
|
||||
try {
|
||||
mSurfaceBehindRemoteAnimationFinishedCallback.onAnimationFinished();
|
||||
mSurfaceBehindRemoteAnimationFinishedCallback = null;
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustStatusBarLocked() {
|
||||
adjustStatusBarLocked(false /* forceHideHomeRecentsButtons */,
|
||||
false /* forceClearFlags */);
|
||||
@@ -2346,6 +2513,19 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
||||
Trace.endSection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the keyguard exit animation, usually because we were swiping to unlock and the swipe
|
||||
* gesture was cancelled.
|
||||
*
|
||||
* This will re-show the keyguard and animate out the app/launcher surface behind the keyguard.
|
||||
*/
|
||||
public void cancelKeyguardExitAnimation() {
|
||||
Trace.beginSection("KeyguardViewMediator#cancelKeyguardExitAnimation");
|
||||
Message msg = mHandler.obtainMessage(CANCEL_KEYGUARD_EXIT_ANIM);
|
||||
mHandler.sendMessage(msg);
|
||||
Trace.endSection();
|
||||
}
|
||||
|
||||
public void onShortPowerPressedGoHome() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.android.systemui.dagger.qualifiers.UiBackground;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.keyguard.DismissCallbackRegistry;
|
||||
import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.navigationbar.NavigationModeController;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
@@ -49,6 +50,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController;
|
||||
import com.android.systemui.statusbar.phone.DozeParameters;
|
||||
import com.android.systemui.statusbar.phone.KeyguardLiftController;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.DeviceConfigProxy;
|
||||
import com.android.systemui.util.sensors.AsyncSensorManager;
|
||||
import com.android.systemui.util.settings.GlobalSettings;
|
||||
@@ -92,7 +94,9 @@ public class KeyguardModule {
|
||||
NavigationModeController navigationModeController,
|
||||
KeyguardDisplayManager keyguardDisplayManager,
|
||||
DozeParameters dozeParameters,
|
||||
StatusBarStateController statusBarStateController) {
|
||||
StatusBarStateController statusBarStateController,
|
||||
KeyguardStateController keyguardStateController,
|
||||
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController) {
|
||||
return new KeyguardViewMediator(
|
||||
context,
|
||||
falsingCollector,
|
||||
@@ -109,7 +113,9 @@ public class KeyguardModule {
|
||||
navigationModeController,
|
||||
keyguardDisplayManager,
|
||||
dozeParameters,
|
||||
statusBarStateController
|
||||
statusBarStateController,
|
||||
keyguardStateController,
|
||||
keyguardUnlockAnimationController
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1395,6 +1395,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
protected void flingToHeight(float vel, boolean expand, float target,
|
||||
float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
|
||||
mHeadsUpTouchHelper.notifyFling(!expand);
|
||||
mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */);
|
||||
setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f);
|
||||
super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
|
||||
}
|
||||
|
||||
@@ -256,7 +256,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
|
||||
state.mScrimsVisibility == ScrimController.OPAQUE;
|
||||
final boolean keyguardOrAod = state.mKeyguardShowing
|
||||
|| (state.mDozing && mDozeParameters.getAlwaysOn());
|
||||
if (keyguardOrAod && !state.mBackdropShowing && !scrimsOccludingWallpaper) {
|
||||
if ((keyguardOrAod && !state.mBackdropShowing && !scrimsOccludingWallpaper)
|
||||
|| mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
|
||||
// Show the wallpaper if we're on keyguard/AOD and the wallpaper is not occluded by a
|
||||
// solid backdrop or scrim. Also, show it if we are currently animating between the
|
||||
// keyguard and the surface behind the keyguard - we want to use the wallpaper as a
|
||||
// backdrop for this animation.
|
||||
mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER;
|
||||
} else {
|
||||
mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER;
|
||||
|
||||
@@ -592,6 +592,7 @@ public abstract class PanelViewController {
|
||||
float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
|
||||
if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) {
|
||||
InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
|
||||
mKeyguardStateController.notifyPanelFlingEnd();
|
||||
notifyExpandingFinished();
|
||||
return;
|
||||
}
|
||||
@@ -679,6 +680,7 @@ public abstract class PanelViewController {
|
||||
|
||||
private void onFlingEnd(boolean cancelled) {
|
||||
setAnimator(null);
|
||||
mKeyguardStateController.notifyPanelFlingEnd();
|
||||
if (!cancelled) {
|
||||
InteractionJankMonitor.getInstance()
|
||||
.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
|
||||
|
||||
@@ -162,6 +162,7 @@ import com.android.systemui.emergency.EmergencyGesture;
|
||||
import com.android.systemui.fragments.ExtensionFragmentListener;
|
||||
import com.android.systemui.fragments.FragmentHostManager;
|
||||
import com.android.systemui.keyguard.DismissCallbackRegistry;
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.keyguard.ScreenLifecycle;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
@@ -800,7 +801,8 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
SystemStatusAnimationScheduler animationScheduler,
|
||||
PrivacyDotViewController dotViewController,
|
||||
TunerService tunerService,
|
||||
FeatureFlags featureFlags) {
|
||||
FeatureFlags featureFlags,
|
||||
KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
|
||||
super(context);
|
||||
mNotificationsController = notificationsController;
|
||||
mLightBarController = lightBarController;
|
||||
@@ -1122,6 +1124,8 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
inflateShelf();
|
||||
mNotificationIconAreaController.setupShelf(mNotificationShelfController);
|
||||
mNotificationPanelViewController.addExpansionListener(mWakeUpCoordinator);
|
||||
mNotificationPanelViewController.addExpansionListener(
|
||||
this::dispatchPanelExpansionForKeyguardDismiss);
|
||||
|
||||
// Allow plugins to reference DarkIconDispatcher and StatusBarStateController
|
||||
mPluginDependencyProvider.allowPluginDependency(DarkIconDispatcher.class);
|
||||
@@ -1348,6 +1352,38 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When swiping up to dismiss the lock screen, the panel expansion goes from 1f to 0f. This
|
||||
* results in the clock/notifications/other content disappearing off the top of the screen.
|
||||
*
|
||||
* We also use the expansion amount to animate in the app/launcher surface from the bottom of
|
||||
* the screen, 'pushing' off the notifications and other content. To do this, we dispatch the
|
||||
* expansion amount to the KeyguardViewMediator if we're in the process of dismissing the
|
||||
* keyguard.
|
||||
*/
|
||||
private void dispatchPanelExpansionForKeyguardDismiss(float expansion, boolean trackingTouch) {
|
||||
// Things that mean we're not dismissing the keyguard, and should ignore this expansion:
|
||||
// - Keyguard isn't even visible.
|
||||
// - Keyguard is visible, but can't be dismissed (swiping up will show PIN/password prompt).
|
||||
// - QS is expanded and we're swiping - swiping up now will hide QS, not dismiss the
|
||||
// keyguard.
|
||||
if (!isKeyguardShowing()
|
||||
|| !mKeyguardStateController.canDismissLockScreen()
|
||||
|| (mNotificationPanelViewController.isQsExpanded() && trackingTouch)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we should let the keyguard know about this if we're tracking touch, or if we
|
||||
// are already animating the keyguard dismiss (since we will need to either finish or cancel
|
||||
// the animation).
|
||||
if (trackingTouch
|
||||
|| mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
|
||||
mKeyguardStateController.notifyKeyguardDismissAmountChanged(
|
||||
1f - expansion, trackingTouch);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Lifecycle getLifecycle() {
|
||||
|
||||
@@ -571,6 +571,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
mNotificationPanelViewController.blockExpansionForCurrentTouch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blockPanelExpansionFromCurrentTouch() {
|
||||
mNotificationPanelViewController.blockExpansionForCurrentTouch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide(long startTime, long fadeoutDuration) {
|
||||
mShowing = false;
|
||||
@@ -584,7 +589,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
long uptimeMillis = SystemClock.uptimeMillis();
|
||||
long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis);
|
||||
|
||||
if (mStatusBar.isInLaunchTransition() ) {
|
||||
if (mStatusBar.isInLaunchTransition()
|
||||
|| mKeyguardStateController.isFlingingToDismissKeyguard()) {
|
||||
mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.UiBackground;
|
||||
import com.android.systemui.demomode.DemoModeController;
|
||||
import com.android.systemui.keyguard.DismissCallbackRegistry;
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.keyguard.ScreenLifecycle;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
@@ -214,7 +215,8 @@ public interface StatusBarPhoneModule {
|
||||
SystemStatusAnimationScheduler animationScheduler,
|
||||
PrivacyDotViewController dotViewController,
|
||||
TunerService tunerService,
|
||||
FeatureFlags featureFlags) {
|
||||
FeatureFlags featureFlags,
|
||||
KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
|
||||
return new StatusBar(
|
||||
context,
|
||||
notificationsController,
|
||||
@@ -300,6 +302,7 @@ public interface StatusBarPhoneModule {
|
||||
animationScheduler,
|
||||
dotViewController,
|
||||
tunerService,
|
||||
featureFlags);
|
||||
featureFlags,
|
||||
keyguardUnlockAnimationController);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +139,38 @@ public interface KeyguardStateController extends CallbackController<Callback> {
|
||||
*/
|
||||
long calculateGoingToFullShadeDelay();
|
||||
|
||||
/**
|
||||
* How much (from 0f to 1f) the keyguard is dismissed, either via a swipe gesture or an
|
||||
* animation.
|
||||
*/
|
||||
float getDismissAmount();
|
||||
|
||||
/**
|
||||
* Whether the keyguard is being dismissed due to direct user input, rather than a canned
|
||||
* animation.
|
||||
*/
|
||||
boolean isDismissingFromSwipe();
|
||||
|
||||
/**
|
||||
* Whether a fling animation is currently playing on the keyguard, either to dismiss it or to
|
||||
* cancel dismissing it.
|
||||
*/
|
||||
boolean isFlingingToDismissKeyguard();
|
||||
|
||||
/**
|
||||
* Whether a fling animation is currently playing on the keyguard, either to dismiss it or to
|
||||
* cancel dismissing it, and that animation started during a swipe gesture. Fling animations
|
||||
* can also be started without a swipe (e.g. activity launch from lock screen notification), so
|
||||
* this is a way to tell them apart for animation purposes.
|
||||
*/
|
||||
boolean isFlingingToDismissKeyguardDuringSwipeGesture();
|
||||
|
||||
/**
|
||||
* Whether a fling animation is currently playing on the keyguard to cancel dismissing it, after
|
||||
* the user released their finger during a swipe gesture.
|
||||
*/
|
||||
boolean isSnappingKeyguardBackAfterSwipe();
|
||||
|
||||
/** **/
|
||||
default void setLaunchTransitionFadingAway(boolean b) {}
|
||||
/** **/
|
||||
@@ -148,6 +180,28 @@ public interface KeyguardStateController extends CallbackController<Callback> {
|
||||
/** **/
|
||||
default void notifyKeyguardState(boolean showing, boolean occluded) {}
|
||||
|
||||
/**
|
||||
* Updates the keyguard state to reflect that it's in the process of being dismissed, either by
|
||||
* a swipe gesture on the lock screen or by a canned animation.
|
||||
*
|
||||
* @param dismissAmount 0f means we're not dismissed at all, 1f means we have been completely
|
||||
* swiped away.
|
||||
* @param dismissingFromTouch True if this change was caused by direct user interaction, false
|
||||
* if it's due to an animation.
|
||||
*/
|
||||
default void notifyKeyguardDismissAmountChanged(
|
||||
float dismissAmount, boolean dismissingFromTouch) {}
|
||||
|
||||
/**
|
||||
* Updates the keyguard state to reflect that a dismiss fling gesture has started.
|
||||
*
|
||||
* @param dismiss Whether we're flinging to dismiss (upward) or to cancel a dismiss gesture.
|
||||
*/
|
||||
void notifyPanelFlingStart(boolean dismiss);
|
||||
|
||||
/** Updates the keyguard state to reflect that a dismiss fling gesture has ended. */
|
||||
void notifyPanelFlingEnd();
|
||||
|
||||
/**
|
||||
* Callback for authentication events.
|
||||
*/
|
||||
@@ -173,5 +227,11 @@ public interface KeyguardStateController extends CallbackController<Callback> {
|
||||
* Triggered when the device was just unlocked and the lock screen is being dismissed.
|
||||
*/
|
||||
default void onKeyguardFadingAwayChanged() {}
|
||||
|
||||
/**
|
||||
* Triggered when the keyguard dismiss amount has changed, via either a swipe gesture or an
|
||||
* animation.
|
||||
*/
|
||||
default void onKeyguardDismissAmountChanged() {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,28 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
|
||||
private boolean mDebugUnlocked = false;
|
||||
private boolean mFaceAuthEnabled;
|
||||
|
||||
private float mDismissAmount = 0f;
|
||||
private boolean mDismissingFromTouch = false;
|
||||
|
||||
/**
|
||||
* Whether the panel is currently flinging to a collapsed state, which means we're dismissing
|
||||
* the keyguard.
|
||||
*/
|
||||
private boolean mFlingingToDismissKeyguard = false;
|
||||
|
||||
/**
|
||||
* Whether the panel is currently flinging to a collapsed state, which means we're dismissing
|
||||
* the keyguard, and the fling started during a swipe gesture. This means that we need to take
|
||||
* over the gesture and animate the rest of the way dismissed.
|
||||
*/
|
||||
private boolean mFlingingToDismissKeyguardDuringSwipeGesture = false;
|
||||
|
||||
/**
|
||||
* Whether the panel is currently flinging to an expanded state, which means we cancelled the
|
||||
* dismiss gesture and are snapping back to the keyguard state.
|
||||
*/
|
||||
private boolean mSnappingKeyguardBackAfterSwipe = false;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Inject
|
||||
@@ -240,11 +262,59 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
|
||||
return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlingingToDismissKeyguard() {
|
||||
return mFlingingToDismissKeyguard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlingingToDismissKeyguardDuringSwipeGesture() {
|
||||
return mFlingingToDismissKeyguardDuringSwipeGesture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSnappingKeyguardBackAfterSwipe() {
|
||||
return mSnappingKeyguardBackAfterSwipe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDismissAmount() {
|
||||
return mDismissAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDismissingFromSwipe() {
|
||||
return mDismissingFromTouch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyKeyguardGoingAway(boolean keyguardGoingAway) {
|
||||
mKeyguardGoingAway = keyguardGoingAway;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPanelFlingEnd() {
|
||||
mFlingingToDismissKeyguard = false;
|
||||
mFlingingToDismissKeyguardDuringSwipeGesture = false;
|
||||
mSnappingKeyguardBackAfterSwipe = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPanelFlingStart(boolean flingToDismiss) {
|
||||
mFlingingToDismissKeyguard = flingToDismiss;
|
||||
mFlingingToDismissKeyguardDuringSwipeGesture =
|
||||
flingToDismiss && mDismissingFromTouch;
|
||||
mSnappingKeyguardBackAfterSwipe = !flingToDismiss;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyKeyguardDismissAmountChanged(float dismissAmount,
|
||||
boolean dismissingFromTouch) {
|
||||
mDismissAmount = dismissAmount;
|
||||
mDismissingFromTouch = dismissingFromTouch;
|
||||
new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardDismissAmountChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLaunchTransitionFadingAway(boolean fadingAway) {
|
||||
mLaunchTransitionFadingAway = fadingAway;
|
||||
|
||||
@@ -29,17 +29,13 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
@@ -51,9 +47,9 @@ import com.android.systemui.classifier.FalsingCollectorFake;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.navigationbar.NavigationModeController;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.LightRevealScrim;
|
||||
import com.android.systemui.statusbar.phone.DozeParameters;
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.DeviceConfigProxy;
|
||||
import com.android.systemui.util.DeviceConfigProxyFake;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
@@ -84,6 +80,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
|
||||
private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
|
||||
private @Mock DozeParameters mDozeParameters;
|
||||
private @Mock StatusBarStateController mStatusBarStateController;
|
||||
private @Mock KeyguardStateController mKeyguardStateController;
|
||||
private @Mock KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
|
||||
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
|
||||
|
||||
@@ -102,7 +100,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
|
||||
() -> mStatusBarKeyguardViewManager,
|
||||
mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
|
||||
mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController,
|
||||
mKeyguardDisplayManager, mDozeParameters, mStatusBarStateController);
|
||||
mKeyguardDisplayManager, mDozeParameters, mStatusBarStateController,
|
||||
mKeyguardStateController, () -> mKeyguardUnlockAnimationController);
|
||||
mViewMediator.start();
|
||||
}
|
||||
|
||||
|
||||
@@ -553,6 +553,36 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwipeWhileLocked_notifiesKeyguardState() {
|
||||
mStatusBarStateController.setState(KEYGUARD);
|
||||
|
||||
// Fling expanded (cancelling the keyguard exit swipe). We should notify keyguard state that
|
||||
// the fling occurred and did not dismiss the keyguard.
|
||||
mNotificationPanelViewController.flingToHeight(
|
||||
0f, true /* expand */, 1000f, 1f, false);
|
||||
verify(mKeyguardStateController).notifyPanelFlingStart(false /* dismissKeyguard */);
|
||||
|
||||
// Fling un-expanded, which is a keyguard exit fling when we're in KEYGUARD state.
|
||||
mNotificationPanelViewController.flingToHeight(
|
||||
0f, false /* expand */, 1000f, 1f, false);
|
||||
verify(mKeyguardStateController).notifyPanelFlingStart(true /* dismissKeyguard */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelSwipeWhileLocked_notifiesKeyguardState() {
|
||||
mStatusBarStateController.setState(KEYGUARD);
|
||||
|
||||
mNotificationPanelViewController.setOverExpansion(100f, true);
|
||||
|
||||
// Fling expanded (cancelling the keyguard exit swipe). We should notify keyguard state that
|
||||
// the fling occurred and did not dismiss the keyguard.
|
||||
mNotificationPanelViewController.flingToHeight(
|
||||
0f, true /* expand */, 1000f, 1f, false);
|
||||
mNotificationPanelViewController.cancelHeightAnimator();
|
||||
verify(mKeyguardStateController).notifyPanelFlingEnd();
|
||||
}
|
||||
|
||||
private View newViewWithId(int id) {
|
||||
View view = new View(mContext);
|
||||
view.setId(id);
|
||||
|
||||
@@ -133,6 +133,19 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
|
||||
assertThat((mLayoutParameters.getValue().flags & FLAG_SHOW_WALLPAPER) != 0).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attach_animatingKeyguardAndSurface_wallpaperVisible() {
|
||||
clearInvocations(mWindowManager);
|
||||
when(mKeyguardViewMediator.isShowingAndNotOccluded()).thenReturn(true);
|
||||
when(mKeyguardViewMediator
|
||||
.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe())
|
||||
.thenReturn(true);
|
||||
mNotificationShadeWindowController.attach();
|
||||
|
||||
verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
|
||||
assertThat((mLayoutParameters.getValue().flags & FLAG_SHOW_WALLPAPER) != 0).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBackgroundBlurRadius_expandedWithBlurs() {
|
||||
mNotificationShadeWindowController.setBackgroundBlurRadius(10);
|
||||
|
||||
@@ -86,6 +86,7 @@ import com.android.systemui.classifier.FalsingManagerFake;
|
||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||
import com.android.systemui.demomode.DemoModeController;
|
||||
import com.android.systemui.keyguard.DismissCallbackRegistry;
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.keyguard.ScreenLifecycle;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
@@ -271,6 +272,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
@Mock private TunerService mTunerService;
|
||||
@Mock private FeatureFlags mFeatureFlags;
|
||||
@Mock private IWallpaperManager mWallpaperManager;
|
||||
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||
private ShadeController mShadeController;
|
||||
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
|
||||
private InitController mInitController = new InitController();
|
||||
@@ -439,7 +441,8 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
mAnimationScheduler,
|
||||
mDotViewController,
|
||||
mTunerService,
|
||||
mFeatureFlags);
|
||||
mFeatureFlags,
|
||||
mKeyguardUnlockAnimationController);
|
||||
when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
|
||||
any(NotificationPanelViewController.class), any(BiometricUnlockController.class),
|
||||
any(ViewGroup.class), any(KeyguardBypassController.class)))
|
||||
|
||||
@@ -143,4 +143,14 @@ public class KeyguardStateControllerTest extends SysuiTestCase {
|
||||
verify(callback).onUnlockedChanged();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyguardDismissAmountCallbackInvoked() {
|
||||
KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
|
||||
mKeyguardStateController.addCallback(callback);
|
||||
|
||||
mKeyguardStateController.notifyKeyguardDismissAmountChanged(100f, false);
|
||||
|
||||
verify(callback).onKeyguardDismissAmountChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -92,4 +92,39 @@ public class FakeKeyguardStateController implements KeyguardStateController {
|
||||
public long calculateGoingToFullShadeDelay() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDismissAmount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDismissingFromSwipe() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlingingToDismissKeyguard() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlingingToDismissKeyguardDuringSwipeGesture() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSnappingKeyguardBackAfterSwipe() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPanelFlingStart(boolean dismiss) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPanelFlingEnd() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ import java.util.ArrayList;
|
||||
class RemoteAnimationController implements DeathRecipient {
|
||||
private static final String TAG = TAG_WITH_CLASS_NAME
|
||||
? "RemoteAnimationController" : TAG_WM;
|
||||
private static final long TIMEOUT_MS = 2000;
|
||||
private static final long TIMEOUT_MS = 10000;
|
||||
|
||||
private final WindowManagerService mService;
|
||||
private final DisplayContent mDisplayContent;
|
||||
|
||||
@@ -177,7 +177,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
|
||||
mFinishedCallback);
|
||||
mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
|
||||
|
||||
mClock.fastForward(2500);
|
||||
mClock.fastForward(10500);
|
||||
mHandler.timeAdvance();
|
||||
|
||||
verify(mMockRunner).onAnimationCancelled();
|
||||
@@ -198,12 +198,12 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
|
||||
mFinishedCallback);
|
||||
mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
|
||||
|
||||
mClock.fastForward(2500);
|
||||
mClock.fastForward(10500);
|
||||
mHandler.timeAdvance();
|
||||
|
||||
verify(mMockRunner, never()).onAnimationCancelled();
|
||||
|
||||
mClock.fastForward(10000);
|
||||
mClock.fastForward(52500);
|
||||
mHandler.timeAdvance();
|
||||
|
||||
verify(mMockRunner).onAnimationCancelled();
|
||||
|
||||
Reference in New Issue
Block a user