diff options
5 files changed, 108 insertions, 32 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 823979b861b4..c821b81be265 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -29,7 +29,6 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ParceledListSlice; import android.graphics.Rect; -import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -45,6 +44,7 @@ import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipBoundsHandler; @@ -61,7 +61,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac private static final String TAG = "PipController"; private Context mContext; - private Handler mHandler = new Handler(); + private ShellExecutor mMainExecutor; private final DisplayInfo mTmpDisplayInfo = new DisplayInfo(); private final Rect mTmpInsetBounds = new Rect(); @@ -81,6 +81,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac protected PipMenuActivityController mMenuController; protected PipTaskOrganizer mPipTaskOrganizer; + protected PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener = + new PipControllerPinnedStackListener(); /** * Handler for display rotation changes. @@ -149,12 +151,12 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac PinnedStackListenerForwarder.PinnedStackListener { @Override public void onListenerRegistered(IPinnedStackController controller) { - mHandler.post(() -> mTouchHandler.setPinnedStackController(controller)); + mMainExecutor.execute(() -> mTouchHandler.setPinnedStackController(controller)); } @Override public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight); mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight); }); @@ -162,19 +164,19 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onMovementBoundsChanged(boolean fromImeAdjustment) { - mHandler.post(() -> updateMovementBounds(null /* toBounds */, + mMainExecutor.execute(() -> updateMovementBounds(null /* toBounds */, false /* fromRotation */, fromImeAdjustment, false /* fromShelfAdjustment */, null /* windowContainerTransaction */)); } @Override public void onActionsChanged(ParceledListSlice<RemoteAction> actions) { - mHandler.post(() -> mMenuController.setAppActions(actions)); + mMainExecutor.execute(() -> mMenuController.setAppActions(actions)); } @Override public void onActivityHidden(ComponentName componentName) { - mHandler.post(() -> { + mMainExecutor.execute(() -> { if (componentName.equals(mPipBoundsState.getLastPipComponentName())) { // The activity was removed, we don't want to restore to the reentry state // saved for this component anymore. @@ -185,12 +187,12 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onDisplayInfoChanged(DisplayInfo displayInfo) { - mHandler.post(() -> mPipBoundsState.setDisplayInfo(displayInfo)); + mMainExecutor.execute(() -> mPipBoundsState.setDisplayInfo(displayInfo)); } @Override public void onConfigurationChanged() { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mPipBoundsHandler.onConfigurationChanged(mContext); mTouchHandler.onConfigurationChanged(); }); @@ -200,7 +202,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac public void onAspectRatioChanged(float aspectRatio) { // TODO(b/169373982): Remove this callback as it is redundant with PipTaskOrg params // change. - mHandler.post(() -> { + mMainExecutor.execute(() -> { mPipBoundsState.setAspectRatio(aspectRatio); mTouchHandler.onAspectRatioChanged(); }); @@ -216,7 +218,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer, PipTouchHandler pipTouchHandler, - WindowManagerShellWrapper windowManagerShellWrapper + WindowManagerShellWrapper windowManagerShellWrapper, + ShellExecutor mainExecutor ) { // Ensure that we are the primary user's SystemUI. final int processUser = UserManager.get(context).getUserHandle(); @@ -230,6 +233,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mPipBoundsHandler = pipBoundsHandler; mPipBoundsState = pipBoundsState; mPipTaskOrganizer = pipTaskOrganizer; + mMainExecutor = mainExecutor; mPipTaskOrganizer.registerPipTransitionCallback(this); mPipTaskOrganizer.registerOnDisplayIdChangeCallback((int displayId) -> { final DisplayInfo newDisplayInfo = new DisplayInfo(); @@ -253,8 +257,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mPipBoundsState.setDisplayInfo(displayInfo); try { - mWindowManagerShellWrapper.addPinnedStackListener( - new PipControllerPinnedStackListener()); + mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener); } catch (RemoteException e) { Slog.e(TAG, "Failed to register pinned stack listener", e); } @@ -262,14 +265,14 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onDensityOrFontScaleChanged() { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext); }); } @Override public void onActivityPinned(String packageName) { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mTouchHandler.onActivityPinned(); mMediaController.onActivityPinned(); mMenuController.onActivityPinned(); @@ -279,7 +282,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onActivityUnpinned(ComponentName topActivity) { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mMenuController.onActivityUnpinned(); mTouchHandler.onActivityUnpinned(topActivity); mAppOpsListener.onActivityUnpinned(); @@ -298,7 +301,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onOverlayChanged() { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mPipBoundsState.setDisplayLayout(new DisplayLayout(mContext, mContext.getDisplay())); updateMovementBounds(null /* toBounds */, false /* fromRotation */, false /* fromImeAdjustment */, @@ -357,7 +360,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac */ @Override public void setShelfHeight(boolean visible, int height) { - mHandler.post(() -> setShelfHeightLocked(visible, height)); + mMainExecutor.execute(() -> setShelfHeightLocked(visible, height)); } private void setShelfHeightLocked(boolean visible, int height) { @@ -373,12 +376,12 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void setPinnedStackAnimationType(int animationType) { - mHandler.post(() -> mPipTaskOrganizer.setOneShotAnimationType(animationType)); + mMainExecutor.execute(() -> mPipTaskOrganizer.setOneShotAnimationType(animationType)); } @Override public void setPinnedStackAnimationListener(Consumer<Boolean> callback) { - mHandler.post(() -> mPinnedStackAnimationRecentsCallback = callback); + mMainExecutor.execute(() -> mPinnedStackAnimationRecentsCallback = callback); } @Override @@ -475,7 +478,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac PipBoundsState pipBoundsState, PipMediaController pipMediaController, PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer, PipTouchHandler pipTouchHandler, - WindowManagerShellWrapper windowManagerShellWrapper) { + WindowManagerShellWrapper windowManagerShellWrapper, + ShellExecutor mainExecutor) { if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { Slog.w(TAG, "Device doesn't support Pip feature"); return null; @@ -483,6 +487,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac return new PipController(context, displayController, pipAppOpsListener, pipBoundsHandler, pipBoundsState, pipMediaController, pipMenuActivityController, - pipTaskOrganizer, pipTouchHandler, windowManagerShellWrapper); + pipTaskOrganizer, pipTouchHandler, windowManagerShellWrapper, mainExecutor); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java index 39a96a291c86..1d10a84c53b9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java @@ -69,11 +69,13 @@ public class PipTaskOrganizerTest extends PipTestCase { private PipBoundsState mPipBoundsState; private ComponentName mComponent1; + private ComponentName mComponent2; @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); mComponent1 = new ComponentName(mContext, "component1"); + mComponent2 = new ComponentName(mContext, "component2"); mPipBoundsState = new PipBoundsState(); mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mPipBoundsState, mMockPipBoundsHandler, mMockPipSurfaceTransactionHelper, mMockOptionalSplitScreen, @@ -101,29 +103,57 @@ public class PipTaskOrganizerTest extends PipTestCase { } @Test + public void startSwipePipToHome_updatesLastPipComponentName() { + mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, null, null); + + assertEquals(mComponent1, mPipBoundsState.getLastPipComponentName()); + } + + @Test public void onTaskAppeared_updatesAspectRatio() { final Rational aspectRatio = new Rational(2, 1); - mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo( + mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1, createPipParams(aspectRatio)), null /* leash */); assertEquals(aspectRatio.floatValue(), mPipBoundsState.getAspectRatio(), 0.01f); } @Test + public void onTaskAppeared_updatesLastPipComponentName() { + mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1, createPipParams(null)), + null /* leash */); + + assertEquals(mComponent1, mPipBoundsState.getLastPipComponentName()); + } + + @Test public void onTaskInfoChanged_updatesAspectRatioIfChanged() { final Rational startAspectRatio = new Rational(2, 1); final Rational newAspectRatio = new Rational(1, 2); - mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo( + mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1, createPipParams(startAspectRatio)), null /* leash */); - mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(createPipParams(newAspectRatio))); + mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent1, + createPipParams(newAspectRatio))); assertEquals(newAspectRatio.floatValue(), mPipBoundsState.getAspectRatio(), 0.01f); } + @Test + public void onTaskInfoChanged_updatesLastPipComponentName() { + mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1, + createPipParams(null)), null /* leash */); + + mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent2, + createPipParams(null))); + + assertEquals(mComponent2, mPipBoundsState.getLastPipComponentName()); + } + private void preparePipTaskOrg() { final DisplayInfo info = new DisplayInfo(); + mPipBoundsState.setDisplayInfo(info); when(mMockPipBoundsHandler.getDestinationBounds(any(), any())).thenReturn(new Rect()); when(mMockPipBoundsHandler.getDestinationBounds(any(), any(), anyBoolean())) .thenReturn(new Rect()); @@ -133,10 +163,12 @@ public class PipTaskOrganizerTest extends PipTestCase { doNothing().when(mSpiedPipTaskOrganizer).scheduleAnimateResizePip(any(), anyInt(), any()); } - private static ActivityManager.RunningTaskInfo createTaskInfo(PictureInPictureParams params) { + private static ActivityManager.RunningTaskInfo createTaskInfo( + ComponentName componentName, PictureInPictureParams params) { final ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); info.token = mock(WindowContainerToken.class); info.pictureInPictureParams = params; + info.topActivity = componentName; return info; } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java index a282a48e8494..1b31d96b138a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java @@ -20,11 +20,14 @@ import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.os.RemoteException; @@ -34,6 +37,7 @@ import android.testing.TestableLooper; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.pip.PipBoundsHandler; import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipTaskOrganizer; @@ -63,6 +67,7 @@ public class PipControllerTest extends PipTestCase { @Mock private PipTouchHandler mMockPipTouchHandler; @Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper; @Mock private PipBoundsState mMockPipBoundsState; + @Mock private ShellExecutor mMockExecutor; @Before public void setUp() throws RemoteException { @@ -70,7 +75,11 @@ public class PipControllerTest extends PipTestCase { mPipController = new PipController(mContext, mMockDisplayController, mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState, mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer, - mMockPipTouchHandler, mMockWindowManagerShellWrapper); + mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockExecutor); + doAnswer(invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + }).when(mMockExecutor).execute(any()); } @Test @@ -98,6 +107,27 @@ public class PipControllerTest extends PipTestCase { assertNull(PipController.create(spyContext, mMockDisplayController, mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState, mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer, - mMockPipTouchHandler, mMockWindowManagerShellWrapper)); + mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockExecutor)); + } + + @Test + public void onActivityHidden_isLastPipComponentName_clearLastPipComponent() { + final ComponentName component1 = new ComponentName(mContext, "component1"); + when(mMockPipBoundsState.getLastPipComponentName()).thenReturn(component1); + + mPipController.mPinnedStackListener.onActivityHidden(component1); + + verify(mMockPipBoundsState).setLastPipComponentName(null); + } + + @Test + public void onActivityHidden_isNotLastPipComponentName_lastPipComponentNotCleared() { + final ComponentName component1 = new ComponentName(mContext, "component1"); + final ComponentName component2 = new ComponentName(mContext, "component2"); + when(mMockPipBoundsState.getLastPipComponentName()).thenReturn(component1); + + mPipController.mPinnedStackListener.onActivityHidden(component2); + + verify(mMockPipBoundsState, never()).setLastPipComponentName(null); } } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index cff1c9d086ea..0761ca1f1dca 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -34,6 +34,7 @@ import com.android.wm.shell.common.AnimationThread; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.HandlerExecutor; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SystemWindows; import com.android.wm.shell.common.TransactionPool; @@ -158,9 +159,9 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static ShellTaskOrganizer provideShellTaskOrganizer(SyncTransactionQueue syncQueue, - @Main Handler handler, TransactionPool transactionPool) { + ShellExecutor mainExecutor, TransactionPool transactionPool) { return new ShellTaskOrganizer(syncQueue, transactionPool, - new HandlerExecutor(handler), AnimationThread.instance().getExecutor()); + mainExecutor, AnimationThread.instance().getExecutor()); } @BindsOptionalOf @@ -175,4 +176,11 @@ public abstract class WMShellBaseModule { DisplayController displayController) { return Optional.ofNullable(OneHandedController.create(context, displayController)); } + + @WMSingleton + @Provides + static ShellExecutor provideMainShellExecutor(@Main Handler handler) { + return new HandlerExecutor(handler); + } + } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index a6fe72850716..4b1dca7cb1c8 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -27,6 +27,7 @@ import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.FloatingContentCoordinator; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SystemWindows; import com.android.wm.shell.common.TransactionPool; @@ -82,11 +83,12 @@ public class WMShellModule { PipAppOpsListener pipAppOpsListener, PipBoundsHandler pipBoundsHandler, PipBoundsState pipBoundsState, PipMediaController pipMediaController, PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer, - PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper) { + PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper, + ShellExecutor mainExecutor) { return Optional.ofNullable(PipController.create(context, displayController, pipAppOpsListener, pipBoundsHandler, pipBoundsState, pipMediaController, pipMenuActivityController, pipTaskOrganizer, pipTouchHandler, - windowManagerShellWrapper)); + windowManagerShellWrapper, mainExecutor)); } @WMSingleton |