Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb94ac8b authored by Jerry Chang's avatar Jerry Chang
Browse files

Update smallestScreenWidthDp when split bounds resized

Update smallestScreenWidthDp of the splitting tasks, so client apps can
determine which resources they should apply.

Fix: 217600744
Fix: 220069817
Test: atest WMShellUnitTests
Test: manual check smallestScreenWidthDp of splitting apps in winscope

Change-Id: Ie36065a951dfab2d4bb8d7a56dbc12ae03ff4033
parent 038fd80c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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.
+4 −6
Original line number Diff line number Diff line
@@ -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 */);
        wct.reorder(rootToken, true /* onTop */);
        if (includingTopTask) {
            wct.reparentTasks(
                    null /* currentParent */,
+10 −9
Original line number Diff line number Diff line
@@ -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 -> {
+4 −8
Original line number Diff line number Diff line
@@ -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) {
+14 −0
Original line number Diff line number Diff line
@@ -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<Runnable> 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();
Loading