Merge "Disable All Apps keyboard shortcut during user setup." into main
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index f704254..df3869e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -629,6 +629,7 @@
      */
     public void setSetupUIVisible(boolean isVisible) {
         mSharedState.setupUIVisible = isVisible;
+        mAllAppsActionManager.setSetupUiVisible(isVisible);
         TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
         if (taskbar != null) {
             taskbar.setSetupUIVisible(isVisible);
diff --git a/quickstep/src/com/android/quickstep/AllAppsActionManager.kt b/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
index 6fd68d5..b807a4b 100644
--- a/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
+++ b/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
@@ -21,10 +21,16 @@
 import android.app.RemoteAction
 import android.content.Context
 import android.graphics.drawable.Icon
+import android.provider.Settings
+import android.provider.Settings.Secure.USER_SETUP_COMPLETE
 import android.view.accessibility.AccessibilityManager
 import com.android.launcher3.R
+import com.android.launcher3.util.SettingsCache
+import com.android.launcher3.util.SettingsCache.OnChangeListener
 import java.util.concurrent.Executor
 
+private val USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(USER_SETUP_COMPLETE)
+
 /**
  * Registers a [RemoteAction] for toggling All Apps if needed.
  *
@@ -38,6 +44,12 @@
     private val createAllAppsPendingIntent: () -> PendingIntent,
 ) {
 
+    private val onSettingsChangeListener = OnChangeListener { v -> isUserSetupComplete = v }
+
+    init {
+        SettingsCache.INSTANCE[context].register(USER_SETUP_COMPLETE_URI, onSettingsChangeListener)
+    }
+
     /** `true` if home and overview are the same Activity. */
     var isHomeAndOverviewSame = false
         set(value) {
@@ -52,12 +64,27 @@
             updateSystemAction()
         }
 
+    /** `true` if the setup UI is visible. */
+    var isSetupUiVisible = false
+        set(value) {
+            field = value
+            updateSystemAction()
+        }
+
+    private var isUserSetupComplete =
+        SettingsCache.INSTANCE[context].getValue(USER_SETUP_COMPLETE_URI, 0)
+        set(value) {
+            field = value
+            updateSystemAction()
+        }
+
     /** `true` if the action should be registered. */
     var isActionRegistered = false
         private set
 
     private fun updateSystemAction() {
-        val shouldRegisterAction = isHomeAndOverviewSame || isTaskbarPresent
+        val isInSetupFlow = isSetupUiVisible || !isUserSetupComplete
+        val shouldRegisterAction = (isHomeAndOverviewSame || isTaskbarPresent) && !isInSetupFlow
         if (isActionRegistered == shouldRegisterAction) return
         isActionRegistered = shouldRegisterAction
 
@@ -84,8 +111,10 @@
         isActionRegistered = false
         context
             .getSystemService(AccessibilityManager::class.java)
-            ?.unregisterSystemAction(
-                GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
-            )
+            ?.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS)
+        SettingsCache.INSTANCE[context].unregister(
+            USER_SETUP_COMPLETE_URI,
+            onSettingsChangeListener,
+        )
     }
 }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/util/SettingsCacheSandbox.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/util/SettingsCacheSandbox.kt
index dcd5352..52238c8 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/util/SettingsCacheSandbox.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/util/SettingsCacheSandbox.kt
@@ -17,19 +17,22 @@
 package com.android.launcher3.util
 
 import android.net.Uri
+import com.android.launcher3.util.SettingsCache.OnChangeListener
 import org.mockito.kotlin.any
 import org.mockito.kotlin.doAnswer
 import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 
-/**
- * Provides a sandboxed [SettingsCache] for testing.
- *
- * Note that listeners registered to [cache] will never be invoked.
- */
+/** Provides [SettingsCache] sandboxed from system settings for testing. */
 class SettingsCacheSandbox {
     private val values = mutableMapOf<Uri, Int>()
+    private val listeners = mutableMapOf<Uri, MutableSet<OnChangeListener>>()
 
-    /** Fake cache that delegates [SettingsCache.getValue] to [values]. */
+    /**
+     * Fake cache that delegates:
+     * - [SettingsCache.getValue] to [values]
+     * - [SettingsCache.mListenerMap] to [listeners].
+     */
     val cache =
         mock<SettingsCache> {
             on { getValue(any<Uri>()) } doAnswer { mock.getValue(it.getArgument(0), 1) }
@@ -37,11 +40,22 @@
                 {
                     values.getOrDefault(it.getArgument(0), it.getArgument(1)) == 1
                 }
+
+            doAnswer {
+                    listeners.getOrPut(it.getArgument(0)) { mutableSetOf() }.add(it.getArgument(1))
+                }
+                .whenever(mock)
+                .register(any(), any())
+            doAnswer { listeners[it.getArgument(0)]?.remove(it.getArgument(1)) }
+                .whenever(mock)
+                .unregister(any(), any())
         }
 
     operator fun get(key: Uri): Int? = values[key]
 
     operator fun set(key: Uri, value: Int) {
+        if (value == values[key]) return
         values[key] = value
+        listeners[key]?.forEach { it.onSettingsChanged(value == 1) }
     }
 }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt
