summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java4
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java17
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java4
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java23
-rw-r--r--services/core/java/com/android/server/wm/Task.java32
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java114
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java38
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java157
12 files changed, 339 insertions, 83 deletions
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ba26e13f69c3..c00da8c90cc1 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -729,9 +729,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
if (mTask.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
// We didn't call prepareFreezingBounds on the task, so use the current value.
- final Configuration config = new Configuration(mService.mGlobalConfiguration);
- config.updateFrom(mTask.mOverrideConfig);
- mFrozenMergedConfig.offer(config);
+ mFrozenMergedConfig.offer(new Configuration(mTask.getConfiguration()));
} else {
mFrozenMergedConfig.offer(new Configuration(mTask.mPreparedFrozenMergedConfig));
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a09c5976e2ec..c4071ab13a6a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -45,6 +45,7 @@ import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
import android.annotation.NonNull;
import android.app.ActivityManager.StackId;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Region.Op;
@@ -208,18 +209,26 @@ class DisplayContent extends WindowContainer<TaskStack> {
return null;
}
- /** Callback used to notify about configuration changes. */
- void onConfigurationChanged(@NonNull List<Integer> changedStackList) {
+ @Override
+ void onConfigurationChanged(Configuration newParentConfig) {
+ super.onConfigurationChanged(newParentConfig);
+
// The display size information is heavily dependent on the resources in the current
// configuration, so we need to reconfigure it every time the configuration changes.
// See {@link PhoneWindowManager#setInitialDisplaySize}...sigh...
mService.reconfigureDisplayLocked(this);
getDockedDividerController().onConfigurationChanged();
+ }
- for (int i = 0; i < mChildren.size(); i++) {
+ /**
+ * Callback used to trigger bounds update after configuration change and get ids of stacks whose
+ * bounds were updated.
+ */
+ void updateStackBoundsAfterConfigChange(@NonNull List<Integer> changedStackList) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
final TaskStack stack = mChildren.get(i);
- if (stack.onConfigurationChanged()) {
+ if (stack.updateBoundsAfterConfigChange()) {
changedStackList.add(stack.mStackId);
}
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ef8f492f5a6f..15a952dd385e 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -153,7 +153,7 @@ public class DockedStackDividerController implements DimLayerUser {
// If the bounds are fullscreen, return the value of the fullscreen configuration
if (bounds == null || (bounds.left == 0 && bounds.top == 0
&& bounds.right == di.logicalWidth && bounds.bottom == di.logicalHeight)) {
- return mService.mGlobalConfiguration.smallestScreenWidthDp;
+ return mDisplayContent.getConfiguration().smallestScreenWidthDp;
}
final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
@@ -190,7 +190,7 @@ public class DockedStackDividerController implements DimLayerUser {
}
private void initSnapAlgorithmForRotations() {
- final Configuration baseConfig = mService.mGlobalConfiguration;
+ final Configuration baseConfig = mDisplayContent.getConfiguration();
// Initialize the snap algorithms for all 4 screen orientations.
final Configuration config = new Configuration();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8f533fb1ac61..af5f35ce95bd 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -347,18 +347,35 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
}
}
- int[] onConfigurationChanged(Configuration config) {
+ /** Set new config and return array of ids of stacks that were changed during update. */
+ int[] setGlobalConfigurationIfNeeded(Configuration newConfiguration) {
+ final boolean configChanged = getConfiguration().diff(newConfiguration) != 0;
+ if (!configChanged) {
+ return null;
+ }
+ onConfigurationChanged(newConfiguration);
+ return updateStackBoundsAfterConfigChange();
+ }
+
+ @Override
+ void onConfigurationChanged(Configuration newParentConfig) {
prepareFreezingTaskBounds();
- mService.mGlobalConfiguration = new Configuration(config);
+ super.onConfigurationChanged(newParentConfig);
mService.mPolicy.onConfigurationChanged();
+ }
+ /**
+ * Callback used to trigger bounds update after configuration change and get ids of stacks whose
+ * bounds were updated.
+ */
+ int[] updateStackBoundsAfterConfigChange() {
mChangedStackList.clear();
final int numDisplays = mChildren.size();
for (int i = 0; i < numDisplays; ++i) {
final DisplayContent dc = mChildren.get(i);
- dc.onConfigurationChanged(mChangedStackList);
+ dc.updateStackBoundsAfterConfigChange(mChangedStackList);
}
return mChangedStackList.isEmpty() ? null : ArrayUtils.convertToIntArray(mChangedStackList);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9e8c6091909e..f6598c14da44 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -70,12 +70,6 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
// Whether mBounds is fullscreen
private boolean mFillsParent = true;
- /**
- * Contains configurations settings that are different from the parent configuration due to
- * stack specific operations. E.g. {@link #setBounds}.
- */
- Configuration mOverrideConfig = Configuration.EMPTY;
-
// For comparison with DisplayContent bounds.
private Rect mTmpRect = new Rect();
// For handling display rotations.
@@ -120,8 +114,9 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
}
}
- if (wtoken.mParent != null) {
- wtoken.mParent.removeChild(wtoken);
+ final WindowContainer parent = wtoken.getParent();
+ if (parent != null) {
+ parent.removeChild(wtoken);
}
addChild(wtoken, addPos);
wtoken.mTask = this;
@@ -153,7 +148,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
if (content != null) {
content.mDimLayerController.removeDimLayerUser(this);
}
- mParent.removeChild(this);
+ getParent().removeChild(this);
mService.mTaskIdToTask.delete(mTaskId);
}
@@ -165,7 +160,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
+ " from stack=" + mStack);
EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
- mParent.removeChild(this);
+ getParent().removeChild(this);
stack.addTask(this, toTop);
}
@@ -254,7 +249,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
if (displayContent != null) {
displayContent.mDimLayerController.updateDimLayer(this);
}
- mOverrideConfig = mFillsParent ? Configuration.EMPTY : overrideConfig;
+ onOverrideConfigurationChanged(mFillsParent ? Configuration.EMPTY : overrideConfig);
return boundsChange;
}
@@ -321,8 +316,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
*/
void prepareFreezingBounds() {
mPreparedFrozenBounds.set(mBounds);
- mPreparedFrozenMergedConfig.setTo(mService.mGlobalConfiguration);
- mPreparedFrozenMergedConfig.updateFrom(mOverrideConfig);
+ mPreparedFrozenMergedConfig.setTo(getConfiguration());
}
/**
@@ -334,9 +328,9 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
* bounds's bottom; false if the task's top should be aligned
* the adjusted bounds's top.
*/
- void alignToAdjustedBounds(
- Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
- if (!isResizeable() || mOverrideConfig == Configuration.EMPTY) {
+ void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
+ final Configuration overrideConfig = getOverrideConfiguration();
+ if (!isResizeable() || Configuration.EMPTY.equals(overrideConfig)) {
return;
}
@@ -348,7 +342,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
}
setTempInsetBounds(tempInsetBounds);
- resizeLocked(mTmpRect2, mOverrideConfig, false /* forced */);
+ resizeLocked(mTmpRect2, overrideConfig, false /* forced */);
}
/** Return true if the current bound can get outputted to the rest of the system as-is. */
@@ -500,12 +494,12 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
mTmpRect2.set(mBounds);
if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
- setBounds(mTmpRect2, mOverrideConfig);
+ setBounds(mTmpRect2, getOverrideConfiguration());
return;
}
displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
- if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
+ if (setBounds(mTmpRect2, getOverrideConfiguration()) != BOUNDS_CHANGE_NONE) {
// Post message to inform activity manager of the bounds change simulating a one-way
// call. We do this to prevent a deadlock between window manager lock and activity
// manager lock been held.
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 21db840ad255..688731256f89 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -478,7 +478,7 @@ class TaskPositioner implements DimLayer.DimLayerUser {
private int getDimSide(int x) {
if (mTask.mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID
|| !mTask.mStack.fillsParent()
- || mService.mGlobalConfiguration.orientation != ORIENTATION_LANDSCAPE) {
+ || mTask.mStack.getConfiguration().orientation != ORIENTATION_LANDSCAPE) {
return CTRL_NONE;
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index e374185e7210..179cfd5c6454 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -354,11 +354,8 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
// If the rotation or density didn't match, we'll update it in onConfigurationChanged.
}
- boolean onConfigurationChanged() {
- return updateBoundsAfterConfigChange();
- }
-
- private boolean updateBoundsAfterConfigChange() {
+ /** @return true if bounds were updated to some non-empty value. */
+ boolean updateBoundsAfterConfigChange() {
if (mDisplayContent == null) {
// If the stack is already detached we're not updating anything,
// as it's going away soon anyway.
@@ -459,7 +456,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
// Snap the position to a target.
final int rotation = displayInfo.rotation;
- final int orientation = mService.mGlobalConfiguration.orientation;
+ final int orientation = mDisplayContent.getConfiguration().orientation;
mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
mService.mContext.getResources(), displayWidth, displayHeight,
@@ -713,7 +710,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
di.logicalWidth,
di.logicalHeight,
dockDividerWidth,
- mService.mGlobalConfiguration.orientation == ORIENTATION_PORTRAIT,
+ mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT,
mTmpRect2).getMiddleTarget().position;
if (dockOnTopOrLeft) {
@@ -1182,7 +1179,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
return DOCKED_INVALID;
}
mDisplayContent.getLogicalDisplayRect(mTmpRect);
- final int orientation = mService.mGlobalConfiguration.orientation;
+ final int orientation = mDisplayContent.getConfiguration().orientation;
return getDockSideUnchecked(bounds, mTmpRect, orientation);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index af0fbd3ba24a..8777d88a8777 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import android.annotation.CallSuper;
+import android.content.res.Configuration;
import android.view.animation.Animation;
import java.util.Comparator;
@@ -34,13 +35,33 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
*/
class WindowContainer<E extends WindowContainer> implements Comparable<WindowContainer> {
- // The parent of this window container.
- protected WindowContainer mParent = null;
+ /**
+ * The parent of this window container.
+ * For removing or setting new parent {@link #setParent} should be used, because it also
+ * performs configuration updates based on new parent's settings.
+ */
+ private WindowContainer mParent = null;
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
protected final LinkedList<E> mChildren = new LinkedList();
+ /** Contains override configuration settings applied to this window container. */
+ private Configuration mOverrideConfiguration = new Configuration();
+
+ /**
+ * Contains full configuration applied to this window container. Corresponds to full parent's
+ * config with applied {@link #mOverrideConfiguration}.
+ */
+ private Configuration mFullConfiguration = new Configuration();
+
+ /**
+ * Contains merged override configuration settings from the top of the hierarchy down to this
+ * particular instance. It is different from {@link #mFullConfiguration} because it starts from
+ * topmost container's override config instead of global config.
+ */
+ private Configuration mMergedOverrideConfiguration = new Configuration();
+
// The specified orientation for this window container.
protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
@@ -48,6 +69,14 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon
return mParent;
}
+ final protected void setParent(WindowContainer parent) {
+ mParent = parent;
+ // Update full configuration of this container and all its children.
+ onConfigurationChanged(mParent != null ? mParent.mFullConfiguration : Configuration.EMPTY);
+ // Update merged override configuration of this container and all its children.
+ onMergedOverrideConfigurationChanged();
+ }
+
// Temp. holders for a chain of containers we are currently processing.
private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList();
private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList();
@@ -61,12 +90,12 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon
*/
@CallSuper
protected void addChild(E child, Comparator<E> comparator) {
- if (child.mParent != null) {
+ if (child.getParent() != null) {
throw new IllegalArgumentException("addChild: container=" + child.getName()
- + " is already a child of container=" + child.mParent.getName()
+ + " is already a child of container=" + child.getParent().getName()
+ " can't add to container=" + getName());
}
- child.mParent = this;
+ child.setParent(this);
if (mChildren.isEmpty() || comparator == null) {
mChildren.add(child);
@@ -87,12 +116,12 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon
/** Adds the input window container has a child of this container at the input index. */
@CallSuper
protected void addChild(E child, int index) {
- if (child.mParent != null) {
+ if (child.getParent() != null) {
throw new IllegalArgumentException("addChild: container=" + child.getName()
- + " is already a child of container=" + child.mParent.getName()
+ + " is already a child of container=" + child.getParent().getName()
+ " can't add to container=" + getName());
}
- child.mParent = this;
+ child.setParent(this);
mChildren.add(index, child);
}
@@ -104,7 +133,7 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon
@CallSuper
void removeChild(E child) {
if (mChildren.remove(child)) {
- child.mParent = null;
+ child.setParent(null);
} else {
throw new IllegalArgumentException("removeChild: container=" + child.getName()
+ " is not a child of container=" + getName());
@@ -158,6 +187,73 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon
return false;
}
+ /**
+ * Returns full configuration applied to this window container.
+ * This method should be used for getting settings applied in each particular level of the
+ * hierarchy.
+ */
+ Configuration getConfiguration() {
+ return mFullConfiguration;
+ }
+
+ /**
+ * Notify that parent config changed and we need to update full configuration.
+ * @see #mFullConfiguration
+ */
+ void onConfigurationChanged(Configuration newParentConfig) {
+ mFullConfiguration.setTo(newParentConfig);
+ mFullConfiguration.updateFrom(mOverrideConfiguration);
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ child.onConfigurationChanged(mFullConfiguration);
+ }
+ }
+
+ /** Returns override configuration applied to this window container. */
+ Configuration getOverrideConfiguration() {
+ return mOverrideConfiguration;
+ }
+
+ /**
+ * Update override configuration and recalculate full config.
+ * @see #mOverrideConfiguration
+ * @see #mFullConfiguration
+ */
+ void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
+ mOverrideConfiguration.setTo(overrideConfiguration);
+ // Update full configuration of this container and all its children.
+ onConfigurationChanged(mParent != null ? mParent.getConfiguration() : Configuration.EMPTY);
+ // Update merged override config of this container and all its children.
+ onMergedOverrideConfigurationChanged();
+ }
+
+ /**
+ * Get merged override configuration from the top of the hierarchy down to this
+ * particular instance. This should be reported to client as override config.
+ */
+ Configuration getMergedOverrideConfiguration() {
+ return mMergedOverrideConfiguration;
+ }
+
+ /**
+ * Update merged override configuration based on corresponding parent's config and notify all
+ * its children. If there is no parent, merged override configuration will set equal to current
+ * override config.
+ * @see #mMergedOverrideConfiguration
+ */
+ private void onMergedOverrideConfigurationChanged() {
+ if (mParent != null) {
+ mMergedOverrideConfiguration.setTo(mParent.getMergedOverrideConfiguration());
+ mMergedOverrideConfiguration.updateFrom(mOverrideConfiguration);
+ } else {
+ mMergedOverrideConfiguration.setTo(mOverrideConfiguration);
+ }
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ child.onMergedOverrideConfigurationChanged();
+ }
+ }
+
void setWaitingForDrawnIfResizingChanged() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1ed4055746b8..b9f3d5ac047e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -592,12 +592,6 @@ public class WindowManagerService extends IWindowManager.Stub
// State while inside of layoutAndPlaceSurfacesLocked().
boolean mFocusMayChange;
- /**
- * Current global configuration information. Contains general settings for the entire system,
- * corresponds to the configuration of the default display.
- */
- Configuration mGlobalConfiguration = new Configuration();
-
// This is held as long as we have the screen frozen, to give us time to
// perform a rotation animation when turning off shows the lock screen which
// changes the orientation.
@@ -2674,7 +2668,8 @@ public class WindowManagerService extends IWindowManager.Stub
// is running.
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
if (okToDisplay()) {
- DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
+ final DisplayContent displayContent = atoken.mTask.getDisplayContent();
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int width = displayInfo.appWidth;
final int height = displayInfo.appHeight;
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG_WM,
@@ -2711,10 +2706,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "Loading animation for app transition."
+ " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
+ " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
- Animation a = mAppTransition.loadAnimation(lp, transit, enter,
- mGlobalConfiguration.uiMode, mGlobalConfiguration.orientation, frame,
- displayFrame, insets, surfaceInsets, isVoiceInteraction, freeform,
- atoken.mTask.mTaskId);
+ final Configuration displayConfig = displayContent.getConfiguration();
+ Animation a = mAppTransition.loadAnimation(lp, transit, enter, displayConfig.uiMode,
+ displayConfig.orientation, frame, displayFrame, insets, surfaceInsets,
+ isVoiceInteraction, freeform, atoken.mTask.mTaskId);
if (a != null) {
if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken);
final int containingWidth = frame.width();
@@ -3104,11 +3099,7 @@ public class WindowManagerService extends IWindowManager.Stub
mWaitingForConfig = false;
mLastFinishedFreezeSource = "new-config";
}
- final boolean configChanged = mGlobalConfiguration.diff(config) != 0;
- if (!configChanged) {
- return null;
- }
- return mRoot.onConfigurationChanged(config);
+ return mRoot.setGlobalConfigurationIfNeeded(config);
}
}
@@ -5595,7 +5586,7 @@ public class WindowManagerService extends IWindowManager.Stub
// the top of the method, the caller is obligated to call computeNewConfigurationLocked().
// By updating the Display info here it will be available to
// computeScreenConfigurationLocked later.
- updateDisplayAndOrientationLocked(mGlobalConfiguration.uiMode);
+ updateDisplayAndOrientationLocked(mRoot.getConfiguration().uiMode);
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (!inTransaction) {
@@ -6961,8 +6952,8 @@ public class WindowManagerService extends IWindowManager.Stub
View view = null;
try {
- final Configuration overrideConfig = wtoken != null && wtoken.mTask != null
- ? wtoken.mTask.mOverrideConfig : null;
+ final Configuration overrideConfig =
+ wtoken != null ? wtoken.getMergedOverrideConfiguration() : null;
view = mPolicy.addStartingWindow(wtoken.token, sd.pkg, sd.theme,
sd.compatInfo, sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo,
sd.windowFlags, overrideConfig);
@@ -7911,9 +7902,10 @@ public class WindowManagerService extends IWindowManager.Stub
displayContent.layoutNeeded = true;
boolean configChanged = updateOrientationFromAppTokensLocked(false);
- mTempConfiguration.setTo(mGlobalConfiguration);
+ final Configuration globalConfig = mRoot.getConfiguration();
+ mTempConfiguration.setTo(globalConfig);
computeScreenConfigurationLocked(mTempConfiguration);
- configChanged |= mGlobalConfiguration.diff(mTempConfiguration) != 0;
+ configChanged |= globalConfig.diff(mTempConfiguration) != 0;
if (configChanged) {
mWaitingForConfig = true;
@@ -8071,7 +8063,7 @@ public class WindowManagerService extends IWindowManager.Stub
w.setReportResizeHints();
boolean configChanged = w.isConfigChanged();
if (DEBUG_CONFIGURATION && configChanged) {
- Slog.v(TAG_WM, "Win " + w + " config changed: " + mGlobalConfiguration);
+ Slog.v(TAG_WM, "Win " + w + " config changed: " + w.getConfiguration());
}
final boolean dragResizingChanged = w.isDragResizeChanged()
&& !w.isDragResizingChangeReported();
@@ -8959,7 +8951,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
pw.println();
- pw.print(" mGlobalConfiguration="); pw.println(mGlobalConfiguration);
+ pw.print(" mGlobalConfiguration="); pw.println(mRoot.getConfiguration());
pw.print(" mHasPermanentDpad="); pw.println(mHasPermanentDpad);
pw.print(" mCurrentFocus="); pw.println(mCurrentFocus);
if (mLastFocus != mCurrentFocus) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c3affeb9a25c..df099dcb3aea 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2886,14 +2886,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
outConfig.setTo(mAppToken.mFrozenMergedConfig.peek());
return;
}
- final Task task = getTask();
- final Configuration overrideConfig = task != null
- ? task.mOverrideConfig
- : Configuration.EMPTY;
- outConfig.setTo(mService.mGlobalConfiguration);
- if (overrideConfig != Configuration.EMPTY) {
- outConfig.updateFrom(overrideConfig);
- }
+ outConfig.setTo(
+ mAppToken != null ? getConfiguration() : mDisplayContent.getConfiguration());
}
void reportResized() {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 6d10c5aaf34e..d1439f307df7 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -25,6 +25,7 @@ import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD
import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
+import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
@@ -233,7 +234,7 @@ class WindowSurfacePlacer {
}
mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mService.mRotation,
- mService.mGlobalConfiguration.uiMode);
+ displayContent.getConfiguration().uiMode);
if (isDefaultDisplay) {
// Not needed on non-default displays.
mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
@@ -840,13 +841,14 @@ class WindowSurfacePlacer {
Rect appRect = win != null ? win.getContentFrameLw() :
new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
Rect insets = win != null ? win.mContentInsets : null;
+ final Configuration displayConfig = displayContent.getConfiguration();
// For the new aspect-scaled transition, we want it to always show
// above the animating opening/closing window, and we want to
// synchronize its thumbnail surface with the surface for the
// open/close animation (only on the way down)
anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
- insets, thumbnailHeader, taskId, mService.mGlobalConfiguration.uiMode,
- mService.mGlobalConfiguration.orientation);
+ insets, thumbnailHeader, taskId, displayConfig.uiMode,
+ displayConfig.orientation);
openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
openingAppAnimator.deferThumbnailDestruction =
!mService.mAppTransition.isNextThumbnailTransitionScaleUp();
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index eb2372a03a96..6eb347ba7444 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import org.junit.Test;
import org.junit.runner.RunWith;
+import android.content.res.Configuration;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -28,6 +29,8 @@ import java.util.Comparator;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static org.junit.Assert.assertEquals;
@@ -377,6 +380,160 @@ public class WindowContainerTests {
assertEquals(1, child2223.compareTo(child21));
}
+ @Test
+ public void testConfigurationInit() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+
+ // Check root container initial config.
+ final TestWindowContainer root = builder.setLayer(0).build();
+ assertEquals(Configuration.EMPTY, root.getOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, root.getMergedOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, root.getConfiguration());
+
+ // Check child initial config.
+ final TestWindowContainer child1 = root.addChildWindow();
+ assertEquals(Configuration.EMPTY, child1.getOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, child1.getMergedOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, child1.getConfiguration());
+
+ // Check child initial config if root has overrides.
+ final Configuration rootOverrideConfig = new Configuration();
+ rootOverrideConfig.fontScale = 1.3f;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+ final TestWindowContainer child2 = root.addChildWindow();
+ assertEquals(Configuration.EMPTY, child2.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, child2.getMergedOverrideConfiguration());
+ assertEquals(rootOverrideConfig, child2.getConfiguration());
+
+ // Check child initial config if root has parent config set.
+ final Configuration rootParentConfig = new Configuration();
+ rootParentConfig.fontScale = 0.8f;
+ rootParentConfig.orientation = SCREEN_ORIENTATION_LANDSCAPE;
+ root.onConfigurationChanged(rootParentConfig);
+ final Configuration rootFullConfig = new Configuration(rootParentConfig);
+ rootFullConfig.updateFrom(rootOverrideConfig);
+
+ final TestWindowContainer child3 = root.addChildWindow();
+ assertEquals(Configuration.EMPTY, child3.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, child3.getMergedOverrideConfiguration());
+ assertEquals(rootFullConfig, child3.getConfiguration());
+ }
+
+ @Test
+ public void testConfigurationChangeOnAddRemove() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+
+ // Init root's config.
+ final TestWindowContainer root = builder.setLayer(0).build();
+ final Configuration rootOverrideConfig = new Configuration();
+ rootOverrideConfig.fontScale = 1.3f;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+ // Init child's config.
+ final TestWindowContainer child = root.addChildWindow();
+ final Configuration childOverrideConfig = new Configuration();
+ childOverrideConfig.densityDpi = 320;
+ child.onOverrideConfigurationChanged(childOverrideConfig);
+
+ // Check configuration update when child is removed from parent.
+ root.removeChild(child);
+ assertEquals(childOverrideConfig, child.getOverrideConfiguration());
+ assertEquals(childOverrideConfig, child.getMergedOverrideConfiguration());
+ assertEquals(childOverrideConfig, child.getConfiguration());
+
+ // It may be paranoia... but let's check if parent's config didn't change after removal.
+ assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getConfiguration());
+
+ // Check configuration update when child is added to parent.
+ final Configuration mergedOverrideConfig = new Configuration(root.getConfiguration());
+ mergedOverrideConfig.updateFrom(childOverrideConfig);
+ root.addChildWindow(child);
+ assertEquals(childOverrideConfig, child.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig, child.getMergedOverrideConfiguration());
+ assertEquals(mergedOverrideConfig, child.getConfiguration());
+ }
+
+ @Test
+ public void testConfigurationChangePropagation() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+
+ // Builds 3-level vertical hierarchy with one window container on each level.
+ // In addition to different overrides on each level, everyone in hierarchy will have one
+ // common overridden value - orientation;
+
+ // Init root's config.
+ final TestWindowContainer root = builder.setLayer(0).build();
+ final Configuration rootOverrideConfig = new Configuration();
+ rootOverrideConfig.fontScale = 1.3f;
+ rootOverrideConfig.orientation = SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+ // Init children.
+ final TestWindowContainer child1 = root.addChildWindow();
+ final Configuration childOverrideConfig1 = new Configuration();
+ childOverrideConfig1.densityDpi = 320;
+ childOverrideConfig1.orientation = SCREEN_ORIENTATION_LANDSCAPE;
+ child1.onOverrideConfigurationChanged(childOverrideConfig1);
+
+ final TestWindowContainer child2 = child1.addChildWindow();
+ final Configuration childOverrideConfig2 = new Configuration();
+ childOverrideConfig2.screenWidthDp = 150;
+ childOverrideConfig2.orientation = SCREEN_ORIENTATION_PORTRAIT;
+ child2.onOverrideConfigurationChanged(childOverrideConfig2);
+
+ // Check configuration on all levels when root override is updated.
+ rootOverrideConfig.smallestScreenWidthDp = 200;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+ final Configuration mergedOverrideConfig1 = new Configuration(rootOverrideConfig);
+ mergedOverrideConfig1.updateFrom(childOverrideConfig1);
+ final Configuration mergedConfig1 = new Configuration(mergedOverrideConfig1);
+
+ final Configuration mergedOverrideConfig2 = new Configuration(mergedOverrideConfig1);
+ mergedOverrideConfig2.updateFrom(childOverrideConfig2);
+ final Configuration mergedConfig2 = new Configuration(mergedOverrideConfig2);
+
+ assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getConfiguration());
+
+ assertEquals(childOverrideConfig1, child1.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig1, child1.getConfiguration());
+
+ assertEquals(childOverrideConfig2, child2.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig2, child2.getConfiguration());
+
+ // Check configuration on all levels when root parent config is updated.
+ final Configuration rootParentConfig = new Configuration();
+ rootParentConfig.screenHeightDp = 100;
+ rootParentConfig.orientation = SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+ root.onConfigurationChanged(rootParentConfig);
+ final Configuration mergedRootConfig = new Configuration(rootParentConfig);
+ mergedRootConfig.updateFrom(rootOverrideConfig);
+
+ mergedConfig1.setTo(mergedRootConfig);
+ mergedConfig1.updateFrom(mergedOverrideConfig1);
+
+ mergedConfig2.setTo(mergedConfig1);
+ mergedConfig2.updateFrom(mergedOverrideConfig2);
+
+ assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+ assertEquals(mergedRootConfig, root.getConfiguration());
+
+ assertEquals(childOverrideConfig1, child1.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig1, child1.getConfiguration());
+
+ assertEquals(childOverrideConfig2, child2.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig2, child2.getConfiguration());
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;