Merge "Register all apps key gesture event in quickstep launcher" into main

This commit is contained in:
Treehugger Robot
2025-04-10 09:57:21 -07:00
committed by Android (Google) Code Review
8 changed files with 314 additions and 22 deletions

View File

@@ -35,6 +35,7 @@ import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
import com.android.launcher3.util.TestUtil
import com.android.quickstep.AllAppsActionManager
import com.android.quickstep.fallback.window.RecentsDisplayModel
import com.android.quickstep.input.QuickstepKeyGestureEventsManager
import java.lang.reflect.Field
import java.lang.reflect.ParameterizedType
import java.util.Locale
@@ -108,7 +109,11 @@ class TaskbarUnitTestRule(
object :
TaskbarManager(
context,
AllAppsActionManager(context, UI_HELPER_EXECUTOR) {
AllAppsActionManager(
context,
UI_HELPER_EXECUTOR,
QuickstepKeyGestureEventsManager(context),
) {
PendingIntent(IIntentSender.Default())
},
object : TaskbarNavButtonCallbacks {},

View File

@@ -18,6 +18,7 @@ package com.android.quickstep
import android.app.PendingIntent
import android.content.IIntentSender
import android.hardware.input.InputManager
import android.provider.Settings
import android.provider.Settings.Secure.USER_SETUP_COMPLETE
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -29,6 +30,7 @@ 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.android.quickstep.input.QuickstepKeyGestureEventsManager
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
@@ -39,6 +41,11 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.kotlin.any
import org.mockito.kotlin.doNothing
import org.mockito.kotlin.whenever
private const val TIMEOUT = 5L
private val USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(USER_SETUP_COMPLETE)
@@ -49,24 +56,29 @@ class AllAppsActionManagerTest {
private val bgExecutor = UI_HELPER_EXECUTOR
@get:Rule val context = SandboxApplication()
private val inputManager = context.spyService(InputManager::class.java)
private val settingsCacheSandbox =
SettingsCacheSandbox().also { it[USER_SETUP_COMPLETE_URI] = 1 }
private val quickstepKeyGestureEventsManager = spy(QuickstepKeyGestureEventsManager(context))
private val allAppsActionManager by
lazy(LazyThreadSafetyMode.NONE) {
AllAppsActionManager(context, bgExecutor) {
AllAppsActionManager(context, bgExecutor, quickstepKeyGestureEventsManager) {
callbackSemaphore.release()
PendingIntent(IIntentSender.Default())
}
}
@Before
fun initDaggerComponent() {
fun setUp() {
context.initDaggerComponent(
DaggerAllAppsActionManagerTestComponent.builder()
.bindSettingsCache(settingsCacheSandbox.cache)
)
doNothing().whenever(inputManager).registerKeyGestureEventHandler(any(), any())
doNothing().whenever(inputManager).unregisterKeyGestureEventHandler(any())
}
@After fun destroyManager() = allAppsActionManager.onDestroy()
@@ -74,15 +86,19 @@ class AllAppsActionManagerTest {
@Test
fun taskbarPresent_actionRegistered() {
allAppsActionManager.isTaskbarPresent = true
TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to register.
assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
assertThat(allAppsActionManager.isActionRegistered).isTrue()
verify(quickstepKeyGestureEventsManager).registerAllAppsKeyGestureEvent(any())
}
@Test
fun homeAndOverviewSame_actionRegistered() {
allAppsActionManager.isHomeAndOverviewSame = true
TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to register.
assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
assertThat(allAppsActionManager.isActionRegistered).isTrue()
verify(quickstepKeyGestureEventsManager).registerAllAppsKeyGestureEvent(any())
}
@Test
@@ -93,6 +109,7 @@ class AllAppsActionManagerTest {
allAppsActionManager.isTaskbarPresent = false
TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to unregister.
assertThat(allAppsActionManager.isActionRegistered).isFalse()
verify(quickstepKeyGestureEventsManager).unregisterAllAppsKeyGestureEvent()
}
@Test
@@ -103,6 +120,7 @@ class AllAppsActionManagerTest {
TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to unregister.
assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
assertThat(allAppsActionManager.isActionRegistered).isFalse()
verify(quickstepKeyGestureEventsManager).unregisterAllAppsKeyGestureEvent()
}
@Test
@@ -136,8 +154,10 @@ class AllAppsActionManagerTest {
allAppsActionManager.isTaskbarPresent = true
settingsCacheSandbox[USER_SETUP_COMPLETE_URI] = 1
TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to register.
assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
assertThat(allAppsActionManager.isActionRegistered).isTrue()
verify(quickstepKeyGestureEventsManager).registerAllAppsKeyGestureEvent(any())
}
@Test
@@ -146,8 +166,10 @@ class AllAppsActionManagerTest {
allAppsActionManager.isTaskbarPresent = true
allAppsActionManager.isSetupUiVisible = false
TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to register.
assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
assertThat(allAppsActionManager.isActionRegistered).isTrue()
verify(quickstepKeyGestureEventsManager).registerAllAppsKeyGestureEvent(any())
}
}

View File

@@ -0,0 +1,143 @@
/*
* Copyright (C) 2025 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.input
import android.app.PendingIntent
import android.hardware.input.InputManager
import android.hardware.input.KeyGestureEvent
import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS
import android.os.Bundle
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.taskbar.TaskbarManager.EXTRA_KEY_ALL_APPS_ACTION_DISPLAY_ID
import com.android.launcher3.util.SandboxApplication
import com.android.window.flags.Flags
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.KArgumentCaptor
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doNothing
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoInteractions
import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
class QuickstepKeyGestureEventsHandlerTest {
@get:Rule val context = SandboxApplication()
@get:Rule val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
private val inputManager = context.spyService(InputManager::class.java)
private val keyGestureEventsManager = QuickstepKeyGestureEventsManager(context)
private val allAppsPendingIntent: PendingIntent = mock()
private val keyGestureEventsCaptor: KArgumentCaptor<List<Int>> = argumentCaptor()
private val bundleCaptor: KArgumentCaptor<Bundle> = argumentCaptor()
@Before
fun setup() {
doNothing().whenever(inputManager).registerKeyGestureEventHandler(any(), any())
doNothing().whenever(inputManager).unregisterKeyGestureEventHandler(any())
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_KEY_GESTURE_HANDLER_FOR_RECENTS)
fun registerKeyGestureEventsHandler_flagEnabled_registerWithExpectedKeyGestureEvents() {
keyGestureEventsManager.registerAllAppsKeyGestureEvent(allAppsPendingIntent)
verify(inputManager)
.registerKeyGestureEventHandler(
keyGestureEventsCaptor.capture(),
eq(keyGestureEventsManager.allAppsKeyGestureEventHandler),
)
assertThat(keyGestureEventsCaptor.firstValue).containsExactly(KEY_GESTURE_TYPE_ALL_APPS)
}
@Test
@DisableFlags(Flags.FLAG_ENABLE_KEY_GESTURE_HANDLER_FOR_RECENTS)
fun registerKeyGestureEventsHandler_flagDisabled_noRegister() {
keyGestureEventsManager.registerAllAppsKeyGestureEvent(allAppsPendingIntent)
verifyNoInteractions(inputManager)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_KEY_GESTURE_HANDLER_FOR_RECENTS)
fun unregisterKeyGestureEventsHandler_flagEnabled_unregisterHandler() {
keyGestureEventsManager.unregisterAllAppsKeyGestureEvent()
verify(inputManager)
.unregisterKeyGestureEventHandler(
eq(keyGestureEventsManager.allAppsKeyGestureEventHandler)
)
}
@Test
@DisableFlags(Flags.FLAG_ENABLE_KEY_GESTURE_HANDLER_FOR_RECENTS)
fun unregisterKeyGestureEventsHandler_flagDisabled_noUnregister() {
keyGestureEventsManager.unregisterAllAppsKeyGestureEvent()
verifyNoInteractions(inputManager)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_KEY_GESTURE_HANDLER_FOR_RECENTS)
fun handleEvent_flagEnabled_allApps_toggleAllAppsSearchWithDisplayId() {
keyGestureEventsManager.registerAllAppsKeyGestureEvent(allAppsPendingIntent)
keyGestureEventsManager.allAppsKeyGestureEventHandler.handleKeyGestureEvent(
KeyGestureEvent.Builder()
.setDisplayId(TEST_DISPLAY_ID)
.setKeyGestureType(KEY_GESTURE_TYPE_ALL_APPS)
.build(),
/* focusedToken= */ null,
)
verify(allAppsPendingIntent).send(bundleCaptor.capture())
assertThat(bundleCaptor.firstValue.getInt(EXTRA_KEY_ALL_APPS_ACTION_DISPLAY_ID))
.isEqualTo(TEST_DISPLAY_ID)
}
@Test
@DisableFlags(Flags.FLAG_ENABLE_KEY_GESTURE_HANDLER_FOR_RECENTS)
fun handleEvent_flagDisabled_allApps_noInteractionWithTaskbar() {
keyGestureEventsManager.registerAllAppsKeyGestureEvent(allAppsPendingIntent)
keyGestureEventsManager.allAppsKeyGestureEventHandler.handleKeyGestureEvent(
KeyGestureEvent.Builder()
.setDisplayId(TEST_DISPLAY_ID)
.setKeyGestureType(KEY_GESTURE_TYPE_ALL_APPS)
.build(),
/* focusedToken= */ null,
)
verifyNoInteractions(allAppsPendingIntent)
}
private companion object {
const val TEST_DISPLAY_ID = 6789
}
}