Merge "Adds the continuous unlock animation!" into sc-dev

This commit is contained in:
Josh Tsuji
2021-04-27 14:23:25 +00:00
committed by Android (Google) Code Review
21 changed files with 865 additions and 69 deletions

View File

@@ -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.
*/

View File

@@ -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();
}
};

View File

@@ -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()
}
}

View File

@@ -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
}

View File

@@ -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
);
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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);
}
}

View File

@@ -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() {}
}
}

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)))

View File

@@ -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();
}
}

View File

@@ -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() {
}
}

View File

@@ -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;

View File

@@ -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();