Merge "Adds Launcher in-window animations, and reworks how the unlock flow works."

This commit is contained in:
Josh Tsuji
2022-01-24 20:34:44 +00:00
committed by Android (Google) Code Review
33 changed files with 938 additions and 438 deletions

View File

@@ -122,6 +122,11 @@ public interface BcSmartspaceDataPlugin extends Plugin {
* Set or clear device media playing
*/
void setMediaTarget(@Nullable SmartspaceTarget target);
/**
* Get the index of the currently selected page.
*/
int getSelectedPage();
}
/** Interface for launching Intents, which can differ on the lockscreen */

View File

@@ -55,8 +55,8 @@ public class QuickStepContract {
// See IStartingWindow.aidl
public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
"extra_shell_starting_window";
// See ISmartspaceTransitionController.aidl
public static final String KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER = "smartspace_transition";
// See ISysuiUnlockAnimationController.aidl
public static final String KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER = "unlock_animation";
// See IRecentTasks.aidl
public static final String KEY_EXTRA_RECENT_TASKS = "recent_tasks";

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.shared.system.smartspace;
import com.android.systemui.shared.system.smartspace.SmartspaceState;
// Methods for System UI to interface with Launcher to perform the unlock animation.
interface ILauncherUnlockAnimationController {
// Prepares Launcher for the unlock animation by setting scale/alpha/etc. to their starting
// values.
void prepareForUnlock(boolean willAnimateSmartspace, int selectedPage);
// Set the unlock percentage. This is used when System UI is controlling each frame of the
// unlock animation, such as during a swipe to unlock touch gesture.
oneway void setUnlockAmount(float amount);
// Play a full unlock animation from 0f to 1f. This is used when System UI is unlocking from a
// single action, such as biometric auth, and doesn't need to control individual frames.
oneway void playUnlockAnimation(boolean unlocked, long duration);
// Set the selected page on Launcher's smartspace.
oneway void setSmartspaceSelectedPage(int selectedPage);
// Set the visibility of Launcher's smartspace.
void setSmartspaceVisibility(int visibility);
// Tell SystemUI the smartspace's current state. Launcher code should call this whenever the
// smartspace state may have changed.
oneway void dispatchSmartspaceStateToSysui();
}

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.shared.system.smartspace;
import com.android.systemui.shared.system.smartspace.SmartspaceState;
// Methods for getting and setting the state of a SmartSpace. This is used to allow a remote process
// (such as System UI) to sync with and control a SmartSpace view hosted in another process (such as
// Launcher).
interface ISmartspaceCallback {
// Return information about the state of the SmartSpace, including location on-screen and
// currently selected page.
SmartspaceState getSmartspaceState();
// Set the currently selected page of this SmartSpace.
oneway void setSelectedPage(int selectedPage);
oneway void setVisibility(int visibility);
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.shared.system.smartspace;
import com.android.systemui.shared.system.smartspace.ISmartspaceCallback;
// Controller that keeps track of SmartSpace instances in remote processes (such as Launcher).
interface ISmartspaceTransitionController {
oneway void setSmartspace(ISmartspaceCallback callback);
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.shared.system.smartspace;
import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController;
import com.android.systemui.shared.system.smartspace.SmartspaceState;
// System UI unlock controller. Launcher will provide a LauncherUnlockAnimationController to this
// controller, which System UI will use to control the unlock animation within the Launcher window.
interface ISysuiUnlockAnimationController {
// Provides an implementation of the LauncherUnlockAnimationController to System UI, so that
// SysUI can use it to control the unlock animation in the launcher window.
oneway void setLauncherUnlockController(ILauncherUnlockAnimationController callback);
// Called by Launcher whenever anything happens to change the state of its smartspace. System UI
// proactively saves this and uses it to perform the unlock animation without needing to make a
// blocking query to Launcher asking about the smartspace state.
oneway void onLauncherSmartspaceStateUpdated(in SmartspaceState state);
}

View File

@@ -28,15 +28,18 @@ import android.os.Parcelable
class SmartspaceState() : Parcelable {
var boundsOnScreen: Rect = Rect()
var selectedPage = 0
var visibleOnScreen = false
constructor(parcel: Parcel) : this() {
this.boundsOnScreen = parcel.readParcelable(Rect::javaClass.javaClass.classLoader)
this.selectedPage = parcel.readInt()
this.visibleOnScreen = parcel.readBoolean()
}
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.writeParcelable(boundsOnScreen, 0)
dest?.writeInt(selectedPage)
dest?.writeBoolean(visibleOnScreen)
}
override fun describeContents(): Int {
@@ -44,7 +47,9 @@ class SmartspaceState() : Parcelable {
}
override fun toString(): String {
return "boundsOnScreen: $boundsOnScreen, selectedPage: $selectedPage"
return "boundsOnScreen: $boundsOnScreen, " +
"selectedPage: $selectedPage, " +
"visibleOnScreen: $visibleOnScreen"
}
companion object CREATOR : Parcelable.Creator<SmartspaceState> {

View File

@@ -20,6 +20,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import android.app.WallpaperManager;
import android.content.res.Resources;
@@ -41,7 +42,6 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -86,6 +86,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private AnimatableClockController mLargeClockViewController;
private FrameLayout mLargeClockFrame; // centered clock
@KeyguardClockSwitch.ClockSize
private int mCurrentClockSize = SMALL;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardBypassController mBypassController;
@@ -110,7 +113,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private View mSmartspaceView;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private SmartspaceTransitionController mSmartspaceTransitionController;
private boolean mOnlyClock = false;
private Executor mUiExecutor;
@@ -136,7 +138,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
KeyguardBypassController bypassController,
LockscreenSmartspaceController smartspaceController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
SmartspaceTransitionController smartspaceTransitionController,
SecureSettings secureSettings,
@Main Executor uiExecutor,
@Main Resources resources) {
@@ -155,7 +156,22 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mSecureSettings = secureSettings;
mUiExecutor = uiExecutor;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mSmartspaceTransitionController = smartspaceTransitionController;
mKeyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@Override
public void onSmartspaceSharedElementTransitionStarted() {
// The smartspace needs to be able to translate out of bounds in order to
// end up where the launcher's smartspace is, while its container is being
// swiped off the top of the screen.
setClipChildrenForUnlock(false);
}
@Override
public void onUnlockAnimationFinished() {
// For performance reasons, reset this once the unlock animation ends.
setClipChildrenForUnlock(true);
}
});
}
/**
@@ -236,7 +252,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mSmartspaceView.setPaddingRelative(startPadding, 0, endPadding, 0);
updateClockLayout();
mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
mKeyguardUnlockAnimationController.setLockscreenSmartspace(mSmartspaceView);
}
mSecureSettings.registerContentObserver(
@@ -293,6 +309,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
return;
}
mCurrentClockSize = clockSize;
boolean appeared = mView.switchToClock(clockSize, animate);
if (animate && appeared && clockSize == LARGE) {
mLargeClockViewController.animateAppear();
@@ -368,7 +386,14 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
final Set<View> excludedViews = new HashSet<>();
if (mSmartspaceView != null) {
excludedViews.add(mSmartspaceView);
excludedViews.add(mStatusArea);
}
// Don't change the alpha of the invisible clock.
if (mCurrentClockSize == LARGE) {
excludedViews.add(mClockFrame);
} else {
excludedViews.add(mLargeClockFrame);
}
setChildrenAlphaExcluding(alpha, excludedViews);
@@ -449,4 +474,16 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mUiExecutor.execute(() -> displayClock(KeyguardClockSwitch.SMALL, /* animate */ true));
}
}
/**
* Sets the clipChildren property on relevant views, to allow the smartspace to draw out of
* bounds during the unlock transition.
*/
private void setClipChildrenForUnlock(boolean clip) {
mView.setClipChildren(clip);
if (mStatusArea != null) {
mStatusArea.setClipChildren(clip);
}
}
}

View File

@@ -22,7 +22,6 @@ import android.util.Slog;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -55,7 +54,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final KeyguardStateController mKeyguardStateController;
private SmartspaceTransitionController mSmartspaceTransitionController;
private final Rect mClipBounds = new Rect();
@Inject
@@ -69,7 +67,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
ConfigurationController configurationController,
DozeParameters dozeParameters,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
SmartspaceTransitionController smartspaceTransitionController,
ScreenOffAnimationController screenOffAnimationController) {
super(keyguardStatusView);
mKeyguardSliceViewController = keyguardSliceViewController;
@@ -82,7 +79,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
keyguardStateController, dozeParameters, screenOffAnimationController,
/* animateYPos= */ true, /* visibleOnCommunal= */ false);
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mSmartspaceTransitionController = smartspaceTransitionController;
}
@Override

