Merge "Migrate StatusBarKeyguardViewManager to Predictive Back" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
fd0c9bfa3b
@@ -416,6 +416,9 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn
|
|||||||
|
|
||||||
void endAffordanceLaunch();
|
void endAffordanceLaunch();
|
||||||
|
|
||||||
|
/** Should the keyguard be hidden immediately in response to a back press/gesture. */
|
||||||
|
boolean shouldKeyguardHideImmediately();
|
||||||
|
|
||||||
boolean onBackPressed();
|
boolean onBackPressed();
|
||||||
|
|
||||||
boolean onSpacePressed();
|
boolean onSpacePressed();
|
||||||
|
|||||||
@@ -3312,19 +3312,23 @@ public class CentralSurfacesImpl extends CoreStartable implements
|
|||||||
mNotificationPanelViewController.onAffordanceLaunchEnded();
|
mNotificationPanelViewController.onAffordanceLaunchEnded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the keyguard should hide immediately (as opposed to via an animation).
|
||||||
|
* Non-scrimmed bouncers have a special animation tied to the notification panel expansion.
|
||||||
|
* @return whether the keyguard should be immediately hidden.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onBackPressed() {
|
public boolean shouldKeyguardHideImmediately() {
|
||||||
final boolean isScrimmedBouncer =
|
final boolean isScrimmedBouncer =
|
||||||
mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
|
mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
|
||||||
final boolean isBouncerOverDream = isBouncerShowingOverDream();
|
final boolean isBouncerOverDream = isBouncerShowingOverDream();
|
||||||
|
return (isScrimmedBouncer || isBouncerOverDream);
|
||||||
if (mStatusBarKeyguardViewManager.onBackPressed(
|
|
||||||
isScrimmedBouncer || isBouncerOverDream /* hideImmediately */)) {
|
|
||||||
if (isScrimmedBouncer || isBouncerOverDream) {
|
|
||||||
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
|
|
||||||
} else {
|
|
||||||
mNotificationPanelViewController.expandWithoutQs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onBackPressed() {
|
||||||
|
if (mStatusBarKeyguardViewManager.canHandleBackPressed()) {
|
||||||
|
mStatusBarKeyguardViewManager.onBackPressed(false /* unused */);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (mNotificationPanelViewController.isQsCustomizing()) {
|
if (mNotificationPanelViewController.isQsCustomizing()) {
|
||||||
@@ -3339,7 +3343,7 @@ public class CentralSurfacesImpl extends CoreStartable implements
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED
|
if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED
|
||||||
&& !isBouncerOverDream) {
|
&& !isBouncerShowingOverDream()) {
|
||||||
if (mNotificationPanelViewController.canPanelBeCollapsed()) {
|
if (mNotificationPanelViewController.canPanelBeCollapsed()) {
|
||||||
mShadeController.animateCollapsePanels();
|
mShadeController.animateCollapsePanels();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,12 +31,15 @@ import android.hardware.biometrics.BiometricSourceType;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.Trace;
|
import android.os.Trace;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
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.view.WindowManagerGlobal;
|
import android.view.WindowManagerGlobal;
|
||||||
|
import android.window.OnBackInvokedCallback;
|
||||||
|
import android.window.OnBackInvokedDispatcher;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -119,6 +122,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
|
private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
|
||||||
|
|
||||||
private static String TAG = "StatusBarKeyguardViewManager";
|
private static String TAG = "StatusBarKeyguardViewManager";
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
protected final Context mContext;
|
protected final Context mContext;
|
||||||
private final ConfigurationController mConfigurationController;
|
private final ConfigurationController mConfigurationController;
|
||||||
@@ -184,8 +188,25 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
if (mAlternateAuthInterceptor != null) {
|
if (mAlternateAuthInterceptor != null) {
|
||||||
mAlternateAuthInterceptor.onBouncerVisibilityChanged();
|
mAlternateAuthInterceptor.onBouncerVisibilityChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Register predictive back callback when keyguard becomes visible, and unregister
|
||||||
|
when it's hidden. */
|
||||||
|
if (isVisible) {
|
||||||
|
registerBackCallback();
|
||||||
|
} else {
|
||||||
|
unregisterBackCallback();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()");
|
||||||
|
}
|
||||||
|
onBackPressed(false /* unused */);
|
||||||
|
};
|
||||||
|
private boolean mIsBackCallbackRegistered = false;
|
||||||
|
|
||||||
private final DockManager.DockEventListener mDockEventListener =
|
private final DockManager.DockEventListener mDockEventListener =
|
||||||
new DockManager.DockEventListener() {
|
new DockManager.DockEventListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -378,6 +399,46 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Register a callback, to be invoked by the Predictive Back system. */
|
||||||
|
private void registerBackCallback() {
|
||||||
|
if (!mIsBackCallbackRegistered) {
|
||||||
|
ViewRootImpl viewRoot = getViewRootImpl();
|
||||||
|
if (viewRoot != null) {
|
||||||
|
viewRoot.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
|
||||||
|
OnBackInvokedDispatcher.PRIORITY_OVERLAY, mOnBackInvokedCallback);
|
||||||
|
mIsBackCallbackRegistered = true;
|
||||||
|
} else {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "view root was null, could not register back callback");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "prevented registering back callback twice");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Unregister the callback formerly registered with the Predictive Back system. */
|
||||||
|
private void unregisterBackCallback() {
|
||||||
|
if (mIsBackCallbackRegistered) {
|
||||||
|
ViewRootImpl viewRoot = getViewRootImpl();
|
||||||
|
if (viewRoot != null) {
|
||||||
|
viewRoot.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(
|
||||||
|
mOnBackInvokedCallback);
|
||||||
|
mIsBackCallbackRegistered = false;
|
||||||
|
} else {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "view root was null, could not unregister back callback");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "prevented unregistering back callback twice");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDensityOrFontScaleChanged() {
|
public void onDensityOrFontScaleChanged() {
|
||||||
hideBouncer(true /* destroyView */);
|
hideBouncer(true /* destroyView */);
|
||||||
@@ -1025,25 +1086,47 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies this manager that the back button has been pressed.
|
* Returns whether a back invocation can be handled, which depends on whether the keyguard
|
||||||
|
* is currently showing (which itself is derived from multiple states).
|
||||||
*
|
*
|
||||||
* @param hideImmediately Hide bouncer when {@code true}, keep it around otherwise.
|
* @return whether a back press can be handled right now.
|
||||||
* Non-scrimmed bouncers have a special animation tied to the expansion
|
|
||||||
* of the notification panel.
|
|
||||||
* @return whether the back press has been handled
|
|
||||||
*/
|
*/
|
||||||
public boolean onBackPressed(boolean hideImmediately) {
|
public boolean canHandleBackPressed() {
|
||||||
if (bouncerIsShowing()) {
|
return mBouncer.isShowing();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies this manager that the back button has been pressed.
|
||||||
|
*/
|
||||||
|
// TODO(b/244635782): This "accept boolean and ignore it, and always return false" was done
|
||||||
|
// to make it possible to check this in *and* allow merging to master,
|
||||||
|
// where ArcStatusBarKeyguardViewManager inherits this class, and its
|
||||||
|
// build will break if we change this interface.
|
||||||
|
// So, overall, while this function refactors the behavior of onBackPressed,
|
||||||
|
// (it now handles the back press, and no longer returns *whether* it did so)
|
||||||
|
// its interface is not changing right now (but will, in a follow-up CL).
|
||||||
|
public boolean onBackPressed(boolean ignored) {
|
||||||
|
if (!canHandleBackPressed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
mCentralSurfaces.endAffordanceLaunch();
|
mCentralSurfaces.endAffordanceLaunch();
|
||||||
// The second condition is for SIM card locked bouncer
|
// The second condition is for SIM card locked bouncer
|
||||||
if (bouncerIsScrimmed()
|
if (bouncerIsScrimmed() && needsFullscreenBouncer()) {
|
||||||
&& !needsFullscreenBouncer()) {
|
|
||||||
hideBouncer(false);
|
hideBouncer(false);
|
||||||
updateStates();
|
updateStates();
|
||||||
} else {
|
} else {
|
||||||
|
/* Non-scrimmed bouncers have a special animation tied to the expansion
|
||||||
|
* of the notification panel. We decide whether to kick this animation off
|
||||||
|
* by computing the hideImmediately boolean.
|
||||||
|
*/
|
||||||
|
boolean hideImmediately = mCentralSurfaces.shouldKeyguardHideImmediately();
|
||||||
reset(hideImmediately);
|
reset(hideImmediately);
|
||||||
|
if (hideImmediately) {
|
||||||
|
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
|
||||||
|
} else {
|
||||||
|
mNotificationPanelViewController.expandWithoutQs();
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1318,7 +1401,15 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ViewRootImpl getViewRootImpl() {
|
public ViewRootImpl getViewRootImpl() {
|
||||||
return mNotificationShadeWindowController.getNotificationShadeView().getViewRootImpl();
|
ViewGroup viewGroup = mNotificationShadeWindowController.getNotificationShadeView();
|
||||||
|
if (viewGroup != null) {
|
||||||
|
return viewGroup.getViewRootImpl();
|
||||||
|
} else {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "ViewGroup was null, cannot get ViewRootImpl");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void launchPendingWakeupAction() {
|
public void launchPendingWakeupAction() {
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ import android.testing.AndroidTestingRunner;
|
|||||||
import android.testing.TestableLooper;
|
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.window.OnBackInvokedCallback;
|
||||||
|
import android.window.OnBackInvokedDispatcher;
|
||||||
|
import android.window.WindowOnBackInvokedDispatcher;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
@@ -73,6 +77,7 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
@@ -119,6 +124,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
|||||||
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
||||||
private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback;
|
private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback;
|
||||||
|
|
||||||
|
@Mock private ViewRootImpl mViewRootImpl;
|
||||||
|
@Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
@@ -154,7 +165,14 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
|||||||
mFeatureFlags,
|
mFeatureFlags,
|
||||||
mBouncerCallbackInteractor,
|
mBouncerCallbackInteractor,
|
||||||
mBouncerInteractor,
|
mBouncerInteractor,
|
||||||
mBouncerView);
|
mBouncerView) {
|
||||||
|
@Override
|
||||||
|
public ViewRootImpl getViewRootImpl() {
|
||||||
|
return mViewRootImpl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
when(mViewRootImpl.getOnBackInvokedDispatcher())
|
||||||
|
.thenReturn(mOnBackInvokedDispatcher);
|
||||||
mStatusBarKeyguardViewManager.registerCentralSurfaces(
|
mStatusBarKeyguardViewManager.registerCentralSurfaces(
|
||||||
mCentralSurfaces,
|
mCentralSurfaces,
|
||||||
mNotificationPanelView,
|
mNotificationPanelView,
|
||||||
@@ -508,6 +526,37 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
|||||||
fraction, expanded, tracking, /* dragDownPxAmount= */ 0f);
|
fraction, expanded, tracking, /* dragDownPxAmount= */ 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPredictiveBackCallback_registration() {
|
||||||
|
/* verify that a predictive back callback is registered when the bouncer becomes visible */
|
||||||
|
mBouncerExpansionCallback.onVisibilityChanged(true);
|
||||||
|
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
|
||||||
|
eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
|
||||||
|
mOnBackInvokedCallback.capture());
|
||||||
|
|
||||||
|
/* verify that the same callback is unregistered when the bouncer becomes invisible */
|
||||||
|
mBouncerExpansionCallback.onVisibilityChanged(false);
|
||||||
|
verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
|
||||||
|
eq(mOnBackInvokedCallback.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPredictiveBackCallback_invocationHidesBouncer() {
|
||||||
|
mBouncerExpansionCallback.onVisibilityChanged(true);
|
||||||
|
/* capture the predictive back callback during registration */
|
||||||
|
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
|
||||||
|
eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
|
||||||
|
mOnBackInvokedCallback.capture());
|
||||||
|
|
||||||
|
when(mBouncer.isShowing()).thenReturn(true);
|
||||||
|
when(mCentralSurfaces.shouldKeyguardHideImmediately()).thenReturn(true);
|
||||||
|
/* invoke the back callback directly */
|
||||||
|
mOnBackInvokedCallback.getValue().onBackInvoked();
|
||||||
|
|
||||||
|
/* verify that the bouncer will be hidden as a result of the invocation */
|
||||||
|
verify(mCentralSurfaces).setBouncerShowing(eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReportBouncerOnDreamWhenVisible() {
|
public void testReportBouncerOnDreamWhenVisible() {
|
||||||
mBouncerExpansionCallback.onVisibilityChanged(true);
|
mBouncerExpansionCallback.onVisibilityChanged(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user