Merge changes I0ea9aae2,I369e83cb
* changes: 5/ Update splitscreen to use shell main thread 4/ Update HideDisplayCutout and AppPairs to use shell main thread
This commit is contained in:
@@ -19,41 +19,58 @@ package com.android.wm.shell.apppairs;
|
||||
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
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.ShellExecutor;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Class manages app-pairs multitasking mode and implements the main interface {@link AppPairs}.
|
||||
*/
|
||||
public class AppPairsController implements AppPairs {
|
||||
public class AppPairsController {
|
||||
private static final String TAG = AppPairsController.class.getSimpleName();
|
||||
|
||||
private final ShellTaskOrganizer mTaskOrganizer;
|
||||
private final SyncTransactionQueue mSyncQueue;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final AppPairsImpl mImpl = new AppPairsImpl();
|
||||
|
||||
private AppPairsPool mPairsPool;
|
||||
// Active app-pairs mapped by root task id key.
|
||||
private final SparseArray<AppPair> mActiveAppPairs = new SparseArray<>();
|
||||
private final DisplayController mDisplayController;
|
||||
|
||||
public AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
|
||||
DisplayController displayController) {
|
||||
/**
|
||||
* Creates {@link AppPairs}, returns {@code null} if the feature is not supported.
|
||||
*/
|
||||
@Nullable
|
||||
public static AppPairs create(ShellTaskOrganizer organizer,
|
||||
SyncTransactionQueue syncQueue, DisplayController displayController,
|
||||
ShellExecutor mainExecutor) {
|
||||
return new AppPairsController(organizer, syncQueue, displayController,
|
||||
mainExecutor).mImpl;
|
||||
}
|
||||
|
||||
AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
|
||||
DisplayController displayController, ShellExecutor mainExecutor) {
|
||||
mTaskOrganizer = organizer;
|
||||
mSyncQueue = syncQueue;
|
||||
mDisplayController = displayController;
|
||||
mMainExecutor = mainExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOrganizerRegistered() {
|
||||
void onOrganizerRegistered() {
|
||||
if (mPairsPool == null) {
|
||||
setPairsPool(new AppPairsPool(this));
|
||||
}
|
||||
@@ -64,8 +81,7 @@ public class AppPairsController implements AppPairs {
|
||||
mPairsPool = pool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pair(int taskId1, int taskId2) {
|
||||
boolean pair(int taskId1, int taskId2) {
|
||||
final ActivityManager.RunningTaskInfo task1 = mTaskOrganizer.getRunningTaskInfo(taskId1);
|
||||
final ActivityManager.RunningTaskInfo task2 = mTaskOrganizer.getRunningTaskInfo(taskId2);
|
||||
if (task1 == null || task2 == null) {
|
||||
@@ -74,8 +90,7 @@ public class AppPairsController implements AppPairs {
|
||||
return pair(task1, task2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pair(ActivityManager.RunningTaskInfo task1,
|
||||
boolean pair(ActivityManager.RunningTaskInfo task1,
|
||||
ActivityManager.RunningTaskInfo task2) {
|
||||
return pairInner(task1, task2) != null;
|
||||
}
|
||||
@@ -94,8 +109,7 @@ public class AppPairsController implements AppPairs {
|
||||
return pair;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpair(int taskId) {
|
||||
void unpair(int taskId) {
|
||||
unpair(taskId, true /* releaseToPool */);
|
||||
}
|
||||
|
||||
@@ -135,8 +149,7 @@ public class AppPairsController implements AppPairs {
|
||||
return mDisplayController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull PrintWriter pw, String prefix) {
|
||||
private void dump(@NonNull PrintWriter pw, String prefix) {
|
||||
final String innerPrefix = prefix + " ";
|
||||
final String childPrefix = innerPrefix + " ";
|
||||
pw.println(prefix + this);
|
||||
@@ -155,4 +168,55 @@ public class AppPairsController implements AppPairs {
|
||||
return TAG + "#" + mActiveAppPairs.size();
|
||||
}
|
||||
|
||||
private class AppPairsImpl implements AppPairs {
|
||||
@Override
|
||||
public boolean pair(int task1, int task2) {
|
||||
boolean[] result = new boolean[1];
|
||||
try {
|
||||
mMainExecutor.executeBlocking(() -> {
|
||||
result[0] = AppPairsController.this.pair(task1, task2);
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
Slog.e(TAG, "Failed to pair tasks: " + task1 + ", " + task2);
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pair(ActivityManager.RunningTaskInfo task1,
|
||||
ActivityManager.RunningTaskInfo task2) {
|
||||
boolean[] result = new boolean[1];
|
||||
try {
|
||||
mMainExecutor.executeBlocking(() -> {
|
||||
result[0] = AppPairsController.this.pair(task1, task2);
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
Slog.e(TAG, "Failed to pair tasks: " + task1 + ", " + task2);
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpair(int taskId) {
|
||||
mMainExecutor.execute(() -> {
|
||||
AppPairsController.this.unpair(taskId);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOrganizerRegistered() {
|
||||
mMainExecutor.execute(() -> {
|
||||
AppPairsController.this.onOrganizerRegistered();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull PrintWriter pw, String prefix) {
|
||||
try {
|
||||
mMainExecutor.executeBlocking(() -> AppPairsController.this.dump(pw, prefix));
|
||||
} catch (InterruptedException e) {
|
||||
Slog.e(TAG, "Failed to dump AppPairsController in 2s");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.wm.shell.hidedisplaycutout;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Slog;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -28,17 +29,18 @@ import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Manages the hide display cutout status.
|
||||
*/
|
||||
public class HideDisplayCutoutController implements HideDisplayCutout {
|
||||
public class HideDisplayCutoutController {
|
||||
private static final String TAG = "HideDisplayCutoutController";
|
||||
|
||||
private final Context mContext;
|
||||
private final HideDisplayCutoutOrganizer mOrganizer;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final HideDisplayCutoutImpl mImpl = new HideDisplayCutoutImpl();
|
||||
@VisibleForTesting
|
||||
boolean mEnabled;
|
||||
|
||||
@@ -55,7 +57,7 @@ public class HideDisplayCutoutController implements HideDisplayCutout {
|
||||
* supported.
|
||||
*/
|
||||
@Nullable
|
||||
public static HideDisplayCutoutController create(
|
||||
public static HideDisplayCutout create(
|
||||
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.
|
||||
@@ -66,7 +68,7 @@ public class HideDisplayCutoutController implements HideDisplayCutout {
|
||||
|
||||
HideDisplayCutoutOrganizer organizer =
|
||||
new HideDisplayCutoutOrganizer(context, displayController, mainExecutor);
|
||||
return new HideDisplayCutoutController(context, organizer, mainExecutor);
|
||||
return new HideDisplayCutoutController(context, organizer, mainExecutor).mImpl;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -88,13 +90,11 @@ public class HideDisplayCutoutController implements HideDisplayCutout {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
private void onConfigurationChanged(Configuration newConfig) {
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull PrintWriter pw) {
|
||||
private void dump(@NonNull PrintWriter pw) {
|
||||
final String prefix = " ";
|
||||
pw.print(TAG);
|
||||
pw.println(" states: ");
|
||||
@@ -103,4 +103,22 @@ public class HideDisplayCutoutController implements HideDisplayCutout {
|
||||
pw.println(mEnabled);
|
||||
mOrganizer.dump(pw);
|
||||
}
|
||||
|
||||
private class HideDisplayCutoutImpl implements HideDisplayCutout {
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
mMainExecutor.execute(() -> {
|
||||
HideDisplayCutoutController.this.onConfigurationChanged(newConfig);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull PrintWriter pw) {
|
||||
try {
|
||||
mMainExecutor.executeBlocking(() -> HideDisplayCutoutController.this.dump(pw));
|
||||
} catch (InterruptedException e) {
|
||||
Slog.e(TAG, "Failed to dump HideDisplayCutoutController in 2s");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import android.graphics.Region;
|
||||
import android.graphics.Region.Op;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Slog;
|
||||
@@ -60,7 +59,6 @@ import android.view.animation.Interpolator;
|
||||
import android.view.animation.PathInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.policy.DividerSnapAlgorithm;
|
||||
@@ -146,8 +144,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
private LegacySplitDisplayLayout mSplitLayout;
|
||||
private DividerImeController mImeController;
|
||||
private DividerCallbacks mCallback;
|
||||
private final AnimationHandler mAnimationHandler = new AnimationHandler();
|
||||
|
||||
private AnimationHandler mSfVsyncAnimationHandler;
|
||||
private ValueAnimator mCurrentAnimator;
|
||||
private boolean mEntranceAnimationRunning;
|
||||
private boolean mExitAnimationRunning;
|
||||
@@ -172,8 +170,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
// used interact with keyguard.
|
||||
private boolean mSurfaceHidden = false;
|
||||
|
||||
private final Handler mHandler = new Handler();
|
||||
|
||||
private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
|
||||
@@ -284,7 +280,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
final DisplayManager displayManager =
|
||||
(DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
|
||||
mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
|
||||
mAnimationHandler.setProvider(new SfVsyncFrameCallbackProvider());
|
||||
}
|
||||
|
||||
public void setAnimationHandler(AnimationHandler sfVsyncAnimationHandler) {
|
||||
mSfVsyncAnimationHandler = sfVsyncAnimationHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -669,12 +668,12 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
} else {
|
||||
final Boolean cancelled = mCancelled;
|
||||
if (DEBUG) Slog.d(TAG, "Posting endFling " + cancelled + " d:" + delay + "ms");
|
||||
mHandler.postDelayed(() -> endAction.accept(cancelled), delay);
|
||||
getHandler().postDelayed(() -> endAction.accept(cancelled), delay);
|
||||
}
|
||||
}
|
||||
});
|
||||
anim.setAnimationHandler(mAnimationHandler);
|
||||
mCurrentAnimator = anim;
|
||||
mCurrentAnimator.setAnimationHandler(mSfVsyncAnimationHandler);
|
||||
return anim;
|
||||
}
|
||||
|
||||
@@ -1061,8 +1060,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
}
|
||||
}
|
||||
if (getViewRootImpl() != null) {
|
||||
mHandler.removeCallbacks(mUpdateEmbeddedMatrix);
|
||||
mHandler.post(mUpdateEmbeddedMatrix);
|
||||
getHandler().removeCallbacks(mUpdateEmbeddedMatrix);
|
||||
getHandler().post(mUpdateEmbeddedMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ import com.android.wm.shell.R;
|
||||
/**
|
||||
* Translucent activity that gets started on top of a task in multi-window to inform the user that
|
||||
* we forced the activity below to be resizable.
|
||||
*
|
||||
* Note: This activity runs on the main thread of the process hosting the Shell lib.
|
||||
*/
|
||||
public class ForcedResizableInfoActivity extends Activity implements OnTouchListener {
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
|
||||
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import android.animation.AnimationHandler;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.app.ActivityTaskManager;
|
||||
@@ -40,6 +41,8 @@ import android.window.TaskOrganizer;
|
||||
import android.window.WindowContainerToken;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.policy.DividerSnapAlgorithm;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
@@ -60,14 +63,14 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Controls split screen feature.
|
||||
*/
|
||||
public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
DisplayController.OnDisplaysChangedListener {
|
||||
public class LegacySplitScreenController implements DisplayController.OnDisplaysChangedListener {
|
||||
static final boolean DEBUG = false;
|
||||
|
||||
private static final String TAG = "SplitScreenCtrl";
|
||||
@@ -81,11 +84,13 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
private final DividerState mDividerState = new DividerState();
|
||||
private final ForcedResizableInfoActivityController mForcedResizableController;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final AnimationHandler mSfVsyncAnimationHandler;
|
||||
private final LegacySplitScreenTaskListener mSplits;
|
||||
private final SystemWindows mSystemWindows;
|
||||
final TransactionPool mTransactionPool;
|
||||
private final WindowManagerProxy mWindowManagerProxy;
|
||||
private final TaskOrganizer mTaskOrganizer;
|
||||
private final SplitScreenImpl mImpl = new SplitScreenImpl();
|
||||
|
||||
private final CopyOnWriteArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners
|
||||
= new CopyOnWriteArrayList<>();
|
||||
@@ -106,21 +111,37 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
|
||||
private boolean mIsKeyguardShowing;
|
||||
private boolean mVisible = false;
|
||||
private boolean mMinimized = false;
|
||||
private boolean mAdjustedForIme = false;
|
||||
private volatile boolean mMinimized = false;
|
||||
private volatile boolean mAdjustedForIme = false;
|
||||
private boolean mHomeStackResizable = false;
|
||||
|
||||
/**
|
||||
* Creates {@link SplitScreen}, returns {@code null} if the feature is not supported.
|
||||
*/
|
||||
@Nullable
|
||||
public static LegacySplitScreen create(Context context,
|
||||
DisplayController displayController, SystemWindows systemWindows,
|
||||
DisplayImeController imeController, TransactionPool transactionPool,
|
||||
ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
|
||||
TaskStackListenerImpl taskStackListener, Transitions transitions,
|
||||
ShellExecutor mainExecutor, AnimationHandler sfVsyncAnimationHandler) {
|
||||
return new LegacySplitScreenController(context, displayController, systemWindows,
|
||||
imeController, transactionPool, shellTaskOrganizer, syncQueue, taskStackListener,
|
||||
transitions, mainExecutor, sfVsyncAnimationHandler).mImpl;
|
||||
}
|
||||
|
||||
public LegacySplitScreenController(Context context,
|
||||
DisplayController displayController, SystemWindows systemWindows,
|
||||
DisplayImeController imeController, TransactionPool transactionPool,
|
||||
ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
|
||||
TaskStackListenerImpl taskStackListener, Transitions transitions,
|
||||
ShellExecutor mainExecutor) {
|
||||
ShellExecutor mainExecutor, AnimationHandler sfVsyncAnimationHandler) {
|
||||
mContext = context;
|
||||
mDisplayController = displayController;
|
||||
mSystemWindows = systemWindows;
|
||||
mImeController = imeController;
|
||||
mMainExecutor = mainExecutor;
|
||||
mSfVsyncAnimationHandler = sfVsyncAnimationHandler;
|
||||
mForcedResizableController = new ForcedResizableInfoActivityController(context, this,
|
||||
mainExecutor);
|
||||
mTransactionPool = transactionPool;
|
||||
@@ -216,8 +237,7 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
mTaskOrganizer.applyTransaction(tct);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyguardVisibilityChanged(boolean showing) {
|
||||
private void onKeyguardVisibilityChanged(boolean showing) {
|
||||
if (!isSplitActive() || mView == null) {
|
||||
return;
|
||||
}
|
||||
@@ -273,23 +293,19 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DividerView getDividerView() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMinimized() {
|
||||
boolean isMinimized() {
|
||||
return mMinimized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHomeStackResizable() {
|
||||
boolean isHomeStackResizable() {
|
||||
return mHomeStackResizable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDividerVisible() {
|
||||
DividerView getDividerView() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
boolean isDividerVisible() {
|
||||
return mView != null && mView.getVisibility() == View.VISIBLE;
|
||||
}
|
||||
|
||||
@@ -308,6 +324,7 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId());
|
||||
mView = (DividerView)
|
||||
LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
|
||||
mView.setAnimationHandler(mSfVsyncAnimationHandler);
|
||||
DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
|
||||
mView.injectDependencies(this, mWindowManager, mDividerState, mForcedResizableController,
|
||||
mSplits, mSplitLayout, mImePositionProcessor, mWindowManagerProxy);
|
||||
@@ -373,8 +390,7 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinimized(final boolean minimized) {
|
||||
private void setMinimized(final boolean minimized) {
|
||||
if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
|
||||
mMainExecutor.execute(() -> {
|
||||
if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible);
|
||||
@@ -437,23 +453,20 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
mWindowManager.setTouchable(!mAdjustedForIme);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUndockingTask() {
|
||||
private void onUndockingTask() {
|
||||
if (mView != null) {
|
||||
mView.onUndockingTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppTransitionFinished() {
|
||||
private void onAppTransitionFinished() {
|
||||
if (mView == null) {
|
||||
return;
|
||||
}
|
||||
mForcedResizableController.onAppTransitionFinished();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw) {
|
||||
private void dump(PrintWriter pw) {
|
||||
pw.print(" mVisible="); pw.println(mVisible);
|
||||
pw.print(" mMinimized="); pw.println(mMinimized);
|
||||
pw.print(" mAdjustedForIme="); pw.println(mAdjustedForIme);
|
||||
@@ -469,16 +482,14 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
return (long) (transitionDuration * transitionScale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerInSplitScreenListener(Consumer<Boolean> listener) {
|
||||
void registerInSplitScreenListener(Consumer<Boolean> listener) {
|
||||
listener.accept(isDividerVisible());
|
||||
synchronized (mDockedStackExistsListeners) {
|
||||
mDockedStackExistsListeners.add(new WeakReference<>(listener));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterInSplitScreenListener(Consumer<Boolean> listener) {
|
||||
void unregisterInSplitScreenListener(Consumer<Boolean> listener) {
|
||||
synchronized (mDockedStackExistsListeners) {
|
||||
for (int i = mDockedStackExistsListeners.size() - 1; i >= 0; i--) {
|
||||
if (mDockedStackExistsListeners.get(i) == listener) {
|
||||
@@ -488,15 +499,13 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
|
||||
private void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
|
||||
synchronized (mBoundsChangedListeners) {
|
||||
mBoundsChangedListeners.add(new WeakReference<>(listener));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean splitPrimaryTask() {
|
||||
private boolean splitPrimaryTask() {
|
||||
try {
|
||||
if (ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED
|
||||
|| isSplitActive()) {
|
||||
@@ -529,8 +538,7 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
topRunningTask.taskId, true /* onTop */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismissSplitToPrimaryTask() {
|
||||
private void dismissSplitToPrimaryTask() {
|
||||
startDismissSplit(true /* toPrimaryTask */);
|
||||
}
|
||||
|
||||
@@ -621,11 +629,136 @@ public class LegacySplitScreenController implements LegacySplitScreen,
|
||||
return mWindowManagerProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowContainerToken getSecondaryRoot() {
|
||||
WindowContainerToken getSecondaryRoot() {
|
||||
if (mSplits == null || mSplits.mSecondary == null) {
|
||||
return null;
|
||||
}
|
||||
return mSplits.mSecondary.token;
|
||||
}
|
||||
|
||||
private class SplitScreenImpl implements LegacySplitScreen {
|
||||
@Override
|
||||
public boolean isMinimized() {
|
||||
return mMinimized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHomeStackResizable() {
|
||||
return mHomeStackResizable;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Remove usage from outside the shell.
|
||||
*/
|
||||
@Override
|
||||
public DividerView getDividerView() {
|
||||
return LegacySplitScreenController.this.getDividerView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDividerVisible() {
|
||||
boolean[] result = new boolean[1];
|
||||
try {
|
||||
mMainExecutor.executeBlocking(() -> {
|
||||
result[0] = LegacySplitScreenController.this.isDividerVisible();
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
Slog.e(TAG, "Failed to get divider visible");
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyguardVisibilityChanged(boolean isShowing) {
|
||||
mMainExecutor.execute(() -> {
|
||||
LegacySplitScreenController.this.onKeyguardVisibilityChanged(isShowing);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinimized(boolean minimized) {
|
||||
mMainExecutor.execute(() -> {
|
||||
LegacySplitScreenController.this.setMinimized(minimized);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUndockingTask() {
|
||||
mMainExecutor.execute(() -> {
|
||||
LegacySplitScreenController.this.onUndockingTask();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppTransitionFinished() {
|
||||
mMainExecutor.execute(() -> {
|
||||
LegacySplitScreenController.this.onAppTransitionFinished();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerInSplitScreenListener(Consumer<Boolean> listener) {
|
||||
mMainExecutor.execute(() -> {
|
||||
LegacySplitScreenController.this.registerInSplitScreenListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterInSplitScreenListener(Consumer<Boolean> listener) {
|
||||
mMainExecutor.execute(() -> {
|
||||
LegacySplitScreenController.this.unregisterInSplitScreenListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
|
||||
mMainExecutor.execute(() -> {
|
||||
LegacySplitScreenController.this.registerBoundsChangeListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowContainerToken getSecondaryRoot() {
|
||||
WindowContainerToken[] result = new WindowContainerToken[1];
|
||||
try {
|
||||
mMainExecutor.executeBlocking(() -> {
|
||||
result[0] = LegacySplitScreenController.this.getSecondaryRoot();
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
Slog.e(TAG, "Failed to get secondary root");
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean splitPrimaryTask() {
|
||||
boolean[] result = new boolean[1];
|
||||
try {
|
||||
mMainExecutor.executeBlocking(() -> {
|
||||
result[0] = LegacySplitScreenController.this.splitPrimaryTask();
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
Slog.e(TAG, "Failed to split primary task");
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismissSplitToPrimaryTask() {
|
||||
mMainExecutor.execute(() -> {
|
||||
LegacySplitScreenController.this.dismissSplitToPrimaryTask();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw) {
|
||||
try {
|
||||
mMainExecutor.executeBlocking(() -> {
|
||||
LegacySplitScreenController.this.dump(pw);
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
Slog.e(TAG, "Failed to dump LegacySplitScreenController in 2s");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,6 @@ import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Proxy to simplify calls into window manager/activity manager
|
||||
@@ -77,25 +75,7 @@ class WindowManagerProxy {
|
||||
@GuardedBy("mDockedRect")
|
||||
private final Rect mTouchableRegion = new Rect();
|
||||
|
||||
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
|
||||
|
||||
private final SyncTransactionQueue mSyncTransactionQueue;
|
||||
|
||||
private final Runnable mSetTouchableRegionRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
synchronized (mDockedRect) {
|
||||
mTmpRect1.set(mTouchableRegion);
|
||||
}
|
||||
WindowManagerGlobal.getWindowManagerService().setDockedStackDividerTouchRegion(
|
||||
mTmpRect1);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to set touchable region: " + e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final TaskOrganizer mTaskOrganizer;
|
||||
|
||||
WindowManagerProxy(SyncTransactionQueue syncQueue, TaskOrganizer taskOrganizer) {
|
||||
@@ -108,29 +88,29 @@ class WindowManagerProxy {
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
tiles.mSplitScreenController.startDismissSplit(!dismissOrMaximize, true /* snapped */);
|
||||
} else {
|
||||
mExecutor.execute(() -> applyDismissSplit(tiles, layout, dismissOrMaximize));
|
||||
applyDismissSplit(tiles, layout, dismissOrMaximize);
|
||||
}
|
||||
}
|
||||
|
||||
public void setResizing(final boolean resizing) {
|
||||
mExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ActivityTaskManager.getService().setSplitScreenResizing(resizing);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Error calling setDockedStackResizing: " + e);
|
||||
}
|
||||
}
|
||||
});
|
||||
try {
|
||||
ActivityTaskManager.getService().setSplitScreenResizing(resizing);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Error calling setDockedStackResizing: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets a touch region */
|
||||
public void setTouchRegion(Rect region) {
|
||||
synchronized (mDockedRect) {
|
||||
mTouchableRegion.set(region);
|
||||
try {
|
||||
synchronized (mDockedRect) {
|
||||
mTouchableRegion.set(region);
|
||||
}
|
||||
WindowManagerGlobal.getWindowManagerService().setDockedStackDividerTouchRegion(
|
||||
mTouchableRegion);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to set touchable region: " + e);
|
||||
}
|
||||
mExecutor.execute(mSetTouchableRegionRunnable);
|
||||
}
|
||||
|
||||
void applyResizeSplits(int position, LegacySplitDisplayLayout splitLayout) {
|
||||
|
||||
@@ -16,16 +16,21 @@
|
||||
|
||||
package com.android.wm.shell.apppairs;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
|
||||
import org.mockito.Mock;
|
||||
|
||||
public class TestAppPairsController extends AppPairsController {
|
||||
TestAppPairsPool mPool;
|
||||
private TestAppPairsPool mPool;
|
||||
|
||||
public TestAppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
|
||||
DisplayController displayController) {
|
||||
super(organizer, syncQueue, displayController);
|
||||
super(organizer, syncQueue, displayController, mock(ShellExecutor.class));
|
||||
mPool = new TestAppPairsPool(this);
|
||||
setPairsPool(mPool);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.wmshell;
|
||||
|
||||
import android.animation.AnimationHandler;
|
||||
import android.content.Context;
|
||||
import android.view.IWindowManager;
|
||||
|
||||
@@ -28,6 +29,7 @@ import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.common.SystemWindows;
|
||||
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
import com.android.wm.shell.common.TransactionPool;
|
||||
import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
||||
@@ -58,9 +60,10 @@ public class TvWMShellModule {
|
||||
DisplayImeController displayImeController, TransactionPool transactionPool,
|
||||
ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
|
||||
TaskStackListenerImpl taskStackListener, Transitions transitions,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
return new LegacySplitScreenController(context, displayController, systemWindows,
|
||||
@ShellMainThread ShellExecutor mainExecutor,
|
||||
@ChoreographerSfVsync AnimationHandler sfVsyncAnimationHandler) {
|
||||
return LegacySplitScreenController.create(context, displayController, systemWindows,
|
||||
displayImeController, transactionPool, shellTaskOrganizer, syncQueue,
|
||||
taskStackListener, transitions, mainExecutor);
|
||||
taskStackListener, transitions, mainExecutor, sfVsyncAnimationHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,18 +146,18 @@ public abstract class WMShellBaseModule {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a Shell animation-thread AnimationHandler. The AnimationHandler can be set on
|
||||
* Provide a Shell main-thread AnimationHandler. The AnimationHandler can be set on
|
||||
* {@link android.animation.ValueAnimator}s and will ensure that the animation will run on
|
||||
* the Shell animation-thread.
|
||||
* the Shell main-thread with the SF vsync.
|
||||
*/
|
||||
@WMSingleton
|
||||
@Provides
|
||||
@ChoreographerSfVsync
|
||||
public static AnimationHandler provideShellAnimationExecutorSfVsyncAnimationHandler(
|
||||
@ShellAnimationThread ShellExecutor shellAnimationExecutor) {
|
||||
public static AnimationHandler provideShellMainExecutorSfVsyncAnimationHandler(
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
try {
|
||||
AnimationHandler handler = new AnimationHandler();
|
||||
shellAnimationExecutor.executeBlocking(() -> {
|
||||
mainExecutor.executeBlocking(() -> {
|
||||
// This is called on the animation thread since it calls
|
||||
// Choreographer.getSfInstance() which returns a thread-local Choreographer instance
|
||||
// that uses the SF vsync
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.wmshell;
|
||||
|
||||
import android.animation.AnimationHandler;
|
||||
import android.content.Context;
|
||||
import android.view.IWindowManager;
|
||||
|
||||
@@ -33,6 +34,7 @@ import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.common.SystemWindows;
|
||||
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
import com.android.wm.shell.common.TransactionPool;
|
||||
import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
||||
@@ -78,10 +80,11 @@ public class WMShellModule {
|
||||
DisplayImeController displayImeController, TransactionPool transactionPool,
|
||||
ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
|
||||
TaskStackListenerImpl taskStackListener, Transitions transitions,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
return new LegacySplitScreenController(context, displayController, systemWindows,
|
||||
@ShellMainThread ShellExecutor mainExecutor,
|
||||
@ChoreographerSfVsync AnimationHandler sfVsyncAnimationHandler) {
|
||||
return LegacySplitScreenController.create(context, displayController, systemWindows,
|
||||
displayImeController, transactionPool, shellTaskOrganizer, syncQueue,
|
||||
taskStackListener, transitions, mainExecutor);
|
||||
taskStackListener, transitions, mainExecutor, sfVsyncAnimationHandler);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@@ -96,8 +99,10 @@ public class WMShellModule {
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static AppPairs provideAppPairs(ShellTaskOrganizer shellTaskOrganizer,
|
||||
SyncTransactionQueue syncQueue, DisplayController displayController) {
|
||||
return new AppPairsController(shellTaskOrganizer, syncQueue, displayController);
|
||||
SyncTransactionQueue syncQueue, DisplayController displayController,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
return AppPairsController.create(shellTaskOrganizer, syncQueue, displayController,
|
||||
mainExecutor);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
|
||||
Reference in New Issue
Block a user