blob: 103e6bb08ed49eb10a8a74b9948088c45e6bf645 [file] [log] [blame]
/*
* Copyright (C) 2020 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.systemui.wmshell;
import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import android.animation.AnimationHandler;
import android.app.ActivityTaskManager;
import android.app.IActivityManager;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.view.IWindowManager;
import android.view.WindowManager;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dagger.WMSingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.FullscreenTaskListener;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.ShellCommandHandlerImpl;
import com.android.wm.shell.ShellInit;
import com.android.wm.shell.ShellInitImpl;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.TaskViewFactoryController;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.HandlerExecutor;
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.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.phone.PipAppOpsListener;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
import dagger.BindsOptionalOf;
import dagger.Module;
import dagger.Provides;
/**
* Provides basic dependencies from {@link com.android.wm.shell}, the dependencies declared here
* should be shared among different branches of SystemUI.
*/
@Module
public abstract class WMShellBaseModule {
private static final boolean ENABLE_SHELL_MAIN_THREAD = false;
//
// Shell Concurrency - Components used for managing threading in the Shell and SysUI
//
/**
* Provide a SysUI main-thread Executor.
*/
@WMSingleton
@Provides
@Main
public static ShellExecutor provideSysUIMainExecutor(@Main Handler sysuiMainHandler) {
return new HandlerExecutor(sysuiMainHandler);
}
/**
* Shell main-thread Handler, don't use this unless really necessary (ie. need to dedupe
* multiple types of messages, etc.)
*/
@WMSingleton
@Provides
@ShellMainThread
public static Handler provideShellMainHandler(@Main Handler sysuiMainHandler) {
if (ENABLE_SHELL_MAIN_THREAD) {
HandlerThread mainThread = new HandlerThread("wmshell.main");
mainThread.start();
return mainThread.getThreadHandler();
}
return sysuiMainHandler;
}
/**
* Provide a Shell main-thread Executor.
*/
@WMSingleton
@Provides
@ShellMainThread
public static ShellExecutor provideShellMainExecutor(@ShellMainThread Handler mainHandler,
@Main ShellExecutor sysuiMainExecutor) {
if (ENABLE_SHELL_MAIN_THREAD) {
return new HandlerExecutor(mainHandler);
}
return sysuiMainExecutor;
}
/**
* Provide a Shell animation-thread Executor.
*/
@WMSingleton
@Provides
@ShellAnimationThread
public static ShellExecutor provideShellAnimationExecutor() {
HandlerThread shellAnimationThread = new HandlerThread("wmshell.anim",
THREAD_PRIORITY_DISPLAY);
shellAnimationThread.start();
return new HandlerExecutor(shellAnimationThread.getThreadHandler());
}
/**
* Provide a Shell main-thread AnimationHandler. The AnimationHandler can be set on
* {@link android.animation.ValueAnimator}s and will ensure that the animation will run on
* the Shell main-thread with the SF vsync.
*/
@WMSingleton
@Provides
@ChoreographerSfVsync
public static AnimationHandler provideShellMainExecutorSfVsyncAnimationHandler(
@ShellMainThread ShellExecutor mainExecutor) {
try {
AnimationHandler handler = new AnimationHandler();
mainExecutor.executeBlocking(() -> {
// This is called on the animation thread since it calls
// Choreographer.getSfInstance() which returns a thread-local Choreographer instance
// that uses the SF vsync
handler.setProvider(new SfVsyncFrameCallbackProvider());
});
return handler;
} catch (InterruptedException e) {
throw new RuntimeException("Failed to initialize SfVsync animation handler in 1s", e);
}
}
@WMSingleton
@Provides
static ShellInit provideShellInit(DisplayImeController displayImeController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
@ShellMainThread ShellExecutor mainExecutor) {
return ShellInitImpl.create(displayImeController,
dragAndDropController,
shellTaskOrganizer,
legacySplitScreenOptional,
splitScreenOptional,
appPairsOptional,
fullscreenTaskListener,
transitions,
mainExecutor);
}
/**
* Note, this is only optional because we currently pass this to the SysUI component scope and
* for non-primary users, we may inject a null-optional for that dependency.
*/
@WMSingleton
@Provides
static Optional<ShellCommandHandler> provideShellCommandHandler(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout,
Optional<AppPairs> appPairsOptional,
@ShellMainThread ShellExecutor mainExecutor) {
return Optional.of(ShellCommandHandlerImpl.create(shellTaskOrganizer,
legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
hideDisplayCutout, appPairsOptional, mainExecutor));
}
@WMSingleton
@Provides
static TransactionPool provideTransactionPool() {
return new TransactionPool();
}
@WMSingleton
@Provides
static DisplayController provideDisplayController(Context context,
IWindowManager wmService, @ShellMainThread ShellExecutor mainExecutor) {
return new DisplayController(context, wmService, mainExecutor);
}
@WMSingleton
@Provides
static DragAndDropController provideDragAndDropController(Context context,
DisplayController displayController) {
return new DragAndDropController(context, displayController);
}
@WMSingleton
@Provides
static FloatingContentCoordinator provideFloatingContentCoordinator() {
return new FloatingContentCoordinator();
}
@WMSingleton
@Provides
static WindowManagerShellWrapper provideWindowManagerShellWrapper(
@ShellMainThread ShellExecutor mainExecutor) {
return new WindowManagerShellWrapper(mainExecutor);
}
@WMSingleton
@Provides
static PipAppOpsListener providePipAppOpsListener(Context context,
IActivityManager activityManager,
PipTouchHandler pipTouchHandler,
@ShellMainThread ShellExecutor mainExecutor) {
return new PipAppOpsListener(context, pipTouchHandler.getMotionHelper(), mainExecutor);
}
// Needs handler for registering broadcast receivers
@WMSingleton
@Provides
static PipMediaController providePipMediaController(Context context,
@ShellMainThread Handler mainHandler) {
return new PipMediaController(context, mainHandler);
}
@WMSingleton
@Provides
static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger,
PackageManager packageManager) {
return new PipUiEventLogger(uiEventLogger, packageManager);
}
@WMSingleton
@Provides
static PipSurfaceTransactionHelper providePipSurfaceTransactionHelper(Context context) {
return new PipSurfaceTransactionHelper(context);
}
@WMSingleton
@Provides
static SystemWindows provideSystemWindows(DisplayController displayController,
IWindowManager wmService) {
return new SystemWindows(displayController, wmService);
}
@WMSingleton
@Provides
static SyncTransactionQueue provideSyncTransactionQueue(TransactionPool pool,
@ShellMainThread ShellExecutor mainExecutor) {
return new SyncTransactionQueue(pool, mainExecutor);
}
@WMSingleton
@Provides
static ShellTaskOrganizer provideShellTaskOrganizer(@ShellMainThread ShellExecutor mainExecutor,
Context context) {
return new ShellTaskOrganizer(mainExecutor, context);
}
@WMSingleton
@Provides
static RootTaskDisplayAreaOrganizer provideRootTaskDisplayAreaOrganizer(
@ShellMainThread ShellExecutor mainExecutor, Context context) {
return new RootTaskDisplayAreaOrganizer(mainExecutor, context);
}
// We currently dedupe multiple messages, so we use the shell main handler directly
@WMSingleton
@Provides
static TaskStackListenerImpl providerTaskStackListenerImpl(
@ShellMainThread Handler mainHandler) {
return new TaskStackListenerImpl(mainHandler);
}
@BindsOptionalOf
abstract LegacySplitScreen optionalLegacySplitScreen();
@WMSingleton
@Provides
static Optional<SplitScreen> provideSplitScreen(ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context,
rootTaskDisplayAreaOrganizer));
} else {
return Optional.empty();
}
}
@BindsOptionalOf
abstract AppPairs optionalAppPairs();
@WMSingleton
@Provides
static Optional<Bubbles> provideBubbles(Context context,
FloatingContentCoordinator floatingContentCoordinator,
IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
LauncherApps launcherApps,
UiEventLogger uiEventLogger,
ShellTaskOrganizer organizer,
@ShellMainThread ShellExecutor mainExecutor) {
return Optional.of(BubbleController.create(context, null /* synchronizer */,
floatingContentCoordinator, statusBarService, windowManager,
windowManagerShellWrapper, launcherApps, uiEventLogger, organizer,
mainExecutor));
}
// Needs the shell main handler for ContentObserver callbacks
@WMSingleton
@Provides
static Optional<OneHanded> provideOneHandedController(Context context,
DisplayController displayController, TaskStackListenerImpl taskStackListener,
UiEventLogger uiEventLogger,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler) {
return Optional.ofNullable(OneHandedController.create(context, displayController,
taskStackListener, uiEventLogger, mainExecutor, mainHandler));
}
@WMSingleton
@Provides
static Optional<HideDisplayCutout> provideHideDisplayCutoutController(Context context,
DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor) {
return Optional.ofNullable(
HideDisplayCutoutController.create(context, displayController, mainExecutor));
}
@WMSingleton
@Provides
static Optional<TaskViewFactory> provideTaskViewFactory(ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
return Optional.of(new TaskViewFactoryController(shellTaskOrganizer, mainExecutor)
.getTaskViewFactory());
}
@WMSingleton
@Provides
static FullscreenTaskListener provideFullscreenTaskListener(
SyncTransactionQueue syncQueue) {
return new FullscreenTaskListener(syncQueue);
}
@WMSingleton
@Provides
static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool,
@ShellMainThread ShellExecutor mainExecutor,
@ShellAnimationThread ShellExecutor animExecutor) {
return new Transitions(organizer, pool, mainExecutor, animExecutor);
}
}