Merge "3/ Fix inverted ShellInit dependency order (no functional changes)" into tm-qpr-dev am: 19aa091129

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19215131

Change-Id: I0220a85b35244d42a888477f7c11e3da7f8e4894
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Winson Chung
2022-08-02 23:04:01 +00:00
committed by Automerger Merge Worker
49 changed files with 1035 additions and 453 deletions

View File

@@ -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> unfoldAnimationController,
Optional<RecentTasksController> recentTasks) {
this(null /* taskOrganizerController */, mainExecutor, context, compatUI,
unfoldAnimationController, recentTasks);
Optional<RecentTasksController> 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> unfoldAnimationController,
Optional<RecentTasksController> recentTasks) {
Optional<RecentTasksController> 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<TaskAppearedInfo> registerOrganizer() {
synchronized (mLock) {

View File

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

View File

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

View File

@@ -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<OnDisplayChangingListener> 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) {

View File

@@ -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<DisplayRecord> mDisplays = new SparseArray<>();
private final ArrayList<OnDisplaysChangedListener> 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++) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<DisplayImeController> 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> unfoldAnimationController,
Optional<RecentTasksController> recentTasksOptional
Optional<RecentTasksController> 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> unfoldAnimationController,
Optional<RecentTasksController> recentTasksOptional
Optional<RecentTasksController> 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<BackAnimationController> 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> fullscreenTaskListener,
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue,
Optional<RecentTasksController> 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<FreeformComponents> provideFreeformTaskListener(
static Optional<FreeformComponents> provideFreeformComponents(
@DynamicOverride Optional<FreeformComponents> freeformComponents,
Context context) {
if (FreeformComponents.isFreeformEnabled(context)) {
@@ -440,11 +465,13 @@ public abstract class WMShellBaseModule {
@Provides
static Optional<RecentTasksController> 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<ActivityEmbeddingController> 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> unfoldTransitionHandler,
Optional<FreeformComponents> freeformComponents,
Optional<RecentTasksController> recentTasksOptional,
Optional<ActivityEmbeddingController> 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<Object> 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<BackAnimationController> provideBackAnimationController(
Context context,
@ShellMainThread ShellExecutor shellExecutor,
@ShellBackgroundThread Handler backgroundHandler
) {
if (BackAnimationController.IS_ENABLED) {
return Optional.of(
new BackAnimationController(shellExecutor, backgroundHandler, context));
}
return Optional.empty();
}
}

View File

@@ -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<RecentTasksController> 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<RecentTasksController> 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<SplitScreenController> splitScreenOptional,
Optional<PipTouchHandler> 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<Optional<UnfoldTransitionHandler>> unfoldTransitionHandler,
ShellInit shellInit,
@ShellMainThread ShellExecutor mainExecutor
) {
final List<UnfoldTaskAnimator> 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<Optional<SplitScreenController>> 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();
}
}

View File

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

View File

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

View File

@@ -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<T extends AutoCloseable>
implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "FreeformTaskListener";
private final ShellTaskOrganizer mShellTaskOrganizer;
private final WindowDecorViewModel<T> mWindowDecorationViewModel;
private final SparseArray<State<T>> mTasks = new SparseArray<>();
@@ -53,8 +57,19 @@ public class FreeformTaskListener<T extends AutoCloseable>
T mWindowDecoration;
}
public FreeformTaskListener(WindowDecorViewModel<T> windowDecorationViewModel) {
public FreeformTaskListener(
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
WindowDecorViewModel<T> windowDecorationViewModel) {
mShellTaskOrganizer = shellTaskOrganizer;
mWindowDecorationViewModel = windowDecorationViewModel;
if (shellInit != null) {
shellInit.addInitCallback(this::onInit, this);
}
}
private void onInit() {
mShellTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_FREEFORM);
}
@Override

View File

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

View File

@@ -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<RecentTasksController> mRecentTasksOptional;
private final SparseArray<TaskData> 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<RecentTasksController> recentTasks) {
public FullscreenTaskListener(ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue,
Optional<RecentTasksController> 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

View File

@@ -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> unfoldAnimationController,
Optional<RecentTasksController> 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> unfoldAnimationController,
Optional<RecentTasksController> recentTasks) {
super(mainExecutor, context, /* compatUI= */ null, unfoldAnimationController, recentTasks);
Optional<RecentTasksController> 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);
}

View File

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

View File

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

View File

@@ -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<RecentTasksController> recentTasks) {
DragAndDropController dragAndDropController,
Transitions transitions,
TransactionPool transactionPool,
IconProvider iconProvider,
Optional<RecentTasksController> 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();
}

