summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Caitlin Shkuratov <caitlinshk@google.com> 2023-08-23 18:07:43 +0000
committer Caitlin Shkuratov <caitlinshk@google.com> 2023-08-28 14:03:18 +0000
commit0bc3b2854f1c59398ea7fb83c2d0a332a8ef1a6a (patch)
tree6fe07ba2f2d206cbab336ce8fce949760850b251
parent3c102221505d8330ddc68751f6c90a0ca87cd5ab (diff)
[CS] 3/4: Move back gesture callback registration to back interactor.
Bug: 296050180 Test: open QS customization -> do back gesture -> verify customization is closed (verified with flag on and off) Test: open full QS -> do back gesture -> verify shade updates to be QQS (verified with flag on and off) Test: atest BackActionInteractorTest CentralSurfacesImplTest Change-Id: I0c393b96d9dbed5e6d8de7583f9f03799f1e2ed5
-rw-r--r--packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt82
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java82
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt195
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java101
8 files changed, 280 insertions, 193 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
index 3c74bf484e98..066cba230b76 100644
--- a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
@@ -16,24 +16,69 @@
package com.android.systemui.back.domain.interactor
+import android.window.BackEvent
+import android.window.OnBackAnimationCallback
+import android.window.OnBackInvokedCallback
+import android.window.OnBackInvokedDispatcher
+import android.window.WindowOnBackInvokedDispatcher
+import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
import com.android.systemui.shade.QuickSettingsController
import com.android.systemui.shade.ShadeController
import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
/** Handles requests to go back either from a button or gesture. */
@SysUISingleton
class BackActionInteractor
@Inject
constructor(
+ @Application private val scope: CoroutineScope,
private val statusBarStateController: StatusBarStateController,
private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
- private val shadeController: ShadeController
-) {
+ private val shadeController: ShadeController,
+ private val notificationShadeWindowController: NotificationShadeWindowController,
+ private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor,
+ featureFlags: FeatureFlags,
+) : CoreStartable {
+
+ private var isCallbackRegistered = false
+
+ private val callback =
+ if (featureFlags.isEnabled(Flags.WM_SHADE_ANIMATE_BACK_GESTURE)) {
+ /**
+ * New callback that handles back gesture invoked, cancel, progress and provides
+ * feedback via Shade animation.
+ */
+ object : OnBackAnimationCallback {
+ override fun onBackInvoked() {
+ onBackRequested()
+ }
+
+ override fun onBackProgressed(backEvent: BackEvent) {
+ if (shouldBackBeHandled() && shadeViewController.canBeCollapsed()) {
+ shadeViewController.onBackProgressed(backEvent.progress)
+ }
+ }
+ }
+ } else {
+ OnBackInvokedCallback { onBackRequested() }
+ }
+
+ private val onBackInvokedDispatcher: WindowOnBackInvokedDispatcher?
+ get() =
+ notificationShadeWindowController.windowRootView?.viewRootImpl?.onBackInvokedDispatcher
+
private lateinit var shadeViewController: ShadeViewController
private lateinit var qsController: QuickSettingsController
@@ -42,6 +87,19 @@ constructor(
this.shadeViewController = svController
}
+ override fun start() {
+ scope.launch {
+ windowRootViewVisibilityInteractor.isLockscreenOrShadeVisibleAndInteractive.collect {
+ visible ->
+ if (visible) {
+ registerBackCallback()
+ } else {
+ unregisterBackCallback()
+ }
+ }
+ }
+ }
+
fun shouldBackBeHandled(): Boolean {
return statusBarStateController.state != StatusBarState.KEYGUARD &&
statusBarStateController.state != StatusBarState.SHADE_LOCKED &&
@@ -74,4 +132,24 @@ constructor(
}
return false
}
+
+ private fun registerBackCallback() {
+ if (isCallbackRegistered) {
+ return
+ }
+ onBackInvokedDispatcher?.let {
+ it.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT, callback)
+ isCallbackRegistered = true
+ }
+ }
+
+ private fun unregisterBackCallback() {
+ if (!isCallbackRegistered) {
+ return
+ }
+ onBackInvokedDispatcher?.let {
+ it.unregisterOnBackInvokedCallback(callback)
+ isCallbackRegistered = false
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 1b2a9ebc9ca4..7ce7ce94e4c9 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -23,6 +23,7 @@ import com.android.systemui.ScreenDecorations
import com.android.systemui.SliceBroadcastRelayHandler
import com.android.systemui.accessibility.SystemActions
import com.android.systemui.accessibility.WindowMagnification
+import com.android.systemui.back.domain.interactor.BackActionInteractor
import com.android.systemui.biometrics.AuthController
import com.android.systemui.biometrics.BiometricNotificationService
import com.android.systemui.clipboardoverlay.ClipboardListener
@@ -346,4 +347,9 @@ abstract class SystemUICoreStartableModule {
abstract fun bindStatusBarHeadsUpChangeListener(
impl: StatusBarHeadsUpChangeListener
): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(BackActionInteractor::class)
+ abstract fun bindBackActionInteractor(impl: BackActionInteractor): CoreStartable
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index 2532bad1d7a7..b553f0fccd91 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -99,9 +99,6 @@ interface ShadeSurface : ShadeViewController {
/** Sets the view's alpha to max. */
fun resetAlpha()
- /** Sets progress of the predictive back animation. */
- fun onBackProgressed(progressFraction: Float)
-
/** @see com.android.systemui.keyguard.ScreenLifecycle.Observer.onScreenTurningOn */
fun onScreenTurningOn()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 182a676c9841..1121834f196d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -155,6 +155,9 @@ interface ShadeViewController {
/** Called when Back gesture has been committed (i.e. a back event has definitely occurred) */
fun onBackPressed()
+ /** Sets progress of the predictive back animation. */
+ fun onBackProgressed(progressFraction: Float)
+
/** Sets whether the status bar launch animation is currently running. */
fun setIsLaunchAnimationRunning(running: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
index 09b74b213ebf..6a2bef296b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
@@ -58,6 +58,7 @@ class ShadeViewControllerEmptyImpl @Inject constructor() : ShadeViewController {
return false
}
override fun onBackPressed() {}
+ override fun onBackProgressed(progressFraction: Float) {}
override fun setIsLaunchAnimationRunning(running: Boolean) {}
override fun setAlpha(alpha: Int, animate: Boolean) {}
override fun setAlphaChangeAnimationEndAction(r: Runnable) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index b862ee09506d..827e4fe6408f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -92,17 +92,12 @@ import android.view.IWindowManager;
import android.view.MotionEvent;
import android.view.ThreadedRenderer;
import android.view.View;
-import android.view.ViewRootImpl;
import android.view.WindowInsets;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import android.widget.DateTimeView;
-import android.window.BackEvent;
-import android.window.OnBackAnimationCallback;
-import android.window.OnBackInvokedCallback;
-import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
@@ -493,7 +488,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final BrightnessSliderController.Factory mBrightnessSliderFactory;
private final FeatureFlags mFeatureFlags;
- private final boolean mAnimateBack;
private final FragmentService mFragmentService;
private final ScreenOffAnimationController mScreenOffAnimationController;
private final WallpaperController mWallpaperController;
@@ -506,13 +500,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private CentralSurfacesComponent mCentralSurfacesComponent;
- /**
- * 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) */
private @Appearance int mAppearance;
@@ -638,31 +625,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private final InteractionJankMonitor mJankMonitor;
- /** Existing callback that handles back gesture invoked for the Shade. */
- private final OnBackInvokedCallback mOnBackInvokedCallback;
-
- /**
- * New callback that handles back gesture invoked, cancel, progress
- * and provides feedback via Shade animation.
- * (enabled via the WM_SHADE_ANIMATE_BACK_GESTURE flag)
- */
- private final OnBackAnimationCallback mOnBackAnimationCallback = new OnBackAnimationCallback() {
- @Override
- public void onBackInvoked() {
- mBackActionInteractor.onBackRequested();
- }
-
- @Override
- public void onBackProgressed(BackEvent event) {
- if (mBackActionInteractor.shouldBackBeHandled()) {
- if (mShadeSurface.canBeCollapsed()) {
- float fraction = event.getProgress();
- mShadeSurface.onBackProgressed(fraction);
- }
- }
- }
- };
-
/**
* Public constructor for CentralSurfaces.
*
@@ -922,14 +884,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
if (mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI)) {
mContext.getApplicationInfo().setEnableOnBackInvokedCallback(true);
}
- // Based on teamfood flag, enable predictive back animation for the Shade.
- mAnimateBack = mFeatureFlags.isEnabled(Flags.WM_SHADE_ANIMATE_BACK_GESTURE);
- mOnBackInvokedCallback = () -> {
- if (DEBUG) {
- Log.d(TAG, "mOnBackInvokedCallback() called");
- }
- mBackActionInteractor.onBackRequested();
- };
}
private void initBubbles(Bubbles bubbles) {
@@ -2172,39 +2126,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
protected void handleVisibleToUserChanged(boolean visibleToUser) {
if (visibleToUser) {
onVisibleToUser();
- if (!mIsBackCallbackRegistered) {
- ViewRootImpl viewRootImpl = getViewRootImpl();
- if (viewRootImpl != null) {
- viewRootImpl.getOnBackInvokedDispatcher()
- .registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT,
- mAnimateBack ? mOnBackAnimationCallback
- : 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 {
onInvisibleToUser();
-
- if (mIsBackCallbackRegistered) {
- ViewRootImpl viewRootImpl = getViewRootImpl();
- if (viewRootImpl != null) {
- viewRootImpl.getOnBackInvokedDispatcher()
- .unregisterOnBackInvokedCallback(
- mAnimateBack ? mOnBackAnimationCallback
- : 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)");
- }
- }
}
}
@@ -2724,11 +2647,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mNavigationBarController.showPinningEscapeToast(mDisplayId);
}
- protected ViewRootImpl getViewRootImpl() {
- View root = mNotificationShadeWindowController.getWindowRootView();
- if (root != null) return root.getViewRootImpl();
- return null;
- }
/**
* Propagation of the bouncer state, indicating that it's fully visible.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
index 88c710aedf93..c53f222cbbc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
@@ -16,18 +16,42 @@
package com.android.systemui.back.domain.interactor
+import android.view.ViewRootImpl
+import android.window.BackEvent
+import android.window.BackEvent.EDGE_LEFT
+import android.window.OnBackAnimationCallback
+import android.window.OnBackInvokedCallback
+import android.window.OnBackInvokedDispatcher
+import android.window.WindowOnBackInvokedDispatcher
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.WakeSleepReason
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
+import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.QuickSettingsController
import com.android.systemui.shade.ShadeController
import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -41,7 +65,11 @@ import org.mockito.junit.MockitoJUnit
@SmallTest
@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
class BackActionInteractorTest : SysuiTestCase() {
+ private val testScope = TestScope()
+ private val featureFlags = FakeFeatureFlags()
+
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
@Mock private lateinit var statusBarStateController: StatusBarStateController
@@ -49,18 +77,38 @@ class BackActionInteractorTest : SysuiTestCase() {
@Mock private lateinit var shadeController: ShadeController
@Mock private lateinit var qsController: QuickSettingsController
@Mock private lateinit var shadeViewController: ShadeViewController
+ @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
+ @Mock private lateinit var windowRootView: WindowRootView
+ @Mock private lateinit var viewRootImpl: ViewRootImpl
+ @Mock private lateinit var onBackInvokedDispatcher: WindowOnBackInvokedDispatcher
- private lateinit var backActionInteractor: BackActionInteractor
+ private val keyguardRepository = FakeKeyguardRepository()
+ private val windowRootViewVisibilityInteractor =
+ WindowRootViewVisibilityInteractor(
+ testScope.backgroundScope,
+ WindowRootViewVisibilityRepository(),
+ keyguardRepository,
+ )
- @Before
- fun setup() {
- backActionInteractor =
- BackActionInteractor(
+ private val backActionInteractor: BackActionInteractor by lazy {
+ BackActionInteractor(
+ testScope.backgroundScope,
statusBarStateController,
statusBarKeyguardViewManager,
shadeController,
+ notificationShadeWindowController,
+ windowRootViewVisibilityInteractor,
+ featureFlags,
)
- backActionInteractor.setup(qsController, shadeViewController)
+ .apply { this.setup(qsController, shadeViewController) }
+ }
+
+ @Before
+ fun setUp() {
+ featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, false)
+ whenever(notificationShadeWindowController.windowRootView).thenReturn(windowRootView)
+ whenever(windowRootView.viewRootImpl).thenReturn(viewRootImpl)
+ whenever(viewRootImpl.onBackInvokedDispatcher).thenReturn(onBackInvokedDispatcher)
}
@Test
@@ -117,4 +165,139 @@ class BackActionInteractorTest : SysuiTestCase() {
verify(statusBarKeyguardViewManager, never()).onBackPressed()
verify(shadeViewController, never()).animateCollapseQs(anyBoolean())
}
+
+ @Test
+ fun shadeVisibleAndDeviceAwake_callbackRegistered() {
+ backActionInteractor.start()
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ setWakefulness(WakefulnessState.AWAKE)
+
+ testScope.runCurrent()
+
+ verify(onBackInvokedDispatcher)
+ .registerOnBackInvokedCallback(eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any())
+ }
+
+ @Test
+ fun noWindowRootView_noCrashAttemptingCallbackRegistration() {
+ whenever(notificationShadeWindowController.windowRootView).thenReturn(null)
+
+ backActionInteractor.start()
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ setWakefulness(WakefulnessState.AWAKE)
+
+ testScope.runCurrent()
+ // No assert necessary, just testing no crash
+ }
+
+ @Test
+ fun shadeNotVisible_callbackUnregistered() {
+ backActionInteractor.start()
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ setWakefulness(WakefulnessState.AWAKE)
+ val callback = getBackInvokedCallback()
+
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false)
+ testScope.runCurrent()
+
+ verify(onBackInvokedDispatcher).unregisterOnBackInvokedCallback(callback)
+ }
+
+ @Test
+ fun deviceAsleep_callbackUnregistered() {
+ backActionInteractor.start()
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ setWakefulness(WakefulnessState.AWAKE)
+ val callback = getBackInvokedCallback()
+
+ setWakefulness(WakefulnessState.ASLEEP)
+ testScope.runCurrent()
+
+ verify(onBackInvokedDispatcher).unregisterOnBackInvokedCallback(callback)
+ }
+
+ @Test
+ fun animationFlagOff_onBackInvoked_keyguardNotified() {
+ backActionInteractor.start()
+ featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, false)
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ setWakefulness(WakefulnessState.AWAKE)
+ val callback = getBackInvokedCallback()
+ whenever(statusBarKeyguardViewManager.canHandleBackPressed()).thenReturn(true)
+
+ callback.onBackInvoked()
+
+ verify(statusBarKeyguardViewManager).onBackPressed()
+ }
+
+ @Test
+ fun animationFlagOn_onBackInvoked_keyguardNotified() {
+ featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true)
+ backActionInteractor.start()
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ setWakefulness(WakefulnessState.AWAKE)
+ val callback = getBackInvokedCallback()
+ whenever(statusBarKeyguardViewManager.canHandleBackPressed()).thenReturn(true)
+
+ callback.onBackInvoked()
+
+ verify(statusBarKeyguardViewManager).onBackPressed()
+ }
+
+ @Test
+ fun animationFlagOn_callbackIsAnimationCallback() {
+ featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true)
+ backActionInteractor.start()
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ setWakefulness(WakefulnessState.AWAKE)
+
+ val callback = getBackInvokedCallback()
+
+ assertThat(callback).isInstanceOf(OnBackAnimationCallback::class.java)
+ }
+
+ @Test
+ fun onBackProgressed_shadeCannotBeCollapsed_shadeViewControllerNotNotified() {
+ featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true)
+ backActionInteractor.start()
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ setWakefulness(WakefulnessState.AWAKE)
+ val callback = getBackInvokedCallback() as OnBackAnimationCallback
+
+ whenever(shadeViewController.canBeCollapsed()).thenReturn(false)
+
+ callback.onBackProgressed(createBackEvent(0.3f))
+
+ verify(shadeViewController, never()).onBackProgressed(0.3f)
+ }
+
+ @Test
+ fun onBackProgressed_shadeCanBeCollapsed_shadeViewControllerNotified() {
+ featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true)
+ backActionInteractor.start()
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ setWakefulness(WakefulnessState.AWAKE)
+ val callback = getBackInvokedCallback() as OnBackAnimationCallback
+
+ whenever(shadeViewController.canBeCollapsed()).thenReturn(true)
+
+ callback.onBackProgressed(createBackEvent(0.4f))
+
+ verify(shadeViewController).onBackProgressed(0.4f)
+ }
+
+ private fun getBackInvokedCallback(): OnBackInvokedCallback {
+ testScope.runCurrent()
+ val captor = argumentCaptor<OnBackInvokedCallback>()
+ verify(onBackInvokedDispatcher).registerOnBackInvokedCallback(any(), captor.capture())
+ return captor.value!!
+ }
+
+ private fun createBackEvent(progress: Float): BackEvent =
+ BackEvent(/* touchX= */ 0f, /* touchY= */ 0f, progress, /* swipeEdge= */ EDGE_LEFT)
+
+ private fun setWakefulness(state: WakefulnessState) {
+ val model = WakefulnessModel(state, WakeSleepReason.OTHER, WakeSleepReason.OTHER)
+ keyguardRepository.setWakefulnessModel(model)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index c965251772e0..7b4a5644872f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -73,13 +73,7 @@ import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
-import android.view.ViewRootImpl;
import android.view.WindowManager;
-import android.window.BackEvent;
-import android.window.OnBackAnimationCallback;
-import android.window.OnBackInvokedCallback;
-import android.window.OnBackInvokedDispatcher;
-import android.window.WindowOnBackInvokedDispatcher;
import androidx.test.filters.SmallTest;
@@ -196,7 +190,6 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -320,16 +313,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
@Mock private Lazy<CameraLauncher> mCameraLauncherLazy;
@Mock private CameraLauncher mCameraLauncher;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
- /**
- * 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;
@Mock private UserTracker mUserTracker;
@Mock private FingerprintManager mFingerprintManager;
- @Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
@Mock IPowerManager mPowerManagerService;
@Mock ActivityStarter mActivityStarter;
@@ -561,16 +546,9 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mUserTracker,
() -> mFingerprintManager,
mActivityStarter
- ) {
- @Override
- protected ViewRootImpl getViewRootImpl() {
- return mViewRootImpl;
- }
- };
+ );
mScreenLifecycle.addObserver(mCentralSurfaces.mScreenObserver);
mCentralSurfaces.initShadeVisibilityListener();
- when(mViewRootImpl.getOnBackInvokedDispatcher())
- .thenReturn(mOnBackInvokedDispatcher);
when(mKeyguardViewMediator.registerCentralSurfaces(
any(CentralSurfacesImpl.class),
any(NotificationPanelViewController.class),
@@ -792,83 +770,6 @@ 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.handleVisibleToUserChanged(true);
- verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
- mOnBackInvokedCallback.capture());
-
- when(mBackActionInteractor.shouldBackBeHandled()).thenReturn(true);
- mOnBackInvokedCallback.getValue().onBackInvoked();
- verify(mBackActionInteractor).onBackRequested();
- }
-
- /**
- * When back progress is at 100%, the onBackProgressed animation driver inside
- * NotificationPanelViewController should be invoked appropriately (with 1.0f passed in).
- */
- @Test
- public void testPredictiveBackAnimation_progressMaxScalesPanel() {
- mCentralSurfaces.handleVisibleToUserChanged(true);
- verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
- mOnBackInvokedCallback.capture());
-
- OnBackAnimationCallback onBackAnimationCallback =
- (OnBackAnimationCallback) (mOnBackInvokedCallback.getValue());
- when(mBackActionInteractor.shouldBackBeHandled()).thenReturn(true);
- when(mNotificationPanelViewController.canBeCollapsed()).thenReturn(true);
-
- BackEvent fakeSwipeInFromLeftEdge = new BackEvent(20.0f, 100.0f, 1.0f, BackEvent.EDGE_LEFT);
- onBackAnimationCallback.onBackProgressed(fakeSwipeInFromLeftEdge);
- verify(mNotificationPanelViewController).onBackProgressed(eq(1.0f));
- }
-
- /**
- * When back progress is at 0%, the onBackProgressed animation driver inside
- * NotificationPanelViewController should be invoked appropriately (with 0.0f passed in).
- */
- @Test
- public void testPredictiveBackAnimation_progressMinScalesPanel() {
- mCentralSurfaces.handleVisibleToUserChanged(true);
- verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
- mOnBackInvokedCallback.capture());
-
- OnBackAnimationCallback onBackAnimationCallback =
- (OnBackAnimationCallback) (mOnBackInvokedCallback.getValue());
- when(mBackActionInteractor.shouldBackBeHandled()).thenReturn(true);
- when(mNotificationPanelViewController.canBeCollapsed()).thenReturn(true);
-
- BackEvent fakeSwipeInFromLeftEdge = new BackEvent(20.0f, 10.0f, 0.0f, BackEvent.EDGE_LEFT);
- onBackAnimationCallback.onBackProgressed(fakeSwipeInFromLeftEdge);
- verify(mNotificationPanelViewController).onBackProgressed(eq(0.0f));
- }
-
@Test
public void testPanelOpenForHeadsUp() {
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);