From 813664c88c949c5db20fdef7f20c32770cf78418 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 7 Dec 2020 22:54:02 -0800 Subject: [PATCH 1/2] 4/ Update HideDisplayCutout and AppPairs to use shell main thread Bug: 161979899 Test: atest WMShellUnitTests Change-Id: I369e83cbc85fea80b0db4d58ba8d05d12fbd09e3 --- .../wm/shell/apppairs/AppPairsController.java | 90 ++++++++++++++++--- .../HideDisplayCutoutController.java | 34 +++++-- .../apppairs/TestAppPairsController.java | 9 +- .../systemui/wmshell/WMShellModule.java | 6 +- 4 files changed, 114 insertions(+), 25 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java index f2f09820639a9..e380426b9ca23 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java @@ -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 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"); + } + } + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java index a89100526b8b7..12b8b87f12855 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java @@ -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"); + } + } + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java index be09636289331..e094158e11449 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java @@ -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); } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index 88f6e1ffac0c5..93725ae778b26 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -84,8 +84,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 From cb4810a673f04aba236bd25e7ba92f35719de481 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Thu, 7 Jan 2021 21:45:30 -0800 Subject: [PATCH 2/2] 5/ Update splitscreen to use shell main thread - Remove some usages of handler - Remove separate executor for transaction updates (until it's clear we need to offload them) - Only animations running on the main shell thread are using the animator handlers, so repurpose that to be for the main thread until we need it for things that actually run on the animation thread (for transitions) Bug: 161979899 Test: atest WMShellUnitTests Test: atest SplitScreenTests Change-Id: I0ea9aae2deddafb620f1f41658e8366443bf9aaa --- .../shell/legacysplitscreen/DividerView.java | 19 +- .../ForcedResizableInfoActivity.java | 2 + .../LegacySplitScreenController.java | 209 ++++++++++++++---- .../legacysplitscreen/WindowManagerProxy.java | 48 ++-- .../systemui/wmshell/TvWMShellModule.java | 9 +- .../systemui/wmshell/WMShellBaseModule.java | 10 +- .../systemui/wmshell/WMShellModule.java | 9 +- 7 files changed, 213 insertions(+), 93 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java index c1b6c4fec792b..e13a1dbe22d67 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java @@ -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); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java index abff69c9ecbb6..4fe28e630114c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java @@ -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 { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java index a785cffb3df06..bca6deb451c92 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java @@ -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>> 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 listener) { + void registerInSplitScreenListener(Consumer listener) { listener.accept(isDividerVisible()); synchronized (mDockedStackExistsListeners) { mDockedStackExistsListeners.add(new WeakReference<>(listener)); } } - @Override - public void unregisterInSplitScreenListener(Consumer listener) { + void unregisterInSplitScreenListener(Consumer 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 listener) { + private void registerBoundsChangeListener(BiConsumer 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 listener) { + mMainExecutor.execute(() -> { + LegacySplitScreenController.this.registerInSplitScreenListener(listener); + }); + } + + @Override + public void unregisterInSplitScreenListener(Consumer listener) { + mMainExecutor.execute(() -> { + LegacySplitScreenController.this.unregisterInSplitScreenListener(listener); + }); + } + + @Override + public void registerBoundsChangeListener(BiConsumer 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"); + } + } + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java index ad05e6d3e6c48..0396e1d113987 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java @@ -44,8 +44,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 @@ -63,25 +61,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) { @@ -94,29 +74,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) { diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java index f0ccc6d156610..f23367b4d65b0 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java @@ -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); } } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index bcb4386c2cebb..c940207b6dd40 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -145,18 +145,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 diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index 93725ae778b26..f1be6886b67ea 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -16,6 +16,7 @@ package com.android.systemui.wmshell; +import android.animation.AnimationHandler; import android.content.Context; import android.view.IWindowManager; @@ -32,6 +33,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; @@ -75,10 +77,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