Revert "Revert "Add TaskbarModeSwitchRule to test both transient/persistent taskbar.""

This reverts commit e7011d2b876770dcefde509e8775bb65b6d1d8e1.

Reason for revert: attempt to fix test issues

- Instead of using SharedPrefs which can be flaky anyways,
  we pass along a boolean to test transient taskbar when
  we are in the test harness

Bug: 257549303
Test: TaplTestsTaskbar
Change-Id: I7c15a97363adc377f29853c1fe60b1960c77bfc3
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index 7292c44..f5a8253 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -38,6 +38,7 @@
     name: "launcher3-quickstep-oop-tests-src",
     path: "tests",
     srcs: [
+        "tests/src/com/android/quickstep/TaskbarModeSwitchRule.java",
         "tests/src/com/android/quickstep/NavigationModeSwitchRule.java",
         "tests/src/com/android/quickstep/AbstractQuickStepTest.java",
         "tests/src/com/android/quickstep/TaplTestsQuickstep.java",
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 3c9e96f..4882842 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -23,6 +23,7 @@
 
 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
+import static com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
@@ -306,7 +307,8 @@
         int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                 | WindowManager.LayoutParams.FLAG_SLIPPERY
                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-        if (DisplayController.isTransientTaskbar(this)) {
+        if (DisplayController.isTransientTaskbar(this)
+                && !IS_RUNNING_IN_TEST_HARNESS) {
             windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
         }
@@ -874,12 +876,25 @@
     }
 
     /**
+     * Enables the auto timeout for taskbar stashing. This method should only be used for taskbar
+     * testing.
+     */
+    @VisibleForTesting
+    public void enableBlockingTimeoutDuringTests(boolean enableBlockingTimeout) {
+        mControllers.taskbarStashController.enableBlockingTimeoutDuringTests(enableBlockingTimeout);
+    }
+
+    /**
      * Unstashes the Taskbar if it is stashed. This method should only be used to unstash the
      * taskbar at the end of a test.
      */
     @VisibleForTesting
     public void unstashTaskbarIfStashed() {
-        mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
+        if (DisplayController.isTransientTaskbar(this)) {
+            mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
+        } else {
+            mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
+        }
     }
 
     protected boolean isUserSetupComplete() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 72ae1d1..b53e9c5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -37,6 +37,7 @@
 import android.view.ViewConfiguration;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.launcher3.Alarm;
@@ -169,6 +170,7 @@
     private boolean mEnableManualStashingDuringTests = false;
 
     private final Alarm mTimeoutAlarm = new Alarm();
+    private boolean mEnableBlockingTimeoutDuringTests = false;
 
     // Evaluate whether the handle should be stashed
     private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
@@ -267,11 +269,21 @@
      * Enables support for manual stashing. This should only be used to add this functionality
      * to Launcher specific tests.
      */
+    @VisibleForTesting
     public void enableManualStashingDuringTests(boolean enableManualStashing) {
         mEnableManualStashingDuringTests = enableManualStashing;
     }
 
     /**
+     * Enables the auto timeout for taskbar stashing. This method should only be used for taskbar
+     * testing.
+     */
+    @VisibleForTesting
+    public void enableBlockingTimeoutDuringTests(boolean enableBlockingTimeout) {
+        mEnableBlockingTimeoutDuringTests = enableBlockingTimeout;
+    }
+
+    /**
      * Sets the flag indicating setup UI is visible
      */
     protected void setSetupUIVisible(boolean isVisible) {
@@ -846,12 +858,12 @@
      * Attempts to start timer to auto hide the taskbar based on time.
      */
     public void tryStartTaskbarTimeout() {
-        if (!DisplayController.isTransientTaskbar(mActivity)) {
+        if (!DisplayController.isTransientTaskbar(mActivity)
+                || mIsStashed
+                || mEnableBlockingTimeoutDuringTests) {
             return;
         }
-        if (mIsStashed) {
-            return;
-        }
+
         cancelTimeoutIfExists();
 
         mTimeoutAlarm.setOnAlarmListener(this::onTaskbarTimeout);
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 9621ce6..6f124b8 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -11,9 +11,11 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.R;
+import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.testing.TestInformationHandler;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.TISBindHelper;
 
@@ -120,6 +122,30 @@
                                 .getCurrentActivityContext()
                                 .getTaskbarAllAppsTopPadding());
             }
+
+            case TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT:
+                runOnTISBinder(tisBinder -> {
+                    enableBlockingTimeout(tisBinder, true);
+                });
+                return response;
+
+            case TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT:
+                runOnTISBinder(tisBinder -> {
+                    enableBlockingTimeout(tisBinder, false);
+                });
+                return response;
+
+            case TestProtocol.REQUEST_ENABLE_TRANSIENT_TASKBAR:
+                runOnTISBinder(tisBinder -> {
+                    enableTransientTaskbar(tisBinder, true);
+                });
+                return response;
+
+            case TestProtocol.REQUEST_DISABLE_TRANSIENT_TASKBAR:
+                runOnTISBinder(tisBinder -> {
+                    enableTransientTaskbar(tisBinder, false);
+                });
+                return response;
         }
 
         return super.call(method, arg, extras);
@@ -149,6 +175,20 @@
                 enable);
     }
 
