Move orientation request into hierarchy.
This CL also removes a hidden method in IWindowManager that's only used
inside of WM right now.
Also wire up Task level logic.
Bug: 113252523
Test: Manual test that app requested orientation still rotates the
display and WmTests.
Change-Id: I7c5046e9beaea79de4ec471eabc792e3593583a2
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4d8440a8..2cd0168 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2486,36 +2486,20 @@
}
void setRequestedOrientation(int requestedOrientation) {
- final int displayId = getDisplayId();
- final Configuration displayConfig =
- mRootActivityContainer.getDisplayOverrideConfiguration(displayId);
-
- final Configuration config = setOrientation(requestedOrientation,
- displayId, displayConfig, mayFreezeScreenLocked(app));
- if (config != null) {
- frozenBeforeDestroy = true;
- if (!mAtmService.updateDisplayOverrideConfigurationLocked(config, this,
- false /* deferResume */, displayId)) {
- mRootActivityContainer.resumeFocusedStacksTopActivities();
- }
- }
+ setOrientation(requestedOrientation, mayFreezeScreenLocked(app));
mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
task.taskId, requestedOrientation);
}
- Configuration setOrientation(int requestedOrientation, int displayId,
- Configuration displayConfig, boolean freezeScreenIfNeeded) {
+ private void setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded) {
if (mAppWindowToken == null) {
Slog.w(TAG_WM,
"Attempted to set orientation of non-existing app token: " + appToken);
- return null;
+ return;
}
- mAppWindowToken.setOrientation(requestedOrientation);
-
final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null;
- return mAtmService.mWindowManager.updateOrientationFromAppTokens(displayConfig, binder,
- displayId);
+ mAppWindowToken.setOrientation(requestedOrientation, binder, this);
}
int getOrientation() {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1943efc..a5ceee2 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -397,10 +397,11 @@
private final Matrix mTmpMatrix = new Matrix();
private final Region mTmpRegion = new Region();
-
/** Used for handing back size of display */
private final Rect mTmpBounds = new Rect();
+ private final Configuration mTmpConfiguration = new Configuration();
+
/** Remove this display when animation on it has completed. */
private boolean mDeferredRemoval;
@@ -1156,6 +1157,36 @@
mWmService.mH.obtainMessage(SEND_NEW_CONFIGURATION, this).sendToTarget();
}
+ @Override
+ boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
+ ConfigurationContainer requestingContainer) {
+ final Configuration config = updateOrientationFromAppTokens(
+ getRequestedOverrideConfiguration(), freezeDisplayToken, false);
+ // If display rotation class tells us that it doesn't consider app requested orientation,
+ // this display won't rotate just because of an app changes its requested orientation. Thus
+ // it indicates that this display chooses not to handle this request.
+ final boolean handled = getDisplayRotation().respectAppRequestedOrientation();
+ if (config == null) {
+ return handled;
+ }
+
+ if (handled && requestingContainer instanceof ActivityRecord) {
+ final ActivityRecord activityRecord = (ActivityRecord) requestingContainer;
+ final boolean kept = mWmService.mAtmService.updateDisplayOverrideConfigurationLocked(
+ config, activityRecord, false /* deferResume */, getDisplayId());
+ activityRecord.frozenBeforeDestroy = true;
+ if (!kept) {
+ mWmService.mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
+ }
+ } else {
+ // We have a new configuration to push so we need to update ATMS for now.
+ // TODO: Clean up display configuration push between ATMS and WMS after unification.
+ mWmService.mAtmService.updateDisplayOverrideConfigurationLocked(
+ config, null /* starting */, false /* deferResume */, getDisplayId());
+ }
+ return handled;
+ }
+
/**
* Determine the new desired orientation of this display.
*
@@ -1169,7 +1200,56 @@
return updateOrientationFromAppTokens(false /* forceUpdate */);
}
- boolean updateOrientationFromAppTokens(boolean forceUpdate) {
+ /**
+ * Update orientation of the target display, returning a non-null new Configuration if it has
+ * changed from the current orientation. If a non-null configuration is returned, someone must
+ * call {@link WindowManagerService#setNewDisplayOverrideConfiguration(Configuration,
+ * DisplayContent)} to tell the window manager it can unfreeze the screen. This will typically
+ * be done by calling {@link WindowManagerService#sendNewConfiguration(int)}.
+ */
+ Configuration updateOrientationFromAppTokens(Configuration currentConfig,
+ IBinder freezeDisplayToken, boolean forceUpdate) {
+ if (!mDisplayReady) {
+ return null;
+ }
+
+ Configuration config = null;
+ if (updateOrientationFromAppTokens(forceUpdate)) {
+ // If we changed the orientation but mOrientationChangeComplete is already true,
+ // we used seamless rotation, and we don't need to freeze the screen.
+ if (freezeDisplayToken != null && !mWmService.mRoot.mOrientationChangeComplete) {
+ final AppWindowToken atoken = getAppWindowToken(freezeDisplayToken);
+ if (atoken != null) {
+ atoken.startFreezingScreen();
+ }
+ }
+ config = new Configuration();
+ computeScreenConfiguration(config);
+ } else if (currentConfig != null) {
+ // No obvious action we need to take, but if our current state mismatches the
+ // activity manager's, update it, disregarding font scale, which should remain set
+ // to the value of the previous configuration.
+ // Here we're calling Configuration#unset() instead of setToDefaults() because we
+ // need to keep override configs clear of non-empty values (e.g. fontSize).
+ mTmpConfiguration.unset();
+ mTmpConfiguration.updateFrom(currentConfig);
+ computeScreenConfiguration(mTmpConfiguration);
+ if (currentConfig.diff(mTmpConfiguration) != 0) {
+ mWaitingForConfig = true;
+ setLayoutNeeded();
+ int[] anim = new int[2];
+ getDisplayPolicy().selectRotationAnimationLw(anim);
+
+ mWmService.startFreezingDisplayLocked(anim[0], anim[1], this);
+ config = new Configuration(mTmpConfiguration);
+ }
+ }
+
+ return config;
+ }
+
+
+ private boolean updateOrientationFromAppTokens(boolean forceUpdate) {
final int req = getOrientation();
if (req != mLastOrientation || forceUpdate) {
mLastOrientation = req;
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 7aabc15..bcc7be4 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -329,6 +329,15 @@
return mFixedToUserRotation;
}
+ /**
+ * Returns {@code true} if this display rotation takes app requested orientation into
+ * consideration; {@code false} otherwise. For the time being the only case where this is {@code
+ * false} is when {@link #isFixedToUserRotation()} is {@code true}.
+ */
+ boolean respectAppRequestedOrientation() {
+ return !mFixedToUserRotation;
+ }
+
public int getLandscapeRotation() {
return mLandscapeRotation;
}
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 8ec97c5..325f95f 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -597,11 +597,15 @@
// Force-update the orientation from the WindowManager, since we need the true configuration
// to send to the client now.
- final Configuration config = mWindowManager.updateOrientationFromAppTokens(
- getDisplayOverrideConfiguration(displayId),
- starting != null && starting.mayFreezeScreenLocked(starting.app)
- ? starting.appToken : null,
- displayId, true /* forceUpdate */);
+ final DisplayContent displayContent = mRootWindowContainer.getDisplayContent(displayId);
+ Configuration config = null;
+ if (displayContent != null) {
+ config = displayContent.updateOrientationFromAppTokens(
+ getDisplayOverrideConfiguration(displayId),
+ starting != null && starting.mayFreezeScreenLocked(starting.app)
+ ? starting.appToken : null,
+ true /* forceUpdate */);
+ }
if (starting != null && markFrozenIfConfigChanged && config != null) {
starting.frozenBeforeDestroy = true;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b10fd31..d334bd2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -44,6 +44,7 @@
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.IBinder;
import android.util.EventLog;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -328,6 +329,23 @@
return boundsChange;
}
+ @Override
+ public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
+ ConfigurationContainer requestingContainer) {
+ if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) {
+ return true;
+ }
+
+ // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
+ // it if possible.
+ // TODO: Move to TaskRecord after unification is done.
+ if (mTaskRecord != null) {
+ mTaskRecord.onConfigurationChanged(mTaskRecord.getParent().getConfiguration());
+ return true;
+ }
+ return false;
+ }
+
void resize(boolean relayout, boolean forced) {
if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) {
getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 651089d..32c5a3b 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -31,10 +31,12 @@
import android.annotation.CallSuper;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.IBinder;
import android.util.Pools;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -698,8 +700,58 @@
}
}
+ /**
+ * Called when this container or one of its descendants changed its requested orientation, and
+ * wants this container to handle it or pass it to its parent.
+ *
+ * @param freezeDisplayToken freeze this app window token if display needs to freeze
+ * @param requestingContainer the container which orientation request has changed
+ * @return {@code true} if handled; {@code false} otherwise.
+ */
+ boolean onDescendantOrientationChanged(@Nullable IBinder freezeDisplayToken,
+ @Nullable ConfigurationContainer requestingContainer) {
+ final WindowContainer parent = getParent();
+ if (parent == null) {
+ return false;
+ }
+ return parent.onDescendantOrientationChanged(freezeDisplayToken,
+ requestingContainer);
+ }
+
+ /**
+ * Calls {@link #setOrientation(int, IBinder, ActivityRecord)} with {@code null} to the last 2
+ * parameters.
+ *
+ * @param orientation the specified orientation.
+ */
void setOrientation(int orientation) {
+ setOrientation(orientation, null /* freezeDisplayToken */,
+ null /* ActivityRecord */);
+ }
+
+ /**
+ * Sets the specified orientation of this container. It percolates this change upward along the
+ * hierarchy to let each level of the hierarchy a chance to respond to it.
+ *
+ * @param orientation the specified orientation. Needs to be one of {@link
+ * android.content.pm.ActivityInfo.ScreenOrientation}.
+ * @param freezeDisplayToken uses this token to freeze display if orientation change is not
+ * done. Display will not be frozen if this is {@code null}, which
+ * should only happen in tests.
+ * @param requestingContainer the container which orientation request has changed. Mostly used
+ * to ensure it gets correct configuration.
+ */
+ void setOrientation(int orientation, @Nullable IBinder freezeDisplayToken,
+ @Nullable ConfigurationContainer requestingContainer) {
+ final boolean changed = mOrientation != orientation;
mOrientation = orientation;
+ if (!changed) {
+ return;
+ }
+ final WindowContainer parent = getParent();
+ if (parent != null) {
+ onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
+ }
}
int getOrientation() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e3ced83..b6a4a51 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2383,85 +2383,6 @@
}
}
- @Override
- public Configuration updateOrientationFromAppTokens(Configuration currentConfig,
- IBinder freezeThisOneIfNeeded, int displayId) {
- return updateOrientationFromAppTokens(currentConfig, freezeThisOneIfNeeded, displayId,
- false /* forceUpdate */);
- }
-
- public Configuration updateOrientationFromAppTokens(Configuration currentConfig,
- IBinder freezeThisOneIfNeeded, int displayId, boolean forceUpdate) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "updateOrientationFromAppTokens()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- final Configuration config;
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded,
- displayId, forceUpdate);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- return config;
- }
-
- /**
- * Update orientation of the target display, returning a non-null new Configuration if it has
- * changed from the current orientation. If a non-null configuration is returned, someone must
- * call {@link #setNewDisplayOverrideConfiguration(Configuration, int)} to tell the window
- * manager it can unfreeze the screen. This will typically be done by calling
- * {@link #sendNewConfiguration(int)}.
- *
- * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
- */
- private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig,
- IBinder freezeThisOneIfNeeded, int displayId, boolean forceUpdate) {
- if (!mDisplayReady) {
- return null;
- }
- Configuration config = null;
-
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc != null && dc.updateOrientationFromAppTokens(forceUpdate)) {
- // If we changed the orientation but mOrientationChangeComplete is already true,
- // we used seamless rotation, and we don't need to freeze the screen.
- if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
- final AppWindowToken atoken = mRoot.getAppWindowToken(freezeThisOneIfNeeded);
- if (atoken != null) {
- atoken.startFreezingScreen();
- }
- }
- config = computeNewConfigurationLocked(displayId);
-
- } else if (currentConfig != null) {
- // No obvious action we need to take, but if our current state mismatches the activity
- // manager's, update it, disregarding font scale, which should remain set to the value
- // of the previous configuration.
- // Here we're calling Configuration#unset() instead of setToDefaults() because we need
- // to keep override configs clear of non-empty values (e.g. fontSize).
- mTempConfiguration.unset();
- mTempConfiguration.updateFrom(currentConfig);
- final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- displayContent.computeScreenConfiguration(mTempConfiguration);
- if (currentConfig.diff(mTempConfiguration) != 0) {
- displayContent.mWaitingForConfig = true;
- displayContent.setLayoutNeeded();
- int anim[] = new int[2];
- displayContent.getDisplayPolicy().selectRotationAnimationLw(anim);
-
- startFreezingDisplayLocked(anim[0], anim[1], displayContent);
- config = new Configuration(mTempConfiguration);
- }
- }
-
- return config;
- }
-
void setNewDisplayOverrideConfiguration(Configuration overrideConfig,
@NonNull DisplayContent dc) {
if (dc.mWaitingForConfig) {