2/ Migrate some common shell classes to use executors

- Remove Handler usage in some (non-feature specific) shell code
(Note: The shell main thread will still be the sysui main thread)
- Add explicit executor for display organizer

Bug: 161979899
Test: atest WMShellUnitTests
Change-Id: I9a354f742167b907c32537eb022e22c0d5bfb97a
This commit is contained in:
Winson Chung
2020-11-11 13:43:54 -08:00
parent 0a398edf5a
commit 68d5d7cdfe
30 changed files with 557 additions and 340 deletions

View File

@@ -16,113 +16,32 @@
package com.android.wm.shell;
import android.util.Slog;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import java.io.PrintWriter;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
* An entry point into the shell for dumping shell internal state and running adb commands.
*
* Use with {@code adb shell dumpsys activity service SystemUIService WMShell ...}.
*/
public final class ShellCommandHandler {
public interface ShellCommandHandler {
/**
* Dumps the shell state.
*/
void dump(PrintWriter pw);
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
private final Optional<Pip> mPipOptional;
private final Optional<OneHanded> mOneHandedOptional;
private final Optional<HideDisplayCutout> mHideDisplayCutout;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<AppPairs> mAppPairsOptional;
public ShellCommandHandler(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout,
Optional<AppPairs> appPairsOptional) {
mShellTaskOrganizer = shellTaskOrganizer;
mLegacySplitScreenOptional = legacySplitScreenOptional;
mPipOptional = pipOptional;
mOneHandedOptional = oneHandedOptional;
mHideDisplayCutout = hideDisplayCutout;
mAppPairsOptional = appPairsOptional;
}
/** Dumps WM Shell internal state. */
@ExternalThread
public void dump(PrintWriter pw) {
mShellTaskOrganizer.dump(pw, "");
pw.println();
pw.println();
mPipOptional.ifPresent(pip -> pip.dump(pw));
mLegacySplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw));
mOneHandedOptional.ifPresent(oneHanded -> oneHanded.dump(pw));
mHideDisplayCutout.ifPresent(hideDisplayCutout -> hideDisplayCutout.dump(pw));
pw.println();
pw.println();
mAppPairsOptional.ifPresent(appPairs -> appPairs.dump(pw, ""));
}
/** Returns {@code true} if command was found and executed. */
@ExternalThread
public boolean handleCommand(String[] args, PrintWriter pw) {
if (args.length < 2) {
// Argument at position 0 is "WMShell".
return false;
}
switch (args[1]) {
case "pair":
return runPair(args, pw);
case "unpair":
return runUnpair(args, pw);
case "help":
return runHelp(pw);
default:
return false;
}
}
private boolean runPair(String[] args, PrintWriter pw) {
if (args.length < 4) {
// First two arguments are "WMShell" and command name.
pw.println("Error: two task ids should be provided as arguments");
return false;
}
final int taskId1 = new Integer(args[2]);
final int taskId2 = new Integer(args[3]);
mAppPairsOptional.ifPresent(appPairs -> appPairs.pair(taskId1, taskId2));
return true;
}
private boolean runUnpair(String[] args, PrintWriter pw) {
if (args.length < 3) {
// First two arguments are "WMShell" and command name.
pw.println("Error: task id should be provided as an argument");
return false;
}
final int taskId = new Integer(args[2]);
mAppPairsOptional.ifPresent(appPairs -> appPairs.unpair(taskId));
return true;
}
private boolean runHelp(PrintWriter pw) {
pw.println("Window Manager Shell commands:");
pw.println(" help");
pw.println(" Print this help text.");
pw.println(" <no arguments provided>");
pw.println(" Dump Window Manager Shell internal state");
pw.println(" pair <taskId1> <taskId2>");
pw.println(" unpair <taskId>");
pw.println(" Pairs/unpairs tasks with given ids.");
return true;
}
/**
* Handles a shell command.
*/
boolean handleCommand(final String[] args, PrintWriter pw);
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright (C) 2019 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;
import android.util.Slog;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import java.io.PrintWriter;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
* An entry point into the shell for dumping shell internal state and running adb commands.
*
* Use with {@code adb shell dumpsys activity service SystemUIService WMShell ...}.
*/
public final class ShellCommandHandlerImpl {
private static final String TAG = ShellCommandHandlerImpl.class.getSimpleName();
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
private final Optional<Pip> mPipOptional;
private final Optional<OneHanded> mOneHandedOptional;
private final Optional<HideDisplayCutout> mHideDisplayCutout;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<AppPairs> mAppPairsOptional;
private final ShellExecutor mMainExecutor;
private final HandlerImpl mImpl = new HandlerImpl();
public static ShellCommandHandler create(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout,
Optional<AppPairs> appPairsOptional,
ShellExecutor mainExecutor) {
return new ShellCommandHandlerImpl(shellTaskOrganizer, legacySplitScreenOptional,
pipOptional, oneHandedOptional, hideDisplayCutout, appPairsOptional,
mainExecutor).mImpl;
}
private ShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout,
Optional<AppPairs> appPairsOptional,
ShellExecutor mainExecutor) {
mShellTaskOrganizer = shellTaskOrganizer;
mLegacySplitScreenOptional = legacySplitScreenOptional;
mPipOptional = pipOptional;
mOneHandedOptional = oneHandedOptional;
mHideDisplayCutout = hideDisplayCutout;
mAppPairsOptional = appPairsOptional;
mMainExecutor = mainExecutor;
}
/** Dumps WM Shell internal state. */
private void dump(PrintWriter pw) {
mShellTaskOrganizer.dump(pw, "");
pw.println();
pw.println();
mPipOptional.ifPresent(pip -> pip.dump(pw));
mLegacySplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw));
mOneHandedOptional.ifPresent(oneHanded -> oneHanded.dump(pw));
mHideDisplayCutout.ifPresent(hideDisplayCutout -> hideDisplayCutout.dump(pw));
pw.println();
pw.println();
mAppPairsOptional.ifPresent(appPairs -> appPairs.dump(pw, ""));
}
/** Returns {@code true} if command was found and executed. */
private boolean handleCommand(final String[] args, PrintWriter pw) {
if (args.length < 2) {
// Argument at position 0 is "WMShell".
return false;
}
switch (args[1]) {
case "pair":
return runPair(args, pw);
case "unpair":
return runUnpair(args, pw);
case "help":
return runHelp(pw);
default:
return false;
}
}
private boolean runPair(String[] args, PrintWriter pw) {
if (args.length < 4) {
// First two arguments are "WMShell" and command name.
pw.println("Error: two task ids should be provided as arguments");
return false;
}
final int taskId1 = new Integer(args[2]);
final int taskId2 = new Integer(args[3]);
mAppPairsOptional.ifPresent(appPairs -> appPairs.pair(taskId1, taskId2));
return true;
}
private boolean runUnpair(String[] args, PrintWriter pw) {
if (args.length < 3) {
// First two arguments are "WMShell" and command name.
pw.println("Error: task id should be provided as an argument");
return false;
}
final int taskId = new Integer(args[2]);
mAppPairsOptional.ifPresent(appPairs -> appPairs.unpair(taskId));
return true;
}
private boolean runHelp(PrintWriter pw) {
pw.println("Window Manager Shell commands:");
pw.println(" help");
pw.println(" Print this help text.");
pw.println(" <no arguments provided>");
pw.println(" Dump Window Manager Shell internal state");
pw.println(" pair <taskId1> <taskId2>");
pw.println(" unpair <taskId>");
pw.println(" Pairs/unpairs tasks with given ids.");
return true;
}
private class HandlerImpl implements ShellCommandHandler {
@Override
public void dump(PrintWriter pw) {
try {
mMainExecutor.executeBlocking(() -> ShellCommandHandlerImpl.this.dump(pw));
} catch (InterruptedException e) {
throw new RuntimeException("Failed to dump the Shell in 2s", e);
}
}
@Override
public boolean handleCommand(String[] args, PrintWriter pw) {
try {
boolean[] result = new boolean[1];
mMainExecutor.executeBlocking(() -> {
result[0] = ShellCommandHandlerImpl.this.handleCommand(args, pw);
});
return result[0];
} catch (InterruptedException e) {
throw new RuntimeException("Failed to handle Shell command in 2s", e);
}
}
}
}