+    private void enableBlockingTimeout(
+            TouchInteractionService.TISBinder tisBinder, boolean enable) {
+        // Allow null-pointer to catch illegal states.
+        tisBinder.getTaskbarManager().getCurrentActivityContext().enableBlockingTimeoutDuringTests(
+                enable);
+    }
+
+    private void enableTransientTaskbar(
+            TouchInteractionService.TISBinder tisBinder, boolean enable) {
+        // Allow null-pointer to catch illegal states.
+        TaskbarActivityContext context = tisBinder.getTaskbarManager().getCurrentActivityContext();
+        DisplayController.INSTANCE.get(context).enableTransientTaskbarForTests(enable);
+    }
+
     /**
      * Runs the given command on the UI thread, after ensuring we are connected to
      * TouchInteractionService.
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
index e2774c0..2c5825f 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -39,6 +39,7 @@
     protected TestRule getRulesInsideActivityMonitor() {
         return RuleChain.
                 outerRule(new NavigationModeSwitchRule(mLauncher)).
+                around(new TaskbarModeSwitchRule(mLauncher)).
                 around(super.getRulesInsideActivityMonitor());
     }
 
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index e5e2cf3..eded1c9 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -51,7 +51,7 @@
 
 /**
  * Test rule that allows executing a test with Quickstep on and then Quickstep off.
- * The test should be annotated with @QuickstepOnOff.
+ * The test should be annotated with @NavigationModeSwitch.
  */
 public class NavigationModeSwitchRule implements TestRule {
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index 9337cb5..0b8bc10 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -17,6 +17,8 @@
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
+
 import static junit.framework.TestCase.assertEquals;
 
 import android.content.Intent;
@@ -27,6 +29,7 @@
 import com.android.launcher3.tapl.Taskbar;
 import com.android.launcher3.ui.TaplTestsLauncher3;
 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 
 import org.junit.After;
 import org.junit.Assume;
@@ -53,21 +56,25 @@
         TaplTestsLauncher3.initialize(this);
 
         startAppFast(CALCULATOR_APP_PACKAGE);
+        mLauncher.enableBlockTimeout(true);
         mLauncher.showTaskbarIfHidden();
     }
 
     @After
     public void tearDown() {
         mLauncher.useDefaultWorkspaceLayoutOnReload();
+        mLauncher.enableBlockTimeout(false);
     }
 
     @Test
+    @TaskbarModeSwitch(mode = PERSISTENT)
     public void testHideShowTaskbar() {
         getTaskbar().hide();
         mLauncher.getLaunchedAppState().showTaskbar();
     }
 
     @Test
+    @TaskbarModeSwitch(mode = PERSISTENT)
     public void testHideTaskbarPersistsOnRecreate() {
         getTaskbar().hide();
         mLauncher.recreateTaskbar();
@@ -75,16 +82,19 @@
     }
 
     @Test
+    @TaskbarModeSwitch
     public void testLaunchApp() throws Exception {
         getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
     }
 
     @Test
+    @TaskbarModeSwitch
     public void testOpenMenu() throws Exception {
         getTaskbar().getAppIcon(TEST_APP_NAME).openMenu();
     }
 
     @Test
