diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-04-28 16:02:56 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-04-28 16:02:56 +0000 |
commit | 958a1009551942c8a44a580b44bda0a011206eca (patch) | |
tree | 800bdec2e564423d50ef1bc5fa2adab53823ccde | |
parent | 0dcdc69a57d48b2e63fa7e8af0ab78f30bae6e74 (diff) | |
parent | 19ce8d14c4ca3a0db001c4f8f43a9547e6e92f68 (diff) | |
download | base-958a1009551942c8a44a580b44bda0a011206eca.tar.gz |
Merge cherrypicks of ['googleplex-android-review.googlesource.com/22815560', 'googleplex-android-review.googlesource.com/22794847', 'googleplex-android-review.googlesource.com/22791220', 'googleplex-android-review.googlesource.com/22779400', 'googleplex-android-review.googlesource.com/22569796', 'googleplex-android-review.googlesource.com/22670803', 'googleplex-android-review.googlesource.com/22885816'] into tm-qpr3-c-release.
Change-Id: Ie66f8fc640cc38b85fc338b10dda4b5b8fa7979d
21 files changed, 197 insertions, 81 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 514083cefca9..9891409a08bb 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -572,6 +572,9 @@ docked if the dock is configured to enable the accelerometer. --> <bool name="config_supportAutoRotation">true</bool> + <!-- If true, allows rotation resolver service to help resolve screen rotation. --> + <bool name="config_allowRotationResolver">true</bool> + <!-- If true, the screen can be rotated via the accelerometer in all 4 rotations as the default behavior. --> <bool name="config_allowAllRotations">false</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 17a8a76bd590..01c6b5509cb7 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1754,6 +1754,7 @@ <java-symbol type="bool" name="config_perDisplayFocusEnabled" /> <java-symbol type="bool" name="config_showNavigationBar" /> <java-symbol type="bool" name="config_supportAutoRotation" /> + <java-symbol type="bool" name="config_allowRotationResolver" /> <java-symbol type="bool" name="config_dockedStackDividerFreeSnapMode" /> <java-symbol type="dimen" name="docked_stack_divider_thickness" /> <java-symbol type="dimen" name="docked_stack_divider_insets" /> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index b4acd6046182..ffc56b6f6106 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -727,10 +727,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange getRefBounds2(mTempRect); t.setPosition(leash2, mTempRect.left, mTempRect.top) .setWindowCrop(leash2, mTempRect.width(), mTempRect.height()); - // Make right or bottom side surface always higher than left or top side to avoid weird - // animation when dismiss split. e.g. App surface fling above on decor surface. - t.setLayer(leash1, 1); - t.setLayer(leash2, 2); if (mImePositionProcessor.adjustSurfaceLayoutForIme( t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 77939c7c6964..fbeff255b45d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -468,26 +468,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, final IRemoteAnimationFinishedCallback finishedCallback) { - boolean openingToSide = false; - if (apps != null) { - for (int i = 0; i < apps.length; ++i) { - if (apps[i].mode == MODE_OPENING - && mSideStage.containsTask(apps[i].taskId)) { - openingToSide = true; - break; - } - } - } else if (mSideStage.getChildCount() != 0) { - // There are chances the entering app transition got canceled by performing - // rotation transition. Checks if there is any child task existed in split - // screen before fallback to cancel entering flow. - openingToSide = true; - } - - if (isEnteringSplit && !openingToSide) { + if (isEnteringSplit && mSideStage.getChildCount() == 0) { mMainExecutor.execute(() -> exitSplitScreen( - mSideStage.getChildCount() == 0 ? mMainStage : mSideStage, - EXIT_REASON_UNKNOWN)); + null /* childrenToTop */, EXIT_REASON_UNKNOWN)); + mSplitUnsupportedToast.show(); } if (finishedCallback != null) { @@ -572,26 +556,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback, SurfaceControl.Transaction t) { - boolean openingToSide = false; - if (apps != null) { - for (int i = 0; i < apps.length; ++i) { - if (apps[i].mode == MODE_OPENING - && mSideStage.containsTask(apps[i].taskId)) { - openingToSide = true; - break; - } - } - } else if (mSideStage.getChildCount() != 0) { - // There are chances the entering app transition got canceled by performing - // rotation transition. Checks if there is any child task existed in split - // screen before fallback to cancel entering flow. - openingToSide = true; - } - - if (isEnteringSplit && !openingToSide && apps != null) { + if (isEnteringSplit && mSideStage.getChildCount() == 0) { mMainExecutor.execute(() -> exitSplitScreen( - mSideStage.getChildCount() == 0 ? mMainStage : mSideStage, - EXIT_REASON_UNKNOWN)); + null /* childrenToTop */, EXIT_REASON_UNKNOWN)); + mSplitUnsupportedToast.show(); } if (apps != null) { @@ -1034,7 +1002,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) { mIsDividerRemoteAnimating = false; mShouldUpdateRecents = true; - mSplitRequest = null; + clearRequestIfPresented(); // If any stage has no child after animation finished, it means that split will display // nothing, such status will happen if task and intent is same app but not support // multi-instance, we should exit split and expand that app as full screen. @@ -1054,7 +1022,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) { mIsDividerRemoteAnimating = false; mShouldUpdateRecents = true; - mSplitRequest = null; + clearRequestIfPresented(); // If any stage has no child after finished animation, that side of the split will display // nothing. This might happen if starting the same app on the both sides while not // supporting multi-instance. Exit the split screen and expand that app to full screen. @@ -1320,6 +1288,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, }); mShouldUpdateRecents = false; mIsDividerRemoteAnimating = false; + mSplitRequest = null; mSplitLayout.getInvisibleBounds(mTempRect1); if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) { @@ -1412,6 +1381,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } + private void clearRequestIfPresented() { + if (mSideStageListener.mVisible && mSideStageListener.mHasChildren + && mMainStageListener.mVisible && mSideStageListener.mHasChildren) { + mSplitRequest = null; + } + } + /** * Returns whether the split pair in the recent tasks list should be broken. */ @@ -1776,6 +1752,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, true /* setReparentLeafTaskIfRelaunch */); setRootForceTranslucent(true, wct); } else { + clearRequestIfPresented(); wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false /* setReparentLeafTaskIfRelaunch */); setRootForceTranslucent(false, wct); @@ -1926,7 +1903,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) { mShouldUpdateRecents = true; - mSplitRequest = null; + clearRequestIfPresented(); updateRecentTasksSplitPair(); if (!mLogger.hasStartedSession()) { @@ -2565,6 +2542,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } }); mShouldUpdateRecents = false; + mSplitRequest = null; // Update local states. setSplitsVisible(false); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index ead0bcd15c73..a841b7f96d3c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -220,20 +220,12 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { mCallbacks.onNoLongerSupportMultiWindow(); return; } - if (taskInfo.topActivity == null && mChildrenTaskInfo.contains(taskInfo.taskId) - && mChildrenTaskInfo.get(taskInfo.taskId).topActivity != null) { - // If top activity become null, it means the task is about to vanish, we use this - // signal to remove it from children list earlier for smooth dismiss transition. - mChildrenTaskInfo.remove(taskInfo.taskId); - mChildrenLeashes.remove(taskInfo.taskId); - } else { - mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); - } + mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */, taskInfo.isVisible); - if (!ENABLE_SHELL_TRANSITIONS && mChildrenLeashes.contains(taskInfo.taskId)) { - updateChildTaskSurface(taskInfo, mChildrenLeashes.get(taskInfo.taskId), - false /* firstAppeared */); + if (!ENABLE_SHELL_TRANSITIONS) { + updateChildTaskSurface( + taskInfo, mChildrenLeashes.get(taskInfo.taskId), false /* firstAppeared */); } } else { throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo @@ -267,6 +259,9 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { return; } sendStatusChanged(); + } else { + throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo + + "\n mRootTaskInfo: " + mRootTaskInfo); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java index b31e20fcc438..5ee8bf3006a3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java @@ -126,6 +126,12 @@ public final class StageTaskListenerTests extends ShellTestCase { verify(mCallbacks).onStatusChanged(eq(mRootTask.isVisible), eq(true)); } + @Test(expected = IllegalArgumentException.class) + public void testUnknownTaskVanished() { + final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build(); + mStageTaskListener.onTaskVanished(task); + } + @Test public void testTaskVanished() { // With shell transitions, the transition manages status changes, so skip this test. diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java index 76e1df1459e3..ea4ac2c928ce 100644 --- a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java +++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java @@ -62,7 +62,6 @@ public final class DeviceStateRotationLockSettingsManager { private SparseIntArray mPostureRotationLockSettings; private SparseIntArray mPostureDefaultRotationLockSettings; private SparseIntArray mPostureRotationLockFallbackSettings; - private String mLastSettingValue; private List<SettableDeviceState> mSettableDeviceStates; @VisibleForTesting @@ -209,10 +208,7 @@ public final class DeviceStateRotationLockSettingsManager { } private void initializeInMemoryMap() { - String serializedSetting = - mSecureSettings.getStringForUser( - Settings.Secure.DEVICE_STATE_ROTATION_LOCK, - UserHandle.USER_CURRENT); + String serializedSetting = getPersistedSettingValue(); if (TextUtils.isEmpty(serializedSetting)) { // No settings saved, we should load the defaults and persist them. fallbackOnDefaults(); @@ -290,19 +286,25 @@ public final class DeviceStateRotationLockSettingsManager { } private void persistSettingIfChanged(String newSettingValue) { + String lastSettingValue = getPersistedSettingValue(); Log.v(TAG, "persistSettingIfChanged: " - + "last=" + mLastSettingValue + ", " + + "last=" + lastSettingValue + ", " + "new=" + newSettingValue); - if (TextUtils.equals(mLastSettingValue, newSettingValue)) { + if (TextUtils.equals(lastSettingValue, newSettingValue)) { return; } - mLastSettingValue = newSettingValue; mSecureSettings.putStringForUser( Settings.Secure.DEVICE_STATE_ROTATION_LOCK, /* value= */ newSettingValue, UserHandle.USER_CURRENT); } + private String getPersistedSettingValue() { + return mSecureSettings.getStringForUser( + Settings.Secure.DEVICE_STATE_ROTATION_LOCK, + UserHandle.USER_CURRENT); + } + private void loadDefaults() { mSettableDeviceStates = new ArrayList<>(mPostureRotationLockDefaults.length); mPostureDefaultRotationLockSettings = new SparseIntArray( @@ -351,7 +353,6 @@ public final class DeviceStateRotationLockSettingsManager { pw.println("mDeviceStateRotationLockSettings: " + mPostureRotationLockSettings); pw.println("mPostureRotationLockFallbackSettings: " + mPostureRotationLockFallbackSettings); pw.println("mSettableDeviceStates: " + mSettableDeviceStates); - pw.println("mLastSettingValue: " + mLastSettingValue); pw.decreaseIndent(); } diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java index fdefcde3a170..52c2a87cc961 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java @@ -114,6 +114,21 @@ public class DeviceStateRotationLockSettingsManagerTest { } @Test + public void updateSetting_twiceWithSameValue_persistedValueDifferent_persistsAgain() { + mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true); + // This persists a different setting than what was set above. It simulates the persisted + // setting being changed from a different process. + persistSettings("0:1:1:2:2:2"); + mNumSettingsChanges = 0; + + // Updating again with the same value as in the first line of the test should persist the + // setting, as it is different to what is actually persisted. + mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true); + + assertThat(mNumSettingsChanges).isEqualTo(1); + } + + @Test public void getSettableDeviceStates_returnsExpectedValuesInOriginalOrder() { when(mMockResources.getStringArray( R.array.config_perDeviceStateRotationLockDefaults)).thenReturn( diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java index b575f9a0ab8b..a2872e3c639b 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java @@ -197,7 +197,8 @@ public class DreamOverlayStateController implements if (mShouldShowComplications) { return (requiredTypes & getAvailableComplicationTypes()) == requiredTypes; } - return (requiredTypes & mSupportedTypes) == requiredTypes; + final int typesToAlwaysShow = mSupportedTypes & getAvailableComplicationTypes(); + return (requiredTypes & typesToAlwaysShow) == requiredTypes; }) .collect(Collectors.toCollection(HashSet::new)) : mComplications); diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java index 55f0a8cd3f08..d0c1c4db62d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java @@ -353,6 +353,34 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase { } } + @Test + public void testHomeControlsDoNotShowIfNotAvailable_featureEnabled() { + when(mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)).thenReturn(true); + + final DreamOverlayStateController stateController = getDreamOverlayStateController(true); + stateController.setShouldShowComplications(true); + + final Complication homeControlsComplication = Mockito.mock(Complication.class); + when(homeControlsComplication.getRequiredTypeAvailability()) + .thenReturn(Complication.COMPLICATION_TYPE_HOME_CONTROLS); + + stateController.addComplication(homeControlsComplication); + + final DreamOverlayStateController.Callback callback = + Mockito.mock(DreamOverlayStateController.Callback.class); + + stateController.addCallback(callback); + mExecutor.runAllReady(); + + // No home controls since it is not available. + assertThat(stateController.getComplications()).doesNotContain(homeControlsComplication); + + stateController.setAvailableComplicationTypes(Complication.COMPLICATION_TYPE_HOME_CONTROLS + | Complication.COMPLICATION_TYPE_WEATHER); + mExecutor.runAllReady(); + assertThat(stateController.getComplications()).contains(homeControlsComplication); + } + private DreamOverlayStateController getDreamOverlayStateController(boolean overlayEnabled) { return new DreamOverlayStateController(mExecutor, overlayEnabled, mFeatureFlags); } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 47e880a3fce2..8eed76505847 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -2094,14 +2094,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call && !mScreenOffBecauseOfProximity) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF); unblockScreenOn(); - mWindowManagerPolicy.screenTurnedOff(mDisplayId); + mWindowManagerPolicy.screenTurnedOff(mDisplayId, mIsInTransition); } else if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_OFF) { // We told policy already that screen was turning off, but now we changed our minds. // Complete the full state transition on -> turningOff -> off. unblockScreenOff(); - mWindowManagerPolicy.screenTurnedOff(mDisplayId); + mWindowManagerPolicy.screenTurnedOff(mDisplayId, mIsInTransition); setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF); } if (!isOff diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index f064f83393c0..74d87cd60b68 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4756,11 +4756,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Called on the DisplayManager's DisplayPowerController thread. @Override - public void screenTurnedOff(int displayId) { + public void screenTurnedOff(int displayId, boolean isSwappingDisplay) { if (DEBUG_WAKEUP) Slog.i(TAG, "Display" + displayId + " turned off..."); if (displayId == DEFAULT_DISPLAY) { - updateScreenOffSleepToken(true); + updateScreenOffSleepToken(true, isSwappingDisplay); mRequestedOrSleepingDefaultDisplay = false; mDefaultDisplayPolicy.screenTurnedOff(); synchronized (mLock) { @@ -4811,7 +4811,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (displayId == DEFAULT_DISPLAY) { Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */); - updateScreenOffSleepToken(false); + updateScreenOffSleepToken(false /* acquire */, false /* isSwappingDisplay */); mDefaultDisplayPolicy.screenTurnedOn(screenOnListener); mBootAnimationDismissable = false; @@ -5330,9 +5330,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } // TODO (multidisplay): Support multiple displays in WindowManagerPolicy. - private void updateScreenOffSleepToken(boolean acquire) { + private void updateScreenOffSleepToken(boolean acquire, boolean isSwappingDisplay) { if (acquire) { - mScreenOffSleepTokenAcquirer.acquire(DEFAULT_DISPLAY); + mScreenOffSleepTokenAcquirer.acquire(DEFAULT_DISPLAY, isSwappingDisplay); } else { mScreenOffSleepTokenAcquirer.release(DEFAULT_DISPLAY); } diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 77007fa229a2..cd63caa063f0 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -829,8 +829,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { /** * Called when the display has turned off. + * @param displayId The display to apply to. + * @param isSwappingDisplay Whether the display is swapping to another physical display. */ - public void screenTurnedOff(int displayId); + void screenTurnedOff(int displayId, boolean isSwappingDisplay); public interface ScreenOnListener { void onScreenOn(); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d872ada1fd0c..f3d7448f19ab 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -8417,6 +8417,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return inTransitionSelfOrParent(); } + boolean isDisplaySleepingAndSwapping() { + for (int i = mDisplayContent.mAllSleepTokens.size() - 1; i >= 0; i--) { + RootWindowContainer.SleepToken sleepToken = mDisplayContent.mAllSleepTokens.get(i); + if (sleepToken.isDisplaySwapping()) { + return true; + } + } + return false; + } + /** * Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed * orientation then aspect ratio restrictions are also already respected. diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 2792f4265caa..9123ffa329df 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -141,6 +141,13 @@ public abstract class ActivityTaskManagerInternal { void acquire(int displayId); /** + * Acquires a sleep token. + * @param displayId The display to apply to. + * @param isSwappingDisplay Whether the display is swapping to another physical display. + */ + void acquire(int displayId, boolean isSwappingDisplay); + + /** * Releases the sleep token. * @param displayId The display to apply to. */ diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index f6e92a642900..863bf94b13c1 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -4747,10 +4747,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void acquire(int displayId) { + acquire(displayId, false /* isSwappingDisplay */); + } + + @Override + public void acquire(int displayId, boolean isSwappingDisplay) { synchronized (mGlobalLock) { if (!mSleepTokens.contains(displayId)) { mSleepTokens.append(displayId, - mRootWindowContainer.createSleepToken(mTag, displayId)); + mRootWindowContainer.createSleepToken(mTag, displayId, + isSwappingDisplay)); updateSleepIfNeededLocked(); } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 9b9337e24f53..371480884391 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -179,6 +179,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // How long we can hold the launch wake lock before giving up. private static final int LAUNCH_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; + // How long we delay processing the stopping and finishing activities. + private static final int SCHEDULE_FINISHING_STOPPING_ACTIVITY_MS = 200; + /** How long we wait until giving up on the activity telling us it released the top state. */ private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT = 500; @@ -1933,13 +1936,15 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { boolean processPausingActivities, String reason) { // Stop any activities that are scheduled to do so but have been waiting for the transition // animation to finish. + boolean displaySwapping = false; ArrayList<ActivityRecord> readyToStopActivities = null; for (int i = mStoppingActivities.size() - 1; i >= 0; --i) { final ActivityRecord s = mStoppingActivities.get(i); final boolean animating = s.isInTransition(); + displaySwapping |= s.isDisplaySleepingAndSwapping(); ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b " + "finishing=%s", s, s.nowVisible, animating, s.finishing); - if (!animating || mService.mShuttingDown) { + if ((!animating && !displaySwapping) || mService.mShuttingDown) { if (!processPausingActivities && s.isState(PAUSING)) { // Defer processing pausing activities in this iteration and reschedule // a delayed idle to reprocess it again @@ -1958,6 +1963,16 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { } } + // Stopping activities are deferred processing if the display is swapping. Check again + // later to ensure the stopping activities can be stopped after display swapped. + if (displaySwapping) { + mHandler.postDelayed(() -> { + synchronized (mService.mGlobalLock) { + scheduleProcessStoppingAndFinishingActivitiesIfNeeded(); + } + }, SCHEDULE_FINISHING_STOPPING_ACTIVITY_MS); + } + final int numReadyStops = readyToStopActivities == null ? 0 : readyToStopActivities.size(); for (int i = 0; i < numReadyStops; i++) { final ActivityRecord r = readyToStopActivities.get(i); diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 0a1e29ace045..6107aa73b32e 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -123,6 +123,7 @@ public class DisplayRotation { public final boolean isDefaultDisplay; private final boolean mSupportAutoRotation; + private final boolean mAllowRotationResolver; private final int mLidOpenRotation; private final int mCarDockRotation; private final int mDeskDockRotation; @@ -265,6 +266,8 @@ public class DisplayRotation { mSupportAutoRotation = mContext.getResources().getBoolean(R.bool.config_supportAutoRotation); + mAllowRotationResolver = + mContext.getResources().getBoolean(R.bool.config_allowRotationResolver); mLidOpenRotation = readRotation(R.integer.config_lidOpenRotation); mCarDockRotation = readRotation(R.integer.config_carDockRotation); mDeskDockRotation = readRotation(R.integer.config_deskDockRotation); @@ -913,6 +916,16 @@ public class DisplayRotation { } void freezeRotation(int rotation) { + if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()) { + // Flipping 270 and 90 has the same effect as changing the direction which rotation is + // applied. + if (rotation == Surface.ROTATION_90) { + rotation = Surface.ROTATION_270; + } else if (rotation == Surface.ROTATION_270) { + rotation = Surface.ROTATION_90; + } + } + rotation = (rotation == -1) ? mRotation : rotation; setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation); } @@ -1992,7 +2005,8 @@ public class DisplayRotation { @Override public boolean isRotationResolverEnabled() { - return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE + return mAllowRotationResolver + && mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE && mCameraRotationMode == CAMERA_ROTATION_ENABLED && !mService.mPowerManager.isPowerSaveMode(); } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index a4e08dfb1e3b..76afdc387dbd 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2569,6 +2569,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } SleepToken createSleepToken(String tag, int displayId) { + return createSleepToken(tag, displayId, false /* isSwappingDisplay */); + } + + SleepToken createSleepToken(String tag, int displayId, boolean isSwappingDisplay) { final DisplayContent display = getDisplayContent(displayId); if (display == null) { throw new IllegalArgumentException("Invalid display: " + displayId); @@ -2577,7 +2581,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final int tokenKey = makeSleepTokenKey(tag, displayId); SleepToken token = mSleepTokens.get(tokenKey); if (token == null) { - token = new SleepToken(tag, displayId); + token = new SleepToken(tag, displayId, isSwappingDisplay); mSleepTokens.put(tokenKey, token); display.mAllSleepTokens.add(token); ProtoLog.d(WM_DEBUG_STATES, "Create sleep token: tag=%s, displayId=%d", tag, displayId); @@ -3526,18 +3530,34 @@ class RootWindowContainer extends WindowContainer<DisplayContent> private final String mTag; private final long mAcquireTime; private final int mDisplayId; + private final boolean mIsSwappingDisplay; final int mHashKey; - SleepToken(String tag, int displayId) { + // The display could remain in sleep after the physical display swapped, adding a 1 + // seconds display swap timeout to prevent activities staying in PAUSED state. + // Otherwise, the sleep token should be removed once display turns back on after swapped. + private static final long DISPLAY_SWAP_TIMEOUT = 1000; + + SleepToken(String tag, int displayId, boolean isSwappingDisplay) { mTag = tag; mDisplayId = displayId; mAcquireTime = SystemClock.uptimeMillis(); + mIsSwappingDisplay = isSwappingDisplay; mHashKey = makeSleepTokenKey(mTag, mDisplayId); } + public boolean isDisplaySwapping() { + long now = SystemClock.uptimeMillis(); + if (now - mAcquireTime > DISPLAY_SWAP_TIMEOUT) { + return false; + } + return mIsSwappingDisplay; + } + @Override public String toString() { return "{\"" + mTag + "\", display " + mDisplayId + + (mIsSwappingDisplay ? " is swapping " : "") + ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}"; } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java index 950e9e4848b0..a831b270dbd9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -537,6 +537,24 @@ public class DisplayRotationTests { SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_180)); } + @Test + public void testFreezeRotation_reverseRotationDirectionAroundZAxis_yes() throws Exception { + mBuilder.build(); + when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()).thenReturn(true); + + freezeRotation(Surface.ROTATION_90); + assertEquals(Surface.ROTATION_270, mTarget.getUserRotation()); + } + + @Test + public void testFreezeRotation_reverseRotationDirectionAroundZAxis_no() throws Exception { + mBuilder.build(); + when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()).thenReturn(false); + + freezeRotation(Surface.ROTATION_90); + assertEquals(Surface.ROTATION_90, mTarget.getUserRotation()); + } + private boolean waitForUiHandler() { final CountDownLatch latch = new CountDownLatch(1); UiThread.getHandler().post(latch::countDown); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index e2db2e6b19e1..148dd8dfd25a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -147,7 +147,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public void screenTurnedOff(int displayId) { + public void screenTurnedOff(int displayId, boolean isSwappingDisplay) { } @Override |