View File

@@ -48,7 +48,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -188,12 +187,6 @@ public abstract class SystemUIModule {
return SystemUIFactory.getInstance();
}
@SysUISingleton
@Provides
static SmartspaceTransitionController provideSmartspaceTransitionController() {
return new SmartspaceTransitionController();
}
// TODO: This should provided by the WM component
/** Provides Optional of BubbleManager */
@SysUISingleton

View File

@@ -85,7 +85,7 @@ public class Flags {
new BooleanFlag(400, true);
public static final BooleanFlag SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED =
new BooleanFlag(401, false);
new BooleanFlag(401, true);
public static final ResourceBooleanFlag SMARTSPACE =
new ResourceBooleanFlag(402, R.bool.flag_smartspace);

View File

@@ -21,6 +21,8 @@ import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Matrix
import android.graphics.Rect
import android.os.Handler
import android.view.RemoteAnimationTarget
import android.view.SyncRtSurfaceTransactionApplier
import android.view.View
@@ -33,11 +35,17 @@ import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.shared.system.QuickStepContract
import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController
import com.android.systemui.shared.system.smartspace.SmartspaceState
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy
import javax.inject.Inject
import kotlin.math.min
/**
* Starting scale factor for the app/launcher surface behind the keyguard, when it's animating
@@ -75,6 +83,25 @@ const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.25f
*/
const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.4f
/**
* How long the canned unlock animation takes. This is used if we are unlocking from biometric auth,
* from a tap on the unlock icon, or from the bouncer. This is not relevant if the lockscreen is
* swiped away via a touch gesture, or when it's flinging expanded/collapsed after a swipe.
*/
const val UNLOCK_ANIMATION_DURATION_MS = 200L
/**
* Duration for the alpha animation on the surface behind. This plays to fade in the surface during
* a swipe to unlock (and to fade it back out if the swipe is cancelled).
*/
const val SURFACE_BEHIND_SWIPE_FADE_DURATION_MS = 150L
/**
* Start delay for the surface behind animation, used so that the lockscreen can get out of the way
* before the surface begins appearing.
*/
const val UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS = 75L
/**
* Initiates, controls, and ends the keyguard unlock animation.
*
@@ -85,7 +112,7 @@ const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.4f
* this controller will play a canned animation on the surface as well.
*
* The surface behind the keyguard is manipulated via a RemoteAnimation passed to
* [notifyStartKeyguardExitAnimation] by [KeyguardViewMediator].
* [notifyStartSurfaceBehindRemoteAnimation] by [KeyguardViewMediator].
*/
@SysUISingleton
class KeyguardUnlockAnimationController @Inject constructor(
@@ -94,10 +121,99 @@ class KeyguardUnlockAnimationController @Inject constructor(
private val
keyguardViewMediator: Lazy<KeyguardViewMediator>,
private val keyguardViewController: KeyguardViewController,
private val smartspaceTransitionController: SmartspaceTransitionController,
private val featureFlags: FeatureFlags,
private val biometricUnlockController: BiometricUnlockController
) : KeyguardStateController.Callback {
private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>
) : KeyguardStateController.Callback, ISysuiUnlockAnimationController.Stub() {
interface KeyguardUnlockAnimationListener {
/**
* Called when the remote unlock animation, controlled by
* [KeyguardUnlockAnimationController], first starts.
*
* [playingCannedAnimation] indicates whether we are playing a canned animation to show the
* app/launcher behind the keyguard, vs. this being a swipe to unlock where the dismiss
* amount drives the animation.
* [fromWakeAndUnlock] tells us whether we are unlocking directly from AOD - in this case,
* the lockscreen is dismissed instantly, so we shouldn't run any animations that rely on it
* being visible.
*/
@JvmDefault
fun onUnlockAnimationStarted(playingCannedAnimation: Boolean, fromWakeAndUnlock: Boolean) {}
/**
* Called when the remote unlock animation ends, in all cases, canned or swipe-to-unlock.
* The keyguard is no longer visible in this state and the app/launcher behind the keyguard
* is now completely visible.
*/
@JvmDefault
fun onUnlockAnimationFinished() {}
/**
* Called when we begin the smartspace shared element transition, either due to an unlock
* action (biometric, etc.) or a swipe to unlock.
*
* This transition can begin BEFORE [onUnlockAnimationStarted] is called, if we are swiping
* to unlock and the surface behind the keyguard has not yet been made visible. This is
* because the lockscreen smartspace immediately begins moving towards the launcher
* smartspace location when a swipe begins, even before we start the keyguard exit remote
* animation and show the launcher itself.
*/
@JvmDefault
fun onSmartspaceSharedElementTransitionStarted() {}
}
/** The SmartSpace view on the lockscreen, provided by [KeyguardClockSwitchController]. */
var lockscreenSmartspace: View? = null
/**
* The state of the Launcher's smartspace, delivered via [onLauncherSmartspaceStateUpdated].
* This is pushed to us from Launcher whenever their smartspace moves or its visibility changes.
* We'll animate the lockscreen smartspace to this location during an unlock.
*/
var launcherSmartspaceState: SmartspaceState? = null
/**
* Whether a canned unlock animation is playing, vs. currently unlocking in response to a swipe
* gesture or panel fling. If we're swiping/flinging, the unlock animation is driven by the
* dismiss amount, via [onKeyguardDismissAmountChanged]. If we're using a canned animation, it's
* being driven by ValueAnimators started in [playCannedUnlockAnimation].
*/
var playingCannedUnlockAnimation = false
/**
* Remote callback provided by Launcher that allows us to control the Launcher's unlock
* animation and smartspace.
*
* If this is null, we will not be animating any Launchers today and should fall back to window
* animations.
*/
private var launcherUnlockController: ILauncherUnlockAnimationController? = null
private val listeners = ArrayList<KeyguardUnlockAnimationListener>()
/**
* Called from SystemUiProxy to pass us the launcher's unlock animation controller. If this
* doesn't happen, we won't use in-window animations or the smartspace shared element
* transition, but that's okay!
*/
override fun setLauncherUnlockController(callback: ILauncherUnlockAnimationController?) {
launcherUnlockController = callback
// If the provided callback dies, set it to null. We'll always check whether it's null
// to avoid DeadObjectExceptions.
callback?.asBinder()?.linkToDeath({
launcherUnlockController = null
launcherSmartspaceState = null
}, 0 /* flags */)
}
/**
* Called from SystemUiProxy to pass us the latest state of the Launcher's smartspace. This is
* only done when the state has changed in some way.
*/
override fun onLauncherSmartspaceStateUpdated(state: SmartspaceState?) {
launcherSmartspaceState = state
}
/**
* Information used to start, run, and finish a RemoteAnimation on the app or launcher surface
@@ -105,15 +221,16 @@ class KeyguardUnlockAnimationController @Inject constructor(
*
* If we're swiping to unlock, the "animation" is controlled via the gesture, tied to the
* dismiss amounts received in [onKeyguardDismissAmountChanged]. It does not have a fixed
* duration, and it ends when the gesture reaches a certain threshold or is cancelled.
* duration, and it ends when the gesture reaches a certain threshold or is cancell
*
* If we're unlocking via biometrics, PIN entry, or from clicking a notification, a canned
* animation is started in [notifyStartKeyguardExitAnimation].
* animation is started in [playCannedUnlockAnimation].
*/
@VisibleForTesting
var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null
private var surfaceBehindRemoteAnimationTarget: RemoteAnimationTarget? = null
private var surfaceBehindRemoteAnimationStartTime: Long = 0
private var surfaceBehindParams: SyncRtSurfaceTransactionApplier.SurfaceParams? = null
/**
* Alpha value applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
@@ -125,6 +242,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
*/
private var surfaceBehindAlpha = 1f
private var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
private var smartspaceAnimator = ValueAnimator.ofFloat(0f, 1f)
/**
* Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
@@ -144,57 +262,113 @@ class KeyguardUnlockAnimationController @Inject constructor(
/** Rounded corner radius to apply to the surface behind the keyguard. */
private var roundedCornerRadius = 0f
/** The SmartSpace view on the lockscreen, provided by [KeyguardClockSwitchController]. */
public var lockscreenSmartSpace: View? = null
/**
* Whether we are currently in the process of unlocking the keyguard, and we are performing the
* shared element SmartSpace transition.
*/
private var unlockingWithSmartSpaceTransition: Boolean = false
/**
* Whether we tried to start the SmartSpace shared element transition for this unlock swipe.
* It's possible we're unable to do so (if the Launcher SmartSpace is not available).
* It's possible we were unable to do so (if the Launcher SmartSpace is not available), and we
* need to keep track of that so that we don't start doing it halfway through the swipe if
* Launcher becomes available suddenly.
*/
private var attemptedSmartSpaceTransitionForThisSwipe = false
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(
false /* cancelled */)
}
}
})
/**
* The original location of the lockscreen smartspace on the screen.
*/
private val smartspaceOriginBounds = Rect()
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(
false /* cancelled */)
/**
* The bounds to which the lockscreen smartspace is moving. This is set to the bounds of the
* launcher's smartspace prior to the transition starting.
*/
private val smartspaceDestBounds = Rect()
/**
* From 0f to 1f, the progress of the smartspace shared element animation. 0f means the
* smartspace is at its normal position within the lock screen hierarchy, and 1f means it has
* fully animated to the location of the Launcher's smartspace.
*/
private var smartspaceUnlockProgress = 0f
/**
* Whether we're currently unlocking, and we're talking to Launcher to perform in-window
* animations rather than simply animating the Launcher window like any other app. This can be
* true while [unlockingWithSmartspaceTransition] is false, if the smartspace is not available
* or was not ready in time.
*/
private var unlockingToLauncherWithInWindowAnimations: Boolean = false
/**
* Whether we are currently unlocking, and the smartspace shared element transition is in
* progress. If true, we're also [unlockingToLauncherWithInWindowAnimations].
*/
private var unlockingWithSmartspaceTransition: Boolean = false
private val handler = Handler()
init {
with(surfaceBehindAlphaAnimator) {
duration = SURFACE_BEHIND_SWIPE_FADE_DURATION_MS
interpolator = Interpolators.TOUCH_RESPONSE
addUpdateListener { valueAnimator: ValueAnimator ->
surfaceBehindAlpha = valueAnimator.animatedValue as Float
updateSurfaceBehindAppearAmount()
}
})
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
// If the surface alpha is 0f, it's no longer visible so we can safely be done
// with the animation even if other properties are still animating.
if (surfaceBehindAlpha == 0f) {
keyguardViewMediator.get().finishSurfaceBehindRemoteAnimation(
false /* cancelled */)
}
}
})
}
with(surfaceBehindEntryAnimator) {
duration = UNLOCK_ANIMATION_DURATION_MS
startDelay = UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS
interpolator = Interpolators.TOUCH_RESPONSE
addUpdateListener { valueAnimator: ValueAnimator ->
surfaceBehindAlpha = valueAnimator.animatedValue as Float
setSurfaceBehindAppearAmount(valueAnimator.animatedValue as Float)
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
playingCannedUnlockAnimation = false
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
false /* cancelled */
)
}
})
}
with(smartspaceAnimator) {
duration = UNLOCK_ANIMATION_DURATION_MS
interpolator = Interpolators.TOUCH_RESPONSE
addUpdateListener {
smartspaceUnlockProgress = it.animatedValue as Float
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
launcherUnlockController?.setSmartspaceVisibility(View.VISIBLE)
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
false /* cancelled */)
}
})
}
// Listen for changes in the dismiss amount.
keyguardStateController.addCallback(this)
roundedCornerRadius =
context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat()
context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat()
}
/**
* Add a listener to be notified of various stages of the unlock animation.
*/
fun addKeyguardUnlockAnimationListener(listener: KeyguardUnlockAnimationListener) {
listeners.add(listener)
}
/**
@@ -203,78 +377,220 @@ class KeyguardUnlockAnimationController @Inject constructor(
* surface for the unlock gesture/animation.
*
* When we're done with it, we'll call [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation]
* to end the RemoteAnimation.
* to end the RemoteAnimation. The KeyguardViewMediator will then end the animation and let us
* know that it's over by calling [notifyFinishedKeyguardExitAnimation].
*
* [requestedShowSurfaceBehindKeyguard] denotes whether the exit animation started because of a
* [requestedShowSurfaceBehindKeyguard] indicates whether the animation started because of a
* call to [KeyguardViewMediator.showSurfaceBehindKeyguard], as happens during a swipe gesture,
* as opposed to the keyguard hiding.
* as opposed to being called because the device was unlocked and the keyguard is going away.
*/
fun notifyStartKeyguardExitAnimation(
fun notifyStartSurfaceBehindRemoteAnimation(
target: RemoteAnimationTarget,
startTime: Long,
requestedShowSurfaceBehindKeyguard: Boolean
) {
if (surfaceTransactionApplier == null) {
surfaceTransactionApplier = SyncRtSurfaceTransactionApplier(
keyguardViewController.viewRootImpl.view)
}
// New animation, new params.
surfaceBehindParams = null
surfaceBehindRemoteAnimationTarget = target
surfaceBehindRemoteAnimationStartTime = startTime
// If the surface behind wasn't made visible during a swipe, we'll do a canned animation
// to animate it in. Otherwise, the swipe touch events will continue animating it.
// If we specifically requested that the surface behind be made visible, it means we are
// swiping to unlock. In that case, the surface visibility is tied to the dismiss amount,
// and we'll handle that in onKeyguardDismissAmountChanged(). If we didn't request that, the
// keyguard is being dismissed for a different reason (biometric auth, etc.) and we should
// play a canned animation to make the surface fully visible.
if (!requestedShowSurfaceBehindKeyguard) {
keyguardViewController.hide(startTime, 350)
// If we're wake and unlocking, we don't want to animate the surface since we're going
// to do the light reveal scrim from the black AOD screen. Make it visible and end the
// remote aimation.
if (biometricUnlockController.isWakeAndUnlock) {
setSurfaceBehindAppearAmount(1f)
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
false /* cancelled */)
} else {
// Otherwise, animate it in normally.
surfaceBehindEntryAnimator.start()
}
playCannedUnlockAnimation()
}
listeners.forEach {
it.onUnlockAnimationStarted(
playingCannedUnlockAnimation /* playingCannedAnimation */,
biometricUnlockControllerLazy.get().isWakeAndUnlock /* isWakeAndUnlock */) }
// Finish the keyguard remote animation if the dismiss amount has crossed the threshold.
// Check it here in case there is no more change to the dismiss amount after the last change
// that starts the keyguard animation. @see #updateKeyguardViewMediatorIfThresholdsReached()
finishKeyguardExitRemoteAnimationIfReachThreshold()
}
fun notifyCancelKeyguardExitAnimation() {
surfaceBehindRemoteAnimationTarget = null
}
/**
* Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and
* we should clean up all of our state.
*/
fun notifyFinishedKeyguardExitAnimation(cancelled: Boolean) {
// Cancel any pending actions.
handler.removeCallbacksAndMessages(null)
fun notifyFinishedKeyguardExitAnimation() {
surfaceBehindRemoteAnimationTarget = null
}
// Make sure we made the surface behind fully visible, just in case. It should already be
// fully visible.
setSurfaceBehindAppearAmount(1f)
launcherUnlockController?.setUnlockAmount(1f)
smartspaceDestBounds.setEmpty()
fun hideKeyguardViewAfterRemoteAnimation() {
keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350)
// That target is no longer valid since the animation finished, null it out.
surfaceBehindRemoteAnimationTarget = null
surfaceBehindParams = null
playingCannedUnlockAnimation = false
unlockingToLauncherWithInWindowAnimations = false
unlockingWithSmartspaceTransition = false
resetSmartspaceTransition()
listeners.forEach { it.onUnlockAnimationFinished() }
}
/**
* Whether we are currently in the process of unlocking the keyguard, and we are performing the
* shared element SmartSpace transition.
* Play a canned unlock animation to unlock the device. This is used when we were *not* swiping
* to unlock using a touch gesture. If we were swiping to unlock, the animation will be driven
* by the dismiss amount via [onKeyguardDismissAmountChanged].
*/
fun isUnlockingWithSmartSpaceTransition(): Boolean {
return unlockingWithSmartSpaceTransition
fun playCannedUnlockAnimation() {
playingCannedUnlockAnimation = true
if (canPerformInWindowLauncherAnimations()) {
// If possible, use the neat in-window animations to unlock to the launcher.
unlockToLauncherWithInWindowAnimations()
} else if (!biometricUnlockControllerLazy.get().isWakeAndUnlock) {
// If the launcher isn't behind the keyguard, or the launcher unlock controller is not
// available, animate in the entire window.
surfaceBehindEntryAnimator.start()
} else {
setSurfaceBehindAppearAmount(1f)
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(false)
}
// If this is a wake and unlock, hide the lockscreen immediately. In the future, we should
// animate it out nicely instead, but to the current state of wake and unlock, not hiding it
// causes a lot of issues.
// TODO(b/210016643): Not this, it looks not-ideal!
if (biometricUnlockControllerLazy.get().isWakeAndUnlock) {
keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350)
}
}
/**
* Unlock to the launcher, using in-window animations, and the smartspace shared element
* transition if possible.
*/
private fun unlockToLauncherWithInWindowAnimations() {
unlockingToLauncherWithInWindowAnimations = true
// See if we can do the smartspace transition, and if so, do it!
if (prepareForSmartspaceTransition()) {
animateSmartspaceToDestination()
listeners.forEach { it.onSmartspaceSharedElementTransitionStarted() }
}
// Tell the launcher to prepare for the animation by setting its views invisible and
// syncing the selected smartspace pages.
launcherUnlockController?.prepareForUnlock(
unlockingWithSmartspaceTransition /* willAnimateSmartspace */,
(lockscreenSmartspace as BcSmartspaceDataPlugin.SmartspaceView?)?.selectedPage ?: -1)
// Begin the animation.
launcherUnlockController?.playUnlockAnimation(
true /* unlocked */, UNLOCK_ANIMATION_DURATION_MS)
if (!unlockingWithSmartspaceTransition) {
// If we are not unlocking with the smartspace transition, wait for the unlock animation
// to end and then finish the remote animation. If we are using the smartspace
// transition, it will finish the remote animation once it ends.
handler.postDelayed({
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
false /* cancelled */)
}, UNLOCK_ANIMATION_DURATION_MS)
}
// Wait a moment, then show the launcher surface.
setSurfaceBehindAppearAmount(1f)
}
/**
* Animates the lockscreen smartspace all the way to the launcher's smartspace location, then
* makes the launcher smartspace visible and ends the remote animation.
*/
private fun animateSmartspaceToDestination() {
smartspaceAnimator.start()
}
/**
* Reset the lockscreen smartspace's position, and reset all state involving the smartspace
* transition.
*/
public fun resetSmartspaceTransition() {
unlockingWithSmartspaceTransition = false
smartspaceUnlockProgress = 0f
lockscreenSmartspace?.post {
lockscreenSmartspace!!.translationX = 0f
lockscreenSmartspace!!.translationY = 0f
}
}
/**
* Moves the lockscreen smartspace towards the launcher smartspace's position.
*/
private fun setSmartspaceProgressToDestinationBounds(progress: Float) {
if (smartspaceDestBounds.isEmpty) {
return
}
val progressClamped = min(1f, progress)
// Calculate the distance (relative to the origin) that we need to be for the current
// progress value.
val progressX =
(smartspaceDestBounds.left - smartspaceOriginBounds.left) * progressClamped
val progressY =
(smartspaceDestBounds.top - smartspaceOriginBounds.top) * progressClamped
val lockscreenSmartspaceCurrentBounds = Rect().also {
lockscreenSmartspace!!.getBoundsOnScreen(it)
}
// Figure out how far that is from our present location on the screen. This approach
// compensates for the fact that our parent container is also translating to animate out.
val dx = smartspaceOriginBounds.left + progressX -
lockscreenSmartspaceCurrentBounds.left
val dy = smartspaceOriginBounds.top + progressY -
lockscreenSmartspaceCurrentBounds.top
with(lockscreenSmartspace!!) {
translationX += dx
translationY += dy
}
}
/**
* Update the lockscreen SmartSpace to be positioned according to the current dismiss amount. As
* the dismiss amount increases, we will increase our SmartSpace's progress to the destination
* bounds (the location of the Launcher SmartSpace).
*
* This is used by [KeyguardClockSwitchController] to keep the smartspace position updated as
* the clock is swiped away.
*/
fun updateLockscreenSmartSpacePosition() {
smartspaceTransitionController.setProgressToDestinationBounds(
keyguardStateController.dismissAmount / DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)
setSmartspaceProgressToDestinationBounds(smartspaceUnlockProgress)
}
/**
* Asks the keyguard view to hide, using the start time from the beginning of the remote
* animation.
*/
fun hideKeyguardViewAfterRemoteAnimation() {
// Hide the keyguard, with no fade out since we animated it away during the unlock.
keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 0 /* fadeOutDuration */)
}
private fun applyParamsToSurface(params: SyncRtSurfaceTransactionApplier.SurfaceParams) {
surfaceTransactionApplier!!.scheduleApply(params)
surfaceBehindParams = params
}
/**
@@ -287,34 +603,56 @@ class KeyguardUnlockAnimationController @Inject constructor(
return
}
val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.height()
val scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR +
(1f - SURFACE_BEHIND_START_SCALE_FACTOR) *
MathUtils.clamp(amount, 0f, 1f))
if (unlockingToLauncherWithInWindowAnimations) {
// If we're using the in-window launcher animations, and haven't yet applied alpha = 1f
// to the launcher surface, do that now so we can see the launcher animations.
if (surfaceBehindParams?.alpha?.let { it < 1f } != false) {
applyParamsToSurface(
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
surfaceBehindRemoteAnimationTarget!!.leash)
.withAlpha(1f)
.build())
}
// Scale up from a point at the center-bottom of the surface.
surfaceBehindMatrix.setScale(
// If we aren't using the canned unlock animation (which would be setting the unlock
// amount in its update listener), do it here.
if (!isPlayingCannedUnlockAnimation()) {
launcherUnlockController?.setUnlockAmount(amount)
}
} else {
// Otherwise, animate in the surface's scale/transltion.
val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.height()
val scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR +
(1f - SURFACE_BEHIND_START_SCALE_FACTOR) *
MathUtils.clamp(amount, 0f, 1f))
// Scale up from a point at the center-bottom of the surface.
surfaceBehindMatrix.setScale(
scaleFactor,
scaleFactor,
surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.width() / 2f,
surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y)
surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y
)
// Translate up from the bottom.
surfaceBehindMatrix.postTranslate(0f,
surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount))
// Translate up from the bottom.
surfaceBehindMatrix.postTranslate(
0f,
surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount)
)
// If we're snapping the keyguard back, immediately begin fading it out.
val animationAlpha =
// If we're snapping the keyguard back, immediately begin fading it out.
val animationAlpha =
if (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount
else surfaceBehindAlpha
val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
surfaceBehindRemoteAnimationTarget!!.leash)
applyParamsToSurface(
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
surfaceBehindRemoteAnimationTarget!!.leash)
.withMatrix(surfaceBehindMatrix)
.withCornerRadius(roundedCornerRadius)
.withAlpha(animationAlpha)
.build()
surfaceTransactionApplier!!.scheduleApply(params)
.build())
}
}
/**
@@ -326,6 +664,10 @@ class KeyguardUnlockAnimationController @Inject constructor(
return
}
if (playingCannedUnlockAnimation) {
return
}
// For fling animations, we want to animate the surface in over the full distance. If we're
// dismissing the keyguard via a swipe gesture (or cancelling the swipe gesture), we want to
// bring in the surface behind over a relatively short swipe distance (~15%), to keep the
@@ -344,17 +686,19 @@ class KeyguardUnlockAnimationController @Inject constructor(
}
override fun onKeyguardDismissAmountChanged() {
if (!KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation) {
if (!willHandleUnlockAnimation()) {
return
}
if (keyguardViewController.isShowing) {
updateKeyguardViewMediatorIfThresholdsReached()
showOrHideSurfaceIfDismissAmountThresholdsReached()
// If the surface is visible or it's about to be, start updating its appearance to
// reflect the new dismiss amount.
if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
if ((keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
keyguardViewMediator.get()
.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) &&
!playingCannedUnlockAnimation) {
updateSurfaceBehindAppearAmount()
}
}
@@ -362,7 +706,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
// The end of the SmartSpace transition can occur after the keyguard is hidden (when we tell
// Launcher's SmartSpace to become visible again), so update it even if the keyguard view is
// no longer showing.
updateSmartSpaceTransition()
applyDismissAmountToSmartspaceTransition()
}
/**
@@ -370,16 +714,28 @@ class KeyguardUnlockAnimationController @Inject constructor(
* such as reaching the point in the dismiss swipe where we need to make the surface behind the
* keyguard visible.
*/
private fun updateKeyguardViewMediatorIfThresholdsReached() {
private fun showOrHideSurfaceIfDismissAmountThresholdsReached() {
if (!featureFlags.isEnabled(Flags.NEW_UNLOCK_SWIPE_ANIMATION)) {
return
}
// If we are playing the canned unlock animation, we flung away the keyguard to hide it and
// started a canned animation to show the surface behind the keyguard. The fling will cause
// panel height/dismiss amount updates, but we should ignore those updates here since the
// surface behind is already visible and animating.
if (playingCannedUnlockAnimation) {
return
}
val dismissAmount = keyguardStateController.dismissAmount
if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
// We passed the threshold, and we're not yet showing the surface behind the
// keyguard. Animate it in.
if (canPerformInWindowLauncherAnimations()) {
launcherUnlockController?.setUnlockAmount(0f)
unlockingToLauncherWithInWindowAnimations = true
}
keyguardViewMediator.get().showSurfaceBehindKeyguard()
fadeInSurfaceBehind()
} else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
@@ -388,9 +744,9 @@ class KeyguardUnlockAnimationController @Inject constructor(
// out.
keyguardViewMediator.get().hideSurfaceBehindKeyguard()
fadeOutSurfaceBehind()
} else {
finishKeyguardExitRemoteAnimationIfReachThreshold()
}
finishKeyguardExitRemoteAnimationIfReachThreshold()
}
/**
@@ -417,6 +773,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
// animating it out. This will be called again after the fling ends.
!keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)) {
setSurfaceBehindAppearAmount(1f)
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(false /* cancelled */)
}
}
@@ -426,31 +783,53 @@ class KeyguardUnlockAnimationController @Inject constructor(
* dismiss amount, and also updates the SmartSpaceTransitionController, which will let Launcher
* know if it needs to do something as a result.
*/
private fun updateSmartSpaceTransition() {
private fun applyDismissAmountToSmartspaceTransition() {
if (!featureFlags.isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED)) {
return
}
// If we are playing the canned animation, the smartspace is being animated directly between
// its original location and the location of the launcher smartspace by smartspaceAnimator.
// We can ignore the dismiss amount, which is caused by panel height changes as the panel is
// flung away.
if (playingCannedUnlockAnimation) {
return
}
val dismissAmount = keyguardStateController.dismissAmount
// If we've begun a swipe, and are capable of doing the SmartSpace transition, start it!
// If we've begun a swipe, and haven't yet tried doing the SmartSpace transition, do that
// now.
if (!attemptedSmartSpaceTransitionForThisSwipe &&
dismissAmount > 0f &&
dismissAmount < 1f &&
keyguardViewController.isShowing) {
keyguardViewController.isShowing &&
dismissAmount > 0f &&
dismissAmount < 1f) {
attemptedSmartSpaceTransitionForThisSwipe = true
smartspaceTransitionController.prepareForUnlockTransition()
if (keyguardStateController.canPerformSmartSpaceTransition()) {
unlockingWithSmartSpaceTransition = true
smartspaceTransitionController.launcherSmartspace?.setVisibility(
View.INVISIBLE)
if (prepareForSmartspaceTransition()) {
unlockingWithSmartspaceTransition = true
// Ensure that the smartspace is invisible if we're doing the transition, and
// visible if we aren't.
launcherUnlockController?.setSmartspaceVisibility(
if (unlockingWithSmartspaceTransition) View.INVISIBLE else View.VISIBLE)
if (unlockingWithSmartspaceTransition) {
listeners.forEach { it.onSmartspaceSharedElementTransitionStarted() }
}
}
} else if (attemptedSmartSpaceTransitionForThisSwipe &&
(dismissAmount == 0f || dismissAmount == 1f)) {
(dismissAmount == 0f || dismissAmount == 1f)) {
attemptedSmartSpaceTransitionForThisSwipe = false
unlockingWithSmartSpaceTransition = false
smartspaceTransitionController.launcherSmartspace?.setVisibility(View.VISIBLE)
unlockingWithSmartspaceTransition = false
launcherUnlockController?.setSmartspaceVisibility(View.VISIBLE)
}
if (unlockingWithSmartspaceTransition) {
val swipedFraction: Float = keyguardStateController.dismissAmount
val progress = swipedFraction / DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD
smartspaceUnlockProgress = progress
setSmartspaceProgressToDestinationBounds(smartspaceUnlockProgress)
}
}
@@ -463,4 +842,121 @@ class KeyguardUnlockAnimationController @Inject constructor(
surfaceBehindAlphaAnimator.cancel()
surfaceBehindAlphaAnimator.reverse()
}
/**
* Prepare for the smartspace shared element transition, if possible, by figuring out where we
* are animating from/to.
*
* Return true if we'll be able to do the smartspace transition, or false if conditions are not
* right to do it right now.
*/
private fun prepareForSmartspaceTransition(): Boolean {
// Feature is disabled, so we don't want to.
if (!featureFlags.isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED)) {
return false
}
// If our controllers are null, or we haven't received a smartspace state from Launcher yet,
// we will not be doing any smartspace transitions today.
if (launcherUnlockController == null ||
lockscreenSmartspace == null ||
launcherSmartspaceState == null) {
return false
}
// If the launcher does not have a visible smartspace (either because it's paged off-screen,
// or the smartspace just doesn't exist), we can't do the transition.
if ((launcherSmartspaceState?.visibleOnScreen) != true) {
return false
}
// If our launcher isn't underneath, then we're unlocking to an app or custom launcher,
// neither of which have a smartspace.
if (!isNexusLauncherUnderneath()) {
return false
}
// TODO(b/213910911): Unfortunately the keyguard is hidden instantly on wake and unlock, so
// we won't have a lockscreen smartspace to animate. This is sad, and we should fix that!
if (biometricUnlockControllerLazy.get().isWakeAndUnlock) {
return false
}
// If we can't dismiss the lock screen via a swipe, then the only way we can do the shared
// element transition is if we're doing a biometric unlock. Otherwise, it means the bouncer
// is showing, and you can't see the lockscreen smartspace, so a shared element transition
// would not make sense.
if (!keyguardStateController.canDismissLockScreen() &&
!biometricUnlockControllerLazy.get().isBiometricUnlock) {
return false
}
unlockingWithSmartspaceTransition = true
smartspaceDestBounds.setEmpty()
// Assuming we were able to retrieve the launcher's state, start the lockscreen
// smartspace at 0, 0, and save its starting bounds.
with(lockscreenSmartspace!!) {
translationX = 0f
translationY = 0f
getBoundsOnScreen(smartspaceOriginBounds)
}
// Set the destination bounds to the launcher smartspace's bounds, offset by any
// padding on our smartspace.
with(smartspaceDestBounds) {
set(launcherSmartspaceState!!.boundsOnScreen)
offset(-lockscreenSmartspace!!.paddingLeft, -lockscreenSmartspace!!.paddingTop)
}
return true
}
/**
* Whether we should be able to do the in-window launcher animations given the current state of
* the device.
*/
fun canPerformInWindowLauncherAnimations(): Boolean {
return isNexusLauncherUnderneath() && launcherUnlockController != null
}
/**
* Whether we are currently in the process of unlocking the keyguard, and we are performing the
* shared element SmartSpace transition.
*/
fun isUnlockingWithSmartSpaceTransition(): Boolean {
return unlockingWithSmartspaceTransition
}
/**
* Whether this animation controller will be handling the unlock. We require remote animations
* to be enabled to do this.
*
* If this is not true, nothing in this class is relevant, and the unlock will be handled in
* [KeyguardViewMediator].
*/
fun willHandleUnlockAnimation(): Boolean {
return KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation
}
/**
* Whether we are playing a canned unlock animation, vs. unlocking from a touch gesture such as
* a swipe.
*/
fun isPlayingCannedUnlockAnimation(): Boolean {
return playingCannedUnlockAnimation
}
companion object {
/**
* Return whether the Google Nexus launcher is underneath the keyguard, vs. some other
* launcher or an app. If so, we can communicate with it to perform in-window/shared element
* transitions!
*/
fun isNexusLauncherUnderneath(): Boolean {
return ActivityManagerWrapper.getInstance()
.runningTask?.topActivity?.className?.equals(
QuickStepContract.LAUNCHER_ACTIVITY_CLASS_NAME) ?: false
}
}
}

