Disable All Apps keyboard shortcut during user setup.
Flag: EXEMPT bugfix Fix: 394238663 Test: go/testedequals Change-Id: I4a9175613686a358bd62800789b30262d9dc39cb
This commit is contained in:
@@ -612,6 +612,7 @@ public class TaskbarManager {
|
||||
*/
|
||||
public void setSetupUIVisible(boolean isVisible) {
|
||||
mSharedState.setupUIVisible = isVisible;
|
||||
mAllAppsActionManager.setSetupUiVisible(isVisible);
|
||||
TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
|
||||
if (taskbar != null) {
|
||||
taskbar.setSetupUIVisible(isVisible);
|
||||
|
||||
@@ -21,10 +21,16 @@ import android.app.PendingIntent
|
||||
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 @@ class AllAppsActionManager(
|
||||
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 @@ class AllAppsActionManager(
|
||||
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 @@ class AllAppsActionManager(
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+20
-6
@@ -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 @@ class SettingsCacheSandbox {
|
||||
{
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
||||
+81
-8
@@ -18,32 +18,59 @@ package com.android.quickstep
|
||||
|
||||
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 @@ class AllAppsActionManagerTest {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user