diff options
10 files changed, 327 insertions, 118 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 f2f09820639a..e380426b9ca2 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<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"); + } + } + } } 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 a89100526b8b..12b8b87f1285 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/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java index c1b6c4fec792..e13a1dbe22d6 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 abff69c9ecbb..4fe28e630114 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 a785cffb3df0..bca6deb451c9 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<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"); + } + } + } } 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 a8cd1dd4fbde..94c6f018b6ac 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 @@ -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) { 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 be0963628933..e094158e1144 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/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java index f0ccc6d15661..f23367b4d65b 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 02eb26d19343..a44fcec69e6a 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index 4351c4f0b9ce..ee761691a97d 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; @@ -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 |