View File

@@ -2235,8 +2235,9 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
createInteractionJankMonitorConf("DismissPanel"));
// Pass the surface and metadata to the unlock animation controller.
mKeyguardUnlockAnimationControllerLazy.get().notifyStartKeyguardExitAnimation(
apps[0], startTime, mSurfaceBehindRemoteAnimationRequested);
mKeyguardUnlockAnimationControllerLazy.get()
.notifyStartSurfaceBehindRemoteAnimation(
apps[0], startTime, mSurfaceBehindRemoteAnimationRequested);
} else {
mInteractionJankMonitor.begin(
createInteractionJankMonitorConf("RemoteAnimationDisabled"));
@@ -2373,8 +2374,10 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
finishSurfaceBehindRemoteAnimation(cancelled);
mSurfaceBehindRemoteAnimationRequested = false;
mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation();
});
mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation(
cancelled);
}
/**
@@ -2412,8 +2415,16 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
return mSurfaceBehindRemoteAnimationRequested;
}
public boolean isAnimatingBetweenKeyguardAndSurfaceBehind() {
return mSurfaceBehindRemoteAnimationRunning;
}
/** If it's running, finishes the RemoteAnimation on the surface behind the keyguard. */
public void finishSurfaceBehindRemoteAnimation(boolean cancelled) {
if (!mSurfaceBehindRemoteAnimationRunning) {
return;
}
mSurfaceBehindRemoteAnimationRunning = false;
if (mSurfaceBehindRemoteAnimationFinishedCallback != null) {

View File

@@ -31,9 +31,9 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHE
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
@@ -83,6 +83,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBar;
@@ -97,7 +98,6 @@ import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
@@ -161,7 +161,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final CommandQueue mCommandQueue;
private final ShellTransitions mShellTransitions;
private final Optional<StartingSurface> mStartingSurface;
private final SmartspaceTransitionController mSmartspaceTransitionController;
private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController;
private final Optional<RecentTasks> mRecentTasks;
private final UiEventLogger mUiEventLogger;
@@ -503,8 +503,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
KEY_EXTRA_SHELL_STARTING_WINDOW,
startingwindow.createExternalInterface().asBinder()));
params.putBinder(
KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER,
mSmartspaceTransitionController.createExternalInterface().asBinder());
KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER,
mSysuiUnlockAnimationController.asBinder());
mRecentTasks.ifPresent(recentTasks -> params.putBinder(
KEY_EXTRA_RECENT_TASKS,
recentTasks.createExternalInterface().asBinder()));
@@ -570,8 +570,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
BroadcastDispatcher broadcastDispatcher,
ShellTransitions shellTransitions,
ScreenLifecycle screenLifecycle,
SmartspaceTransitionController smartspaceTransitionController,
UiEventLogger uiEventLogger,
KeyguardUnlockAnimationController sysuiUnlockAnimationController,
DumpManager dumpManager) {
super(broadcastDispatcher);
mContext = context;
@@ -644,7 +644,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
updateEnabledState();
startConnectionToCurrentUser();
mStartingSurface = startingSurface;
mSmartspaceTransitionController = smartspaceTransitionController;
mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
}
@Override

