Add predictive back animation to Bouncer.
Bug: 238475429 Test: atest KeyguardSecurityContainerControllerTest Test: atest KeyguardSecurityContainerTest Test: atest StatusBarKeyguardViewManagerTest Test: Enable flags and swipe back on Bouncer. Change up security mode and make sure animation looks nice in all modes. Change-Id: Iaf0c265076bc4a917d9826beee74b9c3a635ef33
This commit is contained in:
@@ -29,6 +29,9 @@ import android.view.View;
|
|||||||
import android.view.View.OnKeyListener;
|
import android.view.View.OnKeyListener;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
import android.window.OnBackAnimationCallback;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
|
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
|
||||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||||
@@ -393,6 +396,14 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public OnBackAnimationCallback getBackCallback() {
|
||||||
|
return mKeyguardSecurityContainerController.getBackCallback();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows the media keys to work when the keyguard is showing.
|
* Allows the media keys to work when the keyguard is showing.
|
||||||
* The media keys should be of no interest to the actual keyguard view(s),
|
* The media keys should be of no interest to the actual keyguard view(s),
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import static androidx.constraintlayout.widget.ConstraintSet.START;
|
|||||||
import static androidx.constraintlayout.widget.ConstraintSet.TOP;
|
import static androidx.constraintlayout.widget.ConstraintSet.TOP;
|
||||||
import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
|
import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
|
||||||
|
|
||||||
|
import static com.android.systemui.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
|
||||||
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
|
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
|
||||||
|
|
||||||
import static java.lang.Integer.max;
|
import static java.lang.Integer.max;
|
||||||
@@ -73,6 +74,8 @@ import android.view.WindowManager;
|
|||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.window.BackEvent;
|
||||||
|
import android.window.OnBackAnimationCallback;
|
||||||
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -135,7 +138,9 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
|
|||||||
private static final float MIN_DRAG_SIZE = 10;
|
private static final float MIN_DRAG_SIZE = 10;
|
||||||
// How much to scale the default slop by, to avoid accidental drags.
|
// How much to scale the default slop by, to avoid accidental drags.
|
||||||
private static final float SLOP_SCALE = 4f;
|
private static final float SLOP_SCALE = 4f;
|
||||||
|
@VisibleForTesting
|
||||||
|
// How much the view scales down to during back gestures.
|
||||||
|
static final float MIN_BACK_SCALE = 0.9f;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
KeyguardSecurityViewFlipper mSecurityViewFlipper;
|
KeyguardSecurityViewFlipper mSecurityViewFlipper;
|
||||||
private GlobalSettings mGlobalSettings;
|
private GlobalSettings mGlobalSettings;
|
||||||
@@ -240,6 +245,33 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private final OnBackAnimationCallback mBackCallback = new OnBackAnimationCallback() {
|
||||||
|
@Override
|
||||||
|
public void onBackCancelled() {
|
||||||
|
// TODO(b/259608500): Remove once back API auto animates progress to 0 on cancel.
|
||||||
|
resetScale();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackInvoked() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackProgressed(BackEvent event) {
|
||||||
|
float progress = event.getProgress();
|
||||||
|
// TODO(b/263819310): Update the interpolator to match spec.
|
||||||
|
float scale = MIN_BACK_SCALE
|
||||||
|
+ (1 - MIN_BACK_SCALE) * (1 - DECELERATE_QUINT.getInterpolation(progress));
|
||||||
|
setScale(scale);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
OnBackAnimationCallback getBackCallback() {
|
||||||
|
return mBackCallback;
|
||||||
|
}
|
||||||
|
|
||||||
// Used to notify the container when something interesting happens.
|
// Used to notify the container when something interesting happens.
|
||||||
public interface SecurityCallback {
|
public interface SecurityCallback {
|
||||||
/**
|
/**
|
||||||
@@ -736,6 +768,15 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
|
|||||||
mViewMode.onDensityOrFontScaleChanged();
|
mViewMode.onDensityOrFontScaleChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetScale() {
|
||||||
|
setScale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setScale(float scale) {
|
||||||
|
setScaleX(scale);
|
||||||
|
setScaleY(scale);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enscapsulates the differences between bouncer modes for the container.
|
* Enscapsulates the differences between bouncer modes for the container.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ import android.util.Log;
|
|||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.window.OnBackAnimationCallback;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -479,6 +481,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
|||||||
/** Called when the bouncer changes visibility. */
|
/** Called when the bouncer changes visibility. */
|
||||||
public void onBouncerVisibilityChanged(@View.Visibility int visibility) {
|
public void onBouncerVisibilityChanged(@View.Visibility int visibility) {
|
||||||
setBouncerVisible(visibility == View.VISIBLE);
|
setBouncerVisible(visibility == View.VISIBLE);
|
||||||
|
if (visibility == View.INVISIBLE) {
|
||||||
|
mView.resetScale();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setBouncerVisible(boolean visible) {
|
private void setBouncerVisible(boolean visible) {
|
||||||
@@ -587,6 +592,14 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
|||||||
return getCurrentSecurityController().needsInput();
|
return getCurrentSecurityController().needsInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
OnBackAnimationCallback getBackCallback() {
|
||||||
|
return mView.getBackCallback();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switches to the given security view unless it's already being shown, in which case
|
* Switches to the given security view unless it's already being shown, in which case
|
||||||
* this is a no-op.
|
* this is a no-op.
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.systemui.keyguard.data
|
package com.android.systemui.keyguard.data
|
||||||
|
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
|
import android.window.OnBackAnimationCallback
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.plugins.ActivityStarter
|
import com.android.systemui.plugins.ActivityStarter
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
@@ -51,4 +52,6 @@ interface BouncerViewDelegate {
|
|||||||
cancelAction: Runnable?,
|
cancelAction: Runnable?,
|
||||||
)
|
)
|
||||||
fun willDismissWithActions(): Boolean
|
fun willDismissWithActions(): Boolean
|
||||||
|
/** @return the {@link OnBackAnimationCallback} to animate Bouncer during a back gesture. */
|
||||||
|
fun getBackCallback(): OnBackAnimationCallback
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.binder
|
|||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.window.OnBackAnimationCallback
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import com.android.internal.policy.SystemBarUtils
|
import com.android.internal.policy.SystemBarUtils
|
||||||
@@ -55,6 +56,10 @@ object KeyguardBouncerViewBinder {
|
|||||||
mode == KeyguardSecurityModel.SecurityMode.SimPuk
|
mode == KeyguardSecurityModel.SecurityMode.SimPuk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getBackCallback(): OnBackAnimationCallback {
|
||||||
|
return hostViewController.backCallback
|
||||||
|
}
|
||||||
|
|
||||||
override fun shouldDismissOnMenuPressed(): Boolean {
|
override fun shouldDismissOnMenuPressed(): Boolean {
|
||||||
return hostViewController.shouldEnableMenuKey()
|
return hostViewController.shouldEnableMenuKey()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -279,7 +279,6 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
|
|||||||
@Override
|
@Override
|
||||||
public void triggerBack() {
|
public void triggerBack() {
|
||||||
// Notify FalsingManager that an intentional gesture has occurred.
|
// Notify FalsingManager that an intentional gesture has occurred.
|
||||||
// TODO(b/186519446): use a different method than isFalseTouch
|
|
||||||
mFalsingManager.isFalseTouch(BACK_GESTURE);
|
mFalsingManager.isFalseTouch(BACK_GESTURE);
|
||||||
// Only inject back keycodes when ahead-of-time back dispatching is disabled.
|
// Only inject back keycodes when ahead-of-time back dispatching is disabled.
|
||||||
if (mBackAnimation == null) {
|
if (mBackAnimation == null) {
|
||||||
@@ -955,6 +954,10 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
|
|||||||
mThresholdCrossed = true;
|
mThresholdCrossed = true;
|
||||||
// Capture inputs
|
// Capture inputs
|
||||||
mInputMonitor.pilferPointers();
|
mInputMonitor.pilferPointers();
|
||||||
|
if (mBackAnimation != null) {
|
||||||
|
// Notify FalsingManager that an intentional gesture has occurred.
|
||||||
|
mFalsingManager.isFalseTouch(BACK_GESTURE);
|
||||||
|
}
|
||||||
mInputEventReceiver.setBatchingEnabled(true);
|
mInputEventReceiver.setBatchingEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_FAR_FROM_EDGE);
|
logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_FAR_FROM_EDGE);
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewRootImpl;
|
import android.view.ViewRootImpl;
|
||||||
import android.view.WindowManagerGlobal;
|
import android.view.WindowManagerGlobal;
|
||||||
import android.window.OnBackInvokedCallback;
|
import android.window.BackEvent;
|
||||||
|
import android.window.OnBackAnimationCallback;
|
||||||
import android.window.OnBackInvokedDispatcher;
|
import android.window.OnBackInvokedDispatcher;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -198,11 +199,38 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
|
private final OnBackAnimationCallback mOnBackInvokedCallback = new OnBackAnimationCallback() {
|
||||||
if (DEBUG) {
|
@Override
|
||||||
Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()");
|
public void onBackInvoked() {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()");
|
||||||
|
}
|
||||||
|
onBackPressed();
|
||||||
|
if (shouldPlayBackAnimation()) {
|
||||||
|
mPrimaryBouncerView.getDelegate().getBackCallback().onBackInvoked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackProgressed(BackEvent event) {
|
||||||
|
if (shouldPlayBackAnimation()) {
|
||||||
|
mPrimaryBouncerView.getDelegate().getBackCallback().onBackProgressed(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackCancelled() {
|
||||||
|
if (shouldPlayBackAnimation()) {
|
||||||
|
mPrimaryBouncerView.getDelegate().getBackCallback().onBackCancelled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackStarted(BackEvent event) {
|
||||||
|
if (shouldPlayBackAnimation()) {
|
||||||
|
mPrimaryBouncerView.getDelegate().getBackCallback().onBackStarted(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onBackPressed();
|
|
||||||
};
|
};
|
||||||
private boolean mIsBackCallbackRegistered = false;
|
private boolean mIsBackCallbackRegistered = false;
|
||||||
|
|
||||||
@@ -256,6 +284,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
private boolean mIsModernBouncerEnabled;
|
private boolean mIsModernBouncerEnabled;
|
||||||
private boolean mIsModernAlternateBouncerEnabled;
|
private boolean mIsModernAlternateBouncerEnabled;
|
||||||
private boolean mIsUnoccludeTransitionFlagEnabled;
|
private boolean mIsUnoccludeTransitionFlagEnabled;
|
||||||
|
private boolean mIsBackAnimationEnabled;
|
||||||
|
|
||||||
private OnDismissAction mAfterKeyguardGoneAction;
|
private OnDismissAction mAfterKeyguardGoneAction;
|
||||||
private Runnable mKeyguardGoneCancelAction;
|
private Runnable mKeyguardGoneCancelAction;
|
||||||
@@ -337,6 +366,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER);
|
mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER);
|
||||||
mAlternateBouncerInteractor = alternateBouncerInteractor;
|
mAlternateBouncerInteractor = alternateBouncerInteractor;
|
||||||
mIsUnoccludeTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
|
mIsUnoccludeTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
|
||||||
|
mIsBackAnimationEnabled =
|
||||||
|
featureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -472,6 +503,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean shouldPlayBackAnimation() {
|
||||||
|
// Suppress back animation when bouncer shouldn't be dismissed on back invocation.
|
||||||
|
return !needsFullscreenBouncer() && mIsBackAnimationEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDensityOrFontScaleChanged() {
|
public void onDensityOrFontScaleChanged() {
|
||||||
hideBouncer(true /* destroyView */);
|
hideBouncer(true /* destroyView */);
|
||||||
|
|||||||
@@ -404,6 +404,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
|||||||
verify(mSideFpsController, never()).show(any());
|
verify(mSideFpsController, never()).show(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBouncerVisibilityChanged_resetsScale() {
|
||||||
|
mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.INVISIBLE);
|
||||||
|
|
||||||
|
verify(mView).resetScale();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onStartingToHide_sideFpsHintShown_sideFpsHintHidden() {
|
public void onStartingToHide_sideFpsHintShown_sideFpsHintHidden() {
|
||||||
setupGetSecurityView();
|
setupGetSecurityView();
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ import android.view.MotionEvent;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
|
import android.window.BackEvent;
|
||||||
|
import android.window.OnBackAnimationCallback;
|
||||||
|
|
||||||
import androidx.constraintlayout.widget.ConstraintSet;
|
import androidx.constraintlayout.widget.ConstraintSet;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
@@ -357,6 +359,27 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(PARENT_ID);
|
assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(PARENT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPlayBackAnimation() {
|
||||||
|
OnBackAnimationCallback backCallback = mKeyguardSecurityContainer.getBackCallback();
|
||||||
|
backCallback.onBackStarted(createBackEvent(0, 0));
|
||||||
|
mKeyguardSecurityContainer.getBackCallback().onBackProgressed(
|
||||||
|
createBackEvent(0, 1));
|
||||||
|
assertThat(mKeyguardSecurityContainer.getScaleX()).isEqualTo(
|
||||||
|
KeyguardSecurityContainer.MIN_BACK_SCALE);
|
||||||
|
assertThat(mKeyguardSecurityContainer.getScaleY()).isEqualTo(
|
||||||
|
KeyguardSecurityContainer.MIN_BACK_SCALE);
|
||||||
|
|
||||||
|
// reset scale
|
||||||
|
mKeyguardSecurityContainer.resetScale();
|
||||||
|
assertThat(mKeyguardSecurityContainer.getScaleX()).isEqualTo(1);
|
||||||
|
assertThat(mKeyguardSecurityContainer.getScaleY()).isEqualTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BackEvent createBackEvent(float touchX, float progress) {
|
||||||
|
return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
private Configuration configuration(@Configuration.Orientation int orientation) {
|
private Configuration configuration(@Configuration.Orientation int orientation) {
|
||||||
Configuration config = new Configuration();
|
Configuration config = new Configuration();
|
||||||
config.orientation = orientation;
|
config.orientation = orientation;
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ import android.testing.TestableLooper;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewRootImpl;
|
import android.view.ViewRootImpl;
|
||||||
|
import android.window.BackEvent;
|
||||||
|
import android.window.OnBackAnimationCallback;
|
||||||
import android.window.OnBackInvokedCallback;
|
import android.window.OnBackInvokedCallback;
|
||||||
import android.window.OnBackInvokedDispatcher;
|
import android.window.OnBackInvokedDispatcher;
|
||||||
import android.window.WindowOnBackInvokedDispatcher;
|
import android.window.WindowOnBackInvokedDispatcher;
|
||||||
@@ -54,6 +56,7 @@ import com.android.systemui.SysuiTestCase;
|
|||||||
import com.android.systemui.dock.DockManager;
|
import com.android.systemui.dock.DockManager;
|
||||||
import com.android.systemui.dreams.DreamOverlayStateController;
|
import com.android.systemui.dreams.DreamOverlayStateController;
|
||||||
import com.android.systemui.flags.FeatureFlags;
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
|
import com.android.systemui.flags.Flags;
|
||||||
import com.android.systemui.keyguard.data.BouncerView;
|
import com.android.systemui.keyguard.data.BouncerView;
|
||||||
import com.android.systemui.keyguard.data.BouncerViewDelegate;
|
import com.android.systemui.keyguard.data.BouncerViewDelegate;
|
||||||
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
|
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
|
||||||
@@ -118,16 +121,19 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
|||||||
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
|
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
|
||||||
@Mock private BouncerView mBouncerView;
|
@Mock private BouncerView mBouncerView;
|
||||||
@Mock private BouncerViewDelegate mBouncerViewDelegate;
|
@Mock private BouncerViewDelegate mBouncerViewDelegate;
|
||||||
|
@Mock private OnBackAnimationCallback mBouncerViewDelegateBackCallback;
|
||||||
|
|
||||||
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
||||||
private KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
|
private KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
|
||||||
private FakeKeyguardStateController mKeyguardStateController =
|
private FakeKeyguardStateController mKeyguardStateController =
|
||||||
spy(new FakeKeyguardStateController());
|
spy(new FakeKeyguardStateController());
|
||||||
|
|
||||||
@Mock private ViewRootImpl mViewRootImpl;
|
@Mock
|
||||||
@Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
|
private ViewRootImpl mViewRootImpl;
|
||||||
|
@Mock
|
||||||
|
private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
|
||||||
@Captor
|
@Captor
|
||||||
private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
|
private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -138,6 +144,10 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
|||||||
when(mKeyguardMessageAreaFactory.create(any(KeyguardMessageArea.class)))
|
when(mKeyguardMessageAreaFactory.create(any(KeyguardMessageArea.class)))
|
||||||
.thenReturn(mKeyguardMessageAreaController);
|
.thenReturn(mKeyguardMessageAreaController);
|
||||||
when(mBouncerView.getDelegate()).thenReturn(mBouncerViewDelegate);
|
when(mBouncerView.getDelegate()).thenReturn(mBouncerViewDelegate);
|
||||||
|
when(mBouncerViewDelegate.getBackCallback()).thenReturn(mBouncerViewDelegateBackCallback);
|
||||||
|
when(mFeatureFlags
|
||||||
|
.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM))
|
||||||
|
.thenReturn(true);
|
||||||
|
|
||||||
when(mFeatureFlags.isEnabled(MODERN_BOUNCER)).thenReturn(true);
|
when(mFeatureFlags.isEnabled(MODERN_BOUNCER)).thenReturn(true);
|
||||||
|
|
||||||
@@ -191,7 +201,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void dismissWithAction_AfterKeyguardGoneSetToFalse() {
|
public void dismissWithAction_AfterKeyguardGoneSetToFalse() {
|
||||||
OnDismissAction action = () -> false;
|
OnDismissAction action = () -> false;
|
||||||
Runnable cancelAction = () -> {};
|
Runnable cancelAction = () -> {
|
||||||
|
};
|
||||||
mStatusBarKeyguardViewManager.dismissWithAction(
|
mStatusBarKeyguardViewManager.dismissWithAction(
|
||||||
action, cancelAction, false /* afterKeyguardGone */);
|
action, cancelAction, false /* afterKeyguardGone */);
|
||||||
verify(mPrimaryBouncerInteractor).setDismissAction(eq(action), eq(cancelAction));
|
verify(mPrimaryBouncerInteractor).setDismissAction(eq(action), eq(cancelAction));
|
||||||
@@ -539,12 +550,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
|||||||
mBouncerExpansionCallback.onVisibilityChanged(true);
|
mBouncerExpansionCallback.onVisibilityChanged(true);
|
||||||
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
|
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
|
||||||
eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
|
eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
|
||||||
mOnBackInvokedCallback.capture());
|
mBackCallbackCaptor.capture());
|
||||||
|
|
||||||
/* verify that the same callback is unregistered when the bouncer becomes invisible */
|
/* verify that the same callback is unregistered when the bouncer becomes invisible */
|
||||||
mBouncerExpansionCallback.onVisibilityChanged(false);
|
mBouncerExpansionCallback.onVisibilityChanged(false);
|
||||||
verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
|
verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
|
||||||
eq(mOnBackInvokedCallback.getValue()));
|
eq(mBackCallbackCaptor.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -553,17 +564,62 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
|||||||
/* capture the predictive back callback during registration */
|
/* capture the predictive back callback during registration */
|
||||||
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
|
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
|
||||||
eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
|
eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
|
||||||
mOnBackInvokedCallback.capture());
|
mBackCallbackCaptor.capture());
|
||||||
|
|
||||||
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
|
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
|
||||||
when(mCentralSurfaces.shouldKeyguardHideImmediately()).thenReturn(true);
|
when(mCentralSurfaces.shouldKeyguardHideImmediately()).thenReturn(true);
|
||||||
/* invoke the back callback directly */
|
/* invoke the back callback directly */
|
||||||
mOnBackInvokedCallback.getValue().onBackInvoked();
|
mBackCallbackCaptor.getValue().onBackInvoked();
|
||||||
|
|
||||||
/* verify that the bouncer will be hidden as a result of the invocation */
|
/* verify that the bouncer will be hidden as a result of the invocation */
|
||||||
verify(mCentralSurfaces).setBouncerShowing(eq(false));
|
verify(mCentralSurfaces).setBouncerShowing(eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPredictiveBackCallback_noBackAnimationForFullScreenBouncer() {
|
||||||
|
when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
|
||||||
|
.thenReturn(KeyguardSecurityModel.SecurityMode.SimPin);
|
||||||
|
mBouncerExpansionCallback.onVisibilityChanged(true);
|
||||||
|
/* capture the predictive back callback during registration */
|
||||||
|
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
|
||||||
|
eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
|
||||||
|
mBackCallbackCaptor.capture());
|
||||||
|
assertTrue(mBackCallbackCaptor.getValue() instanceof OnBackAnimationCallback);
|
||||||
|
|
||||||
|
OnBackAnimationCallback backCallback =
|
||||||
|
(OnBackAnimationCallback) mBackCallbackCaptor.getValue();
|
||||||
|
|
||||||
|
BackEvent event = new BackEvent(0, 0, 0, BackEvent.EDGE_LEFT);
|
||||||
|
backCallback.onBackStarted(event);
|
||||||
|
verify(mBouncerViewDelegateBackCallback, never()).onBackStarted(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPredictiveBackCallback_forwardsBackDispatches() {
|
||||||
|
mBouncerExpansionCallback.onVisibilityChanged(true);
|
||||||
|
/* capture the predictive back callback during registration */
|
||||||
|
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
|
||||||
|
eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
|
||||||
|
mBackCallbackCaptor.capture());
|
||||||
|
assertTrue(mBackCallbackCaptor.getValue() instanceof OnBackAnimationCallback);
|
||||||
|
|
||||||
|
OnBackAnimationCallback backCallback =
|
||||||
|
(OnBackAnimationCallback) mBackCallbackCaptor.getValue();
|
||||||
|
|
||||||
|
BackEvent event = new BackEvent(0, 0, 0, BackEvent.EDGE_LEFT);
|
||||||
|
backCallback.onBackStarted(event);
|
||||||
|
verify(mBouncerViewDelegateBackCallback).onBackStarted(eq(event));
|
||||||
|
|
||||||
|
backCallback.onBackProgressed(event);
|
||||||
|
verify(mBouncerViewDelegateBackCallback).onBackProgressed(eq(event));
|
||||||
|
|
||||||
|
backCallback.onBackInvoked();
|
||||||
|
verify(mBouncerViewDelegateBackCallback).onBackInvoked();
|
||||||
|
|
||||||
|
backCallback.onBackCancelled();
|
||||||
|
verify(mBouncerViewDelegateBackCallback).onBackCancelled();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReportBouncerOnDreamWhenVisible() {
|
public void testReportBouncerOnDreamWhenVisible() {
|
||||||
mBouncerExpansionCallback.onVisibilityChanged(true);
|
mBouncerExpansionCallback.onVisibilityChanged(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user