From ec8d20d0ed9ee0629c9d071ce340b381aff152a8 Mon Sep 17 00:00:00 2001 From: Will Osborn Date: Mon, 17 Mar 2025 16:13:34 +0000 Subject: [PATCH] Refactor RecentsAnimationDeviceState and TaskAnimationManager using new PerDisplay library Test: locally tested on Tangor Bug: 399371607 Flag: EXEMPT refactor Change-Id: Ie52f53a2d5dee757a8dc3b19248736bc15e5e0c6 --- Android.bp | 1 + .../dagger/LauncherConcurrencyModule.kt | 72 ++++++ .../launcher3/dagger/PerDisplayModule.kt | 116 ++++++++++ .../android/quickstep/AbsSwipeUpHandler.java | 8 +- .../quickstep/FallbackSwipeHandler.java | 7 +- .../quickstep/LauncherDisplayRepository.kt | 24 ++ .../quickstep/LauncherSwipeHandlerV2.java | 3 +- .../quickstep/OverviewCommandHelper.kt | 10 +- .../RecentsAnimationDeviceState.java | 120 +++++----- .../quickstep/TaskAnimationManager.java | 27 ++- .../quickstep/TouchInteractionService.java | 205 +++++++++++------- .../dagger/QuickstepBaseAppComponent.java | 8 +- .../fallback/window/RecentsDisplayModel.kt | 12 - .../window/RecentsWindowSwipeHandler.java | 4 +- .../OtherActivityInputConsumer.java | 7 + .../recents/di/RecentsDependencies.kt | 26 ++- .../quickstep/util/ActivityPreloadUtil.kt | 3 +- .../android/quickstep/views/RecentsView.java | 3 +- .../util/ActiveGestureProtoLogProxy.java | 9 + .../model/data/TaskViewItemInfoTest.kt | 5 +- .../quickstep/AbsSwipeUpHandlerTestCase.java | 5 +- .../FallbackSwipeHandlerTestCase.java | 1 + .../quickstep/LauncherSwipeHandlerV2Test.kt | 6 +- .../LauncherSwipeHandlerV2TestCase.java | 1 + .../quickstep/OverviewCommandHelperTest.kt | 1 + .../RecentsAnimationDeviceStateTest.kt | 43 +--- .../RecentsWindowSwipeHandlerTestCase.java | 1 + .../quickstep/TaskAnimationManagerTest.java | 3 +- .../AspectRatioSystemShortcutTests.kt | 14 +- .../quickstep/InputConsumerUtilsTest.java | 10 +- .../launcher3/dagger/LauncherAppModule.java | 4 +- .../graphics/LauncherPreviewRenderer.java | 7 +- .../com/android/launcher3/dagger/Modules.kt | 4 + .../android/launcher3/util/DaggerGraphs.kt | 29 ++- 34 files changed, 547 insertions(+), 252 deletions(-) create mode 100644 quickstep/src/com/android/launcher3/dagger/LauncherConcurrencyModule.kt create mode 100644 quickstep/src/com/android/launcher3/dagger/PerDisplayModule.kt create mode 100644 quickstep/src/com/android/quickstep/LauncherDisplayRepository.kt diff --git a/Android.bp b/Android.bp index 2c4fb37908..9c2d97ba88 100644 --- a/Android.bp +++ b/Android.bp @@ -481,6 +481,7 @@ android_library { "SettingsLibSettingsTheme", "dagger2", "protolog-group", + "displaylib", ], manifest: "quickstep/AndroidManifest.xml", min_sdk_version: "current", diff --git a/quickstep/src/com/android/launcher3/dagger/LauncherConcurrencyModule.kt b/quickstep/src/com/android/launcher3/dagger/LauncherConcurrencyModule.kt new file mode 100644 index 0000000000..cb2220d589 --- /dev/null +++ b/quickstep/src/com/android/launcher3/dagger/LauncherConcurrencyModule.kt @@ -0,0 +1,72 @@ +/* + * 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.launcher3.dagger + +import android.os.Handler +import android.os.HandlerThread +import android.os.Looper +import android.os.Process +import com.android.launcher3.util.coroutines.DispatcherProvider +import com.android.launcher3.util.coroutines.ProductionDispatchers +import com.android.systemui.dagger.qualifiers.Background +import dagger.Module +import dagger.Provides +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob + +/** Dagger Module for per-display thread handling. */ +@Module +object LauncherConcurrencyModule { + // Slow BG executor can potentially affect UI if UI is waiting for an updated state from this + // thread + private const val BG_SLOW_DISPATCH_THRESHOLD = 1000L + private const val BG_SLOW_DELIVERY_THRESHOLD = 1000L + + /** Background Looper */ + @Provides + @LauncherAppSingleton + @Background + fun provideBgLooper(): Looper { + val thread = HandlerThread("LauncherBg", Process.THREAD_PRIORITY_BACKGROUND) + thread.start() + thread + .getLooper() + .setSlowLogThresholdMs(BG_SLOW_DISPATCH_THRESHOLD, BG_SLOW_DELIVERY_THRESHOLD) + return thread.getLooper() + } + + /** + * Background Handler. + * + * Prefer the Background Executor when possible. + */ + @Provides + @Background + fun provideBgHandler(@Background bgLooper: Looper): Handler = Handler(bgLooper) + + /** CoroutineDispatcher provider. */ + @Provides fun provideCoroutineDispatcherProvider(): DispatcherProvider = ProductionDispatchers + + /** Background CoroutineScope provider. */ + @Provides + @Background + fun provideBgCoroutineScope(dispatcherProvider: DispatcherProvider) = + CoroutineScope( + SupervisorJob() + dispatcherProvider.background + CoroutineName("LauncherBg") + ) +} diff --git a/quickstep/src/com/android/launcher3/dagger/PerDisplayModule.kt b/quickstep/src/com/android/launcher3/dagger/PerDisplayModule.kt new file mode 100644 index 0000000000..5a80c527ff --- /dev/null +++ b/quickstep/src/com/android/launcher3/dagger/PerDisplayModule.kt @@ -0,0 +1,116 @@ +/* + * 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.launcher3.dagger + +import android.content.Context +import android.hardware.display.DisplayManager +import android.os.Handler +import android.util.Log +import android.view.Display.DEFAULT_DISPLAY +import com.android.app.displaylib.DisplayLibBackground +import com.android.app.displaylib.DisplayLibComponent +import com.android.app.displaylib.DisplayRepository +import com.android.app.displaylib.PerDisplayInstanceRepositoryImpl +import com.android.app.displaylib.PerDisplayRepository +import com.android.app.displaylib.SingleInstanceRepositoryImpl +import com.android.app.displaylib.createDisplayLibComponent +import com.android.launcher3.Flags.enableOverviewOnConnectedDisplays +import com.android.launcher3.util.coroutines.DispatcherProvider +import com.android.quickstep.RecentsAnimationDeviceState +import com.android.quickstep.TaskAnimationManager +import com.android.systemui.dagger.qualifiers.Background +import dagger.Binds +import dagger.Module +import dagger.Provides +import kotlinx.coroutines.CoroutineScope + +@Module(includes = [DisplayLibModule::class, PerDisplayRepositoriesModule::class]) +interface PerDisplayModule { + @Binds + @DisplayLibBackground + abstract fun bindDisplayLibBackground(@Background bgScope: CoroutineScope): CoroutineScope +} + +@Module +object PerDisplayRepositoriesModule { + @Provides + fun provideRecentsAnimationDeviceStateRepo( + repositoryFactory: PerDisplayInstanceRepositoryImpl.Factory, + instanceFactory: RecentsAnimationDeviceState.Factory, + ): PerDisplayRepository { + return if (enableOverviewOnConnectedDisplays()) { + repositoryFactory.create("RecentsAnimationDeviceStateRepo", instanceFactory::create) + } else { + SingleInstanceRepositoryImpl( + "RecentsAnimationDeviceStateRepo", + instanceFactory.create(DEFAULT_DISPLAY), + ) + } + } + + @Provides + fun provideTaskAnimationManagerRepo( + repositoryFactory: PerDisplayInstanceRepositoryImpl.Factory, + instanceFactory: TaskAnimationManager.Factory, + ): PerDisplayRepository { + return if (enableOverviewOnConnectedDisplays()) { + repositoryFactory.create("TaskAnimationManagerRepo", instanceFactory::create) + } else { + SingleInstanceRepositoryImpl( + "TaskAnimationManager", + instanceFactory.create(DEFAULT_DISPLAY), + ) + } + } + + @Provides + fun dumpRegistrationLambda(): PerDisplayRepository.InitCallback = + PerDisplayRepository.InitCallback { debugName, _ -> + Log.d("PerDisplayInitCallback", debugName) + } +} + +/** + * Module to bind the DisplayRepository from displaylib to the LauncherAppSingleton dagger graph. + */ +@Module +object DisplayLibModule { + @Provides + @LauncherAppSingleton + fun displayLibComponent( + @ApplicationContext context: Context, + @Background bgHandler: Handler, + @Background bgApplicationScope: CoroutineScope, + coroutineDispatcherProvider: DispatcherProvider, + ): DisplayLibComponent { + val displayManager = context.getSystemService(DisplayManager::class.java) + return createDisplayLibComponent( + displayManager, + bgHandler, + bgApplicationScope, + coroutineDispatcherProvider.background, + ) + } + + @Provides + @LauncherAppSingleton + fun providesDisplayRepositoryFromLib( + displayLibComponent: DisplayLibComponent + ): DisplayRepository { + return displayLibComponent.displayRepository + } +} diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 48630b11d3..15f2496285 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -380,12 +380,12 @@ public abstract class AbsSwipeUpHandler< private final MSDLPlayerWrapper mMSDLPlayerWrapper; public AbsSwipeUpHandler(Context context, - TaskAnimationManager taskAnimationManager, GestureState gestureState, + TaskAnimationManager taskAnimationManager, RecentsAnimationDeviceState deviceState, + GestureState gestureState, long touchTimeMs, boolean continuingLastGesture, InputConsumerController inputConsumer, MSDLPlayerWrapper msdlPlayerWrapper) { super(context, gestureState); - mDeviceState = RecentsAnimationDeviceState.INSTANCE.get(mContext); mContainerInterface = gestureState.getContainerInterface(); mContextInitListener = mContainerInterface.createActivityInitListener(this::onActivityInit); @@ -400,6 +400,7 @@ public abstract class AbsSwipeUpHandler< endLauncherTransitionController(); }, new InputProxyHandlerFactory(mContainerInterface, mGestureState)); mTaskAnimationManager = taskAnimationManager; + mDeviceState = deviceState; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; @@ -2787,6 +2788,7 @@ public abstract class AbsSwipeUpHandler< } public interface Factory { - AbsSwipeUpHandler newHandler(GestureState gestureState, long touchTimeMs); + @Nullable + AbsSwipeUpHandler newHandler(GestureState gestureState, long touchTimeMs); } } diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java index 9365383880..bc60124e74 100644 --- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java @@ -102,11 +102,12 @@ public class FallbackSwipeHandler extends private boolean mAppCanEnterPip; - public FallbackSwipeHandler(Context context, - TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs, + public FallbackSwipeHandler(Context context, TaskAnimationManager taskAnimationManager, + RecentsAnimationDeviceState deviceState, + GestureState gestureState, long touchTimeMs, boolean continuingLastGesture, InputConsumerController inputConsumer, MSDLPlayerWrapper msdlPlayerWrapper) { - super(context, taskAnimationManager, gestureState, touchTimeMs, + super(context, taskAnimationManager, deviceState, gestureState, touchTimeMs, continuingLastGesture, inputConsumer, msdlPlayerWrapper); mRunningOverHome = mGestureState.getRunningTask() != null diff --git a/quickstep/src/com/android/quickstep/LauncherDisplayRepository.kt b/quickstep/src/com/android/quickstep/LauncherDisplayRepository.kt new file mode 100644 index 0000000000..c56d2781f4 --- /dev/null +++ b/quickstep/src/com/android/quickstep/LauncherDisplayRepository.kt @@ -0,0 +1,24 @@ +/* + * 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 + +import com.android.launcher3.util.DaggerSingletonObject +import com.android.quickstep.dagger.QuickstepBaseAppComponent + +object LauncherDisplayRepository { + @JvmStatic val INSTANCE = DaggerSingletonObject(QuickstepBaseAppComponent::getDisplayRepository) +} diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java index 4c56f35d90..90557e5316 100644 --- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -69,9 +69,10 @@ public class LauncherSwipeHandlerV2 extends AbsSwipeUpHandler< QuickstepLauncher, RecentsView, LauncherState> { public LauncherSwipeHandlerV2(Context context, TaskAnimationManager taskAnimationManager, + RecentsAnimationDeviceState deviceState, GestureState gestureState, long touchTimeMs, boolean continuingLastGesture, InputConsumerController inputConsumer, MSDLPlayerWrapper msdlPlayerWrapper) { - super(context, taskAnimationManager, gestureState, touchTimeMs, + super(context, taskAnimationManager, deviceState, gestureState, touchTimeMs, continuingLastGesture, inputConsumer, msdlPlayerWrapper); } diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt index e37fb145ca..0aea994e69 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt @@ -28,6 +28,7 @@ import android.window.TransitionInfo import androidx.annotation.BinderThread import androidx.annotation.UiThread import androidx.annotation.VisibleForTesting +import com.android.app.displaylib.PerDisplayRepository import com.android.app.tracing.traceSection import com.android.internal.jank.Cuj import com.android.launcher3.Flags.enableLargeDesktopWindowingTile @@ -77,6 +78,7 @@ constructor( private val dispatcherProvider: DispatcherProvider = ProductionDispatchers, private val recentsDisplayModel: RecentsDisplayModel, private val taskbarManager: TaskbarManager, + private val taskAnimationManagerRepository: PerDisplayRepository, ) { private val coroutineScope = CoroutineScope(SupervisorJob() + dispatcherProvider.background) @@ -416,6 +418,12 @@ constructor( touchInteractionService .getSwipeUpHandlerFactory(command.displayId) .newHandler(gestureState, command.createTime) + if (interactionHandler == null) { + // Can happen e.g. when a display is disconnected, so try to handle gracefully. + Log.d(TAG, "AbsSwipeUpHandler not available for displayId=${command.displayId})") + ActiveGestureProtoLogProxy.logOnAbsSwipeUpHandlerNotAvailable(command.displayId) + return false + } interactionHandler.setGestureEndCallback { onTransitionComplete(command, interactionHandler, onCallbackResult) } @@ -461,7 +469,7 @@ constructor( } val taskAnimationManager = - recentsDisplayModel.getTaskAnimationManager(command.displayId) + taskAnimationManagerRepository.get(command.displayId) ?: run { Log.e(TAG, "No TaskAnimationManager found for display ${command.displayId}") ActiveGestureProtoLogProxy.logOnTaskAnimationManagerNotAvailable( diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index 9bf63a0ce7..1ceb2c33cf 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -17,7 +17,6 @@ package com.android.quickstep; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.view.Display.DEFAULT_DISPLAY; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static com.android.launcher3.MotionEventsUtils.isTrackpadScroll; @@ -63,11 +62,9 @@ import android.view.ViewConfiguration; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; +import com.android.app.displaylib.PerDisplayRepository; import com.android.launcher3.dagger.ApplicationContext; -import com.android.launcher3.dagger.LauncherAppComponent; -import com.android.launcher3.dagger.LauncherAppSingleton; import com.android.launcher3.util.DaggerSingletonObject; import com.android.launcher3.util.DaggerSingletonTracker; import com.android.launcher3.util.DisplayController; @@ -76,6 +73,7 @@ import com.android.launcher3.util.DisplayController.Info; import com.android.launcher3.util.NavigationMode; import com.android.launcher3.util.SettingsCache; import com.android.quickstep.TopTaskTracker.CachedTaskInfo; +import com.android.quickstep.dagger.QuickstepBaseAppComponent; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ContextualSearchStateManager; import com.android.quickstep.util.GestureExclusionManager; @@ -89,16 +87,14 @@ import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; import java.io.PrintWriter; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import javax.inject.Inject; +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; /** * Manages the state of the system during a swipe up gesture. */ -@LauncherAppSingleton public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, ExclusionListener { static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode"; @@ -107,8 +103,9 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E private static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 3f; private static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 1.414f; - public static DaggerSingletonObject INSTANCE = - new DaggerSingletonObject<>(LauncherAppComponent::getRecentsAnimationDeviceState); + public static final DaggerSingletonObject> + REPOSITORY_INSTANCE = new DaggerSingletonObject<>( + QuickstepBaseAppComponent::getRecentsAnimationDeviceStateRepository); private final Context mContext; private final DisplayController mDisplayController; @@ -123,7 +120,6 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E InputMethodService.canImeRenderGesturalNavButtons(); private @SystemUiStateFlags long mSystemUiStateFlags = QuickStepContract.SYSUI_STATE_AWAKE; - private final Map mSysUIStateFlagsPerDisplay = new ConcurrentHashMap<>(); private NavigationMode mMode = THREE_BUTTONS; private NavBarPosition mNavBarPosition; @@ -140,11 +136,12 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E private int mGestureBlockingTaskId = -1; private @NonNull Region mExclusionRegion = GestureExclusionManager.EMPTY_REGION; private boolean mExclusionListenerRegistered; + private final int mDisplayId; - @VisibleForTesting - @Inject + @AssistedInject RecentsAnimationDeviceState( @ApplicationContext Context context, + @Assisted int displayId, GestureExclusionManager exclusionManager, DisplayController displayController, ContextualSearchStateManager contextualSearchStateManager, @@ -152,6 +149,7 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E SettingsCache settingsCache, DaggerSingletonTracker lifeCycle) { mContext = context; + mDisplayId = displayId; mDisplayController = displayController; mExclusionManager = exclusionManager; mContextualSearchStateManager = contextualSearchStateManager; @@ -357,47 +355,28 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E * Updates the system ui state flags from SystemUI for a specific display. * * @param stateFlags the current {@link SystemUiStateFlags} for the display. - * @param displayId the display's ID. */ - public void setSysUIStateFlagsForDisplay(@SystemUiStateFlags long stateFlags, - int displayId) { - mSysUIStateFlagsPerDisplay.put(displayId, stateFlags); + public void setSysUIStateFlags(@SystemUiStateFlags long stateFlags) { + mSystemUiStateFlags = stateFlags; } /** * Clears the system ui state flags for a specific display. This is called when the display is * destroyed. * - * @param displayId the display's ID. */ - public void clearSysUIStateFlagsForDisplay(int displayId) { - mSysUIStateFlagsPerDisplay.remove(displayId); + public void clearSysUIStateFlags() { + mSystemUiStateFlags = QuickStepContract.SYSUI_STATE_AWAKE; } /** - * @return the system ui state flags for the default display. - */ - // TODO(141886704): See if we can remove this - @SystemUiStateFlags - public long getSysuiStateFlag() { - return getSystemUiStateFlags(DEFAULT_DISPLAY); - } - - /** - * @return the system ui state flags for a given display ID. + * @return the system ui state flags for this display. */ @SystemUiStateFlags - public long getSystemUiStateFlags(int displayId) { - return mSysUIStateFlagsPerDisplay.getOrDefault(displayId, - QuickStepContract.SYSUI_STATE_AWAKE); + public long getSysuiStateFlags() { + return mSystemUiStateFlags; } - /** - * @return the display ids that have sysui state. - */ - public Set getDisplaysWithSysUIState() { - return mSysUIStateFlagsPerDisplay.keySet(); - } /** * Sets the flag that indicates whether a predictive back-to-home animation is in progress */ @@ -416,8 +395,8 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E * @return whether SystemUI is in a state where we can start a system gesture. */ public boolean canStartSystemGesture() { - boolean canStartWithNavHidden = (getSysuiStateFlag() & SYSUI_STATE_NAV_BAR_HIDDEN) == 0 - || (getSysuiStateFlag() & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0 + boolean canStartWithNavHidden = (getSysuiStateFlags() & SYSUI_STATE_NAV_BAR_HIDDEN) == 0 + || (getSysuiStateFlags() & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0 || mRotationTouchHelper.isTaskListFrozen(); return canStartWithNavHidden && canStartAnyGesture(); } @@ -429,7 +408,7 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E */ public boolean canStartTrackpadGesture() { boolean trackpadGesturesEnabled = - (getSysuiStateFlag() & SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED) == 0; + (getSysuiStateFlags() & SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED) == 0; return trackpadGesturesEnabled && canStartAnyGesture(); } @@ -437,8 +416,8 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E * Common logic to determine if either trackpad or finger gesture can be started */ private boolean canStartAnyGesture() { - boolean homeOrOverviewEnabled = (getSysuiStateFlag() & SYSUI_STATE_HOME_DISABLED) == 0 - || (getSysuiStateFlag() & SYSUI_STATE_OVERVIEW_DISABLED) == 0; + boolean homeOrOverviewEnabled = (getSysuiStateFlags() & SYSUI_STATE_HOME_DISABLED) == 0 + || (getSysuiStateFlags() & SYSUI_STATE_OVERVIEW_DISABLED) == 0; long gestureDisablingStates = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_QUICK_SETTINGS_EXPANDED @@ -446,7 +425,7 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E | SYSUI_STATE_DEVICE_DREAMING | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION | SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING; - return (gestureDisablingStates & getSysuiStateFlag()) == 0 && homeOrOverviewEnabled; + return (gestureDisablingStates & getSysuiStateFlags()) == 0 && homeOrOverviewEnabled; } /** @@ -454,35 +433,35 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E * (like camera or maps) */ public boolean isKeyguardShowingOccluded() { - return (getSysuiStateFlag() & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0; + return (getSysuiStateFlags() & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0; } /** * @return whether screen pinning is enabled and active */ public boolean isScreenPinningActive() { - return (getSysuiStateFlag() & SYSUI_STATE_SCREEN_PINNING) != 0; + return (getSysuiStateFlags() & SYSUI_STATE_SCREEN_PINNING) != 0; } /** * @return whether assistant gesture is constraint */ public boolean isAssistantGestureIsConstrained() { - return (getSysuiStateFlag() & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0; + return (getSysuiStateFlags() & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0; } /** * @return whether the bubble stack is expanded */ public boolean isBubblesExpanded() { - return (getSysuiStateFlag() & SYSUI_STATE_BUBBLES_EXPANDED) != 0; + return (getSysuiStateFlags() & SYSUI_STATE_BUBBLES_EXPANDED) != 0; } /** * @return whether the global actions dialog is showing */ public boolean isSystemUiDialogShowing() { - return (getSysuiStateFlag() & SYSUI_STATE_DIALOG_SHOWING) != 0; + return (getSysuiStateFlags() & SYSUI_STATE_DIALOG_SHOWING) != 0; } /** @@ -496,35 +475,35 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E * @return whether the accessibility menu is available. */ public boolean isAccessibilityMenuAvailable() { - return (getSysuiStateFlag() & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0; + return (getSysuiStateFlags() & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0; } /** * @return whether the accessibility menu shortcut is available. */ public boolean isAccessibilityMenuShortcutAvailable() { - return (getSysuiStateFlag() & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0; + return (getSysuiStateFlags() & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0; } /** * @return whether home is disabled (either by SUW/SysUI/device policy) */ public boolean isHomeDisabled() { - return (getSysuiStateFlag() & SYSUI_STATE_HOME_DISABLED) != 0; + return (getSysuiStateFlags() & SYSUI_STATE_HOME_DISABLED) != 0; } /** * @return whether overview is disabled (either by SUW/SysUI/device policy) */ public boolean isOverviewDisabled() { - return (getSysuiStateFlag() & SYSUI_STATE_OVERVIEW_DISABLED) != 0; + return (getSysuiStateFlags() & SYSUI_STATE_OVERVIEW_DISABLED) != 0; } /** * @return whether one-handed mode is enabled and active */ public boolean isOneHandedModeActive() { - return (getSysuiStateFlag() & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0; + return (getSysuiStateFlags() & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0; } /** @@ -587,7 +566,7 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E */ public boolean canTriggerAssistantAction(MotionEvent ev) { return mAssistantAvailable - && !QuickStepContract.isAssistantGestureDisabled(getSysuiStateFlag()) + && !QuickStepContract.isAssistantGestureDisabled(getSysuiStateFlags()) && mRotationTouchHelper.touchInAssistantRegion(ev) && !isTrackpadScroll(ev) && !isLockToAppActive(); @@ -627,7 +606,7 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E /** Returns whether IME is rendering nav buttons, and IME is currently showing. */ public boolean isImeRenderingNavButtons() { return mCanImeRenderGesturalNavButtons && mMode == NO_BUTTON - && ((getSysuiStateFlag() & SYSUI_STATE_IME_VISIBLE) != 0); + && ((getSysuiStateFlags() & SYSUI_STATE_IME_VISIBLE) != 0); } /** @@ -661,7 +640,7 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E /** Returns a string representation of the system ui state flags for the default display. */ public String getSystemUiStateString() { - return getSystemUiStateString(getSysuiStateFlag()); + return getSystemUiStateString(getSysuiStateFlags()); } /** Returns a string representation of the system ui state flags. */ @@ -672,24 +651,29 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E public void dump(PrintWriter pw) { pw.println("DeviceState:"); pw.println(" canStartSystemGesture=" + canStartSystemGesture()); - pw.println(" systemUiFlagsForDefaultDisplay=" + getSysuiStateFlag()); + pw.println(" systemUiFlagsForDefaultDisplay=" + getSysuiStateFlags()); pw.println(" systemUiFlagsDesc=" + getSystemUiStateString()); pw.println(" assistantAvailable=" + mAssistantAvailable); pw.println(" assistantDisabled=" - + QuickStepContract.isAssistantGestureDisabled(getSysuiStateFlag())); + + QuickStepContract.isAssistantGestureDisabled(getSysuiStateFlags())); pw.println(" isOneHandedModeEnabled=" + mIsOneHandedModeEnabled); pw.println(" isSwipeToNotificationEnabled=" + mIsSwipeToNotificationEnabled); pw.println(" deferredGestureRegion=" + mDeferredGestureRegion.getBounds()); pw.println(" exclusionRegion=" + mExclusionRegion.getBounds()); pw.println(" pipIsActive=" + mPipIsActive); pw.println(" predictiveBackToHomeInProgress=" + mIsPredictiveBackToHomeInProgress); - for (int displayId : mSysUIStateFlagsPerDisplay.keySet()) { - pw.println(" systemUiFlagsForDisplay" + displayId + "=" + getSystemUiStateFlags( - displayId)); - pw.println(" systemUiFlagsForDisplay" + displayId + "Desc=" + getSystemUiStateString( - getSystemUiStateFlags(displayId))); - } pw.println(" RotationTouchHelper:"); mRotationTouchHelper.dump(pw); } -} + + public int getDisplayId() { + return mDisplayId; + } + + @AssistedFactory + public interface Factory { + /** Creates a new instance of [RecentsAnimationDeviceState] for a given [displayId]. */ + RecentsAnimationDeviceState create(int displayId); + } + +} \ No newline at end of file diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index cf0a3d570f..2a6b38722a 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -41,11 +41,15 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; +import com.android.app.displaylib.PerDisplayRepository; import com.android.internal.util.ArrayUtils; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.dagger.ApplicationContext; import com.android.launcher3.taskbar.TaskbarUIController; +import com.android.launcher3.util.DaggerSingletonObject; import com.android.launcher3.util.DisplayController; +import com.android.quickstep.dagger.QuickstepBaseAppComponent; import com.android.quickstep.fallback.window.RecentsDisplayModel; import com.android.quickstep.fallback.window.RecentsWindowFlags; import com.android.quickstep.fallback.window.RecentsWindowManager; @@ -61,6 +65,10 @@ import java.io.PrintWriter; import java.util.HashMap; import java.util.Locale; +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; + public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener { public static final boolean SHELL_TRANSITIONS_ROTATION = SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false); @@ -69,7 +77,6 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn private RecentsAnimationCallbacks mCallbacks; private RecentsAnimationTargets mTargets; private TransitionInfo mTransitionInfo; - private RecentsAnimationDeviceState mDeviceState; // Temporary until we can hook into gesture state events private GestureState mLastGestureState; @@ -80,6 +87,10 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn private boolean mShouldIgnoreMotionEvents = false; private final int mDisplayId; + public static final DaggerSingletonObject> + REPOSITORY_INSTANCE = new DaggerSingletonObject<>( + QuickstepBaseAppComponent::getTaskAnimationManagerRepository); + private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() { @Override public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, @@ -103,10 +114,11 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn } }; - public TaskAnimationManager(Context ctx, RecentsAnimationDeviceState deviceState, - int displayId) { + @AssistedInject + public TaskAnimationManager( + @ApplicationContext Context ctx, + @Assisted int displayId) { mCtx = ctx; - mDeviceState = deviceState; mDisplayId = displayId; } @@ -524,4 +536,11 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mLastGestureState.dump(prefix + '\t', pw); } } + + @AssistedFactory + public interface Factory { + /** Creates a new instance of [TaskAnimationManager] for a given [displayId]. */ + TaskAnimationManager create(int displayId); + } + } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 6abb681b9c..b059b330ed 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -68,6 +68,8 @@ import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.annotation.VisibleForTesting; +import com.android.app.displaylib.DisplayRepository; +import com.android.app.displaylib.PerDisplayRepository; import com.android.launcher3.ConstantItem; import com.android.launcher3.EncryptionType; import com.android.launcher3.Flags; @@ -94,7 +96,6 @@ import com.android.launcher3.util.TraceHelper; import com.android.quickstep.OverviewCommandHelper.CommandType; import com.android.quickstep.OverviewComponentObserver.OverviewChangeListener; import com.android.quickstep.fallback.window.RecentsDisplayModel; -import com.android.quickstep.fallback.window.RecentsDisplayModel.RecentsDisplayResource; import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler; import com.android.quickstep.inputconsumers.BubbleBarInputConsumer; import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer; @@ -215,12 +216,15 @@ public class TouchInteractionService extends Service { public void onOverviewToggle() { TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle"); executeForTouchInteractionService(tis -> { + // TODO: update for non-default displays. + RecentsAnimationDeviceState deviceState = tis.mDeviceStateRepository.get( + DEFAULT_DISPLAY); // If currently screen pinning, do not enter overview - if (tis.mDeviceState.isScreenPinningActive()) { + if (deviceState != null && deviceState.isScreenPinningActive()) { return; } TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); - tis.mOverviewCommandHelper.addCommand(CommandType.TOGGLE); + tis.mOverviewCommandHelper.addCommand(CommandType.TOGGLE, DEFAULT_DISPLAY); }); } @@ -258,7 +262,9 @@ public class TouchInteractionService extends Service { @Override public void onAssistantAvailable(boolean available, boolean longPressHomeEnabled) { MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> { - tis.mDeviceState.setAssistantAvailable(available); + tis.mDeviceStateRepository.forEach(/* createIfAbsent= */ true, deviceState -> + deviceState.setAssistantAvailable(available) + ); tis.onAssistantVisibilityChanged(); executeForTaskbarManager(taskbarManager -> taskbarManager .onLongPressHomeEnabled(longPressHomeEnabled)); @@ -269,7 +275,9 @@ public class TouchInteractionService extends Service { @Override public void onAssistantVisibilityChanged(float visibility) { MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> { - tis.mDeviceState.setAssistantVisibility(visibility); + tis.mDeviceStateRepository.forEach(/* createIfAbsent= */ true, deviceState -> + deviceState.setAssistantVisibility( + visibility)); tis.onAssistantVisibilityChanged(); })); } @@ -292,16 +300,23 @@ public class TouchInteractionService extends Service { public void onSystemUiStateChanged(@SystemUiStateFlags long stateFlags, int displayId) { MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> { // Last flags is only used for the default display case. - long lastFlags = tis.mDeviceState.getSysuiStateFlag(); - tis.mDeviceState.setSysUIStateFlagsForDisplay(stateFlags, displayId); - tis.onSystemUiFlagsChanged(lastFlags, displayId); + RecentsAnimationDeviceState deviceState = tis.mDeviceStateRepository.get(displayId); + if (deviceState != null) { + long lastFlags = deviceState.getSysuiStateFlags(); + deviceState.setSysUIStateFlags(stateFlags); + tis.onSystemUiFlagsChanged(lastFlags, displayId); + } })); } @BinderThread public void onActiveNavBarRegionChanges(Region region) { MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService( - tis -> tis.mDeviceState.setDeferredGestureRegion(region))); + tis -> + tis.mDeviceStateRepository.forEach(/* createIfAbsent= */ true, + deviceState -> + deviceState.setDeferredGestureRegion(region)) + )); } @BinderThread @@ -329,7 +344,6 @@ public class TouchInteractionService extends Service { public void onDisplayRemoved(int displayId) { executeForTouchInteractionService(tis -> { tis.mSystemDecorationChangeObserver.notifyOnDisplayRemoved(displayId); - tis.mDeviceState.clearSysUIStateFlagsForDisplay(displayId); }); } @@ -486,7 +500,8 @@ public class TouchInteractionService extends Service { */ public void setPredictiveBackToHomeInProgress(boolean isInProgress) { executeForTouchInteractionService(tis -> - tis.mDeviceState.setPredictiveBackToHomeInProgress(isInProgress)); + tis.mDeviceStateRepository.forEach(/* createIfAbsent= */ true, deviceState -> + deviceState.setPredictiveBackToHomeInProgress(isInProgress))); } /** @@ -514,7 +529,11 @@ public class TouchInteractionService extends Service { */ public void setGestureBlockedTaskId(int taskId) { executeForTouchInteractionService( - tis -> tis.mDeviceState.setGestureBlockingTaskId(taskId)); + tis -> + tis.mDeviceStateRepository.forEach(/* createIfAbsent= */ true, + deviceState -> + deviceState.setGestureBlockingTaskId(taskId)) + ); } /** Refreshes the current overview target. */ @@ -561,9 +580,11 @@ public class TouchInteractionService extends Service { private OverviewCommandHelper mOverviewCommandHelper; private OverviewComponentObserver mOverviewComponentObserver; private InputConsumerController mInputConsumer; - private RecentsAnimationDeviceState mDeviceState; + private PerDisplayRepository mDeviceStateRepository; + private PerDisplayRepository mTaskAnimationManagerRepository; private @NonNull InputConsumer mUncheckedConsumer = InputConsumer.DEFAULT_NO_OP; + private @NonNull InputConsumer mConsumer = InputConsumer.DEFAULT_NO_OP; private Choreographer mMainChoreographer; private boolean mUserUnlocked = false; @@ -588,6 +609,8 @@ public class TouchInteractionService extends Service { private SystemDecorationChangeObserver mSystemDecorationChangeObserver; + private DisplayRepository mDisplayRepository; + @Override public void onCreate() { super.onCreate(); @@ -595,8 +618,10 @@ public class TouchInteractionService extends Service { + " instance=" + System.identityHashCode(this)); // Initialize anything here that is needed in direct boot mode. // Everything else should be initialized in onUserUnlocked() below. + mDisplayRepository = LauncherDisplayRepository.getINSTANCE().get(this); + mDeviceStateRepository = RecentsAnimationDeviceState.REPOSITORY_INSTANCE.get(this); + mTaskAnimationManagerRepository = TaskAnimationManager.REPOSITORY_INSTANCE.get(this); mMainChoreographer = Choreographer.getInstance(); - mDeviceState = RecentsAnimationDeviceState.INSTANCE.get(this); mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(this); mRecentsDisplayModel = RecentsDisplayModel.getINSTANCE().get(this); mSystemDecorationChangeObserver = SystemDecorationChangeObserver.getINSTANCE().get(this); @@ -620,8 +645,10 @@ public class TouchInteractionService extends Service { // Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized. LockedUserState.get(this).runOnUserUnlocked(mUserUnlockedRunnable); + // Assume that the navigation mode changes for all displays at once. mDisplayInfoChangeListener = - mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged); + mDeviceStateRepository.get(DEFAULT_DISPLAY).addNavigationModeChangedCallback( + this::onNavigationModeChanged); ScreenOnTracker.INSTANCE.get(this).addListener(mScreenOnListener); } @@ -665,9 +692,9 @@ public class TouchInteractionService extends Service { private void initInputMonitor(String reason) { disposeEventHandlers("Initializing input monitor due to: " + reason); - - if (mDeviceState.isButtonNavMode() - && !mDeviceState.supportsAssistantGestureInButtonNav() + RecentsAnimationDeviceState deviceState = mDeviceStateRepository.get(DEFAULT_DISPLAY); + if (deviceState.isButtonNavMode() + && !deviceState.supportsAssistantGestureInButtonNav() && (mTrackpadsConnected.isEmpty())) { return; } @@ -696,12 +723,13 @@ public class TouchInteractionService extends Service { + " instance=" + System.identityHashCode(this)); mOverviewComponentObserver = OverviewComponentObserver.INSTANCE.get(this); mOverviewCommandHelper = new OverviewCommandHelper(this, - mOverviewComponentObserver, mRecentsDisplayModel, mTaskbarManager); + mOverviewComponentObserver, mRecentsDisplayModel, mTaskbarManager, + mTaskAnimationManagerRepository); mUserUnlocked = true; mInputConsumer.registerInputConsumer(); - for (int displayId : mDeviceState.getDisplaysWithSysUIState()) { - onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags(displayId), displayId); - } + mDeviceStateRepository.forEach(/* createIfAbsent= */ true, deviceState -> + onSystemUiFlagsChanged(deviceState.getSysuiStateFlags(), + deviceState.getDisplayId())); onAssistantVisibilityChanged(); // Initialize the task tracker @@ -722,7 +750,8 @@ public class TouchInteractionService extends Service { } private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() { - if (!LockedUserState.get(this).isUserUnlocked() || mDeviceState.isButtonNavMode()) { + if (!LockedUserState.get(this).isUserUnlocked() || mDeviceStateRepository.get( + DEFAULT_DISPLAY).isButtonNavMode()) { // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation // mode doesn't have gestures return; @@ -768,18 +797,18 @@ public class TouchInteractionService extends Service { @UiThread private void onSystemUiFlagsChanged(@SystemUiStateFlags long lastSysUIFlags, int displayId) { if (LockedUserState.get(this).isUserUnlocked()) { - long systemUiStateFlags = mDeviceState.getSystemUiStateFlags(displayId); - mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags, displayId); - if (displayId == DEFAULT_DISPLAY) { - // The following don't care about non-default displays, at least for now. If they - // ever will, they should be taken care of. - SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags); - mOverviewComponentObserver.setHomeDisabled(mDeviceState.isHomeDisabled()); - // TODO b/399371607 - Propagate to taskAnimationManager once overview is multi - // display. - TaskAnimationManager taskAnimationManager = - mRecentsDisplayModel.getTaskAnimationManager(displayId); - if (taskAnimationManager != null) { + RecentsAnimationDeviceState deviceState = mDeviceStateRepository.get(displayId); + TaskAnimationManager taskAnimationManager = mTaskAnimationManagerRepository.get( + displayId); + if (deviceState != null && taskAnimationManager != null) { + long systemUiStateFlags = deviceState.getSysuiStateFlags(); + mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags, displayId); + if (displayId == DEFAULT_DISPLAY) { + // The following don't care about non-default displays, at least for now. If + // they + // ever will, they should be taken care of. + SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags); + mOverviewComponentObserver.setHomeDisabled(deviceState.isHomeDisabled()); taskAnimationManager.onSystemUiFlagsChanged(lastSysUIFlags, systemUiStateFlags); } } @@ -791,7 +820,7 @@ public class TouchInteractionService extends Service { if (LockedUserState.get(this).isUserUnlocked()) { mOverviewComponentObserver.getContainerInterface( DEFAULT_DISPLAY).onAssistantVisibilityChanged( - mDeviceState.getAssistantVisibility()); + mDeviceStateRepository.get(DEFAULT_DISPLAY).getAssistantVisibility()); } } @@ -815,7 +844,8 @@ public class TouchInteractionService extends Service { mDesktopAppLaunchTransitionManager.unregisterTransitions(); } mDesktopAppLaunchTransitionManager = null; - mDeviceState.removeDisplayInfoChangeListener(mDisplayInfoChangeListener); + mDeviceStateRepository.get(DEFAULT_DISPLAY).removeDisplayInfoChangeListener( + mDisplayInfoChangeListener); LockedUserState.get(this).removeOnUserUnlockedRunnable(mUserUnlockedRunnable); ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener); super.onDestroy(); @@ -855,13 +885,19 @@ public class TouchInteractionService extends Service { return; } - NavigationMode currentNavMode = mDeviceState.getMode(); + RecentsAnimationDeviceState deviceState = mDeviceStateRepository.get(displayId); + if (deviceState == null) { + Log.d(TAG, "RecentsAnimationDeviceState not available for displayId " + displayId); + return; + } + + NavigationMode currentNavMode = deviceState.getMode(); if (mGestureStartNavMode != null && mGestureStartNavMode != currentNavMode) { ActiveGestureProtoLogProxy.logOnInputEventNavModeSwitched( displayId, mGestureStartNavMode.name(), currentNavMode.name()); event.setAction(ACTION_CANCEL); - } else if (mDeviceState.isButtonNavMode() - && !mDeviceState.supportsAssistantGestureInButtonNav() + } else if (deviceState.isButtonNavMode() + && !deviceState.supportsAssistantGestureInButtonNav() && !isTrackpadMotionEvent(event)) { ActiveGestureProtoLogProxy.logOnInputEventThreeButtonNav(displayId); return; @@ -873,8 +909,7 @@ public class TouchInteractionService extends Service { boolean isHoverActionWithoutConsumer = enableCursorHoverStates() && isHoverActionWithoutConsumer(event); - TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager( - displayId); + TaskAnimationManager taskAnimationManager = mTaskAnimationManagerRepository.get(displayId); if (taskAnimationManager == null) { Log.e(TAG, "TaskAnimationManager not available for displayId " + displayId); ActiveGestureProtoLogProxy.logOnTaskAnimationManagerNotAvailable(displayId); @@ -908,24 +943,24 @@ public class TouchInteractionService extends Service { if (action == ACTION_DOWN || isHoverActionWithoutConsumer) { mRotationTouchHelper.setOrientationTransformIfNeeded(event); - boolean isOneHandedModeActive = mDeviceState.isOneHandedModeActive(); + boolean isOneHandedModeActive = deviceState.isOneHandedModeActive(); boolean isInSwipeUpTouchRegion = mRotationTouchHelper.isInSwipeUpTouchRegion(event); TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext(); BubbleControllers bubbleControllers = tac != null ? tac.getBubbleControllers() : null; boolean isOnBubbles = bubbleControllers != null && BubbleBarInputConsumer.isEventOnBubbles(tac, event); - if (mDeviceState.isButtonNavMode() - && mDeviceState.supportsAssistantGestureInButtonNav()) { + if (deviceState.isButtonNavMode() + && deviceState.supportsAssistantGestureInButtonNav()) { reasonString.append("in three button mode which supports Assistant gesture"); // Consume gesture event for Assistant (all other gestures should do nothing). - if (mDeviceState.canTriggerAssistantAction(event)) { + if (deviceState.canTriggerAssistantAction(event)) { reasonString.append(" and event can trigger assistant action, " + "consuming gesture for assistant action"); mGestureState = createGestureState( displayId, mGestureState, getTrackpadGestureType(event)); mUncheckedConsumer = tryCreateAssistantInputConsumer( this, - mDeviceState, + deviceState, inputMonitorCompat, mGestureState, event); @@ -951,7 +986,7 @@ public class TouchInteractionService extends Service { this, mUserUnlocked, mOverviewComponentObserver, - mDeviceState, + deviceState, prevGestureState, mGestureState, taskAnimationManager, @@ -964,9 +999,9 @@ public class TouchInteractionService extends Service { mOverviewCommandHelper, event); mUncheckedConsumer = mConsumer; - } else if ((mDeviceState.isFullyGesturalNavMode() || isTrackpadMultiFingerSwipe(event)) - && mDeviceState.canTriggerAssistantAction(event)) { - reasonString.append(mDeviceState.isFullyGesturalNavMode() + } else if ((deviceState.isFullyGesturalNavMode() || isTrackpadMultiFingerSwipe(event)) + && deviceState.canTriggerAssistantAction(event)) { + reasonString.append(deviceState.isFullyGesturalNavMode() ? "using fully gestural nav and event can trigger assistant action, " + "consuming gesture for assistant action" : "event is a trackpad multi-finger swipe and event can trigger assistant " @@ -977,15 +1012,15 @@ public class TouchInteractionService extends Service { // should not interrupt it. QuickSwitch assumes that interruption can only // happen if the next gesture is also quick switch. mUncheckedConsumer = tryCreateAssistantInputConsumer( - this, mDeviceState, inputMonitorCompat, mGestureState, event); - } else if (mDeviceState.canTriggerOneHandedAction(event)) { + this, deviceState, inputMonitorCompat, mGestureState, event); + } else if (deviceState.canTriggerOneHandedAction(event)) { reasonString.append("event can trigger one-handed action, " + "consuming gesture for one-handed action"); // Consume gesture event for triggering one handed feature. mUncheckedConsumer = new OneHandedModeInputConsumer( this, displayId, - mDeviceState, + deviceState, InputConsumer.createNoOpInputConsumer(displayId), inputMonitorCompat); } else { mUncheckedConsumer = InputConsumer.createNoOpInputConsumer(displayId); @@ -1072,8 +1107,7 @@ public class TouchInteractionService extends Service { GestureState.TrackpadGestureType trackpadGestureType) { final GestureState gestureState; TopTaskTracker.CachedTaskInfo taskInfo; - TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager( - displayId); + TaskAnimationManager taskAnimationManager = mTaskAnimationManagerRepository.get(displayId); if (taskAnimationManager != null && taskAnimationManager.isRecentsAnimationRunning()) { gestureState = new GestureState( mOverviewComponentObserver, displayId, ActiveGestureLog.INSTANCE.getLogId()); @@ -1098,7 +1132,10 @@ public class TouchInteractionService extends Service { // Log initial state for the gesture. ActiveGestureProtoLogProxy.logRunningTaskPackage(taskInfo.getPackageName()); - ActiveGestureProtoLogProxy.logSysuiStateFlags(mDeviceState.getSystemUiStateString()); + RecentsAnimationDeviceState deviceState = mDeviceStateRepository.get(displayId); + if (deviceState != null) { + ActiveGestureProtoLogProxy.logSysuiStateFlags(deviceState.getSystemUiStateString()); + } return gestureState; } @@ -1133,7 +1170,7 @@ public class TouchInteractionService extends Service { mConsumer = mUncheckedConsumer = InputConsumerUtils.getDefaultInputConsumer( displayId, mUserUnlocked, - mRecentsDisplayModel.getTaskAnimationManager(displayId), + mTaskAnimationManagerRepository.get(displayId), mTaskbarManager, CompoundString.NO_OP); mGestureState = DEFAULT_STATE; @@ -1170,7 +1207,8 @@ public class TouchInteractionService extends Service { int newGesturalHeight = ResourceUtils.getNavbarSize( ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getApplicationContext().getResources()); - mDeviceState.onOneHandedModeChanged(newGesturalHeight); + mDeviceStateRepository.forEach(/* createIfAbsent= */ true, deviceState -> + deviceState.onOneHandedModeChanged(newGesturalHeight)); return; } @@ -1187,7 +1225,6 @@ public class TouchInteractionService extends Service { if (LockedUserState.get(this).isUserUnlocked()) { PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw); } - mDeviceState.dump(pw); if (mOverviewComponentObserver != null) { mOverviewComponentObserver.dump(pw); } @@ -1206,9 +1243,12 @@ public class TouchInteractionService extends Service { mInputMonitorDisplayModel.dump("\t", pw); } DisplayController.INSTANCE.get(this).dump(pw); - for (RecentsDisplayResource resource : mRecentsDisplayModel.getActiveDisplayResources()) { - int displayId = resource.getDisplayId(); + mDisplayRepository.getDisplayIds().getValue().forEach(displayId -> { pw.println(String.format(Locale.ENGLISH, "TouchState (displayId %d):", displayId)); + RecentsAnimationDeviceState deviceState = mDeviceStateRepository.get(displayId); + if (deviceState != null) { + deviceState.dump(pw); + } RecentsViewContainer createdOverviewContainer = mOverviewComponentObserver == null ? null : mOverviewComponentObserver.getContainerInterface( @@ -1220,8 +1260,12 @@ public class TouchInteractionService extends Service { if (createdOverviewContainer != null) { createdOverviewContainer.getDeviceProfile().dump(this, "", pw); } - resource.getTaskAnimationManager().dump("\t", pw); - } + TaskAnimationManager taskAnimationManager = mTaskAnimationManagerRepository.get( + displayId); + if (taskAnimationManager != null) { + taskAnimationManager.dump("\t", pw); + } + }); pw.println("\tmConsumer=" + mConsumer.getName()); ActiveGestureLog.INSTANCE.dump("", pw); RecentsModel.INSTANCE.get(this).dump("", pw); @@ -1234,29 +1278,44 @@ public class TouchInteractionService extends Service { TopTaskTracker.INSTANCE.get(this).dump(pw); } - private AbsSwipeUpHandler createLauncherSwipeHandler( + private @Nullable AbsSwipeUpHandler createLauncherSwipeHandler( GestureState gestureState, long touchTimeMs) { - TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager( + TaskAnimationManager taskAnimationManager = mTaskAnimationManagerRepository.get( gestureState.getDisplayId()); - return new LauncherSwipeHandlerV2(this, taskAnimationManager, + RecentsAnimationDeviceState deviceState = mDeviceStateRepository.get( + gestureState.getDisplayId()); + if (taskAnimationManager == null || deviceState == null) { + return null; + } + return new LauncherSwipeHandlerV2(this, taskAnimationManager, deviceState, gestureState, touchTimeMs, taskAnimationManager.isRecentsAnimationRunning(), mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this)); } - private AbsSwipeUpHandler createFallbackSwipeHandler( + private @Nullable AbsSwipeUpHandler createFallbackSwipeHandler( GestureState gestureState, long touchTimeMs) { - TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager( + TaskAnimationManager taskAnimationManager = mTaskAnimationManagerRepository.get( gestureState.getDisplayId()); - return new FallbackSwipeHandler(this, taskAnimationManager, + RecentsAnimationDeviceState deviceState = mDeviceStateRepository.get( + gestureState.getDisplayId()); + if (taskAnimationManager == null || deviceState == null) { + return null; + } + return new FallbackSwipeHandler(this, taskAnimationManager, deviceState, gestureState, touchTimeMs, taskAnimationManager.isRecentsAnimationRunning(), mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this)); } - private AbsSwipeUpHandler createRecentsWindowSwipeHandler( + private @Nullable AbsSwipeUpHandler createRecentsWindowSwipeHandler( GestureState gestureState, long touchTimeMs) { - TaskAnimationManager taskAnimationManager = mRecentsDisplayModel.getTaskAnimationManager( + TaskAnimationManager taskAnimationManager = mTaskAnimationManagerRepository.get( gestureState.getDisplayId()); - return new RecentsWindowSwipeHandler(this, taskAnimationManager, + RecentsAnimationDeviceState deviceState = mDeviceStateRepository.get( + gestureState.getDisplayId()); + if (taskAnimationManager == null || deviceState == null) { + return null; + } + return new RecentsWindowSwipeHandler(this, taskAnimationManager, deviceState, gestureState, touchTimeMs, taskAnimationManager.isRecentsAnimationRunning(), mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this)); } diff --git a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java index 23b8a82b2a..1a744aba56 100644 --- a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java +++ b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java @@ -16,6 +16,8 @@ package com.android.quickstep.dagger; +import com.android.app.displaylib.DisplayRepository; +import com.android.app.displaylib.PerDisplayRepository; import com.android.launcher3.dagger.LauncherAppComponent; import com.android.launcher3.dagger.LauncherBaseAppComponent; import com.android.launcher3.model.WellbeingModel; @@ -27,6 +29,7 @@ import com.android.quickstep.RotationTouchHelper; import com.android.quickstep.SimpleOrientationTouchTransformer; import com.android.quickstep.SystemDecorationChangeObserver; import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.TopTaskTracker; import com.android.quickstep.fallback.window.RecentsDisplayModel; import com.android.quickstep.logging.SettingsChangeLogger; @@ -64,7 +67,8 @@ public interface QuickstepBaseAppComponent extends LauncherBaseAppComponent { ContextualSearchStateManager getContextualSearchStateManager(); - RecentsAnimationDeviceState getRecentsAnimationDeviceState(); + PerDisplayRepository getRecentsAnimationDeviceStateRepository(); + PerDisplayRepository getTaskAnimationManagerRepository(); RecentsModel getRecentsModel(); @@ -73,4 +77,6 @@ public interface QuickstepBaseAppComponent extends LauncherBaseAppComponent { SimpleOrientationTouchTransformer getSimpleOrientationTouchTransformer(); SystemDecorationChangeObserver getSystemDecorationChangeObserver(); + + DisplayRepository getDisplayRepository(); } diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt index 5b88686cb8..205f9af8f9 100644 --- a/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt +++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt @@ -28,8 +28,6 @@ import com.android.launcher3.util.DaggerSingletonTracker import com.android.launcher3.util.WallpaperColorHints import com.android.quickstep.DisplayModel import com.android.quickstep.FallbackWindowInterface -import com.android.quickstep.RecentsAnimationDeviceState -import com.android.quickstep.TaskAnimationManager import com.android.quickstep.dagger.QuickstepBaseAppComponent import com.android.quickstep.fallback.window.RecentsDisplayModel.RecentsDisplayResource import com.android.quickstep.fallback.window.RecentsWindowFlags.Companion.enableOverviewInWindow @@ -84,10 +82,6 @@ constructor( return getDisplayResource(displayId)?.fallbackWindowInterface } - fun getTaskAnimationManager(displayId: Int): TaskAnimationManager? { - return getDisplayResource(displayId)?.taskAnimationManager - } - val activeDisplayResources: Iterable get() = object : Iterable { @@ -104,12 +98,6 @@ constructor( else null val fallbackWindowInterface = if (enableOverviewInWindow) FallbackWindowInterface(recentsWindowManager) else null - val taskAnimationManager = - TaskAnimationManager( - displayContext, - RecentsAnimationDeviceState.INSTANCE.get(displayContext), - displayId, - ) override fun cleanup() { recentsWindowManager?.destroy() diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java index 0d139b4e9f..a0d790680a 100644 --- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java @@ -67,6 +67,7 @@ import com.android.launcher3.util.MSDLPlayerWrapper; import com.android.quickstep.AbsSwipeUpHandler; import com.android.quickstep.GestureState; import com.android.quickstep.RecentsAnimationController; +import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.fallback.FallbackRecentsView; @@ -111,9 +112,10 @@ public class RecentsWindowSwipeHandler extends AbsSwipeUpHandler() init { - startDefaultScope(appContext) + startDefaultScope(appContext, dispatcherProvider) } /** @@ -52,11 +52,10 @@ class RecentsDependencies private constructor(appContext: Context) { * are global while others are per-RecentsView. The scope is used to differentiate between * RecentsViews. */ - private fun startDefaultScope(appContext: Context) { + private fun startDefaultScope(appContext: Context, dispatcherProvider: DispatcherProvider) { Log.d(TAG, "startDefaultScope") createScope(DEFAULT_SCOPE_ID).apply { set(RecentsViewData::class.java.simpleName, RecentsViewData()) - val dispatcherProvider: DispatcherProvider = ProductionDispatchers val recentsCoroutineScope = CoroutineScope( SupervisorJob() + dispatcherProvider.unconfined + CoroutineName("RecentsView") @@ -80,7 +79,7 @@ class RecentsDependencies private constructor(appContext: Context) { iconCache, taskVisualsChangedDelegate, recentsCoroutineScope, - ProductionDispatchers, + dispatcherProvider, ) } set(RecentTasksRepository::class.java.simpleName, recentTasksRepository) @@ -241,17 +240,24 @@ class RecentsDependencies private constructor(appContext: Context) { @Volatile private var instance: RecentsDependencies? = null - private fun initialize(context: Context): RecentsDependencies { + private fun initialize( + context: Context, + dispatcherProvider: DispatcherProvider, + ): RecentsDependencies { Log.d(TAG, "initializing") synchronized(this) { - val newInstance = RecentsDependencies(context.applicationContext) + val newInstance = + RecentsDependencies(context.applicationContext, dispatcherProvider) instance = newInstance return newInstance } } - fun maybeInitialize(context: Context): RecentsDependencies { - return instance ?: initialize(context) + fun maybeInitialize( + context: Context, + dispatcherProvider: DispatcherProvider, + ): RecentsDependencies { + return instance ?: initialize(context, dispatcherProvider) } fun getInstance(): RecentsDependencies { diff --git a/quickstep/src/com/android/quickstep/util/ActivityPreloadUtil.kt b/quickstep/src/com/android/quickstep/util/ActivityPreloadUtil.kt index df26b6bb90..3c7ac40a7a 100644 --- a/quickstep/src/com/android/quickstep/util/ActivityPreloadUtil.kt +++ b/quickstep/src/com/android/quickstep/util/ActivityPreloadUtil.kt @@ -46,7 +46,8 @@ object ActivityPreloadUtil { try { if (!LockedUserState.get(ctx).isUserUnlocked) return - val deviceState = RecentsAnimationDeviceState.INSTANCE[ctx] + val deviceState = + RecentsAnimationDeviceState.REPOSITORY_INSTANCE.get(ctx)[ctx.displayId] ?: return val overviewCompObserver = OverviewComponentObserver.INSTANCE[ctx] // Prevent the overview from being started before the real home on first boot diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 8ef3c8c23b..73b7d0fb9d 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -183,6 +183,7 @@ import com.android.launcher3.util.TranslateEdgeEffect; import com.android.launcher3.util.VibratorWrapper; import com.android.launcher3.util.ViewPool; import com.android.launcher3.util.coroutines.DispatcherProvider; +import com.android.launcher3.util.coroutines.ProductionDispatchers; import com.android.quickstep.BaseContainerInterface; import com.android.quickstep.GestureState; import com.android.quickstep.HighResLoadingState; @@ -888,7 +889,7 @@ public abstract class RecentsView< // Start Recents Dependency graph if (enableRefactorTaskThumbnail()) { RecentsDependencies recentsDependencies = RecentsDependencies.Companion.maybeInitialize( - context); + context, ProductionDispatchers.INSTANCE); String scopeId = recentsDependencies.createRecentsViewScope(context); mRecentsViewModel = new RecentsViewModel( recentsDependencies.inject(RecentTasksRepository.class, scopeId), diff --git a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java index 2532fcf8cf..cfa3e4990c 100644 --- a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java +++ b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java @@ -561,6 +561,15 @@ public class ActiveGestureProtoLogProxy { displayId); } + public static void logOnAbsSwipeUpHandlerNotAvailable(int displayId) { + ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString( + "AbsSwipeUpHandler not available for displayId=%d", + displayId)); + if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return; + ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler not available for displayId=%d", + displayId); + } + public static void logGestureStartSwipeHandler(@NonNull String interactionHandler) { ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString( "OtherActivityInputConsumer.startTouchTrackingForWindowAnimation: " diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt index 42adfec82c..6170551420 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt @@ -30,6 +30,7 @@ import com.android.launcher3.pm.UserCache import com.android.launcher3.util.AllModulesForTest import com.android.launcher3.util.SandboxContext import com.android.launcher3.util.SplitConfigurationOptions +import com.android.launcher3.util.TestDispatcherProvider import com.android.launcher3.util.TransformingTouchDelegate import com.android.launcher3.util.UserIconInfo import com.android.quickstep.TaskOverlayFactory @@ -47,6 +48,7 @@ import com.android.systemui.shared.recents.model.Task.TaskKey import com.google.common.truth.Truth.assertThat import dagger.BindsInstance import dagger.Component +import kotlinx.coroutines.test.StandardTestDispatcher import org.junit.After import org.junit.Before import org.junit.Test @@ -64,6 +66,7 @@ class TaskViewItemInfoTest { private val overlayFactory = mock() private val userCache = mock() private val userInfo = mock() + private val dispatcher = StandardTestDispatcher() @Before fun setUp() { @@ -76,7 +79,7 @@ class TaskViewItemInfoTest { context.initDaggerComponent( DaggerTaskViewItemInfoTest_TestComponent.builder().bindUserCache(userCache) ) - RecentsDependencies.maybeInitialize(context) + RecentsDependencies.maybeInitialize(context, TestDispatcherProvider(dispatcher)) } @After diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java index 1e2f9ad21c..035c162526 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java @@ -51,7 +51,6 @@ import android.os.SystemClock; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; -import android.view.Display; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.ViewTreeObserver; @@ -136,6 +135,7 @@ public abstract class AbsSwipeUpHandlerTestCase< @Mock protected SystemUiController mSystemUiController; @Mock protected GestureState mGestureState; @Mock protected MSDLPlayerWrapper mMSDLPlayerWrapper; + @Mock protected RecentsAnimationDeviceState mDeviceState; @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -192,8 +192,7 @@ public abstract class AbsSwipeUpHandlerTestCase< @Before public void setUpRecentsContainer() { - mTaskAnimationManager = new TaskAnimationManager(mContext, - RecentsAnimationDeviceState.INSTANCE.get(mContext), DEFAULT_DISPLAY); + mTaskAnimationManager = new TaskAnimationManager(mContext, DEFAULT_DISPLAY); RecentsViewContainer recentsContainer = getRecentsContainer(); RECENTS_VIEW recentsView = getRecentsView(); diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java index 3489519e74..ef82ee5105 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java @@ -45,6 +45,7 @@ public class FallbackSwipeHandlerTestCase extends AbsSwipeUpHandlerTestCase< return new FallbackSwipeHandler( mContext, mTaskAnimationManager, + mDeviceState, mGestureState, touchTimeMs, continuingLastGesture, diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt index 5661dcf699..ce142cb127 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt @@ -53,6 +53,8 @@ class LauncherSwipeHandlerV2Test { @Mock private lateinit var taskAnimationManager: TaskAnimationManager + @Mock private lateinit var deviceState: RecentsAnimationDeviceState + private lateinit var gestureState: GestureState @Mock private lateinit var inputConsumerController: InputConsumerController @@ -89,7 +91,6 @@ class LauncherSwipeHandlerV2Test { DaggerTestComponent.builder() .bindSystemUiProxy(systemUiProxy) .bindRotationHelper(mock(RotationTouchHelper::class.java)) - .bindRecentsState(mock(RecentsAnimationDeviceState::class.java)) ) gestureState = spy( @@ -104,6 +105,7 @@ class LauncherSwipeHandlerV2Test { LauncherSwipeHandlerV2( sandboxContext, taskAnimationManager, + deviceState, gestureState, 0, false, @@ -138,8 +140,6 @@ interface TestComponent : LauncherAppComponent { @BindsInstance fun bindRotationHelper(helper: RotationTouchHelper): Builder - @BindsInstance fun bindRecentsState(state: RecentsAnimationDeviceState): Builder - override fun build(): TestComponent } } diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java index 66c4ab5ce3..0d0bec5122 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java @@ -76,6 +76,7 @@ public class LauncherSwipeHandlerV2TestCase extends AbsSwipeUpHandlerTestCase< return new LauncherSwipeHandlerV2( mContext, mTaskAnimationManager, + mDeviceState, mGestureState, touchTimeMs, continuingLastGesture, diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt index 600a29c055..3aa1e9fd9d 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt @@ -92,6 +92,7 @@ class OverviewCommandHelperTest { dispatcherProvider = TestDispatcherProvider(dispatcher), recentsDisplayModel = recentsDisplayModel, taskbarManager = mock(), + taskAnimationManagerRepository = mock(), ) ) diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt index a7370b02e9..9f8498b9ee 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt @@ -1,6 +1,6 @@ package com.android.quickstep -import android.view.Display +import android.view.Display.DEFAULT_DISPLAY import androidx.test.annotation.UiThreadTest import androidx.test.filters.SmallTest import com.android.launcher3.dagger.LauncherComponentProvider @@ -14,7 +14,6 @@ import com.android.launcher3.util.LauncherMultivalentJUnit import com.android.launcher3.util.NavigationMode import com.android.launcher3.util.SandboxApplication import com.android.quickstep.util.GestureExclusionManager -import com.android.systemui.shared.system.QuickStepContract import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION @@ -61,6 +60,7 @@ class RecentsAnimationDeviceStateTest { underTest = RecentsAnimationDeviceState( context, + DEFAULT_DISPLAY, exclusionManager, component.displayController, component.contextualSearchStateManager, @@ -152,7 +152,7 @@ class RecentsAnimationDeviceStateTest { allSysUiStates().forEach { state -> val canStartGesture = !disablingStates.contains(state) - underTest.setSysUIStateFlagsForDisplay(state, Display.DEFAULT_DISPLAY) + underTest.setSysUIStateFlags(state) assertThat(underTest.canStartTrackpadGesture()).isEqualTo(canStartGesture) } } @@ -168,7 +168,7 @@ class RecentsAnimationDeviceStateTest { ) stateToExpectedResult.forEach { (state, allowed) -> - underTest.setSysUIStateFlagsForDisplay(state, Display.DEFAULT_DISPLAY) + underTest.setSysUIStateFlags(state) assertThat(underTest.canStartTrackpadGesture()).isEqualTo(allowed) } } @@ -179,7 +179,7 @@ class RecentsAnimationDeviceStateTest { allSysUiStates().forEach { state -> val canStartGesture = !disablingStates.contains(state) - underTest.setSysUIStateFlagsForDisplay(state, Display.DEFAULT_DISPLAY) + underTest.setSysUIStateFlags(state) assertThat(underTest.canStartSystemGesture()).isEqualTo(canStartGesture) } } @@ -199,42 +199,11 @@ class RecentsAnimationDeviceStateTest { ) stateToExpectedResult.forEach { (state, gestureAllowed) -> - underTest.setSysUIStateFlagsForDisplay(state, Display.DEFAULT_DISPLAY) + underTest.setSysUIStateFlags(state) assertThat(underTest.canStartSystemGesture()).isEqualTo(gestureAllowed) } } - @Test - fun getSystemUiStateFlags_defaultAwake() { - val NOT_EXISTENT_DISPLAY = 2 - assertThat(underTest.getSystemUiStateFlags(NOT_EXISTENT_DISPLAY)) - .isEqualTo(QuickStepContract.SYSUI_STATE_AWAKE) - } - - @Test - fun clearSysUIStateFlagsForDisplay_displayNotReturnedAnymore() { - underTest.setSysUIStateFlagsForDisplay(1, /* displayId= */ 1) - - assertThat(underTest.displaysWithSysUIState).contains(1) - assertThat(underTest.getSystemUiStateFlags(1)).isEqualTo(1) - - underTest.clearSysUIStateFlagsForDisplay(1) - - assertThat(underTest.displaysWithSysUIState).doesNotContain(1) - assertThat(underTest.getSystemUiStateFlags(1)) - .isEqualTo(QuickStepContract.SYSUI_STATE_AWAKE) - } - - @Test - fun setSysUIStateFlagsForDisplay_setsCorrectly() { - underTest.setSysUIStateFlagsForDisplay(1, /* displayId= */ 1) - underTest.setSysUIStateFlagsForDisplay(2, /* displayId= */ 2) - - assertThat(underTest.getSystemUiStateFlags(1)).isEqualTo(1) - assertThat(underTest.getSystemUiStateFlags(2)).isEqualTo(2) - assertThat(underTest.displaysWithSysUIState).containsAtLeast(1, 2) - } - private fun allSysUiStates(): List { // SYSUI_STATES_* are binary flags return (0..SYSUI_STATES_COUNT).map { 1L shl it } diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java index c1be1cee9b..e2b1a55f97 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java @@ -63,6 +63,7 @@ public class RecentsWindowSwipeHandlerTestCase extends AbsSwipeUpHandlerTestCase return new RecentsWindowSwipeHandler( mContext, mTaskAnimationManager, + mDeviceState, mGestureState, touchTimeMs, continuingLastGesture, diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java index fd88a5cb27..11cfa09174 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java @@ -54,8 +54,7 @@ public class TaskAnimationManagerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mTaskAnimationManager = new TaskAnimationManager(mContext, - RecentsAnimationDeviceState.INSTANCE.get(mContext), Display.DEFAULT_DISPLAY) { + mTaskAnimationManager = new TaskAnimationManager(mContext, Display.DEFAULT_DISPLAY) { @Override SystemUiProxy getSystemUiProxy() { return mSystemUiProxy; diff --git a/quickstep/tests/src/com/android/quickstep/AspectRatioSystemShortcutTests.kt b/quickstep/tests/src/com/android/quickstep/AspectRatioSystemShortcutTests.kt index 10e85e6a1b..fa5766bade 100644 --- a/quickstep/tests/src/com/android/quickstep/AspectRatioSystemShortcutTests.kt +++ b/quickstep/tests/src/com/android/quickstep/AspectRatioSystemShortcutTests.kt @@ -43,6 +43,7 @@ import com.android.launcher3.model.data.ItemInfo import com.android.launcher3.model.data.TaskViewItemInfo import com.android.launcher3.util.RunnableList import com.android.launcher3.util.SplitConfigurationOptions +import com.android.launcher3.util.TestDispatcherProvider import com.android.launcher3.util.TransformingTouchDelegate import com.android.launcher3.util.WindowBounds import com.android.quickstep.orientation.LandscapePagedViewHandler @@ -61,6 +62,7 @@ import com.android.systemui.shared.recents.model.Task import com.android.systemui.shared.recents.model.Task.TaskKey import com.android.window.flags.Flags import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.StandardTestDispatcher import org.junit.After import org.junit.Before import org.junit.Rule @@ -124,8 +126,9 @@ class AspectRatioSystemShortcutTests { private val orientedState: RecentsOrientedState = mock(defaultAnswer = Mockito.RETURNS_DEEP_STUBS) private val taskView: TaskView = - LayoutInflater.from(context).cloneInContext(launcher).inflate(R.layout.task, null) as - TaskView + LayoutInflater.from(context).cloneInContext(launcher).inflate(R.layout.task, null) + as TaskView + private val dispatcher = StandardTestDispatcher() @Before fun setUp() { @@ -139,17 +142,18 @@ class AspectRatioSystemShortcutTests { taskView.setLayoutParams(ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)) if (enableRefactorTaskThumbnail()) { - val recentsDependencies = RecentsDependencies.maybeInitialize(launcher) + val recentsDependencies = + RecentsDependencies.maybeInitialize(launcher, TestDispatcherProvider(dispatcher)) val scopeId = recentsDependencies.createRecentsViewScope(launcher) recentsDependencies.provide( RecentsRotationStateRepository::class.java, scopeId, - { mock() } + { mock() }, ) recentsDependencies.provide( RecentsDeviceProfileRepository::class.java, scopeId, - { mock() } + { mock() }, ) } } diff --git a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java index 655560c0a6..bdca74d4f3 100644 --- a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java +++ b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java @@ -38,6 +38,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.app.displaylib.PerDisplayRepository; import com.android.launcher3.DeviceProfile; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.dagger.LauncherAppComponent; @@ -113,6 +114,7 @@ public class InputConsumerUtilsTest { @NonNull @Mock private TaskbarActivityContext mTaskbarActivityContext; @NonNull @Mock private OverviewComponentObserver mOverviewComponentObserver; @NonNull @Mock private RecentsAnimationDeviceState mDeviceState; + @NonNull @Mock private PerDisplayRepository mDeviceStateRepo; @NonNull @Mock private AbsSwipeUpHandler.Factory mSwipeUpHandlerFactory; @NonNull @Mock private TaskbarManager mTaskbarManager; @NonNull @Mock private OverviewCommandHelper mOverviewCommandHelper; @@ -128,7 +130,7 @@ public class InputConsumerUtilsTest { @Before public void setupTaskAnimationManager() { - mTaskAnimationManager = new TaskAnimationManager(mContext, mDeviceState, mDisplayId); + mTaskAnimationManager = new TaskAnimationManager(mContext, mDisplayId); } @Before @@ -136,8 +138,8 @@ public class InputConsumerUtilsTest { mContext.initDaggerComponent(DaggerInputConsumerUtilsTest_TestComponent .builder() .bindLockedState(mLockedUserState) - .bindRotationHelper(mock(RotationTouchHelper.class)) - .bindRecentsState(mDeviceState)); + .bindRotationHelper(mock(RotationTouchHelper.class))); +// .bindRecentsState(mDeviceState)); } @Before @@ -193,6 +195,7 @@ public class InputConsumerUtilsTest { @Before public void setupDeviceState() { + when(mDeviceStateRepo.get(anyInt())).thenReturn(mDeviceState); when(mDeviceState.canStartTrackpadGesture()).thenReturn(true); when(mDeviceState.canStartSystemGesture()).thenReturn(true); when(mDeviceState.isFullyGesturalNavMode()).thenReturn(true); @@ -626,7 +629,6 @@ public class InputConsumerUtilsTest { interface Builder extends LauncherAppComponent.Builder { @BindsInstance Builder bindLockedState(LockedUserState state); @BindsInstance Builder bindRotationHelper(RotationTouchHelper helper); - @BindsInstance Builder bindRecentsState(RecentsAnimationDeviceState state); @Override TestComponent build(); diff --git a/src/com/android/launcher3/dagger/LauncherAppModule.java b/src/com/android/launcher3/dagger/LauncherAppModule.java index 0fd32190c4..ef20a616a6 100644 --- a/src/com/android/launcher3/dagger/LauncherAppModule.java +++ b/src/com/android/launcher3/dagger/LauncherAppModule.java @@ -24,7 +24,9 @@ import dagger.Module; PluginManagerWrapperModule.class, StaticObjectModule.class, WidgetModule.class, - AppModule.class + AppModule.class, + PerDisplayModule.class, + LauncherConcurrencyModule.class, }) public class LauncherAppModule { } diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index a062a54ee3..0e9ddd2ab4 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -84,6 +84,8 @@ import com.android.launcher3.dagger.AppModule; import com.android.launcher3.dagger.LauncherAppComponent; import com.android.launcher3.dagger.LauncherAppSingleton; import com.android.launcher3.dagger.LauncherComponentProvider; +import com.android.launcher3.dagger.LauncherConcurrencyModule; +import com.android.launcher3.dagger.PerDisplayModule; import com.android.launcher3.dagger.PluginManagerWrapperModule; import com.android.launcher3.dagger.StaticObjectModule; import com.android.launcher3.dagger.WindowManagerProxyModule; @@ -670,7 +672,10 @@ public class LauncherPreviewRenderer extends BaseContext ApiWrapperModule.class, PluginManagerWrapperModule.class, StaticObjectModule.class, - AppModule.class}) + AppModule.class, + PerDisplayModule.class, + LauncherConcurrencyModule.class, + }) public interface PreviewAppComponent extends LauncherAppComponent { LoaderTaskFactory getLoaderTaskFactory(); diff --git a/src_no_quickstep/com/android/launcher3/dagger/Modules.kt b/src_no_quickstep/com/android/launcher3/dagger/Modules.kt index 21d8e06cdd..244634022a 100644 --- a/src_no_quickstep/com/android/launcher3/dagger/Modules.kt +++ b/src_no_quickstep/com/android/launcher3/dagger/Modules.kt @@ -44,3 +44,7 @@ abstract class StaticObjectModule { // Module containing bindings for the final derivative app @Module abstract class AppModule {} + +@Module abstract class PerDisplayModule {} + +@Module abstract class LauncherConcurrencyModule {} diff --git a/tests/multivalentTests/src/com/android/launcher3/util/DaggerGraphs.kt b/tests/multivalentTests/src/com/android/launcher3/util/DaggerGraphs.kt index a76ccf015e..22f04f49b6 100644 --- a/tests/multivalentTests/src/com/android/launcher3/util/DaggerGraphs.kt +++ b/tests/multivalentTests/src/com/android/launcher3/util/DaggerGraphs.kt @@ -20,6 +20,8 @@ import com.android.launcher3.FakeLauncherPrefs import com.android.launcher3.LauncherPrefs import com.android.launcher3.dagger.ApiWrapperModule import com.android.launcher3.dagger.AppModule +import com.android.launcher3.dagger.LauncherConcurrencyModule +import com.android.launcher3.dagger.PerDisplayModule import com.android.launcher3.dagger.StaticObjectModule import com.android.launcher3.dagger.WidgetModule import com.android.launcher3.dagger.WindowManagerProxyModule @@ -33,34 +35,29 @@ abstract class FakePrefsModule { @Binds abstract fun bindLauncherPrefs(prefs: FakeLauncherPrefs): LauncherPrefs } -/** All modules. We also exclude the plugin module from tests */ @Module( includes = [ - ApiWrapperModule::class, - WindowManagerProxyModule::class, StaticObjectModule::class, WidgetModule::class, AppModule::class, + PerDisplayModule::class, + LauncherConcurrencyModule::class, ] ) +class CommonModulesForTest + +/** All modules. We also exclude the plugin module from tests */ +@Module( + includes = + [ApiWrapperModule::class, CommonModulesForTest::class, WindowManagerProxyModule::class] +) class AllModulesForTest /** All modules except the WMProxy */ -@Module( - includes = - [ApiWrapperModule::class, StaticObjectModule::class, AppModule::class, WidgetModule::class] -) +@Module(includes = [ApiWrapperModule::class, CommonModulesForTest::class]) class AllModulesMinusWMProxy /** All modules except the ApiWrapper */ -@Module( - includes = - [ - WindowManagerProxyModule::class, - StaticObjectModule::class, - AppModule::class, - WidgetModule::class, - ] -) +@Module(includes = [WindowManagerProxyModule::class, CommonModulesForTest::class]) class AllModulesMinusApiWrapper