Add unit testing for InputConsumerUtils
Flag: EXEMPT unit testing
Bug: 371020209
Test: InputConsumerUtilsTest
Change-Id: Ia3f9c13dae7650dc0ae37b48b1d75e84cac60142
diff --git a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
new file mode 100644
index 0000000..5dc6932
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) 2024 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.quickstep;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.quickstep.InputConsumerUtils.newBaseConsumer;
+import static com.android.quickstep.InputConsumerUtils.newConsumer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Looper;
+import android.view.Choreographer;
+import android.view.MotionEvent;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.launcher3.taskbar.TaskbarManager;
+import com.android.launcher3.taskbar.bubbles.BubbleBarController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarPinController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
+import com.android.launcher3.taskbar.bubbles.BubbleCreator;
+import com.android.launcher3.taskbar.bubbles.BubbleDismissController;
+import com.android.launcher3.taskbar.bubbles.BubbleDragController;
+import com.android.launcher3.taskbar.bubbles.BubblePinController;
+import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
+import com.android.launcher3.util.LockedUserState;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
+import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
+import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
+import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
+import com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer;
+import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
+import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
+import com.android.quickstep.inputconsumers.OverviewInputConsumer;
+import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
+import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer;
+import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
+import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
+import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
+import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer;
+import com.android.quickstep.util.ActiveGestureLog;
+import com.android.quickstep.util.NavBarPosition;
+import com.android.quickstep.views.RecentsViewContainer;
+import com.android.systemui.shared.system.InputChannelCompat;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+import javax.inject.Provider;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputConsumerUtilsTest {
+
+ @NonNull private final MainThreadInitializedObject.SandboxContext mContext =
+ new MainThreadInitializedObject.SandboxContext(getApplicationContext());
+ @NonNull private final TaskAnimationManager mTaskAnimationManager = new TaskAnimationManager(
+ mContext, mock(RecentsWindowManager.class));
+ @NonNull private final InputMonitorCompat mInputMonitorCompat = new InputMonitorCompat("", 0);
+
+ private InputChannelCompat.InputEventReceiver mInputEventReceiver;
+ @Nullable private ResetGestureInputConsumer mResetGestureInputConsumer;
+ @NonNull private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = (state) -> null;
+
+ @NonNull @Mock private TaskbarActivityContext mTaskbarActivityContext;
+ @NonNull @Mock private OverviewComponentObserver mOverviewComponentObserver;
+ @NonNull @Mock private RecentsAnimationDeviceState mDeviceState;
+ @NonNull @Mock private AbsSwipeUpHandler.Factory mSwipeUpHandlerFactory;
+ @NonNull @Mock private TaskbarManager mTaskbarManager;
+ @NonNull @Mock private OverviewCommandHelper mOverviewCommandHelper;
+ @NonNull @Mock private GestureState mPreviousGestureState;
+ @NonNull @Mock private GestureState mCurrentGestureState;
+ @NonNull @Mock private LockedUserState mLockedUserState;
+ @NonNull @Mock private TopTaskTracker.CachedTaskInfo mRunningTask;
+ @NonNull @Mock private BaseContainerInterface<?, ?> mContainerInterface;
+ @NonNull @Mock private BaseDragLayer<?> mBaseDragLayer;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Before
+ public void setupMainThreadInitializedObjects() {
+ mContext.putObject(LockedUserState.INSTANCE, mLockedUserState);
+ }
+
+ @Before
+ public void setUpInputEventReceiver() {
+ runOnMainSync(() ->
+ mInputEventReceiver = mInputMonitorCompat.getInputReceiver(
+ Looper.getMainLooper(),
+ Choreographer.getInstance(),
+ event -> {}));
+ }
+
+ @Before
+ public void setUpTaskbarActivityContext() {
+ NavHandle navHandle = mock(NavHandle.class);
+
+ when(navHandle.canNavHandleBeLongPressed()).thenReturn(true);
+
+ when(mTaskbarActivityContext.getDeviceProfile()).thenReturn(new DeviceProfile());
+ when(mTaskbarActivityContext.getNavHandle()).thenReturn(navHandle);
+ }
+
+ @Before
+ public void setUpTaskbarManager() {
+ when(mTaskbarManager.getCurrentActivityContext()).thenReturn(mTaskbarActivityContext);
+ }
+
+ @Before
+ public void setUpResetGestureInputConsumer() {
+ mResetGestureInputConsumer = new ResetGestureInputConsumer(
+ mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext);
+ }
+
+ @Before
+ public void setupLockedUserState() {
+ when(mLockedUserState.isUserUnlocked()).thenReturn(true);
+ }
+
+ @Before
+ public void setupGestureStates() {
+ when(mCurrentGestureState.getRunningTask()).thenReturn(mRunningTask);
+ doReturn(mContainerInterface).when(mCurrentGestureState).getContainerInterface();
+ }
+
+ @Before
+ public void setUpContainerInterface() {
+ RecentsViewContainer recentsViewContainer = mock(RecentsViewContainer.class);
+
+ when(recentsViewContainer.getDragLayer()).thenReturn(mBaseDragLayer);
+ when(recentsViewContainer.getRootView()).thenReturn(mBaseDragLayer);
+ when(recentsViewContainer.asContext()).thenReturn(mContext);
+
+ doReturn(recentsViewContainer).when(mContainerInterface).getCreatedContainer();
+ }
+
+ @Before
+ public void setupBaseDragLayer() {
+ when(mBaseDragLayer.hasWindowFocus()).thenReturn(true);
+ }
+
+ @Before
+ public void setupDeviceState() {
+ when(mDeviceState.canStartTrackpadGesture()).thenReturn(true);
+ when(mDeviceState.canStartSystemGesture()).thenReturn(true);
+ when(mDeviceState.isFullyGesturalNavMode()).thenReturn(true);
+ when(mDeviceState.getNavBarPosition()).thenReturn(mock(NavBarPosition.class));
+ when(mDeviceState.getRotationTouchHelper()).thenReturn(mock(RotationTouchHelper.class));
+ }
+
+ @After
+ public void cleanUp() {
+ mInputMonitorCompat.dispose();
+ mInputEventReceiver.dispose();
+ }
+
+ @Test
+ public void testNewBaseConsumer_onKeyguard_returnsDeviceLockedInputConsumer() {
+ when(mDeviceState.isKeyguardShowingOccluded()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ DeviceLockedInputConsumer.class,
+ InputConsumer.TYPE_DEVICE_LOCKED);
+ }
+
+ @Test
+ public void testNewBaseConsumer_onLiveTileModeWithNoContainer_returnsDefaultInputConsumer() {
+ when(mContainerInterface.isInLiveTileMode()).thenReturn(true);
+ when(mContainerInterface.getCreatedContainer()).thenReturn(null);
+
+ assertEqualsDefaultInputConsumer(this::createBaseInputConsumer);
+ }
+
+ @Test
+ public void testNewBaseConsumer_onLiveTileMode_returnsOverviewInputConsumer() {
+ when(mContainerInterface.isInLiveTileMode()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW);
+ }
+
+ @Test
+ public void testNewBaseConsumer_withNoRunningTask_returnsDefaultInputConsumer() {
+ when(mCurrentGestureState.getRunningTask()).thenReturn(null);
+
+ assertEqualsDefaultInputConsumer(this::createBaseInputConsumer);
+ }
+
+ @Test
+ public void testNewBaseConsumer_prevGestureAnimatingToLauncher_returnsOverviewInputConsumer() {
+ when(mPreviousGestureState.isRunningAnimationToLauncher()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW);
+ }
+
+ @Test
+ public void testNewBaseConsumer_predictiveBackToHomeInProgress_returnsOverviewInputConsumer() {
+ when(mDeviceState.isPredictiveBackToHomeInProgress()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW);
+ }
+
+ @Test
+ public void testNewBaseConsumer_resumedThroughShellTransition_returnsOverviewInputConsumer() {
+ when(mContainerInterface.isResumed()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW);
+ }
+
+ @Test
+ public void testNewBaseConsumer_shellNoWindowFocus_returnsOverviewWithoutFocusInputConsumer() {
+ when(mContainerInterface.isResumed()).thenReturn(true);
+ when(mBaseDragLayer.hasWindowFocus()).thenReturn(false);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewWithoutFocusInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW_WITHOUT_FOCUS);
+ }
+
+ @Test
+ public void testNewBaseConsumer_forceOverviewInputConsumer_returnsOverviewInputConsumer() {
+ when(mContainerInterface.isResumed()).thenReturn(true);
+ when(mRunningTask.isRootChooseActivity()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OverviewInputConsumer.class,
+ InputConsumer.TYPE_OVERVIEW);
+ }
+
+ @Test
+ public void testNewBaseConsumer_launcherChildActivityResumed_returnsDefaultInputConsumer() {
+ when(mRunningTask.isHomeTask()).thenReturn(true);
+ when(mOverviewComponentObserver.isHomeAndOverviewSame()).thenReturn(true);
+
+ assertEqualsDefaultInputConsumer(this::createBaseInputConsumer);
+ }
+
+ @Test
+ public void testNewBaseConsumer_onGestureBlockedTask_returnsDefaultInputConsumer() {
+ when(mDeviceState.isGestureBlockedTask(any())).thenReturn(true);
+
+ assertEqualsDefaultInputConsumer(this::createBaseInputConsumer);
+ }
+
+ @Test
+ public void testNewBaseConsumer_containsOtherActivityInputConsumer() {
+ // OtherActivityInputConsumer needs to be initialized on the main thread because of
+ // MotionPauseDetector.mForcePauseTimeout
+ assertCorrectInputConsumer(
+ this::createBaseInputConsumer,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY);
+ }
+
+ @Test
+ public void testNewConsumer_containsOtherActivityInputConsumer() {
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ NavHandleLongPressInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS);
+ }
+
+ @Test
+ public void testNewConsumer_eventCanTriggerAssistantAction_containsAssistantInputConsumer() {
+ when(mDeviceState.canTriggerAssistantAction(any())).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ NavHandleLongPressInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY
+ | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS
+ | InputConsumer.TYPE_ASSISTANT);
+ }
+
+ @Test
+ public void testNewConsumer_taskbarIsPresent_containsTaskbarUnstashInputConsumer() {
+ DeviceProfile deviceProfile = new DeviceProfile();
+ deviceProfile.isTaskbarPresent = true;
+ when(mTaskbarActivityContext.getDeviceProfile()).thenReturn(deviceProfile);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ NavHandleLongPressInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY
+ | InputConsumer.TYPE_TASKBAR_STASH
+ | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS
+ | InputConsumer.TYPE_CURSOR_HOVER);
+ }
+
+ @Test
+ public void testNewConsumer_whileSystemUiDialogShowing_returnsSysUiOverlayInputConsumer() {
+ when(mDeviceState.isSystemUiDialogShowing()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ SysUiOverlayInputConsumer.class,
+ InputConsumer.TYPE_SYSUI_OVERLAY);
+ }
+
+ @Test
+ public void testNewConsumer_onTrackpadGesture_returnsTrackpadStatusBarInputConsumer() {
+ when(mCurrentGestureState.isTrackpadGesture()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ TrackpadStatusBarInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY
+ | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS
+ | InputConsumer.TYPE_STATUS_BAR);
+ }
+
+ @Test
+ public void testNewConsumer_whileScreenPinningActive_returnsScreenPinnedInputConsumer() {
+ when(mDeviceState.isScreenPinningActive()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ ScreenPinnedInputConsumer.class,
+ InputConsumer.TYPE_SCREEN_PINNED);
+ }
+
+ @Test
+ public void testNewConsumer_canTriggerOneHandedAction_returnsOneHandedModeInputConsumer() {
+ when(mDeviceState.canTriggerOneHandedAction(any())).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ OneHandedModeInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY
+ | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS
+ | InputConsumer.TYPE_ONE_HANDED);
+ }
+
+ @Test
+ public void testNewConsumer_accessibilityMenuAvailable_returnsAccessibilityInputConsumer() {
+ when(mDeviceState.isAccessibilityMenuAvailable()).thenReturn(true);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ AccessibilityInputConsumer.class,
+ OtherActivityInputConsumer.class,
+ InputConsumer.TYPE_OTHER_ACTIVITY
+ | InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS
+ | InputConsumer.TYPE_ACCESSIBILITY);
+ }
+
+ @Test
+ public void testNewConsumer_onStashedBubbleBar_returnsBubbleBarInputConsumer() {
+ BubbleControllers bubbleControllers = createBubbleControllers(/* isStashed= */ true);
+
+ when(mTaskbarActivityContext.isBubbleBarEnabled()).thenReturn(true);
+ when(mTaskbarActivityContext.getBubbleControllers()).thenReturn(bubbleControllers);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ BubbleBarInputConsumer.class,
+ InputConsumer.TYPE_BUBBLE_BAR);
+ }
+
+ @Test
+ public void testNewConsumer_onVisibleBubbleBar_returnsBubbleBarInputConsumer() {
+ BubbleControllers bubbleControllers = createBubbleControllers(/* isStashed= */ false);
+
+ when(mTaskbarActivityContext.isBubbleBarEnabled()).thenReturn(true);
+ when(mTaskbarActivityContext.getBubbleControllers()).thenReturn(bubbleControllers);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ BubbleBarInputConsumer.class,
+ InputConsumer.TYPE_BUBBLE_BAR);
+ }
+
+ @Test
+ public void testNewConsumer_withSwipeUpProxyProvider_returnsProgressDelegateInputConsumer() {
+ mSwipeUpProxyProvider = (state) -> new AnimatedFloat();
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ ProgressDelegateInputConsumer.class,
+ InputConsumer.TYPE_PROGRESS_DELEGATE);
+ }
+
+ @Test
+ public void testNewConsumer_onLockedState_returnsDeviceLockedInputConsumer() {
+ when(mLockedUserState.isUserUnlocked()).thenReturn(false);
+
+ assertCorrectInputConsumer(
+ this::createInputConsumer,
+ DeviceLockedInputConsumer.class,
+ InputConsumer.TYPE_DEVICE_LOCKED);
+ }
+
+ @Test
+ public void testNewConsumer_cannotStartSysGestureOnLockedState_returnsDefaultInputConsumer() {
+ when(mLockedUserState.isUserUnlocked()).thenReturn(false);
+ when(mDeviceState.canStartSystemGesture()).thenReturn(false);
+
+ assertEqualsDefaultInputConsumer(this::createInputConsumer);
+ }
+
+ @Test
+ public void testNewConsumer_cannotStartTrackGestureOnLockedState_returnsDefaultInputConsumer() {
+ when(mLockedUserState.isUserUnlocked()).thenReturn(false);
+ when(mCurrentGestureState.isTrackpadGesture()).thenReturn(true);
+ when(mDeviceState.canStartTrackpadGesture()).thenReturn(false);
+
+ assertEqualsDefaultInputConsumer(this::createInputConsumer);
+ }
+
+ private InputConsumer createInputConsumer() {
+ MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ InputConsumer inputConsumer = newConsumer(
+ mContext,
+ mContext,
+ mResetGestureInputConsumer,
+ mOverviewComponentObserver,
+ mDeviceState,
+ mPreviousGestureState,
+ mCurrentGestureState,
+ mTaskAnimationManager,
+ mInputMonitorCompat,
+ mSwipeUpHandlerFactory,
+ otherActivityInputConsumer -> {},
+ mInputEventReceiver,
+ mTaskbarManager,
+ mSwipeUpProxyProvider,
+ mOverviewCommandHelper,
+ event);
+
+ event.recycle();
+
+ return inputConsumer;
+ }
+
+ private InputConsumer createBaseInputConsumer() {
+ MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ InputConsumer inputConsumer = newBaseConsumer(
+ mContext,
+ mResetGestureInputConsumer,
+ mOverviewComponentObserver,
+ mDeviceState,
+ mPreviousGestureState,
+ mCurrentGestureState,
+ mTaskAnimationManager,
+ mInputMonitorCompat,
+ mSwipeUpHandlerFactory,
+ otherActivityInputConsumer -> {},
+ mInputEventReceiver,
+ event,
+ ActiveGestureLog.CompoundString.NO_OP);
+
+ event.recycle();
+
+ return inputConsumer;
+ }
+
+ private void assertEqualsDefaultInputConsumer(
+ @NonNull Provider<InputConsumer> inputConsumerProvider) {
+ assertCorrectInputConsumer(
+ inputConsumerProvider,
+ ResetGestureInputConsumer.class,
+ InputConsumer.TYPE_RESET_GESTURE);
+
+ mResetGestureInputConsumer = null;
+
+ runOnMainSync(() -> assertThat(inputConsumerProvider.get()).isEqualTo(InputConsumer.NO_OP));
+ }
+
+ private static void assertCorrectInputConsumer(
+ @NonNull Provider<InputConsumer> inputConsumerProvider,
+ @NonNull Class<? extends InputConsumer> expectedOutputConsumer,
+ int expectedType) {
+ assertCorrectInputConsumer(
+ inputConsumerProvider,
+ expectedOutputConsumer,
+ expectedOutputConsumer,
+ expectedType);
+ }
+
+ private static void assertCorrectInputConsumer(
+ @NonNull Provider<InputConsumer> inputConsumerProvider,
+ @NonNull Class<? extends InputConsumer> expectedOutputConsumer,
+ @NonNull Class<? extends InputConsumer> expectedActiveConsumer,
+ int expectedType) {
+ runOnMainSync(() -> {
+ InputConsumer inputConsumer = inputConsumerProvider.get();
+
+ assertThat(inputConsumer).isInstanceOf(expectedOutputConsumer);
+ assertThat(inputConsumer.getActiveConsumerInHierarchy())
+ .isInstanceOf(expectedActiveConsumer);
+ assertThat(inputConsumer.getType()).isEqualTo(expectedType);
+ });
+ }
+
+ private static void runOnMainSync(@NonNull Runnable runnable) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
+ }
+
+ private static BubbleControllers createBubbleControllers(boolean isStashed) {
+ BubbleBarController bubbleBarController = mock(BubbleBarController.class);
+ BubbleBarViewController bubbleBarViewController = mock(BubbleBarViewController.class);
+ BubbleStashController bubbleStashController = mock(BubbleStashController.class);
+ BubbleStashedHandleViewController bubbleStashedHandleViewController =
+ mock(BubbleStashedHandleViewController.class);
+ BubbleDragController bubbleDragController = mock(BubbleDragController.class);
+ BubbleDismissController bubbleDismissController = mock(BubbleDismissController.class);
+ BubbleBarPinController bubbleBarPinController = mock(BubbleBarPinController.class);
+ BubblePinController bubblePinController = mock(BubblePinController.class);
+ BubbleBarSwipeController bubbleBarSwipeController = mock(BubbleBarSwipeController.class);
+ BubbleCreator bubbleCreator = mock(BubbleCreator.class);
+ BubbleControllers bubbleControllers = new BubbleControllers(
+ bubbleBarController,
+ bubbleBarViewController,
+ bubbleStashController,
+ Optional.of(bubbleStashedHandleViewController),
+ bubbleDragController,
+ bubbleDismissController,
+ bubbleBarPinController,
+ bubblePinController,
+ Optional.of(bubbleBarSwipeController),
+ bubbleCreator);
+
+ when(bubbleBarViewController.hasBubbles()).thenReturn(true);
+ when(bubbleStashController.isStashed()).thenReturn(isStashed);
+ when(bubbleStashedHandleViewController.isEventOverHandle(any())).thenReturn(true);
+ when(bubbleBarViewController.isBubbleBarVisible()).thenReturn(!isStashed);
+ when(bubbleBarViewController.isEventOverBubbleBar(any())).thenReturn(true);
+
+ return bubbleControllers;
+ }
+}