View File

@@ -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<StartingWindowCo
private TriConsumer<Integer, Integer, Integer> 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<StartingWindowCo
@GuardedBy("mTaskBackgroundColors")
private final SparseIntArray mTaskBackgroundColors = new SparseIntArray();
public StartingWindowController(Context context, ShellExecutor splashScreenExecutor,
StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, IconProvider iconProvider,
public StartingWindowController(Context context,
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
ShellExecutor splashScreenExecutor,
StartingWindowTypeAlgorithm startingWindowTypeAlgorithm,
IconProvider iconProvider,
TransactionPool pool) {
mContext = context;
mShellTaskOrganizer = shellTaskOrganizer;
mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor,
iconProvider, pool);
mStartingWindowTypeAlgorithm = startingWindowTypeAlgorithm;
mSplashScreenExecutor = splashScreenExecutor;
shellInit.addInitCallback(this::onInit, this);
}
/**
@@ -98,6 +107,10 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
return mImpl;
}
private void onInit() {
mShellTaskOrganizer.initStartingWindow(this);
}
@Override
public Context getContext() {
return mContext;

View File

@@ -45,7 +45,6 @@ public final class ShellCommandHandler {
private final Optional<RecentTasksController> 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);
}

View File

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

View File

@@ -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<BubbleController> mBubblesOptional;
private final Optional<SplitScreenController> mSplitScreenOptional;
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
private final FullscreenTaskListener mFullscreenTaskListener;
private final Optional<UnfoldAnimationController> mUnfoldController;
private final Optional<UnfoldTransitionHandler> mUnfoldTransitionHandler;
private final Optional<FreeformComponents> mFreeformComponentsOptional;
private final ShellExecutor mMainExecutor;
private final Transitions mTransitions;
private final StartingWindowController mStartingWindow;
private final Optional<RecentTasksController> mRecentTasks;
private final Optional<ActivityEmbeddingController> mActivityEmbeddingOptional;
// An ordered list of init callbacks to be made once shell is first started
private final ArrayList<Pair<String, Runnable>> mInitCallbacks = new ArrayList<>();
private boolean mHasInitialized;
public ShellInit(
ShellController shellController,
DisplayController displayController,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Optional<UnfoldAnimationController> unfoldAnimationController,
Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
Optional<FreeformComponents> freeformComponentsOptional,
Optional<RecentTasksController> recentTasks,
Optional<ActivityEmbeddingController> 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;
}
}

View File

@@ -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() {

View File

@@ -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<SplitScreenController> mSplitScreenOptional;
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
private final Transitions mTransitions;
public SplitscreenPipMixedHandler(ShellInit shellInit,
Optional<SplitScreenController> splitScreenControllerOptional,
Optional<PipTouchHandler> 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);
}
}

View File

@@ -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<Transitions> {
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<Transitions> {
/** Keeps track of currently playing transitions in the order of receipt. */
private final ArrayList<ActiveTransition> 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<Transitions> {
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<Transitions> {
}
}
/** 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

View File

@@ -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<UnfoldTaskAnimator> mAnimators;
private final Lazy<Optional<UnfoldTransitionHandler>> mUnfoldTransitionHandler;
@@ -55,28 +56,36 @@ public class UnfoldAnimationController implements UnfoldListener {
private final SparseArray<SurfaceControl> mTaskSurfaces = new SparseArray<>();
private final SparseArray<UnfoldTaskAnimator> mAnimatorsByTaskId = new SparseArray<>();
public UnfoldAnimationController(@NonNull TransactionPool transactionPool,
public UnfoldAnimationController(
@NonNull ShellInit shellInit,
@NonNull TransactionPool transactionPool,
@NonNull ShellUnfoldProgressProvider unfoldProgressProvider,
@NonNull List<UnfoldTaskAnimator> animators,
@NonNull Lazy<Optional<UnfoldTransitionHandler>> 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);
}
}

View File

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

View File

@@ -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<BubbleController> mBubblesOptional;
@Mock private Optional<SplitScreenController> mSplitScreenOptional;
@Mock private Optional<PipTouchHandler> mPipTouchHandlerOptional;
@Mock private FullscreenTaskListener mFullscreenTaskListener;
@Mock private Optional<UnfoldAnimationController> mUnfoldAnimationController;
@Mock private Optional<UnfoldTransitionHandler> mUnfoldTransitionHandler;
@Mock private Optional<FreeformComponents> mFreeformComponentsOptional;
@Mock private Optional<RecentTasksController> mRecentTasks;
@Mock private Optional<ActivityEmbeddingController> 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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