View File

@@ -16,61 +16,15 @@
package com.android.wm.shell;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import java.util.Optional;
/**
* An entry point into the shell for initializing shell internal state.
*/
public class ShellInit {
private final DisplayImeController mDisplayImeController;
private final DragAndDropController mDragAndDropController;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
private final Optional<AppPairs> mAppPairsOptional;
private final FullscreenTaskListener mFullscreenTaskListener;
private final Transitions mTransitions;
public ShellInit(DisplayImeController displayImeController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions) {
mDisplayImeController = displayImeController;
mDragAndDropController = dragAndDropController;
mShellTaskOrganizer = shellTaskOrganizer;
mLegacySplitScreenOptional = legacySplitScreenOptional;
mAppPairsOptional = appPairsOptional;
mFullscreenTaskListener = fullscreenTaskListener;
mTransitions = transitions;
}
@ExternalThread
public void init() {
// Start listening for display changes
mDisplayImeController.startMonitorDisplays();
mShellTaskOrganizer.addListenerForType(
mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
// Register the shell organizer
mShellTaskOrganizer.registerOrganizer();
mAppPairsOptional.ifPresent(AppPairs::onOrganizerRegistered);
// Bind the splitscreen impl to the drag drop controller
mDragAndDropController.setSplitScreenController(mLegacySplitScreenOptional);
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
mTransitions.register(mShellTaskOrganizer);
}
}
@ExternalThread
public interface ShellInit {
/**
* Initializes the shell state.
*/
void init();
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (C) 2019 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;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
* The entry point implementation into the shell for initializing shell internal state.
*/
public class ShellInitImpl {
private static final String TAG = ShellInitImpl.class.getSimpleName();
private final DisplayImeController mDisplayImeController;
private final DragAndDropController mDragAndDropController;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
private final Optional<AppPairs> mAppPairsOptional;
private final FullscreenTaskListener mFullscreenTaskListener;
private final ShellExecutor mMainExecutor;
private final InitImpl mImpl = new InitImpl();
public static ShellInit create(DisplayImeController displayImeController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener,
ShellExecutor mainExecutor) {
return new ShellInitImpl(displayImeController,
dragAndDropController,
shellTaskOrganizer,
legacySplitScreenOptional,
appPairsOptional,
fullscreenTaskListener,
mainExecutor).mImpl;
}
private ShellInitImpl(DisplayImeController displayImeController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener,
ShellExecutor mainExecutor) {
mDisplayImeController = displayImeController;
mDragAndDropController = dragAndDropController;
mShellTaskOrganizer = shellTaskOrganizer;
mLegacySplitScreenOptional = legacySplitScreenOptional;
mAppPairsOptional = appPairsOptional;
mFullscreenTaskListener = fullscreenTaskListener;
mMainExecutor = mainExecutor;
}
private void init() {
// Start listening for display changes
mDisplayImeController.startMonitorDisplays();
mShellTaskOrganizer.addListenerForType(
mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
// Register the shell organizer
mShellTaskOrganizer.registerOrganizer();
mAppPairsOptional.ifPresent(AppPairs::onOrganizerRegistered);
// Bind the splitscreen impl to the drag drop controller
mDragAndDropController.initialize(mLegacySplitScreenOptional);
}
@ExternalThread
private class InitImpl implements ShellInit {
@Override
public void init() {
try {
mMainExecutor.executeBlocking(() -> ShellInitImpl.this.init());
} catch (InterruptedException e) {
throw new RuntimeException("Failed to initialize the Shell in 2s", e);
}
}
}
}

View File

@@ -37,8 +37,8 @@ public class WindowManagerShellWrapper {
*/
private final PinnedStackListenerForwarder mPinnedStackListenerForwarder;
public WindowManagerShellWrapper(ShellExecutor shellMainExecutor) {
mPinnedStackListenerForwarder = new PinnedStackListenerForwarder(shellMainExecutor);
public WindowManagerShellWrapper(ShellExecutor mainExecutor) {
mPinnedStackListenerForwarder = new PinnedStackListenerForwarder(mainExecutor);
}
/**

View File

@@ -45,7 +45,6 @@ import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -68,6 +67,7 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import java.io.FileDescriptor;
@@ -106,7 +106,6 @@ public class BubbleController implements Bubbles {
private final FloatingContentCoordinator mFloatingContentCoordinator;
private final BubbleDataRepository mDataRepository;
private BubbleLogger mLogger;
private final Handler mMainHandler;
private BubbleData mBubbleData;
private View mBubbleScrim;
@Nullable private BubbleStackView mStackView;
@@ -138,7 +137,7 @@ public class BubbleController implements Bubbles {
private WindowManager mWindowManager;
// Used to post to main UI thread
private Handler mHandler = new Handler();
private final ShellExecutor mMainExecutor;
/** LayoutParams used to add the BubbleStackView to the window manager. */
private WindowManager.LayoutParams mWmLayoutParams;
@@ -186,15 +185,15 @@ public class BubbleController implements Bubbles {
WindowManagerShellWrapper windowManagerShellWrapper,
LauncherApps launcherApps,
UiEventLogger uiEventLogger,
Handler mainHandler,
ShellTaskOrganizer organizer) {
ShellTaskOrganizer organizer,
ShellExecutor mainExecutor) {
BubbleLogger logger = new BubbleLogger(uiEventLogger);
BubblePositioner positioner = new BubblePositioner(context, windowManager);
BubbleData data = new BubbleData(context, logger, positioner);
return new BubbleController(context, data, synchronizer, floatingContentCoordinator,
new BubbleDataRepository(context, launcherApps),
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
logger, mainHandler, organizer, positioner);
logger, organizer, positioner, mainExecutor);
}
/**
@@ -211,14 +210,14 @@ public class BubbleController implements Bubbles {
WindowManagerShellWrapper windowManagerShellWrapper,
LauncherApps launcherApps,
BubbleLogger bubbleLogger,
Handler mainHandler,
ShellTaskOrganizer organizer,
BubblePositioner positioner) {
BubblePositioner positioner,
ShellExecutor mainExecutor) {
mContext = context;
mFloatingContentCoordinator = floatingContentCoordinator;
mDataRepository = dataRepository;
mLogger = bubbleLogger;
mMainHandler = mainHandler;
mMainExecutor = mainExecutor;
mBubblePositioner = positioner;
mBubbleData = data;
@@ -241,7 +240,7 @@ public class BubbleController implements Bubbles {
bubble.setPendingIntentCanceled();
return;
}
mHandler.post(() -> removeBubble(bubble.getKey(), DISMISS_INVALID_INTENT));
mMainExecutor.execute(() -> removeBubble(bubble.getKey(), DISMISS_INVALID_INTENT));
});
try {

View File

@@ -16,7 +16,6 @@
package com.android.wm.shell.common;
import android.os.Handler;
import android.os.RemoteException;
import android.view.IDisplayWindowRotationCallback;
import android.view.IDisplayWindowRotationController;
@@ -37,7 +36,7 @@ import java.util.ArrayList;
*/
public class DisplayChangeController {
private final Handler mHandler;
private final ShellExecutor mMainExecutor;
private final IWindowManager mWmService;
private final IDisplayWindowRotationController mControllerImpl;
@@ -45,8 +44,8 @@ public class DisplayChangeController {
new ArrayList<>();
private final ArrayList<OnDisplayChangingListener> mTmpListeners = new ArrayList<>();
public DisplayChangeController(Handler mainHandler, IWindowManager wmService) {
mHandler = mainHandler;
public DisplayChangeController(IWindowManager wmService, ShellExecutor mainExecutor) {
mMainExecutor = mainExecutor;
mWmService = wmService;
mControllerImpl = new DisplayWindowRotationControllerImpl();
try {
@@ -97,7 +96,7 @@ public class DisplayChangeController {
@Override
public void onRotateDisplay(int displayId, final int fromRotation,
final int toRotation, IDisplayWindowRotationCallback callback) {
mHandler.post(() -> {
mMainExecutor.execute(() -> {
DisplayChangeController.this.onRotateDisplay(displayId, fromRotation, toRotation,
callback);
});

View File

@@ -20,7 +20,6 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Slog;
import android.util.SparseArray;
@@ -44,7 +43,7 @@ import java.util.ArrayList;
public class DisplayController {
private static final String TAG = "DisplayController";
private final Handler mHandler;
private final ShellExecutor mMainExecutor;
private final Context mContext;
private final IWindowManager mWmService;
private final DisplayChangeController mChangeController;
@@ -61,12 +60,12 @@ public class DisplayController {
return displayManager.getDisplay(displayId);
}
public DisplayController(Context context, Handler handler,
IWindowManager wmService) {
mHandler = handler;
public DisplayController(Context context, IWindowManager wmService,
ShellExecutor mainExecutor) {
mMainExecutor = mainExecutor;
mContext = context;
mWmService = wmService;
mChangeController = new DisplayChangeController(mHandler, mWmService);
mChangeController = new DisplayChangeController(mWmService, mainExecutor);
mDisplayContainerListener = new DisplayWindowListenerImpl();
try {
mWmService.registerDisplayWindowListener(mDisplayContainerListener);
@@ -229,35 +228,35 @@ public class DisplayController {
private class DisplayWindowListenerImpl extends IDisplayWindowListener.Stub {
@Override
public void onDisplayAdded(int displayId) {
mHandler.post(() -> {
mMainExecutor.execute(() -> {
DisplayController.this.onDisplayAdded(displayId);
});
}
@Override
public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
mHandler.post(() -> {
mMainExecutor.execute(() -> {
DisplayController.this.onDisplayConfigurationChanged(displayId, newConfig);
});
}
@Override
public void onDisplayRemoved(int displayId) {
mHandler.post(() -> {
mMainExecutor.execute(() -> {
DisplayController.this.onDisplayRemoved(displayId);
});
}
@Override
public void onFixedRotationStarted(int displayId, int newRotation) {
mHandler.post(() -> {
mMainExecutor.execute(() -> {
DisplayController.this.onFixedRotationStarted(displayId, newRotation);
});
}
@Override
public void onFixedRotationFinished(int displayId) {
mHandler.post(() -> {
mMainExecutor.execute(() -> {
DisplayController.this.onFixedRotationFinished(displayId);
});
}

View File

@@ -40,10 +40,12 @@ import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import androidx.annotation.BinderThread;
import androidx.annotation.VisibleForTesting;
import com.android.internal.view.IInputMethodManager;
import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -64,7 +66,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
private static final int FLOATING_IME_BOTTOM_INSET = -80;
protected final IWindowManager mWmService;
protected final Executor mExecutor;
protected final Executor mMainExecutor;
private final TransactionPool mTransactionPool;
private final DisplayController mDisplayController;
private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
@@ -73,10 +75,10 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
public DisplayImeController(IWindowManager wmService, DisplayController displayController,
Executor mainExecutor, TransactionPool transactionPool) {
mExecutor = mainExecutor;
mWmService = wmService;
mTransactionPool = transactionPool;
mDisplayController = displayController;
mMainExecutor = mainExecutor;
mTransactionPool = transactionPool;
}
/** Starts monitor displays changes and set insets controller for each displays. */
@@ -90,11 +92,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
// WM will defer IME inset handling to it in multi-window scenarious.
PerDisplay pd = new PerDisplay(displayId,
mDisplayController.getDisplayLayout(displayId).rotation());
try {
mWmService.setDisplayWindowInsetsController(displayId, pd);
} catch (RemoteException e) {
Slog.w(TAG, "Unable to set insets controller on display " + displayId);
}
pd.register();
mImePerDisplay.put(displayId, pd);
}
@@ -182,9 +180,11 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
/** An implementation of {@link IDisplayWindowInsetsController} for a given display id. */
public class PerDisplay extends IDisplayWindowInsetsController.Stub {
public class PerDisplay {
final int mDisplayId;
final InsetsState mInsetsState = new InsetsState();
protected final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
new DisplayWindowInsetsControllerImpl();
InsetsSourceControl mImeSourceControl = null;
int mAnimationDirection = DIRECTION_NONE;
ValueAnimator mAnimation = null;
@@ -198,10 +198,16 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
mRotation = initialRotation;
}
@BinderThread
@Override
public void insetsChanged(InsetsState insetsState) {
mExecutor.execute(() -> {
public void register() {
try {
mWmService.setDisplayWindowInsetsController(mDisplayId, mInsetsControllerImpl);
} catch (RemoteException e) {
Slog.w(TAG, "Unable to set insets controller on display " + mDisplayId);
}
}
protected void insetsChanged(InsetsState insetsState) {
mMainExecutor.execute(() -> {
if (mInsetsState.equals(insetsState)) {
return;
}
@@ -220,9 +226,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
});
}
@BinderThread
@Override
public void insetsControlChanged(InsetsState insetsState,
@VisibleForTesting
protected void insetsControlChanged(InsetsState insetsState,
InsetsSourceControl[] activeControls) {
insetsChanged(insetsState);
if (activeControls != null) {
@@ -231,7 +236,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
continue;
}
if (activeControl.getType() == InsetsState.ITYPE_IME) {
mExecutor.execute(() -> {
mMainExecutor.execute(() -> {
final Point lastSurfacePosition = mImeSourceControl != null
? mImeSourceControl.getSurfacePosition() : null;
final boolean positionChanged =
@@ -271,30 +276,25 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
@BinderThread
@Override
public void showInsets(int types, boolean fromIme) {
protected void showInsets(int types, boolean fromIme) {
if ((types & WindowInsets.Type.ime()) == 0) {
return;
}
if (DEBUG) Slog.d(TAG, "Got showInsets for ime");
mExecutor.execute(() -> startAnimation(true /* show */, false /* forceRestart */));
mMainExecutor.execute(() -> startAnimation(true /* show */, false /* forceRestart */));
}
@BinderThread
@Override
public void hideInsets(int types, boolean fromIme) {
protected void hideInsets(int types, boolean fromIme) {
if ((types & WindowInsets.Type.ime()) == 0) {
return;
}
if (DEBUG) Slog.d(TAG, "Got hideInsets for ime");
mExecutor.execute(() -> startAnimation(false /* show */, false /* forceRestart */));
mMainExecutor.execute(() -> startAnimation(false /* show */, false /* forceRestart */));
}
@BinderThread
@Override
public void topFocusedWindowChanged(String packageName) {
// no-op
// Do nothing
}
/**
@@ -457,6 +457,47 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
setVisibleDirectly(true /* visible */);
}
}
@VisibleForTesting
@BinderThread
public class DisplayWindowInsetsControllerImpl
extends IDisplayWindowInsetsController.Stub {
@Override
public void topFocusedWindowChanged(String packageName) throws RemoteException {
mMainExecutor.execute(() -> {
PerDisplay.this.topFocusedWindowChanged(packageName);
});
}
@Override
public void insetsChanged(InsetsState insetsState) throws RemoteException {
mMainExecutor.execute(() -> {
PerDisplay.this.insetsChanged(insetsState);
});
}
@Override
public void insetsControlChanged(InsetsState insetsState,
InsetsSourceControl[] activeControls) throws RemoteException {
mMainExecutor.execute(() -> {
PerDisplay.this.insetsControlChanged(insetsState, activeControls);
});
}
@Override
public void showInsets(int types, boolean fromIme) throws RemoteException {
mMainExecutor.execute(() -> {
PerDisplay.this.showInsets(types, fromIme);
});
}
@Override
public void hideInsets(int types, boolean fromIme) throws RemoteException {
mMainExecutor.execute(() -> {
PerDisplay.this.hideInsets(types, fromIme);
});
}
}
}
void removeImeSurface() {

View File

@@ -50,6 +50,16 @@ public interface ShellExecutor extends Executor {
latch.await(waitTimeout, waitTimeUnit);
}
/**
* Convenience method to execute the blocking call with a default timeout.
*
* @throws InterruptedException if runnable does not return in the time specified by
* {@param waitTimeout}
*/
default void executeBlocking(Runnable runnable) throws InterruptedException {
executeBlocking(runnable, 2, TimeUnit.SECONDS);
}
/**
* See {@link android.os.Handler#postDelayed(Runnable, long)}.
*/

View File

@@ -16,16 +16,14 @@
package com.android.wm.shell.common;
import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.os.Handler;
import android.util.Slog;
import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
import androidx.annotation.BinderThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import java.util.ArrayList;
@@ -41,7 +39,7 @@ public final class SyncTransactionQueue {
private static final int REPLY_TIMEOUT = 5300;
private final TransactionPool mTransactionPool;
private final Handler mHandler;
private final ShellExecutor mMainExecutor;
// Sync Transactions currently don't support nesting or interleaving properly, so
// queue up transactions to run them serially.
@@ -59,9 +57,9 @@ public final class SyncTransactionQueue {
}
};
public SyncTransactionQueue(TransactionPool pool, Handler handler) {
public SyncTransactionQueue(TransactionPool pool, ShellExecutor mainExecutor) {
mTransactionPool = pool;
mHandler = handler;
mMainExecutor = mainExecutor;
}
/**
@@ -152,14 +150,14 @@ public final class SyncTransactionQueue {
if (DEBUG) Slog.d(TAG, "Sending sync transaction: " + mWCT);
mId = new WindowOrganizer().applySyncTransaction(mWCT, this);
if (DEBUG) Slog.d(TAG, " Sent sync transaction. Got id=" + mId);
mHandler.postDelayed(mOnReplyTimeout, REPLY_TIMEOUT);
mMainExecutor.executeDelayed(mOnReplyTimeout, REPLY_TIMEOUT);
}
@BinderThread
@Override
public void onTransactionReady(int id,
@NonNull SurfaceControl.Transaction t) {
mHandler.post(() -> {
mMainExecutor.execute(() -> {
synchronized (mQueue) {
if (mId != id) {
Slog.e(TAG, "Got an unexpected onTransactionReady. Expected "
@@ -167,7 +165,7 @@ public final class SyncTransactionQueue {
return;
}
mInFlight = null;
mHandler.removeCallbacks(mOnReplyTimeout);
mMainExecutor.removeCallbacks(mOnReplyTimeout);
if (DEBUG) Slog.d(TAG, "onTransactionReady id=" + mId);
mQueue.remove(this);
onTransactionReceived(t);

View File

@@ -71,11 +71,11 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
private final IActivityTaskManager mActivityTaskManager;
// NOTE: In this case we do want to use a handler since we rely on the message system to
// efficiently dedupe sequential calls
private Handler mHandler;
private Handler mMainHandler;
public TaskStackListenerImpl(Handler handler) {
public TaskStackListenerImpl(Handler mainHandler) {
mActivityTaskManager = ActivityTaskManager.getService();
mHandler = new Handler(handler.getLooper(), this);
mMainHandler = new Handler(mainHandler.getLooper(), this);
}
@VisibleForTesting
@@ -84,8 +84,8 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
}
@VisibleForTesting
void setHandler(Handler handler) {
mHandler = handler;
void setHandler(Handler mainHandler) {
mMainHandler = mainHandler;
}
public void addListener(TaskStackListenerCallback listener) {
@@ -124,13 +124,13 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
@Override
public void onRecentTaskListUpdated() {
mHandler.obtainMessage(ON_TASK_LIST_UPDATED).sendToTarget();
mMainHandler.obtainMessage(ON_TASK_LIST_UPDATED).sendToTarget();
}
@Override
public void onRecentTaskListFrozenChanged(boolean frozen) {
mHandler.obtainMessage(ON_TASK_LIST_FROZEN_UNFROZEN, frozen ? 1 : 0, 0 /* unused */)
.sendToTarget();
mMainHandler.obtainMessage(ON_TASK_LIST_FROZEN_UNFROZEN, frozen ? 1 : 0,
0 /* unused */).sendToTarget();
}
@Override
@@ -147,48 +147,50 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
}
mTmpListeners.clear();
mHandler.removeMessages(ON_TASK_STACK_CHANGED);
mHandler.sendEmptyMessage(ON_TASK_STACK_CHANGED);
mMainHandler.removeMessages(ON_TASK_STACK_CHANGED);
mMainHandler.sendEmptyMessage(ON_TASK_STACK_CHANGED);
}
@Override
public void onTaskProfileLocked(int taskId, int userId) {
mHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
mMainHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
}
@Override
public void onTaskDisplayChanged(int taskId, int newDisplayId) {
mHandler.obtainMessage(ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
mMainHandler.obtainMessage(ON_TASK_DISPLAY_CHANGED, taskId,
newDisplayId).sendToTarget();
}
@Override
public void onTaskCreated(int taskId, ComponentName componentName) {
mHandler.obtainMessage(ON_TASK_CREATED, taskId, 0, componentName).sendToTarget();
mMainHandler.obtainMessage(ON_TASK_CREATED, taskId, 0, componentName).sendToTarget();
}
@Override
public void onTaskRemoved(int taskId) {
mHandler.obtainMessage(ON_TASK_REMOVED, taskId, 0).sendToTarget();
mMainHandler.obtainMessage(ON_TASK_REMOVED, taskId, 0).sendToTarget();
}
@Override
public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
mHandler.obtainMessage(ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
mMainHandler.obtainMessage(ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
}
@Override
public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo) {
mHandler.obtainMessage(ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
mMainHandler.obtainMessage(ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
}
@Override
public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
mHandler.obtainMessage(ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
mMainHandler.obtainMessage(ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot)
.sendToTarget();
}
@Override
public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
mHandler.obtainMessage(ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
mMainHandler.obtainMessage(ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
}
@Override
@@ -198,44 +200,44 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
args.argi1 = userId;
args.argi2 = taskId;
args.argi3 = stackId;
mHandler.removeMessages(ON_ACTIVITY_PINNED);
mHandler.obtainMessage(ON_ACTIVITY_PINNED, args).sendToTarget();
mMainHandler.removeMessages(ON_ACTIVITY_PINNED);
mMainHandler.obtainMessage(ON_ACTIVITY_PINNED, args).sendToTarget();
}
@Override
public void onActivityUnpinned() {
mHandler.removeMessages(ON_ACTIVITY_UNPINNED);
mHandler.sendEmptyMessage(ON_ACTIVITY_UNPINNED);
mMainHandler.removeMessages(ON_ACTIVITY_UNPINNED);
mMainHandler.sendEmptyMessage(ON_ACTIVITY_UNPINNED);
}
@Override
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, boolean homeTaskVisible,
boolean clearedTask, boolean wasVisible) {
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
final SomeArgs args = SomeArgs.obtain();
args.arg1 = task;
args.argi1 = homeTaskVisible ? 1 : 0;
args.argi2 = clearedTask ? 1 : 0;
args.argi3 = wasVisible ? 1 : 0;
mHandler.removeMessages(ON_ACTIVITY_RESTART_ATTEMPT);
mHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
mMainHandler.removeMessages(ON_ACTIVITY_RESTART_ATTEMPT);
mMainHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
}
@Override
public void onActivityForcedResizable(String packageName, int taskId, int reason) {
mHandler.obtainMessage(ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
mMainHandler.obtainMessage(ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
.sendToTarget();
}
@Override
public void onActivityDismissingDockedStack() {
mHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
mMainHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
}
@Override
public void onActivityLaunchOnSecondaryDisplayFailed(
ActivityManager.RunningTaskInfo taskInfo,
int requestedDisplayId) {
mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED,
mMainHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED,
requestedDisplayId,
0 /* unused */,
taskInfo).sendToTarget();
@@ -245,25 +247,25 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
public void onActivityLaunchOnSecondaryDisplayRerouted(
ActivityManager.RunningTaskInfo taskInfo,
int requestedDisplayId) {
mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED,
mMainHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED,
requestedDisplayId, 0 /* unused */, taskInfo).sendToTarget();
}
@Override
public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
mHandler.obtainMessage(ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
mMainHandler.obtainMessage(ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
requestedOrientation).sendToTarget();
}
@Override
public void onActivityRotation(int displayId) {
mHandler.obtainMessage(ON_ACTIVITY_ROTATION, displayId, 0 /* unused */)
mMainHandler.obtainMessage(ON_ACTIVITY_ROTATION, displayId, 0 /* unused */)
.sendToTarget();
}
@Override
public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
mHandler.obtainMessage(ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId,
mMainHandler.obtainMessage(ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId,
0 /* unused */,
activityToken).sendToTarget();
}

View File

@@ -74,11 +74,11 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
public DragAndDropController(Context context, DisplayController displayController) {
mContext = context;
mDisplayController = displayController;
mDisplayController.addDisplayWindowListener(this);
}
public void setSplitScreenController(Optional<LegacySplitScreen> splitscreen) {
public void initialize(Optional<LegacySplitScreen> splitscreen) {
mLegacySplitScreen = splitscreen.orElse(null);
mDisplayController.addDisplayWindowListener(this);
}
@Override

View File

@@ -25,6 +25,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
import java.io.PrintWriter;
import java.util.concurrent.Executor;
@@ -37,12 +38,15 @@ public class HideDisplayCutoutController implements HideDisplayCutout {
private final Context mContext;
private final HideDisplayCutoutOrganizer mOrganizer;
private final ShellExecutor mMainExecutor;
@VisibleForTesting
boolean mEnabled;
HideDisplayCutoutController(Context context, HideDisplayCutoutOrganizer organizer) {
HideDisplayCutoutController(Context context, HideDisplayCutoutOrganizer organizer,
ShellExecutor mainExecutor) {
mContext = context;
mOrganizer = organizer;
mMainExecutor = mainExecutor;
updateStatus();
}
@@ -52,7 +56,7 @@ public class HideDisplayCutoutController implements HideDisplayCutout {
*/
@Nullable
public static HideDisplayCutoutController create(
Context context, DisplayController displayController, Executor executor) {
Context context, DisplayController displayController, ShellExecutor mainExecutor) {
// The SystemProperty is set for devices that support this feature and is used to control
// whether to create the HideDisplayCutout instance.
// It's defined in the device.mk (e.g. device/google/crosshatch/device.mk).
@@ -61,8 +65,8 @@ public class HideDisplayCutoutController implements HideDisplayCutout {
}
HideDisplayCutoutOrganizer organizer =
new HideDisplayCutoutOrganizer(context, displayController, executor);
return new HideDisplayCutoutController(context, organizer);
new HideDisplayCutoutOrganizer(context, displayController, mainExecutor);
return new HideDisplayCutoutController(context, organizer, mainExecutor);
}
@VisibleForTesting

View File

@@ -42,6 +42,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.R;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
import java.io.PrintWriter;
import java.util.List;
@@ -90,8 +91,8 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer {
};
HideDisplayCutoutOrganizer(Context context, DisplayController displayController,
Executor executor) {
super(executor);
ShellExecutor mainExecutor) {
super(mainExecutor);
mContext = context;
mDisplayController = displayController;
}

View File

@@ -24,7 +24,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.Handler;
import android.util.Slog;
import android.view.Choreographer;
import android.view.SurfaceControl;
@@ -33,6 +32,7 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
class DividerImeController implements DisplayImeController.ImePositionProcessor {
@@ -43,7 +43,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
private final LegacySplitScreenTaskListener mSplits;
private final TransactionPool mTransactionPool;
private final Handler mHandler;
private final ShellExecutor mMainExecutor;
private final TaskOrganizer mTaskOrganizer;
/**
@@ -94,10 +94,10 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
private boolean mAdjustedWhileHidden = false;
DividerImeController(LegacySplitScreenTaskListener splits, TransactionPool pool,
Handler handler, TaskOrganizer taskOrganizer) {
ShellExecutor mainExecutor, TaskOrganizer taskOrganizer) {
mSplits = splits;
mTransactionPool = pool;
mHandler = handler;
mMainExecutor = mainExecutor;
mTaskOrganizer = taskOrganizer;
}
@@ -377,7 +377,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
/** Completely aborts/resets adjustment state */
public void pause(int displayId) {
if (DEBUG) Slog.d(TAG, "ime pause posting " + dumpState());
mHandler.post(() -> {
mMainExecutor.execute(() -> {
if (DEBUG) Slog.d(TAG, "ime pause run posted " + dumpState());
if (mPaused) {
return;
@@ -396,7 +396,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
public void resume(int displayId) {
if (DEBUG) Slog.d(TAG, "ime resume posting " + dumpState());
mHandler.post(() -> {
mMainExecutor.execute(() -> {
if (DEBUG) Slog.d(TAG, "ime resume run posted " + dumpState());
if (!mPaused) {
return;

View File

@@ -22,12 +22,12 @@ import static com.android.wm.shell.legacysplitscreen.ForcedResizableInfoActivity
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.UserHandle;
import android.util.ArraySet;
import android.widget.Toast;
import com.android.wm.shell.R;
import com.android.wm.shell.common.ShellExecutor;
import java.util.function.Consumer;
@@ -40,7 +40,7 @@ final class ForcedResizableInfoActivityController implements DividerView.Divider
private static final int TIMEOUT = 1000;
private final Context mContext;
private final Handler mHandler = new Handler();
private final ShellExecutor mMainExecutor;
private final ArraySet<PendingTaskRecord> mPendingTasks = new ArraySet<>();
private final ArraySet<String> mPackagesShownInSession = new ArraySet<>();
private boolean mDividerDragging;
@@ -69,15 +69,17 @@ final class ForcedResizableInfoActivityController implements DividerView.Divider
}
ForcedResizableInfoActivityController(Context context,
LegacySplitScreenController splitScreenController) {
LegacySplitScreenController splitScreenController,
ShellExecutor mainExecutor) {
mContext = context;
mMainExecutor = mainExecutor;
splitScreenController.registerInSplitScreenListener(mDockedStackExistsListener);
}
@Override
public void onDraggingStart() {
mDividerDragging = true;
mHandler.removeCallbacks(mTimeoutRunnable);
mMainExecutor.removeCallbacks(mTimeoutRunnable);
}
@Override
@@ -111,7 +113,7 @@ final class ForcedResizableInfoActivityController implements DividerView.Divider
}
private void showPending() {
mHandler.removeCallbacks(mTimeoutRunnable);
mMainExecutor.removeCallbacks(mTimeoutRunnable);
for (int i = mPendingTasks.size() - 1; i >= 0; i--) {
PendingTaskRecord pendingRecord = mPendingTasks.valueAt(i);
Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class);
@@ -127,8 +129,8 @@ final class ForcedResizableInfoActivityController implements DividerView.Divider
}
private void postTimeout() {
mHandler.removeCallbacks(mTimeoutRunnable);
mHandler.postDelayed(mTimeoutRunnable, TIMEOUT);
mMainExecutor.removeCallbacks(mTimeoutRunnable);
mMainExecutor.executeDelayed(mTimeoutRunnable, TIMEOUT);
}
private boolean debounce(String packageName) {

View File

@@ -30,7 +30,6 @@ import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Slog;
@@ -49,6 +48,7 @@ import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
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.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerCallback;
@@ -80,7 +80,7 @@ public class LegacySplitScreenController implements LegacySplitScreen,
private final DividerImeController mImePositionProcessor;
private final DividerState mDividerState = new DividerState();
private final ForcedResizableInfoActivityController mForcedResizableController;
private final Handler mHandler;
private final ShellExecutor mMainExecutor;
private final LegacySplitScreenTaskListener mSplits;
private final SystemWindows mSystemWindows;
final TransactionPool mTransactionPool;
@@ -112,21 +112,23 @@ public class LegacySplitScreenController implements LegacySplitScreen,
public LegacySplitScreenController(Context context,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController imeController, Handler handler, TransactionPool transactionPool,
DisplayImeController imeController, TransactionPool transactionPool,
ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
TaskStackListenerImpl taskStackListener, Transitions transitions) {
TaskStackListenerImpl taskStackListener, Transitions transitions,
ShellExecutor mainExecutor) {
mContext = context;
mDisplayController = displayController;
mSystemWindows = systemWindows;
mImeController = imeController;
mHandler = handler;
mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
mMainExecutor = mainExecutor;
mForcedResizableController = new ForcedResizableInfoActivityController(context, this,
mainExecutor);
mTransactionPool = transactionPool;
mWindowManagerProxy = new WindowManagerProxy(syncQueue, shellTaskOrganizer);
mTaskOrganizer = shellTaskOrganizer;
mSplits = new LegacySplitScreenTaskListener(this, shellTaskOrganizer, transitions,
syncQueue);
mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler,
mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mMainExecutor,
shellTaskOrganizer);
mRotationController =
(display, fromRotation, toRotation, wct) -> {
@@ -271,11 +273,6 @@ public class LegacySplitScreenController implements LegacySplitScreen,
}
}
/** Posts task to handler dealing with divider. */
void post(Runnable task) {
mHandler.post(task);
}
@Override
public DividerView getDividerView() {
return mView;
@@ -345,7 +342,7 @@ public class LegacySplitScreenController implements LegacySplitScreen,
}
void onTaskVanished() {
mHandler.post(this::removeDivider);
removeDivider();
}
private void updateVisibility(final boolean visible) {
@@ -379,7 +376,7 @@ public class LegacySplitScreenController implements LegacySplitScreen,
@Override
public void setMinimized(final boolean minimized) {
if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
mHandler.post(() -> {
mMainExecutor.execute(() -> {
if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible);
if (!mVisible) {
return;

View File

@@ -204,7 +204,7 @@ class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
return;
}
mSplitScreenController.post(() -> handleTaskInfoChanged(taskInfo));
handleTaskInfoChanged(taskInfo);
}
}

View File

@@ -38,11 +38,11 @@ import java.util.ArrayList;
public class PinnedStackListenerForwarder {
private final IPinnedStackListener mListenerImpl = new PinnedStackListenerImpl();
private final ShellExecutor mShellMainExecutor;
private final ShellExecutor mMainExecutor;
private final ArrayList<PinnedStackListener> mListeners = new ArrayList<>();
public PinnedStackListenerForwarder(ShellExecutor shellMainExecutor) {
mShellMainExecutor = shellMainExecutor;
public PinnedStackListenerForwarder(ShellExecutor mainExecutor) {
mMainExecutor = mainExecutor;
}
/** Adds a listener to receive updates from the WindowManagerService. */
@@ -94,35 +94,35 @@ public class PinnedStackListenerForwarder {
private class PinnedStackListenerImpl extends IPinnedStackListener.Stub {
@Override
public void onMovementBoundsChanged(boolean fromImeAdjustment) {
mShellMainExecutor.execute(() -> {
mMainExecutor.execute(() -> {
PinnedStackListenerForwarder.this.onMovementBoundsChanged(fromImeAdjustment);
});
}
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mShellMainExecutor.execute(() -> {
mMainExecutor.execute(() -> {
PinnedStackListenerForwarder.this.onImeVisibilityChanged(imeVisible, imeHeight);
});
}
@Override
public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
mShellMainExecutor.execute(() -> {
mMainExecutor.execute(() -> {
PinnedStackListenerForwarder.this.onActionsChanged(actions);
});
}
@Override
public void onActivityHidden(ComponentName componentName) {
mShellMainExecutor.execute(() -> {
mMainExecutor.execute(() -> {
PinnedStackListenerForwarder.this.onActivityHidden(componentName);
});
}
@Override
public void onAspectRatioChanged(float aspectRatio) {
mShellMainExecutor.execute(() -> {
mMainExecutor.execute(() -> {
PinnedStackListenerForwarder.this.onAspectRatioChanged(aspectRatio);
});
}

View File

@@ -155,7 +155,7 @@ public class PipTouchHandler {
PipTaskOrganizer pipTaskOrganizer,
FloatingContentCoordinator floatingContentCoordinator,
PipUiEventLogger pipUiEventLogger,
ShellExecutor shellMainExecutor) {
ShellExecutor mainExecutor) {
// Initialize the Pip input consumer
mContext = context;
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -186,7 +186,7 @@ public class PipTouchHandler {
mFloatingContentCoordinator = floatingContentCoordinator;
mConnection = new PipAccessibilityInteractionConnection(mContext, pipBoundsState,
mMotionHelper, pipTaskOrganizer, mPipBoundsAlgorithm.getSnapAlgorithm(),
this::onAccessibilityShowMenu, this::updateMovementBounds, shellMainExecutor);
this::onAccessibilityShowMenu, this::updateMovementBounds, mainExecutor);
mPipUiEventLogger = pipUiEventLogger;

View File

@@ -27,6 +27,8 @@ import android.testing.TestableLooper;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.ShellExecutor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,12 +46,14 @@ public class HideDisplayCutoutControllerTest {
private HideDisplayCutoutController mHideDisplayCutoutController;
@Mock
private HideDisplayCutoutOrganizer mMockDisplayAreaOrganizer;
@Mock
private ShellExecutor mMockMainExecutor;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mHideDisplayCutoutController = new HideDisplayCutoutController(
mContext, mMockDisplayAreaOrganizer);
mContext, mMockDisplayAreaOrganizer, mMockMainExecutor);
}
@Test

View File

@@ -50,6 +50,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
import org.junit.Before;
import org.junit.Test;
@@ -72,6 +73,9 @@ public class HideDisplayCutoutOrganizerTest {
private DisplayController mMockDisplayController;
private HideDisplayCutoutOrganizer mOrganizer;
@Mock
private ShellExecutor mMockMainExecutor;
private DisplayAreaInfo mDisplayAreaInfo;
private SurfaceControl mLeash;
@@ -93,7 +97,7 @@ public class HideDisplayCutoutOrganizerTest {
when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
HideDisplayCutoutOrganizer organizer = new HideDisplayCutoutOrganizer(
mContext, mMockDisplayController, Runnable::run);
mContext, mMockDisplayController, mMockMainExecutor);
mOrganizer = Mockito.spy(organizer);
doNothing().when(mOrganizer).unregisterOrganizer();
doNothing().when(mOrganizer).applyBoundsAndOffsets(any(), any(), any(), any());

View File

@@ -73,7 +73,7 @@ public class PipTouchHandlerTest extends ShellTestCase {
private PipUiEventLogger mPipUiEventLogger;
@Mock
private ShellExecutor mShellMainExecutor;
private ShellExecutor mMainExecutor;
private PipBoundsState mPipBoundsState;
private PipBoundsAlgorithm mPipBoundsAlgorithm;
@@ -98,7 +98,7 @@ public class PipTouchHandlerTest extends ShellTestCase {
mPipSnapAlgorithm = new PipSnapAlgorithm();
mPipTouchHandler = new PipTouchHandler(mContext, mPhonePipMenuController,
mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer,
mFloatingContentCoordinator, mPipUiEventLogger, mShellMainExecutor);
mFloatingContentCoordinator, mPipUiEventLogger, mMainExecutor);
mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
mPipTouchHandler.setPipMotionHelper(mMotionHelper);

View File

@@ -17,24 +17,22 @@
package com.android.systemui.wmshell;
import android.content.Context;
import android.os.Handler;
import android.view.IWindowManager;
import com.android.systemui.dagger.WMSingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.Transitions;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import java.util.concurrent.Executor;
import dagger.Module;
import dagger.Provides;
@@ -47,9 +45,9 @@ public class TvWMShellModule {
@WMSingleton
@Provides
static DisplayImeController provideDisplayImeController(IWindowManager wmService,
DisplayController displayController, @Main Executor mainExecutor,
DisplayController displayController, @ShellMainThread ShellExecutor shellMainExecutor,
TransactionPool transactionPool) {
return new DisplayImeController(wmService, displayController, mainExecutor,
return new DisplayImeController(wmService, displayController, shellMainExecutor,
transactionPool);
}
@@ -57,12 +55,12 @@ public class TvWMShellModule {
@Provides
static LegacySplitScreen provideSplitScreen(Context context,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener,
Transitions transitions) {
DisplayImeController displayImeController, TransactionPool transactionPool,
ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
TaskStackListenerImpl taskStackListener, Transitions transitions,
@ShellMainThread ShellExecutor mainExecutor) {
return new LegacySplitScreenController(context, displayController, systemWindows,
displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue,
taskStackListener, transitions);
displayImeController, transactionPool, shellTaskOrganizer, syncQueue,
taskStackListener, transitions, mainExecutor);
}
}

View File

@@ -36,7 +36,9 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.FullscreenTaskListener;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.ShellCommandHandlerImpl;
import com.android.wm.shell.ShellInit;
import com.android.wm.shell.ShellInitImpl;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.Transitions;
import com.android.wm.shell.WindowManagerShellWrapper;
@@ -158,7 +160,7 @@ public abstract class WMShellBaseModule {
// Choreographer.getSfInstance() which returns a thread-local Choreographer instance
// that uses the SF vsync
handler.setProvider(new SfVsyncFrameCallbackProvider());
}, 1, TimeUnit.SECONDS);
});
return handler;
} catch (InterruptedException e) {
throw new RuntimeException("Failed to initialize SfVsync animation handler in 1s", e);
@@ -173,14 +175,14 @@ public abstract class WMShellBaseModule {
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions) {
return new ShellInit(displayImeController,
@ShellMainThread ShellExecutor shellMainExecutor) {
return ShellInitImpl.create(displayImeController,
dragAndDropController,
shellTaskOrganizer,
legacySplitScreenOptional,
appPairsOptional,
fullscreenTaskListener,
transitions);
shellMainExecutor);
}
/**
@@ -195,9 +197,11 @@ public abstract class WMShellBaseModule {
Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout,
Optional<AppPairs> appPairsOptional) {
return Optional.of(new ShellCommandHandler(shellTaskOrganizer, legacySplitScreenOptional,
pipOptional, oneHandedOptional, hideDisplayCutout, appPairsOptional));
Optional<AppPairs> appPairsOptional,
@ShellMainThread ShellExecutor shellMainExecutor) {
return Optional.of(ShellCommandHandlerImpl.create(shellTaskOrganizer,
legacySplitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout,
appPairsOptional, shellMainExecutor));
}
@WMSingleton
@@ -208,9 +212,9 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static DisplayController provideDisplayController(Context context, @Main Handler handler,
IWindowManager wmService) {
return new DisplayController(context, handler, wmService);
static DisplayController provideDisplayController(Context context,
IWindowManager wmService, @ShellMainThread ShellExecutor shellMainExecutor) {
return new DisplayController(context, wmService, shellMainExecutor);
}
@WMSingleton
@@ -269,9 +273,9 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static SyncTransactionQueue provideSyncTransactionQueue(@Main Handler handler,
TransactionPool pool) {
return new SyncTransactionQueue(pool, handler);
static SyncTransactionQueue provideSyncTransactionQueue(TransactionPool pool,
@ShellMainThread ShellExecutor shellMainExecutor) {
return new SyncTransactionQueue(pool, shellMainExecutor);
}
@WMSingleton
@@ -288,10 +292,12 @@ public abstract class WMShellBaseModule {
return new RootTaskDisplayAreaOrganizer(mainExecutor, context);
}
// We currently dedupe multiple messages, so we use the shell main handler directly
@WMSingleton
@Provides
static TaskStackListenerImpl providerTaskStackListenerImpl(@Main Handler handler) {
return new TaskStackListenerImpl(handler);
static TaskStackListenerImpl providerTaskStackListenerImpl(
@ShellMainThread Handler shellMainHandler) {
return new TaskStackListenerImpl(shellMainHandler);
}
@BindsOptionalOf
@@ -309,11 +315,12 @@ public abstract class WMShellBaseModule {
WindowManagerShellWrapper windowManagerShellWrapper,
LauncherApps launcherApps,
UiEventLogger uiEventLogger,
@Main Handler mainHandler,
ShellTaskOrganizer organizer) {
ShellTaskOrganizer organizer,
@ShellMainThread ShellExecutor shellMainExecutor) {
return Optional.of(BubbleController.create(context, null /* synchronizer */,
floatingContentCoordinator, statusBarService, windowManager,
windowManagerShellWrapper, launcherApps, uiEventLogger, mainHandler, organizer));
windowManagerShellWrapper, launcherApps, uiEventLogger, organizer,
shellMainExecutor));
}
@WMSingleton

View File

@@ -65,9 +65,9 @@ public class WMShellModule {
@WMSingleton
@Provides
static DisplayImeController provideDisplayImeController(IWindowManager wmService,
DisplayController displayController, @Main Executor mainExecutor,
DisplayController displayController, @ShellMainThread ShellExecutor shellMainExecutor,
TransactionPool transactionPool) {
return new DisplayImeController(wmService, displayController, mainExecutor,
return new DisplayImeController(wmService, displayController, shellMainExecutor,
transactionPool);
}
@@ -75,13 +75,13 @@ public class WMShellModule {
@Provides
static LegacySplitScreen provideLegacySplitScreen(Context context,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener,
Transitions transitions) {
DisplayImeController displayImeController, TransactionPool transactionPool,
ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
TaskStackListenerImpl taskStackListener, Transitions transitions,
@ShellMainThread ShellExecutor mainExecutor) {
return new LegacySplitScreenController(context, displayController, systemWindows,
displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue,
taskStackListener, transitions);
displayImeController, transactionPool, shellTaskOrganizer, syncQueue,
taskStackListener, transitions, mainExecutor);
}
@WMSingleton

View File

@@ -100,6 +100,7 @@ import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.google.common.collect.ImmutableList;
@@ -278,9 +279,9 @@ public class BubblesTest extends SysuiTestCase {
mWindowManagerShellWrapper,
mLauncherApps,
mBubbleLogger,
mock(Handler.class),
mock(ShellTaskOrganizer.class),
mPositioner);
mPositioner,
mock(ShellExecutor.class));
mBubbleController.setExpandListener(mBubbleExpandListener);
mBubblesManager = new BubblesManager(

View File

@@ -93,6 +93,7 @@ import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import org.junit.Before;
import org.junit.Ignore;
@@ -246,9 +247,9 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mWindowManagerShellWrapper,
mLauncherApps,
mBubbleLogger,
mock(Handler.class),
mock(ShellTaskOrganizer.class),
mPositioner);
mPositioner,
mock(ShellExecutor.class));
mBubbleController.setExpandListener(mBubbleExpandListener);
mBubblesManager = new BubblesManager(

View File

@@ -30,6 +30,7 @@ import com.android.wm.shell.bubbles.BubbleDataRepository;
import com.android.wm.shell.bubbles.BubbleLogger;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
/**
* Testable BubbleController subclass that immediately synchronizes surfaces.
@@ -46,12 +47,12 @@ public class TestableBubbleController extends BubbleController {
WindowManagerShellWrapper windowManagerShellWrapper,
LauncherApps launcherApps,
BubbleLogger bubbleLogger,
Handler mainHandler,
ShellTaskOrganizer shellTaskOrganizer,
BubblePositioner positioner) {
BubblePositioner positioner,
ShellExecutor shellMainExecutor) {
super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
bubbleLogger, mainHandler, shellTaskOrganizer, positioner);
bubbleLogger, shellTaskOrganizer, positioner, shellMainExecutor);
setInflateSynchronously(true);
}
}