Move handheld-specific controllers out of base module
- Provide a way for overridable impls of *required* base components
so we don't have to duplicate across various projects, and also use
it to have the specialized modules provide impls dyanmically
- Use the above to replace nested optional usage for FreeformTaskListner
- Also remove unused/duplicated split controller providers from TV module
Bug: 205019015
Test: mp SystemUIGoogle
Test: mp CarSystemUI
Test: mp ArcSystemUI
Change-Id: If56b18e5814d1fa3d66f5ff04fa84ac6dd54f453
(cherry picked from commit 71b45a051f)
Merged-In: If56b18e5814d1fa3d66f5ff04fa84ac6dd54f453
This commit is contained in:
@@ -74,7 +74,7 @@ public class ShellInitImpl {
|
||||
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Optional<FullscreenUnfoldController> fullscreenUnfoldTransitionController,
|
||||
Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
|
||||
Optional<FreeformTaskListener> freeformTaskListenerOptional,
|
||||
Optional<RecentTasksController> 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;
|
||||
|
||||
@@ -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<Interface> 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<Interface> 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<Interface> providesOptionalInterface(
|
||||
* @DynamicOverride Optional<Interface> 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<Interface> providesOptionalInterface(
|
||||
* @DynamicOverride Optional<Interface> 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 {}
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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<DisplayImeController> 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<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,
|
||||
@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<FullscreenUnfoldController> provideFullscreenUnfoldController(
|
||||
Context context,
|
||||
Optional<ShellUnfoldProgressProvider> progressProvider,
|
||||
Lazy<UnfoldBackgroundController> unfoldBackgroundController,
|
||||
DisplayInsetsController displayInsetsController,
|
||||
@ShellMainThread ShellExecutor mainExecutor
|
||||
) {
|
||||
return progressProvider.map(shellUnfoldTransitionProgressProvider ->
|
||||
new FullscreenUnfoldController(context, mainExecutor,
|
||||
unfoldBackgroundController.get(), shellUnfoldTransitionProgressProvider,
|
||||
displayInsetsController));
|
||||
}
|
||||
|
||||
@Provides
|
||||
static Optional<StageTaskUnfoldController> provideStageTaskUnfoldController(
|
||||
Optional<ShellUnfoldProgressProvider> progressProvider,
|
||||
Context context,
|
||||
TransactionPool transactionPool,
|
||||
Lazy<UnfoldBackgroundController> 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> fullscreenUnfoldController,
|
||||
Optional<ShellUnfoldProgressProvider> 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<FreeformTaskListener> optionalFreeformTaskListener();
|
||||
@DynamicOverride
|
||||
abstract FreeformTaskListener optionalFreeformTaskListener();
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Optional<FreeformTaskListener> provideFreeformTaskListener(
|
||||
@DynamicOverride Optional<FreeformTaskListener> 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<OneHandedController> 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<OneHandedController> providesOneHandedController(
|
||||
@DynamicOverride Optional<OneHandedController> 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<DisplayAreaHelper> 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<DisplayAreaHelper> provideDisplayAreaHelper(
|
||||
@ShellMainThread ShellExecutor mainExecutor,
|
||||
RootDisplayAreaOrganizer rootDisplayAreaOrganizer) {
|
||||
return Optional.of(new DisplayAreaHelperController(mainExecutor,
|
||||
rootDisplayAreaOrganizer));
|
||||
}
|
||||
|
||||
//
|
||||
// Splitscreen (optional feature)
|
||||
//
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Optional<SplitScreen> 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<SplitScreenController> provideSplitScreenController(
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
SyncTransactionQueue syncQueue, Context context,
|
||||
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
|
||||
@ShellMainThread ShellExecutor mainExecutor,
|
||||
DisplayImeController displayImeController,
|
||||
DisplayInsetsController displayInsetsController, Transitions transitions,
|
||||
TransactionPool transactionPool, IconProvider iconProvider,
|
||||
Optional<RecentTasksController> recentTasks,
|
||||
Provider<Optional<StageTaskUnfoldController>> stageTaskUnfoldControllerProvider) {
|
||||
static Optional<SplitScreenController> providesSplitScreenController(
|
||||
@DynamicOverride Optional<SplitScreenController> 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> 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<PipTouchHandler> pipTouchHandlerOptional,
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Optional<FullscreenUnfoldController> appUnfoldTransitionController,
|
||||
Optional<Optional<FreeformTaskListener>> freeformTaskListener,
|
||||
Optional<FreeformTaskListener> freeformTaskListener,
|
||||
Optional<RecentTasksController> recentTasksOptional,
|
||||
Transitions transitions,
|
||||
StartingWindowController startingWindow,
|
||||
|
||||
@@ -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<FreeformTaskListener> 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<RecentTasksController> recentTasks,
|
||||
Provider<Optional<StageTaskUnfoldController>> 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<ShellUnfoldProgressProvider> progressProvider,
|
||||
Lazy<UnfoldBackgroundController> unfoldBackgroundController,
|
||||
DisplayInsetsController displayInsetsController,
|
||||
@ShellMainThread ShellExecutor mainExecutor
|
||||
) {
|
||||
return new FullscreenUnfoldController(context, mainExecutor,
|
||||
unfoldBackgroundController.get(), progressProvider.get(),
|
||||
displayInsetsController);
|
||||
}
|
||||
|
||||
@Provides
|
||||
static Optional<StageTaskUnfoldController> provideStageTaskUnfoldController(
|
||||
Optional<ShellUnfoldProgressProvider> progressProvider,
|
||||
Context context,
|
||||
TransactionPool transactionPool,
|
||||
Lazy<UnfoldBackgroundController> 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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<OneHandedController>,
|
||||
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<OneHandedController>,
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -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<Optional<StageTaskUnfoldController>> 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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -100,11 +100,11 @@ class UnfoldTransitionModule {
|
||||
fun provideShellProgressProvider(
|
||||
config: UnfoldTransitionConfig,
|
||||
provider: Optional<UnfoldTransitionProgressProvider>
|
||||
): Optional<ShellUnfoldProgressProvider> =
|
||||
): ShellUnfoldProgressProvider =
|
||||
if (config.isEnabled && provider.isPresent()) {
|
||||
Optional.of(UnfoldProgressProvider(provider.get()))
|
||||
UnfoldProgressProvider(provider.get())
|
||||
} else {
|
||||
Optional.empty()
|
||||
ShellUnfoldProgressProvider.NO_PROVIDER
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user