Merge changes Ie1b6609b,If115625c,I418675ba,I930e7458 into main
* changes:
Add tests for TaskbarAllAppsViewController.
Add tests for TaskbarAutohideSuspendController.
Add tests for TaskbarScrimViewController.
Add tests for TaskbarStashController.
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index 7a8b58e..32fda48 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -31,6 +31,7 @@
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.ColorInt;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -253,4 +254,9 @@
public View getFocusedChild() {
return null;
}
+
+ @VisibleForTesting
+ public DividerType getDividerType() {
+ return mDividerType;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 751a42a..bf086b4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -27,6 +27,8 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
import com.android.launcher3.util.DisplayController;
@@ -77,7 +79,7 @@
public void onTaskbarVisibilityChanged(int visibility) {
mTaskbarVisible = visibility == VISIBLE;
if (shouldShowScrim()) {
- showScrim(true, getScrimAlpha(), false /* skipAnim */);
+ showScrim(true, computeScrimAlpha(), false /* skipAnim */);
} else if (mScrimView.getScrimAlpha() > 0f) {
showScrim(false, 0, false /* skipAnim */);
}
@@ -96,7 +98,7 @@
return;
}
mSysUiStateFlags = stateFlags;
- showScrim(shouldShowScrim(), getScrimAlpha(), skipAnim);
+ showScrim(shouldShowScrim(), computeScrimAlpha(), skipAnim);
}
private boolean shouldShowScrim() {
@@ -119,7 +121,7 @@
&& !mControllers.taskbarStashController.isHiddenForBubbles();
}
- private float getScrimAlpha() {
+ private float computeScrimAlpha() {
final boolean isPersistentTaskBarVisible =
mTaskbarVisible && !DisplayController.isTransientTaskbar(mScrimView.getContext());
final boolean manageMenuExpanded =
@@ -140,7 +142,7 @@
mScrimView.setOnClickListener(showScrim ? (view) -> onClick() : null);
mScrimView.setClickable(showScrim);
if (skipAnim) {
- mScrimView.setScrimAlpha(alpha);
+ mScrimAlpha.updateValue(alpha);
} else {
ObjectAnimator anim = mScrimAlpha.animateToValue(showScrim ? alpha : 0);
anim.setInterpolator(showScrim ? SCRIM_ALPHA_IN : SCRIM_ALPHA_OUT);
@@ -167,4 +169,14 @@
pw.println(prefix + "\tmScrimAlpha.value=" + mScrimAlpha.value);
}
+
+ @VisibleForTesting
+ TaskbarScrimView getScrimView() {
+ return mScrimView;
+ }
+
+ @VisibleForTesting
+ float getScrimAlpha() {
+ return mScrimAlpha.value;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 266f384..5b168e0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -81,6 +81,8 @@
private static final String TAG = "TaskbarStashController";
private static final boolean DEBUG = false;
+ private static boolean sEnableSoftwareImeForTests = false;
+
/**
* Def. value for @param shouldBubblesFollow in
* {@link #updateAndAnimateTransientTaskbar(boolean)} */
@@ -130,19 +132,22 @@
*
* Use {@link #getStashDuration()} to query duration
*/
- private static final long TASKBAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE;
+ @VisibleForTesting
+ static final long TASKBAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE;
/**
* How long to stash/unstash transient taskbar.
*
* Use {@link #getStashDuration()} to query duration.
*/
- private static final long TRANSIENT_TASKBAR_STASH_DURATION = 417;
+ @VisibleForTesting
+ static final long TRANSIENT_TASKBAR_STASH_DURATION = 417;
/**
* How long to stash/unstash when keyboard is appearing/disappearing.
*/
- private static final long TASKBAR_STASH_DURATION_FOR_IME = 80;
+ @VisibleForTesting
+ static final long TASKBAR_STASH_DURATION_FOR_IME = 80;
/**
* The scale TaskbarView animates to when being stashed.
@@ -163,7 +168,7 @@
/**
* How long the icon/stash handle alpha animation plays.
*/
- public static final long TASKBAR_STASH_ALPHA_DURATION = 50;
+ public static final long TRANSIENT_TASKBAR_STASH_ALPHA_DURATION = 50;
/**
* How long to delay the icon/stash handle alpha for the home to app taskbar animation.
@@ -252,7 +257,7 @@
private boolean mEnableBlockingTimeoutDuringTests = false;
private Animator mTaskbarBackgroundAlphaAnimator;
- private long mTaskbarBackgroundDuration;
+ private final long mTaskbarBackgroundDuration;
private boolean mUserIsNotGoingHome = false;
// Evaluate whether the handle should be stashed
@@ -799,14 +804,14 @@
if (animationType == TRANSITION_HANDLE_FADE) {
// When fading, the handle fades in/out at the beginning of the transition with
// TASKBAR_STASH_ALPHA_DURATION.
- backgroundAndHandleAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
+ backgroundAndHandleAlphaDuration = TRANSIENT_TASKBAR_STASH_ALPHA_DURATION;
// The iconAlphaDuration must be set to duration for the skippable interpolators
// below to work.
iconAlphaDuration = duration;
} else {
iconAlphaStartDelay = TASKBAR_STASH_ALPHA_START_DELAY;
- iconAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
- backgroundAndHandleAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
+ iconAlphaDuration = TRANSIENT_TASKBAR_STASH_ALPHA_DURATION;
+ backgroundAndHandleAlphaDuration = TRANSIENT_TASKBAR_STASH_ALPHA_DURATION;
if (isStashed) {
if (animationType == TRANSITION_HOME_TO_APP) {
@@ -1070,7 +1075,8 @@
/**
* When hiding the IME, delay the unstash animation to align with the end of the transition.
*/
- private long getTaskbarStashStartDelayForIme() {
+ @VisibleForTesting
+ long getTaskbarStashStartDelayForIme() {
if (mIsImeShowing) {
// Only delay when IME is exiting, not entering.
return 0;
@@ -1126,13 +1132,13 @@
}
// Do not stash if pinned taskbar, hardware keyboard is attached and no IME is docked
- if (mActivity.isHardwareKeyboard() && DisplayController.isPinnedTaskbar(mActivity)
+ if (isHardwareKeyboard() && DisplayController.isPinnedTaskbar(mActivity)
&& !mActivity.isImeDocked()) {
return false;
}
// Do not stash if hardware keyboard is attached, in 3 button nav and desktop windowing mode
- if (mActivity.isHardwareKeyboard()
+ if (isHardwareKeyboard()
&& mActivity.isThreeButtonNav()
&& mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
return false;
@@ -1146,6 +1152,21 @@
return mIsImeShowing || mIsImeSwitcherShowing;
}
+ private boolean isHardwareKeyboard() {
+ return mActivity.isHardwareKeyboard() && !sEnableSoftwareImeForTests;
+ }
+
+ /**
+ * Overrides {@link #isHardwareKeyboard()} to {@code false} for testing, if enabled.
+ * <p>
+ * Virtual devices are sometimes in hardware keyboard mode, leading to an inconsistent
+ * testing environment.
+ */
+ @VisibleForTesting
+ static void enableSoftwareImeForTests(boolean enable) {
+ sEnableSoftwareImeForTests = enable;
+ }
+
/**
* Updates the proper flag to indicate whether the task bar should be stashed.
*
@@ -1271,7 +1292,7 @@
/**
* Attempts to start timer to auto hide the taskbar based on time.
*/
- public void tryStartTaskbarTimeout() {
+ private void tryStartTaskbarTimeout() {
if (!DisplayController.isTransientTaskbar(mActivity)
|| mIsStashed
|| mEnableBlockingTimeoutDuringTests) {
@@ -1299,6 +1320,11 @@
updateAndAnimateTransientTaskbarForTimeout();
}
+ @VisibleForTesting
+ Alarm getTimeoutAlarm() {
+ return mTimeoutAlarm;
+ }
+
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarStashController:");
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 4f0337d..74e3c00 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -32,8 +32,8 @@
import com.android.launcher3.anim.AnimatedFloat
import com.android.launcher3.anim.SpringAnimationBuilder
import com.android.launcher3.taskbar.TaskbarInsetsController
-import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_DURATION
import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_START_DELAY
+import com.android.launcher3.taskbar.TaskbarStashController.TRANSIENT_TASKBAR_STASH_ALPHA_DURATION
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_DURATION
@@ -305,7 +305,8 @@
animatorSet.play(
createBackgroundAlphaAnimator(isStashed).apply {
- val alphaDuration = if (isStashed) duration else TASKBAR_STASH_ALPHA_DURATION
+ val alphaDuration =
+ if (isStashed) duration else TRANSIENT_TASKBAR_STASH_ALPHA_DURATION
val alphaDelay = if (isStashed) TASKBAR_STASH_ALPHA_START_DELAY else 0L
this.duration = max(0L, alphaDuration - alphaDelay)
this.startDelay = alphaDelay
@@ -317,7 +318,7 @@
bubbleBarBubbleAlpha
.animateToValue(getBarAlphaStart(isStashed), getBarAlphaEnd(isStashed))
.apply {
- this.duration = TASKBAR_STASH_ALPHA_DURATION
+ this.duration = TRANSIENT_TASKBAR_STASH_ALPHA_DURATION
this.startDelay = TASKBAR_STASH_ALPHA_START_DELAY
this.interpolator = LINEAR
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index f9b4dab..6482f34 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -55,6 +55,7 @@
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import com.android.internal.logging.InstanceId;
@@ -187,7 +188,8 @@
@Nullable
private final ProxyUnfoldTransitionProvider mUnfoldTransitionProvider;
- private SystemUiProxy(Context context) {
+ @VisibleForTesting
+ protected SystemUiProxy(Context context) {
mContext = context;
mAsyncHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleMessageAsync);
final Intent baseIntent = new Intent().setPackage(mContext.getPackageName());
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendControllerTest.kt
new file mode 100644
index 0000000..f3fff9f
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendControllerTest.kt
@@ -0,0 +1,114 @@
+/*
+ * 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.launcher3.taskbar
+
+import android.animation.AnimatorTestRule
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING
+import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER
+import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TOUCHING
+import com.android.launcher3.taskbar.rules.TaskbarModeRule
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.quickstep.SystemUiProxy
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+import org.junit.runners.model.Statement
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelTablet2023"])
+class TaskbarAutohideSuspendControllerTest {
+
+ private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+
+ @get:Rule(order = 0) val animatorTestRule = AnimatorTestRule(this)
+ @get:Rule(order = 1)
+ val systemUiProxyRule = TestRule { base, _ ->
+ object : Statement() {
+ override fun evaluate() {
+ getInstrumentation().runOnMainSync {
+ context.applicationContext.putObject(
+ SystemUiProxy.INSTANCE,
+ object : SystemUiProxy(context) {
+ override fun notifyTaskbarAutohideSuspend(suspend: Boolean) {
+ latestSuspendNotification = suspend
+ }
+ },
+ )
+ }
+ base.evaluate()
+ }
+ }
+ }
+ @get:Rule(order = 2) val taskbarModeRule = TaskbarModeRule(context)
+ @get:Rule(order = 3) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @InjectController lateinit var autohideSuspendController: TaskbarAutohideSuspendController
+ @InjectController lateinit var stashController: TaskbarStashController
+
+ private var latestSuspendNotification: Boolean? = null
+
+ @Test
+ fun testUpdateFlag_suspendInLauncher_notifiesSuspend() {
+ getInstrumentation().runOnMainSync {
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER, true)
+ }
+ assertThat(latestSuspendNotification).isTrue()
+ }
+
+ @Test
+ fun testUpdateFlag_toggleSuspendDraggingTwice_notifiesUnsuspend() {
+ getInstrumentation().runOnMainSync {
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, true)
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, false)
+ }
+ assertThat(latestSuspendNotification).isFalse()
+ }
+
+ @Test
+ fun testUpdateFlag_resetsAlreadyUnsetFlag_noNotifyUnsuspend() {
+ getInstrumentation().runOnMainSync {
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, false)
+ }
+ assertThat(latestSuspendNotification).isNull()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateFlag_suspendTransientTaskbarForTouch_cancelsAutoStashTimeout() {
+ // Unstash and verify alarm.
+ getInstrumentation().runOnMainSync {
+ stashController.updateAndAnimateTransientTaskbar(false)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.timeoutAlarm.alarmPending()).isTrue()
+
+ // EDU opens while unstashed.
+ getInstrumentation().runOnMainSync {
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_TOUCHING, true)
+ }
+ assertThat(stashController.timeoutAlarm.alarmPending()).isFalse()
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarScrimViewControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarScrimViewControllerTest.kt
new file mode 100644
index 0000000..3524961
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarScrimViewControllerTest.kt
@@ -0,0 +1,163 @@
+/*
+ * 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.launcher3.taskbar
+
+import android.animation.AnimatorTestRule
+import android.view.View.GONE
+import android.view.View.VISIBLE
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.taskbar.rules.TaskbarModeRule
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.quickstep.SystemUiProxy
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
+import com.android.wm.shell.shared.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelTablet2023"])
+class TaskbarScrimViewControllerTest {
+ private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+
+ @get:Rule(order = 0) val taskbarModeRule = TaskbarModeRule(context)
+ @get:Rule(order = 1) val animatorTestRule = AnimatorTestRule(this)
+ @get:Rule(order = 2) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @InjectController lateinit var scrimViewController: TaskbarScrimViewController
+
+ // Default animation duration.
+ private val animationDuration =
+ context.resources.getInteger(android.R.integer.config_mediumAnimTime).toLong()
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibleChanged_onlyTaskbarVisible_noScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ scrimViewController.updateStateForSysuiFlags(0, true)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibilityChanged_pinnedTaskbarVisibleWithBubblesExpanded_showsScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ animatorTestRule.advanceTimeBy(animationDuration)
+ }
+
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(BUBBLE_EXPANDED_SCRIM_ALPHA)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibilityChanged_pinnedTaskbarHiddenDuringScrim_hidesScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(BUBBLE_EXPANDED_SCRIM_ALPHA)
+
+ getInstrumentation().runOnMainSync {
+ scrimViewController.onTaskbarVisibilityChanged(GONE)
+ animatorTestRule.advanceTimeBy(animationDuration)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibilityChanged_notificationsOverPinnedTaskbarAndBubbles_noScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.updateStateForSysuiFlags(
+ SYSUI_STATE_BUBBLES_EXPANDED or SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE,
+ true,
+ )
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibilityChanged_pinnedTaskbarWithBubbleMenu_darkerScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ scrimViewController.updateStateForSysuiFlags(
+ SYSUI_STATE_BUBBLES_EXPANDED or SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED,
+ true,
+ )
+ }
+ assertThat(scrimViewController.scrimAlpha).isGreaterThan(BUBBLE_EXPANDED_SCRIM_ALPHA)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testOnTaskbarVisibilityChanged_stashedTaskbarWithBubbles_noScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnClick_scrimShown_performsSystemBack() {
+ var backPressed = false
+ context.applicationContext.putObject(
+ SystemUiProxy.INSTANCE,
+ object : SystemUiProxy(context) {
+ override fun onBackPressed() {
+ backPressed = true
+ }
+ },
+ )
+
+ getInstrumentation().runOnMainSync {
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ }
+ assertThat(scrimViewController.scrimView.isClickable).isTrue()
+
+ getInstrumentation().runOnMainSync { scrimViewController.scrimView.performClick() }
+ assertThat(backPressed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testOnClick_scrimHidden_notClickable() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ }
+ assertThat(scrimViewController.scrimView.isClickable).isFalse()
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt
new file mode 100644
index 0000000..e736446
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt
@@ -0,0 +1,681 @@
+/*
+ * 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.launcher3.taskbar
+
+import android.animation.AnimatorTestRule
+import android.platform.test.annotations.EnableFlags
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.R
+import com.android.launcher3.taskbar.StashedHandleViewController.ALPHA_INDEX_STASHED
+import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_OVERVIEW
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_DEVICE_LOCKED
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IME
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_AUTO
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_SMALL_SCREEN
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_SYSUI
+import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION
+import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION_FOR_IME
+import com.android.launcher3.taskbar.TaskbarStashController.TRANSIENT_TASKBAR_STASH_ALPHA_DURATION
+import com.android.launcher3.taskbar.TaskbarStashController.TRANSIENT_TASKBAR_STASH_DURATION
+import com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_STASH
+import com.android.launcher3.taskbar.bubbles.BubbleControllers
+import com.android.launcher3.taskbar.rules.TaskbarModeRule
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.THREE_BUTTONS
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
+import com.android.launcher3.taskbar.rules.TaskbarPinningPreferenceRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.UserSetupMode
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING
+import com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_BAR
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelTablet2023"])
+class TaskbarStashControllerTest {
+ private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+
+ @get:Rule(order = 0) val taskbarModeRule = TaskbarModeRule(context)
+ @get:Rule(order = 1) val taskbarPinningPreferenceRule = TaskbarPinningPreferenceRule(context)
+ @get:Rule(order = 2) val animatorTestRule = AnimatorTestRule(this)
+ @get:Rule(order = 3) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @InjectController lateinit var stashController: TaskbarStashController
+ @InjectController lateinit var viewController: TaskbarViewController
+ @InjectController lateinit var stashedHandleViewController: StashedHandleViewController
+ @InjectController lateinit var dragLayerController: TaskbarDragLayerController
+ @InjectController lateinit var autohideSuspendController: TaskbarAutohideSuspendController
+ @InjectController lateinit var bubbleControllers: Optional<BubbleControllers>
+
+ private val activityContext by taskbarUnitTestRule::activityContext
+
+ // Disable hardware keyboard mode during tests.
+ @Before fun enableSoftwareIme() = TaskbarStashController.enableSoftwareImeForTests(true)
+
+ @After fun resetIme() = TaskbarStashController.enableSoftwareImeForTests(false)
+
+ @After fun cancelTimeoutIfExists() = stashController.cancelTimeoutIfExists()
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testInit_transientMode_stashedInApp() {
+ assertThat(stashController.isStashedInApp).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testInit_pinnedMode_unstashedInApp() {
+ assertThat(stashController.isStashedInApp).isFalse()
+ }
+
+ @Test
+ @UserSetupMode
+ @TaskbarMode(PINNED)
+ fun testInit_userSetupWithPinnedMode_stashedInApp() {
+ assertThat(stashController.isStashedInApp).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testSetSetupUiVisible_true_stashedInApp() {
+ getInstrumentation().runOnMainSync { stashController.setSetupUIVisible(true) }
+ assertThat(stashController.isStashedInApp).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testSetSetupUiVisible_false_unstashedInApp() {
+ getInstrumentation().runOnMainSync { stashController.setSetupUIVisible(false) }
+ assertThat(stashController.isStashedInApp).isFalse()
+ }
+
+ @Test
+ fun testRecreateAsTransient_timeoutStarted() {
+ taskbarPinningPreferenceRule.isPinned = true
+ activityContext.controllers.sharedState?.taskbarWasPinned = true
+
+ taskbarPinningPreferenceRule.isPinned = false
+ assertThat(stashController.timeoutAlarm.alarmPending()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testSupportsVisualStashing_transientMode_supported() {
+ assertThat(stashController.supportsVisualStashing()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testSupportsVisualStashing_pinnedMode_supported() {
+ assertThat(stashController.supportsVisualStashing()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(THREE_BUTTONS)
+ fun testSupportsVisualStashing_threeButtonsMode_unsupported() {
+ assertThat(stashController.supportsVisualStashing()).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testGetStashDuration_transientMode() {
+ assertThat(stashController.stashDuration).isEqualTo(TRANSIENT_TASKBAR_STASH_DURATION)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetStashDuration_pinnedMode() {
+ assertThat(stashController.stashDuration).isEqualTo(TASKBAR_STASH_DURATION)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsStashed_pinnedInApp_isUnstashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testIsStashed_transientInApp_isStashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testIsStashed_transientNotInApp_isUnstashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ fun testIsStashed_stashedInLauncherState_isStashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testIsStashed_transientInOverview_isUnstashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.updateStateForFlag(FLAG_IN_OVERVIEW, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsStashed_pinnedInOverviewWithIme_isStashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.updateStateForFlag(FLAG_IN_OVERVIEW, true)
+ stashController.updateStateForFlag(FLAG_STASHED_IME, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsStashed_pinnedTaskbarWithPinnedApp_isStashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, true)
+ stashController.updateStateForFlag(FLAG_STASHED_SYSUI, true) // App pinned.
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ fun testIsInStashedLauncherState_flagUnset_false() {
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, false)
+ assertThat(stashController.isInStashedLauncherState).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(THREE_BUTTONS)
+ fun testIsInStashedLauncherState_flagSetInThreeButtonsMode_false() {
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, true)
+ assertThat(stashController.isInStashedLauncherState).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsInStashedLauncherState_flagSetInPinnedMode_true() {
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, true)
+ assertThat(stashController.isInStashedLauncherState).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsTaskbarVisibleAndNotStashing_pinnedButNotVisible_false() {
+ getInstrumentation().runOnMainSync {
+ viewController.taskbarIconAlpha.get(ALPHA_INDEX_STASH).value = 0f
+ }
+ assertThat(stashController.isTaskbarVisibleAndNotStashing).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testIsTaskbarVisibleAndNotStashing_visibleButStashed_false() {
+ getInstrumentation().runOnMainSync {
+ viewController.taskbarIconAlpha.get(ALPHA_INDEX_STASH).value = 1f
+ }
+ assertThat(stashController.isTaskbarVisibleAndNotStashing).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsTaskbarVisibleAndNotStashing_pinnedAndVisible_true() {
+ getInstrumentation().runOnMainSync {
+ viewController.taskbarIconAlpha.get(ALPHA_INDEX_STASH).value = 1f
+ }
+ assertThat(stashController.isTaskbarVisibleAndNotStashing).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testGetTouchableHeight_isStashed_stashedHeight() {
+ assertThat(stashController.touchableHeight).isEqualTo(stashController.stashedHeight)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testGetTouchableHeight_unstashedTransientMode_heightAndBottomMargin() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, false)
+ stashController.applyState(0)
+ }
+
+ val expectedHeight =
+ activityContext.deviceProfile.run { taskbarHeight + taskbarBottomMargin }
+ assertThat(stashController.touchableHeight).isEqualTo(expectedHeight)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetTouchableHeight_pinnedMode_taskbarHeight() {
+ assertThat(stashController.touchableHeight)
+ .isEqualTo(activityContext.deviceProfile.taskbarHeight)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testGetContentHeightToReportToApps_transientMode_stashedHeight() {
+ assertThat(stashController.contentHeightToReportToApps)
+ .isEqualTo(stashController.stashedHeight)
+ }
+
+ @Test
+ @TaskbarMode(THREE_BUTTONS)
+ fun testGetContentHeightToReportToApps_threeButtonsMode_taskbarHeight() {
+ assertThat(stashController.contentHeightToReportToApps)
+ .isEqualTo(activityContext.deviceProfile.taskbarHeight)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetContentHeightToReportToApps_pinnedMode_taskbarHeight() {
+ assertThat(stashController.contentHeightToReportToApps)
+ .isEqualTo(activityContext.deviceProfile.taskbarHeight)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ @UserSetupMode
+ fun testGetContentHeightToReportToApps_pinnedInSetupMode_setupWizardInsets() {
+ assertThat(stashController.contentHeightToReportToApps)
+ .isEqualTo(context.resources.getDimensionPixelSize(R.dimen.taskbar_suw_insets))
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetContentHeightToReportToApps_pinnedModeButFolded_stashedHeight() {
+ getInstrumentation().runOnMainSync {
+ stashedHandleViewController.stashedHandleAlpha.get(ALPHA_INDEX_STASHED).value = 1f
+ stashController.updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, true)
+ }
+ assertThat(stashController.contentHeightToReportToApps)
+ .isEqualTo(stashController.stashedHeight)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetContentHeightToReportToApps_homeDisabledWhenFolded_zeroHeight() {
+ getInstrumentation().runOnMainSync {
+ stashedHandleViewController.stashedHandleAlpha.get(ALPHA_INDEX_STASHED).value = 1f
+ stashedHandleViewController.setIsHomeButtonDisabled(true)
+ stashController.updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, true)
+ }
+ assertThat(stashController.contentHeightToReportToApps).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testGetTappableHeightToReportToApps_transientMode_zeroHeight() {
+ assertThat(stashController.tappableHeightToReportToApps).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetTappableHeightToReportToApps_pinnedMode_taskbarHeight() {
+ assertThat(stashController.tappableHeightToReportToApps)
+ .isEqualTo(activityContext.deviceProfile.taskbarHeight)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_unstashTaskbar_updatesState() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateAndAnimateTransientTaskbar(false)
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_runUnstashAnimation_startsTaskbarTimeout() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateAndAnimateTransientTaskbar(false)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.timeoutAlarm.alarmPending()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_finishTaskbarTimeout_taskbarStashes() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateAndAnimateTransientTaskbar(false)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.timeoutAlarm.alarmPending()).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ stashController.timeoutAlarm.finishAlarm()
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_autoHideSuspendedForEdu_remainsUnstashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateAndAnimateTransientTaskbar(false)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+
+ getInstrumentation().runOnMainSync {
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_EDU_OPEN, true)
+ stashController.updateAndAnimateTransientTaskbar(true)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_unstashTaskbarWithBubbles_bubbleBarUnstashes() {
+ getInstrumentation().runOnMainSync {
+ bubbleControllers.get().bubbleBarViewController.setHiddenForBubbles(false)
+ bubbleControllers.get().bubbleStashController.stashBubbleBarImmediate()
+ stashController.updateAndAnimateTransientTaskbar(false, true)
+ }
+ assertThat(bubbleControllers.get().bubbleStashController.isStashed).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_unstashTaskbarWithoutBubbles_bubbleBarStashed() {
+ getInstrumentation().runOnMainSync {
+ bubbleControllers.get().bubbleBarViewController.setHiddenForBubbles(false)
+ bubbleControllers.get().bubbleStashController.stashBubbleBarImmediate()
+ stashController.updateAndAnimateTransientTaskbar(false, false)
+ }
+ assertThat(bubbleControllers.get().bubbleStashController.isStashed).isTrue()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_stashTaskbarWithBubbles_bubbleBarStashes() {
+ getInstrumentation().runOnMainSync {
+ bubbleControllers.get().bubbleBarViewController.setHiddenForBubbles(false)
+ bubbleControllers.get().bubbleStashController.showBubbleBarImmediate()
+ stashController.updateAndAnimateTransientTaskbar(true, true)
+ }
+ assertThat(bubbleControllers.get().bubbleStashController.isStashed).isTrue()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_stashTaskbarWithoutBubbles_bubbleBarUnstashed() {
+ getInstrumentation().runOnMainSync {
+ bubbleControllers.get().bubbleBarViewController.setHiddenForBubbles(false)
+ bubbleControllers.get().bubbleStashController.showBubbleBarImmediate()
+ stashController.updateAndAnimateTransientTaskbar(true, false)
+ }
+ assertThat(bubbleControllers.get().bubbleStashController.isStashed).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_bubbleBarExpandedBeforeTimeout_expandedAfterwards() {
+ getInstrumentation().runOnMainSync {
+ bubbleControllers.get().bubbleBarViewController.setHiddenForBubbles(false)
+ bubbleControllers.get().bubbleBarViewController.isExpanded = true
+ stashController.updateAndAnimateTransientTaskbar(false)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.timeoutAlarm.alarmPending()).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ stashController.timeoutAlarm.finishAlarm()
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(bubbleControllers.get().bubbleBarViewController.isExpanded).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testToggleTaskbarStash_pinnedMode_doesNothing() {
+ getInstrumentation().runOnMainSync { stashController.toggleTaskbarStash() }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testToggleTaskbarStash_transientMode_unstashesTaskbar() {
+ getInstrumentation().runOnMainSync { stashController.toggleTaskbarStash() }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testToggleTaskbarStash_twiceInTransientMode_stashesTaskbar() {
+ getInstrumentation().runOnMainSync {
+ stashController.toggleTaskbarStash()
+ stashController.toggleTaskbarStash()
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testToggleTaskbarStash_notInAppWithTransientMode_doesNothing() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.applyState(0)
+ stashController.toggleTaskbarStash()
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testAnimateTransientTaskbar_bubblesShownInOverview_stashesTaskbar() {
+ // Start in Overview. Should unstash Taskbar.
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, false)
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.updateStateForFlag(FLAG_IN_OVERVIEW, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isFalse()
+
+ // Expand bubbles. Should stash Taskbar.
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, false)
+ animatorTestRule.advanceTimeBy(TASKBAR_STASH_DURATION)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testAnimatePinnedTaskbar_imeShown_replacesIconsWithHandle() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, false)
+ animatorTestRule.advanceTimeBy(TASKBAR_STASH_DURATION_FOR_IME)
+ }
+ assertThat(viewController.areIconsVisible()).isFalse()
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testAnimatePinnedTaskbar_imeHidden_replacesHandleWithIcons() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, true)
+ animatorTestRule.advanceTimeBy(0)
+ }
+
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(0, true)
+ animatorTestRule.advanceTimeBy(0)
+ }
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isFalse()
+ assertThat(viewController.areIconsVisible()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testAnimatePinnedTaskbar_imeHidden_verifyAnimationDuration() {
+ // Start with IME shown.
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, true)
+ animatorTestRule.advanceTimeBy(0)
+ }
+
+ // Hide IME with animation.
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(0, false)
+ // Fast forward without start delay.
+ animatorTestRule.advanceTimeBy(TASKBAR_STASH_DURATION_FOR_IME)
+ }
+ // Icons should not be visible yet due to start delay.
+ assertThat(viewController.areIconsVisible()).isFalse()
+
+ // Advance by start delay retroactively. Animation should complete.
+ getInstrumentation().runOnMainSync {
+ animatorTestRule.advanceTimeBy(stashController.taskbarStashStartDelayForIme)
+ }
+ assertThat(viewController.areIconsVisible()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(THREE_BUTTONS)
+ fun testAnimateThreeButtonsTaskbar_imeShown_hidesIconsAndBg() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, false)
+ animatorTestRule.advanceTimeBy(TASKBAR_STASH_DURATION_FOR_IME)
+ }
+ assertThat(viewController.areIconsVisible()).isFalse()
+ assertThat(dragLayerController.imeBgTaskbar.value).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(THREE_BUTTONS)
+ fun testAnimateThreeButtonsTaskbar_imeHidden_showsIconsAndBg() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, false)
+ animatorTestRule.advanceTimeBy(TASKBAR_STASH_DURATION_FOR_IME)
+ }
+
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(0, false)
+ animatorTestRule.advanceTimeBy(
+ TASKBAR_STASH_DURATION_FOR_IME + stashController.taskbarStashStartDelayForIme
+ )
+ }
+ assertThat(viewController.areIconsVisible()).isTrue()
+ assertThat(dragLayerController.imeBgTaskbar.value).isEqualTo(1)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testSetSystemGestureInProgress_whileImeShown_unstashesTaskbar() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, true)
+ animatorTestRule.advanceTimeBy(0)
+ }
+
+ getInstrumentation().runOnMainSync {
+ stashController.setSystemGestureInProgress(true)
+ animatorTestRule.advanceTimeBy(
+ TASKBAR_STASH_DURATION_FOR_IME + stashController.taskbarStashStartDelayForIme
+ )
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testUnlockTransition_pinnedMode_fadesOutHandle() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, false)
+ stashController.applyState()
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUnlockTransition_transientMode_fadesOutHandleEarly() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, false)
+ stashController.applyState()
+ // Time it takes for just the handle to hide (full stash animation is longer).
+ animatorTestRule.advanceTimeBy(TRANSIENT_TASKBAR_STASH_ALPHA_DURATION)
+ }
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isFalse()
+ }
+}
+
+private fun TaskbarStashController.updateStateForFlag(flag: Int, value: Boolean) {
+ updateStateForFlag(flag.toLong(), value)
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt
index 43d924a..f783e40 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt
@@ -199,8 +199,8 @@
assertThat(editText?.hasFocus()).isTrue()
}
- private companion object {
- private val TEST_APPS =
+ companion object {
+ val TEST_APPS =
Array(16) {
AppInfo(
ComponentName(
@@ -213,6 +213,6 @@
)
}
- private val TEST_PREDICTED_APPS = TEST_APPS.take(4).map { WorkspaceItemInfo(it) }
+ val TEST_PREDICTED_APPS = TEST_APPS.take(4).map { WorkspaceItemInfo(it) }
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewControllerTest.kt
new file mode 100644
index 0000000..04f02e9
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewControllerTest.kt
@@ -0,0 +1,156 @@
+/*
+ * 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.launcher3.taskbar.allapps
+
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.R
+import com.android.launcher3.appprediction.AppsDividerView
+import com.android.launcher3.appprediction.AppsDividerView.DividerType
+import com.android.launcher3.appprediction.PredictionRowView
+import com.android.launcher3.taskbar.TaskbarStashController
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_AUTO
+import com.android.launcher3.taskbar.allapps.TaskbarAllAppsControllerTest.Companion.TEST_PREDICTED_APPS
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayController
+import com.android.launcher3.taskbar.rules.TaskbarModeRule
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
+import com.android.launcher3.taskbar.rules.TaskbarPreferenceRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT
+import com.android.launcher3.util.TestUtil
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023"])
+class TaskbarAllAppsViewControllerTest {
+
+ private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+
+ @get:Rule(order = 0) val taskbarModeRule = TaskbarModeRule(context)
+ @get:Rule(order = 1)
+ val allAppsVisitedPreferenceRule =
+ TaskbarPreferenceRule(context, ALL_APPS_VISITED_COUNT.prefItem)
+ @get:Rule(order = 2) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @InjectController lateinit var overlayController: TaskbarOverlayController
+ @InjectController lateinit var stashController: TaskbarStashController
+
+ private val searchSessionController =
+ TestUtil.getOnUiThread { TaskbarSearchSessionController.newInstance(context) }
+
+ @After
+ fun cleanUpSearchSessionController() {
+ getInstrumentation().runOnMainSync { searchSessionController.onDestroy() }
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testShow_transientMode_stashesTaskbar() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_IN_APP_AUTO.toLong(), false)
+ stashController.applyState(0)
+ }
+
+ val viewController = createViewController()
+ getInstrumentation().runOnMainSync { viewController.show(false) }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testShow_pinnedMode_taskbarDoesNotStash() {
+ val viewController = createViewController()
+ getInstrumentation().runOnMainSync { viewController.show(false) }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testHide_transientMode_unstashesTaskbar() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_IN_APP_AUTO.toLong(), false)
+ stashController.applyState(0)
+ }
+
+ val viewController = createViewController()
+ getInstrumentation().runOnMainSync { viewController.show(false) }
+ getInstrumentation().runOnMainSync { viewController.close(false) }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ fun testShow_firstAllAppsVisit_hasAllAppsTextDivider() {
+ allAppsVisitedPreferenceRule.value = 0
+ val viewController = createViewController()
+ getInstrumentation().runOnMainSync { viewController.show(false) }
+
+ val appsView = overlayController.requestWindow().appsView
+ getInstrumentation().runOnMainSync {
+ appsView.floatingHeaderView
+ .findFixedRowByType(PredictionRowView::class.java)
+ .setPredictedApps(TEST_PREDICTED_APPS)
+ }
+
+ val dividerView =
+ appsView.floatingHeaderView.findFixedRowByType(AppsDividerView::class.java)
+ assertThat(dividerView.dividerType).isEqualTo(DividerType.ALL_APPS_LABEL)
+ }
+
+ @Test
+ fun testShow_maxAllAppsVisitedCount_hasLineDivider() {
+ allAppsVisitedPreferenceRule.value = ALL_APPS_VISITED_COUNT.maxCount
+ val viewController = createViewController()
+ getInstrumentation().runOnMainSync { viewController.show(false) }
+
+ val appsView = overlayController.requestWindow().appsView
+ getInstrumentation().runOnMainSync {
+ appsView.floatingHeaderView
+ .findFixedRowByType(PredictionRowView::class.java)
+ .setPredictedApps(TEST_PREDICTED_APPS)
+ }
+
+ val dividerView =
+ appsView.floatingHeaderView.findFixedRowByType(AppsDividerView::class.java)
+ assertThat(dividerView.dividerType).isEqualTo(DividerType.LINE)
+ }
+
+ private fun createViewController(): TaskbarAllAppsViewController {
+ return TestUtil.getOnUiThread {
+ val overlayContext = overlayController.requestWindow()
+ TaskbarAllAppsViewController(
+ overlayContext,
+ overlayContext.layoutInflater.inflate(
+ R.layout.taskbar_all_apps_sheet,
+ overlayContext.dragLayer,
+ false,
+ ) as TaskbarAllAppsSlideInView,
+ taskbarUnitTestRule.activityContext.controllers,
+ searchSessionController,
+ /* showKeyboard= */ false, // Covered in TaskbarAllAppsControllerTest.
+ )
+ }
+ }
+}
diff --git a/src/com/android/launcher3/Alarm.java b/src/com/android/launcher3/Alarm.java
index fb8088c..e516ad0 100644
--- a/src/com/android/launcher3/Alarm.java
+++ b/src/com/android/launcher3/Alarm.java
@@ -20,6 +20,8 @@
import android.os.Looper;
import android.os.SystemClock;
+import androidx.annotation.VisibleForTesting;
+
public class Alarm implements Runnable{
// if we reach this time and the alarm hasn't been cancelled, call the listener
private long mAlarmTriggerTime;
@@ -96,4 +98,13 @@
public long getLastSetTimeout() {
return mLastSetTimeout;
}
+
+ /** Simulates the alarm firing for tests. */
+ @VisibleForTesting
+ public void finishAlarm() {
+ if (!mAlarmPending) return;
+ mAlarmPending = false;
+ mHandler.removeCallbacks(this);
+ mAlarmListener.onAlarm(this);
+ }
}