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:
Winson Chung
2021-11-10 06:42:26 +00:00
parent 34873949e9
commit 8b5b7e5beb
10 changed files with 368 additions and 205 deletions

View File

@@ -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;

View File

@@ -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 {}

View File

@@ -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();
};

View File

@@ -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,

View File

@@ -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
);
}
}

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -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

View File

@@ -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
}
}