Merge "Register all apps key gesture event in quickstep launcher" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
a2b5b589dc
@@ -49,6 +49,9 @@
|
||||
-->
|
||||
<uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES_FULL" />
|
||||
|
||||
<!-- Permission required to listen to recent, all app key gestures. -->
|
||||
<uses-permission android:name="android.permission.MANAGE_KEY_GESTURES" />
|
||||
|
||||
<!-- Permission required to start a WidgetPickerActivity. -->
|
||||
<permission android:name="${applicationId}.permission.START_WIDGET_PICKER_ACTIVITY"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
@@ -34,6 +34,7 @@ import static com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE;
|
||||
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
|
||||
import static com.android.launcher3.util.DisplayController.CHANGE_SHOW_LOCKED_TASKBAR;
|
||||
import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
|
||||
import static com.android.quickstep.util.SystemActionConstants.ACTION_SHOW_TASKBAR;
|
||||
@@ -44,12 +45,16 @@ import android.annotation.SuppressLint;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentCallbacks;
|
||||
import android.content.Context;
|
||||
import android.content.IIntentReceiver;
|
||||
import android.content.IIntentSender;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Trace;
|
||||
import android.provider.Settings;
|
||||
import android.util.ArraySet;
|
||||
@@ -116,6 +121,12 @@ public class TaskbarManager implements DisplayDecorationListener {
|
||||
|
||||
// TODO: b/397738606 - Remove all logs with this tag after the growth framework is integrated.
|
||||
public static final String GROWTH_FRAMEWORK_TAG = "Growth Framework";
|
||||
/**
|
||||
* An integer extra specifying the ID of the display on which the All Apps UI should be shown
|
||||
* or hidden.
|
||||
*/
|
||||
public static final String EXTRA_KEY_ALL_APPS_ACTION_DISPLAY_ID =
|
||||
"com.android.quickstep.allapps.display_id";
|
||||
|
||||
/**
|
||||
* All the configurations which do not initiate taskbar recreation.
|
||||
@@ -575,10 +586,19 @@ public class TaskbarManager implements DisplayDecorationListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles All Apps for Taskbar or Launcher depending on the current state.
|
||||
* Shows or hides the All Apps view in the Taskbar or Launcher, based on its current
|
||||
* visibility on the System UI tracked focused display.
|
||||
*/
|
||||
public void toggleAllAppsSearch() {
|
||||
TaskbarActivityContext taskbar = getTaskbarForDisplay(getFocusedDisplayId());
|
||||
toggleAllAppsSearchForDisplay(getFocusedDisplayId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows or hides the All Apps view in the Taskbar or Launcher, based on its current
|
||||
* visibility on the given display, with ID {@code displayId}.
|
||||
*/
|
||||
public void toggleAllAppsSearchForDisplay(int displayId) {
|
||||
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
||||
if (taskbar == null) {
|
||||
// Home All Apps should be toggled from this class, because the controllers are not
|
||||
// initialized when Taskbar is disabled (i.e. TaskbarActivityContext is null).
|
||||
@@ -1713,6 +1733,28 @@ public class TaskbarManager implements DisplayDecorationListener {
|
||||
debugTaskbarManager(debugReason, mPrimaryDisplayId, verbose);
|
||||
}
|
||||
|
||||
/** Creates a {@link PendingIntent} for showing / hiding the all apps UI. */
|
||||
public PendingIntent createAllAppsPendingIntent() {
|
||||
return new PendingIntent(new IIntentSender.Stub() {
|
||||
@Override
|
||||
public void send(int code, Intent intent, String resolvedType,
|
||||
IBinder allowlistToken, IIntentReceiver finishedReceiver,
|
||||
String requiredPermission, Bundle options) {
|
||||
MAIN_EXECUTOR.execute(() -> {
|
||||
int displayId = -1;
|
||||
if (options != null) {
|
||||
displayId = options.getInt(EXTRA_KEY_ALL_APPS_ACTION_DISPLAY_ID, -1);
|
||||
}
|
||||
if (displayId == -1) {
|
||||
toggleAllAppsSearch();
|
||||
} else {
|
||||
toggleAllAppsSearchForDisplay(displayId);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs verbose debug information about the TaskbarManager for a specific display.
|
||||
*/
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.view.accessibility.AccessibilityManager
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.util.SettingsCache
|
||||
import com.android.launcher3.util.SettingsCache.OnChangeListener
|
||||
import com.android.quickstep.input.QuickstepKeyGestureEventsManager
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
private val USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(USER_SETUP_COMPLETE)
|
||||
@@ -41,6 +42,7 @@ private val USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(USER_SETUP_COMPL
|
||||
class AllAppsActionManager(
|
||||
private val context: Context,
|
||||
private val bgExecutor: Executor,
|
||||
private val quickstepKeyGestureEventsManager: QuickstepKeyGestureEventsManager,
|
||||
private val createAllAppsPendingIntent: () -> PendingIntent,
|
||||
) {
|
||||
|
||||
@@ -92,17 +94,22 @@ class AllAppsActionManager(
|
||||
val accessibilityManager =
|
||||
context.getSystemService(AccessibilityManager::class.java) ?: return@execute
|
||||
if (shouldRegisterAction) {
|
||||
val allAppsPendingIntent = createAllAppsPendingIntent()
|
||||
accessibilityManager.registerSystemAction(
|
||||
RemoteAction(
|
||||
Icon.createWithResource(context, R.drawable.ic_apps),
|
||||
context.getString(R.string.all_apps_label),
|
||||
context.getString(R.string.all_apps_label),
|
||||
createAllAppsPendingIntent(),
|
||||
allAppsPendingIntent,
|
||||
),
|
||||
GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
|
||||
)
|
||||
quickstepKeyGestureEventsManager.registerAllAppsKeyGestureEvent(
|
||||
allAppsPendingIntent
|
||||
)
|
||||
} else {
|
||||
accessibilityManager.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS)
|
||||
quickstepKeyGestureEventsManager.unregisterAllAppsKeyGestureEvent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,11 +42,8 @@ import static com.android.quickstep.InputConsumerUtils.newConsumer;
|
||||
import static com.android.quickstep.InputConsumerUtils.tryCreateAssistantInputConsumer;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.IIntentReceiver;
|
||||
import android.content.IIntentSender;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Region;
|
||||
@@ -101,6 +98,7 @@ import com.android.quickstep.OverviewComponentObserver.OverviewChangeListener;
|
||||
import com.android.quickstep.fallback.window.RecentsDisplayModel;
|
||||
import com.android.quickstep.fallback.window.RecentsWindowFlags;
|
||||
import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler;
|
||||
import com.android.quickstep.input.QuickstepKeyGestureEventsManager;
|
||||
import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
@@ -639,6 +637,8 @@ public class TouchInteractionService extends Service {
|
||||
|
||||
private DisplayRepository mDisplayRepository;
|
||||
|
||||
private QuickstepKeyGestureEventsManager mQuickstepKeyGestureEventsHandler;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
@@ -653,8 +653,10 @@ public class TouchInteractionService extends Service {
|
||||
mRotationTouchHelperRepository = RotationTouchHelper.REPOSITORY_INSTANCE.get(this);
|
||||
mRecentsDisplayModel = RecentsDisplayModel.getINSTANCE().get(this);
|
||||
mSystemDecorationChangeObserver = SystemDecorationChangeObserver.getINSTANCE().get(this);
|
||||
mAllAppsActionManager = new AllAppsActionManager(
|
||||
this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
|
||||
mQuickstepKeyGestureEventsHandler = new QuickstepKeyGestureEventsManager(this);
|
||||
mAllAppsActionManager = new AllAppsActionManager(this, UI_HELPER_EXECUTOR,
|
||||
mQuickstepKeyGestureEventsHandler,
|
||||
() -> mTaskbarManager.createAllAppsPendingIntent());
|
||||
mTrackpadsConnected = new ActiveTrackpadList(this, () -> {
|
||||
if (mInputMonitorCompat != null && !mTrackpadsConnected.isEmpty()) {
|
||||
// Don't destroy and reinitialize input monitor due to trackpad
|
||||
@@ -812,17 +814,6 @@ public class TouchInteractionService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private PendingIntent createAllAppsPendingIntent() {
|
||||
return new PendingIntent(new IIntentSender.Stub() {
|
||||
@Override
|
||||
public void send(int code, Intent intent, String resolvedType,
|
||||
IBinder allowlistToken, IIntentReceiver finishedReceiver,
|
||||
String requiredPermission, Bundle options) {
|
||||
MAIN_EXECUTOR.execute(() -> mTaskbarManager.toggleAllAppsSearch());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void onSystemUiFlagsChanged(@SystemUiStateFlags long lastSysUIFlags, int displayId) {
|
||||
if (LockedUserState.get(this).isUserUnlocked()) {
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.content.Context
|
||||
import android.hardware.input.InputManager
|
||||
import android.hardware.input.InputManager.KeyGestureEventHandler
|
||||
import android.hardware.input.KeyGestureEvent
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.launcher3.taskbar.TaskbarManager
|
||||
import com.android.window.flags.Flags
|
||||
|
||||
/**
|
||||
* Manages subscription and unsubscription to launcher's key gesture events, e.g. all apps and
|
||||
* recents (incl. alt + tab).
|
||||
*/
|
||||
class QuickstepKeyGestureEventsManager(context: Context) {
|
||||
private val inputManager = requireNotNull(context.getSystemService(InputManager::class.java))
|
||||
private var allAppsPendingIntent: PendingIntent? = null
|
||||
@VisibleForTesting
|
||||
val allAppsKeyGestureEventHandler =
|
||||
object : KeyGestureEventHandler {
|
||||
override fun handleKeyGestureEvent(event: KeyGestureEvent, focusedToken: IBinder?) {
|
||||
if (!Flags.enableKeyGestureHandlerForRecents()) {
|
||||
return
|
||||
}
|
||||
if (event.keyGestureType != KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS) {
|
||||
Log.e(TAG, "Ignore unsupported key gesture event type: ${event.keyGestureType}")
|
||||
return
|
||||
}
|
||||
|
||||
allAppsPendingIntent?.send(
|
||||
Bundle().apply {
|
||||
putInt(TaskbarManager.EXTRA_KEY_ALL_APPS_ACTION_DISPLAY_ID, event.displayId)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Registers the all apps key gesture events. */
|
||||
fun registerAllAppsKeyGestureEvent(allAppsPendingIntent: PendingIntent) {
|
||||
if (Flags.enableKeyGestureHandlerForRecents()) {
|
||||
this.allAppsPendingIntent = allAppsPendingIntent
|
||||
inputManager.registerKeyGestureEventHandler(
|
||||
listOf(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS),
|
||||
allAppsKeyGestureEventHandler,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Unregisters the all apps key gesture events. */
|
||||
fun unregisterAllAppsKeyGestureEvent() {
|
||||
if (Flags.enableKeyGestureHandlerForRecents()) {
|
||||
inputManager.unregisterKeyGestureEventHandler(allAppsKeyGestureEventHandler)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val TAG = "KeyGestureEventsHandler"
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -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 {},
|
||||
|
||||
+24
-2
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+143
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user