Loading services/core/java/com/android/server/wm/ActivityRecord.java +2 −0 Original line number Diff line number Diff line Loading @@ -7867,6 +7867,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( task.mTaskId, requestedOrientation); mDisplayContent.getDisplayRotation().onSetRequestedOrientation(); } /* Loading services/core/java/com/android/server/wm/DisplayRotation.java +22 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,8 @@ public class DisplayRotation { // config changes and unexpected jumps while folding the device to closed state. private static final int FOLDING_RECOMPUTE_CONFIG_DELAY_MS = 800; private static final int ROTATION_UNDEFINED = -1; private static class RotationAnimationPair { @AnimRes int mEnter; Loading Loading @@ -184,6 +186,12 @@ public class DisplayRotation { */ private int mShowRotationSuggestions; /** * The most recent {@link Surface.Rotation} choice shown to the user for confirmation, or * {@link #ROTATION_UNDEFINED} */ private int mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; private static final int ALLOW_ALL_ROTATIONS_UNDEFINED = -1; private static final int ALLOW_ALL_ROTATIONS_DISABLED = 0; private static final int ALLOW_ALL_ROTATIONS_ENABLED = 1; Loading Loading @@ -861,6 +869,7 @@ public class DisplayRotation { @VisibleForTesting void setUserRotation(int userRotationMode, int userRotation) { mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; if (isDefaultDisplay) { // We'll be notified via settings listener, so we don't need to update internal values. final ContentResolver res = mContext.getContentResolver(); Loading Loading @@ -1568,6 +1577,17 @@ public class DisplayRotation { return shouldUpdateRotation; } /** * Called from {@link ActivityRecord#setRequestedOrientation(int)} */ void onSetRequestedOrientation() { if (mCompatPolicyForImmersiveApps == null || mRotationChoiceShownToUserForConfirmation == ROTATION_UNDEFINED) { return; } mOrientationListener.onProposedRotationChanged(mRotationChoiceShownToUserForConfirmation); } void dump(String prefix, PrintWriter pw) { pw.println(prefix + "DisplayRotation"); pw.println(prefix + " mCurrentAppOrientation=" Loading Loading @@ -1966,9 +1986,11 @@ public class DisplayRotation { // Send interaction power boost to improve redraw performance. mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0); if (isRotationChoiceAllowed(rotation)) { mRotationChoiceShownToUserForConfirmation = rotation; final boolean isValid = isValidRotationChoice(rotation); sendProposedRotationChangeToStatusBarInternal(rotation, isValid); } else { mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; mService.updateRotation(false /* alwaysSendConfiguration */, false /* forceRelayout */); } Loading services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +6 −0 Original line number Diff line number Diff line Loading @@ -588,12 +588,18 @@ public class ActivityRecordTests extends WindowTestsBase { throw new IllegalStateException("Orientation in new config should be either" + "landscape or portrait."); } final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation(); spyOn(displayRotation); activity.setRequestedOrientation(requestedOrientation); final ActivityConfigurationChangeItem expected = ActivityConfigurationChangeItem.obtain(newConfig); verify(mAtm.getLifecycleManager()).scheduleTransaction(eq(activity.app.getThread()), eq(activity.token), eq(expected)); verify(displayRotation).onSetRequestedOrientation(); } @Test Loading services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +37 −2 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import android.view.DisplayAddress; import android.view.Surface; import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import com.android.internal.util.test.FakeSettingsProvider; Loading Loading @@ -137,6 +138,8 @@ public class DisplayRotationTests { private DeviceStateController mDeviceStateController; private DisplayRotation mTarget; @Nullable private DisplayRotationImmersiveAppCompatPolicy mDisplayRotationImmersiveAppCompatPolicyMock; @BeforeClass public static void setUpOnce() { Loading @@ -161,7 +164,7 @@ public class DisplayRotationTests { LocalServices.removeServiceForTest(StatusBarManagerInternal.class); mMockStatusBarManagerInternal = mock(StatusBarManagerInternal.class); LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal); mDisplayRotationImmersiveAppCompatPolicyMock = null; mBuilder = new DisplayRotationBuilder(); } Loading Loading @@ -573,6 +576,38 @@ public class DisplayRotationTests { verify(mMockStatusBarManagerInternal).onProposedRotationChanged(Surface.ROTATION_90, true); } @Test public void testNotifiesChoiceWhenSensorUpdates_immersiveApp() throws Exception { mDisplayRotationImmersiveAppCompatPolicyMock = mock( DisplayRotationImmersiveAppCompatPolicy.class); when(mDisplayRotationImmersiveAppCompatPolicyMock.isRotationLockEnforced( Surface.ROTATION_90)).thenReturn(true); mBuilder.build(); configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); thawRotation(); enableOrientationSensor(); mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); assertTrue(waitForUiHandler()); verify(mMockStatusBarManagerInternal).onProposedRotationChanged(Surface.ROTATION_90, true); // An imaginary ActivityRecord.setRequestedOrientation call disables immersive mode: when(mDisplayRotationImmersiveAppCompatPolicyMock.isRotationLockEnforced( Surface.ROTATION_90)).thenReturn(false); // And then ActivityRecord.setRequestedOrientation calls onSetRequestedOrientation. mTarget.onSetRequestedOrientation(); // onSetRequestedOrientation should lead to a second call to // mOrientationListener.onProposedRotationChanged // but now, instead of notifying mMockStatusBarManagerInternal, it calls updateRotation: verify(sMockWm).updateRotation(false, false); } @Test public void testAllowAllRotations_allowsUpsideDownSuggestion() throws Exception { Loading Loading @@ -1354,7 +1389,7 @@ public class DisplayRotationTests { @Override DisplayRotationImmersiveAppCompatPolicy initImmersiveAppCompatPolicy( WindowManagerService service, DisplayContent displayContent) { return null; return mDisplayRotationImmersiveAppCompatPolicyMock; } @Override Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +2 −0 Original line number Diff line number Diff line Loading @@ -7867,6 +7867,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( task.mTaskId, requestedOrientation); mDisplayContent.getDisplayRotation().onSetRequestedOrientation(); } /* Loading
services/core/java/com/android/server/wm/DisplayRotation.java +22 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,8 @@ public class DisplayRotation { // config changes and unexpected jumps while folding the device to closed state. private static final int FOLDING_RECOMPUTE_CONFIG_DELAY_MS = 800; private static final int ROTATION_UNDEFINED = -1; private static class RotationAnimationPair { @AnimRes int mEnter; Loading Loading @@ -184,6 +186,12 @@ public class DisplayRotation { */ private int mShowRotationSuggestions; /** * The most recent {@link Surface.Rotation} choice shown to the user for confirmation, or * {@link #ROTATION_UNDEFINED} */ private int mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; private static final int ALLOW_ALL_ROTATIONS_UNDEFINED = -1; private static final int ALLOW_ALL_ROTATIONS_DISABLED = 0; private static final int ALLOW_ALL_ROTATIONS_ENABLED = 1; Loading Loading @@ -861,6 +869,7 @@ public class DisplayRotation { @VisibleForTesting void setUserRotation(int userRotationMode, int userRotation) { mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; if (isDefaultDisplay) { // We'll be notified via settings listener, so we don't need to update internal values. final ContentResolver res = mContext.getContentResolver(); Loading Loading @@ -1568,6 +1577,17 @@ public class DisplayRotation { return shouldUpdateRotation; } /** * Called from {@link ActivityRecord#setRequestedOrientation(int)} */ void onSetRequestedOrientation() { if (mCompatPolicyForImmersiveApps == null || mRotationChoiceShownToUserForConfirmation == ROTATION_UNDEFINED) { return; } mOrientationListener.onProposedRotationChanged(mRotationChoiceShownToUserForConfirmation); } void dump(String prefix, PrintWriter pw) { pw.println(prefix + "DisplayRotation"); pw.println(prefix + " mCurrentAppOrientation=" Loading Loading @@ -1966,9 +1986,11 @@ public class DisplayRotation { // Send interaction power boost to improve redraw performance. mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0); if (isRotationChoiceAllowed(rotation)) { mRotationChoiceShownToUserForConfirmation = rotation; final boolean isValid = isValidRotationChoice(rotation); sendProposedRotationChangeToStatusBarInternal(rotation, isValid); } else { mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; mService.updateRotation(false /* alwaysSendConfiguration */, false /* forceRelayout */); } Loading
services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +6 −0 Original line number Diff line number Diff line Loading @@ -588,12 +588,18 @@ public class ActivityRecordTests extends WindowTestsBase { throw new IllegalStateException("Orientation in new config should be either" + "landscape or portrait."); } final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation(); spyOn(displayRotation); activity.setRequestedOrientation(requestedOrientation); final ActivityConfigurationChangeItem expected = ActivityConfigurationChangeItem.obtain(newConfig); verify(mAtm.getLifecycleManager()).scheduleTransaction(eq(activity.app.getThread()), eq(activity.token), eq(expected)); verify(displayRotation).onSetRequestedOrientation(); } @Test Loading
services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +37 −2 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import android.view.DisplayAddress; import android.view.Surface; import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import com.android.internal.util.test.FakeSettingsProvider; Loading Loading @@ -137,6 +138,8 @@ public class DisplayRotationTests { private DeviceStateController mDeviceStateController; private DisplayRotation mTarget; @Nullable private DisplayRotationImmersiveAppCompatPolicy mDisplayRotationImmersiveAppCompatPolicyMock; @BeforeClass public static void setUpOnce() { Loading @@ -161,7 +164,7 @@ public class DisplayRotationTests { LocalServices.removeServiceForTest(StatusBarManagerInternal.class); mMockStatusBarManagerInternal = mock(StatusBarManagerInternal.class); LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal); mDisplayRotationImmersiveAppCompatPolicyMock = null; mBuilder = new DisplayRotationBuilder(); } Loading Loading @@ -573,6 +576,38 @@ public class DisplayRotationTests { verify(mMockStatusBarManagerInternal).onProposedRotationChanged(Surface.ROTATION_90, true); } @Test public void testNotifiesChoiceWhenSensorUpdates_immersiveApp() throws Exception { mDisplayRotationImmersiveAppCompatPolicyMock = mock( DisplayRotationImmersiveAppCompatPolicy.class); when(mDisplayRotationImmersiveAppCompatPolicyMock.isRotationLockEnforced( Surface.ROTATION_90)).thenReturn(true); mBuilder.build(); configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); thawRotation(); enableOrientationSensor(); mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); assertTrue(waitForUiHandler()); verify(mMockStatusBarManagerInternal).onProposedRotationChanged(Surface.ROTATION_90, true); // An imaginary ActivityRecord.setRequestedOrientation call disables immersive mode: when(mDisplayRotationImmersiveAppCompatPolicyMock.isRotationLockEnforced( Surface.ROTATION_90)).thenReturn(false); // And then ActivityRecord.setRequestedOrientation calls onSetRequestedOrientation. mTarget.onSetRequestedOrientation(); // onSetRequestedOrientation should lead to a second call to // mOrientationListener.onProposedRotationChanged // but now, instead of notifying mMockStatusBarManagerInternal, it calls updateRotation: verify(sMockWm).updateRotation(false, false); } @Test public void testAllowAllRotations_allowsUpsideDownSuggestion() throws Exception { Loading Loading @@ -1354,7 +1389,7 @@ public class DisplayRotationTests { @Override DisplayRotationImmersiveAppCompatPolicy initImmersiveAppCompatPolicy( WindowManagerService service, DisplayContent displayContent) { return null; return mDisplayRotationImmersiveAppCompatPolicyMock; } @Override Loading