Loading services/core/java/com/android/server/wm/AsyncRotationController.java +302 −164 File changed.Preview size limit exceeded, changes collapsed. Show changes services/core/java/com/android/server/wm/DisplayContent.java +4 −8 Original line number Diff line number Diff line Loading @@ -1880,7 +1880,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } if (mAsyncRotationController == null) { mAsyncRotationController = new AsyncRotationController(this); mAsyncRotationController.hide(); mAsyncRotationController.start(); return true; } return false; Loading @@ -1890,7 +1890,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp void finishAsyncRotationIfPossible() { final AsyncRotationController controller = mAsyncRotationController; if (controller != null && !mDisplayRotation.hasSeamlessRotatingWindow()) { controller.show(); controller.completeAll(); mAsyncRotationController = null; } } Loading @@ -1898,19 +1898,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /** Shows the given window which may be hidden for screen rotation. */ void finishAsyncRotation(WindowToken windowToken) { final AsyncRotationController controller = mAsyncRotationController; if (controller != null && controller.show(windowToken)) { if (controller != null && controller.completeRotation(windowToken)) { mAsyncRotationController = null; } } /** Returns {@code true} if the screen rotation animation needs to wait for the window. */ boolean shouldSyncRotationChange(WindowState w) { if (w.mForceSeamlesslyRotate) { // The window should look no different before and after rotation. return false; } final AsyncRotationController controller = mAsyncRotationController; return controller == null || !controller.isHandledToken(w.mToken); return controller == null || !controller.isAsync(w); } void notifyInsetsChanged(Consumer<WindowState> dispatchInsetsChanged) { Loading services/core/java/com/android/server/wm/DisplayRotation.java +15 −12 Original line number Diff line number Diff line Loading @@ -675,18 +675,7 @@ public class DisplayRotation { return false; } // For the upside down rotation we don't rotate seamlessly as the navigation bar moves // position. Note most apps (using orientation:sensor or user as opposed to fullSensor) // will not enter the reverse portrait orientation, so actually the orientation won't change // at all. if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) { return false; } // If the navigation bar can't change sides, then it will jump when we change orientations // and we don't rotate seamlessly - unless that is allowed, eg. with gesture navigation // where the navbar is low-profile enough that this isn't very noticeable. if (!mAllowSeamlessRotationDespiteNavBarMoving && !mDisplayPolicy.navigationBarCanMove()) { if (!canRotateSeamlessly(oldRotation, newRotation)) { return false; } Loading @@ -713,6 +702,20 @@ public class DisplayRotation { return true; } boolean canRotateSeamlessly(int oldRotation, int newRotation) { // For the upside down rotation we don't rotate seamlessly as the navigation bar moves // position. Note most apps (using orientation:sensor or user as opposed to fullSensor) // will not enter the reverse portrait orientation, so actually the orientation won't change // at all. if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) { return false; } // If the navigation bar can't change sides, then it will jump when we change orientations // and we don't rotate seamlessly - unless that is allowed, eg. with gesture navigation // where the navbar is low-profile enough that this isn't very noticeable. return mAllowSeamlessRotationDespiteNavBarMoving || mDisplayPolicy.navigationBarCanMove(); } void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) { if (seamlesslyRotated == w.mSeamlesslyRotated || w.mForceSeamlesslyRotate) { return; Loading services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +28 −9 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_CLOSE; Loading Loading @@ -504,7 +505,12 @@ public class TransitionTests extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, "statusBar"); final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "navBar"); final WindowState ime = createWindow(null, TYPE_INPUT_METHOD, "ime"); final WindowState[] windows = { statusBar, navBar, ime }; final WindowToken decorToken = new WindowToken.Builder(mWm, mock(IBinder.class), TYPE_NAVIGATION_BAR_PANEL).setDisplayContent(mDisplayContent) .setRoundedCornerOverlay(true).build(); final WindowState screenDecor = createWindow(null, decorToken.windowType, decorToken, "screenDecor"); final WindowState[] windows = { statusBar, navBar, ime, screenDecor }; makeWindowVisible(windows); mDisplayContent.getDisplayPolicy().addWindowLw(statusBar, statusBar.mAttrs); mDisplayContent.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs); Loading @@ -523,26 +529,27 @@ public class TransitionTests extends WindowTestsBase { player.startTransition(); assertFalse(statusBar.mToken.inTransition()); assertFalse(decorToken.inTransition()); assertTrue(ime.mToken.inTransition()); assertTrue(task.inTransition()); assertTrue(asyncRotationController.isTargetToken(decorToken)); screenDecor.setOrientationChanging(false); // Status bar finishes drawing before the start transaction. Its fade-in animation will be // executed until the transaction is committed, so it is still in target tokens. statusBar.setOrientationChanging(false); assertTrue(asyncRotationController.isTargetToken(statusBar.mToken)); final SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class); final ArgumentCaptor<SurfaceControl.TransactionCommittedListener> listenerCaptor = ArgumentCaptor.forClass(SurfaceControl.TransactionCommittedListener.class); player.onTransactionReady(startTransaction); final SurfaceControl.TransactionCommittedListener transactionCommittedListener = onRotationTransactionReady(player, startTransaction); verify(startTransaction).addTransactionCommittedListener(any(), listenerCaptor.capture()); // The transaction is committed, so fade-in animation for status bar is consumed. listenerCaptor.getValue().onTransactionCommitted(); transactionCommittedListener.onTransactionCommitted(); assertFalse(asyncRotationController.isTargetToken(statusBar.mToken)); // Status bar finishes drawing after the start transaction, so its fade-in animation can // execute directly. // Navigation bar finishes drawing after the start transaction, so its fade-in animation // can execute directly. navBar.setOrientationChanging(false); assertFalse(asyncRotationController.isTargetToken(navBar.mToken)); assertNull(mDisplayContent.getAsyncRotationController()); Loading Loading @@ -577,7 +584,8 @@ public class TransitionTests extends WindowTestsBase { final SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class); final SurfaceControl leash = statusBar.mToken.getAnimationLeash(); doReturn(true).when(leash).isValid(); player.onTransactionReady(startTransaction); final SurfaceControl.TransactionCommittedListener transactionCommittedListener = onRotationTransactionReady(player, startTransaction); // The leash should be unrotated. verify(startTransaction).setMatrix(eq(leash), any(), any()); Loading @@ -588,6 +596,8 @@ public class TransitionTests extends WindowTestsBase { mock(SurfaceControl.Transaction.class); final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction); assertFalse(layoutNeeded); transactionCommittedListener.onTransactionCommitted(); player.finish(); // The controller should capture the draw transaction and merge it when preparing to run // fade-in animation. Loading Loading @@ -750,4 +760,13 @@ public class TransitionTests extends WindowTestsBase { changes.put(curr, new Transition.ChangeInfo(true /* vis */, false /* exChg */)); } } private static SurfaceControl.TransactionCommittedListener onRotationTransactionReady( TestTransitionPlayer player, SurfaceControl.Transaction startTransaction) { final ArgumentCaptor<SurfaceControl.TransactionCommittedListener> listenerCaptor = ArgumentCaptor.forClass(SurfaceControl.TransactionCommittedListener.class); player.onTransactionReady(startTransaction); verify(startTransaction).addTransactionCommittedListener(any(), listenerCaptor.capture()); return listenerCaptor.getValue(); } } Loading
services/core/java/com/android/server/wm/AsyncRotationController.java +302 −164 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/core/java/com/android/server/wm/DisplayContent.java +4 −8 Original line number Diff line number Diff line Loading @@ -1880,7 +1880,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } if (mAsyncRotationController == null) { mAsyncRotationController = new AsyncRotationController(this); mAsyncRotationController.hide(); mAsyncRotationController.start(); return true; } return false; Loading @@ -1890,7 +1890,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp void finishAsyncRotationIfPossible() { final AsyncRotationController controller = mAsyncRotationController; if (controller != null && !mDisplayRotation.hasSeamlessRotatingWindow()) { controller.show(); controller.completeAll(); mAsyncRotationController = null; } } Loading @@ -1898,19 +1898,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /** Shows the given window which may be hidden for screen rotation. */ void finishAsyncRotation(WindowToken windowToken) { final AsyncRotationController controller = mAsyncRotationController; if (controller != null && controller.show(windowToken)) { if (controller != null && controller.completeRotation(windowToken)) { mAsyncRotationController = null; } } /** Returns {@code true} if the screen rotation animation needs to wait for the window. */ boolean shouldSyncRotationChange(WindowState w) { if (w.mForceSeamlesslyRotate) { // The window should look no different before and after rotation. return false; } final AsyncRotationController controller = mAsyncRotationController; return controller == null || !controller.isHandledToken(w.mToken); return controller == null || !controller.isAsync(w); } void notifyInsetsChanged(Consumer<WindowState> dispatchInsetsChanged) { Loading
services/core/java/com/android/server/wm/DisplayRotation.java +15 −12 Original line number Diff line number Diff line Loading @@ -675,18 +675,7 @@ public class DisplayRotation { return false; } // For the upside down rotation we don't rotate seamlessly as the navigation bar moves // position. Note most apps (using orientation:sensor or user as opposed to fullSensor) // will not enter the reverse portrait orientation, so actually the orientation won't change // at all. if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) { return false; } // If the navigation bar can't change sides, then it will jump when we change orientations // and we don't rotate seamlessly - unless that is allowed, eg. with gesture navigation // where the navbar is low-profile enough that this isn't very noticeable. if (!mAllowSeamlessRotationDespiteNavBarMoving && !mDisplayPolicy.navigationBarCanMove()) { if (!canRotateSeamlessly(oldRotation, newRotation)) { return false; } Loading @@ -713,6 +702,20 @@ public class DisplayRotation { return true; } boolean canRotateSeamlessly(int oldRotation, int newRotation) { // For the upside down rotation we don't rotate seamlessly as the navigation bar moves // position. Note most apps (using orientation:sensor or user as opposed to fullSensor) // will not enter the reverse portrait orientation, so actually the orientation won't change // at all. if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) { return false; } // If the navigation bar can't change sides, then it will jump when we change orientations // and we don't rotate seamlessly - unless that is allowed, eg. with gesture navigation // where the navbar is low-profile enough that this isn't very noticeable. return mAllowSeamlessRotationDespiteNavBarMoving || mDisplayPolicy.navigationBarCanMove(); } void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) { if (seamlesslyRotated == w.mSeamlesslyRotated || w.mForceSeamlesslyRotate) { return; Loading
services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +28 −9 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_CLOSE; Loading Loading @@ -504,7 +505,12 @@ public class TransitionTests extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, "statusBar"); final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "navBar"); final WindowState ime = createWindow(null, TYPE_INPUT_METHOD, "ime"); final WindowState[] windows = { statusBar, navBar, ime }; final WindowToken decorToken = new WindowToken.Builder(mWm, mock(IBinder.class), TYPE_NAVIGATION_BAR_PANEL).setDisplayContent(mDisplayContent) .setRoundedCornerOverlay(true).build(); final WindowState screenDecor = createWindow(null, decorToken.windowType, decorToken, "screenDecor"); final WindowState[] windows = { statusBar, navBar, ime, screenDecor }; makeWindowVisible(windows); mDisplayContent.getDisplayPolicy().addWindowLw(statusBar, statusBar.mAttrs); mDisplayContent.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs); Loading @@ -523,26 +529,27 @@ public class TransitionTests extends WindowTestsBase { player.startTransition(); assertFalse(statusBar.mToken.inTransition()); assertFalse(decorToken.inTransition()); assertTrue(ime.mToken.inTransition()); assertTrue(task.inTransition()); assertTrue(asyncRotationController.isTargetToken(decorToken)); screenDecor.setOrientationChanging(false); // Status bar finishes drawing before the start transaction. Its fade-in animation will be // executed until the transaction is committed, so it is still in target tokens. statusBar.setOrientationChanging(false); assertTrue(asyncRotationController.isTargetToken(statusBar.mToken)); final SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class); final ArgumentCaptor<SurfaceControl.TransactionCommittedListener> listenerCaptor = ArgumentCaptor.forClass(SurfaceControl.TransactionCommittedListener.class); player.onTransactionReady(startTransaction); final SurfaceControl.TransactionCommittedListener transactionCommittedListener = onRotationTransactionReady(player, startTransaction); verify(startTransaction).addTransactionCommittedListener(any(), listenerCaptor.capture()); // The transaction is committed, so fade-in animation for status bar is consumed. listenerCaptor.getValue().onTransactionCommitted(); transactionCommittedListener.onTransactionCommitted(); assertFalse(asyncRotationController.isTargetToken(statusBar.mToken)); // Status bar finishes drawing after the start transaction, so its fade-in animation can // execute directly. // Navigation bar finishes drawing after the start transaction, so its fade-in animation // can execute directly. navBar.setOrientationChanging(false); assertFalse(asyncRotationController.isTargetToken(navBar.mToken)); assertNull(mDisplayContent.getAsyncRotationController()); Loading Loading @@ -577,7 +584,8 @@ public class TransitionTests extends WindowTestsBase { final SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class); final SurfaceControl leash = statusBar.mToken.getAnimationLeash(); doReturn(true).when(leash).isValid(); player.onTransactionReady(startTransaction); final SurfaceControl.TransactionCommittedListener transactionCommittedListener = onRotationTransactionReady(player, startTransaction); // The leash should be unrotated. verify(startTransaction).setMatrix(eq(leash), any(), any()); Loading @@ -588,6 +596,8 @@ public class TransitionTests extends WindowTestsBase { mock(SurfaceControl.Transaction.class); final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction); assertFalse(layoutNeeded); transactionCommittedListener.onTransactionCommitted(); player.finish(); // The controller should capture the draw transaction and merge it when preparing to run // fade-in animation. Loading Loading @@ -750,4 +760,13 @@ public class TransitionTests extends WindowTestsBase { changes.put(curr, new Transition.ChangeInfo(true /* vis */, false /* exChg */)); } } private static SurfaceControl.TransactionCommittedListener onRotationTransactionReady( TestTransitionPlayer player, SurfaceControl.Transaction startTransaction) { final ArgumentCaptor<SurfaceControl.TransactionCommittedListener> listenerCaptor = ArgumentCaptor.forClass(SurfaceControl.TransactionCommittedListener.class); player.onTransactionReady(startTransaction); verify(startTransaction).addTransactionCommittedListener(any(), listenerCaptor.capture()); return listenerCaptor.getValue(); } }