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 4080b99d30cf0..5cba3b4ec1303 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -31,7 +31,6 @@ import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; import android.app.WindowConfiguration; -import android.content.Context; import android.content.LocusId; import android.content.pm.ActivityInfo; import android.graphics.Rect; @@ -56,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.ShellInit; import com.android.wm.shell.unfold.UnfoldAnimationController; import java.io.PrintWriter; @@ -186,41 +186,45 @@ public class ShellTaskOrganizer extends TaskOrganizer implements @Nullable private RunningTaskInfo mLastFocusedTaskInfo; - public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context) { - this(null /* taskOrganizerController */, mainExecutor, context, null /* compatUI */, + public ShellTaskOrganizer(ShellExecutor mainExecutor) { + this(null /* shellInit */, null /* taskOrganizerController */, null /* compatUI */, Optional.empty() /* unfoldAnimationController */, - Optional.empty() /* recentTasksController */); + Optional.empty() /* recentTasksController */, + mainExecutor); } - public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable - CompatUIController compatUI) { - this(null /* taskOrganizerController */, mainExecutor, context, compatUI, - Optional.empty() /* unfoldAnimationController */, - Optional.empty() /* recentTasksController */); - } - - public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable - CompatUIController compatUI, + public ShellTaskOrganizer(ShellInit shellInit, + @Nullable CompatUIController compatUI, Optional unfoldAnimationController, - Optional recentTasks) { - this(null /* taskOrganizerController */, mainExecutor, context, compatUI, - unfoldAnimationController, recentTasks); + Optional recentTasks, + ShellExecutor mainExecutor) { + this(shellInit, null /* taskOrganizerController */, compatUI, + unfoldAnimationController, recentTasks, mainExecutor); } @VisibleForTesting - protected ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, - ShellExecutor mainExecutor, Context context, @Nullable CompatUIController compatUI, + protected ShellTaskOrganizer(ShellInit shellInit, + ITaskOrganizerController taskOrganizerController, + @Nullable CompatUIController compatUI, Optional unfoldAnimationController, - Optional recentTasks) { + Optional recentTasks, + ShellExecutor mainExecutor) { super(taskOrganizerController, mainExecutor); mCompatUI = compatUI; mRecentTasks = recentTasks; mUnfoldAnimationController = unfoldAnimationController.orElse(null); - if (compatUI != null) { - compatUI.setCompatUICallback(this); + if (shellInit != null) { + shellInit.addInitCallback(this::onInit, this); } } + private void onInit() { + if (mCompatUI != null) { + mCompatUI.setCompatUICallback(this); + } + registerOrganizer(); + } + @Override public List registerOrganizer() { synchronized (mLock) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java index 82b0270698e48..b305897b77ae0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java @@ -28,6 +28,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; /** @@ -38,13 +39,17 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle private final Context mContext; private final Transitions mTransitions; - public ActivityEmbeddingController(Context context, Transitions transitions) { + public ActivityEmbeddingController(Context context, ShellInit shellInit, + Transitions transitions) { mContext = context; mTransitions = transitions; + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + shellInit.addInitCallback(this::onInit, this); + } } /** Registers to handle transitions. */ - public void init() { + public void onInit() { mTransitions.addHandler(this); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 1c2f0d8ca7b2b..398261600dc7f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -101,6 +101,7 @@ import com.android.wm.shell.onehanded.OneHandedTransitionCallback; import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import java.io.PrintWriter; import java.util.ArrayList; @@ -227,6 +228,7 @@ public class BubbleController implements ConfigurationChangeListener { public BubbleController(Context context, + ShellInit shellInit, ShellController shellController, BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer, @@ -279,6 +281,7 @@ public class BubbleController implements ConfigurationChangeListener { mOneHandedOptional = oneHandedOptional; mDragAndDropController = dragAndDropController; mSyncQueue = syncQueue; + shellInit.addInitCallback(this::onInit, this); } private void registerOneHandedState(OneHandedController oneHanded) { @@ -300,7 +303,7 @@ public class BubbleController implements ConfigurationChangeListener { }); } - public void initialize() { + protected void onInit() { mBubbleData.setListener(mBubbleDataListener); mBubbleData.setSuppressionChangedListener(this::onBubbleMetadataFlagChanged); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java index 28c7367662a20..ae1f43320c8b4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java @@ -28,6 +28,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.BinderThread; import com.android.wm.shell.common.annotations.ShellMainThread; +import com.android.wm.shell.sysui.ShellInit; import java.util.concurrent.CopyOnWriteArrayList; @@ -47,10 +48,15 @@ public class DisplayChangeController { private final CopyOnWriteArrayList mDisplayChangeListener = new CopyOnWriteArrayList<>(); - public DisplayChangeController(IWindowManager wmService, ShellExecutor mainExecutor) { + public DisplayChangeController(IWindowManager wmService, ShellInit shellInit, + ShellExecutor mainExecutor) { mMainExecutor = mainExecutor; mWmService = wmService; mControllerImpl = new DisplayChangeWindowControllerImpl(); + shellInit.addInitCallback(this::onInit, this); + } + + private void onInit() { try { mWmService.setDisplayChangeWindowController(mControllerImpl); } catch (RemoteException e) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java index 764936cceb015..f07ea751b044b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java @@ -34,6 +34,7 @@ import androidx.annotation.BinderThread; import com.android.wm.shell.common.DisplayChangeController.OnDisplayChangingListener; import com.android.wm.shell.common.annotations.ShellMainThread; +import com.android.wm.shell.sysui.ShellInit; import java.util.ArrayList; import java.util.List; @@ -57,19 +58,23 @@ public class DisplayController { private final SparseArray mDisplays = new SparseArray<>(); private final ArrayList mDisplayChangedListeners = new ArrayList<>(); - public DisplayController(Context context, IWindowManager wmService, + public DisplayController(Context context, IWindowManager wmService, ShellInit shellInit, ShellExecutor mainExecutor) { mMainExecutor = mainExecutor; mContext = context; mWmService = wmService; - mChangeController = new DisplayChangeController(mWmService, mainExecutor); + // TODO: Inject this instead + mChangeController = new DisplayChangeController(mWmService, shellInit, mainExecutor); mDisplayContainerListener = new DisplayWindowListenerImpl(); + // Note, add this after DisplaceChangeController is constructed to ensure that is + // initialized first + shellInit.addInitCallback(this::onInit, this); } /** * Initializes the window listener. */ - public void initialize() { + public void onInit() { try { int[] displayIds = mWmService.registerDisplayWindowListener(mDisplayContainerListener); for (int i = 0; i < displayIds.length; i++) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index b3f62477077c1..266cf294a9503 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -44,6 +44,7 @@ import android.view.animation.PathInterpolator; import androidx.annotation.VisibleForTesting; import com.android.internal.view.IInputMethodManager; +import com.android.wm.shell.sysui.ShellInit; import java.util.ArrayList; import java.util.concurrent.Executor; @@ -74,18 +75,24 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged private final ArrayList mPositionProcessors = new ArrayList<>(); - public DisplayImeController(IWindowManager wmService, DisplayController displayController, + public DisplayImeController(IWindowManager wmService, + ShellInit shellInit, + DisplayController displayController, DisplayInsetsController displayInsetsController, - Executor mainExecutor, TransactionPool transactionPool) { + TransactionPool transactionPool, + Executor mainExecutor) { mWmService = wmService; mDisplayController = displayController; mDisplayInsetsController = displayInsetsController; mMainExecutor = mainExecutor; mTransactionPool = transactionPool; + shellInit.addInitCallback(this::onInit, this); } - /** Starts monitor displays changes and set insets controller for each displays. */ - public void startMonitorDisplays() { + /** + * Starts monitor displays changes and set insets controller for each displays. + */ + public void onInit() { mDisplayController.addDisplayWindowListener(this); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java index f546f110e87c3..90a01f8c52959 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java @@ -29,6 +29,7 @@ import android.view.InsetsVisibilities; import androidx.annotation.BinderThread; import com.android.wm.shell.common.annotations.ShellMainThread; +import com.android.wm.shell.sysui.ShellInit; import java.util.concurrent.CopyOnWriteArrayList; @@ -45,17 +46,20 @@ public class DisplayInsetsController implements DisplayController.OnDisplaysChan private final SparseArray> mListeners = new SparseArray<>(); - public DisplayInsetsController(IWindowManager wmService, DisplayController displayController, + public DisplayInsetsController(IWindowManager wmService, + ShellInit shellInit, + DisplayController displayController, ShellExecutor mainExecutor) { mWmService = wmService; mDisplayController = displayController; mMainExecutor = mainExecutor; + shellInit.addInitCallback(this::onInit, this); } /** * Starts listening for insets for each display. **/ - public void initialize() { + public void onInit() { mDisplayController.addDisplayWindowListener(this); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java index 806f795d10158..10b121bbc32ce 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java @@ -92,6 +92,8 @@ import javax.inject.Qualifier; * * For example, this uses the same setup as above, but the interface provided (if bound) is used * otherwise the default is created: + * + * BaseModule: * @BindsOptionalOf * @DynamicOverride * abstract Interface dynamicInterface(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/ShellCreateTrigger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/ShellCreateTrigger.java new file mode 100644 index 0000000000000..482b199838504 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/ShellCreateTrigger.java @@ -0,0 +1,38 @@ +/* + * 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.dagger; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Qualifier; + +/** + * An annotation to specifically mark the provider that is triggering the creation of independent + * shell components that are not created as a part of the dependencies for interfaces passed to + * SysUI. + * + * TODO: This will be removed once we have a more explicit method for specifying components to start + * with SysUI + */ +@Documented +@Inherited +@Qualifier +@Retention(RetentionPolicy.RUNTIME) +public @interface ShellCreateTrigger {} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/ShellCreateTriggerOverride.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/ShellCreateTriggerOverride.java new file mode 100644 index 0000000000000..31c678968a25c --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/ShellCreateTriggerOverride.java @@ -0,0 +1,38 @@ +/* + * 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.dagger; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Qualifier; + +/** + * An annotation for non-base modules to specifically mark the provider that is triggering the + * creation of independent shell components that are not created as a part of the dependencies for + * interfaces passed to SysUI. + * + * TODO: This will be removed once we have a more explicit method for specifying components to start + * with SysUI + */ +@Documented +@Inherited +@Qualifier +@Retention(RetentionPolicy.RUNTIME) +public @interface ShellCreateTriggerOverride {} 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 a168cb22f6ad7..3add4179ef82c 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 @@ -112,16 +112,20 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static DisplayController provideDisplayController(Context context, - IWindowManager wmService, @ShellMainThread ShellExecutor mainExecutor) { - return new DisplayController(context, wmService, mainExecutor); + IWindowManager wmService, + ShellInit shellInit, + @ShellMainThread ShellExecutor mainExecutor) { + return new DisplayController(context, wmService, shellInit, mainExecutor); } @WMSingleton @Provides - static DisplayInsetsController provideDisplayInsetsController( IWindowManager wmService, + static DisplayInsetsController provideDisplayInsetsController(IWindowManager wmService, + ShellInit shellInit, DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor) { - return new DisplayInsetsController(wmService, displayController, mainExecutor); + return new DisplayInsetsController(wmService, shellInit, displayController, + mainExecutor); } // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} @@ -134,16 +138,17 @@ public abstract class WMShellBaseModule { static DisplayImeController provideDisplayImeController( @DynamicOverride Optional overrideDisplayImeController, IWindowManager wmService, + ShellInit shellInit, DisplayController displayController, DisplayInsetsController displayInsetsController, - @ShellMainThread ShellExecutor mainExecutor, - TransactionPool transactionPool + TransactionPool transactionPool, + @ShellMainThread ShellExecutor mainExecutor ) { if (overrideDisplayImeController.isPresent()) { return overrideDisplayImeController.get(); } - return new DisplayImeController(wmService, displayController, displayInsetsController, - mainExecutor, transactionPool); + return new DisplayImeController(wmService, shellInit, displayController, + displayInsetsController, transactionPool, mainExecutor); } @WMSingleton @@ -155,42 +160,45 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static DragAndDropController provideDragAndDropController(Context context, + ShellInit shellInit, ShellController shellController, DisplayController displayController, UiEventLogger uiEventLogger, IconProvider iconProvider, @ShellMainThread ShellExecutor mainExecutor) { - return new DragAndDropController(context, shellController, displayController, uiEventLogger, - iconProvider, mainExecutor); + return new DragAndDropController(context, shellInit, shellController, displayController, + uiEventLogger, iconProvider, mainExecutor); } @WMSingleton @Provides - static ShellTaskOrganizer provideShellTaskOrganizer(@ShellMainThread ShellExecutor mainExecutor, - Context context, + static ShellTaskOrganizer provideShellTaskOrganizer( + ShellInit shellInit, CompatUIController compatUI, Optional unfoldAnimationController, - Optional recentTasksOptional + Optional recentTasksOptional, + @ShellMainThread ShellExecutor mainExecutor ) { - return new ShellTaskOrganizer(mainExecutor, context, compatUI, unfoldAnimationController, - recentTasksOptional); + return new ShellTaskOrganizer(shellInit, compatUI, unfoldAnimationController, + recentTasksOptional, mainExecutor); } @WMSingleton @Provides static KidsModeTaskOrganizer provideKidsModeTaskOrganizer( - @ShellMainThread ShellExecutor mainExecutor, - @ShellMainThread Handler mainHandler, Context context, + ShellInit shellInit, SyncTransactionQueue syncTransactionQueue, DisplayController displayController, DisplayInsetsController displayInsetsController, Optional unfoldAnimationController, - Optional recentTasksOptional + Optional recentTasksOptional, + @ShellMainThread ShellExecutor mainExecutor, + @ShellMainThread Handler mainHandler ) { - return new KidsModeTaskOrganizer(mainExecutor, mainHandler, context, syncTransactionQueue, + return new KidsModeTaskOrganizer(context, shellInit, syncTransactionQueue, displayController, displayInsetsController, unfoldAnimationController, - recentTasksOptional); + recentTasksOptional, mainExecutor, mainHandler); } @WMSingleton @@ -256,6 +264,20 @@ public abstract class WMShellBaseModule { return backAnimationController.map(BackAnimationController::getBackAnimationImpl); } + @WMSingleton + @Provides + static Optional provideBackAnimationController( + Context context, + @ShellMainThread ShellExecutor shellExecutor, + @ShellBackgroundThread Handler backgroundHandler + ) { + if (BackAnimationController.IS_ENABLED) { + return Optional.of( + new BackAnimationController(shellExecutor, backgroundHandler, context)); + } + return Optional.empty(); + } + // // Bubbles (optional feature) // @@ -282,12 +304,15 @@ public abstract class WMShellBaseModule { @Provides static FullscreenTaskListener provideFullscreenTaskListener( @DynamicOverride Optional fullscreenTaskListener, + ShellInit shellInit, + ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Optional recentTasksOptional) { if (fullscreenTaskListener.isPresent()) { return fullscreenTaskListener.get(); } else { - return new FullscreenTaskListener(syncQueue, recentTasksOptional); + return new FullscreenTaskListener(shellInit, shellTaskOrganizer, syncQueue, + recentTasksOptional); } } @@ -343,7 +368,7 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static Optional provideFreeformTaskListener( + static Optional provideFreeformComponents( @DynamicOverride Optional freeformComponents, Context context) { if (FreeformComponents.isFreeformEnabled(context)) { @@ -440,11 +465,13 @@ public abstract class WMShellBaseModule { @Provides static Optional provideRecentTasksController( Context context, + ShellInit shellInit, TaskStackListenerImpl taskStackListener, @ShellMainThread ShellExecutor mainExecutor ) { return Optional.ofNullable( - RecentTasksController.create(context, taskStackListener, mainExecutor)); + RecentTasksController.create(context, shellInit, taskStackListener, + mainExecutor)); } // @@ -459,12 +486,15 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool, - DisplayController displayController, Context context, + static Transitions provideTransitions(Context context, + ShellInit shellInit, + ShellTaskOrganizer organizer, + TransactionPool pool, + DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler, @ShellAnimationThread ShellExecutor animExecutor) { - return new Transitions(organizer, pool, displayController, context, mainExecutor, + return new Transitions(context, shellInit, organizer, pool, displayController, mainExecutor, mainHandler, animExecutor); } @@ -542,11 +572,13 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static StartingWindowController provideStartingWindowController(Context context, + ShellInit shellInit, + ShellTaskOrganizer shellTaskOrganizer, @ShellSplashscreenThread ShellExecutor splashScreenExecutor, StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, IconProvider iconProvider, TransactionPool pool) { - return new StartingWindowController(context, splashScreenExecutor, - startingWindowTypeAlgorithm, iconProvider, pool); + return new StartingWindowController(context, shellInit, shellTaskOrganizer, + splashScreenExecutor, startingWindowTypeAlgorithm, iconProvider, pool); } // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} @@ -595,9 +627,11 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static Optional provideActivityEmbeddingController( - Context context, Transitions transitions) { - return Optional.of(new ActivityEmbeddingController(context, transitions)); + static ActivityEmbeddingController provideActivityEmbeddingController( + Context context, + ShellInit shellInit, + Transitions transitions) { + return new ActivityEmbeddingController(context, shellInit, transitions); } // @@ -606,24 +640,34 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static ShellInterface provideShellSysuiCallbacks(ShellController shellController) { + static ShellInterface provideShellSysuiCallbacks( + @ShellCreateTrigger Object createTrigger, + ShellController shellController) { return shellController.asShell(); } @WMSingleton @Provides - static ShellController provideShellController(@ShellMainThread ShellExecutor mainExecutor) { - return new ShellController(mainExecutor); + static ShellController provideShellController(ShellInit shellInit, + @ShellMainThread ShellExecutor mainExecutor) { + return new ShellController(shellInit, mainExecutor); } // // Misc // + // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride} + @BindsOptionalOf + @ShellCreateTriggerOverride + abstract Object provideIndependentShellComponentsToCreateOverride(); + + // TODO: Temporarily move dependencies to this instead of ShellInit since that is needed to add + // the callback. We will be moving to a different explicit startup mechanism in a follow- up CL. @WMSingleton + @ShellCreateTrigger @Provides - static ShellInit provideShellInitImpl( - ShellController shellController, + static Object provideIndependentShellComponentsToCreate( DisplayController displayController, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, @@ -638,29 +682,17 @@ public abstract class WMShellBaseModule { Optional unfoldTransitionHandler, Optional freeformComponents, Optional recentTasksOptional, - Optional activityEmbeddingOptional, + ActivityEmbeddingController activityEmbeddingOptional, Transitions transitions, StartingWindowController startingWindow, - @ShellMainThread ShellExecutor mainExecutor) { - return new ShellInit(shellController, - displayController, - displayImeController, - displayInsetsController, - dragAndDropController, - shellTaskOrganizer, - kidsModeTaskOrganizer, - bubblesOptional, - splitScreenOptional, - pipTouchHandlerOptional, - fullscreenTaskListener, - unfoldAnimationController, - unfoldTransitionHandler, - freeformComponents, - recentTasksOptional, - activityEmbeddingOptional, - transitions, - startingWindow, - mainExecutor); + @ShellCreateTriggerOverride Optional overriddenCreateTrigger) { + return new Object(); + } + + @WMSingleton + @Provides + static ShellInit provideShellInit(@ShellMainThread ShellExecutor mainExecutor) { + return new ShellInit(mainExecutor); } @WMSingleton @@ -679,18 +711,4 @@ public abstract class WMShellBaseModule { kidsModeTaskOrganizer, splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout, recentTasksOptional, mainExecutor); } - - @WMSingleton - @Provides - static Optional provideBackAnimationController( - Context context, - @ShellMainThread ShellExecutor shellExecutor, - @ShellBackgroundThread Handler backgroundHandler - ) { - if (BackAnimationController.IS_ENABLED) { - return Optional.of( - new BackAnimationController(shellExecutor, backgroundHandler, context)); - } - return Optional.empty(); - } } 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 588a1aa57a3a3..e2bf7678f4b40 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 @@ -75,6 +75,8 @@ 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.ShellController; +import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.transition.SplitscreenPipMixedHandler; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider; import com.android.wm.shell.unfold.UnfoldAnimationController; @@ -138,6 +140,7 @@ public abstract class WMShellModule { @WMSingleton @Provides static BubbleController provideBubbleController(Context context, + ShellInit shellInit, ShellController shellController, BubbleData data, FloatingContentCoordinator floatingContentCoordinator, @@ -158,8 +161,8 @@ public abstract class WMShellModule { @ShellBackgroundThread ShellExecutor bgExecutor, TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) { - return new BubbleController(context, shellController, data, null /* synchronizer */, - floatingContentCoordinator, + return new BubbleController(context, shellInit, shellController, data, + null /* synchronizer */, floatingContentCoordinator, new BubbleDataRepository(context, launcherApps, mainExecutor), statusBarService, windowManager, windowManagerShellWrapper, userManager, launcherApps, logger, taskStackListener, organizer, positioner, displayController, @@ -205,18 +208,34 @@ public abstract class WMShellModule { @WMSingleton @Provides static FreeformTaskListener provideFreeformTaskListener( + Context context, + ShellInit shellInit, + ShellTaskOrganizer shellTaskOrganizer, WindowDecorViewModel windowDecorViewModel) { - return new FreeformTaskListener<>(windowDecorViewModel); + // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic + // override for this controller from the base module + ShellInit init = FreeformComponents.isFreeformEnabled(context) + ? shellInit + : null; + return new FreeformTaskListener<>(init, shellTaskOrganizer, + windowDecorViewModel); } @WMSingleton @Provides - static FreeformTaskTransitionHandler provideTaskTransitionHandler( + static FreeformTaskTransitionHandler provideFreeformTaskTransitionHandler( + Context context, + ShellInit shellInit, Transitions transitions, WindowDecorViewModel windowDecorViewModel, FreeformTaskListener freeformTaskListener) { - return new FreeformTaskTransitionHandler(transitions, windowDecorViewModel, - freeformTaskListener); + // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic + // override for this controller from the base module + ShellInit init = FreeformComponents.isFreeformEnabled(context) + ? shellInit + : null; + return new FreeformTaskTransitionHandler(init, transitions, + windowDecorViewModel, freeformTaskListener); } // @@ -247,20 +266,25 @@ public abstract class WMShellModule { @Provides @DynamicOverride static SplitScreenController provideSplitScreenController( + Context context, + ShellInit shellInit, ShellController shellController, ShellTaskOrganizer shellTaskOrganizer, - SyncTransactionQueue syncQueue, Context context, + SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, - @ShellMainThread ShellExecutor mainExecutor, DisplayController displayController, DisplayImeController displayImeController, - DisplayInsetsController displayInsetsController, Transitions transitions, - TransactionPool transactionPool, IconProvider iconProvider, - Optional recentTasks) { - return new SplitScreenController(shellController, shellTaskOrganizer, syncQueue, context, - rootTaskDisplayAreaOrganizer, mainExecutor, displayController, displayImeController, - displayInsetsController, transitions, transactionPool, iconProvider, - recentTasks); + DisplayInsetsController displayInsetsController, + DragAndDropController dragAndDropController, + Transitions transitions, + TransactionPool transactionPool, + IconProvider iconProvider, + Optional recentTasks, + @ShellMainThread ShellExecutor mainExecutor) { + return new SplitScreenController(context, shellInit, shellController, shellTaskOrganizer, + syncQueue, rootTaskDisplayAreaOrganizer, displayController, displayImeController, + displayInsetsController, dragAndDropController, transitions, transactionPool, + iconProvider, recentTasks, mainExecutor); } // @@ -332,14 +356,16 @@ public abstract class WMShellModule { @WMSingleton @Provides static PipTouchHandler providePipTouchHandler(Context context, - PhonePipMenuController menuPhoneController, PipBoundsAlgorithm pipBoundsAlgorithm, + ShellInit shellInit, + PhonePipMenuController menuPhoneController, + PipBoundsAlgorithm pipBoundsAlgorithm, PipBoundsState pipBoundsState, PipTaskOrganizer pipTaskOrganizer, PipMotionHelper pipMotionHelper, FloatingContentCoordinator floatingContentCoordinator, PipUiEventLogger pipUiEventLogger, @ShellMainThread ShellExecutor mainExecutor) { - return new PipTouchHandler(context, menuPhoneController, pipBoundsAlgorithm, + return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm, pipBoundsState, pipTaskOrganizer, pipMotionHelper, floatingContentCoordinator, pipUiEventLogger, mainExecutor); } @@ -414,9 +440,31 @@ public abstract class WMShellModule { floatingContentCoordinator); } + @WMSingleton + @Provides + static PipParamsChangedForwarder providePipParamsChangedForwarder() { + return new PipParamsChangedForwarder(); + } + + // + // Transitions + // + + @WMSingleton + @Provides + static SplitscreenPipMixedHandler provideSplitscreenPipMixedHandler( + ShellInit shellInit, + Optional splitScreenOptional, + Optional pipTouchHandlerOptional, + Transitions transitions) { + return new SplitscreenPipMixedHandler(shellInit, splitScreenOptional, + pipTouchHandlerOptional, transitions); + } + // // Unfold transition // + @WMSingleton @Provides @DynamicOverride @@ -426,6 +474,7 @@ public abstract class WMShellModule { @UnfoldTransition SplitTaskUnfoldAnimator splitAnimator, FullscreenUnfoldTaskAnimator fullscreenAnimator, Lazy> unfoldTransitionHandler, + ShellInit shellInit, @ShellMainThread ShellExecutor mainExecutor ) { final List animators = new ArrayList<>(); @@ -433,6 +482,7 @@ public abstract class WMShellModule { animators.add(fullscreenAnimator); return new UnfoldAnimationController( + shellInit, transactionPool, progressProvider.get(), animators, @@ -441,7 +491,6 @@ public abstract class WMShellModule { ); } - @Provides static FullscreenUnfoldTaskAnimator provideFullscreenUnfoldTaskAnimator( Context context, @@ -460,6 +509,10 @@ public abstract class WMShellModule { Lazy> splitScreenOptional, DisplayInsetsController displayInsetsController ) { + // TODO(b/238217847): The lazy reference here causes some dependency issues since it + // immediately registers a listener on that controller on init. We should reference the + // controller directly once we refactor ShellTaskOrganizer to not depend on the unfold + // animation controller directly. return new SplitTaskUnfoldAnimator(context, executor, splitScreenOptional, backgroundController, displayInsetsController); } @@ -485,8 +538,9 @@ public abstract class WMShellModule { @UnfoldShellTransition SplitTaskUnfoldAnimator unfoldAnimator, TransactionPool transactionPool, Transitions transitions, - @ShellMainThread ShellExecutor executor) { - return new UnfoldTransitionHandler(progressProvider.get(), animator, + @ShellMainThread ShellExecutor executor, + ShellInit shellInit) { + return new UnfoldTransitionHandler(shellInit, progressProvider.get(), animator, unfoldAnimator, transactionPool, executor, transitions); } @@ -502,9 +556,17 @@ public abstract class WMShellModule { ); } + // + // Misc + // + + // TODO: Temporarily move dependencies to this instead of ShellInit since that is needed to add + // the callback. We will be moving to a different explicit startup mechanism in a follow- up CL. @WMSingleton + @ShellCreateTriggerOverride @Provides - static PipParamsChangedForwarder providePipParamsChangedForwarder() { - return new PipParamsChangedForwarder(); + static Object provideIndependentShellComponentsToCreate( + SplitscreenPipMixedHandler splitscreenPipMixedHandler) { + return new Object(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md index f4e2f20f46375..2aa933d641fa0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md @@ -44,10 +44,24 @@ to SysUI where it posts the work to the main Shell thread. ### Component initialization To initialize the component: -- On the Shell side, update `ShellInitImpl` to get a signal to initialize when the SysUI is started +- On the Shell side, you potentially need to do two things to initialize the component: + - Inject `ShellInit` into your component and add an init callback + - Ensure that your component is a part of the dagger dependency graph, either by: + - Making this component a dependency of an existing component already exposed to SystemUI + - Explicitly add this component to the WMShellBaseModule @ShellCreateTrigger provider or + the @ShellCreateTriggerOverride provider for your product module to expose it explicitly + if it is a completely independent component - On the SysUI side, update `WMShell` to setup any bindings for the component that depend on SysUI code +To verify that your component is being initialized at startup, you can enable the `WM_SHELL_INIT` +protolog group and restart the SysUI process: +```shell +adb shell wm logging enable-text WM_SHELL_INIT +adb shell kill `pid com.android.systemui` +adb logcat *:S WindowManagerShell +``` + ### General Do's & Dont's Do: - Do add unit tests for all new components diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java index c5df53b6dbc83..4697a0184eb4c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java @@ -62,9 +62,9 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import java.util.ArrayList; -import java.util.Optional; /** * Handles the global drag and drop handling for the Shell. @@ -94,6 +94,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange } public DragAndDropController(Context context, + ShellInit shellInit, ShellController shellController, DisplayController displayController, UiEventLogger uiEventLogger, @@ -105,14 +106,29 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange mLogger = new DragAndDropEventLogger(uiEventLogger); mIconProvider = iconProvider; mMainExecutor = mainExecutor; + shellInit.addInitCallback(this::onInit, this); } - public void initialize(Optional splitscreen) { - mSplitScreen = splitscreen.orElse(null); - mDisplayController.addDisplayWindowListener(this); + /** + * Called when the controller is initialized. + */ + public void onInit() { + // TODO(b/238217847): The dependency from SplitscreenController on DragAndDropController is + // inverted, which leads to SplitscreenController not setting its instance until after + // onDisplayAdded. We can remove this post once we fix that dependency. + mMainExecutor.executeDelayed(() -> { + mDisplayController.addDisplayWindowListener(this); + }, 0); mShellController.addConfigurationChangeListener(this); } + /** + * Sets the splitscreen controller to use if the feature is available. + */ + public void setSplitScreenController(SplitScreenController splitscreen) { + mSplitScreen = splitscreen; + } + /** Adds a listener to be notified of drag and drop events. */ public void addListener(DragAndDropListener listener) { mListeners.add(listener); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java index ba093a5fcc058..ab66107399c6f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java @@ -16,6 +16,8 @@ package com.android.wm.shell.freeform; +import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM; + import android.app.ActivityManager.RunningTaskInfo; import android.util.Log; import android.util.SparseArray; @@ -27,6 +29,7 @@ import androidx.annotation.Nullable; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.protolog.ShellProtoLogGroup; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.windowdecor.WindowDecorViewModel; @@ -42,6 +45,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { private static final String TAG = "FreeformTaskListener"; + private final ShellTaskOrganizer mShellTaskOrganizer; private final WindowDecorViewModel mWindowDecorationViewModel; private final SparseArray> mTasks = new SparseArray<>(); @@ -53,8 +57,19 @@ public class FreeformTaskListener T mWindowDecoration; } - public FreeformTaskListener(WindowDecorViewModel windowDecorationViewModel) { + public FreeformTaskListener( + ShellInit shellInit, + ShellTaskOrganizer shellTaskOrganizer, + WindowDecorViewModel windowDecorationViewModel) { + mShellTaskOrganizer = shellTaskOrganizer; mWindowDecorationViewModel = windowDecorationViewModel; + if (shellInit != null) { + shellInit.addInitCallback(this::onInit, this); + } + } + + private void onInit() { + mShellTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_FREEFORM); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java index 8731eb604cbc9..20d77259406a2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java @@ -32,6 +32,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.windowdecor.WindowDecorViewModel; @@ -49,17 +50,26 @@ public class FreeformTaskTransitionHandler private final Transitions mTransitions; private final FreeformTaskListener mFreeformTaskListener; + private final WindowDecorViewModel mWindowDecorViewModel; private final List mPendingTransitionTokens = new ArrayList<>(); public FreeformTaskTransitionHandler( + ShellInit shellInit, Transitions transitions, WindowDecorViewModel windowDecorViewModel, FreeformTaskListener freeformTaskListener) { mTransitions = transitions; mFreeformTaskListener = freeformTaskListener; + mWindowDecorViewModel = windowDecorViewModel; + if (shellInit != null && Transitions.ENABLE_SHELL_TRANSITIONS) { + shellInit.addInitCallback(this::onInit, this); + } + } - windowDecorViewModel.setFreeformTaskTransitionStarter(this); + private void onInit() { + mWindowDecorViewModel.setFreeformTaskTransitionStarter(this); + mTransitions.addHandler(this); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java index 79e363bcdb41e..0ba4afc24c451 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java @@ -32,6 +32,7 @@ import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.recents.RecentTasksController; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; @@ -43,19 +44,34 @@ import java.util.Optional; public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { private static final String TAG = "FullscreenTaskListener"; + private final ShellTaskOrganizer mShellTaskOrganizer; private final SyncTransactionQueue mSyncQueue; private final Optional mRecentTasksOptional; private final SparseArray mDataByTaskId = new SparseArray<>(); + /** + * This constructor is used by downstream products. + */ public FullscreenTaskListener(SyncTransactionQueue syncQueue) { - this(syncQueue, Optional.empty()); + this(null /* shellInit */, null /* shellTaskOrganizer */, syncQueue, Optional.empty()); } - public FullscreenTaskListener(SyncTransactionQueue syncQueue, - Optional recentTasks) { + public FullscreenTaskListener(ShellInit shellInit, + ShellTaskOrganizer shellTaskOrganizer, + SyncTransactionQueue syncQueue, + Optional recentTasksOptional) { + mShellTaskOrganizer = shellTaskOrganizer; mSyncQueue = syncQueue; - mRecentTasksOptional = recentTasks; + mRecentTasksOptional = recentTasksOptional; + // Note: Some derivative FullscreenTaskListener implementations do not use ShellInit + if (shellInit != null) { + shellInit.addInitCallback(this::onInit, this); + } + } + + private void onInit() { + mShellTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_FULLSCREEN); } @Override 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 2c8ba0970ccc2..73b9b89e6993b 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,7 +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.startingsurface.StartingWindowController; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.unfold.UnfoldAnimationController; import java.io.PrintWriter; @@ -140,18 +140,18 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer { @VisibleForTesting KidsModeTaskOrganizer( - ITaskOrganizerController taskOrganizerController, - ShellExecutor mainExecutor, - Handler mainHandler, Context context, + ITaskOrganizerController taskOrganizerController, SyncTransactionQueue syncTransactionQueue, DisplayController displayController, DisplayInsetsController displayInsetsController, Optional unfoldAnimationController, Optional recentTasks, - KidsModeSettingsObserver kidsModeSettingsObserver) { - super(taskOrganizerController, mainExecutor, context, /* compatUI= */ null, - unfoldAnimationController, recentTasks); + KidsModeSettingsObserver kidsModeSettingsObserver, + ShellExecutor mainExecutor, + Handler mainHandler) { + super(/* shellInit= */ null, taskOrganizerController, /* compatUI= */ null, + unfoldAnimationController, recentTasks, mainExecutor); mContext = context; mMainHandler = mainHandler; mSyncQueue = syncTransactionQueue; @@ -161,27 +161,30 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer { } public KidsModeTaskOrganizer( - ShellExecutor mainExecutor, - Handler mainHandler, Context context, + ShellInit shellInit, SyncTransactionQueue syncTransactionQueue, DisplayController displayController, DisplayInsetsController displayInsetsController, Optional unfoldAnimationController, - Optional recentTasks) { - super(mainExecutor, context, /* compatUI= */ null, unfoldAnimationController, recentTasks); + Optional recentTasks, + 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); mContext = context; mMainHandler = mainHandler; mSyncQueue = syncTransactionQueue; mDisplayController = displayController; mDisplayInsetsController = displayInsetsController; + shellInit.addInitCallback(this::onInit, this); } /** * Initializes kids mode status. */ - public void initialize(StartingWindowController startingWindowController) { - initStartingWindow(startingWindowController); + public void onInit() { if (mKidsModeSettingsObserver == null) { mKidsModeSettingsObserver = new KidsModeSettingsObserver(mMainHandler, mContext); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java index a2ff972471892..c86c1368b88e1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java @@ -57,6 +57,7 @@ import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip.PipUiEventLogger; import com.android.wm.shell.protolog.ShellProtoLogGroup; +import com.android.wm.shell.sysui.ShellInit; import java.io.PrintWriter; @@ -165,6 +166,7 @@ public class PipTouchHandler { @SuppressLint("InflateParams") public PipTouchHandler(Context context, + ShellInit shellInit, PhonePipMenuController menuController, PipBoundsAlgorithm pipBoundsAlgorithm, @NonNull PipBoundsState pipBoundsState, @@ -173,7 +175,6 @@ public class PipTouchHandler { FloatingContentCoordinator floatingContentCoordinator, PipUiEventLogger pipUiEventLogger, ShellExecutor mainExecutor) { - // Initialize the Pip input consumer mContext = context; mMainExecutor = mainExecutor; mAccessibilityManager = context.getSystemService(AccessibilityManager.class); @@ -213,9 +214,17 @@ public class PipTouchHandler { mMotionHelper, pipTaskOrganizer, mPipBoundsAlgorithm.getSnapAlgorithm(), this::onAccessibilityShowMenu, this::updateMovementBounds, this::animateToUnStashedState, mainExecutor); + + // TODO(b/181599115): This should really be initializes as part of the pip controller, but + // until all PIP implementations derive from the controller, just initialize the touch handler + // if it is needed + shellInit.addInitCallback(this::onInit, this); } - public void init() { + /** + * Called when the touch handler is initialized. + */ + public void onInit() { Resources res = mContext.getResources(); mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu); reloadResources(); 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 49042e663f6ef..3d1a7e98e20d0 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.ShellInit; import com.android.wm.shell.util.GroupedRecentTaskInfo; import com.android.wm.shell.util.SplitBounds; @@ -85,28 +86,32 @@ public class RecentTasksController implements TaskStackListenerCallback, @Nullable public static RecentTasksController create( Context context, + ShellInit shellInit, TaskStackListenerImpl taskStackListener, @ShellMainThread ShellExecutor mainExecutor ) { if (!context.getResources().getBoolean(com.android.internal.R.bool.config_hasRecents)) { return null; } - return new RecentTasksController(context, taskStackListener, mainExecutor); + return new RecentTasksController(context, shellInit, taskStackListener, mainExecutor); } - RecentTasksController(Context context, TaskStackListenerImpl taskStackListener, + RecentTasksController(Context context, + ShellInit shellInit, + TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) { mContext = context; mIsDesktopMode = mContext.getPackageManager().hasSystemFeature(FEATURE_PC); mTaskStackListener = taskStackListener; mMainExecutor = mainExecutor; + shellInit.addInitCallback(this::onInit, this); } public RecentTasks asRecentTasks() { return mImpl; } - public void init() { + private void onInit() { 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 2008a757839d6..1be17f9bc5fde 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 @@ -78,12 +78,14 @@ import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; +import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.DragAndDropPolicy; 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.ShellController; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.LegacyTransitions; import com.android.wm.shell.transition.Transitions; @@ -141,6 +143,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private final DisplayController mDisplayController; private final DisplayImeController mDisplayImeController; private final DisplayInsetsController mDisplayInsetsController; + private final DragAndDropController mDragAndDropController; private final Transitions mTransitions; private final TransactionPool mTransactionPool; private final SplitscreenEventLogger mLogger; @@ -152,15 +155,21 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, // outside the bounds of the roots by being reparented into a higher level fullscreen container private SurfaceControl mSplitTasksContainerLayer; - public SplitScreenController(ShellController shellController, + public SplitScreenController(Context context, + ShellInit shellInit, + ShellController shellController, ShellTaskOrganizer shellTaskOrganizer, - SyncTransactionQueue syncQueue, Context context, + SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTDAOrganizer, - ShellExecutor mainExecutor, DisplayController displayController, + DisplayController displayController, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, - Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, - Optional recentTasks) { + DragAndDropController dragAndDropController, + Transitions transitions, + TransactionPool transactionPool, + IconProvider iconProvider, + Optional recentTasks, + ShellExecutor mainExecutor) { mShellController = shellController; mTaskOrganizer = shellTaskOrganizer; mSyncQueue = syncQueue; @@ -170,17 +179,40 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mDisplayController = displayController; mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; + mDragAndDropController = dragAndDropController; mTransitions = transitions; mTransactionPool = transactionPool; mLogger = new SplitscreenEventLogger(); mIconProvider = iconProvider; mRecentTasksOptional = recentTasks; + // 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)) { + shellInit.addInitCallback(this::onInit, this); + } } public SplitScreen asSplitScreen() { return mImpl; } + /** + * This will be called after ShellTaskOrganizer has initialized/registered because of the + * dependency order. + */ + @VisibleForTesting + void onInit() { + mShellController.addKeyguardChangeListener(this); + if (mStageCoordinator == null) { + // TODO: Multi-display + mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, + mTaskOrganizer, mDisplayController, mDisplayImeController, + mDisplayInsetsController, mTransitions, mTransactionPool, mLogger, + mIconProvider, mMainExecutor, mRecentTasksOptional); + } + mDragAndDropController.setSplitScreenController(this); + } + @Override public Context getContext() { return mContext; @@ -191,17 +223,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, return mMainExecutor; } - public void onOrganizerRegistered() { - mShellController.addKeyguardChangeListener(this); - if (mStageCoordinator == null) { - // TODO: Multi-display - mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, - mTaskOrganizer, mDisplayController, mDisplayImeController, - mDisplayInsetsController, mTransitions, mTransactionPool, mLogger, - mIconProvider, mMainExecutor, mRecentTasksOptional); - } - } - public boolean isSplitScreenVisible() { return mStageCoordinator.isSplitScreenVisible(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java index fbc992378e504..379af21ac9568 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java @@ -42,10 +42,12 @@ import androidx.annotation.BinderThread; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.function.TriConsumer; import com.android.launcher3.icons.IconProvider; +import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SingleInstanceRemoteListener; import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.sysui.ShellInit; /** * Implementation to draw the starting window to an application, and remove the starting window @@ -74,6 +76,7 @@ public class StartingWindowController implements RemoteCallable mTaskLaunchingCallback; private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl(); private final Context mContext; + private final ShellTaskOrganizer mShellTaskOrganizer; private final ShellExecutor mSplashScreenExecutor; /** * Need guarded because it has exposed to StartingSurface @@ -81,14 +84,20 @@ public class StartingWindowController implements RemoteCallable mRecentTasks; private final ShellTaskOrganizer mShellTaskOrganizer; private final KidsModeTaskOrganizer mKidsModeTaskOrganizer; - private final ShellExecutor mMainExecutor; public ShellCommandHandler( ShellController shellController, @@ -64,7 +63,6 @@ public final class ShellCommandHandler { mPipOptional = pipOptional; mOneHandedOptional = oneHandedOptional; mHideDisplayCutout = hideDisplayCutout; - mMainExecutor = mainExecutor; // TODO(238217847): To be removed once the command handler dependencies are inverted shellController.setShellCommandHandler(this); } 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 618028c1544fe..f1f317f65ba9c 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 @@ -44,10 +44,10 @@ import java.util.concurrent.CopyOnWriteArrayList; public class ShellController { private static final String TAG = ShellController.class.getSimpleName(); + private final ShellInit mShellInit; private final ShellExecutor mMainExecutor; private final ShellInterfaceImpl mImpl = new ShellInterfaceImpl(); - private ShellInit mShellInit; private ShellCommandHandler mShellCommandHandler; private final CopyOnWriteArrayList mConfigChangeListeners = @@ -57,7 +57,8 @@ public class ShellController { private Configuration mLastConfiguration; - public ShellController(ShellExecutor mainExecutor) { + public ShellController(ShellInit shellInit, ShellExecutor mainExecutor) { + mShellInit = shellInit; mMainExecutor = mainExecutor; } @@ -68,15 +69,6 @@ public class ShellController { return mImpl; } - /** - * Sets the init handler to call back to. - * TODO(238217847): This is only exposed this way until we can remove the dependencies from the - * init handler to other classes. - */ - public void setShellInit(ShellInit shellInit) { - mShellInit = shellInit; - } - /** * Sets the command handler to call back to. * TODO(238217847): This is only exposed this way until we can remove the dependencies from the 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 dd7fab7c5f461..c250e03132556 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 @@ -16,7 +16,6 @@ package com.android.wm.shell.sysui; -import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_INIT; import android.os.Build; @@ -26,149 +25,27 @@ import android.util.Pair; import androidx.annotation.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; -import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.activityembedding.ActivityEmbeddingController; -import com.android.wm.shell.bubbles.BubbleController; -import com.android.wm.shell.common.DisplayController; -import com.android.wm.shell.common.DisplayImeController; -import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.draganddrop.DragAndDropController; -import com.android.wm.shell.freeform.FreeformComponents; -import com.android.wm.shell.fullscreen.FullscreenTaskListener; -import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer; -import com.android.wm.shell.pip.phone.PipTouchHandler; -import com.android.wm.shell.recents.RecentTasksController; -import com.android.wm.shell.splitscreen.SplitScreenController; -import com.android.wm.shell.startingsurface.StartingWindowController; -import com.android.wm.shell.transition.DefaultMixedHandler; -import com.android.wm.shell.transition.Transitions; -import com.android.wm.shell.unfold.UnfoldAnimationController; -import com.android.wm.shell.unfold.UnfoldTransitionHandler; import java.util.ArrayList; -import java.util.Optional; /** * The entry point implementation into the shell for initializing shell internal state. Classes - * which need to setup on start should inject an instance of this class and add an init callback. + * which need to initialize on start of the host SysUI should inject an instance of this class and + * add an init callback. */ public class ShellInit { private static final String TAG = ShellInit.class.getSimpleName(); - private final DisplayController mDisplayController; - private final DisplayImeController mDisplayImeController; - private final DisplayInsetsController mDisplayInsetsController; - private final DragAndDropController mDragAndDropController; - private final ShellTaskOrganizer mShellTaskOrganizer; - private final KidsModeTaskOrganizer mKidsModeTaskOrganizer; - private final Optional mBubblesOptional; - private final Optional mSplitScreenOptional; - private final Optional mPipTouchHandlerOptional; - private final FullscreenTaskListener mFullscreenTaskListener; - private final Optional mUnfoldController; - private final Optional mUnfoldTransitionHandler; - private final Optional mFreeformComponentsOptional; private final ShellExecutor mMainExecutor; - private final Transitions mTransitions; - private final StartingWindowController mStartingWindow; - private final Optional mRecentTasks; - private final Optional mActivityEmbeddingOptional; // An ordered list of init callbacks to be made once shell is first started private final ArrayList> mInitCallbacks = new ArrayList<>(); private boolean mHasInitialized; - public ShellInit( - ShellController shellController, - DisplayController displayController, - DisplayImeController displayImeController, - DisplayInsetsController displayInsetsController, - DragAndDropController dragAndDropController, - ShellTaskOrganizer shellTaskOrganizer, - KidsModeTaskOrganizer kidsModeTaskOrganizer, - Optional bubblesOptional, - Optional splitScreenOptional, - Optional pipTouchHandlerOptional, - FullscreenTaskListener fullscreenTaskListener, - Optional unfoldAnimationController, - Optional unfoldTransitionHandler, - Optional freeformComponentsOptional, - Optional recentTasks, - Optional activityEmbeddingOptional, - Transitions transitions, - StartingWindowController startingWindow, - ShellExecutor mainExecutor) { - mDisplayController = displayController; - mDisplayImeController = displayImeController; - mDisplayInsetsController = displayInsetsController; - mDragAndDropController = dragAndDropController; - mShellTaskOrganizer = shellTaskOrganizer; - mKidsModeTaskOrganizer = kidsModeTaskOrganizer; - mBubblesOptional = bubblesOptional; - mSplitScreenOptional = splitScreenOptional; - mFullscreenTaskListener = fullscreenTaskListener; - mPipTouchHandlerOptional = pipTouchHandlerOptional; - mUnfoldController = unfoldAnimationController; - mUnfoldTransitionHandler = unfoldTransitionHandler; - mFreeformComponentsOptional = freeformComponentsOptional; - mRecentTasks = recentTasks; - mActivityEmbeddingOptional = activityEmbeddingOptional; - mTransitions = transitions; + + public ShellInit(ShellExecutor mainExecutor) { mMainExecutor = mainExecutor; - mStartingWindow = startingWindow; - // TODO(238217847): To be removed once the init dependencies are inverted - shellController.setShellInit(this); - } - - private void legacyInit() { - // Start listening for display and insets changes - mDisplayController.initialize(); - mDisplayInsetsController.initialize(); - mDisplayImeController.startMonitorDisplays(); - - // Setup the shell organizer - mShellTaskOrganizer.addListenerForType( - mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN); - mShellTaskOrganizer.initStartingWindow(mStartingWindow); - mShellTaskOrganizer.registerOrganizer(); - - mSplitScreenOptional.ifPresent(SplitScreenController::onOrganizerRegistered); - mBubblesOptional.ifPresent(BubbleController::initialize); - - // Bind the splitscreen impl to the drag drop controller - mDragAndDropController.initialize(mSplitScreenOptional); - - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - mTransitions.register(mShellTaskOrganizer); - mActivityEmbeddingOptional.ifPresent(ActivityEmbeddingController::init); - mUnfoldTransitionHandler.ifPresent(UnfoldTransitionHandler::init); - mFreeformComponentsOptional.flatMap(f -> f.mTaskTransitionHandler) - .ifPresent(mTransitions::addHandler); - if (mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) { - final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions, - mPipTouchHandlerOptional.get().getTransitionHandler(), - mSplitScreenOptional.get().getTransitionHandler()); - // Added at end so that it has highest priority. - mTransitions.addHandler(mixedHandler); - } - } - - // TODO(b/181599115): This should really be the pip controller, but until we can provide the - // controller instead of the feature interface, can just initialize the touch handler if - // needed - mPipTouchHandlerOptional.ifPresent((handler) -> handler.init()); - - // Initialize optional freeform - mFreeformComponentsOptional.ifPresent(f -> - mShellTaskOrganizer.addListenerForType( - f.mTaskListener, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM)); - - mUnfoldController.ifPresent(UnfoldAnimationController::init); - mRecentTasks.ifPresent(RecentTasksController::init); - - // Initialize kids mode task organizer - mKidsModeTaskOrganizer.initialize(mStartingWindow); } /** @@ -201,13 +78,9 @@ public class ShellInit { final long t1 = SystemClock.uptimeMillis(); info.second.run(); final long t2 = SystemClock.uptimeMillis(); - ProtoLog.v(WM_SHELL_INIT, "\t%s took %dms", info.first, (t2 - t1)); + ProtoLog.v(WM_SHELL_INIT, "\t%s init took %dms", info.first, (t2 - t1)); } mInitCallbacks.clear(); - - // TODO: To be removed - legacyInit(); - mHasInitialized = true; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 0bec54399dd84..afc70a448aa8c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -109,6 +109,7 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.protolog.ShellProtoLogGroup; +import com.android.wm.shell.sysui.ShellInit; import java.util.ArrayList; import java.util.List; @@ -136,6 +137,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { private final TransactionPool mTransactionPool; private final DisplayController mDisplayController; private final Context mContext; + private final Handler mMainHandler; private final ShellExecutor mMainExecutor; private final ShellExecutor mAnimExecutor; private final TransitionAnimation mTransitionAnimation; @@ -167,27 +169,33 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } }; - DefaultTransitionHandler(@NonNull DisplayController displayController, - @NonNull TransactionPool transactionPool, Context context, + DefaultTransitionHandler(@NonNull Context context, + @NonNull ShellInit shellInit, + @NonNull DisplayController displayController, + @NonNull TransactionPool transactionPool, @NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler, @NonNull ShellExecutor animExecutor) { mDisplayController = displayController; mTransactionPool = transactionPool; mContext = context; + mMainHandler = mainHandler; mMainExecutor = mainExecutor; mAnimExecutor = animExecutor; mTransitionAnimation = new TransitionAnimation(context, false /* debug */, Transitions.TAG); mCurrentUserId = UserHandle.myUserId(); + mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class); + shellInit.addInitCallback(this::onInit, this); + } - mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class); + private void onInit() { updateEnterpriseThumbnailDrawable(); mContext.registerReceiver( mEnterpriseResourceUpdatedReceiver, new IntentFilter(ACTION_DEVICE_POLICY_RESOURCE_UPDATED), /* broadcastPermission = */ null, - mainHandler); + mMainHandler); - AttributeCache.init(context); + AttributeCache.init(mContext); } private void updateEnterpriseThumbnailDrawable() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java new file mode 100644 index 0000000000000..678e91fd88290 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java @@ -0,0 +1,55 @@ +/* + * 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.transition; + +import com.android.wm.shell.pip.phone.PipTouchHandler; +import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.wm.shell.sysui.ShellInit; + +import java.util.Optional; + +/** + * Handles transitions between the Splitscreen and PIP components. + */ +public class SplitscreenPipMixedHandler { + + private final Optional mSplitScreenOptional; + private final Optional mPipTouchHandlerOptional; + private final Transitions mTransitions; + + public SplitscreenPipMixedHandler(ShellInit shellInit, + Optional splitScreenControllerOptional, + Optional pipTouchHandlerOptional, + Transitions transitions) { + mSplitScreenOptional = splitScreenControllerOptional; + mPipTouchHandlerOptional = pipTouchHandlerOptional; + mTransitions = transitions; + if (Transitions.ENABLE_SHELL_TRANSITIONS + && mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) { + shellInit.addInitCallback(this::onInit, this); + } + } + + private void onInit() { + // Special handling for initializing based on multiple components + final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions, + mPipTouchHandlerOptional.get().getTransitionHandler(), + mSplitScreenOptional.get().getTransitionHandler()); + // Added at end so that it has highest priority. + mTransitions.addHandler(mixedHandler); + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 881b7a1699f6b..e6006c4fc6d0e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -59,13 +59,13 @@ import androidx.annotation.BinderThread; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; -import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.protolog.ShellProtoLogGroup; +import com.android.wm.shell.sysui.ShellInit; import java.util.ArrayList; import java.util.Arrays; @@ -111,6 +111,7 @@ public class Transitions implements RemoteCallable { private final ShellExecutor mMainExecutor; private final ShellExecutor mAnimExecutor; private final TransitionPlayerImpl mPlayerImpl; + private final DefaultTransitionHandler mDefaultTransitionHandler; private final RemoteTransitionHandler mRemoteTransitionHandler; private final DisplayController mDisplayController; private final ShellTransitionImpl mImpl = new ShellTransitionImpl(); @@ -136,8 +137,11 @@ public class Transitions implements RemoteCallable { /** Keeps track of currently playing transitions in the order of receipt. */ private final ArrayList mActiveTransitions = new ArrayList<>(); - public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool, - @NonNull DisplayController displayController, @NonNull Context context, + public Transitions(@NonNull Context context, + @NonNull ShellInit shellInit, + @NonNull WindowOrganizer organizer, + @NonNull TransactionPool pool, + @NonNull DisplayController displayController, @NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler, @NonNull ShellExecutor animExecutor) { mOrganizer = organizer; @@ -146,33 +150,35 @@ public class Transitions implements RemoteCallable { mAnimExecutor = animExecutor; mDisplayController = displayController; mPlayerImpl = new TransitionPlayerImpl(); + mDefaultTransitionHandler = new DefaultTransitionHandler(context, shellInit, + displayController, pool, mainExecutor, mainHandler, animExecutor); + mRemoteTransitionHandler = new RemoteTransitionHandler(mMainExecutor); + shellInit.addInitCallback(this::onInit, this); + } + + private void onInit() { // The very last handler (0 in the list) should be the default one. - mHandlers.add(new DefaultTransitionHandler(displayController, pool, context, mainExecutor, - mainHandler, animExecutor)); + mHandlers.add(mDefaultTransitionHandler); // Next lowest priority is remote transitions. - mRemoteTransitionHandler = new RemoteTransitionHandler(mainExecutor); mHandlers.add(mRemoteTransitionHandler); - ContentResolver resolver = context.getContentResolver(); + ContentResolver resolver = mContext.getContentResolver(); mTransitionAnimationScaleSetting = Settings.Global.getFloat(resolver, Settings.Global.TRANSITION_ANIMATION_SCALE, - context.getResources().getFloat( + mContext.getResources().getFloat( R.dimen.config_appTransitionAnimationDurationScaleDefault)); dispatchAnimScaleSetting(mTransitionAnimationScaleSetting); resolver.registerContentObserver( Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE), false, new SettingsObserver()); - } - private Transitions() { - mOrganizer = null; - mContext = null; - mMainExecutor = null; - mAnimExecutor = null; - mDisplayController = null; - mPlayerImpl = null; - mRemoteTransitionHandler = null; + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + // Register this transition handler with Core + mOrganizer.registerTransitionPlayer(mPlayerImpl); + // Pre-load the instance. + TransitionMetrics.getInstance(); + } } public ShellTransitions asRemoteTransitions() { @@ -195,14 +201,6 @@ public class Transitions implements RemoteCallable { } } - /** Register this transition handler with Core */ - public void register(ShellTaskOrganizer taskOrganizer) { - if (mPlayerImpl == null) return; - taskOrganizer.registerTransitionPlayer(mPlayerImpl); - // Pre-load the instance. - TransitionMetrics.getInstance(); - } - /** * Adds a handler candidate. * @see TransitionHandler diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java index 05a024a0eb128..6b59e313b01ba 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java @@ -24,13 +24,14 @@ import android.app.TaskInfo; import android.util.SparseArray; import android.view.SurfaceControl; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener; import com.android.wm.shell.unfold.animation.UnfoldTaskAnimator; import java.util.List; import java.util.Optional; -import java.util.concurrent.Executor; import dagger.Lazy; @@ -47,7 +48,7 @@ import dagger.Lazy; public class UnfoldAnimationController implements UnfoldListener { private final ShellUnfoldProgressProvider mUnfoldProgressProvider; - private final Executor mExecutor; + private final ShellExecutor mExecutor; private final TransactionPool mTransactionPool; private final List mAnimators; private final Lazy> mUnfoldTransitionHandler; @@ -55,28 +56,36 @@ public class UnfoldAnimationController implements UnfoldListener { private final SparseArray mTaskSurfaces = new SparseArray<>(); private final SparseArray mAnimatorsByTaskId = new SparseArray<>(); - public UnfoldAnimationController(@NonNull TransactionPool transactionPool, + public UnfoldAnimationController( + @NonNull ShellInit shellInit, + @NonNull TransactionPool transactionPool, @NonNull ShellUnfoldProgressProvider unfoldProgressProvider, @NonNull List animators, @NonNull Lazy> unfoldTransitionHandler, - @NonNull Executor executor) { + @NonNull ShellExecutor executor) { mUnfoldProgressProvider = unfoldProgressProvider; mUnfoldTransitionHandler = unfoldTransitionHandler; mTransactionPool = transactionPool; mExecutor = executor; mAnimators = animators; + // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic + // override for this controller from the base module + if (unfoldProgressProvider != ShellUnfoldProgressProvider.NO_PROVIDER) { + shellInit.addInitCallback(this::onInit, this); + } } /** * Initializes the controller, starts listening for the external events */ - public void init() { + public void onInit() { mUnfoldProgressProvider.addListener(mExecutor, this); for (int i = 0; i < mAnimators.size(); i++) { final UnfoldTaskAnimator animator = mAnimators.get(i); animator.init(); - animator.start(); + // TODO(b/238217847): See #provideSplitTaskUnfoldAnimatorBase + mExecutor.executeDelayed(animator::start, 0); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java index 9bf32faa12bdf..5d7b62905d3b0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java @@ -28,6 +28,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.transition.Transitions.TransitionFinishCallback; import com.android.wm.shell.transition.Transitions.TransitionHandler; @@ -59,11 +60,13 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene private final List mAnimators = new ArrayList<>(); - public UnfoldTransitionHandler(ShellUnfoldProgressProvider unfoldProgressProvider, + public UnfoldTransitionHandler(ShellInit shellInit, + ShellUnfoldProgressProvider unfoldProgressProvider, FullscreenUnfoldTaskAnimator fullscreenUnfoldAnimator, SplitTaskUnfoldAnimator splitUnfoldTaskAnimator, TransactionPool transactionPool, - Executor executor, Transitions transitions) { + Executor executor, + Transitions transitions) { mUnfoldProgressProvider = unfoldProgressProvider; mTransactionPool = transactionPool; mExecutor = executor; @@ -71,9 +74,18 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene mAnimators.add(splitUnfoldTaskAnimator); mAnimators.add(fullscreenUnfoldAnimator); + // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic + // override for this controller from the base module + if (unfoldProgressProvider != ShellUnfoldProgressProvider.NO_PROVIDER + && Transitions.ENABLE_SHELL_TRANSITIONS) { + shellInit.addInitCallback(this::onInit, this); + } } - public void init() { + /** + * Called when the transition handler is initialized. + */ + public void onInit() { for (int i = 0; i < mAnimators.size(); i++) { mAnimators.get(i).init(); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellInitTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellInitTest.java index 6cd5677db2c37..4bcdcaae230bf 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellInitTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellInitTest.java @@ -24,25 +24,8 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import com.android.wm.shell.activityembedding.ActivityEmbeddingController; -import com.android.wm.shell.bubbles.BubbleController; -import com.android.wm.shell.common.DisplayController; -import com.android.wm.shell.common.DisplayImeController; -import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.draganddrop.DragAndDropController; -import com.android.wm.shell.freeform.FreeformComponents; -import com.android.wm.shell.fullscreen.FullscreenTaskListener; -import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer; -import com.android.wm.shell.pip.phone.PipTouchHandler; -import com.android.wm.shell.recents.RecentTasksController; -import com.android.wm.shell.splitscreen.SplitScreenController; -import com.android.wm.shell.startingsurface.StartingWindowController; -import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; -import com.android.wm.shell.transition.Transitions; -import com.android.wm.shell.unfold.UnfoldAnimationController; -import com.android.wm.shell.unfold.UnfoldTransitionHandler; import org.junit.Before; import org.junit.Test; @@ -51,31 +34,12 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; -import java.util.Optional; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) public class ShellInitTest extends ShellTestCase { - @Mock private ShellController mShellController; - @Mock private DisplayController mDisplayController; - @Mock private DisplayImeController mDisplayImeController; - @Mock private DisplayInsetsController mDisplayInsetsController; - @Mock private DragAndDropController mDragAndDropController; - @Mock private ShellTaskOrganizer mShellTaskOrganizer; - @Mock private KidsModeTaskOrganizer mKidsModeTaskOrganizer; - @Mock private Optional mBubblesOptional; - @Mock private Optional mSplitScreenOptional; - @Mock private Optional mPipTouchHandlerOptional; - @Mock private FullscreenTaskListener mFullscreenTaskListener; - @Mock private Optional mUnfoldAnimationController; - @Mock private Optional mUnfoldTransitionHandler; - @Mock private Optional mFreeformComponentsOptional; - @Mock private Optional mRecentTasks; - @Mock private Optional mActivityEmbeddingController; - @Mock private Transitions mTransitions; - @Mock private StartingWindowController mStartingWindow; @Mock private ShellExecutor mMainExecutor; private ShellInit mImpl; @@ -83,12 +47,7 @@ public class ShellInitTest extends ShellTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mImpl = new ShellInit(mShellController, mDisplayController, mDisplayImeController, - mDisplayInsetsController, mDragAndDropController, mShellTaskOrganizer, - mKidsModeTaskOrganizer, mBubblesOptional, mSplitScreenOptional, - mPipTouchHandlerOptional, mFullscreenTaskListener, mUnfoldAnimationController, - mUnfoldTransitionHandler, mFreeformComponentsOptional, mRecentTasks, - mActivityEmbeddingController, mTransitions, mStartingWindow, mMainExecutor); + mImpl = new ShellInit(mMainExecutor); } @Test 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 3dd00329253cb..7517e8ab68266 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 @@ -36,11 +36,11 @@ import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; -import android.content.Context; import android.content.LocusId; import android.content.pm.ParceledListSlice; import android.os.Binder; @@ -58,9 +58,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.compatui.CompatUIController; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Test; @@ -84,13 +83,11 @@ public class ShellTaskOrganizerTests extends ShellTestCase { @Mock private ITaskOrganizerController mTaskOrganizerController; @Mock - private Context mContext; - @Mock private CompatUIController mCompatUI; + @Mock + private ShellInit mShellInit; ShellTaskOrganizer mOrganizer; - private final SyncTransactionQueue mSyncTransactionQueue = mock(SyncTransactionQueue.class); - private final TransactionPool mTransactionPool = mock(TransactionPool.class); private final ShellExecutor mTestExecutor = mock(ShellExecutor.class); private class TrackingTaskListener implements ShellTaskOrganizer.TaskListener { @@ -135,8 +132,13 @@ public class ShellTaskOrganizerTests extends ShellTestCase { doReturn(ParceledListSlice.emptyList()) .when(mTaskOrganizerController).registerTaskOrganizer(any()); } catch (RemoteException e) {} - mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mTestExecutor, mContext, - mCompatUI, Optional.empty(), Optional.empty())); + mOrganizer = spy(new ShellTaskOrganizer(mShellInit, mTaskOrganizerController, + mCompatUI, Optional.empty(), Optional.empty(), mTestExecutor)); + } + + @Test + public void instantiate_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java new file mode 100644 index 0000000000000..bfe3b54680852 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java @@ -0,0 +1,67 @@ +/* + * 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.activityembedding; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; + +import static org.junit.Assume.assumeTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.transition.Transitions; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for the activity embedding controller. + * + * Build/Install/Run: + * atest WMShellUnitTests:ActivityEmbeddingControllerTests + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ActivityEmbeddingControllerTests extends ShellTestCase { + + private @Mock Context mContext; + private @Mock ShellInit mShellInit; + private @Mock Transitions mTransitions; + private ActivityEmbeddingController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = spy(new ActivityEmbeddingController(mContext, mShellInit, mTransitions)); + } + + @Test + public void instantiate_addInitCallback() { + assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayChangeControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayChangeControllerTests.java new file mode 100644 index 0000000000000..b8aa8e7cbc482 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayChangeControllerTests.java @@ -0,0 +1,64 @@ +/* + * 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.common; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.view.IWindowManager; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.sysui.ShellInit; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for the display change controller. + * + * Build/Install/Run: + * atest WMShellUnitTests:DisplayChangeControllerTests + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class DisplayChangeControllerTests extends ShellTestCase { + + private @Mock IWindowManager mWM; + private @Mock ShellInit mShellInit; + private @Mock ShellExecutor mMainExecutor; + private DisplayChangeController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = spy(new DisplayChangeController(mWM, mShellInit, mMainExecutor)); + } + + @Test + public void instantiate_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java new file mode 100644 index 0000000000000..1e5e153fdfe17 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java @@ -0,0 +1,65 @@ +/* + * 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.common; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.view.IWindowManager; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.sysui.ShellInit; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for the display controller. + * + * Build/Install/Run: + * atest WMShellUnitTests:DisplayControllerTests + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class DisplayControllerTests extends ShellTestCase { + + private @Mock Context mContext; + private @Mock IWindowManager mWM; + private @Mock ShellInit mShellInit; + private @Mock ShellExecutor mMainExecutor; + private DisplayController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = new DisplayController(mContext, mWM, mShellInit, mMainExecutor); + } + + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), eq(mController)); + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java index 5b691f231d85a..9967e5f47752e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -40,26 +41,32 @@ import androidx.test.filters.SmallTest; import com.android.internal.view.IInputMethodManager; import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.util.concurrent.Executor; @SmallTest public class DisplayImeControllerTest extends ShellTestCase { + @Mock private SurfaceControl.Transaction mT; - private DisplayImeController.PerDisplay mPerDisplay; + @Mock private IInputMethodManager mMock; + @Mock + private ShellInit mShellInit; + private DisplayImeController.PerDisplay mPerDisplay; private Executor mExecutor; @Before public void setUp() throws Exception { - mT = mock(SurfaceControl.Transaction.class); - mMock = mock(IInputMethodManager.class); + MockitoAnnotations.initMocks(this); mExecutor = spy(Runnable::run); - mPerDisplay = new DisplayImeController(null, null, null, mExecutor, new TransactionPool() { + mPerDisplay = new DisplayImeController(null, mShellInit, null, null, new TransactionPool() { @Override public SurfaceControl.Transaction acquire() { return mT; @@ -68,7 +75,7 @@ public class DisplayImeControllerTest extends ShellTestCase { @Override public void release(SurfaceControl.Transaction t) { } - }) { + }, mExecutor) { @Override public IInputMethodManager getImms() { return mMock; @@ -78,6 +85,11 @@ public class DisplayImeControllerTest extends ShellTestCase { }.new PerDisplay(DEFAULT_DISPLAY, ROTATION_0); } + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + @Test public void insetsControlChanged_schedulesNoWorkOnExecutor() { mPerDisplay.insetsControlChanged(insetsStateWithIme(false), insetsSourceControl()); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java index 4a7fd3d259da1..5f5a3c584ee06 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java @@ -19,6 +19,7 @@ package com.android.wm.shell.common; import static android.view.Display.DEFAULT_DISPLAY; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.times; @@ -37,6 +38,7 @@ import androidx.test.filters.SmallTest; 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.Test; @@ -55,6 +57,8 @@ public class DisplayInsetsControllerTest extends ShellTestCase { private IWindowManager mWm; @Mock private DisplayController mDisplayController; + @Mock + private ShellInit mShellInit; private DisplayInsetsController mController; private SparseArray mInsetsControllersByDisplayId; private TestShellExecutor mExecutor; @@ -69,10 +73,15 @@ public class DisplayInsetsControllerTest extends ShellTestCase { mInsetsControllersByDisplayId = new SparseArray<>(); mDisplayIdCaptor = ArgumentCaptor.forClass(Integer.class); mInsetsControllerCaptor = ArgumentCaptor.forClass(IDisplayWindowInsetsController.class); - mController = new DisplayInsetsController(mWm, mDisplayController, mExecutor); + mController = new DisplayInsetsController(mWm, mShellInit, mDisplayController, mExecutor); addDisplay(DEFAULT_DISPLAY); } + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + @Test public void testOnDisplayAdded_setsDisplayWindowInsetsControllerOnWMService() throws RemoteException { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java index e209971998c84..b6dbcf204364b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java @@ -50,6 +50,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Test; @@ -57,8 +58,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.Optional; - /** * Tests for the drag and drop controller. */ @@ -69,6 +68,8 @@ public class DragAndDropControllerTest extends ShellTestCase { @Mock private Context mContext; @Mock + private ShellInit mShellInit; + @Mock private ShellController mShellController; @Mock private DisplayController mDisplayController; @@ -88,9 +89,14 @@ public class DragAndDropControllerTest extends ShellTestCase { @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); - mController = new DragAndDropController(mContext, mShellController, mDisplayController, - mUiEventLogger, mIconProvider, mMainExecutor); - mController.initialize(Optional.of(mSplitScreenController)); + mController = new DragAndDropController(mContext, mShellInit, mShellController, + mDisplayController, mUiEventLogger, mIconProvider, mMainExecutor); + mController.onInit(); + } + + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(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 184a8dfecff97..a919ad0b4765e 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,7 +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.startingsurface.StartingWindowController; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Test; @@ -73,7 +73,7 @@ public class KidsModeTaskOrganizerTest extends ShellTestCase { @Mock private WindowContainerToken mToken; @Mock private WindowContainerTransaction mTransaction; @Mock private KidsModeSettingsObserver mObserver; - @Mock private StartingWindowController mStartingWindowController; + @Mock private ShellInit mShellInit; @Mock private DisplayInsetsController mDisplayInsetsController; KidsModeTaskOrganizer mOrganizer; @@ -87,10 +87,9 @@ public class KidsModeTaskOrganizerTest extends ShellTestCase { } catch (RemoteException e) { } // NOTE: KidsModeTaskOrganizer should have a null CompatUIController. - mOrganizer = spy(new KidsModeTaskOrganizer(mTaskOrganizerController, mTestExecutor, - mHandler, mContext, mSyncTransactionQueue, mDisplayController, - mDisplayInsetsController, Optional.empty(), Optional.empty(), mObserver)); - mOrganizer.initialize(mStartingWindowController); + mOrganizer = spy(new KidsModeTaskOrganizer(mContext, mTaskOrganizerController, + mSyncTransactionQueue, mDisplayController, mDisplayInsetsController, + Optional.empty(), Optional.empty(), mObserver, mTestExecutor, mHandler)); doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction(); doReturn(new InsetsState()).when(mDisplayController).getInsetsState(DEFAULT_DISPLAY); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java index 74519eaf3ebf2..ecefd89d87787 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java @@ -38,6 +38,7 @@ 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.PipUiEventLogger; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Test; @@ -77,6 +78,9 @@ public class PipTouchHandlerTest extends ShellTestCase { @Mock private PipUiEventLogger mPipUiEventLogger; + @Mock + private ShellInit mShellInit; + @Mock private ShellExecutor mMainExecutor; @@ -104,11 +108,11 @@ public class PipTouchHandlerTest extends ShellTestCase { PipMotionHelper pipMotionHelper = new PipMotionHelper(mContext, mPipBoundsState, mPipTaskOrganizer, mPhonePipMenuController, mPipSnapAlgorithm, mMockPipTransitionController, mFloatingContentCoordinator); - mPipTouchHandler = new PipTouchHandler(mContext, mPhonePipMenuController, - mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer, - pipMotionHelper, mFloatingContentCoordinator, mPipUiEventLogger, - mMainExecutor); - mPipTouchHandler.init(); + mPipTouchHandler = new PipTouchHandler(mContext, mShellInit, mPhonePipMenuController, + mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer, pipMotionHelper, + mFloatingContentCoordinator, mPipUiEventLogger, mMainExecutor); + // We aren't actually using ShellInit, so just call init directly + mPipTouchHandler.onInit(); mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper()); mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler()); mPipTouchHandler.setPipMotionHelper(mMotionHelper); @@ -132,6 +136,11 @@ public class PipTouchHandlerTest extends ShellTestCase { mImeHeight = 100; } + @Test + public void instantiate_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + @Test public void updateMovementBounds_minMaxBounds() { final int shorterLength = Math.min(mPipBoundsState.getDisplayBounds().width(), 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 b1e0911bd0a8f..d406a4ed3fd75 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 @@ -48,6 +48,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.ShellInit; import com.android.wm.shell.util.GroupedRecentTaskInfo; import com.android.wm.shell.util.SplitBounds; @@ -71,6 +72,8 @@ public class RecentTasksControllerTest extends ShellTestCase { private Context mContext; @Mock private TaskStackListenerImpl mTaskStackListener; + @Mock + private ShellInit mShellInit; private ShellTaskOrganizer mShellTaskOrganizer; private RecentTasksController mRecentTasksController; @@ -80,10 +83,11 @@ public class RecentTasksControllerTest extends ShellTestCase { public void setUp() { mMainExecutor = new TestShellExecutor(); when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class)); - mRecentTasksController = spy(new RecentTasksController(mContext, mTaskStackListener, - mMainExecutor)); - mShellTaskOrganizer = new ShellTaskOrganizer(mMainExecutor, mContext, - null /* sizeCompatUI */, Optional.empty(), Optional.of(mRecentTasksController)); + mRecentTasksController = spy(new RecentTasksController(mContext, mShellInit, + mTaskStackListener, mMainExecutor)); + mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, + null /* sizeCompatUI */, Optional.empty(), Optional.of(mRecentTasksController), + mMainExecutor); } @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 c7a261f32e43b..10788f9df32f1 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 @@ -51,8 +51,10 @@ 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.common.TransactionPool; +import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.recents.RecentTasksController; 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; @@ -71,6 +73,7 @@ import java.util.Optional; public class SplitScreenControllerTests extends ShellTestCase { @Mock ShellController mShellController; + @Mock ShellInit mShellInit; @Mock ShellTaskOrganizer mTaskOrganizer; @Mock SyncTransactionQueue mSyncQueue; @Mock RootTaskDisplayAreaOrganizer mRootTDAOrganizer; @@ -78,6 +81,7 @@ public class SplitScreenControllerTests extends ShellTestCase { @Mock DisplayController mDisplayController; @Mock DisplayImeController mDisplayImeController; @Mock DisplayInsetsController mDisplayInsetsController; + @Mock DragAndDropController mDragAndDropController; @Mock Transitions mTransitions; @Mock TransactionPool mTransactionPool; @Mock IconProvider mIconProvider; @@ -88,16 +92,21 @@ public class SplitScreenControllerTests extends ShellTestCase { @Before public void setup() { MockitoAnnotations.initMocks(this); - mSplitScreenController = spy(new SplitScreenController(mShellController, mTaskOrganizer, - mSyncQueue, mContext, mRootTDAOrganizer, mMainExecutor, mDisplayController, - mDisplayImeController, mDisplayInsetsController, mTransitions, mTransactionPool, - mIconProvider, mRecentTasks)); + mSplitScreenController = spy(new SplitScreenController(mContext, mShellInit, + mShellController, mTaskOrganizer, mSyncQueue, mRootTDAOrganizer, mDisplayController, + mDisplayImeController, mDisplayInsetsController, mDragAndDropController, + mTransitions, mTransactionPool, mIconProvider, mRecentTasks, mMainExecutor)); + } + + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); } @Test public void testControllerRegistersKeyguardChangeListener() { when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout()); - mSplitScreenController.onOrganizerRegistered(); + mSplitScreenController.onInit(); verify(mShellController, times(1)).addKeyguardChangeListener(any()); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java new file mode 100644 index 0000000000000..35515e3bb6e88 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java @@ -0,0 +1,80 @@ +/* + * 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.startingsurface; + +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.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.hardware.display.DisplayManager; +import android.view.Display; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.launcher3.icons.IconProvider; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.sysui.ShellInit; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for the starting window controller. + * + * Build/Install/Run: + * atest WMShellUnitTests:StartingWindowControllerTests + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class StartingWindowControllerTests extends ShellTestCase { + + private @Mock Context mContext; + private @Mock DisplayManager mDisplayManager; + private @Mock ShellInit mShellInit; + private @Mock ShellTaskOrganizer mTaskOrganizer; + private @Mock ShellExecutor mMainExecutor; + private @Mock StartingWindowTypeAlgorithm mTypeAlgorithm; + private @Mock IconProvider mIconProvider; + private @Mock TransactionPool mTransactionPool; + private StartingWindowController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + doReturn(mock(Display.class)).when(mDisplayManager).getDisplay(anyInt()); + doReturn(mDisplayManager).when(mContext).getSystemService(eq(DisplayManager.class)); + mController = new StartingWindowController(mContext, mShellInit, mTaskOrganizer, + mMainExecutor, mTypeAlgorithm, mIconProvider, mTransactionPool); + } + + @Test + public void instantiate_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), 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 1c0e46f7264e9..02311bab2e4d0 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 @@ -42,6 +42,8 @@ import java.util.Locale; @TestableLooper.RunWithLooper(setAsMainLooper = true) public class ShellControllerTest extends ShellTestCase { + @Mock + private ShellInit mShellInit; @Mock private ShellExecutor mExecutor; @@ -54,7 +56,7 @@ public class ShellControllerTest extends ShellTestCase { MockitoAnnotations.initMocks(this); mKeyguardChangeListener = new TestKeyguardChangeListener(); mConfigChangeListener = new TestConfigurationChangeListener(); - mController = new ShellController(mExecutor); + mController = new ShellController(mShellInit, mExecutor); mController.onConfigurationChanged(getConfigurationCopy()); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java index e2f2b71cea044..388792b63db37 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java @@ -84,6 +84,7 @@ import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Test; @@ -116,6 +117,14 @@ public class ShellTransitionTests extends ShellTestCase { .when(mOrganizer).startTransition(anyInt(), any(), any()); } + @Test + public void instantiate_addInitCallback() { + ShellInit shellInit = mock(ShellInit.class); + final Transitions t = new Transitions(mContext, shellInit, mOrganizer, mTransactionPool, + createTestDisplayController(), mMainExecutor, mMainHandler, mAnimExecutor); + verify(shellInit, times(1)).addInitCallback(any(), eq(t)); + } + @Test public void testBasicTransitionFlow() { Transitions transitions = createTestTransitions(); @@ -832,14 +841,18 @@ public class ShellTransitionTests extends ShellTestCase { } catch (RemoteException e) { // No remote stuff happening, so this can't be hit } - DisplayController out = new DisplayController(mContext, mockWM, mMainExecutor); - out.initialize(); + ShellInit shellInit = new ShellInit(mMainExecutor); + DisplayController out = new DisplayController(mContext, mockWM, shellInit, mMainExecutor); + shellInit.init(); return out; } private Transitions createTestTransitions() { - return new Transitions(mOrganizer, mTransactionPool, createTestDisplayController(), - mContext, mMainExecutor, mMainHandler, mAnimExecutor); + ShellInit shellInit = new ShellInit(mMainExecutor); + final Transitions t = new Transitions(mContext, shellInit, mOrganizer, mTransactionPool, + createTestDisplayController(), mMainExecutor, mMainHandler, mAnimExecutor); + shellInit.init(); + return t; } // // private class TestDisplayController extends DisplayController { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldAnimationControllerTest.java index 46de607727667..81eefe25704e8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldAnimationControllerTest.java @@ -20,7 +20,10 @@ import static com.android.wm.shell.unfold.UnfoldAnimationControllerTest.TestUnfo import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager.RunningTaskInfo; @@ -33,6 +36,7 @@ import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.unfold.animation.UnfoldTaskAnimator; import org.junit.Before; @@ -65,6 +69,8 @@ public class UnfoldAnimationControllerTest extends ShellTestCase { @Mock private UnfoldTransitionHandler mUnfoldTransitionHandler; @Mock + private ShellInit mShellInit; + @Mock private SurfaceControl mLeash; private UnfoldAnimationController mUnfoldAnimationController; @@ -85,6 +91,7 @@ public class UnfoldAnimationControllerTest extends ShellTestCase { animators.add(mTaskAnimator1); animators.add(mTaskAnimator2); mUnfoldAnimationController = new UnfoldAnimationController( + mShellInit, mTransactionPool, mProgressProvider, animators, @@ -93,6 +100,11 @@ public class UnfoldAnimationControllerTest extends ShellTestCase { ); } + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + @Test public void testAppearedMatchingTask_appliesUnfoldProgress() { mTaskAnimator1.setTaskMatcher((info) -> info.getWindowingMode() == 2); @@ -244,7 +256,8 @@ public class UnfoldAnimationControllerTest extends ShellTestCase { @Test public void testInit_initsAndStartsAnimators() { - mUnfoldAnimationController.init(); + mUnfoldAnimationController.onInit(); + mShellExecutor.flushAll(); assertThat(mTaskAnimator1.mInitialized).isTrue(); assertThat(mTaskAnimator1.mStarted).isTrue(); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java index e9ca0fdbb929d..5f586c927ef74 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java @@ -79,11 +79,6 @@ public abstract class SystemUIInitializer { // Stand up WMComponent setupWmComponent(mContext); - if (initializeComponents) { - // Only initialize when not starting from tests since this currently initializes some - // components that shouldn't be run in the test environment - mWMComponent.init(); - } // And finally, retrieve whatever SysUI needs from WMShell and build SysUI. SysUIComponent.Builder builder = mRootComponent.getSysUIComponent(); @@ -102,6 +97,10 @@ public abstract class SystemUIInitializer { .setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper()) .setRecentTasks(mWMComponent.getRecentTasks()) .setBackAnimation(mWMComponent.getBackAnimation()); + + // Only initialize when not starting from tests since this currently initializes some + // components that shouldn't be run in the test environment + mWMComponent.init(); } else { // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option // is separating this logic into newly creating SystemUITestsFactory. diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index d009280345dea..fee17c785ed28 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -134,6 +134,7 @@ import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; import org.junit.Ignore; @@ -217,6 +218,8 @@ public class BubblesTest extends SysuiTestCase { private BubbleEntry mBubbleEntryUser11; private BubbleEntry mBubbleEntry2User11; + @Mock + private ShellInit mShellInit; @Mock private ShellController mShellController; @Mock @@ -339,6 +342,7 @@ public class BubblesTest extends SysuiTestCase { when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor); mBubbleController = new TestableBubbleController( mContext, + mShellInit, mShellController, mBubbleData, mFloatingContentCoordinator, @@ -388,6 +392,11 @@ public class BubblesTest extends SysuiTestCase { mEntryListener = mNotifListenerCaptor.getValue(); } + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), any()); + } + @Test public void instantiateController_registerConfigChangeListener() { verify(mShellController, times(1)).addConfigurationChangeListener(any()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java index f901c327b76e2..880ad187f910e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java @@ -39,6 +39,7 @@ import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; import java.util.Optional; @@ -49,6 +50,7 @@ public class TestableBubbleController extends BubbleController { // Let's assume surfaces can be synchronized immediately. TestableBubbleController(Context context, + ShellInit shellInit, ShellController shellController, BubbleData data, FloatingContentCoordinator floatingContentCoordinator, @@ -69,13 +71,13 @@ public class TestableBubbleController extends BubbleController { Handler shellMainHandler, TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) { - super(context, shellController, data, Runnable::run, floatingContentCoordinator, + super(context, shellInit, shellController, data, Runnable::run, floatingContentCoordinator, dataRepository, statusBarService, windowManager, windowManagerShellWrapper, userManager, launcherApps, bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController, oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler, new SyncExecutor(), taskViewTransitions, syncQueue); setInflateSynchronously(true); - initialize(); + onInit(); } }