diff --git a/quickstep/src/com/android/launcher3/dagger/PerDisplayModule.kt b/quickstep/src/com/android/launcher3/dagger/PerDisplayModule.kt index 74be5e63f7..256d9272e7 100644 --- a/quickstep/src/com/android/launcher3/dagger/PerDisplayModule.kt +++ b/quickstep/src/com/android/launcher3/dagger/PerDisplayModule.kt @@ -27,6 +27,8 @@ import com.android.app.displaylib.DefaultDisplayOnlyInstanceRepositoryImpl import com.android.app.displaylib.DisplayLibBackground import com.android.app.displaylib.DisplayLibComponent import com.android.app.displaylib.DisplayRepository +import com.android.app.displaylib.DisplaysWithDecorationsRepository +import com.android.app.displaylib.DisplaysWithDecorationsRepositoryCompat import com.android.app.displaylib.PerDisplayInstanceRepositoryImpl import com.android.app.displaylib.PerDisplayRepository import com.android.app.displaylib.SingleInstanceRepositoryImpl @@ -240,6 +242,22 @@ object DisplayLibModule { return displayLibComponent.displayRepository } + @Provides + @LauncherAppSingleton + fun providesDisplaysWithDecorationsRepository( + displayLibComponent: DisplayLibComponent + ): DisplaysWithDecorationsRepository { + return displayLibComponent.displaysWithDecorationsRepository + } + + @Provides + @LauncherAppSingleton + fun providesDisplaysWithDecorationsRepositoryCompat( + displayLibComponent: DisplayLibComponent + ): DisplaysWithDecorationsRepositoryCompat { + return displayLibComponent.displaysWithDecorationsRepositoryCompat + } + @Provides fun dumpRegistrationLambda(): PerDisplayRepository.InitCallback = PerDisplayRepository.InitCallback { debugName, _ -> diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.kt index ecf72e3664..36929c524a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.kt @@ -17,15 +17,15 @@ package com.android.launcher3.taskbar import android.app.PendingIntent +import com.android.app.displaylib.DisplayDecorationListener import com.android.launcher3.anim.AnimatorPlaybackController import com.android.launcher3.statemanager.StatefulActivity -import com.android.quickstep.SystemDecorationChangeObserver import com.android.quickstep.views.RecentsViewContainer import com.android.systemui.shared.statusbar.phone.BarTransitions import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags import java.io.PrintWriter -interface TaskbarManager : SystemDecorationChangeObserver.DisplayDecorationListener { +interface TaskbarManager : DisplayDecorationListener { fun createLauncherStartFromSuwAnim(duration: Int): AnimatorPlaybackController? diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManagerImpl.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManagerImpl.java index 202e9e8996..90173a1bc7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManagerImpl.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManagerImpl.java @@ -41,6 +41,7 @@ import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange; import static com.android.quickstep.util.SystemActionConstants.ACTION_SHOW_TASKBAR; import static com.android.quickstep.util.SystemActionConstants.SYSTEM_ACTION_ID_TASKBAR; import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.enableMultipleDesktops; +import static com.android.window.flags.Flags.enableSysDecorsCallbacksViaWm; import android.animation.AnimatorSet; import android.annotation.SuppressLint; @@ -73,6 +74,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import com.android.app.displaylib.DisplayDecorationListener; +import com.android.app.displaylib.DisplaysWithDecorationsRepositoryCompat; import com.android.app.displaylib.PerDisplayRepository; import com.android.internal.util.LatencyTracker; import com.android.launcher3.DeviceProfile; @@ -95,7 +98,6 @@ import com.android.quickstep.BaseContainerInterface; import com.android.quickstep.OverviewComponentObserver; import com.android.quickstep.RecentsActivity; import com.android.quickstep.SystemDecorationChangeObserver; -import com.android.quickstep.SystemDecorationChangeObserver.DisplayDecorationListener; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.fallback.window.RecentsWindowManager; import com.android.quickstep.util.ContextualSearchInvoker; @@ -112,6 +114,8 @@ import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.systemui.unfold.UnfoldTransitionProgressProvider; import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider; +import kotlinx.coroutines.CoroutineDispatcher; + import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.HashMap; @@ -166,6 +170,7 @@ public class TaskbarManagerImpl implements DisplayDecorationListener { private ComponentCallbacks mPrimaryComponentCallbacks; private final SimpleBroadcastReceiver mShutdownReceiver; + private final DisplaysWithDecorationsRepositoryCompat mDisplaysWithDecorationsRepositoryCompat; private final LooperExecutor mPerWindowUiExecutor = new LooperExecutor("TaskbarUiThread", THREAD_PRIORITY_FOREGROUND); @@ -457,12 +462,15 @@ public class TaskbarManagerImpl implements DisplayDecorationListener { Context context, AllAppsActionManager allAppsActionManager, TaskbarNavButtonCallbacks navCallbacks, - PerDisplayRepository recentsWindowManagerRepository) { + PerDisplayRepository recentsWindowManagerRepository, + DisplaysWithDecorationsRepositoryCompat displaysWithDecorationsRepositoryCompat, + CoroutineDispatcher dispatcher) { mBaseContext = context; mPrimaryDisplayId = mBaseContext.getDisplayId(); mAllAppsActionManager = allAppsActionManager; mNavCallbacks = navCallbacks; mRecentsWindowManagerRepository = recentsWindowManagerRepository; + mDisplaysWithDecorationsRepositoryCompat = displaysWithDecorationsRepositoryCompat; // Set up primary display. debugPrimaryTaskbar("TaskbarManager constructor"); @@ -481,8 +489,14 @@ public class TaskbarManagerImpl implements DisplayDecorationListener { .register(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener); SettingsCache.INSTANCE.get(mPrimaryWindowContext) .register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener); - SystemDecorationChangeObserver.getINSTANCE().get(mPrimaryWindowContext) - .registerDisplayDecorationListener(this); + if (enableSysDecorsCallbacksViaWm()) { + displaysWithDecorationsRepositoryCompat + .registerDisplayDecorationListener(this, dispatcher); + } else { + SystemDecorationChangeObserver.getINSTANCE().get(mPrimaryWindowContext) + .registerDisplayDecorationListener(this); + addSystemDecorationForDisplaysAtBoot(); + } mShutdownReceiver = new SimpleBroadcastReceiver( mPrimaryWindowContext, UI_HELPER_EXECUTOR, i -> destroyAllTaskbars()); @@ -510,12 +524,13 @@ public class TaskbarManagerImpl implements DisplayDecorationListener { } recreateTaskbarForDisplay(mPrimaryDisplayId, /* duration= */ 0); - // TODO b/408503553: Remove when WM is used instead of CommandQueue for system decorations. - addSystemDecorationForDisplaysAtBoot(); debugPrimaryTaskbar("TaskbarManager created"); } - /** Calls {@link #onDisplayAddSystemDecorations(int)} for all displays. */ + /** + * Calls {@link #onDisplayAddSystemDecorations(int)} for all displays + * TODO b/408503553: Remove when WM is used instead of CommandQueue for system decorations. + */ private void addSystemDecorationForDisplaysAtBoot() { if (mDisplayManager == null) { return; @@ -1160,8 +1175,12 @@ public class TaskbarManagerImpl implements DisplayDecorationListener { .unregister(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener); SettingsCache.INSTANCE.get(mPrimaryWindowContext) .unregister(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener); - SystemDecorationChangeObserver.getINSTANCE().get(mPrimaryWindowContext) - .unregisterDisplayDecorationListener(this); + if (enableSysDecorsCallbacksViaWm()) { + mDisplaysWithDecorationsRepositoryCompat.unregisterDisplayDecorationListener(this); + } else { + SystemDecorationChangeObserver.getINSTANCE().get(mPrimaryWindowContext) + .unregisterDisplayDecorationListener(this); + } debugPrimaryTaskbar("destroy: unregistering component callbacks"); removeAndUnregisterComponentCallbacks(mPrimaryDisplayId); mShutdownReceiver.unregisterReceiverSafely(); diff --git a/quickstep/src/com/android/quickstep/DisplayModel.kt b/quickstep/src/com/android/quickstep/DisplayModel.kt index 9dbedb7db5..c8fe5458bf 100644 --- a/quickstep/src/com/android/quickstep/DisplayModel.kt +++ b/quickstep/src/com/android/quickstep/DisplayModel.kt @@ -22,14 +22,19 @@ import android.util.Log import android.util.SparseArray import android.view.Display import androidx.core.util.valueIterator +import com.android.app.displaylib.DisplayDecorationListener +import com.android.app.displaylib.DisplaysWithDecorationsRepositoryCompat import com.android.quickstep.DisplayModel.DisplayResource -import com.android.quickstep.SystemDecorationChangeObserver.DisplayDecorationListener +import com.android.window.flags.Flags.enableSysDecorsCallbacksViaWm import java.io.PrintWriter +import kotlinx.coroutines.CoroutineDispatcher /** data model for managing resources with lifecycles that match that of the connected display */ abstract class DisplayModel( val context: Context, private val systemDecorationChangeObserver: SystemDecorationChangeObserver, + private val displaysWithDecorationsRepositoryCompat: DisplaysWithDecorationsRepositoryCompat, + private val dispatcher: CoroutineDispatcher, ) : DisplayDecorationListener { companion object { @@ -58,14 +63,25 @@ abstract class DisplayModel( protected abstract fun createDisplayResource(display: Display): RESOURCE_TYPE protected fun initializeDisplays() { - systemDecorationChangeObserver.registerDisplayDecorationListener(this) + if (enableSysDecorsCallbacksViaWm()) { + displaysWithDecorationsRepositoryCompat.registerDisplayDecorationListener( + this, + dispatcher, + ) + } else { + systemDecorationChangeObserver.registerDisplayDecorationListener(this) + } displayManager.displays .filter { getDisplayResource(it.displayId) == null } .forEach { storeDisplayResource(it.displayId) } } fun destroy() { - systemDecorationChangeObserver.unregisterDisplayDecorationListener(this) + if (enableSysDecorsCallbacksViaWm()) { + displaysWithDecorationsRepositoryCompat.unregisterDisplayDecorationListener(this) + } else { + systemDecorationChangeObserver.unregisterDisplayDecorationListener(this) + } displayResourceArray.valueIterator().forEach { displayResource -> displayResource.cleanup() } diff --git a/quickstep/src/com/android/quickstep/LauncherDisplaysWithDecorationsRepositoryCompat.kt b/quickstep/src/com/android/quickstep/LauncherDisplaysWithDecorationsRepositoryCompat.kt new file mode 100644 index 0000000000..5d61abb377 --- /dev/null +++ b/quickstep/src/com/android/quickstep/LauncherDisplaysWithDecorationsRepositoryCompat.kt @@ -0,0 +1,26 @@ +/* + * 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 LauncherDisplaysWithDecorationsRepositoryCompat { + @JvmStatic + val INSTANCE = + DaggerSingletonObject(QuickstepBaseAppComponent::getDisplaysWithDecorationsRepositoryCompat) +} diff --git a/quickstep/src/com/android/quickstep/SystemDecorationChangeObserver.kt b/quickstep/src/com/android/quickstep/SystemDecorationChangeObserver.kt index 45594786aa..d93f5f5e5d 100644 --- a/quickstep/src/com/android/quickstep/SystemDecorationChangeObserver.kt +++ b/quickstep/src/com/android/quickstep/SystemDecorationChangeObserver.kt @@ -18,6 +18,7 @@ package com.android.quickstep import android.content.Context import android.util.Log +import com.android.app.displaylib.DisplayDecorationListener import com.android.launcher3.dagger.ApplicationContext import com.android.launcher3.dagger.LauncherAppSingleton import com.android.launcher3.util.DaggerSingletonObject @@ -38,14 +39,6 @@ class SystemDecorationChangeObserver @Inject constructor(@ApplicationContext con ) } - interface DisplayDecorationListener { - fun onDisplayAddSystemDecorations(displayId: Int) - - fun onDisplayRemoved(displayId: Int) - - fun onDisplayRemoveSystemDecorations(displayId: Int) - } - fun notifyAddSystemDecorations(displayId: Int) { if (DEBUG) Log.d(TAG, "SystemDecorationAdded: $displayId") for (listener in mDisplayDecorationListeners) { diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 0d87c228ea..e4d9776ec8 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -70,6 +70,7 @@ import androidx.annotation.UiThread; import androidx.annotation.VisibleForTesting; import com.android.app.displaylib.DisplayRepository; +import com.android.app.displaylib.DisplaysWithDecorationsRepositoryCompat; import com.android.app.displaylib.PerDisplayRepository; import com.android.launcher3.ConstantItem; import com.android.launcher3.EncryptionType; @@ -98,6 +99,7 @@ import com.android.launcher3.util.PluginManagerWrapper; import com.android.launcher3.util.SafeCloseable; import com.android.launcher3.util.ScreenOnTracker; import com.android.launcher3.util.TraceHelper; +import com.android.launcher3.util.coroutines.ProductionDispatchers; import com.android.quickstep.OverviewCommandHelper.CommandType; import com.android.quickstep.OverviewComponentObserver.OverviewChangeListener; import com.android.quickstep.actioncorner.ActionCornerHandler; @@ -139,6 +141,8 @@ import com.android.wm.shell.shared.IShellTransitions; import com.android.wm.shell.splitscreen.ISplitScreen; import com.android.wm.shell.startingsurface.IStartingWindow; +import kotlinx.coroutines.CoroutineDispatcher; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -722,6 +726,8 @@ public class TouchInteractionService extends Service { private DisplayRepository mDisplayRepository; private QuickstepKeyGestureEventsManager mQuickstepKeyGestureEventsHandler; + private DisplaysWithDecorationsRepositoryCompat mDisplaysWithDecorationsRepositoryCompat; + private CoroutineDispatcher mCoroutineDispatcher; @Override public void onCreate() { @@ -738,6 +744,9 @@ public class TouchInteractionService extends Service { mRecentsWindowManagerRepository = RecentsWindowManager.REPOSITORY_INSTANCE.get(this); mSystemDecorationChangeObserver = SystemDecorationChangeObserver.getINSTANCE().get(this); mQuickstepKeyGestureEventsHandler = new QuickstepKeyGestureEventsManager(this); + mCoroutineDispatcher = ProductionDispatchers.INSTANCE.getMain(); + mDisplaysWithDecorationsRepositoryCompat = + LauncherDisplaysWithDecorationsRepositoryCompat.getINSTANCE().get(this); mAllAppsActionManager = new AllAppsActionManager(this, UI_HELPER_EXECUTOR, mQuickstepKeyGestureEventsHandler, () -> mTaskbarManager.createAllAppsPendingIntent()); @@ -752,7 +761,8 @@ public class TouchInteractionService extends Service { mTaskbarManager = new TaskbarManagerImplWrapper( new TaskbarManagerImpl(this, mAllAppsActionManager, mNavCallbacks, - mRecentsWindowManagerRepository)); + mRecentsWindowManagerRepository, mDisplaysWithDecorationsRepositoryCompat, + mCoroutineDispatcher)); mDesktopAppLaunchTransitionManager = new DesktopAppLaunchTransitionManager(this, SystemUiProxy.INSTANCE.get(this)); mDesktopAppLaunchTransitionManager.registerTransitions(); @@ -1497,7 +1507,8 @@ public class TouchInteractionService extends Service { private InputMonitorDisplayModel( Context context, SystemDecorationChangeObserver systemDecorationChangeObserver) { - super(context, systemDecorationChangeObserver); + super(context, systemDecorationChangeObserver, mDisplaysWithDecorationsRepositoryCompat, + mCoroutineDispatcher); initializeDisplays(); } diff --git a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java index a3d222f167..3d16fc466d 100644 --- a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java +++ b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java @@ -17,6 +17,7 @@ package com.android.quickstep.dagger; import com.android.app.displaylib.DisplayRepository; +import com.android.app.displaylib.DisplaysWithDecorationsRepositoryCompat; import com.android.app.displaylib.PerDisplayRepository; import com.android.launcher3.dagger.LauncherAppComponent; import com.android.launcher3.dagger.LauncherBaseAppComponent; @@ -89,4 +90,6 @@ public interface QuickstepBaseAppComponent extends LauncherBaseAppComponent { /** Gets the factory to create a new ActionCornerHandlerFactory */ ActionCornerHandler.Factory getActionCornerHandlerFactory(); + + DisplaysWithDecorationsRepositoryCompat getDisplaysWithDecorationsRepositoryCompat(); } diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt index 8827836d07..a8ae8b9266 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt @@ -33,7 +33,9 @@ import com.android.launcher3.taskbar.bubbles.BubbleControllers import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR import com.android.launcher3.util.TestUtil +import com.android.launcher3.util.coroutines.ProductionDispatchers import com.android.quickstep.AllAppsActionManager +import com.android.quickstep.LauncherDisplaysWithDecorationsRepositoryCompat import com.android.quickstep.fallback.window.RecentsWindowManager import com.android.quickstep.input.QuickstepKeyGestureEventsManager import java.lang.reflect.Field @@ -118,6 +120,10 @@ class TaskbarUnitTestRule( }, object : TaskbarNavButtonCallbacks {}, RecentsWindowManager.REPOSITORY_INSTANCE.get(context), + LauncherDisplaysWithDecorationsRepositoryCompat.INSTANCE.get( + context + ), + ProductionDispatchers.main, ) { override fun recreateTaskbars() { super.recreateTaskbars() diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/DisplayModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/DisplayModelTest.kt index bc2a9df6b5..3aab528437 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/DisplayModelTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/DisplayModelTest.kt @@ -21,11 +21,14 @@ import android.view.Display import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.app.displaylib.DisplaysWithDecorationsRepositoryCompat import java.io.PrintWriter +import kotlinx.coroutines.test.StandardTestDispatcher import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.mock @SmallTest @RunWith(AndroidJUnit4::class) @@ -33,6 +36,8 @@ class DisplayModelTest { private val context: Context = ApplicationProvider.getApplicationContext() private val systemDecorationChangeObserver = SystemDecorationChangeObserver.INSTANCE.get(context) + private val displayRepositoryCompat = mock() + private val dispatcher = StandardTestDispatcher() class TestableResource : DisplayModel.DisplayResource() { var isCleanupCalled = false @@ -47,7 +52,13 @@ class DisplayModelTest { } private val testableDisplayModel = - object : DisplayModel(context, systemDecorationChangeObserver) { + object : + DisplayModel( + context, + systemDecorationChangeObserver, + displayRepositoryCompat, + dispatcher, + ) { override fun createDisplayResource(display: Display): TestableResource { return TestableResource() }