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

Commit 83e0b5ee authored by Ikram Gabiyev's avatar Ikram Gabiyev Committed by Android (Google) Code Review
Browse files

Merge "Update DisplayLayouts upon deferred updates" into main

parents 2b81818d 0c861746
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.wm.shell.common;

import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Slog;
@@ -28,6 +29,7 @@ import android.window.WindowContainerTransaction;

import androidx.annotation.BinderThread;

import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.sysui.ShellInit;

@@ -43,6 +45,7 @@ public class DisplayChangeController {
    private static final String TAG = DisplayChangeController.class.getSimpleName();
    private static final String HANDLE_DISPLAY_CHANGE_TRACE_TAG = "HandleRemoteDisplayChange";

    private final DisplayController mDisplayController;
    private final ShellExecutor mMainExecutor;
    private final IWindowManager mWmService;
    private final IDisplayChangeWindowController mControllerImpl;
@@ -50,8 +53,9 @@ public class DisplayChangeController {
    private final CopyOnWriteArrayList<OnDisplayChangingListener> mDisplayChangeListener =
            new CopyOnWriteArrayList<>();

    public DisplayChangeController(IWindowManager wmService, ShellInit shellInit,
            ShellExecutor mainExecutor) {
    public DisplayChangeController(DisplayController displayController, IWindowManager wmService,
            ShellInit shellInit, ShellExecutor mainExecutor) {
        mDisplayController = displayController;
        mMainExecutor = mainExecutor;
        mWmService = wmService;
        mControllerImpl = new DisplayChangeWindowControllerImpl();
@@ -94,8 +98,21 @@ public class DisplayChangeController {
        }
    }

    private void onDisplayChange(int displayId, int fromRotation, int toRotation,
    @VisibleForTesting
    void onDisplayChange(int displayId, int fromRotation, int toRotation,
            DisplayAreaInfo newDisplayAreaInfo, IDisplayChangeWindowCallback callback) {
        final DisplayLayout dl = mDisplayController.getDisplayLayout(displayId);
        if (dl != null && newDisplayAreaInfo != null) {
            // Note: there is a chance Transitions has triggered
            // DisplayController#onDisplayChangeRequested first, in which case layout was updated
            // and startBounds equals endBounds; then DisplayLayout size remains the same.
            // TODO(b/370721807): Remove DisplayChangeWindowControllerImpl and rely on transitions.
            final Rect startBounds = new Rect(0, 0, dl.width(), dl.height());
            final Rect endBounds = newDisplayAreaInfo.configuration.windowConfiguration.getBounds();
            mDisplayController.updateDisplayLayout(displayId, startBounds, endBounds,
                    fromRotation, toRotation);
        }

        WindowContainerTransaction t = new WindowContainerTransaction();
        dispatchOnDisplayChange(t, displayId, fromRotation, toRotation, newDisplayAreaInfo);
        try {
+24 −17
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.wm.shell.common;

import static android.app.WindowConfiguration.ROTATION_UNDEFINED;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
@@ -78,8 +81,8 @@ public class DisplayController {
        mWmService = wmService;
        mDisplayManager = displayManager;
        mDesktopState = desktopState;
        // TODO: Inject this instead
        mChangeController = new DisplayChangeController(mWmService, shellInit, mainExecutor);
        mChangeController = new DisplayChangeController(this, wmService, shellInit,
                mainExecutor);
        mDisplayContainerListener = new DisplayWindowListenerImpl();
        // Note, add this after DisplaceChangeController is constructed to ensure that is
        // initialized first
@@ -233,27 +236,31 @@ public class DisplayController {
    public void onDisplayChangeRequested(WindowContainerTransaction wct, int displayId,
            Rect startAbsBounds, Rect endAbsBounds, int fromRotation, int toRotation) {
        synchronized (mDisplays) {
            final DisplayRecord dr = mDisplays.get(displayId);
            if (dr == null) {
            final DisplayLayout dl = getDisplayLayout(displayId);
            if (dl == null) {
                Slog.w(TAG, "Skipping Display rotate on non-added display.");
                return;
            }
            updateDisplayLayout(displayId, startAbsBounds, endAbsBounds, fromRotation, toRotation);

            if (dr.mDisplayLayout != null) {
                if (endAbsBounds != null) {
                    // If there is a change in the display dimensions update the layout as well;
                    // note that endAbsBounds should ignore any potential rotation changes, so
                    // we still need to rotate the layout after if needed.
                    dr.mDisplayLayout.resizeTo(dr.mContext.getResources(),
                            new Size(endAbsBounds.width(), endAbsBounds.height()));
                }
                if (fromRotation != toRotation) {
                    dr.mDisplayLayout.rotateTo(dr.mContext.getResources(), toRotation);
            mChangeController.dispatchOnDisplayChange(
                    wct, displayId, fromRotation, toRotation, null /* newDisplayAreaInfo */);
        }
    }

            mChangeController.dispatchOnDisplayChange(
                    wct, displayId, fromRotation, toRotation, null /* newDisplayAreaInfo */);
    void updateDisplayLayout(int displayId,
            @NonNull Rect startBounds, @Nullable Rect endBounds, int fromRotation, int toRotation) {
        final DisplayLayout dl = getDisplayLayout(displayId);
        final Context ctx = getDisplayContext(displayId);
        if (dl == null || ctx == null) return;

        if (endBounds != null) {
            // Note that endAbsBounds should ignore any potential rotation changes, so
            // we still need to rotate the layout after if needed.
            dl.resizeTo(ctx.getResources(), new Size(endBounds.width(), endBounds.height()));
        }
        if (fromRotation != toRotation && toRotation != ROTATION_UNDEFINED) {
            dl.rotateTo(ctx.getResources(), toRotation);
        }
    }

+102 −1
Original line number Diff line number Diff line
@@ -19,10 +19,23 @@ package com.android.wm.shell.common;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.WindowConfiguration;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Size;
import android.view.IDisplayChangeWindowCallback;
import android.view.IWindowManager;
import android.view.Surface;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -49,16 +62,104 @@ public class DisplayChangeControllerTests extends ShellTestCase {
    private @Mock IWindowManager mWM;
    private @Mock ShellInit mShellInit;
    private @Mock ShellExecutor mMainExecutor;
    private @Mock DisplayController mDisplayController;

    private @Mock DisplayLayout mMockDisplayLayout;
    private @Mock DisplayChangeController.OnDisplayChangingListener mMockOnDisplayChangingListener;
    private @Mock IDisplayChangeWindowCallback mMockDisplayChangeWindowCallback;
    private DisplayChangeController mController;

    private static final int DISPLAY_ID = 0;
    private static final int START_ROTATION = Surface.ROTATION_0;
    private static final int END_ROTATION = Surface.ROTATION_90;
    private static final Size DISPLAY_START_SIZE = new Size(100, 100);
    private static final Size DISPLAY_END_SIZE = new Size(200, 200);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mController = spy(new DisplayChangeController(mWM, mShellInit, mMainExecutor));
        mController = spy(new DisplayChangeController(mDisplayController, mWM, mShellInit,
                mMainExecutor));
        mController.addDisplayChangeListener(mMockOnDisplayChangingListener);
    }

    @Test
    public void instantiate_addInitCallback() {
        verify(mShellInit, times(1)).addInitCallback(any(), any());
    }

    @Test
    public void onDisplayChange_sizeChange_updateDisplayLayout_thenContinueDisplayChange() throws
            RemoteException {
        // set up the init display layout
        when(mMockDisplayLayout.width()).thenReturn(DISPLAY_START_SIZE.getWidth());
        when(mMockDisplayLayout.height()).thenReturn(DISPLAY_START_SIZE.getHeight());
        when(mDisplayController.getDisplayLayout(eq(DISPLAY_ID))).thenReturn(mMockDisplayLayout);

        // set up the new display area info
        final Rect startBounds = new Rect(0, 0,
                DISPLAY_START_SIZE.getWidth(), DISPLAY_START_SIZE.getHeight());
        final Rect endBounds = new Rect(0, 0,
                DISPLAY_END_SIZE.getWidth(), DISPLAY_END_SIZE.getHeight());

        // create a new display area info for size change
        final DisplayAreaInfo displayAreaInfo = createDisplayAreaInfo(DISPLAY_ID, endBounds);

        mController.onDisplayChange(DISPLAY_ID, START_ROTATION, START_ROTATION, displayAreaInfo,
                mMockDisplayChangeWindowCallback);

        // verify that local display layouts are updated
        verify(mDisplayController, times(1)).updateDisplayLayout(eq(DISPLAY_ID),
                eq(startBounds), eq(endBounds), eq(START_ROTATION), eq(START_ROTATION));

        // verify that display changing callbacks are dispatched
        verify(mMockOnDisplayChangingListener, times(1)).onDisplayChange(
                eq(DISPLAY_ID), eq(START_ROTATION), eq(START_ROTATION), eq(displayAreaInfo),
                any(WindowContainerTransaction.class));

        verify(mMockDisplayChangeWindowCallback, times(1))
                .continueDisplayChange(any(WindowContainerTransaction.class));
    }

    @Test
    public void onDisplayChange_rotationChange_updateDisplayLayout_thenContinueDisplayChange()
            throws RemoteException {
        // set up the init display layout
        when(mMockDisplayLayout.width()).thenReturn(DISPLAY_START_SIZE.getWidth());
        when(mMockDisplayLayout.height()).thenReturn(DISPLAY_START_SIZE.getHeight());
        when(mDisplayController.getDisplayLayout(eq(DISPLAY_ID))).thenReturn(mMockDisplayLayout);

        // set up the new display area info
        final Rect startBounds = new Rect(0, 0,
                DISPLAY_START_SIZE.getWidth(), DISPLAY_START_SIZE.getHeight());

        // create a new display area info for size change
        final DisplayAreaInfo displayAreaInfo = createDisplayAreaInfo(DISPLAY_ID, startBounds);

        mController.onDisplayChange(DISPLAY_ID, START_ROTATION, END_ROTATION, displayAreaInfo,
                mMockDisplayChangeWindowCallback);

        // verify that local display layouts are updated
        verify(mDisplayController, times(1)).updateDisplayLayout(eq(DISPLAY_ID),
                eq(startBounds), eq(startBounds), eq(START_ROTATION), eq(END_ROTATION));

        // verify that display changing callbacks are dispatched
        verify(mMockOnDisplayChangingListener, times(1)).onDisplayChange(
                eq(DISPLAY_ID), eq(START_ROTATION), eq(END_ROTATION), eq(displayAreaInfo),
                any(WindowContainerTransaction.class));

        verify(mMockDisplayChangeWindowCallback, times(1))
                .continueDisplayChange(any(WindowContainerTransaction.class));
    }

    private DisplayAreaInfo createDisplayAreaInfo(int displayId, Rect endBounds) {
        final WindowContainerToken mMockToken = mock(WindowContainerToken.class);
        final WindowConfiguration windowConfiguration = new WindowConfiguration();
        windowConfiguration.setBounds(endBounds);

        final DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(mMockToken,
                displayId, DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER);
        displayAreaInfo.configuration.windowConfiguration.setTo(windowConfiguration);
        return displayAreaInfo;
    }
}