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
+ }
}