Merge "Adds the initial SmartSpace shared element transition!" into sc-dev
This commit is contained in:
@@ -40,7 +40,8 @@ android_library {
|
|||||||
name: "SystemUISharedLib",
|
name: "SystemUISharedLib",
|
||||||
srcs: [
|
srcs: [
|
||||||
"src/**/*.java",
|
"src/**/*.java",
|
||||||
"src/**/I*.aidl",
|
"src/**/*.kt",
|
||||||
|
"src/**/*.aidl",
|
||||||
":wm_shell-aidls",
|
":wm_shell-aidls",
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ import java.util.StringJoiner;
|
|||||||
* Various shared constants between Launcher and SysUI as part of quickstep
|
* Various shared constants between Launcher and SysUI as part of quickstep
|
||||||
*/
|
*/
|
||||||
public class QuickStepContract {
|
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_SYSUI_PROXY = "extra_sysui_proxy";
|
||||||
public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
|
public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
|
||||||
@@ -52,6 +55,8 @@ public class QuickStepContract {
|
|||||||
// See IStartingWindow.aidl
|
// See IStartingWindow.aidl
|
||||||
public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
|
public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
|
||||||
"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 =
|
public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
|
||||||
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
|
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,8 +32,10 @@ import com.android.keyguard.clock.ClockManager;
|
|||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||||
|
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||||
import com.android.systemui.plugins.ClockPlugin;
|
import com.android.systemui.plugins.ClockPlugin;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
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.lockscreen.LockscreenSmartspaceController;
|
||||||
import com.android.systemui.statusbar.notification.AnimatableProperty;
|
import com.android.systemui.statusbar.notification.AnimatableProperty;
|
||||||
import com.android.systemui.statusbar.notification.PropertyAnimator;
|
import com.android.systemui.statusbar.notification.PropertyAnimator;
|
||||||
@@ -44,7 +46,9 @@ import com.android.systemui.statusbar.phone.NotificationIconContainer;
|
|||||||
import com.android.systemui.statusbar.policy.BatteryController;
|
import com.android.systemui.statusbar.policy.BatteryController;
|
||||||
import com.android.systemui.util.ViewController;
|
import com.android.systemui.util.ViewController;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -92,6 +96,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
// If set, will replace keyguard_status_area
|
// If set, will replace keyguard_status_area
|
||||||
private View mSmartspaceView;
|
private View mSmartspaceView;
|
||||||
|
|
||||||
|
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||||
|
private SmartspaceTransitionController mSmartspaceTransitionController;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public KeyguardClockSwitchController(
|
public KeyguardClockSwitchController(
|
||||||
KeyguardClockSwitch keyguardClockSwitch,
|
KeyguardClockSwitch keyguardClockSwitch,
|
||||||
@@ -104,7 +111,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
BatteryController batteryController,
|
BatteryController batteryController,
|
||||||
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||||
KeyguardBypassController bypassController,
|
KeyguardBypassController bypassController,
|
||||||
LockscreenSmartspaceController smartspaceController) {
|
LockscreenSmartspaceController smartspaceController,
|
||||||
|
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
|
||||||
|
SmartspaceTransitionController smartspaceTransitionController) {
|
||||||
super(keyguardClockSwitch);
|
super(keyguardClockSwitch);
|
||||||
mStatusBarStateController = statusBarStateController;
|
mStatusBarStateController = statusBarStateController;
|
||||||
mColorExtractor = colorExtractor;
|
mColorExtractor = colorExtractor;
|
||||||
@@ -116,6 +125,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||||
mBypassController = bypassController;
|
mBypassController = bypassController;
|
||||||
mSmartspaceController = smartspaceController;
|
mSmartspaceController = smartspaceController;
|
||||||
|
|
||||||
|
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
|
||||||
|
mSmartspaceTransitionController = smartspaceTransitionController;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -187,6 +199,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
nic.setLayoutParams(lp);
|
nic.setLayoutParams(lp);
|
||||||
|
|
||||||
mView.setSmartspaceView(mSmartspaceView);
|
mView.setSmartspaceView(mSmartspaceView);
|
||||||
|
mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,12 +298,44 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
if (mSmartspaceView != null) {
|
if (mSmartspaceView != null) {
|
||||||
PropertyAnimator.setProperty(mSmartspaceView, AnimatableProperty.TRANSLATION_X,
|
PropertyAnimator.setProperty(mSmartspaceView, AnimatableProperty.TRANSLATION_X,
|
||||||
x, props, animate);
|
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);
|
mKeyguardSliceViewController.updatePosition(x, props, animate);
|
||||||
mNotificationIconAreaController.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) {
|
void updateTimeZone(TimeZone timeZone) {
|
||||||
mView.onTimeZoneChanged(timeZone);
|
mView.onTimeZoneChanged(timeZone);
|
||||||
if (mClockViewController != null) {
|
if (mClockViewController != null) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.util.AttributeSet;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.widget.GridLayout;
|
import android.widget.GridLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ import com.android.systemui.statusbar.CrossFadeHelper;
|
|||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View consisting of:
|
* View consisting of:
|
||||||
@@ -55,6 +57,7 @@ public class KeyguardStatusView extends GridLayout {
|
|||||||
private final LockPatternUtils mLockPatternUtils;
|
private final LockPatternUtils mLockPatternUtils;
|
||||||
private final IActivityManager mIActivityManager;
|
private final IActivityManager mIActivityManager;
|
||||||
|
|
||||||
|
private ViewGroup mStatusViewContainer;
|
||||||
private TextView mLogoutView;
|
private TextView mLogoutView;
|
||||||
private KeyguardClockSwitch mClockView;
|
private KeyguardClockSwitch mClockView;
|
||||||
private TextView mOwnerInfo;
|
private TextView mOwnerInfo;
|
||||||
@@ -66,6 +69,7 @@ public class KeyguardStatusView extends GridLayout {
|
|||||||
|
|
||||||
private float mDarkAmount = 0;
|
private float mDarkAmount = 0;
|
||||||
private int mTextColor;
|
private int mTextColor;
|
||||||
|
private float mChildrenAlphaExcludingSmartSpace = 1f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bottom margin that defines the margin between bottom of smart space and top of notification
|
* Bottom margin that defines the margin between bottom of smart space and top of notification
|
||||||
@@ -132,6 +136,7 @@ public class KeyguardStatusView extends GridLayout {
|
|||||||
@Override
|
@Override
|
||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
|
mStatusViewContainer = findViewById(R.id.status_view_container);
|
||||||
mLogoutView = findViewById(R.id.logout);
|
mLogoutView = findViewById(R.id.logout);
|
||||||
if (mLogoutView != null) {
|
if (mLogoutView != null) {
|
||||||
mLogoutView.setOnClickListener(this::onLogoutClicked);
|
mLogoutView.setOnClickListener(this::onLogoutClicked);
|
||||||
@@ -249,6 +254,27 @@ public class KeyguardStatusView extends GridLayout {
|
|||||||
mClockView.setTextColor(blendedTextColor);
|
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) {
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
pw.println("KeyguardStatusView:");
|
pw.println("KeyguardStatusView:");
|
||||||
pw.println(" mOwnerInfo: " + (mOwnerInfo == null
|
pw.println(" mOwnerInfo: " + (mOwnerInfo == null
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import android.graphics.Rect;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.util.Slog;
|
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.AnimatableProperty;
|
||||||
import com.android.systemui.statusbar.notification.PropertyAnimator;
|
import com.android.systemui.statusbar.notification.PropertyAnimator;
|
||||||
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
|
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
|
||||||
@@ -49,6 +51,9 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
|||||||
private final ConfigurationController mConfigurationController;
|
private final ConfigurationController mConfigurationController;
|
||||||
private final DozeParameters mDozeParameters;
|
private final DozeParameters mDozeParameters;
|
||||||
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
|
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
|
||||||
|
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||||
|
private final KeyguardStateController mKeyguardStateController;
|
||||||
|
private SmartspaceTransitionController mSmartspaceTransitionController;
|
||||||
private final Rect mClipBounds = new Rect();
|
private final Rect mClipBounds = new Rect();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -59,15 +64,33 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
|||||||
KeyguardStateController keyguardStateController,
|
KeyguardStateController keyguardStateController,
|
||||||
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||||
ConfigurationController configurationController,
|
ConfigurationController configurationController,
|
||||||
DozeParameters dozeParameters) {
|
DozeParameters dozeParameters,
|
||||||
|
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
|
||||||
|
SmartspaceTransitionController smartspaceTransitionController) {
|
||||||
super(keyguardStatusView);
|
super(keyguardStatusView);
|
||||||
mKeyguardSliceViewController = keyguardSliceViewController;
|
mKeyguardSliceViewController = keyguardSliceViewController;
|
||||||
mKeyguardClockSwitchController = keyguardClockSwitchController;
|
mKeyguardClockSwitchController = keyguardClockSwitchController;
|
||||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||||
mConfigurationController = configurationController;
|
mConfigurationController = configurationController;
|
||||||
mDozeParameters = dozeParameters;
|
mDozeParameters = dozeParameters;
|
||||||
|
mKeyguardStateController = keyguardStateController;
|
||||||
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
|
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
|
||||||
dozeParameters);
|
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
|
@Override
|
||||||
@@ -137,7 +160,24 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
|||||||
*/
|
*/
|
||||||
public void setAlpha(float alpha) {
|
public void setAlpha(float alpha) {
|
||||||
if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ public class SystemUIFactory {
|
|||||||
.setTaskViewFactory(Optional.ofNullable(null))
|
.setTaskViewFactory(Optional.ofNullable(null))
|
||||||
.setTransitions(Transitions.createEmptyForTesting())
|
.setTransitions(Transitions.createEmptyForTesting())
|
||||||
.setStartingSurface(Optional.ofNullable(null));
|
.setStartingSurface(Optional.ofNullable(null));
|
||||||
|
|
||||||
}
|
}
|
||||||
mSysUIComponent = builder.build();
|
mSysUIComponent = builder.build();
|
||||||
if (mInitializeComponents) {
|
if (mInitializeComponents) {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import com.android.systemui.power.dagger.PowerModule;
|
|||||||
import com.android.systemui.recents.Recents;
|
import com.android.systemui.recents.Recents;
|
||||||
import com.android.systemui.screenshot.dagger.ScreenshotModule;
|
import com.android.systemui.screenshot.dagger.ScreenshotModule;
|
||||||
import com.android.systemui.settings.dagger.SettingsModule;
|
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.CommandQueue;
|
||||||
import com.android.systemui.statusbar.FeatureFlags;
|
import com.android.systemui.statusbar.FeatureFlags;
|
||||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||||
@@ -173,6 +174,12 @@ public abstract class SystemUIModule {
|
|||||||
return SystemUIFactory.getInstance();
|
return SystemUIFactory.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SysUISingleton
|
||||||
|
@Provides
|
||||||
|
static SmartspaceTransitionController provideSmartspaceTransitionController() {
|
||||||
|
return new SmartspaceTransitionController();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: This should provided by the WM component
|
// TODO: This should provided by the WM component
|
||||||
/** Provides Optional of BubbleManager */
|
/** Provides Optional of BubbleManager */
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
|
|||||||
@@ -23,11 +23,14 @@ import android.content.Context
|
|||||||
import android.graphics.Matrix
|
import android.graphics.Matrix
|
||||||
import android.view.RemoteAnimationTarget
|
import android.view.RemoteAnimationTarget
|
||||||
import android.view.SyncRtSurfaceTransactionApplier
|
import android.view.SyncRtSurfaceTransactionApplier
|
||||||
|
import android.view.View
|
||||||
import androidx.core.math.MathUtils
|
import androidx.core.math.MathUtils
|
||||||
import com.android.internal.R
|
import com.android.internal.R
|
||||||
|
import com.android.keyguard.KeyguardClockSwitchController
|
||||||
import com.android.keyguard.KeyguardViewController
|
import com.android.keyguard.KeyguardViewController
|
||||||
import com.android.systemui.animation.Interpolators
|
import com.android.systemui.animation.Interpolators
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -85,7 +88,8 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
|||||||
context: Context,
|
context: Context,
|
||||||
private val keyguardStateController: KeyguardStateController,
|
private val keyguardStateController: KeyguardStateController,
|
||||||
private val keyguardViewMediator: Lazy<KeyguardViewMediator>,
|
private val keyguardViewMediator: Lazy<KeyguardViewMediator>,
|
||||||
private val keyguardViewController: KeyguardViewController
|
private val keyguardViewController: KeyguardViewController,
|
||||||
|
private val smartspaceTransitionController: SmartspaceTransitionController
|
||||||
) : KeyguardStateController.Callback {
|
) : KeyguardStateController.Callback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,6 +135,21 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
|||||||
/** Rounded corner radius to apply to the surface behind the keyguard. */
|
/** Rounded corner radius to apply to the surface behind the keyguard. */
|
||||||
private var roundedCornerRadius = 0f
|
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 {
|
init {
|
||||||
surfaceBehindAlphaAnimator.duration = 150
|
surfaceBehindAlphaAnimator.duration = 150
|
||||||
surfaceBehindAlphaAnimator.interpolator = Interpolators.ALPHA_IN
|
surfaceBehindAlphaAnimator.interpolator = Interpolators.ALPHA_IN
|
||||||
@@ -213,6 +232,24 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
|||||||
keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350)
|
keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* 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
|
* animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
|
||||||
@@ -284,36 +321,85 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
|||||||
return
|
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
|
val dismissAmount = keyguardStateController.dismissAmount
|
||||||
|
|
||||||
// Hide the keyguard if we're fully dismissed, or if we're swiping to dismiss and have
|
// Hide the keyguard if we're fully dismissed, or if we're swiping to dismiss and have
|
||||||
// crossed the threshold to finish the dismissal.
|
// crossed the threshold to finish the dismissal.
|
||||||
val reachedHideKeyguardThreshold = (dismissAmount >= 1f ||
|
val reachedHideKeyguardThreshold = (dismissAmount >= 1f ||
|
||||||
(keyguardStateController.isDismissingFromSwipe &&
|
(keyguardStateController.isDismissingFromSwipe &&
|
||||||
// Don't hide if we're flinging during a swipe, since we need to finish
|
// 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.
|
// animating it out. This will be called again after the fling ends.
|
||||||
!keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
|
!keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
|
||||||
dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
|
dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
|
||||||
|
|
||||||
if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
|
if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
|
||||||
!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
|
!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
|
||||||
// We passed the threshold, and we're not yet showing the surface behind the keyguard.
|
// We passed the threshold, and we're not yet showing the surface behind the
|
||||||
// Animate it in.
|
// keyguard. Animate it in.
|
||||||
keyguardViewMediator.get().showSurfaceBehindKeyguard()
|
keyguardViewMediator.get().showSurfaceBehindKeyguard()
|
||||||
fadeInSurfaceBehind()
|
fadeInSurfaceBehind()
|
||||||
} else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
|
} else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
|
||||||
keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
|
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()
|
keyguardViewMediator.get().hideSurfaceBehindKeyguard()
|
||||||
fadeOutSurfaceBehind()
|
fadeOutSurfaceBehind()
|
||||||
} else if (keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
|
} else if (keyguardViewMediator.get()
|
||||||
|
.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
|
||||||
reachedHideKeyguardThreshold) {
|
reachedHideKeyguardThreshold) {
|
||||||
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished()
|
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
|
/**
|
||||||
keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
|
* Updates flags related to the SmartSpace transition in response to a change in keyguard
|
||||||
updateSurfaceBehindAppearAmount()
|
* 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ 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_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_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_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_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_SYSUI_PROXY;
|
||||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
|
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
|
||||||
@@ -88,6 +89,7 @@ import com.android.systemui.shared.recents.ISystemUiProxy;
|
|||||||
import com.android.systemui.shared.recents.model.Task;
|
import com.android.systemui.shared.recents.model.Task;
|
||||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||||
import com.android.systemui.shared.system.QuickStepContract;
|
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.CommandQueue;
|
||||||
import com.android.systemui.statusbar.NotificationShadeWindowController;
|
import com.android.systemui.statusbar.NotificationShadeWindowController;
|
||||||
import com.android.systemui.statusbar.phone.StatusBar;
|
import com.android.systemui.statusbar.phone.StatusBar;
|
||||||
@@ -148,6 +150,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
|
|||||||
private final CommandQueue mCommandQueue;
|
private final CommandQueue mCommandQueue;
|
||||||
private final ShellTransitions mShellTransitions;
|
private final ShellTransitions mShellTransitions;
|
||||||
private final Optional<StartingSurface> mStartingSurface;
|
private final Optional<StartingSurface> mStartingSurface;
|
||||||
|
private final SmartspaceTransitionController mSmartspaceTransitionController;
|
||||||
|
|
||||||
private Region mActiveNavBarRegion;
|
private Region mActiveNavBarRegion;
|
||||||
|
|
||||||
@@ -552,6 +555,9 @@ public class OverviewProxyService extends CurrentUserTracker implements
|
|||||||
mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
|
mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
|
||||||
KEY_EXTRA_SHELL_STARTING_WINDOW,
|
KEY_EXTRA_SHELL_STARTING_WINDOW,
|
||||||
startingwindow.createExternalInterface().asBinder()));
|
startingwindow.createExternalInterface().asBinder()));
|
||||||
|
params.putBinder(
|
||||||
|
KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER,
|
||||||
|
mSmartspaceTransitionController.createExternalInterface().asBinder());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Log.d(TAG_OPS + " b/182478748", "OverviewProxyService.onInitialize: curUser="
|
Log.d(TAG_OPS + " b/182478748", "OverviewProxyService.onInitialize: curUser="
|
||||||
@@ -613,7 +619,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
|
|||||||
Optional<OneHanded> oneHandedOptional,
|
Optional<OneHanded> oneHandedOptional,
|
||||||
BroadcastDispatcher broadcastDispatcher,
|
BroadcastDispatcher broadcastDispatcher,
|
||||||
ShellTransitions shellTransitions,
|
ShellTransitions shellTransitions,
|
||||||
Optional<StartingSurface> startingSurface) {
|
Optional<StartingSurface> startingSurface,
|
||||||
|
SmartspaceTransitionController smartspaceTransitionController) {
|
||||||
super(broadcastDispatcher);
|
super(broadcastDispatcher);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mPipOptional = pipOptional;
|
mPipOptional = pipOptional;
|
||||||
@@ -675,6 +682,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
|
|||||||
updateEnabledState();
|
updateEnabledState();
|
||||||
startConnectionToCurrentUser();
|
startConnectionToCurrentUser();
|
||||||
mStartingSurface = startingSurface;
|
mStartingSurface = startingSurface;
|
||||||
|
mSmartspaceTransitionController = smartspaceTransitionController;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -464,6 +464,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
|||||||
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
|
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
|
||||||
private final BrightnessSlider.Factory mBrightnessSliderFactory;
|
private final BrightnessSlider.Factory mBrightnessSliderFactory;
|
||||||
private final FeatureFlags mFeatureFlags;
|
private final FeatureFlags mFeatureFlags;
|
||||||
|
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||||
|
|
||||||
private final List<ExpansionChangedListener> mExpansionChangedListeners;
|
private final List<ExpansionChangedListener> mExpansionChangedListeners;
|
||||||
|
|
||||||
@@ -885,6 +886,8 @@ public class StatusBar extends SystemUI implements DemoMode,
|
|||||||
mAnimationScheduler = animationScheduler;
|
mAnimationScheduler = animationScheduler;
|
||||||
mStatusBarLocationPublisher = locationPublisher;
|
mStatusBarLocationPublisher = locationPublisher;
|
||||||
mFeatureFlags = featureFlags;
|
mFeatureFlags = featureFlags;
|
||||||
|
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
|
||||||
|
|
||||||
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
|
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
|
||||||
lockscreenShadeTransitionController.setStatusbar(this);
|
lockscreenShadeTransitionController.setStatusbar(this);
|
||||||
|
|
||||||
@@ -1369,7 +1372,8 @@ public class StatusBar extends SystemUI implements DemoMode,
|
|||||||
// are already animating the keyguard dismiss (since we will need to either finish or cancel
|
// are already animating the keyguard dismiss (since we will need to either finish or cancel
|
||||||
// the animation).
|
// the animation).
|
||||||
if (trackingTouch
|
if (trackingTouch
|
||||||
|| mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
|
|| mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()
|
||||||
|
|| mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
|
||||||
mKeyguardStateController.notifyKeyguardDismissAmountChanged(
|
mKeyguardStateController.notifyKeyguardDismissAmountChanged(
|
||||||
1f - expansion, trackingTouch);
|
1f - expansion, trackingTouch);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,13 @@ public interface KeyguardStateController extends CallbackController<Callback> {
|
|||||||
*/
|
*/
|
||||||
boolean canDismissLockScreen();
|
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.
|
* If the device has PIN/pattern/password or a lock screen at all.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
|
|||||||
import com.android.keyguard.KeyguardUpdateMonitorCallback;
|
import com.android.keyguard.KeyguardUpdateMonitorCallback;
|
||||||
import com.android.systemui.Dumpable;
|
import com.android.systemui.Dumpable;
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
|
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@@ -53,6 +54,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
|
|||||||
private final LockPatternUtils mLockPatternUtils;
|
private final LockPatternUtils mLockPatternUtils;
|
||||||
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
|
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
|
||||||
new UpdateMonitorCallback();
|
new UpdateMonitorCallback();
|
||||||
|
private final SmartspaceTransitionController mSmartspaceTransitionController;
|
||||||
|
|
||||||
private boolean mCanDismissLockScreen;
|
private boolean mCanDismissLockScreen;
|
||||||
private boolean mShowing;
|
private boolean mShowing;
|
||||||
@@ -96,10 +98,12 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
|
|||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public KeyguardStateControllerImpl(Context context,
|
public KeyguardStateControllerImpl(Context context,
|
||||||
KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils) {
|
KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils,
|
||||||
|
SmartspaceTransitionController smartspaceTransitionController) {
|
||||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||||
mLockPatternUtils = lockPatternUtils;
|
mLockPatternUtils = lockPatternUtils;
|
||||||
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
|
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
|
||||||
|
mSmartspaceTransitionController = smartspaceTransitionController;
|
||||||
|
|
||||||
update(true /* updateAlways */);
|
update(true /* updateAlways */);
|
||||||
if (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB) {
|
if (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB) {
|
||||||
@@ -158,6 +162,11 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
|
|||||||
mShowing = showing;
|
mShowing = showing;
|
||||||
mOccluded = occluded;
|
mOccluded = occluded;
|
||||||
notifyKeyguardChanged();
|
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() {
|
private void notifyKeyguardChanged() {
|
||||||
@@ -227,6 +236,12 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
|
|||||||
return mCanDismissLockScreen;
|
return mCanDismissLockScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPerformSmartSpaceTransition() {
|
||||||
|
return canDismissLockScreen()
|
||||||
|
&& mSmartspaceTransitionController.isSmartspaceTransitionPossible();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFaceAuthEnabled() {
|
public boolean isFaceAuthEnabled() {
|
||||||
return mFaceAuthEnabled;
|
return mFaceAuthEnabled;
|
||||||
|
|||||||
@@ -40,8 +40,10 @@ import com.android.systemui.R;
|
|||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||||
|
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||||
import com.android.systemui.plugins.ClockPlugin;
|
import com.android.systemui.plugins.ClockPlugin;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
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.StatusBarState;
|
||||||
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
|
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
|
||||||
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
||||||
@@ -86,6 +88,9 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
Resources mResources;
|
Resources mResources;
|
||||||
|
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||||
|
@Mock
|
||||||
|
SmartspaceTransitionController mSmartSpaceTransitionController;
|
||||||
@Mock
|
@Mock
|
||||||
private ClockPlugin mClockPlugin;
|
private ClockPlugin mClockPlugin;
|
||||||
@Mock
|
@Mock
|
||||||
@@ -135,7 +140,10 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
|||||||
mBatteryController,
|
mBatteryController,
|
||||||
mKeyguardUpdateMonitor,
|
mKeyguardUpdateMonitor,
|
||||||
mBypassController,
|
mBypassController,
|
||||||
mSmartspaceController);
|
mSmartspaceController,
|
||||||
|
mKeyguardUnlockAnimationController,
|
||||||
|
mSmartSpaceTransitionController
|
||||||
|
);
|
||||||
|
|
||||||
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
|
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
|
||||||
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
|
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import android.test.suitebuilder.annotation.SmallTest;
|
|||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
|
|
||||||
import com.android.systemui.SysuiTestCase;
|
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.phone.DozeParameters;
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
@@ -50,6 +52,10 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
|
|||||||
ConfigurationController mConfigurationController;
|
ConfigurationController mConfigurationController;
|
||||||
@Mock
|
@Mock
|
||||||
DozeParameters mDozeParameters;
|
DozeParameters mDozeParameters;
|
||||||
|
@Mock
|
||||||
|
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||||
|
@Mock
|
||||||
|
SmartspaceTransitionController mSmartSpaceTransitionController;
|
||||||
|
|
||||||
private KeyguardStatusViewController mController;
|
private KeyguardStatusViewController mController;
|
||||||
|
|
||||||
@@ -64,7 +70,9 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
|
|||||||
mKeyguardStateController,
|
mKeyguardStateController,
|
||||||
mKeyguardUpdateMonitor,
|
mKeyguardUpdateMonitor,
|
||||||
mConfigurationController,
|
mConfigurationController,
|
||||||
mDozeParameters);
|
mDozeParameters,
|
||||||
|
mKeyguardUnlockAnimationController,
|
||||||
|
mSmartSpaceTransitionController);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest;
|
|||||||
import com.android.internal.widget.LockPatternUtils;
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -49,12 +50,14 @@ public class KeyguardStateControllerTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
private LockPatternUtils mLockPatternUtils;
|
private LockPatternUtils mLockPatternUtils;
|
||||||
private KeyguardStateController mKeyguardStateController;
|
private KeyguardStateController mKeyguardStateController;
|
||||||
|
@Mock
|
||||||
|
private SmartspaceTransitionController mSmartSpaceTransitionController;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mKeyguardStateController = new KeyguardStateControllerImpl(mContext,
|
mKeyguardStateController = new KeyguardStateControllerImpl(mContext,
|
||||||
mKeyguardUpdateMonitor, mLockPatternUtils);
|
mKeyguardUpdateMonitor, mLockPatternUtils, mSmartSpaceTransitionController);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -127,4 +127,9 @@ public class FakeKeyguardStateController implements KeyguardStateController {
|
|||||||
public void notifyPanelFlingEnd() {
|
public void notifyPanelFlingEnd() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPerformSmartSpaceTransition() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user