View File

@@ -1,143 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.shared.system.smartspace
import android.graphics.Rect
import android.view.View
import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.shared.system.QuickStepContract
import kotlin.math.min
/**
* Controller that keeps track of SmartSpace instances in remote processes (such as Launcher),
* allowing System UI to query or update their state during shared-element transitions.
*/
class SmartspaceTransitionController {
/**
* Implementation of [ISmartspaceTransitionController] that we provide to Launcher, allowing it
* to provide us with a callback to query and update the state of its Smartspace.
*/
private val ISmartspaceTransitionController = object : ISmartspaceTransitionController.Stub() {
override fun setSmartspace(callback: ISmartspaceCallback?) {
this@SmartspaceTransitionController.launcherSmartspace = callback
updateLauncherSmartSpaceState()
}
}
/**
* Callback provided by Launcher to allow us to query and update the state of its SmartSpace.
*/
public var launcherSmartspace: ISmartspaceCallback? = null
public var lockscreenSmartspace: View? = null
/**
* Cached state of the Launcher SmartSpace. Retrieving the state is an IPC, so we should avoid
* unnecessary
*/
public var mLauncherSmartspaceState: SmartspaceState? = null
/**
* The bounds of our SmartSpace when the shared element transition began. We'll interpolate
* between this and [smartspaceDestinationBounds] as the dismiss amount changes.
*/
private val smartspaceOriginBounds = Rect()
/** The bounds of the Launcher's SmartSpace, which is where we are animating our SmartSpace. */
private val smartspaceDestinationBounds = Rect()
fun createExternalInterface(): ISmartspaceTransitionController {
return ISmartspaceTransitionController
}
/**
* Updates [mLauncherSmartspaceState] and returns it. This will trigger a binder call, so use the
* cached [mLauncherSmartspaceState] if possible.
*/
fun updateLauncherSmartSpaceState(): SmartspaceState? {
return launcherSmartspace?.smartspaceState.also {
mLauncherSmartspaceState = it
}
}
fun prepareForUnlockTransition() {
updateLauncherSmartSpaceState().also { state ->
if (state?.boundsOnScreen != null && lockscreenSmartspace != null) {
lockscreenSmartspace!!.getBoundsOnScreen(smartspaceOriginBounds)
with(smartspaceDestinationBounds) {
set(state.boundsOnScreen)
offset(-lockscreenSmartspace!!.paddingLeft,
-lockscreenSmartspace!!.paddingTop)
}
}
}
}
fun setProgressToDestinationBounds(progress: Float) {
if (!isSmartspaceTransitionPossible()) {
return
}
val progressClamped = min(1f, progress)
// Calculate the distance (relative to the origin) that we need to be for the current
// progress value.
val progressX =
(smartspaceDestinationBounds.left - smartspaceOriginBounds.left) * progressClamped
val progressY =
(smartspaceDestinationBounds.top - smartspaceOriginBounds.top) * progressClamped
val lockscreenSmartspaceCurrentBounds = Rect().also {
lockscreenSmartspace!!.getBoundsOnScreen(it)
}
// Figure out how far that is from our present location on the screen. This approach
// compensates for the fact that our parent container is also translating to animate out.
val dx = smartspaceOriginBounds.left + progressX -
lockscreenSmartspaceCurrentBounds.left
var dy = smartspaceOriginBounds.top + progressY -
lockscreenSmartspaceCurrentBounds.top
with(lockscreenSmartspace!!) {
translationX = translationX + dx
translationY = translationY + dy
}
}
/**
* Whether we're capable of performing the Smartspace shared element transition when we unlock.
* This is true if:
*
* - The Launcher registered a Smartspace with us, it's reporting non-empty bounds on screen.
* - Launcher is behind the keyguard, and the Smartspace is visible on the currently selected
* page.
*/
public fun isSmartspaceTransitionPossible(): Boolean {
val smartSpaceNullOrBoundsEmpty = mLauncherSmartspaceState?.boundsOnScreen?.isEmpty ?: true
return isLauncherUnderneath() && !smartSpaceNullOrBoundsEmpty
}
companion object {
fun isLauncherUnderneath(): Boolean {
return ActivityManagerWrapper.getInstance()
.runningTask?.topActivity?.className?.equals(
QuickStepContract.LAUNCHER_ACTIVITY_CLASS_NAME) ?: false
}
}
}