+    @TaskbarModeSwitch
     public void testLaunchShortcut() throws Exception {
         getTaskbar().getAppIcon(TEST_APP_NAME)
                 .openDeepShortcutMenu()
@@ -95,6 +105,7 @@
     @Test
     @ScreenRecord // b/231615831
     @PortraitLandscape
+    @TaskbarModeSwitch
     public void testLaunchAppInSplitscreen() throws Exception {
         getTaskbar().getAppIcon(TEST_APP_NAME).dragToSplitscreen(
                 TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
@@ -103,6 +114,7 @@
     @Test
     @ScreenRecord // b/231615831
     @PortraitLandscape
+    @TaskbarModeSwitch
     public void testLaunchShortcutInSplitscreen() throws Exception {
         getTaskbar().getAppIcon(TEST_APP_NAME)
                 .openDeepShortcutMenu()
@@ -111,16 +123,19 @@
     }
 
     @Test
+    @TaskbarModeSwitch
     public void testLaunchApp_FromTaskbarAllApps() throws Exception {
         getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
     }
 
     @Test
+    @TaskbarModeSwitch
     public void testOpenMenu_FromTaskbarAllApps() throws Exception {
         getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).openMenu();
     }
 
     @Test
+    @TaskbarModeSwitch
     public void testLaunchShortcut_FromTaskbarAllApps() throws Exception {
         getTaskbar().openAllApps()
                 .getAppIcon(TEST_APP_NAME)
@@ -132,6 +147,7 @@
     @Test
     @ScreenRecord // b/231615831
     @PortraitLandscape
+    @TaskbarModeSwitch
     public void testLaunchAppInSplitscreen_FromTaskbarAllApps() throws Exception {
         getTaskbar().openAllApps()
                 .getAppIcon(TEST_APP_NAME)
@@ -141,6 +157,7 @@
     @Test
     @ScreenRecord // b/231615831
     @PortraitLandscape
+    @TaskbarModeSwitch
     public void testLaunchShortcutInSplitscreen_FromTaskbarAllApps() throws Exception {
         getTaskbar().openAllApps()
                 .getAppIcon(TEST_APP_NAME)
diff --git a/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
new file mode 100644
index 0000000..9e41f74
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 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.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.quickstep.TaskbarModeSwitchRule.Mode.ALL;
+import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
+import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.TestHelpers;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.rule.FailureWatcher;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Test rule that allows executing a test multiple times with different conditions
+ * ie. with transient taskbar enabled and disabled.
+ * The test should be annotated with @TaskbarModeSwitch.
+ */
+public class TaskbarModeSwitchRule implements TestRule {
+
+    static final String TAG = "TaskbarModeSwitchRule";
+
+    public static final int WAIT_TIME_MS = 10000;
+
+    public enum Mode {
+        TRANSIENT, PERSISTENT, ALL
+    }
+
+    // Annotation for tests that need to be run with quickstep enabled and disabled.
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface TaskbarModeSwitch {
+        Mode mode() default ALL;
+    }
+
+    private final LauncherInstrumentation mLauncher;
+
+    public TaskbarModeSwitchRule(LauncherInstrumentation launcher) {
+        mLauncher = launcher;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        if (TestHelpers.isInLauncherProcess()
+                && description.getAnnotation(TaskbarModeSwitch.class) != null) {
+            Mode mode = description.getAnnotation(TaskbarModeSwitch.class).mode();
+            return new Statement() {
+                @Override
+                public void evaluate() throws Throwable {
+                    mLauncher.enableDebugTracing();
+                    final boolean wasTransientTaskbarMode =
+                            isTaskbarTransientMode(getInstrumentation().getTargetContext());
+                    try {
+                        if (mode == TRANSIENT || mode == ALL) {
+                            evaluateWithTransientTaskbar();
+                        }
+                        if (mode == PERSISTENT || mode == ALL) {
+                            evaluateWithPersistentTaskbar();
+                        }
+                    } catch (Throwable e) {
+                        Log.e(TAG, "Error", e);
+                        throw e;
+                    } finally {
+                        Log.d(TAG, "In Finally block");
+                        setTaskbarMode(mLauncher, wasTransientTaskbarMode, description);
+                    }
+                }
+
+                private void evaluateWithPersistentTaskbar() throws Throwable {
+                    setTaskbarMode(mLauncher, false, description);
+                    base.evaluate();
+                }
+
+                private void evaluateWithTransientTaskbar() throws Throwable {
+                    setTaskbarMode(mLauncher, true, description);
+                    base.evaluate();
+                }
+            };
+        } else {
+            return base;
+        }
+    }
+
+    private static boolean isTaskbarTransientMode(Context context) {
+        return DisplayController.isTransientTaskbar(context);
+    }
+
+    public static void setTaskbarMode(LauncherInstrumentation launcher,
+            boolean expectTransientTaskbar, Description description) throws Exception {
+        launcher.enableTransientTaskbar(expectTransientTaskbar);
+        launcher.recreateTaskbar();
+
+        Context context = getInstrumentation().getTargetContext();
+        assertTrue(launcher, "Couldn't set taskbar=" + expectTransientTaskbar,
+                isTaskbarTransientMode(context) == expectTransientTaskbar, description);
+
+        AbstractLauncherUiTest.checkDetectedLeaks(launcher);
+    }
+
+    private static void assertTrue(LauncherInstrumentation launcher, String message,
+            boolean condition, Description description) {
+        launcher.checkForAnomaly(true, true);
+        if (!condition) {
+            final AssertionError assertionError = new AssertionError(message);
+            if (description != null) {
+                FailureWatcher.onError(launcher, description, assertionError);
+            }
+            throw assertionError;
+        }
+    }
+}