summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-04-28 16:02:56 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-04-28 16:02:56 +0000
commit958a1009551942c8a44a580b44bda0a011206eca (patch)
tree800bdec2e564423d50ef1bc5fa2adab53823ccde
parent0dcdc69a57d48b2e63fa7e8af0ab78f30bae6e74 (diff)
parent19ce8d14c4ca3a0db001c4f8f43a9547e6e92f68 (diff)
downloadbase-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
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java60
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java19
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java6
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java19
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java28
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java4
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java10
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java10
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java17
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java16
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java2
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