index 73b35e8..a1bd107 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt
@@ -18,32 +18,59 @@
 
 import android.app.PendingIntent
 import android.content.IIntentSender
+import android.provider.Settings
+import android.provider.Settings.Secure.USER_SETUP_COMPLETE
 import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppSingleton
+import com.android.launcher3.util.AllModulesForTest
 import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+import com.android.launcher3.util.SandboxApplication
+import com.android.launcher3.util.SettingsCache
+import com.android.launcher3.util.SettingsCacheSandbox
 import com.android.launcher3.util.TestUtil
 import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
 import java.util.concurrent.Semaphore
 import java.util.concurrent.TimeUnit.SECONDS
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
 private const val TIMEOUT = 5L
+private val USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(USER_SETUP_COMPLETE)
 
 @RunWith(AndroidJUnit4::class)
 class AllAppsActionManagerTest {
     private val callbackSemaphore = Semaphore(0)
     private val bgExecutor = UI_HELPER_EXECUTOR
 
-    private val allAppsActionManager =
-        AllAppsActionManager(
-            InstrumentationRegistry.getInstrumentation().targetContext,
-            bgExecutor,
-        ) {
-            callbackSemaphore.release()
-            PendingIntent(IIntentSender.Default())
+    @get:Rule val context = SandboxApplication()
+
+    private val settingsCacheSandbox =
+        SettingsCacheSandbox().also { it[USER_SETUP_COMPLETE_URI] = 1 }
+
+    private val allAppsActionManager by
+        lazy(LazyThreadSafetyMode.NONE) {
+            AllAppsActionManager(context, bgExecutor) {
+                callbackSemaphore.release()
+                PendingIntent(IIntentSender.Default())
+            }
         }
 
+    @Before
+    fun initDaggerComponent() {
+        context.initDaggerComponent(
+            DaggerAllAppsActionManagerTestComponent.builder()
+                .bindSettingsCache(settingsCacheSandbox.cache)
+        )
+    }
+
+    @After fun destroyManager() = allAppsActionManager.onDestroy()
+
     @Test
     fun taskbarPresent_actionRegistered() {
         allAppsActionManager.isTaskbarPresent = true
@@ -88,4 +115,50 @@
         assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
         assertThat(allAppsActionManager.isActionRegistered).isTrue()
     }
+
+    @Test
+    fun taskbarPresent_userSetupIncomplete_actionUnregistered() {
+        settingsCacheSandbox[USER_SETUP_COMPLETE_URI] = 0
+        allAppsActionManager.isTaskbarPresent = true
+        assertThat(allAppsActionManager.isActionRegistered).isFalse()
+    }
+
+    @Test
+    fun taskbarPresent_setupUiVisible_actionUnregistered() {
+        allAppsActionManager.isSetupUiVisible = true
+        allAppsActionManager.isTaskbarPresent = true
+        assertThat(allAppsActionManager.isActionRegistered).isFalse()
+    }
+
+    @Test
+    fun taskbarPresent_userSetupCompleted_actionRegistered() {
+        settingsCacheSandbox[USER_SETUP_COMPLETE_URI] = 0
+        allAppsActionManager.isTaskbarPresent = true
+
+        settingsCacheSandbox[USER_SETUP_COMPLETE_URI] = 1
+        assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+        assertThat(allAppsActionManager.isActionRegistered).isTrue()
+    }
+
+    @Test
+    fun taskbarPresent_setupUiDismissed_actionRegistered() {
+        allAppsActionManager.isSetupUiVisible = true
+        allAppsActionManager.isTaskbarPresent = true
+
+        allAppsActionManager.isSetupUiVisible = false
+        assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+        assertThat(allAppsActionManager.isActionRegistered).isTrue()
+    }
+}
+
+@LauncherAppSingleton
+@Component(modules = [AllModulesForTest::class])
+interface AllAppsActionManagerTestComponent : LauncherAppComponent {
+
+    @Component.Builder
+    interface Builder : LauncherAppComponent.Builder {
+        @BindsInstance fun bindSettingsCache(settingsCache: SettingsCache): Builder
+
+        override fun build(): AllAppsActionManagerTestComponent
+    }
 }