View File

@@ -153,6 +153,16 @@ class NotificationShadeDepthController @Inject constructor(
shadeAnimation.finishIfRunning()
}
/**
* We're unlocking, and should not blur as the panel expansion changes.
*/
var blursDisabledForUnlock: Boolean = false
set(value) {
if (field == value) return
field = value
scheduleUpdate()
}
/**
* Force stop blur effect when necessary.
*/
@@ -192,7 +202,7 @@ class NotificationShadeDepthController @Inject constructor(
combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress))
var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius)
if (blursDisabledForAppLaunch) {
if (blursDisabledForAppLaunch || blursDisabledForUnlock) {
shadeRadius = 0f
}
@@ -309,9 +319,7 @@ class NotificationShadeDepthController @Inject constructor(
/**
* Update blurs when pulling down the shade
*/
override fun onPanelExpansionChanged(
rawFraction: Float, expanded: Boolean, tracking: Boolean
) {
override fun onPanelExpansionChanged(rawFraction: Float, expanded: Boolean, tracking: Boolean) {
val timestamp = SystemClock.elapsedRealtimeNanos()
val expansion = MathUtils.saturate(
(rawFraction - panelPullDownMinFraction) / (1f - panelPullDownMinFraction))

View File

@@ -44,6 +44,7 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -254,6 +255,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
);
}
private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Inject
public BiometricUnlockController(Context context, DozeScrimController dozeScrimController,
KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
@@ -269,7 +272,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
WakefulnessLifecycle wakefulnessLifecycle,
ScreenLifecycle screenLifecycle,
AuthController authController,
StatusBarStateController statusBarStateController) {
StatusBarStateController statusBarStateController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
mContext = context;
mPowerManager = powerManager;
mShadeController = shadeController;
@@ -292,6 +296,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
mMetricsLogger = metricsLogger;
mAuthController = authController;
mStatusBarStateController = statusBarStateController;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
dumpManager.registerDumpable(getClass().getName(), this);
}
@@ -438,11 +443,15 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
if (!wasDeviceInteractive) {
mPendingShowBouncer = true;
} else {
mShadeController.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_NONE,
true /* force */,
false /* delayed */,
BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
// If the keyguard unlock controller is going to handle the unlock animation, it
// will fling the panel collapsed when it's ready.
if (!mKeyguardUnlockAnimationController.willHandleUnlockAnimation()) {
mShadeController.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_NONE,
true /* force */,
false /* delayed */,
BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
}
mPendingShowBouncer = false;
mKeyguardViewController.notifyKeyguardAuthenticated(
false /* strongAuth */);

View File

@@ -138,6 +138,7 @@ import com.android.systemui.fragments.FragmentService;
import com.android.systemui.idle.IdleHostView;
import com.android.systemui.idle.IdleHostViewController;
import com.android.systemui.idle.dagger.IdleViewComponent;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
@@ -791,7 +792,8 @@ public class NotificationPanelViewController extends PanelViewController {
Optional<SysUIUnfoldComponent> unfoldComponent,
ControlsComponent controlsComponent,
InteractionJankMonitor interactionJankMonitor,
QsFrameTranslateController qsFrameTranslateController) {
QsFrameTranslateController qsFrameTranslateController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
super(view,
featureFlags,
falsingManager,
@@ -806,7 +808,8 @@ public class NotificationPanelViewController extends PanelViewController {
lockscreenGestureLogger,
panelExpansionStateManager,
ambientState,
interactionJankMonitor);
interactionJankMonitor,
keyguardUnlockAnimationController);
mView = view;
mVibratorHelper = vibratorHelper;
mKeyguardMediaController = keyguardMediaController;
@@ -925,8 +928,33 @@ public class NotificationPanelViewController extends PanelViewController {
mQsFrameTranslateController = qsFrameTranslateController;
updateUserSwitcherFlags();
onFinishInflate();
mUseCombinedQSHeaders = featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS);
keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@Override
public void onUnlockAnimationFinished() {
// Make sure the clock is in the correct position after the unlock animation
// so that it's not in the wrong place when we show the keyguard again.
positionClockAndNotifications(true /* forceClockUpdate */);
}
@Override
public void onUnlockAnimationStarted(
boolean playingCannedAnimation, boolean isWakeAndUnlock) {
// Disable blurs while we're unlocking so that panel expansion does not
// cause blurring. This will eventually be re-enabled by the panel view on
// ACTION_UP, since the user's finger might still be down after a swipe to
// unlock gesture, and we don't want that to cause blurring either.
mDepthController.setBlursDisabledForUnlock(mTracking);
if (playingCannedAnimation && !isWakeAndUnlock) {
// Fling the panel away so it's not in the way or the surface behind the
// keyguard, which will be appearing. If we're wake and unlocking, the
// lock screen is hidden instantly so should not be flung away.
fling(0f, false, 0.7f, false);
}
}
});
}
private void onFinishInflate() {
@@ -3324,6 +3352,10 @@ public class NotificationPanelViewController extends PanelViewController {
mAffordanceHelper.reset(true);
}
}
// If we unlocked from a swipe, the user's finger might still be down after the
// unlock animation ends. We need to wait until ACTION_UP to enable blurs again.
mDepthController.setBlursDisabledForUnlock(false);
}
private void updateMaxHeadsUpTranslation() {

View File

@@ -55,6 +55,7 @@ import com.android.systemui.classifier.Classifier;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -212,6 +213,8 @@ public abstract class PanelViewController {
return mAmbientState;
}
private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
public PanelViewController(
PanelView view,
FeatureFlags featureFlags,
@@ -227,7 +230,15 @@ public abstract class PanelViewController {
LockscreenGestureLogger lockscreenGestureLogger,
PanelExpansionStateManager panelExpansionStateManager,
AmbientState ambientState,
InteractionJankMonitor interactionJankMonitor) {
InteractionJankMonitor interactionJankMonitor,
KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
public void onKeyguardFadingAwayChanged() {
requestPanelHeightUpdate();
}
});
mAmbientState = ambientState;
mView = view;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
@@ -437,7 +448,8 @@ public abstract class PanelViewController {
mUpdateFlingVelocity = vel;
}
} else if (!mStatusBar.isBouncerShowing()
&& !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) {
&& !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()
&& !mKeyguardStateController.isKeyguardGoingAway()) {
boolean expands = onEmptySpaceClick(mInitialTouchX);
onTrackingStopped(expands);
}

View File

@@ -809,6 +809,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
: ScrimState.SHADE_LOCKED.getBehindTint();
behindTint = ColorUtils.blendARGB(behindTint, stateTint, mQsExpansion);
}
// If the keyguard is going away, we should not be opaque.
if (mKeyguardStateController.isKeyguardGoingAway()) {
behindAlpha = 0f;
}
return new Pair<>(behindTint, behindAlpha);
}
@@ -1333,9 +1339,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
mExpansionAffectsAlpha = expansionAffectsAlpha;
if (expansionAffectsAlpha) {
applyAndDispatchState();
}
}
public void setKeyguardOccluded(boolean keyguardOccluded) {

View File

@@ -2978,6 +2978,8 @@ public class StatusBar extends CoreStartable implements
public void showKeyguardImpl() {
mIsKeyguard = true;
// In case we're locking while a smartspace transition is in progress, reset it.
mKeyguardUnlockAnimationController.resetSmartspaceTransition();
if (mKeyguardStateController.isLaunchTransitionFadingAway()) {
mNotificationPanelViewController.cancelAnimation();
onLaunchTransitionFadingEnded();
@@ -3156,6 +3158,7 @@ public class StatusBar extends CoreStartable implements
// bar.
mKeyguardStateController.notifyKeyguardGoingAway(true);
mCommandQueue.appTransitionPending(mDisplayId, true /* forced */);
updateScrimController();
}
/**
@@ -3327,7 +3330,10 @@ public class StatusBar extends CoreStartable implements
}
private void showBouncerOrLockScreenIfKeyguard() {
if (!mKeyguardViewMediator.isHiding()) {
// If the keyguard is animating away, we aren't really the keyguard anymore and should not
// show the bouncer/lockscreen.
if (!mKeyguardViewMediator.isHiding()
&& !mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
if (mState == StatusBarState.SHADE_LOCKED
&& mKeyguardUpdateMonitor.isUdfpsEnrolled()) {
// shade is showing while locked on the keyguard, so go back to showing the
@@ -3761,17 +3767,14 @@ public class StatusBar extends CoreStartable implements
public void updateScrimController() {
Trace.beginSection("StatusBar#updateScrimController");
// We don't want to end up in KEYGUARD state when we're unlocking with
// fingerprint from doze. We should cross fade directly from black.
boolean unlocking = mBiometricUnlockController.isWakeAndUnlock()
|| mKeyguardStateController.isKeyguardFadingAway();
boolean unlocking = mKeyguardStateController.isShowing() && (
mBiometricUnlockController.isWakeAndUnlock()
|| mKeyguardStateController.isKeyguardFadingAway()
|| mKeyguardStateController.isKeyguardGoingAway()
|| mKeyguardViewMediator.requestedShowSurfaceBehindKeyguard()
|| mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind());
// Do not animate the scrim expansion when triggered by the fingerprint sensor.
boolean onKeyguardOrHidingIt = mKeyguardStateController.isShowing()
|| mKeyguardStateController.isKeyguardFadingAway()
|| mKeyguardStateController.isKeyguardGoingAway();
mScrimController.setExpansionAffectsAlpha(!(mBiometricUnlockController.isBiometricUnlock()
&& onKeyguardOrHidingIt));
mScrimController.setExpansionAffectsAlpha(!unlocking);
boolean launchingAffordanceWithPreview =
mNotificationPanelViewController.isLaunchingAffordanceWithPreview();
@@ -3783,7 +3786,7 @@ public class StatusBar extends CoreStartable implements
} else {
mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED);
}
} else if (mBouncerShowing) {
} else if (mBouncerShowing && !unlocking) {
// Bouncer needs the front scrim when it's on top of an activity,
// tapping on a notification, editing QS or being dismissed by
// FLAG_DISMISS_KEYGUARD_ACTIVITY.

View File

@@ -49,13 +49,6 @@ public interface KeyguardStateController extends CallbackController<Callback> {
*/
boolean canDismissLockScreen();
/**
* Whether we can currently perform the shared element SmartSpace transition. This is true if
* we're on the lockscreen, it can be dismissed with a swipe, and the Launcher is underneath the
* keyguard and displaying a SmartSpace that it has registered with System UI.
*/
boolean canPerformSmartSpaceTransition();
/**
* Whether the keyguard is allowed to rotate, or needs to be locked to the default orientation.
*/

View File

@@ -35,7 +35,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -44,6 +44,8 @@ import java.util.Objects;
import javax.inject.Inject;
import dagger.Lazy;
/**
*/
@SysUISingleton
@@ -58,7 +60,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
private final LockPatternUtils mLockPatternUtils;
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new UpdateMonitorCallback();
private final SmartspaceTransitionController mSmartspaceTransitionController;
private final Lazy<KeyguardUnlockAnimationController> mUnlockAnimationControllerLazy;
private boolean mCanDismissLockScreen;
private boolean mShowing;
@@ -105,13 +107,13 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
Context context,
KeyguardUpdateMonitor keyguardUpdateMonitor,
LockPatternUtils lockPatternUtils,
SmartspaceTransitionController smartspaceTransitionController,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
DumpManager dumpManager) {
mContext = context;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
mSmartspaceTransitionController = smartspaceTransitionController;
mUnlockAnimationControllerLazy = keyguardUnlockAnimationController;
dumpManager.registerDumpable(getClass().getSimpleName(), this);
@@ -248,12 +250,6 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
return mCanDismissLockScreen;
}
@Override
public boolean canPerformSmartSpaceTransition() {
return canDismissLockScreen()
&& mSmartspaceTransitionController.isSmartspaceTransitionPossible();
}
@Override
public boolean isKeyguardScreenRotationAllowed() {
return SystemProperties.getBoolean("lockscreen.rot_override", false)

View File

@@ -48,7 +48,6 @@ import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -96,9 +95,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Mock
Resources mResources;
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock
SmartspaceTransitionController mSmartSpaceTransitionController;
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock
private ClockPlugin mClockPlugin;
@Mock
@@ -154,7 +152,6 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
mBypassController,
mSmartspaceController,
mKeyguardUnlockAnimationController,
mSmartSpaceTransitionController,
mSecureSettings,
mExecutor,
mResources

View File

@@ -24,7 +24,6 @@ import android.testing.AndroidTestingRunner;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -61,8 +60,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
@Mock
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock
SmartspaceTransitionController mSmartSpaceTransitionController;
@Mock
ScreenOffAnimationController mScreenOffAnimationController;
@Captor
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
@@ -83,7 +80,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
mConfigurationController,
mDozeParameters,
mKeyguardUnlockAnimationController,
mSmartSpaceTransitionController,
mScreenOffAnimationController);
}

View File

@@ -14,7 +14,6 @@ import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardViewController
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController
import junit.framework.Assert.assertEquals
@@ -44,8 +43,6 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
@Mock
private lateinit var keyguardViewController: KeyguardViewController
@Mock
private lateinit var smartspaceTransitionController: SmartspaceTransitionController
@Mock
private lateinit var featureFlags: FeatureFlags
@Mock
private lateinit var biometricUnlockController: BiometricUnlockController
@@ -59,7 +56,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
keyguardUnlockAnimationController = KeyguardUnlockAnimationController(
context, keyguardStateController, { keyguardViewMediator }, keyguardViewController,
smartspaceTransitionController, featureFlags, biometricUnlockController
featureFlags, { biometricUnlockController }
)
`when`(keyguardViewController.viewRootImpl).thenReturn(mock(ViewRootImpl::class.java))
@@ -87,7 +84,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
fun noSurfaceAnimation_ifWakeAndUnlocking() {
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
keyguardUnlockAnimationController.notifyStartKeyguardExitAnimation(
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTarget,
0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */
@@ -118,15 +115,12 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
fun surfaceAnimation_ifNotWakeAndUnlocking() {
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(false)
keyguardUnlockAnimationController.notifyStartKeyguardExitAnimation(
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTarget,
0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */
)
// Make sure the animator was started.
assertTrue(keyguardUnlockAnimationController.surfaceBehindEntryAnimator.isRunning)
// Since the animation is running, we should not have finished the remote animation.
verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished(
false /* cancelled */)

View File

@@ -301,6 +301,40 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
eq(notificationShadeDepthController.updateBlurCallback))
}
@Test
fun ignoreBlurForUnlock_ignores() {
notificationShadeDepthController.onPanelExpansionChanged(
rawFraction = 1f, expanded = true, tracking = false
)
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.blursDisabledForAppLaunch = false
notificationShadeDepthController.blursDisabledForUnlock = true
notificationShadeDepthController.updateBlurCallback.doFrame(0)
// Since we are ignoring blurs for unlock, we should be applying blur = 0 despite setting it
// to maxBlur above.
verify(blurUtils).applyBlur(any(), eq(0), eq(false))
}
@Test
fun ignoreBlurForUnlock_doesNotIgnore() {
notificationShadeDepthController.onPanelExpansionChanged(
rawFraction = 1f, expanded = true, tracking = false
)
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.blursDisabledForAppLaunch = false
notificationShadeDepthController.blursDisabledForUnlock = false
notificationShadeDepthController.updateBlurCallback.doFrame(0)
// Since we are not ignoring blurs for unlock (or app launch), we should apply the blur we
// returned above (maxBlur).
verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
}
@Test
fun brightnessMirrorVisible_whenVisible() {
notificationShadeDepthController.brightnessMirrorVisible = true

View File

@@ -561,6 +561,10 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
override fun setMediaTarget(target: SmartspaceTarget?) {
}
override fun getSelectedPage(): Int {
return -1
}
})
}
}

