diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java index f5678776ed78d..c3ce3627fb0bd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java @@ -74,7 +74,7 @@ public class ShellInitImpl { Optional pipTouchHandlerOptional, FullscreenTaskListener fullscreenTaskListener, Optional fullscreenUnfoldTransitionController, - Optional> freeformTaskListenerOptional, + Optional freeformTaskListenerOptional, Optional recentTasks, Transitions transitions, StartingWindowController startingWindow, @@ -90,7 +90,7 @@ public class ShellInitImpl { mFullscreenTaskListener = fullscreenTaskListener; mPipTouchHandlerOptional = pipTouchHandlerOptional; mFullscreenUnfoldController = fullscreenUnfoldTransitionController; - mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f); + mFreeformTaskListenerOptional = freeformTaskListenerOptional; mRecentTasks = recentTasks; mTransitions = transitions; mMainExecutor = mainExecutor; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java new file mode 100644 index 0000000000000..806f795d10158 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2021 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.wm.shell.dagger; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Qualifier; + +/** + * This is a qualifier that Shell uses to workaround an issue with providing nullable optionals + * which are by default unbound. + * + * For example, ideally we would have this scenario: + * BaseModule: + * @BindsOptionalOf + * abstract Optional optionalInterface(); + * + * SpecializedModule: + * @Provides + * static Interface providesInterface() { + * return new InterfaceImpl(); + * } + * + * However, if the interface is supposed to be provided dynamically, then Dagger is not able to bind + * the optional interface to a null instance, and @BindsOptionalOf does not support @Nullable + * instances of the interface provided by the specialized module. + * + * For example, this does not work: + * BaseModule: + * @BindsOptionalOf + * abstract Optional optionalInterface(); + * + * SpecializedModule: + * @Provides + * static Interface providesInterface() { + * if (systemSupportsInterfaceFeature) { + * return new InterfaceImpl(); + * } else { + * return null; + * } + * } + * + * To workaround this, we can instead upstream the check (assuming it can be upstreamed into the + * base module), and then always provide a non-null instance in the specialized module. + * + * For example: + * BaseModule: + * @BindsOptionalOf + * @DynamicOverride + * abstract Interface dynamicInterface(); + * + * @Provides + * static Optional providesOptionalInterface( + * @DynamicOverride Optional interface) { + * if (systemSupportsInterfaceFeature) { + * return interface; + * } + * return Optional.empty(); + * } + * + * SpecializedModule: + * @Provides + * @DynamicOverride + * static Interface providesInterface() { + * return new InterfaceImpl(); + * } + * + * This is also useful in cases where there needs to be a default implementation in the base module + * which is also overridable in the specialized module. This isn't generally recommended, but + * due to the nature of Shell modules being referenced from a number of various projects, this + * can be useful for *required* components that + * 1) clearly identifies which are intended for overriding in the base module, and + * 2) allows us to declare a default implementation in the base module, without having to force + * every SysUI impl to explicitly provide it (if a large number of them share the default impl) + * + * For example, this uses the same setup as above, but the interface provided (if bound) is used + * otherwise the default is created: + * @BindsOptionalOf + * @DynamicOverride + * abstract Interface dynamicInterface(); + * + * @Provides + * static Optional providesOptionalInterface( + * @DynamicOverride Optional overrideInterfaceImpl) { + * if (overrideInterfaceImpl.isPresent()) { + * return overrideInterfaceImpl.get(); + * } + * return new DefaultImpl(); + * } + * + * SpecializedModule: + * @Provides + * @DynamicOverride + * static Interface providesInterface() { + * return new SuperSpecialImpl(); + * } + */ +@Documented +@Inherited +@Qualifier +@Retention(RetentionPolicy.RUNTIME) +public @interface DynamicOverride {} \ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java index 6997d60c75f14..15bfeb297b41e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java @@ -16,25 +16,16 @@ package com.android.wm.shell.dagger; -import android.animation.AnimationHandler; -import android.content.Context; import android.view.IWindowManager; -import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.SystemWindows; -import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.TransactionPool; -import com.android.wm.shell.common.annotations.ChoreographerSfVsync; import com.android.wm.shell.common.annotations.ShellMainThread; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; import com.android.wm.shell.startingsurface.tv.TvStartingWindowTypeAlgorithm; -import com.android.wm.shell.transition.Transitions; import dagger.Module; import dagger.Provides; @@ -50,43 +41,13 @@ import dagger.Provides; @Module(includes = {TvPipModule.class}) public class TvWMShellModule { - // - // Internal common - Components used internally by multiple shell features - // - - @WMSingleton - @Provides - static DisplayImeController provideDisplayImeController(IWindowManager wmService, - DisplayController displayController, DisplayInsetsController displayInsetsController, - @ShellMainThread ShellExecutor mainExecutor, TransactionPool transactionPool) { - return new DisplayImeController(wmService, displayController, displayInsetsController, - mainExecutor, transactionPool); - } - - // - // Split/multiwindow - // - - @WMSingleton - @Provides - static LegacySplitScreenController provideSplitScreen(Context context, - DisplayController displayController, SystemWindows systemWindows, - DisplayImeController displayImeController, TransactionPool transactionPool, - ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, - TaskStackListenerImpl taskStackListener, Transitions transitions, - @ShellMainThread ShellExecutor mainExecutor, - @ChoreographerSfVsync AnimationHandler sfVsyncAnimationHandler) { - return new LegacySplitScreenController(context, displayController, systemWindows, - displayImeController, transactionPool, shellTaskOrganizer, syncQueue, - taskStackListener, transitions, mainExecutor, sfVsyncAnimationHandler); - } - // // Starting Windows (Splash Screen) // @WMSingleton @Provides + @DynamicOverride static StartingWindowTypeAlgorithm provideStartingWindowTypeAlgorithm() { return new TvStartingWindowTypeAlgorithm(); }; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index ac2e448eab589..3f5b70bac6e1e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -16,16 +16,16 @@ package com.android.wm.shell.dagger; +import static com.android.wm.shell.onehanded.OneHandedController.SUPPORT_ONE_HANDED_MODE; + import android.app.ActivityTaskManager; import android.content.Context; -import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.os.Handler; +import android.os.SystemProperties; import android.view.IWindowManager; -import android.view.WindowManager; import com.android.internal.logging.UiEventLogger; -import com.android.internal.statusbar.IStatusBarService; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.RootDisplayAreaOrganizer; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; @@ -77,23 +77,19 @@ import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.sizecompatui.SizeCompatUIController; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreenController; -import com.android.wm.shell.splitscreen.StageTaskUnfoldController; import com.android.wm.shell.startingsurface.StartingSurface; import com.android.wm.shell.startingsurface.StartingWindowController; import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; +import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm; import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper; import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelperController; import com.android.wm.shell.transition.ShellTransitions; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider; -import com.android.wm.shell.unfold.UnfoldBackgroundController; import java.util.Optional; -import javax.inject.Provider; - import dagger.BindsOptionalOf; -import dagger.Lazy; import dagger.Module; import dagger.Provides; @@ -128,6 +124,28 @@ public abstract class WMShellBaseModule { return new DisplayInsetsController(wmService, displayController, mainExecutor); } + // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} + @BindsOptionalOf + @DynamicOverride + abstract DisplayImeController optionalDisplayImeController(); + + @WMSingleton + @Provides + static DisplayImeController provideDisplayImeController( + @DynamicOverride Optional overrideDisplayImeController, + IWindowManager wmService, + DisplayController displayController, + DisplayInsetsController displayInsetsController, + @ShellMainThread ShellExecutor mainExecutor, + TransactionPool transactionPool + ) { + if (overrideDisplayImeController.isPresent()) { + return overrideDisplayImeController.get(); + } + return new DisplayImeController(wmService, displayController, displayInsetsController, + mainExecutor, transactionPool); + } + @WMSingleton @Provides static DisplayLayout provideDisplayLayout() { @@ -202,7 +220,7 @@ public abstract class WMShellBaseModule { } // - // Bubbles + // Bubbles (optional feature) // @WMSingleton @@ -211,27 +229,8 @@ public abstract class WMShellBaseModule { return bubbleController.map((controller) -> controller.asBubbles()); } - // Note: Handler needed for LauncherApps.register - @WMSingleton - @Provides - static Optional provideBubbleController(Context context, - FloatingContentCoordinator floatingContentCoordinator, - IStatusBarService statusBarService, - WindowManager windowManager, - WindowManagerShellWrapper windowManagerShellWrapper, - LauncherApps launcherApps, - TaskStackListenerImpl taskStackListener, - UiEventLogger uiEventLogger, - ShellTaskOrganizer organizer, - DisplayController displayController, - @ShellMainThread ShellExecutor mainExecutor, - @ShellMainThread Handler mainHandler, - SyncTransactionQueue syncQueue) { - return Optional.of(BubbleController.create(context, null /* synchronizer */, - floatingContentCoordinator, statusBarService, windowManager, - windowManagerShellWrapper, launcherApps, taskStackListener, - uiEventLogger, organizer, displayController, mainExecutor, mainHandler, syncQueue)); - } + @BindsOptionalOf + abstract BubbleController optionalBubblesController(); // // Fullscreen @@ -252,59 +251,45 @@ public abstract class WMShellBaseModule { // Unfold transition // + @BindsOptionalOf + abstract ShellUnfoldProgressProvider optionalShellUnfoldProgressProvider(); + + // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} + @BindsOptionalOf + @DynamicOverride + abstract FullscreenUnfoldController optionalFullscreenUnfoldController(); + @WMSingleton @Provides static Optional provideFullscreenUnfoldController( - Context context, - Optional progressProvider, - Lazy unfoldBackgroundController, - DisplayInsetsController displayInsetsController, - @ShellMainThread ShellExecutor mainExecutor - ) { - return progressProvider.map(shellUnfoldTransitionProgressProvider -> - new FullscreenUnfoldController(context, mainExecutor, - unfoldBackgroundController.get(), shellUnfoldTransitionProgressProvider, - displayInsetsController)); - } - - @Provides - static Optional provideStageTaskUnfoldController( - Optional progressProvider, - Context context, - TransactionPool transactionPool, - Lazy unfoldBackgroundController, - DisplayInsetsController displayInsetsController, - @ShellMainThread ShellExecutor mainExecutor - ) { - return progressProvider.map(shellUnfoldTransitionProgressProvider -> - new StageTaskUnfoldController( - context, - transactionPool, - shellUnfoldTransitionProgressProvider, - displayInsetsController, - unfoldBackgroundController.get(), - mainExecutor - )); - } - - @WMSingleton - @Provides - static UnfoldBackgroundController provideUnfoldBackgroundController( - RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, - Context context - ) { - return new UnfoldBackgroundController( - context, - rootTaskDisplayAreaOrganizer - ); + @DynamicOverride Optional fullscreenUnfoldController, + Optional progressProvider) { + if (progressProvider.isPresent() + && progressProvider.get() != ShellUnfoldProgressProvider.NO_PROVIDER) { + return fullscreenUnfoldController; + } + return Optional.empty(); } // // Freeform (optional feature) // + // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} @BindsOptionalOf - abstract Optional optionalFreeformTaskListener(); + @DynamicOverride + abstract FreeformTaskListener optionalFreeformTaskListener(); + + @WMSingleton + @Provides + static Optional provideFreeformTaskListener( + @DynamicOverride Optional freeformTaskListener, + Context context) { + if (FreeformTaskListener.isFreeformEnabled(context)) { + return freeformTaskListener; + } + return Optional.empty(); + } // // Hide display cutout @@ -335,20 +320,22 @@ public abstract class WMShellBaseModule { return oneHandedController.map((controller) -> controller.asOneHanded()); } - // Needs the shell main handler for ContentObserver callbacks + // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} + @BindsOptionalOf + @DynamicOverride + abstract OneHandedController optionalOneHandedController(); + @WMSingleton @Provides - static Optional provideOneHandedController(Context context, - WindowManager windowManager, DisplayController displayController, - DisplayLayout displayLayout, TaskStackListenerImpl taskStackListener, - UiEventLogger uiEventLogger, - @ShellMainThread ShellExecutor mainExecutor, - @ShellMainThread Handler mainHandler) { - return Optional.ofNullable(OneHandedController.create(context, windowManager, - displayController, displayLayout, taskStackListener, uiEventLogger, mainExecutor, - mainHandler)); + static Optional providesOneHandedController( + @DynamicOverride Optional oneHandedController) { + if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) { + return oneHandedController; + } + return Optional.empty(); } + // // Task to Surface communication // @@ -366,15 +353,6 @@ public abstract class WMShellBaseModule { return Optional.ofNullable(new TaskSurfaceHelperController(taskOrganizer, mainExecutor)); } - @WMSingleton - @Provides - static Optional provideDisplayAreaHelper( - @ShellMainThread ShellExecutor mainExecutor, - RootDisplayAreaOrganizer rootDisplayAreaOrganizer) { - return Optional.ofNullable(new DisplayAreaHelperController(mainExecutor, - rootDisplayAreaOrganizer)); - } - // // Pip (optional feature) // @@ -460,7 +438,7 @@ public abstract class WMShellBaseModule { } // - // Split/multiwindow + // Display areas // @WMSingleton @@ -477,6 +455,19 @@ public abstract class WMShellBaseModule { return new RootDisplayAreaOrganizer(mainExecutor); } + @WMSingleton + @Provides + static Optional provideDisplayAreaHelper( + @ShellMainThread ShellExecutor mainExecutor, + RootDisplayAreaOrganizer rootDisplayAreaOrganizer) { + return Optional.of(new DisplayAreaHelperController(mainExecutor, + rootDisplayAreaOrganizer)); + } + + // + // Splitscreen (optional feature) + // + @WMSingleton @Provides static Optional provideSplitScreen( @@ -484,26 +475,20 @@ public abstract class WMShellBaseModule { return splitScreenController.map((controller) -> controller.asSplitScreen()); } + // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} + @BindsOptionalOf + @DynamicOverride + abstract SplitScreenController optionalSplitScreenController(); + @WMSingleton @Provides - static Optional provideSplitScreenController( - ShellTaskOrganizer shellTaskOrganizer, - SyncTransactionQueue syncQueue, Context context, - RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, - @ShellMainThread ShellExecutor mainExecutor, - DisplayImeController displayImeController, - DisplayInsetsController displayInsetsController, Transitions transitions, - TransactionPool transactionPool, IconProvider iconProvider, - Optional recentTasks, - Provider> stageTaskUnfoldControllerProvider) { + static Optional providesSplitScreenController( + @DynamicOverride Optional splitscreenController, + Context context) { if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) { - return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context, - rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController, - displayInsetsController, transitions, transactionPool, iconProvider, - recentTasks, stageTaskUnfoldControllerProvider)); - } else { - return Optional.empty(); + return splitscreenController; } + return Optional.empty(); } // Legacy split (optional feature) @@ -529,7 +514,9 @@ public abstract class WMShellBaseModule { @BindsOptionalOf abstract AppPairsController optionalAppPairs(); + // // Starting window + // @WMSingleton @Provides @@ -548,6 +535,23 @@ public abstract class WMShellBaseModule { startingWindowTypeAlgorithm, iconProvider, pool); } + // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} + @BindsOptionalOf + @DynamicOverride + abstract StartingWindowTypeAlgorithm optionalStartingWindowTypeAlgorithm(); + + @WMSingleton + @Provides + static StartingWindowTypeAlgorithm provideStartingWindowTypeAlgorithm( + @DynamicOverride Optional startingWindowTypeAlgorithm + ) { + if (startingWindowTypeAlgorithm.isPresent()) { + return startingWindowTypeAlgorithm.get(); + } + // Default to phone starting window type + return new PhoneStartingWindowTypeAlgorithm(); + } + // // Task view factory // @@ -591,7 +595,7 @@ public abstract class WMShellBaseModule { Optional pipTouchHandlerOptional, FullscreenTaskListener fullscreenTaskListener, Optional appUnfoldTransitionController, - Optional> freeformTaskListener, + Optional freeformTaskListener, Optional recentTasksOptional, Transitions transitions, StartingWindowController startingWindow, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index ec701470354cc..46c7b508d6e86 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -18,15 +18,22 @@ package com.android.wm.shell.dagger; import android.animation.AnimationHandler; import android.content.Context; +import android.content.pm.LauncherApps; import android.os.Handler; -import android.view.IWindowManager; +import android.view.WindowManager; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.statusbar.IStatusBarService; +import com.android.launcher3.icons.IconProvider; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.apppairs.AppPairsController; +import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; @@ -36,6 +43,7 @@ import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ChoreographerSfVsync; import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.freeform.FreeformTaskListener; +import com.android.wm.shell.fullscreen.FullscreenUnfoldController; import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.pip.Pip; @@ -55,13 +63,18 @@ import com.android.wm.shell.pip.phone.PipAppOpsListener; import com.android.wm.shell.pip.phone.PipController; import com.android.wm.shell.pip.phone.PipMotionHelper; import com.android.wm.shell.pip.phone.PipTouchHandler; +import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.splitscreen.SplitScreenController; -import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; -import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm; +import com.android.wm.shell.splitscreen.StageTaskUnfoldController; import com.android.wm.shell.transition.Transitions; +import com.android.wm.shell.unfold.ShellUnfoldProgressProvider; +import com.android.wm.shell.unfold.UnfoldBackgroundController; import java.util.Optional; +import javax.inject.Provider; + +import dagger.Lazy; import dagger.Module; import dagger.Provides; @@ -77,17 +90,29 @@ import dagger.Provides; public class WMShellModule { // - // Internal common - Components used internally by multiple shell features + // Bubbles // + // Note: Handler needed for LauncherApps.register @WMSingleton @Provides - static DisplayImeController provideDisplayImeController(IWindowManager wmService, - DisplayController displayController, DisplayInsetsController displayInsetsController, + static BubbleController provideBubbleController(Context context, + FloatingContentCoordinator floatingContentCoordinator, + IStatusBarService statusBarService, + WindowManager windowManager, + WindowManagerShellWrapper windowManagerShellWrapper, + LauncherApps launcherApps, + TaskStackListenerImpl taskStackListener, + UiEventLogger uiEventLogger, + ShellTaskOrganizer organizer, + DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor, - TransactionPool transactionPool) { - return new DisplayImeController(wmService, displayController, displayInsetsController, - mainExecutor, transactionPool); + @ShellMainThread Handler mainHandler, + SyncTransactionQueue syncQueue) { + return BubbleController.create(context, null /* synchronizer */, + floatingContentCoordinator, statusBarService, windowManager, + windowManagerShellWrapper, launcherApps, taskStackListener, + uiEventLogger, organizer, displayController, mainExecutor, mainHandler, syncQueue); } // @@ -96,16 +121,55 @@ public class WMShellModule { @WMSingleton @Provides - static Optional provideFreeformTaskListener( - Context context, + @DynamicOverride + static FreeformTaskListener provideFreeformTaskListener( SyncTransactionQueue syncQueue) { - return Optional.ofNullable(FreeformTaskListener.create(context, syncQueue)); + return new FreeformTaskListener(syncQueue); } // - // Split/multiwindow + // One handed mode // + + // Needs the shell main handler for ContentObserver callbacks + @WMSingleton + @Provides + @DynamicOverride + static OneHandedController provideOneHandedController(Context context, + WindowManager windowManager, DisplayController displayController, + DisplayLayout displayLayout, TaskStackListenerImpl taskStackListener, + UiEventLogger uiEventLogger, + @ShellMainThread ShellExecutor mainExecutor, + @ShellMainThread Handler mainHandler) { + return OneHandedController.create(context, windowManager, + displayController, displayLayout, taskStackListener, uiEventLogger, mainExecutor, + mainHandler); + } + + // + // Splitscreen + // + + @WMSingleton + @Provides + @DynamicOverride + static SplitScreenController provideSplitScreenController( + ShellTaskOrganizer shellTaskOrganizer, + SyncTransactionQueue syncQueue, Context context, + RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, + @ShellMainThread ShellExecutor mainExecutor, + DisplayImeController displayImeController, + DisplayInsetsController displayInsetsController, Transitions transitions, + TransactionPool transactionPool, IconProvider iconProvider, + Optional recentTasks, + Provider> stageTaskUnfoldControllerProvider) { + return new SplitScreenController(shellTaskOrganizer, syncQueue, context, + rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController, + displayInsetsController, transitions, transactionPool, iconProvider, + recentTasks, stageTaskUnfoldControllerProvider); + } + @WMSingleton @Provides static LegacySplitScreenController provideLegacySplitScreen(Context context, @@ -258,12 +322,53 @@ public class WMShellModule { } // - // Starting Windows (Splash Screen) + // Unfold transition // @WMSingleton @Provides - static StartingWindowTypeAlgorithm provideStartingWindowTypeAlgorithm() { - return new PhoneStartingWindowTypeAlgorithm(); + @DynamicOverride + static FullscreenUnfoldController provideFullscreenUnfoldController( + Context context, + Optional progressProvider, + Lazy unfoldBackgroundController, + DisplayInsetsController displayInsetsController, + @ShellMainThread ShellExecutor mainExecutor + ) { + return new FullscreenUnfoldController(context, mainExecutor, + unfoldBackgroundController.get(), progressProvider.get(), + displayInsetsController); + } + + @Provides + static Optional provideStageTaskUnfoldController( + Optional progressProvider, + Context context, + TransactionPool transactionPool, + Lazy unfoldBackgroundController, + DisplayInsetsController displayInsetsController, + @ShellMainThread ShellExecutor mainExecutor + ) { + return progressProvider.map(shellUnfoldTransitionProgressProvider -> + new StageTaskUnfoldController( + context, + transactionPool, + shellUnfoldTransitionProgressProvider, + displayInsetsController, + unfoldBackgroundController.get(), + mainExecutor + )); + } + + @WMSingleton + @Provides + static UnfoldBackgroundController provideUnfoldBackgroundController( + RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, + Context context + ) { + return new UnfoldBackgroundController( + context, + rootTaskDisplayAreaOrganizer + ); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java index 8a8d7c68d9f64..5c8e7d03eb017 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java @@ -141,16 +141,4 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { || Settings.Global.getInt(context.getContentResolver(), DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0; } - - /** - * Creates {@link FreeformTaskListener} if freeform is enabled. - */ - public static FreeformTaskListener create(Context context, - SyncTransactionQueue syncQueue) { - if (!isFreeformEnabled(context)) { - return null; - } - - return new FreeformTaskListener(syncQueue); - } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 9007437122277..e0686146e821b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -46,7 +46,6 @@ import android.view.accessibility.AccessibilityManager; import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.logging.UiEventLogger; @@ -76,7 +75,7 @@ public class OneHandedController implements RemoteCallable, private static final int OVERLAY_ENABLED_DELAY_MS = 250; private static final int DISPLAY_AREA_READY_RETRY_MS = 10; - static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode"; + public static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode"; private volatile boolean mIsOneHandedEnabled; private volatile boolean mIsSwipeToNotificationEnabled; @@ -198,16 +197,10 @@ public class OneHandedController implements RemoteCallable, /** * Creates {@link OneHandedController}, returns {@code null} if the feature is not supported. */ - @Nullable public static OneHandedController create( Context context, WindowManager windowManager, DisplayController displayController, DisplayLayout displayLayout, TaskStackListenerImpl taskStackListener, UiEventLogger uiEventLogger, ShellExecutor mainExecutor, Handler mainHandler) { - if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) { - Slog.w(TAG, "Device doesn't support OneHanded feature"); - return null; - } - OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil(); OneHandedAccessibilityUtil accessibilityUtil = new OneHandedAccessibilityUtil(context); OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 7457be2d08716..8af72a89a75f8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -130,19 +130,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private StageCoordinator mStageCoordinator; - // TODO(b/205019015): Remove after we clean up downstream modules - public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, - SyncTransactionQueue syncQueue, Context context, - RootTaskDisplayAreaOrganizer rootTDAOrganizer, - ShellExecutor mainExecutor, DisplayImeController displayImeController, - DisplayInsetsController displayInsetsController, - Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, - Provider> unfoldControllerProvider) { - this(shellTaskOrganizer, syncQueue, context, rootTDAOrganizer, mainExecutor, - displayImeController, displayInsetsController, transitions, transactionPool, - iconProvider, Optional.empty(), unfoldControllerProvider); - } - public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Context context, RootTaskDisplayAreaOrganizer rootTDAOrganizer, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/ShellUnfoldProgressProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/ShellUnfoldProgressProvider.java index 74e48120bf1aa..367676f54aba6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/ShellUnfoldProgressProvider.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/ShellUnfoldProgressProvider.java @@ -26,10 +26,16 @@ import java.util.concurrent.Executor; */ public interface ShellUnfoldProgressProvider { + // This is a temporary workaround until we move the progress providers into the Shell or + // refactor the dependencies. TLDR, the base module depends on this provider to determine if the + // FullscreenUnfoldController is available, but this check can't rely on an optional component. + public static final ShellUnfoldProgressProvider NO_PROVIDER = + new ShellUnfoldProgressProvider() {}; + /** * Adds a transition listener */ - void addListener(Executor executor, UnfoldListener listener); + default void addListener(Executor executor, UnfoldListener listener) {} /** * Listener for receiving unfold updates diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt index cebc93182f1ee..cd3e2d335f0be 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt @@ -100,11 +100,11 @@ class UnfoldTransitionModule { fun provideShellProgressProvider( config: UnfoldTransitionConfig, provider: Optional - ): Optional = + ): ShellUnfoldProgressProvider = if (config.isEnabled && provider.isPresent()) { - Optional.of(UnfoldProgressProvider(provider.get())) + UnfoldProgressProvider(provider.get()) } else { - Optional.empty() + ShellUnfoldProgressProvider.NO_PROVIDER } }