Merge "Adds Launcher in-window animations, and reworks how the unlock flow works."
This commit is contained in:
@@ -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 */
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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> {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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 */);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -561,6 +561,10 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
||||
|
||||
override fun setMediaTarget(target: SmartspaceTarget?) {
|
||||
}
|
||||
|
||||
override fun getSelectedPage(): Int {
|
||||
return -1
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
() -> {},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,11 +128,6 @@ public class FakeKeyguardStateController implements KeyguardStateController {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPerformSmartSpaceTransition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKeyguardScreenRotationAllowed() {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user