Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java +20 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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(); Loading Loading @@ -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 { Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java +24 −17 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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); } } Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayChangeControllerTests.java +102 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java +20 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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(); Loading Loading @@ -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 { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java +24 −17 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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); } } Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayChangeControllerTests.java +102 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } }