Adds the initial SmartSpace shared element transition!
To see this in action, enable the remote animation (adb shell setprop persist.wm.enable_remote_keyguard_animation 1) and enhanced SmartSpace (adb shell device_config put launcher ENABLE_SMARTSPACE_ENHANCED true). Also, set your lock mode to swipe or some sort of non-bypass biometrics, so you can swipe to unlock.
KIs:
- It looks pretty janky on a fast swipe - this is the same root cause as b/186847064 so will have the same fix
- Launcher animates in with window-level animations (Launcher team is looking into helping)
- Screen off animation is not yet implemented (this is for unlock only)
Bug: 187025480
Test: unlock with every possible permutation of lock settings
Change-Id: I8c186fe57132ebc9a0bc5e3d8785e753e72c3bf2
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index f98a959..b2ae2a0 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -40,7 +40,8 @@
name: "SystemUISharedLib",
srcs: [
"src/**/*.java",
- "src/**/I*.aidl",
+ "src/**/*.kt",
+ "src/**/*.aidl",
":wm_shell-aidls",
],
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 2cf3ad2..c468e41 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -36,6 +36,9 @@
* Various shared constants between Launcher and SysUI as part of quickstep
*/
public class QuickStepContract {
+ // Fully qualified name of the Launcher activity.
+ public static final String LAUNCHER_ACTIVITY_CLASS_NAME =
+ "com.google.android.apps.nexuslauncher.NexusLauncherActivity";
public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
@@ -52,6 +55,8 @@
// 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";
public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl
new file mode 100644
index 0000000..511df4c
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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);
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl
new file mode 100644
index 0000000..2b3e961
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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);
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl
new file mode 100644
index 0000000..2d01d6a
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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;
+
+parcelable SmartspaceState;
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt
new file mode 100644
index 0000000..2d51c4d
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.os.Parcel
+import android.os.Parcelable
+
+/**
+ * Represents the state of a SmartSpace, including its location on screen and the index of the
+ * currently selected page. This object contains all of the information needed to synchronize two
+ * SmartSpace instances so that we can perform shared-element transitions between them.
+ */
+class SmartspaceState() : Parcelable {
+ var boundsOnScreen: Rect = Rect()
+ var selectedPage = 0
+
+ constructor(parcel: Parcel) : this() {
+ this.boundsOnScreen = parcel.readParcelable(Rect::javaClass.javaClass.classLoader)
+ this.selectedPage = parcel.readInt()
+ }
+
+ override fun writeToParcel(dest: Parcel?, flags: Int) {
+ dest?.writeParcelable(boundsOnScreen, 0)
+ dest?.writeInt(selectedPage)
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun toString(): String {
+ return "boundsOnScreen: $boundsOnScreen, selectedPage: $selectedPage"
+ }
+
+ companion object CREATOR : Parcelable.Creator<SmartspaceState> {
+ override fun createFromParcel(parcel: Parcel): SmartspaceState {
+ return SmartspaceState(parcel)
+ }
+
+ override fun newArray(size: Int): Array<SmartspaceState?> {
+ return arrayOfNulls(size)
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 932860f..bc23481 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -32,8 +32,10 @@
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
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.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -44,7 +46,9 @@
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.ViewController;
+import java.util.HashSet;
import java.util.Locale;
+import java.util.Set;
import java.util.TimeZone;
import javax.inject.Inject;
@@ -92,6 +96,9 @@
// If set, will replace keyguard_status_area
private View mSmartspaceView;
+ private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private SmartspaceTransitionController mSmartspaceTransitionController;
+
@Inject
public KeyguardClockSwitchController(
KeyguardClockSwitch keyguardClockSwitch,
@@ -104,7 +111,9 @@
BatteryController batteryController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardBypassController bypassController,
- LockscreenSmartspaceController smartspaceController) {
+ LockscreenSmartspaceController smartspaceController,
+ KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+ SmartspaceTransitionController smartspaceTransitionController) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor;
@@ -116,6 +125,9 @@
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mBypassController = bypassController;
mSmartspaceController = smartspaceController;
+
+ mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+ mSmartspaceTransitionController = smartspaceTransitionController;
}
/**
@@ -187,6 +199,7 @@
nic.setLayoutParams(lp);
mView.setSmartspaceView(mSmartspaceView);
+ mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
}
}
@@ -282,12 +295,44 @@
if (mSmartspaceView != null) {
PropertyAnimator.setProperty(mSmartspaceView, AnimatableProperty.TRANSLATION_X,
x, props, animate);
+
+ // If we're unlocking with the SmartSpace shared element transition, let the controller
+ // know that it should re-position our SmartSpace.
+ if (mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
+ mKeyguardUnlockAnimationController.updateLockscreenSmartSpacePosition();
+ } else {
+ // Otherwise, reset Y translation in case it's still offset from a previous shared
+ // element transition.
+ ((View) mSmartspaceView).setTranslationY(0f);
+ }
}
mKeyguardSliceViewController.updatePosition(x, props, animate);
mNotificationIconAreaController.updatePosition(x, props, animate);
}
+ /** Sets an alpha value on every child view except for the smartspace. */
+ public void setChildrenAlphaExcludingSmartspace(float alpha) {
+ final Set<View> excludedViews = new HashSet<>();
+
+ if (mSmartspaceView != null) {
+ excludedViews.add(mSmartspaceView);
+ }
+
+ setChildrenAlphaExcluding(alpha, excludedViews);
+ }
+
+ /** Sets an alpha value on every child view except for the views in the provided set. */
+ public void setChildrenAlphaExcluding(float alpha, Set<View> excludedViews) {
+ for (int i = 0; i < mView.getChildCount(); i++) {
+ final View child = mView.getChildAt(i);
+
+ if (!excludedViews.contains(child)) {
+ child.setAlpha(alpha);
+ }
+ }
+ }
+
void updateTimeZone(TimeZone timeZone) {
mView.onTimeZoneChanged(timeZone);
if (mClockViewController != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 3ab2cca..250f598 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -28,6 +28,7 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.GridLayout;
import android.widget.TextView;
@@ -39,6 +40,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Set;
/**
* View consisting of:
@@ -55,6 +57,7 @@
private final LockPatternUtils mLockPatternUtils;
private final IActivityManager mIActivityManager;
+ private ViewGroup mStatusViewContainer;
private TextView mLogoutView;
private KeyguardClockSwitch mClockView;
private TextView mOwnerInfo;
@@ -66,6 +69,7 @@
private float mDarkAmount = 0;
private int mTextColor;
+ private float mChildrenAlphaExcludingSmartSpace = 1f;
/**
* Bottom margin that defines the margin between bottom of smart space and top of notification
@@ -132,6 +136,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mStatusViewContainer = findViewById(R.id.status_view_container);
mLogoutView = findViewById(R.id.logout);
if (mLogoutView != null) {
mLogoutView.setOnClickListener(this::onLogoutClicked);
@@ -251,6 +256,27 @@
mClockView.setTextColor(blendedTextColor);
}
+ public void setChildrenAlphaExcludingClockView(float alpha) {
+ setChildrenAlphaExcluding(alpha, Set.of(mClockView));
+ }
+
+ /** Sets an alpha value on every view except for the views in the provided set. */
+ public void setChildrenAlphaExcluding(float alpha, Set<View> excludedViews) {
+ mChildrenAlphaExcludingSmartSpace = alpha;
+
+ for (int i = 0; i < mStatusViewContainer.getChildCount(); i++) {
+ final View child = mStatusViewContainer.getChildAt(i);
+
+ if (!excludedViews.contains(child)) {
+ child.setAlpha(alpha);
+ }
+ }
+ }
+
+ public float getChildrenAlphaExcludingSmartSpace() {
+ return mChildrenAlphaExcludingSmartSpace;
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardStatusView:");
pw.println(" mOwnerInfo: " + (mOwnerInfo == null
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 388c085..7b6514a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -20,6 +20,8 @@
import android.os.UserHandle;
import android.util.Slog;
+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;
@@ -49,6 +51,9 @@
private final ConfigurationController mConfigurationController;
private final DozeParameters mDozeParameters;
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
+ private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private final KeyguardStateController mKeyguardStateController;
+ private SmartspaceTransitionController mSmartspaceTransitionController;
private final Rect mClipBounds = new Rect();
@Inject
@@ -59,15 +64,33 @@
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController,
- DozeParameters dozeParameters) {
+ DozeParameters dozeParameters,
+ KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+ SmartspaceTransitionController smartspaceTransitionController) {
super(keyguardStatusView);
mKeyguardSliceViewController = keyguardSliceViewController;
mKeyguardClockSwitchController = keyguardClockSwitchController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mConfigurationController = configurationController;
mDozeParameters = dozeParameters;
+ mKeyguardStateController = keyguardStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
dozeParameters);
+ mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+ mSmartspaceTransitionController = smartspaceTransitionController;
+
+ mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ // If we explicitly re-show the keyguard, make sure that all the child views are
+ // visible. They might have been animating out as part of the SmartSpace shared
+ // element transition.
+ if (keyguardStateController.isShowing()) {
+ mView.setChildrenAlphaExcludingClockView(1f);
+ mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(1f);
+ }
+ }
+ });
}
@Override
@@ -137,7 +160,24 @@
*/
public void setAlpha(float alpha) {
if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
- mView.setAlpha(alpha);
+ // If we're capable of performing the SmartSpace shared element transition, and we are
+ // going to (we're swiping to dismiss vs. bringing up the PIN screen), then fade out
+ // everything except for the SmartSpace.
+ if (mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
+ mView.setChildrenAlphaExcludingClockView(alpha);
+ mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(alpha);
+ } else if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
+ // Otherwise, we can just set the alpha for the entire container.
+ mView.setAlpha(alpha);
+
+ // If we previously unlocked with the shared element transition, some child views
+ // might still have alpha = 0f. Set them back to 1f since we're just using the
+ // parent container's alpha.
+ if (mView.getChildrenAlphaExcludingSmartSpace() < 1f) {
+ mView.setChildrenAlphaExcludingClockView(1f);
+ mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(1f);
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index cc167b9..e6fe060 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -133,6 +133,7 @@
.setTaskViewFactory(Optional.ofNullable(null))
.setTransitions(Transitions.createEmptyForTesting())
.setStartingSurface(Optional.ofNullable(null));
+
}
mSysUIComponent = builder.build();
if (mInitializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 1396099..f422e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -45,6 +45,7 @@
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.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -173,6 +174,12 @@
return SystemUIFactory.getInstance();
}
+ @SysUISingleton
+ @Provides
+ static SmartspaceTransitionController provideSmartspaceTransitionController() {
+ return new SmartspaceTransitionController();
+ }
+
// TODO: This should provided by the WM component
/** Provides Optional of BubbleManager */
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 411c328..665376a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -23,11 +23,14 @@
import android.graphics.Matrix
import android.view.RemoteAnimationTarget
import android.view.SyncRtSurfaceTransactionApplier
+import android.view.View
import androidx.core.math.MathUtils
import com.android.internal.R
+import com.android.keyguard.KeyguardClockSwitchController
import com.android.keyguard.KeyguardViewController
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy
import javax.inject.Inject
@@ -85,7 +88,8 @@
context: Context,
private val keyguardStateController: KeyguardStateController,
private val keyguardViewMediator: Lazy<KeyguardViewMediator>,
- private val keyguardViewController: KeyguardViewController
+ private val keyguardViewController: KeyguardViewController,
+ private val smartspaceTransitionController: SmartspaceTransitionController
) : KeyguardStateController.Callback {
/**
@@ -131,6 +135,21 @@
/** 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).
+ */
+ private var attemptedSmartSpaceTransitionForThisSwipe = false
+
init {
surfaceBehindAlphaAnimator.duration = 150
surfaceBehindAlphaAnimator.interpolator = Interpolators.ALPHA_IN
@@ -214,6 +233,24 @@
}
/**
+ * 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
+ }
+
+ /**
+ * 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).
+ */
+ fun updateLockscreenSmartSpacePosition() {
+ smartspaceTransitionController.setProgressToDestinationBounds(
+ keyguardStateController.dismissAmount / DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)
+ }
+
+ /**
* Scales in and translates up the surface behind the keyguard. This is used during unlock
* animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
* cancelled).
@@ -284,36 +321,85 @@
return
}
+ if (keyguardViewController.isShowing) {
+ updateKeyguardViewMediatorIfThresholdsReached()
+
+ // 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) {
+ updateSurfaceBehindAppearAmount()
+ }
+ }
+
+ // The end of the SmartSpace transition can occur after the keyguard is hidden (when we tell
+ // Launcher's SmartSpace to become visible again), so update it even if the keyguard view is
+ // no longer showing.
+ updateSmartSpaceTransition()
+ }
+
+ /**
+ * Lets the KeyguardViewMediator know if the dismiss amount has crossed a threshold of interest,
+ * such as reaching the point in the dismiss swipe where we need to make the surface behind the
+ * keyguard visible.
+ */
+ private fun updateKeyguardViewMediatorIfThresholdsReached() {
val dismissAmount = keyguardStateController.dismissAmount
// Hide the keyguard if we're fully dismissed, or if we're swiping to dismiss and have
// crossed the threshold to finish the dismissal.
val reachedHideKeyguardThreshold = (dismissAmount >= 1f ||
(keyguardStateController.isDismissingFromSwipe &&
- // Don't hide if we're flinging during a swipe, since we need to finish
- // animating it out. This will be called again after the fling ends.
- !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
- dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
+ // Don't hide if we're flinging during a swipe, since we need to finish
+ // animating it out. This will be called again after the fling ends.
+ !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
+ dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
- // We passed the threshold, and we're not yet showing the surface behind the keyguard.
- // Animate it in.
+ // We passed the threshold, and we're not yet showing the surface behind the
+ // keyguard. Animate it in.
keyguardViewMediator.get().showSurfaceBehindKeyguard()
fadeInSurfaceBehind()
} else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
- // We're no longer past the threshold but we are showing the surface. Animate it out.
+ // We're no longer past the threshold but we are showing the surface. Animate it
+ // out.
keyguardViewMediator.get().hideSurfaceBehindKeyguard()
fadeOutSurfaceBehind()
- } else if (keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
+ } else if (keyguardViewMediator.get()
+ .isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
reachedHideKeyguardThreshold) {
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished()
}
+ }
- if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
- keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
- updateSurfaceBehindAppearAmount()
+ /**
+ * Updates flags related to the SmartSpace transition in response to a change in keyguard
+ * dismiss amount, and also updates the SmartSpaceTransitionController, which will let Launcher
+ * know if it needs to do something as a result.
+ */
+ private fun updateSmartSpaceTransition() {
+ val dismissAmount = keyguardStateController.dismissAmount
+
+ // If we've begun a swipe, and are capable of doing the SmartSpace transition, start it!
+ if (!attemptedSmartSpaceTransitionForThisSwipe &&
+ dismissAmount > 0f &&
+ dismissAmount < 1f &&
+ keyguardViewController.isShowing) {
+ attemptedSmartSpaceTransitionForThisSwipe = true
+
+ smartspaceTransitionController.prepareForUnlockTransition()
+ if (keyguardStateController.canPerformSmartSpaceTransition()) {
+ unlockingWithSmartSpaceTransition = true
+ smartspaceTransitionController.launcherSmartspace?.setVisibility(
+ View.INVISIBLE)
+ }
+ } else if (attemptedSmartSpaceTransitionForThisSwipe &&
+ (dismissAmount == 0f || dismissAmount == 1f)) {
+ attemptedSmartSpaceTransitionForThisSwipe = false
+ unlockingWithSmartSpaceTransition = false
+ smartspaceTransitionController.launcherSmartspace?.setVisibility(View.VISIBLE)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 20c3e81..6a07a00 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -29,6 +29,7 @@
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_WINDOW_CORNER_RADIUS;
@@ -88,6 +89,7 @@
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.StatusBar;
@@ -148,6 +150,7 @@
private final CommandQueue mCommandQueue;
private final ShellTransitions mShellTransitions;
private final Optional<StartingSurface> mStartingSurface;
+ private final SmartspaceTransitionController mSmartspaceTransitionController;
private Region mActiveNavBarRegion;
@@ -540,6 +543,9 @@
mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
KEY_EXTRA_SHELL_STARTING_WINDOW,
startingwindow.createExternalInterface().asBinder()));
+ params.putBinder(
+ KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER,
+ mSmartspaceTransitionController.createExternalInterface().asBinder());
try {
Log.d(TAG_OPS + " b/182478748", "OverviewProxyService.onInitialize: curUser="
@@ -601,7 +607,8 @@
Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher,
ShellTransitions shellTransitions,
- Optional<StartingSurface> startingSurface) {
+ Optional<StartingSurface> startingSurface,
+ SmartspaceTransitionController smartspaceTransitionController) {
super(broadcastDispatcher);
mContext = context;
mPipOptional = pipOptional;
@@ -663,6 +670,7 @@
updateEnabledState();
startConnectionToCurrentUser();
mStartingSurface = startingSurface;
+ mSmartspaceTransitionController = smartspaceTransitionController;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt
new file mode 100644
index 0000000..89b3df0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt
@@ -0,0 +1,143 @@
+/*
+ * 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
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ec012bf..6f1ab0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -456,6 +456,7 @@
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final BrightnessSlider.Factory mBrightnessSliderFactory;
private final FeatureFlags mFeatureFlags;
+ private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final List<ExpansionChangedListener> mExpansionChangedListeners;
@@ -877,6 +878,8 @@
mAnimationScheduler = animationScheduler;
mStatusBarLocationPublisher = locationPublisher;
mFeatureFlags = featureFlags;
+ mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
lockscreenShadeTransitionController.setStatusbar(this);
@@ -1365,7 +1368,8 @@
// are already animating the keyguard dismiss (since we will need to either finish or cancel
// the animation).
if (trackingTouch
- || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
+ || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()
+ || mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
mKeyguardStateController.notifyKeyguardDismissAmountChanged(
1f - expansion, trackingTouch);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index e7201f8..af7bf95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -50,6 +50,13 @@
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();
+
+ /**
* If the device has PIN/pattern/password or a lock screen at all.
*/
boolean isMethodSecure();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index e69c1f2..0945a3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -32,6 +32,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -53,6 +54,7 @@
private final LockPatternUtils mLockPatternUtils;
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new UpdateMonitorCallback();
+ private final SmartspaceTransitionController mSmartspaceTransitionController;
private boolean mCanDismissLockScreen;
private boolean mShowing;
@@ -96,10 +98,12 @@
*/
@Inject
public KeyguardStateControllerImpl(Context context,
- KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils,
+ SmartspaceTransitionController smartspaceTransitionController) {
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+ mSmartspaceTransitionController = smartspaceTransitionController;
update(true /* updateAlways */);
if (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB) {
@@ -158,6 +162,11 @@
mShowing = showing;
mOccluded = occluded;
notifyKeyguardChanged();
+
+ // Update the dismiss amount to the full 0f/1f if we explicitly show or hide the keyguard.
+ // Otherwise, the dismiss amount could be left at a random value if we show/hide during a
+ // dismiss gesture, canceling the gesture.
+ notifyKeyguardDismissAmountChanged(showing ? 0f : 1f, false);
}
private void notifyKeyguardChanged() {
@@ -228,6 +237,12 @@
}
@Override
+ public boolean canPerformSmartSpaceTransition() {
+ return canDismissLockScreen()
+ && mSmartspaceTransitionController.isSmartspaceTransitionPossible();
+ }
+
+ @Override
public boolean isFaceAuthEnabled() {
return mFaceAuthEnabled;
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 98467d4..1111e70 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -40,8 +40,10 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
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;
@@ -86,6 +88,9 @@
@Mock
Resources mResources;
+ KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock
+ SmartspaceTransitionController mSmartSpaceTransitionController;
@Mock
private ClockPlugin mClockPlugin;
@Mock
@@ -135,7 +140,10 @@
mBatteryController,
mKeyguardUpdateMonitor,
mBypassController,
- mSmartspaceController);
+ mSmartspaceController,
+ mKeyguardUnlockAnimationController,
+ mSmartSpaceTransitionController
+ );
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 49f1655..f9b6d44 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -22,6 +22,8 @@
import android.testing.AndroidTestingRunner;
import com.android.systemui.SysuiTestCase;
+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.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -50,6 +52,10 @@
ConfigurationController mConfigurationController;
@Mock
DozeParameters mDozeParameters;
+ @Mock
+ KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock
+ SmartspaceTransitionController mSmartSpaceTransitionController;
private KeyguardStatusViewController mController;
@@ -64,7 +70,9 @@
mKeyguardStateController,
mKeyguardUpdateMonitor,
mConfigurationController,
- mDozeParameters);
+ mDozeParameters,
+ mKeyguardUnlockAnimationController,
+ mSmartSpaceTransitionController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
index 53a2efc..4b87ec8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
@@ -32,6 +32,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import org.junit.Before;
import org.junit.Test;
@@ -49,12 +50,14 @@
@Mock
private LockPatternUtils mLockPatternUtils;
private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private SmartspaceTransitionController mSmartSpaceTransitionController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mKeyguardStateController = new KeyguardStateControllerImpl(mContext,
- mKeyguardUpdateMonitor, mLockPatternUtils);
+ mKeyguardUpdateMonitor, mLockPatternUtils, mSmartSpaceTransitionController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
index 5fb779a..1aebf1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
@@ -127,4 +127,9 @@
public void notifyPanelFlingEnd() {
}
+
+ @Override
+ public boolean canPerformSmartSpaceTransition() {
+ return false;
+ }
}