Merge changes from topic "taskbar-pinning-preference-rule-fixes" into main

* changes:
  Add subrule for controlling an individual Taskbar preference.
  Taskbar Pinning Preference Rule fixes.
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRule.kt
index 60c8dec..d417790 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRule.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRule.kt
@@ -16,12 +16,13 @@
 
 package com.android.launcher3.taskbar.rules
 
-import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
-import com.android.launcher3.ConstantItem
-import com.android.launcher3.LauncherPrefs
+import android.platform.test.flag.junit.FlagsParameterization
+import android.platform.test.flag.junit.SetFlagsRule
+import com.android.launcher3.Flags.FLAG_ENABLE_TASKBAR_PINNING
 import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
 import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
-import kotlin.reflect.KProperty
+import com.android.launcher3.util.DisplayController
+import org.junit.rules.RuleChain
 import org.junit.rules.TestRule
 import org.junit.runner.Description
 import org.junit.runners.model.Statement
@@ -39,33 +40,26 @@
  */
 class TaskbarPinningPreferenceRule(context: TaskbarWindowSandboxContext) : TestRule {
 
-    private val prefs = LauncherPrefs.get(context)
+    private val setFlagsRule =
+        SetFlagsRule(FlagsParameterization(mapOf(FLAG_ENABLE_TASKBAR_PINNING to true)))
+    private val pinningRule = TaskbarPreferenceRule(context, TASKBAR_PINNING)
+    private val desktopPinningRule = TaskbarPreferenceRule(context, TASKBAR_PINNING_IN_DESKTOP_MODE)
+    private val ruleChain =
+        RuleChain.outerRule(setFlagsRule).around(pinningRule).around(desktopPinningRule)
 
-    var isPinned by PinningPreference(TASKBAR_PINNING)
-    var isPinnedInDesktopMode by PinningPreference(TASKBAR_PINNING_IN_DESKTOP_MODE)
+    var isPinned by pinningRule::value
+    var isPinnedInDesktopMode by desktopPinningRule::value
 
     override fun apply(base: Statement, description: Description): Statement {
         return object : Statement() {
             override fun evaluate() {
-                val wasPinned = isPinned
-                val wasPinnedInDesktopMode = isPinnedInDesktopMode
+                DisplayController.enableTaskbarModePreferenceForTests(true)
                 try {
-                    base.evaluate()
+                    ruleChain.apply(base, description).evaluate()
                 } finally {
-                    isPinned = wasPinned
-                    isPinnedInDesktopMode = wasPinnedInDesktopMode
+                    DisplayController.enableTaskbarModePreferenceForTests(false)
                 }
             }
         }
     }
-
-    private inner class PinningPreference(private val constantItem: ConstantItem<Boolean>) {
-        operator fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
-            return prefs.get(constantItem)
-        }
-
-        operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
-            getInstrumentation().runOnMainSync { prefs.put(constantItem, value) }
-        }
-    }
 }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
index 3f0a238..a709133 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
@@ -19,6 +19,8 @@
 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.window.WindowManagerProxy
