Merge "Migrate CentralSurfacesImpl to Predictive Back api" into tm-qpr-dev

This commit is contained in:
Rahul Banerjee
2022-09-14 16:48:03 +00:00
committed by Android (Google) Code Review
2 changed files with 120 additions and 4 deletions

View File

@@ -100,11 +100,14 @@ import android.view.MotionEvent;
import android.view.ThreadedRenderer; import android.view.ThreadedRenderer;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Appearance;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.WindowManagerGlobal; import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager;
import android.widget.DateTimeView; import android.widget.DateTimeView;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
@@ -526,10 +529,17 @@ public class CentralSurfacesImpl extends CoreStartable implements
private CentralSurfacesComponent mCentralSurfacesComponent; private CentralSurfacesComponent mCentralSurfacesComponent;
// Flags for disabling the status bar // Flags for disabling the status bar
// Two variables becaseu the first one evidently ran out of room for new flags. // Two variables because the first one evidently ran out of room for new flags.
private int mDisabled1 = 0; private int mDisabled1 = 0;
private int mDisabled2 = 0; private int mDisabled2 = 0;
/**
* This keeps track of whether we have (or haven't) registered the predictive back callback.
* Since we can have visible -> visible transitions, we need to avoid
* double-registering (or double-unregistering) our callback.
*/
private boolean mIsBackCallbackRegistered = false;
/** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */ /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
private @Appearance int mAppearance; private @Appearance int mAppearance;
@@ -653,6 +663,12 @@ public class CentralSurfacesImpl extends CoreStartable implements
private final InteractionJankMonitor mJankMonitor; private final InteractionJankMonitor mJankMonitor;
private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
if (DEBUG) {
Log.d(TAG, "mOnBackInvokedCallback() called");
}
onBackPressed();
};
/** /**
* Public constructor for CentralSurfaces. * Public constructor for CentralSurfaces.
@@ -2751,9 +2767,38 @@ public class CentralSurfacesImpl extends CoreStartable implements
if (visibleToUser) { if (visibleToUser) {
handleVisibleToUserChangedImpl(visibleToUser); handleVisibleToUserChangedImpl(visibleToUser);
mNotificationLogger.startNotificationLogging(); mNotificationLogger.startNotificationLogging();
if (!mIsBackCallbackRegistered) {
ViewRootImpl viewRootImpl = getViewRootImpl();
if (viewRootImpl != null) {
viewRootImpl.getOnBackInvokedDispatcher()
.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT,
mOnBackInvokedCallback);
mIsBackCallbackRegistered = true;
if (DEBUG) Log.d(TAG, "is now VISIBLE to user AND callback registered");
}
} else {
if (DEBUG) Log.d(TAG, "is now VISIBLE to user, BUT callback ALREADY unregistered");
}
} else { } else {
mNotificationLogger.stopNotificationLogging(); mNotificationLogger.stopNotificationLogging();
handleVisibleToUserChangedImpl(visibleToUser); handleVisibleToUserChangedImpl(visibleToUser);
if (mIsBackCallbackRegistered) {
ViewRootImpl viewRootImpl = getViewRootImpl();
if (viewRootImpl != null) {
viewRootImpl.getOnBackInvokedDispatcher()
.unregisterOnBackInvokedCallback(mOnBackInvokedCallback);
mIsBackCallbackRegistered = false;
if (DEBUG) Log.d(TAG, "is NOT VISIBLE to user, AND callback unregistered");
}
} else {
if (DEBUG) {
Log.d(TAG,
"is NOT VISIBLE to user, BUT NO callback (or callback ALREADY "
+ "unregistered)");
}
}
} }
} }
@@ -3464,6 +3509,12 @@ public class CentralSurfacesImpl extends CoreStartable implements
return mNotificationPanelViewController.getKeyguardBottomAreaView(); return mNotificationPanelViewController.getKeyguardBottomAreaView();
} }
protected ViewRootImpl getViewRootImpl() {
NotificationShadeWindowView nswv = getNotificationShadeWindowView();
if (nswv != null) return nswv.getViewRootImpl();
return null;
}
/** /**
* Propagation of the bouncer state, indicating that it's fully visible. * Propagation of the bouncer state, indicating that it's fully visible.
*/ */
@@ -3781,6 +3832,12 @@ public class CentralSurfacesImpl extends CoreStartable implements
updateScrimController(); updateScrimController();
} }
@VisibleForTesting
public void setNotificationShadeWindowViewController(
NotificationShadeWindowViewController nswvc) {
mNotificationShadeWindowViewController = nswvc;
}
/** /**
* Set the amount of progress we are currently in if we're transitioning to the full shade. * Set the amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full * 0.0f means we're not transitioning yet, while 1 means we're all the way in the full

View File

@@ -35,6 +35,7 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset; import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -69,7 +70,11 @@ import android.util.DisplayMetrics;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.LayoutParams;
import android.view.ViewRootImpl;
import android.view.WindowManager; import android.view.WindowManager;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import android.window.WindowOnBackInvokedDispatcher;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -168,6 +173,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.MockitoAnnotations; import org.mockito.MockitoAnnotations;
@@ -279,6 +285,15 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
@Mock private InteractionJankMonitor mJankMonitor; @Mock private InteractionJankMonitor mJankMonitor;
@Mock private DeviceStateManager mDeviceStateManager; @Mock private DeviceStateManager mDeviceStateManager;
@Mock private WiredChargingRippleController mWiredChargingRippleController; @Mock private WiredChargingRippleController mWiredChargingRippleController;
/**
* The process of registering/unregistering a predictive back callback requires a
* ViewRootImpl, which is present IRL, but may be missing during a Mockito unit test.
* To prevent an NPE during test execution, we explicitly craft and provide a fake ViewRootImpl.
*/
@Mock private ViewRootImpl mViewRootImpl;
@Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
@Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
private ShadeController mShadeController; private ShadeController mShadeController;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock); private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -368,10 +383,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
return null; return null;
}).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any()); }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
mShadeController = new ShadeControllerImpl(mCommandQueue, mShadeController = spy(new ShadeControllerImpl(mCommandQueue,
mStatusBarStateController, mNotificationShadeWindowController, mStatusBarStateController, mNotificationShadeWindowController,
mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class), mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class),
() -> Optional.of(mCentralSurfaces), () -> mAssistManager); () -> Optional.of(mCentralSurfaces), () -> mAssistManager));
when(mOperatorNameViewControllerFactory.create(any())) when(mOperatorNameViewControllerFactory.create(any()))
.thenReturn(mOperatorNameViewController); .thenReturn(mOperatorNameViewController);
@@ -460,7 +475,14 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mActivityLaunchAnimator, mActivityLaunchAnimator,
mJankMonitor, mJankMonitor,
mDeviceStateManager, mDeviceStateManager,
mWiredChargingRippleController, mDreamManager); mWiredChargingRippleController, mDreamManager) {
@Override
protected ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
}
};
when(mViewRootImpl.getOnBackInvokedDispatcher())
.thenReturn(mOnBackInvokedDispatcher);
when(mKeyguardViewMediator.registerCentralSurfaces( when(mKeyguardViewMediator.registerCentralSurfaces(
any(CentralSurfacesImpl.class), any(CentralSurfacesImpl.class),
any(NotificationPanelViewController.class), any(NotificationPanelViewController.class),
@@ -738,6 +760,43 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
} }
} }
/**
* Do the following:
* 1. verify that a predictive back callback is registered when CSurf becomes visible
* 2. verify that the same callback is unregistered when CSurf becomes invisible
*/
@Test
public void testPredictiveBackCallback_registration() {
mCentralSurfaces.handleVisibleToUserChanged(true);
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mOnBackInvokedCallback.capture());
mCentralSurfaces.handleVisibleToUserChanged(false);
verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
eq(mOnBackInvokedCallback.getValue()));
}
/**
* Do the following:
* 1. capture the predictive back callback during registration
* 2. call the callback directly
* 3. verify that the ShadeController's panel collapse animation is invoked
*/
@Test
public void testPredictiveBackCallback_invocationCollapsesPanel() {
mCentralSurfaces.setNotificationShadeWindowViewController(
mNotificationShadeWindowViewController);
mCentralSurfaces.handleVisibleToUserChanged(true);
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mOnBackInvokedCallback.capture());
when(mNotificationPanelViewController.canPanelBeCollapsed()).thenReturn(true);
mOnBackInvokedCallback.getValue().onBackInvoked();
verify(mShadeController).animateCollapsePanels();
}
@Test @Test
public void testPanelOpenForHeadsUp() { public void testPanelOpenForHeadsUp() {
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);