diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index f7c92fed55225..274a29b33be6f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -478,16 +478,24 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange if (!mBounds1.equals(mWinBounds1) || !task1.token.equals(mWinToken1)) { wct.setBounds(task1.token, mBounds1); + wct.setSmallestScreenWidthDp(task1.token, getSmallestWidthDp(mBounds1)); mWinBounds1.set(mBounds1); mWinToken1 = task1.token; } if (!mBounds2.equals(mWinBounds2) || !task2.token.equals(mWinToken2)) { wct.setBounds(task2.token, mBounds2); + wct.setSmallestScreenWidthDp(task2.token, getSmallestWidthDp(mBounds2)); mWinBounds2.set(mBounds2); mWinToken2 = task2.token; } } + private int getSmallestWidthDp(Rect bounds) { + final int minWidth = Math.min(bounds.width(), bounds.height()); + final float density = mContext.getResources().getDisplayMetrics().density; + return (int) (minWidth / density); + } + /** * Shift configuration bounds to prevent client apps get configuration changed or relaunch. And * restore shifted configuration bounds if it's no longer shifted. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java index 082fe9205be8a..22dd9b953be7a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java @@ -18,7 +18,6 @@ package com.android.wm.shell.splitscreen; import android.annotation.Nullable; import android.content.Context; -import android.graphics.Rect; import android.view.SurfaceSession; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; @@ -49,14 +48,13 @@ class MainStage extends StageTaskListener { return mIsActive; } - void activate(Rect rootBounds, WindowContainerTransaction wct, boolean includingTopTask) { + void activate(WindowContainerTransaction wct, boolean includingTopTask) { if (mIsActive) return; final WindowContainerToken rootToken = mRootTaskInfo.token; - wct.setBounds(rootToken, rootBounds) - // Moving the root task to top after the child tasks were re-parented , or the root - // task cannot be visible and focused. - .reorder(rootToken, true /* onTop */); + // Moving the root task to top after the child tasks were re-parented , or the root + // task cannot be visible and focused. + wct.reorder(rootToken, true /* onTop */); if (includingTopTask) { wct.reparentTasks( null /* currentParent */, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 81dacdb753a74..f441d1d14a641 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -354,8 +354,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.setDivideRatio(splitRatio); // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. - mMainStage.activate(getMainStageBounds(), wct, false /* reparent */); - mSideStage.setBounds(getSideStageBounds(), wct); + mMainStage.activate(wct, false /* reparent */); + updateWindowBounds(mSplitLayout, wct); // Make sure the launch options will put tasks in the corresponding split roots addActivityOptions(mainOptions, mMainStage); @@ -470,13 +470,14 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.setDivideRatio(splitRatio); if (mMainStage.isActive()) { - mMainStage.moveToTop(getMainStageBounds(), wct); + mMainStage.moveToTop(wct); } else { // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. - mMainStage.activate(getMainStageBounds(), wct, false /* reparent */); + mMainStage.activate(wct, false /* reparent */); } - mSideStage.moveToTop(getSideStageBounds(), wct); + mSideStage.moveToTop(wct); + updateWindowBounds(mSplitLayout, wct); // Make sure the launch options will put tasks in the corresponding split roots addActivityOptions(mainOptions, mMainStage); @@ -774,8 +775,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, setSideStagePosition(startPosition, wct); mSideStage.addTask(taskInfo, wct); } - mMainStage.activate(getMainStageBounds(), wct, true /* includingTopTask */); - mSideStage.moveToTop(getSideStageBounds(), wct); + mMainStage.activate(wct, true /* includingTopTask */); + mSideStage.moveToTop(wct); + updateWindowBounds(mSplitLayout, wct); } void finishEnterSplitScreen(SurfaceControl.Transaction t) { @@ -996,10 +998,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Exit to side stage if main stage no longer has children. exitSplitScreen(mSideStage, EXIT_REASON_APP_FINISHED); } - } else if (isSideStage) { + } else if (isSideStage && !mMainStage.isActive()) { final WindowContainerTransaction wct = new WindowContainerTransaction(); mSplitLayout.init(); - // Make sure the main stage is active. prepareEnterSplitScreen(wct); mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 83534c1784695..c5aab45f56faf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -53,8 +53,8 @@ import java.io.PrintWriter; * Base class that handle common task org. related for split-screen stages. * Note that this class and its sub-class do not directly perform hierarchy operations. * They only serve to hold a collection of tasks and provide APIs like - * {@link #setBounds(Rect, WindowContainerTransaction)} for the centralized {@link StageCoordinator} - * to perform operations in-sync with other containers. + * {@link #addTask(ActivityManager.RunningTaskInfo, WindowContainerTransaction)} for the centralized + * {@link StageCoordinator} to perform hierarchy operations in-sync with other containers. * * @see StageCoordinator */ @@ -310,13 +310,9 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { wct.reparent(task.token, mRootTaskInfo.token, true /* onTop*/); } - void moveToTop(Rect rootBounds, WindowContainerTransaction wct) { + void moveToTop(WindowContainerTransaction wct) { final WindowContainerToken rootToken = mRootTaskInfo.token; - wct.setBounds(rootToken, rootBounds).reorder(rootToken, true /* onTop */); - } - - void setBounds(Rect bounds, WindowContainerTransaction wct) { - wct.setBounds(mRootTaskInfo.token, bounds); + wct.reorder(rootToken, true /* onTop */); } void reorderChild(int taskId, boolean onTop, WindowContainerTransaction wct) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java index 83d5f04b7cdb9..daec336fc71ee 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java @@ -28,8 +28,10 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import android.app.ActivityManager; import android.content.res.Configuration; import android.graphics.Rect; +import android.window.WindowContainerTransaction; import androidx.test.annotation.UiThreadTest; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -38,6 +40,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.DisplayImeController; import org.junit.Before; @@ -56,6 +59,7 @@ public class SplitLayoutTests extends ShellTestCase { @Mock SplitWindowManager.ParentContainerCallbacks mCallbacks; @Mock DisplayImeController mDisplayImeController; @Mock ShellTaskOrganizer mTaskOrganizer; + @Mock WindowContainerTransaction mWct; @Captor ArgumentCaptor mRunnableCaptor; private SplitLayout mSplitLayout; @@ -149,6 +153,16 @@ public class SplitLayoutTests extends ShellTestCase { verify(mSplitLayoutHandler).onSnappedToDismiss(eq(true)); } + @Test + public void testApplyTaskChanges_updatesSmallestScreenWidthDp() { + final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build(); + final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build(); + mSplitLayout.applyTaskChanges(mWct, task1, task2); + + verify(mWct).setSmallestScreenWidthDp(eq(task1.token), anyInt()); + verify(mWct).setSmallestScreenWidthDp(eq(task2.token), anyInt()); + } + private void waitDividerFlingFinished() { verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), mRunnableCaptor.capture()); mRunnableCaptor.getValue().run(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java index c9720671f49c6..0639ad5d0a62f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java @@ -67,8 +67,7 @@ public class MainStageTests extends ShellTestCase { @Test public void testActiveDeactivate() { - mMainStage.activate(mRootTaskInfo.configuration.windowConfiguration.getBounds(), mWct, - true /* reparent */); + mMainStage.activate(mWct, true /* reparent */); assertThat(mMainStage.isActive()).isTrue(); mMainStage.deactivate(mWct); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java index 59c377a3e13db..19d2a7ef6f452 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java @@ -44,7 +44,6 @@ import static org.mockito.Mockito.mock; import android.annotation.NonNull; import android.app.ActivityManager; -import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; import android.view.SurfaceControl; @@ -421,8 +420,7 @@ public class SplitTransitionTests extends ShellTestCase { mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class), mock(Transitions.TransitionFinishCallback.class)); - mMainStage.activate(new Rect(0, 0, 100, 100), new WindowContainerTransaction(), - true /* includingTopTask */); + mMainStage.activate(new WindowContainerTransaction(), true /* includingTopTask */); } private boolean containsSplitEnter(@NonNull WindowContainerTransaction wct) {