View File

@@ -42,6 +42,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -104,6 +105,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
private ScreenLifecycle mScreenLifecycle;
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private BiometricUnlockController mBiometricUnlockController;
@Before
@@ -126,7 +129,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters,
mMetricsLogger, mDumpManager, mPowerManager,
mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle,
mAuthController, mStatusBarStateController);
mAuthController, mStatusBarStateController, mKeyguardUnlockAnimationController);
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
mBiometricUnlockController.setBiometricModeListener(mBiometricModeListener);
}

View File

@@ -104,6 +104,7 @@ import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.idle.IdleHostViewController;
import com.android.systemui.idle.dagger.IdleViewComponent;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
@@ -362,6 +363,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private QsFrameTranslateController mQsFrameTranslateController;
@Mock
private StatusBarWindowStateController mStatusBarWindowStateController;
@Mock
private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -546,7 +549,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mSysUIUnfoldComponent,
mControlsComponent,
mInteractionJankMonitor,
mQsFrameTranslateController);
mQsFrameTranslateController,
mKeyguardUnlockAnimationController);
mNotificationPanelViewController.initDependencies(
mStatusBar,
() -> {},

View File

@@ -819,31 +819,27 @@ public class StatusBarTest extends SysuiTestCase {
}
@Test
public void testSetExpansionAffectsAlpha_onlyWhenHidingKeyguard() {
mStatusBar.updateScrimController();
verify(mScrimController).setExpansionAffectsAlpha(eq(true));
clearInvocations(mScrimController);
when(mBiometricUnlockController.isBiometricUnlock()).thenReturn(true);
public void testSetExpansionAffectsAlpha_whenKeyguardShowingButGoingAwayForAnyReason() {
mStatusBar.updateScrimController();
verify(mScrimController).setExpansionAffectsAlpha(eq(true));
clearInvocations(mScrimController);
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false);
mStatusBar.updateScrimController();
verify(mScrimController).setExpansionAffectsAlpha(eq(false));
verify(mScrimController).setExpansionAffectsAlpha(eq(true));
clearInvocations(mScrimController);
reset(mKeyguardStateController);
when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
mStatusBar.updateScrimController();
verify(mScrimController).setExpansionAffectsAlpha(eq(false));
clearInvocations(mScrimController);
reset(mKeyguardStateController);
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
mStatusBar.updateScrimController();
verify(mScrimController).setExpansionAffectsAlpha(eq(false));
clearInvocations(mScrimController);
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
mStatusBar.updateScrimController();
verify(mScrimController).setExpansionAffectsAlpha(eq(false));
}
@Test

View File

@@ -33,7 +33,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import org.junit.Before;
import org.junit.Test;
@@ -41,6 +41,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import dagger.Lazy;
@SmallTest
@TestableLooper.RunWithLooper
@RunWith(AndroidTestingRunner.class)
@@ -52,9 +54,9 @@ public class KeyguardStateControllerTest extends SysuiTestCase {
private LockPatternUtils mLockPatternUtils;
private KeyguardStateController mKeyguardStateController;
@Mock
private SmartspaceTransitionController mSmartSpaceTransitionController;
@Mock
private DumpManager mDumpManager;
@Mock
private Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
@Before
public void setup() {
@@ -63,7 +65,7 @@ public class KeyguardStateControllerTest extends SysuiTestCase {
mContext,
mKeyguardUpdateMonitor,
mLockPatternUtils,
mSmartSpaceTransitionController,
mKeyguardUnlockAnimationControllerLazy,
mDumpManager);
}

View File

@@ -128,11 +128,6 @@ public class FakeKeyguardStateController implements KeyguardStateController {
}
@Override
public boolean canPerformSmartSpaceTransition() {
return false;
}
@Override
public boolean isKeyguardScreenRotationAllowed() {
return false;