+import com.google.android.apps.nexuslauncher.deviceemulator.TestWindowManagerProxy
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.Description
@@ -51,6 +53,11 @@
 
     @Test
     fun testEnableDesktopPinning_verifyDisplayController() {
+        context.applicationContext.putObject(
+            WindowManagerProxy.INSTANCE,
+            TestWindowManagerProxy(context).apply { isInDesktopMode = true },
+        )
+
         onSetup {
             preferenceRule.isPinned = false
             preferenceRule.isPinnedInDesktopMode = true
@@ -60,6 +67,11 @@
 
     @Test
     fun testDisableDesktopPinning_verifyDisplayController() {
+        context.applicationContext.putObject(
+            WindowManagerProxy.INSTANCE,
+            TestWindowManagerProxy(context).apply { isInDesktopMode = true },
+        )
+
         onSetup {
             preferenceRule.isPinned = false
             preferenceRule.isPinnedInDesktopMode = false
@@ -83,12 +95,14 @@
 
     /** Executes [runTest] after the [preferenceRule] setup phase completes. */
     private fun onSetup(runTest: () -> Unit) {
-        preferenceRule.apply(
-            object : Statement() {
-                override fun evaluate() = runTest()
-            },
-            DESCRIPTION,
-        )
+        preferenceRule
+            .apply(
+                object : Statement() {
+                    override fun evaluate() = runTest()
+                },
+                DESCRIPTION,
+            )
+            .evaluate()
     }
 
     private companion object {
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRule.kt
new file mode 100644
index 0000000..a76a77d
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRule.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.rules
+
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.ConstantItem
+import com.android.launcher3.LauncherPrefs
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Rule for modifying a Taskbar preference.
+ *
+ * The original preference value is restored on teardown.
+ */
+class TaskbarPreferenceRule<T : Any>(
+    context: TaskbarWindowSandboxContext,
+    private val constantItem: ConstantItem<T>
+) : TestRule {
+
+    private val prefs = LauncherPrefs.get(context)
+
+    var value: T
+        get() = prefs.get(constantItem)
+        set(value) = getInstrumentation().runOnMainSync { prefs.put(constantItem, value) }
+
+    override fun apply(base: Statement, description: Description): Statement {
+        return object : Statement() {
+            override fun evaluate() {
+                val originalValue = value
+                try {
+                    base.evaluate()
+                } finally {
+                    value = originalValue
+                }
+            }
+        }
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt
new file mode 100644
index 0000000..22d2079
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.rules
+
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.Description
+import org.junit.runner.RunWith
+import org.junit.runners.model.Statement
+
+@RunWith(LauncherMultivalentJUnit::class)
+class TaskbarPreferenceRuleTest {
+
+    private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+    private val preferenceRule = TaskbarPreferenceRule(context, TASKBAR_PINNING)
+
+    @Test
+    fun testSetup_toggleBoolean_updatesPreferences() {
+        val originalValue = preferenceRule.value
+        onSetup {
+            preferenceRule.value = !preferenceRule.value
+            assertThat(preferenceRule.value).isNotEqualTo(originalValue)
+        }
+    }
+
+    @Test
+    fun testTeardown_afterTogglingBoolean_preferenceReset() {
+        val originalValue = preferenceRule.value
+        onSetup { preferenceRule.value = !preferenceRule.value }
+        assertThat(preferenceRule.value).isEqualTo(originalValue)
+    }
+
+    private fun onSetup(runTest: () -> Unit) {
+        preferenceRule
+            .apply(
+                object : Statement() {
+                    override fun evaluate() = runTest()
+                },
+                DESCRIPTION,
+            )
+            .evaluate()
+    }
+
+    private companion object {
+        private val DESCRIPTION =
+            Description.createSuiteDescription(TaskbarPreferenceRule::class.java)
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContext.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContext.kt
index 321e7a9..ee21df8 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContext.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContext.kt
@@ -50,7 +50,7 @@
         )
     }
 
-    override fun getApplicationContext() = application
+    override fun getApplicationContext(): SandboxContext = application
 
     companion object {
         /** Creates a [TaskbarWindowSandboxContext] to sandbox [base] for Taskbar tests. */
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 860f852..b1e82bb 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -77,6 +77,7 @@
 
     private static final String TAG = "DisplayController";
     private static final boolean DEBUG = false;
+    private static boolean sTaskbarModePreferenceStatusForTests = false;
     private static boolean sTransientTaskbarStatusForTests = true;
 
     // TODO(b/254119092) remove all logs with this tag
@@ -207,6 +208,14 @@
     }
 
     /**
+     * Enables respecting taskbar mode preference during test.
+     */
+    @VisibleForTesting
+    public static void enableTaskbarModePreferenceForTests(boolean enable) {
+        sTaskbarModePreferenceStatusForTests = enable;
+    }
+
+    /**
      * Returns whether the taskbar is pinned in gesture navigation mode.
      */
     public static boolean isPinnedTaskbar(Context context) {
@@ -465,7 +474,7 @@
             if (navigationMode != NavigationMode.NO_BUTTON) {
                 return false;
             }
-            if (Utilities.isRunningInTestHarness()) {
+            if (Utilities.isRunningInTestHarness() && !sTaskbarModePreferenceStatusForTests) {
                 // TODO(b/258604917): Once ENABLE_TASKBAR_PINNING is enabled, remove usage of
                 //  sTransientTaskbarStatusForTests and update test to directly
                 //  toggle shared preference to switch transient taskbar on/off.