diff options
29 files changed, 579 insertions, 277 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index 5cba3b4ec130..6ae0f9ba0485 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -55,6 +55,7 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.compatui.CompatUIController; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.startingsurface.StartingWindowController; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.unfold.UnfoldAnimationController; @@ -72,6 +73,7 @@ import java.util.function.Consumer; */ public class ShellTaskOrganizer extends TaskOrganizer implements CompatUIController.CompatUICallback { + private static final String TAG = "ShellTaskOrganizer"; // Intentionally using negative numbers here so the positive numbers can be used // for task id specific listeners that will be added later. @@ -90,8 +92,6 @@ public class ShellTaskOrganizer extends TaskOrganizer implements }) public @interface TaskListenerType {} - private static final String TAG = "ShellTaskOrganizer"; - /** * Callbacks for when the tasks change in the system. */ @@ -177,6 +177,9 @@ public class ShellTaskOrganizer extends TaskOrganizer implements @Nullable private final CompatUIController mCompatUI; + @NonNull + private final ShellCommandHandler mShellCommandHandler; + @Nullable private final Optional<RecentTasksController> mRecentTasks; @@ -187,29 +190,33 @@ public class ShellTaskOrganizer extends TaskOrganizer implements private RunningTaskInfo mLastFocusedTaskInfo; public ShellTaskOrganizer(ShellExecutor mainExecutor) { - this(null /* shellInit */, null /* taskOrganizerController */, null /* compatUI */, + this(null /* shellInit */, null /* shellCommandHandler */, + null /* taskOrganizerController */, null /* compatUI */, Optional.empty() /* unfoldAnimationController */, Optional.empty() /* recentTasksController */, mainExecutor); } public ShellTaskOrganizer(ShellInit shellInit, + ShellCommandHandler shellCommandHandler, @Nullable CompatUIController compatUI, Optional<UnfoldAnimationController> unfoldAnimationController, Optional<RecentTasksController> recentTasks, ShellExecutor mainExecutor) { - this(shellInit, null /* taskOrganizerController */, compatUI, + this(shellInit, shellCommandHandler, null /* taskOrganizerController */, compatUI, unfoldAnimationController, recentTasks, mainExecutor); } @VisibleForTesting protected ShellTaskOrganizer(ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ITaskOrganizerController taskOrganizerController, @Nullable CompatUIController compatUI, Optional<UnfoldAnimationController> unfoldAnimationController, Optional<RecentTasksController> recentTasks, ShellExecutor mainExecutor) { super(taskOrganizerController, mainExecutor); + mShellCommandHandler = shellCommandHandler; mCompatUI = compatUI; mRecentTasks = recentTasks; mUnfoldAnimationController = unfoldAnimationController.orElse(null); @@ -219,6 +226,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements } private void onInit() { + mShellCommandHandler.addDumpCallback(this::dump, this); if (mCompatUI != null) { mCompatUI.setCompatUICallback(this); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index 05fafc54c273..131afafc32c7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -57,6 +57,7 @@ import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.annotations.ShellBackgroundThread; import com.android.wm.shell.common.annotations.ShellMainThread; +import com.android.wm.shell.sysui.ShellInit; import java.util.concurrent.atomic.AtomicBoolean; @@ -90,7 +91,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont * Raw delta between {@link #mInitTouchLocation} and the last touch location. */ private final Point mTouchEventDelta = new Point(); - private final ShellExecutor mShellExecutor; /** True when a back gesture is ongoing */ private boolean mBackGestureStarted = false; @@ -105,6 +105,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private final SurfaceControl.Transaction mTransaction; private final IActivityTaskManager mActivityTaskManager; private final Context mContext; + private final ContentResolver mContentResolver; + private final ShellExecutor mShellExecutor; + private final Handler mBgHandler; @Nullable private IOnBackInvokedCallback mBackToLauncherCallback; private float mTriggerThreshold; @@ -133,16 +136,19 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont }; public BackAnimationController( + @NonNull ShellInit shellInit, @NonNull @ShellMainThread ShellExecutor shellExecutor, @NonNull @ShellBackgroundThread Handler backgroundHandler, Context context) { - this(shellExecutor, backgroundHandler, new SurfaceControl.Transaction(), + this(shellInit, shellExecutor, backgroundHandler, new SurfaceControl.Transaction(), ActivityTaskManager.getService(), context, context.getContentResolver()); } @VisibleForTesting - BackAnimationController(@NonNull @ShellMainThread ShellExecutor shellExecutor, - @NonNull @ShellBackgroundThread Handler handler, + BackAnimationController( + @NonNull ShellInit shellInit, + @NonNull @ShellMainThread ShellExecutor shellExecutor, + @NonNull @ShellBackgroundThread Handler bgHandler, @NonNull SurfaceControl.Transaction transaction, @NonNull IActivityTaskManager activityTaskManager, Context context, ContentResolver contentResolver) { @@ -150,7 +156,13 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mTransaction = transaction; mActivityTaskManager = activityTaskManager; mContext = context; - setupAnimationDeveloperSettingsObserver(contentResolver, handler); + mContentResolver = contentResolver; + mBgHandler = bgHandler; + shellInit.addInitCallback(this::onInit, this); + } + + private void onInit() { + setupAnimationDeveloperSettingsObserver(mContentResolver, mBgHandler); } private void setupAnimationDeveloperSettingsObserver( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index db8d9d423aca..235fd9c469ea 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -43,6 +43,7 @@ import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState; import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager; import com.android.wm.shell.sysui.KeyguardChangeListener; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import java.lang.ref.WeakReference; @@ -119,6 +120,7 @@ public class CompatUIController implements OnDisplaysChangedListener, private boolean mKeyguardShowing; public CompatUIController(Context context, + ShellInit shellInit, ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, @@ -134,10 +136,14 @@ public class CompatUIController implements OnDisplaysChangedListener, mSyncQueue = syncQueue; mMainExecutor = mainExecutor; mTransitionsLazy = transitionsLazy; + mCompatUIHintsState = new CompatUIHintsState(); + shellInit.addInitCallback(this::onInit, this); + } + + private void onInit() { + mShellController.addKeyguardChangeListener(this); mDisplayController.addDisplayWindowListener(this); mImeController.addPositionProcessor(this); - mCompatUIHintsState = new CompatUIHintsState(); - shellController.addKeyguardChangeListener(this); } /** Sets the callback for UI interactions. */ 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 3add4179ef82..bbaf51f7c54c 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 @@ -174,13 +174,14 @@ public abstract class WMShellBaseModule { @Provides static ShellTaskOrganizer provideShellTaskOrganizer( ShellInit shellInit, + ShellCommandHandler shellCommandHandler, CompatUIController compatUI, Optional<UnfoldAnimationController> unfoldAnimationController, Optional<RecentTasksController> recentTasksOptional, @ShellMainThread ShellExecutor mainExecutor ) { - return new ShellTaskOrganizer(shellInit, compatUI, unfoldAnimationController, - recentTasksOptional, mainExecutor); + return new ShellTaskOrganizer(shellInit, shellCommandHandler, compatUI, + unfoldAnimationController, recentTasksOptional, mainExecutor); } @WMSingleton @@ -188,6 +189,7 @@ public abstract class WMShellBaseModule { static KidsModeTaskOrganizer provideKidsModeTaskOrganizer( Context context, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, SyncTransactionQueue syncTransactionQueue, DisplayController displayController, DisplayInsetsController displayInsetsController, @@ -196,19 +198,20 @@ public abstract class WMShellBaseModule { @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler ) { - return new KidsModeTaskOrganizer(context, shellInit, syncTransactionQueue, - displayController, displayInsetsController, unfoldAnimationController, - recentTasksOptional, mainExecutor, mainHandler); + return new KidsModeTaskOrganizer(context, shellInit, shellCommandHandler, + syncTransactionQueue, displayController, displayInsetsController, + unfoldAnimationController, recentTasksOptional, mainExecutor, mainHandler); } @WMSingleton @Provides static CompatUIController provideCompatUIController(Context context, + ShellInit shellInit, ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, DisplayImeController imeController, SyncTransactionQueue syncQueue, @ShellMainThread ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy) { - return new CompatUIController(context, shellController, displayController, + return new CompatUIController(context, shellInit, shellController, displayController, displayInsetsController, imeController, syncQueue, mainExecutor, transitionsLazy); } @@ -268,12 +271,14 @@ public abstract class WMShellBaseModule { @Provides static Optional<BackAnimationController> provideBackAnimationController( Context context, + ShellInit shellInit, @ShellMainThread ShellExecutor shellExecutor, @ShellBackgroundThread Handler backgroundHandler ) { if (BackAnimationController.IS_ENABLED) { return Optional.of( - new BackAnimationController(shellExecutor, backgroundHandler, context)); + new BackAnimationController(shellInit, shellExecutor, backgroundHandler, + context)); } return Optional.empty(); } @@ -384,11 +389,14 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static Optional<HideDisplayCutoutController> provideHideDisplayCutoutController(Context context, - ShellController shellController, DisplayController displayController, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, + ShellController shellController, + DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor) { return Optional.ofNullable( - HideDisplayCutoutController.create(context, shellController, displayController, - mainExecutor)); + HideDisplayCutoutController.create(context, shellInit, shellCommandHandler, + shellController, displayController, mainExecutor)); } // @@ -466,12 +474,13 @@ public abstract class WMShellBaseModule { static Optional<RecentTasksController> provideRecentTasksController( Context context, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, TaskStackListenerImpl taskStackListener, @ShellMainThread ShellExecutor mainExecutor ) { return Optional.ofNullable( - RecentTasksController.create(context, shellInit, taskStackListener, - mainExecutor)); + RecentTasksController.create(context, shellInit, shellCommandHandler, + taskStackListener, mainExecutor)); } // @@ -649,8 +658,9 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static ShellController provideShellController(ShellInit shellInit, + ShellCommandHandler shellCommandHandler, @ShellMainThread ShellExecutor mainExecutor) { - return new ShellController(shellInit, mainExecutor); + return new ShellController(shellInit, shellCommandHandler, mainExecutor); } // @@ -676,12 +686,15 @@ public abstract class WMShellBaseModule { KidsModeTaskOrganizer kidsModeTaskOrganizer, Optional<BubbleController> bubblesOptional, Optional<SplitScreenController> splitScreenOptional, + Optional<Pip> pipOptional, Optional<PipTouchHandler> pipTouchHandlerOptional, FullscreenTaskListener fullscreenTaskListener, Optional<UnfoldAnimationController> unfoldAnimationController, Optional<UnfoldTransitionHandler> unfoldTransitionHandler, Optional<FreeformComponents> freeformComponents, Optional<RecentTasksController> recentTasksOptional, + Optional<OneHandedController> oneHandedControllerOptional, + Optional<HideDisplayCutoutController> hideDisplayCutoutControllerOptional, ActivityEmbeddingController activityEmbeddingOptional, Transitions transitions, StartingWindowController startingWindow, @@ -697,18 +710,7 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static ShellCommandHandler provideShellCommandHandlerImpl( - ShellController shellController, - ShellTaskOrganizer shellTaskOrganizer, - KidsModeTaskOrganizer kidsModeTaskOrganizer, - Optional<SplitScreenController> splitScreenOptional, - Optional<Pip> pipOptional, - Optional<OneHandedController> oneHandedOptional, - Optional<HideDisplayCutoutController> hideDisplayCutout, - Optional<RecentTasksController> recentTasksOptional, - @ShellMainThread ShellExecutor mainExecutor) { - return new ShellCommandHandler(shellController, shellTaskOrganizer, - kidsModeTaskOrganizer, splitScreenOptional, pipOptional, oneHandedOptional, - hideDisplayCutout, recentTasksOptional, mainExecutor); + static ShellCommandHandler provideShellCommandHandler() { + return new ShellCommandHandler(); } } 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 d53451aa6034..2ca9c3be8a69 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 @@ -74,6 +74,7 @@ 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.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.SplitscreenPipMixedHandler; @@ -248,14 +249,20 @@ public abstract class WMShellModule { @Provides @DynamicOverride static OneHandedController provideOneHandedController(Context context, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellController shellController, - WindowManager windowManager, DisplayController displayController, - DisplayLayout displayLayout, TaskStackListenerImpl taskStackListener, - UiEventLogger uiEventLogger, InteractionJankMonitor jankMonitor, - @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler) { - return OneHandedController.create(context, shellController, windowManager, - displayController, displayLayout, taskStackListener, jankMonitor, uiEventLogger, - mainExecutor, mainHandler); + WindowManager windowManager, + DisplayController displayController, + DisplayLayout displayLayout, + TaskStackListenerImpl taskStackListener, + UiEventLogger uiEventLogger, + InteractionJankMonitor jankMonitor, + @ShellMainThread ShellExecutor mainExecutor, + @ShellMainThread Handler mainHandler) { + return OneHandedController.create(context, shellInit, shellCommandHandler, shellController, + windowManager, displayController, displayLayout, taskStackListener, jankMonitor, + uiEventLogger, mainExecutor, mainHandler); } // @@ -268,6 +275,7 @@ public abstract class WMShellModule { static SplitScreenController provideSplitScreenController( Context context, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellController shellController, ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, @@ -281,10 +289,10 @@ public abstract class WMShellModule { IconProvider iconProvider, Optional<RecentTasksController> recentTasks, @ShellMainThread ShellExecutor mainExecutor) { - return new SplitScreenController(context, shellInit, shellController, shellTaskOrganizer, - syncQueue, rootTaskDisplayAreaOrganizer, displayController, displayImeController, - displayInsetsController, dragAndDropController, transitions, transactionPool, - iconProvider, recentTasks, mainExecutor); + return new SplitScreenController(context, shellInit, shellCommandHandler, shellController, + shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, displayController, + displayImeController, displayInsetsController, dragAndDropController, transitions, + transactionPool, iconProvider, recentTasks, mainExecutor); } // @@ -294,24 +302,33 @@ public abstract class WMShellModule { @WMSingleton @Provides static Optional<Pip> providePip(Context context, - ShellController shellController, DisplayController displayController, - PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm, - PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState, - PipMotionHelper pipMotionHelper, PipMediaController pipMediaController, - PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, + ShellController shellController, + DisplayController displayController, + PipAppOpsListener pipAppOpsListener, + PipBoundsAlgorithm pipBoundsAlgorithm, + PipKeepClearAlgorithm pipKeepClearAlgorithm, + PipBoundsState pipBoundsState, + PipMotionHelper pipMotionHelper, + PipMediaController pipMediaController, + PhonePipMenuController phonePipMenuController, + PipTaskOrganizer pipTaskOrganizer, PipTransitionState pipTransitionState, - PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController, + PipTouchHandler pipTouchHandler, + PipTransitionController pipTransitionController, WindowManagerShellWrapper windowManagerShellWrapper, TaskStackListenerImpl taskStackListener, PipParamsChangedForwarder pipParamsChangedForwarder, Optional<OneHandedController> oneHandedController, @ShellMainThread ShellExecutor mainExecutor) { - return Optional.ofNullable(PipController.create(context, shellController, displayController, - pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, - pipMotionHelper, - pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState, - pipTouchHandler, pipTransitionController, windowManagerShellWrapper, - taskStackListener, pipParamsChangedForwarder, oneHandedController, mainExecutor)); + return Optional.ofNullable(PipController.create( + context, shellInit, shellCommandHandler, shellController, + displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, + pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController, + pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController, + windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder, + oneHandedController, mainExecutor)); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md index 52f0c4222b64..99922fbc2d95 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md @@ -59,9 +59,9 @@ WMShell SysUI service: adb shell dumpsys activity service SystemUIService WMShell ``` -If information should be added to the dump, make updates to: -- `WMShell` if you are dumping SysUI state -- `ShellCommandHandler` if you are dumping Shell state +If information should be added to the dump, either: +- Update `WMShell` if you are dumping SysUI state +- Inject `ShellCommandHandler` into your Shell class, and add a dump callback ## Debugging in Android Studio diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md index 0dd50b1bee68..d6302e640ba7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md @@ -32,7 +32,7 @@ interfaces provided by the Shell and the rest of SystemUI. More detail can be found in [go/wm-sysui-dagger](http://go/wm-sysui-dagger). -## Interfaces to Shell components +## Interfaces from SysUI to Shell components Within the same process, the WM Shell components can be running on a different thread than the main SysUI thread (disabled on certain products). This introduces challenges where we have to be @@ -54,12 +54,30 @@ For example, you might have: Adding an interface to a Shell component may seem like a lot of boiler plate, but is currently necessary to maintain proper threading and logic isolation. -## Configuration changes & other SysUI events +## Listening for Configuration changes & other SysUI events -Aside from direct calls into Shell controllers for exposed features, the Shell also receives +Aside from direct calls into Shell controllers for exposed features, the Shell also receives common event callbacks from SysUI via the `ShellController`. This includes things like: - Configuration changes -- TODO: Shell init -- TODO: Shell command -- TODO: Keyguard events
\ No newline at end of file +- Keyguard events +- Shell init +- Shell dumps & commands + +For other events which are specific to the Shell feature, then you can add callback methods on +the Shell feature interface. Any such calls should <u>**never**</u> be synchronous calls as +they will need to post to the Shell main thread to run. + +## Shell commands & Dumps + +Since the Shell library is a part of the SysUI process, it relies on SysUI to trigger commands +on individual Shell components, or to dump individual shell components. + +```shell +# Dump everything +adb shell dumpsys activity service SystemUIService WMShell + +# Run a specific command +adb shell dumpsys activity service SystemUIService WMShell help +adb shell dumpsys activity service SystemUIService WMShell <cmd> <args> ... +```
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java index 665b035bc41c..32125fa44148 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java @@ -27,7 +27,9 @@ import androidx.annotation.VisibleForTesting; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.sysui.ConfigurationChangeListener; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import java.io.PrintWriter; @@ -38,6 +40,7 @@ public class HideDisplayCutoutController implements ConfigurationChangeListener private static final String TAG = "HideDisplayCutoutController"; private final Context mContext; + private final ShellCommandHandler mShellCommandHandler; private final ShellController mShellController; private final HideDisplayCutoutOrganizer mOrganizer; @VisibleForTesting @@ -49,7 +52,10 @@ public class HideDisplayCutoutController implements ConfigurationChangeListener */ @Nullable public static HideDisplayCutoutController create(Context context, - ShellController shellController, DisplayController displayController, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, + ShellController shellController, + DisplayController displayController, ShellExecutor mainExecutor) { // The SystemProperty is set for devices that support this feature and is used to control // whether to create the HideDisplayCutout instance. @@ -60,14 +66,24 @@ public class HideDisplayCutoutController implements ConfigurationChangeListener HideDisplayCutoutOrganizer organizer = new HideDisplayCutoutOrganizer(context, displayController, mainExecutor); - return new HideDisplayCutoutController(context, shellController, organizer); + return new HideDisplayCutoutController(context, shellInit, shellCommandHandler, + shellController, organizer); } - HideDisplayCutoutController(Context context, ShellController shellController, + HideDisplayCutoutController(Context context, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, + ShellController shellController, HideDisplayCutoutOrganizer organizer) { mContext = context; + mShellCommandHandler = shellCommandHandler; mShellController = shellController; mOrganizer = organizer; + shellInit.addInitCallback(this::onInit, this); + } + + private void onInit() { + mShellCommandHandler.addDumpCallback(this::dump, this); updateStatus(); mShellController.addConfigurationChangeListener(this); } @@ -96,11 +112,11 @@ public class HideDisplayCutoutController implements ConfigurationChangeListener updateStatus(); } - public void dump(@NonNull PrintWriter pw) { - final String prefix = " "; + public void dump(@NonNull PrintWriter pw, String prefix) { + final String innerPrefix = " "; pw.print(TAG); pw.println(" states: "); - pw.print(prefix); + pw.print(innerPrefix); pw.print("mEnabled="); pw.println(mEnabled); mOrganizer.dump(pw); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java index 73b9b89e6993..2fdd12185551 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java @@ -50,6 +50,7 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.recents.RecentTasksController; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.unfold.UnfoldAnimationController; @@ -73,6 +74,7 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer { private final Handler mMainHandler; private final Context mContext; + private final ShellCommandHandler mShellCommandHandler; private final SyncTransactionQueue mSyncQueue; private final DisplayController mDisplayController; private final DisplayInsetsController mDisplayInsetsController; @@ -141,6 +143,8 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer { @VisibleForTesting KidsModeTaskOrganizer( Context context, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ITaskOrganizerController taskOrganizerController, SyncTransactionQueue syncTransactionQueue, DisplayController displayController, @@ -150,19 +154,23 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer { KidsModeSettingsObserver kidsModeSettingsObserver, ShellExecutor mainExecutor, Handler mainHandler) { - super(/* shellInit= */ null, taskOrganizerController, /* compatUI= */ null, - unfoldAnimationController, recentTasks, mainExecutor); + // Note: we don't call super with the shell init because we will be initializing manually + super(/* shellInit= */ null, /* shellCommandHandler= */ null, taskOrganizerController, + /* compatUI= */ null, unfoldAnimationController, recentTasks, mainExecutor); mContext = context; + mShellCommandHandler = shellCommandHandler; mMainHandler = mainHandler; mSyncQueue = syncTransactionQueue; mDisplayController = displayController; mDisplayInsetsController = displayInsetsController; mKidsModeSettingsObserver = kidsModeSettingsObserver; + shellInit.addInitCallback(this::onInit, this); } public KidsModeTaskOrganizer( Context context, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, SyncTransactionQueue syncTransactionQueue, DisplayController displayController, DisplayInsetsController displayInsetsController, @@ -171,9 +179,10 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer { ShellExecutor mainExecutor, Handler mainHandler) { // Note: we don't call super with the shell init because we will be initializing manually - super(/* shellInit= */ null, /* compatUI= */ null, unfoldAnimationController, recentTasks, - mainExecutor); + super(/* shellInit= */ null, /* taskOrganizerController= */ null, /* compatUI= */ null, + unfoldAnimationController, recentTasks, mainExecutor); mContext = context; + mShellCommandHandler = shellCommandHandler; mMainHandler = mainHandler; mSyncQueue = syncTransactionQueue; mDisplayController = displayController; @@ -185,6 +194,9 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer { * Initializes kids mode status. */ public void onInit() { + if (mShellCommandHandler != null) { + mShellCommandHandler.addDumpCallback(this::dump, this); + } if (mKidsModeSettingsObserver == null) { mKidsModeSettingsObserver = new KidsModeSettingsObserver(mMainHandler, mContext); } 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 24f02ac1a6cf..9149204b94ce 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 @@ -56,7 +56,9 @@ import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.KeyguardChangeListener; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import java.io.PrintWriter; @@ -85,6 +87,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, private Context mContext; + private final ShellCommandHandler mShellCommandHandler; private final ShellController mShellController; private final AccessibilityManager mAccessibilityManager; private final DisplayController mDisplayController; @@ -192,8 +195,9 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, /** * Creates {@link OneHandedController}, returns {@code null} if the feature is not supported. */ - public static OneHandedController create( - Context context, ShellController shellController, WindowManager windowManager, + public static OneHandedController create(Context context, + ShellInit shellInit, ShellCommandHandler shellCommandHandler, + ShellController shellController, WindowManager windowManager, DisplayController displayController, DisplayLayout displayLayout, TaskStackListenerImpl taskStackListener, InteractionJankMonitor jankMonitor, UiEventLogger uiEventLogger, @@ -213,14 +217,16 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, context, displayLayout, settingsUtil, animationController, tutorialHandler, jankMonitor, mainExecutor); OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger); - return new OneHandedController(context, shellController, displayController, organizer, - touchHandler, tutorialHandler, settingsUtil, accessibilityUtil, timeoutHandler, - oneHandedState, oneHandedUiEventsLogger, taskStackListener, - mainExecutor, mainHandler); + return new OneHandedController(context, shellInit, shellCommandHandler, shellController, + displayController, organizer, touchHandler, tutorialHandler, settingsUtil, + accessibilityUtil, timeoutHandler, oneHandedState, oneHandedUiEventsLogger, + taskStackListener, mainExecutor, mainHandler); } @VisibleForTesting OneHandedController(Context context, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellController shellController, DisplayController displayController, OneHandedDisplayAreaOrganizer displayAreaOrganizer, @@ -235,6 +241,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, ShellExecutor mainExecutor, Handler mainHandler) { mContext = context; + mShellCommandHandler = shellCommandHandler; mShellController = shellController; mOneHandedSettingsUtil = settingsUtil; mOneHandedAccessibilityUtil = oneHandedAccessibilityUtil; @@ -247,8 +254,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, mMainHandler = mainHandler; mOneHandedUiEventLogger = uiEventsLogger; mTaskStackListener = taskStackListener; + mAccessibilityManager = AccessibilityManager.getInstance(mContext); - mDisplayController.addDisplayWindowListener(mDisplaysChangedListener); final float offsetPercentageConfig = context.getResources().getFraction( R.fraction.config_one_handed_offset, 1, 1); final int sysPropPercentageConfig = SystemProperties.getInt( @@ -268,6 +275,12 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, getObserver(this::onSwipeToNotificationEnabledChanged); mShortcutEnabledObserver = getObserver(this::onShortcutEnabledChanged); + shellInit.addInitCallback(this::onInit, this); + } + + private void onInit() { + mShellCommandHandler.addDumpCallback(this::dump, this); + mDisplayController.addDisplayWindowListener(mDisplaysChangedListener); mDisplayController.addDisplayChangingController(this); setupCallback(); registerSettingObservers(mUserId); @@ -275,7 +288,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, updateSettings(); updateDisplayLayout(mContext.getDisplayId()); - mAccessibilityManager = AccessibilityManager.getInstance(context); mAccessibilityManager.addAccessibilityStateChangeListener( mAccessibilityStateChangeListener); @@ -623,7 +635,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, updateOneHandedEnabled(); } - public void dump(@NonNull PrintWriter pw) { + public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = " "; pw.println(); pw.println(TAG); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java index 38631ce26cd1..93172f82edd1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java @@ -20,7 +20,6 @@ import android.graphics.Rect; import com.android.wm.shell.common.annotations.ExternalThread; -import java.io.PrintWriter; import java.util.function.Consumer; /** @@ -99,12 +98,4 @@ public interface Pip { * view hierarchy or destroyed. */ default void removePipExclusionBoundsChangeListener(Consumer<Rect> listener) { } - - /** - * Dump the current state and information if need. - * - * @param pw The stream to dump information to. - */ - default void dump(PrintWriter pw) { - } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 2144305d43c3..f1368ccb0c1c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -89,7 +89,9 @@ import com.android.wm.shell.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.KeyguardChangeListener; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; @@ -122,6 +124,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb private TaskStackListenerImpl mTaskStackListener; private PipParamsChangedForwarder mPipParamsChangedForwarder; private Optional<OneHandedController> mOneHandedController; + private final ShellCommandHandler mShellCommandHandler; private final ShellController mShellController; protected final PipImpl mImpl; @@ -295,6 +298,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb */ @Nullable public static Pip create(Context context, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellController shellController, DisplayController displayController, PipAppOpsListener pipAppOpsListener, @@ -319,16 +324,18 @@ public class PipController implements PipTransitionController.PipTransitionCallb return null; } - return new PipController(context, shellController, displayController, pipAppOpsListener, - pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, - pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState, - pipTouchHandler, pipTransitionController, + return new PipController(context, shellInit, shellCommandHandler, shellController, + displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, + pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController, + pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController, windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder, oneHandedController, mainExecutor) .mImpl; } protected PipController(Context context, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellController shellController, DisplayController displayController, PipAppOpsListener pipAppOpsListener, @@ -355,6 +362,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb } mContext = context; + mShellCommandHandler = shellCommandHandler; mShellController = shellController; mImpl = new PipImpl(); mWindowManagerShellWrapper = windowManagerShellWrapper; @@ -378,11 +386,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb .getInteger(R.integer.config_pipEnterAnimationDuration); mPipParamsChangedForwarder = pipParamsChangedForwarder; - //TODO: move this to ShellInit when PipController can be injected - mMainExecutor.execute(this::init); + shellInit.addInitCallback(this::onInit, this); } - public void init() { + private void onInit() { + mShellCommandHandler.addDumpCallback(this::dump, this); mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(), INPUT_CONSUMER_PIP, mMainExecutor); mPipTransitionController.registerPipTransitionCallback(this); @@ -918,7 +926,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb return true; } - private void dump(PrintWriter pw) { + private void dump(PrintWriter pw, String prefix) { final String innerPrefix = " "; pw.println(TAG); mMenuController.dump(pw, innerPrefix); @@ -1006,18 +1014,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb PipController.this.showPictureInPictureMenu(); }); } - - @Override - public void dump(PrintWriter pw) { - try { - mMainExecutor.executeBlocking(() -> { - PipController.this.dump(pw); - }); - } catch (InterruptedException e) { - ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: Failed to dump PipController in 2s", TAG); - } - } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index 3d1a7e98e20d..7b42350b1365 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -44,6 +44,7 @@ import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.protolog.ShellProtoLogGroup; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.util.GroupedRecentTaskInfo; import com.android.wm.shell.util.SplitBounds; @@ -62,6 +63,7 @@ public class RecentTasksController implements TaskStackListenerCallback, private static final String TAG = RecentTasksController.class.getSimpleName(); private final Context mContext; + private final ShellCommandHandler mShellCommandHandler; private final ShellExecutor mMainExecutor; private final TaskStackListenerImpl mTaskStackListener; private final RecentTasks mImpl = new RecentTasksImpl(); @@ -87,20 +89,24 @@ public class RecentTasksController implements TaskStackListenerCallback, public static RecentTasksController create( Context context, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, TaskStackListenerImpl taskStackListener, @ShellMainThread ShellExecutor mainExecutor ) { if (!context.getResources().getBoolean(com.android.internal.R.bool.config_hasRecents)) { return null; } - return new RecentTasksController(context, shellInit, taskStackListener, mainExecutor); + return new RecentTasksController(context, shellInit, shellCommandHandler, taskStackListener, + mainExecutor); } RecentTasksController(Context context, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) { mContext = context; + mShellCommandHandler = shellCommandHandler; mIsDesktopMode = mContext.getPackageManager().hasSystemFeature(FEATURE_PC); mTaskStackListener = taskStackListener; mMainExecutor = mainExecutor; @@ -112,6 +118,7 @@ public class RecentTasksController implements TaskStackListenerCallback, } private void onInit() { + mShellCommandHandler.addDumpCallback(this::dump, this); mTaskStackListener.addListener(this); } 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 a372acbd6bdd..2117b69ebc2e 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 @@ -84,6 +84,7 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.splitscreen.SplitScreen.StageType; import com.android.wm.shell.sysui.KeyguardChangeListener; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; @@ -131,6 +132,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Retention(RetentionPolicy.SOURCE) @interface ExitReason{} + private final ShellCommandHandler mShellCommandHandler; private final ShellController mShellController; private final ShellTaskOrganizer mTaskOrganizer; private final SyncTransactionQueue mSyncQueue; @@ -147,6 +149,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private final SplitscreenEventLogger mLogger; private final IconProvider mIconProvider; private final Optional<RecentTasksController> mRecentTasksOptional; + private final SplitScreenShellCommandHandler mSplitScreenShellCommandHandler; private StageCoordinator mStageCoordinator; // Only used for the legacy recents animation from splitscreen to allow the tasks to be animated @@ -155,6 +158,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, public SplitScreenController(Context context, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellController shellController, ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, @@ -168,6 +172,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, ShellExecutor mainExecutor) { + mShellCommandHandler = shellCommandHandler; mShellController = shellController; mTaskOrganizer = shellTaskOrganizer; mSyncQueue = syncQueue; @@ -183,6 +188,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mLogger = new SplitscreenEventLogger(); mIconProvider = iconProvider; mRecentTasksOptional = recentTasks; + mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this); // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic // override for this controller from the base module if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) { @@ -200,6 +206,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, */ @VisibleForTesting void onInit() { + mShellCommandHandler.addDumpCallback(this::dump, this); + mShellCommandHandler.addCommandCallback("splitscreen", mSplitScreenShellCommandHandler, + this); mShellController.addKeyguardChangeListener(this); if (mStageCoordinator == null) { // TODO: Multi-display diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java new file mode 100644 index 000000000000..681d9647d154 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 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.splitscreen; + +import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; + +import com.android.wm.shell.sysui.ShellCommandHandler; + +import java.io.PrintWriter; + +/** + * Handles the shell commands for the SplitscreenController. + */ +public class SplitScreenShellCommandHandler implements + ShellCommandHandler.ShellCommandActionHandler { + + private final SplitScreenController mController; + + public SplitScreenShellCommandHandler(SplitScreenController controller) { + mController = controller; + } + + @Override + public boolean onShellCommand(String[] args, PrintWriter pw) { + switch (args[0]) { + case "moveToSideStage": + return runMoveToSideStage(args, pw); + case "removeFromSideStage": + return runRemoveFromSideStage(args, pw); + case "setSideStagePosition": + return runSetSideStagePosition(args, pw); + default: + pw.println("Invalid command: " + args[0]); + return false; + } + } + + private boolean runMoveToSideStage(String[] args, PrintWriter pw) { + if (args.length < 3) { + // First argument is the action name. + pw.println("Error: task id should be provided as arguments"); + return false; + } + final int taskId = new Integer(args[1]); + final int sideStagePosition = args.length > 3 + ? new Integer(args[2]) : SPLIT_POSITION_BOTTOM_OR_RIGHT; + mController.moveToSideStage(taskId, sideStagePosition); + return true; + } + + private boolean runRemoveFromSideStage(String[] args, PrintWriter pw) { + if (args.length < 2) { + // First argument is the action name. + pw.println("Error: task id should be provided as arguments"); + return false; + } + final int taskId = new Integer(args[1]); + mController.removeFromSideStage(taskId); + return true; + } + + private boolean runSetSideStagePosition(String[] args, PrintWriter pw) { + if (args.length < 2) { + // First argument is the action name. + pw.println("Error: side stage position should be provided as arguments"); + return false; + } + final int position = new Integer(args[1]); + mController.setSideStagePosition(position); + return true; + } + + @Override + public void printShellCommandHelp(PrintWriter pw, String prefix) { + pw.println(prefix + "moveToSideStage <taskId> <SideStagePosition>"); + pw.println(prefix + " Move a task with given id in split-screen mode."); + pw.println(prefix + "removeFromSideStage <taskId>"); + pw.println(prefix + " Remove a task with given id in split-screen mode."); + pw.println(prefix + "setSideStagePosition <SideStagePosition>"); + pw.println(prefix + " Sets the position of the side-stage."); + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java index f4fc0c4c36bc..2e6ddc363906 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java @@ -16,19 +16,14 @@ package com.android.wm.shell.sysui; -import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; +import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_INIT; -import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController; -import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer; -import com.android.wm.shell.onehanded.OneHandedController; -import com.android.wm.shell.pip.Pip; -import com.android.wm.shell.recents.RecentTasksController; -import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.internal.protolog.common.ProtoLog; import java.io.PrintWriter; -import java.util.Optional; +import java.util.Arrays; +import java.util.TreeMap; +import java.util.function.BiConsumer; /** * An entry point into the shell for dumping shell internal state and running adb commands. @@ -38,52 +33,61 @@ import java.util.Optional; public final class ShellCommandHandler { private static final String TAG = ShellCommandHandler.class.getSimpleName(); - private final Optional<SplitScreenController> mSplitScreenOptional; - private final Optional<Pip> mPipOptional; - private final Optional<OneHandedController> mOneHandedOptional; - private final Optional<HideDisplayCutoutController> mHideDisplayCutout; - private final Optional<RecentTasksController> mRecentTasks; - private final ShellTaskOrganizer mShellTaskOrganizer; - private final KidsModeTaskOrganizer mKidsModeTaskOrganizer; - - public ShellCommandHandler( - ShellController shellController, - ShellTaskOrganizer shellTaskOrganizer, - KidsModeTaskOrganizer kidsModeTaskOrganizer, - Optional<SplitScreenController> splitScreenOptional, - Optional<Pip> pipOptional, - Optional<OneHandedController> oneHandedOptional, - Optional<HideDisplayCutoutController> hideDisplayCutout, - Optional<RecentTasksController> recentTasks, - ShellExecutor mainExecutor) { - mShellTaskOrganizer = shellTaskOrganizer; - mKidsModeTaskOrganizer = kidsModeTaskOrganizer; - mRecentTasks = recentTasks; - mSplitScreenOptional = splitScreenOptional; - mPipOptional = pipOptional; - mOneHandedOptional = oneHandedOptional; - mHideDisplayCutout = hideDisplayCutout; - // TODO(238217847): To be removed once the command handler dependencies are inverted - shellController.setShellCommandHandler(this); + // We're using a TreeMap to keep them sorted by command name + private final TreeMap<String, BiConsumer<PrintWriter, String>> mDumpables = new TreeMap<>(); + private final TreeMap<String, ShellCommandActionHandler> mCommands = new TreeMap<>(); + + public interface ShellCommandActionHandler { + /** + * Handles the given command. + * + * @param args the arguments starting with the action name, then the action arguments + * @param pw the write to print output to + */ + boolean onShellCommand(String[] args, PrintWriter pw); + + /** + * Prints the help for this class of commands. Implementations do not need to print the + * command class. + */ + void printShellCommandHelp(PrintWriter pw, String prefix); + } + + + /** + * Adds a callback to run when the Shell is being dumped. + * + * @param callback the callback to be made when Shell is dumped, takes the print writer and + * a prefix + * @param instance used for debugging only + */ + public <T> void addDumpCallback(BiConsumer<PrintWriter, String> callback, T instance) { + mDumpables.put(instance.getClass().getSimpleName(), callback); + ProtoLog.v(WM_SHELL_INIT, "Adding dump callback for %s", + instance.getClass().getSimpleName()); + } + + /** + * Adds an action callback to be invoked when the user runs that particular command from adb. + * + * @param commandClass the top level class of command to invoke + * @param actions the interface to callback when an action of this class is invoked + * @param instance used for debugging only + */ + public <T> void addCommandCallback(String commandClass, ShellCommandActionHandler actions, + T instance) { + mCommands.put(commandClass, actions); + ProtoLog.v(WM_SHELL_INIT, "Adding command class %s for %s", commandClass, + instance.getClass().getSimpleName()); } /** Dumps WM Shell internal state. */ public void dump(PrintWriter pw) { - mShellTaskOrganizer.dump(pw, ""); - pw.println(); - pw.println(); - mPipOptional.ifPresent(pip -> pip.dump(pw)); - mOneHandedOptional.ifPresent(oneHanded -> oneHanded.dump(pw)); - mHideDisplayCutout.ifPresent(hideDisplayCutout -> hideDisplayCutout.dump(pw)); - pw.println(); - pw.println(); - mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw, "")); - pw.println(); - pw.println(); - mRecentTasks.ifPresent(recentTasks -> recentTasks.dump(pw, "")); - pw.println(); - pw.println(); - mKidsModeTaskOrganizer.dump(pw, ""); + for (String key : mDumpables.keySet()) { + final BiConsumer<PrintWriter, String> r = mDumpables.get(key); + r.accept(pw, ""); + pw.println(); + } } @@ -93,72 +97,32 @@ public final class ShellCommandHandler { // Argument at position 0 is "WMShell". return false; } - switch (args[1]) { - case "moveToSideStage": - return runMoveToSideStage(args, pw); - case "removeFromSideStage": - return runRemoveFromSideStage(args, pw); - case "setSideStagePosition": - return runSetSideStagePosition(args, pw); - case "help": - return runHelp(pw); - default: - return false; - } - } - private boolean runMoveToSideStage(String[] args, PrintWriter pw) { - if (args.length < 3) { - // First arguments are "WMShell" and command name. - pw.println("Error: task id should be provided as arguments"); - return false; + final String cmdClass = args[1]; + if (cmdClass.toLowerCase().equals("help")) { + return runHelp(pw); } - final int taskId = new Integer(args[2]); - final int sideStagePosition = args.length > 3 - ? new Integer(args[3]) : SPLIT_POSITION_BOTTOM_OR_RIGHT; - mSplitScreenOptional.ifPresent(split -> split.moveToSideStage(taskId, sideStagePosition)); - return true; - } - - private boolean runRemoveFromSideStage(String[] args, PrintWriter pw) { - if (args.length < 3) { - // First arguments are "WMShell" and command name. - pw.println("Error: task id should be provided as arguments"); + if (!mCommands.containsKey(cmdClass)) { return false; } - final int taskId = new Integer(args[2]); - mSplitScreenOptional.ifPresent(split -> split.removeFromSideStage(taskId)); - return true; - } - private boolean runSetSideStagePosition(String[] args, PrintWriter pw) { - if (args.length < 3) { - // First arguments are "WMShell" and command name. - pw.println("Error: side stage position should be provided as arguments"); - return false; - } - final int position = new Integer(args[2]); - mSplitScreenOptional.ifPresent(split -> split.setSideStagePosition(position)); + // Only pass the actions onwards as arguments to the callback + final ShellCommandActionHandler actions = mCommands.get(args[1]); + final String[] cmdClassArgs = Arrays.copyOfRange(args, 2, args.length); + actions.onShellCommand(cmdClassArgs, pw); return true; } private boolean runHelp(PrintWriter pw) { pw.println("Window Manager Shell commands:"); + for (String commandClass : mCommands.keySet()) { + pw.println(" " + commandClass); + mCommands.get(commandClass).printShellCommandHelp(pw, " "); + } pw.println(" help"); pw.println(" Print this help text."); pw.println(" <no arguments provided>"); - pw.println(" Dump Window Manager Shell internal state"); - pw.println(" pair <taskId1> <taskId2>"); - pw.println(" unpair <taskId>"); - pw.println(" Pairs/unpairs tasks with given ids."); - pw.println(" moveToSideStage <taskId> <SideStagePosition>"); - pw.println(" Move a task with given id in split-screen mode."); - pw.println(" removeFromSideStage <taskId>"); - pw.println(" Remove a task with given id in split-screen mode."); - pw.println(" setSideStageOutline <true/false>"); - pw.println(" Enable/Disable outline on the side-stage."); - pw.println(" setSideStagePosition <SideStagePosition>"); - pw.println(" Sets the position of the side-stage."); + pw.println(" Dump all Window Manager Shell internal state"); return true; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java index f1f317f65ba9..52ffb46bb39c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java @@ -45,11 +45,10 @@ public class ShellController { private static final String TAG = ShellController.class.getSimpleName(); private final ShellInit mShellInit; + private final ShellCommandHandler mShellCommandHandler; private final ShellExecutor mMainExecutor; private final ShellInterfaceImpl mImpl = new ShellInterfaceImpl(); - private ShellCommandHandler mShellCommandHandler; - private final CopyOnWriteArrayList<ConfigurationChangeListener> mConfigChangeListeners = new CopyOnWriteArrayList<>(); private final CopyOnWriteArrayList<KeyguardChangeListener> mKeyguardChangeListeners = @@ -57,8 +56,10 @@ public class ShellController { private Configuration mLastConfiguration; - public ShellController(ShellInit shellInit, ShellExecutor mainExecutor) { + public ShellController(ShellInit shellInit, ShellCommandHandler shellCommandHandler, + ShellExecutor mainExecutor) { mShellInit = shellInit; + mShellCommandHandler = shellCommandHandler; mMainExecutor = mainExecutor; } @@ -70,15 +71,6 @@ public class ShellController { } /** - * Sets the command handler to call back to. - * TODO(238217847): This is only exposed this way until we can remove the dependencies from the - * command handler to other classes. - */ - public void setShellCommandHandler(ShellCommandHandler shellCommandHandler) { - mShellCommandHandler = shellCommandHandler; - } - - /** * Adds a new configuration listener. The configuration change callbacks are not made in any * particular order. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java index c250e0313255..ac52235375c4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java @@ -52,6 +52,9 @@ public class ShellInit { * Adds a callback to the ordered list of callbacks be made when Shell is first started. This * can be used in class constructors when dagger is used to ensure that the initialization order * matches the dependency order. + * + * @param r the callback to be made when Shell is initialized + * @param instance used for debugging only */ public <T extends Object> void addInitCallback(Runnable r, T instance) { if (mHasInitialized) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index 7517e8ab6826..f865649b6bbc 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -59,6 +59,7 @@ import androidx.test.filters.SmallTest; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.compatui.CompatUIController; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; @@ -85,10 +86,12 @@ public class ShellTaskOrganizerTests extends ShellTestCase { @Mock private CompatUIController mCompatUI; @Mock - private ShellInit mShellInit; + private ShellExecutor mTestExecutor; + @Mock + private ShellCommandHandler mShellCommandHandler; - ShellTaskOrganizer mOrganizer; - private final ShellExecutor mTestExecutor = mock(ShellExecutor.class); + private ShellTaskOrganizer mOrganizer; + private ShellInit mShellInit; private class TrackingTaskListener implements ShellTaskOrganizer.TaskListener { final ArrayList<RunningTaskInfo> appeared = new ArrayList<>(); @@ -132,8 +135,11 @@ public class ShellTaskOrganizerTests extends ShellTestCase { doReturn(ParceledListSlice.<TaskAppearedInfo>emptyList()) .when(mTaskOrganizerController).registerTaskOrganizer(any()); } catch (RemoteException e) {} - mOrganizer = spy(new ShellTaskOrganizer(mShellInit, mTaskOrganizerController, - mCompatUI, Optional.empty(), Optional.empty(), mTestExecutor)); + mShellInit = spy(new ShellInit(mTestExecutor)); + mOrganizer = spy(new ShellTaskOrganizer(mShellInit, mShellCommandHandler, + mTaskOrganizerController, mCompatUI, Optional.empty(), Optional.empty(), + mTestExecutor)); + mShellInit.init(); } @Test @@ -142,9 +148,12 @@ public class ShellTaskOrganizerTests extends ShellTestCase { } @Test - public void testRegisterOrganizer_sendRegisterTaskOrganizer() throws RemoteException { - mOrganizer.registerOrganizer(); + public void instantiate_addDumpCallback() { + verify(mShellCommandHandler, times(1)).addDumpCallback(any(), any()); + } + @Test + public void testInit_sendRegisterTaskOrganizer() throws RemoteException { verify(mTaskOrganizerController).registerTaskOrganizer(any(ITaskOrganizer.class)); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java index ba81602054a8..b0dd7811c53c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -61,6 +62,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.internal.util.test.FakeSettingsProvider; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestShellExecutor; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Ignore; @@ -81,6 +83,7 @@ public class BackAnimationControllerTest extends ShellTestCase { private static final String ANIMATION_ENABLED = "1"; private final TestShellExecutor mShellExecutor = new TestShellExecutor(); + private ShellInit mShellInit; @Rule public TestableContext mContext = @@ -110,10 +113,12 @@ public class BackAnimationControllerTest extends ShellTestCase { Settings.Global.putString(mContentResolver, Settings.Global.ENABLE_BACK_ANIMATION, ANIMATION_ENABLED); mTestableLooper = TestableLooper.get(this); - mController = new BackAnimationController( + mShellInit = spy(new ShellInit(mShellExecutor)); + mController = new BackAnimationController(mShellInit, mShellExecutor, new Handler(mTestableLooper.getLooper()), mTransaction, mActivityTaskManager, mContext, mContentResolver); + mShellInit.init(); mEventTime = 0; mShellExecutor.flushAll(); } @@ -160,6 +165,11 @@ public class BackAnimationControllerTest extends ShellTestCase { } @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + + @Test @Ignore("b/207481538") public void crossActivity_screenshotAttachedAndVisible() { SurfaceControl screenshotSurface = new SurfaceControl(); @@ -233,10 +243,12 @@ public class BackAnimationControllerTest extends ShellTestCase { public void animationDisabledFromSettings() throws RemoteException { // Toggle the setting off Settings.Global.putString(mContentResolver, Settings.Global.ENABLE_BACK_ANIMATION, "0"); - mController = new BackAnimationController( + ShellInit shellInit = new ShellInit(mShellExecutor); + mController = new BackAnimationController(shellInit, mShellExecutor, new Handler(mTestableLooper.getLooper()), mTransaction, mActivityTaskManager, mContext, mContentResolver); + shellInit.init(); mController.setBackToLauncherCallback(mIOnBackInvokedCallback); RemoteAnimationTarget animationTarget = createAnimationTarget(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java index 828c13ecfda6..6292130ddec9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java @@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -54,6 +55,7 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import org.junit.Before; @@ -79,6 +81,7 @@ public class CompatUIControllerTest extends ShellTestCase { private static final int TASK_ID = 12; private CompatUIController mController; + private ShellInit mShellInit; private @Mock ShellController mMockShellController; private @Mock DisplayController mMockDisplayController; private @Mock DisplayInsetsController mMockDisplayInsetsController; @@ -107,9 +110,10 @@ public class CompatUIControllerTest extends ShellTestCase { doReturn(TASK_ID).when(mMockLetterboxEduLayout).getTaskId(); doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean()); doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean()); - mController = new CompatUIController(mContext, mMockShellController, mMockDisplayController, - mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor, - mMockTransitionsLazy) { + mShellInit = spy(new ShellInit(mMockExecutor)); + mController = new CompatUIController(mContext, mShellInit, mMockShellController, + mMockDisplayController, mMockDisplayInsetsController, mMockImeController, + mMockSyncQueue, mMockExecutor, mMockTransitionsLazy) { @Override CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) { @@ -122,10 +126,16 @@ public class CompatUIControllerTest extends ShellTestCase { return mMockLetterboxEduLayout; } }; + mShellInit.init(); spyOn(mController); } @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + + @Test public void instantiateController_registerKeyguardChangeListener() { verify(mMockShellController, times(1)).addKeyguardChangeListener(any()); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java index dcc504ad0cdb..6c301bbbc7f1 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java @@ -17,7 +17,9 @@ package com.android.wm.shell.hidedisplaycutout; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -29,7 +31,10 @@ import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Test; @@ -45,17 +50,32 @@ public class HideDisplayCutoutControllerTest extends ShellTestCase { InstrumentationRegistry.getInstrumentation().getTargetContext(), null); @Mock + private ShellCommandHandler mShellCommandHandler; + @Mock private ShellController mShellController; @Mock private HideDisplayCutoutOrganizer mMockDisplayAreaOrganizer; private HideDisplayCutoutController mHideDisplayCutoutController; + private ShellInit mShellInit; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mHideDisplayCutoutController = new HideDisplayCutoutController( - mContext, mShellController, mMockDisplayAreaOrganizer); + mShellInit = spy(new ShellInit(mock(ShellExecutor.class))); + mHideDisplayCutoutController = new HideDisplayCutoutController(mContext, mShellInit, + mShellCommandHandler, mShellController, mMockDisplayAreaOrganizer); + mShellInit.init(); + } + + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + + @Test + public void instantiateController_registerDumpCallback() { + verify(mShellCommandHandler, times(1)).addDumpCallback(any(), any()); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java index a919ad0b4765..ecfb427dbced 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java @@ -49,6 +49,7 @@ import com.android.wm.shell.common.DisplayController; 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.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; @@ -74,6 +75,7 @@ public class KidsModeTaskOrganizerTest extends ShellTestCase { @Mock private WindowContainerTransaction mTransaction; @Mock private KidsModeSettingsObserver mObserver; @Mock private ShellInit mShellInit; + @Mock private ShellCommandHandler mShellCommandHandler; @Mock private DisplayInsetsController mDisplayInsetsController; KidsModeTaskOrganizer mOrganizer; @@ -87,14 +89,20 @@ public class KidsModeTaskOrganizerTest extends ShellTestCase { } catch (RemoteException e) { } // NOTE: KidsModeTaskOrganizer should have a null CompatUIController. - mOrganizer = spy(new KidsModeTaskOrganizer(mContext, mTaskOrganizerController, - mSyncTransactionQueue, mDisplayController, mDisplayInsetsController, - Optional.empty(), Optional.empty(), mObserver, mTestExecutor, mHandler)); + mOrganizer = spy(new KidsModeTaskOrganizer(mContext, mShellInit, mShellCommandHandler, + mTaskOrganizerController, mSyncTransactionQueue, mDisplayController, + mDisplayInsetsController, Optional.empty(), Optional.empty(), mObserver, + mTestExecutor, mHandler)); doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction(); doReturn(new InsetsState()).when(mDisplayController).getInsetsState(DEFAULT_DISPLAY); } @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + + @Test public void testKidsModeOn() { doReturn(true).when(mObserver).isEnabled(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java index dbf93ae35c18..90645ce4747d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java @@ -36,7 +36,6 @@ import static org.mockito.Mockito.when; import android.graphics.Rect; import android.os.Handler; -import android.os.UserHandle; import android.testing.AndroidTestingRunner; import android.util.ArrayMap; import android.view.Display; @@ -49,7 +48,9 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerImpl; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Test; @@ -61,18 +62,20 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) public class OneHandedControllerTest extends OneHandedTestCase { - private int mCurrentUser = UserHandle.myUserId(); Display mDisplay; OneHandedAccessibilityUtil mOneHandedAccessibilityUtil; OneHandedController mSpiedOneHandedController; OneHandedTimeoutHandler mSpiedTimeoutHandler; OneHandedState mSpiedTransitionState; + ShellInit mShellInit; @Mock + ShellCommandHandler mMockShellCommandHandler; + @Mock ShellController mMockShellController; @Mock - DisplayLayout mDisplayLayout; + DisplayLayout mMockDisplayLayout; @Mock DisplayController mMockDisplayController; @Mock @@ -102,7 +105,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { public void setUp() { MockitoAnnotations.initMocks(this); mDisplay = mContext.getDisplay(); - mDisplayLayout = Mockito.mock(DisplayLayout.class); + mMockDisplayLayout = Mockito.mock(DisplayLayout.class); mSpiedTimeoutHandler = spy(new OneHandedTimeoutHandler(mMockShellMainExecutor)); mSpiedTransitionState = spy(new OneHandedState()); @@ -122,11 +125,14 @@ public class OneHandedControllerTest extends OneHandedTestCase { when(mMockDisplayAreaOrganizer.getLastDisplayBounds()).thenReturn( new Rect(0, 0, 1080, 2400)); - when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(mDisplayLayout); + when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(mMockDisplayLayout); + mShellInit = spy(new ShellInit(mMockShellMainExecutor)); mOneHandedAccessibilityUtil = new OneHandedAccessibilityUtil(mContext); mSpiedOneHandedController = spy(new OneHandedController( mContext, + mShellInit, + mMockShellCommandHandler, mMockShellController, mMockDisplayController, mMockDisplayAreaOrganizer, @@ -141,6 +147,17 @@ public class OneHandedControllerTest extends OneHandedTestCase { mMockShellMainExecutor, mMockShellMainHandler) ); + mShellInit.init(); + } + + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + + @Test + public void instantiateController_registerDumpCallback() { + verify(mMockShellCommandHandler, times(1)).addDumpCallback(any(), any()); } @Test @@ -308,9 +325,9 @@ public class OneHandedControllerTest extends OneHandedTestCase { @Test public void testRotation90CanNotStartOneHanded() { - mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90); + mMockDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90); mSpiedTransitionState.setState(STATE_NONE); - when(mDisplayLayout.isLandscape()).thenReturn(true); + when(mMockDisplayLayout.isLandscape()).thenReturn(true); mSpiedOneHandedController.setOneHandedEnabled(true); mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */); mSpiedOneHandedController.startOneHanded(); @@ -320,10 +337,10 @@ public class OneHandedControllerTest extends OneHandedTestCase { @Test public void testRotation180CanStartOneHanded() { - mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_180); + mMockDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_180); mSpiedTransitionState.setState(STATE_NONE); when(mMockDisplayAreaOrganizer.isReady()).thenReturn(true); - when(mDisplayLayout.isLandscape()).thenReturn(false); + when(mMockDisplayLayout.isLandscape()).thenReturn(false); mSpiedOneHandedController.setOneHandedEnabled(true); mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */); mSpiedOneHandedController.startOneHanded(); @@ -333,9 +350,9 @@ public class OneHandedControllerTest extends OneHandedTestCase { @Test public void testRotation270CanNotStartOneHanded() { - mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270); + mMockDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270); mSpiedTransitionState.setState(STATE_NONE); - when(mDisplayLayout.isLandscape()).thenReturn(true); + when(mMockDisplayLayout.isLandscape()).thenReturn(true); mSpiedOneHandedController.setOneHandedEnabled(true); mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */); mSpiedOneHandedController.startOneHanded(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java index e6a8220e081b..a39bdf04bf56 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java @@ -41,7 +41,9 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerImpl; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Test; @@ -61,6 +63,10 @@ public class OneHandedStateTest extends OneHandedTestCase { OneHandedState mSpiedState; @Mock + ShellInit mMockShellInit; + @Mock + ShellCommandHandler mMockShellCommandHandler; + @Mock ShellController mMockShellController; @Mock DisplayController mMockDisplayController; @@ -111,6 +117,8 @@ public class OneHandedStateTest extends OneHandedTestCase { mOneHandedAccessibilityUtil = new OneHandedAccessibilityUtil(mContext); mSpiedOneHandedController = spy(new OneHandedController( mContext, + mMockShellInit, + mMockShellCommandHandler, mMockShellController, mMockDisplayController, mMockDisplayAreaOrganizer, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java index f192514c37ab..56e32e241271 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java @@ -55,7 +55,9 @@ import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip.PipTransitionState; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Test; @@ -74,7 +76,9 @@ import java.util.Set; @TestableLooper.RunWithLooper public class PipControllerTest extends ShellTestCase { private PipController mPipController; + private ShellInit mShellInit; + @Mock private ShellCommandHandler mMockShellCommandHandler; @Mock private ShellController mMockShellController; @Mock private DisplayController mMockDisplayController; @Mock private PhonePipMenuController mMockPhonePipMenuController; @@ -105,19 +109,31 @@ public class PipControllerTest extends ShellTestCase { ((Runnable) invocation.getArgument(0)).run(); return null; }).when(mMockExecutor).execute(any()); - mPipController = new PipController(mContext, mMockShellController, mMockDisplayController, - mMockPipAppOpsListener, mMockPipBoundsAlgorithm, - mMockPipKeepClearAlgorithm, + mShellInit = spy(new ShellInit(mMockExecutor)); + mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler, + mMockShellController, mMockDisplayController, mMockPipAppOpsListener, + mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm, mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState, mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper, mMockTaskStackListener, mPipParamsChangedForwarder, mMockOneHandedController, mMockExecutor); + mShellInit.init(); when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm); when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper); } @Test + public void instantiatePipController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + + @Test + public void instantiateController_registerDumpCallback() { + verify(mMockShellCommandHandler, times(1)).addDumpCallback(any(), any()); + } + + @Test public void instantiatePipController_registerConfigChangeListener() { verify(mMockShellController, times(1)).addConfigurationChangeListener(any()); } @@ -149,9 +165,10 @@ public class PipControllerTest extends ShellTestCase { when(mockPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false); when(spyContext.getPackageManager()).thenReturn(mockPackageManager); - assertNull(PipController.create(spyContext, mMockShellController, mMockDisplayController, - mMockPipAppOpsListener, mMockPipBoundsAlgorithm, - mMockPipKeepClearAlgorithm, + ShellInit shellInit = new ShellInit(mMockExecutor); + assertNull(PipController.create(spyContext, shellInit, mMockShellCommandHandler, + mMockShellController, mMockDisplayController, mMockPipAppOpsListener, + mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm, mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState, mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java index d406a4ed3fd7..81bb609cc711 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java @@ -23,7 +23,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -48,6 +50,7 @@ import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerImpl; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.util.GroupedRecentTaskInfo; import com.android.wm.shell.util.SplitBounds; @@ -73,21 +76,35 @@ public class RecentTasksControllerTest extends ShellTestCase { @Mock private TaskStackListenerImpl mTaskStackListener; @Mock - private ShellInit mShellInit; + private ShellCommandHandler mShellCommandHandler; private ShellTaskOrganizer mShellTaskOrganizer; private RecentTasksController mRecentTasksController; + private ShellInit mShellInit; private ShellExecutor mMainExecutor; @Before public void setUp() { mMainExecutor = new TestShellExecutor(); when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class)); + mShellInit = spy(new ShellInit(mMainExecutor)); mRecentTasksController = spy(new RecentTasksController(mContext, mShellInit, - mTaskStackListener, mMainExecutor)); - mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, + mShellCommandHandler, mTaskStackListener, mMainExecutor)); + mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler, null /* sizeCompatUI */, Optional.empty(), Optional.of(mRecentTasksController), mMainExecutor); + mShellInit.init(); + } + + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), isA(RecentTasksController.class)); + } + + @Test + public void instantiateController_addDumpCallback() { + verify(mShellCommandHandler, times(1)).addDumpCallback(any(), + isA(RecentTasksController.class)); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java index c7c78d38d69b..5a68361c595c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java @@ -27,6 +27,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -54,6 +55,7 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.recents.RecentTasksController; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; @@ -73,8 +75,9 @@ import java.util.Optional; @RunWith(AndroidJUnit4.class) public class SplitScreenControllerTests extends ShellTestCase { - @Mock ShellController mShellController; @Mock ShellInit mShellInit; + @Mock ShellController mShellController; + @Mock ShellCommandHandler mShellCommandHandler; @Mock ShellTaskOrganizer mTaskOrganizer; @Mock SyncTransactionQueue mSyncQueue; @Mock RootTaskDisplayAreaOrganizer mRootTDAOrganizer; @@ -94,9 +97,10 @@ public class SplitScreenControllerTests extends ShellTestCase { public void setup() { MockitoAnnotations.initMocks(this); mSplitScreenController = spy(new SplitScreenController(mContext, mShellInit, - mShellController, mTaskOrganizer, mSyncQueue, mRootTDAOrganizer, mDisplayController, - mDisplayImeController, mDisplayInsetsController, mDragAndDropController, - mTransitions, mTransactionPool, mIconProvider, mRecentTasks, mMainExecutor)); + mShellCommandHandler, mShellController, mTaskOrganizer, mSyncQueue, + mRootTDAOrganizer, mDisplayController, mDisplayImeController, + mDisplayInsetsController, mDragAndDropController, mTransitions, mTransactionPool, + mIconProvider, mRecentTasks, mMainExecutor)); } @Test @@ -105,7 +109,24 @@ public class SplitScreenControllerTests extends ShellTestCase { } @Test + public void instantiateController_registerDumpCallback() { + doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor(); + when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout()); + mSplitScreenController.onInit(); + verify(mShellCommandHandler, times(1)).addDumpCallback(any(), any()); + } + + @Test + public void instantiateController_registerCommandCallback() { + doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor(); + when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout()); + mSplitScreenController.onInit(); + verify(mShellCommandHandler, times(1)).addCommandCallback(eq("splitscreen"), any(), any()); + } + + @Test public void testControllerRegistersKeyguardChangeListener() { + doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor(); when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout()); mSplitScreenController.onInit(); verify(mShellController, times(1)).addKeyguardChangeListener(any()); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java index 02311bab2e4d..39e58ffcf9c7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java @@ -45,6 +45,8 @@ public class ShellControllerTest extends ShellTestCase { @Mock private ShellInit mShellInit; @Mock + private ShellCommandHandler mShellCommandHandler; + @Mock private ShellExecutor mExecutor; private ShellController mController; @@ -56,7 +58,7 @@ public class ShellControllerTest extends ShellTestCase { MockitoAnnotations.initMocks(this); mKeyguardChangeListener = new TestKeyguardChangeListener(); mConfigChangeListener = new TestConfigurationChangeListener(); - mController = new ShellController(mShellInit, mExecutor); + mController = new ShellController(mShellInit, mShellCommandHandler, mExecutor); mController.onConfigurationChanged(getConfigurationCopy()); } |