diff options
| author | 2016-09-29 15:25:00 -0700 | |
|---|---|---|
| committer | 2016-09-29 16:44:38 -0700 | |
| commit | 441e4494682144aec2ec7f19060464af3d29c319 (patch) | |
| tree | cb11b73a90b6f21d69c3f055a6780327a5d2d849 | |
| parent | 015deed8104aae1f306394cdf66088592995f0da (diff) | |
Add override and merged config to WindowContainer
This consolidates usages of override and full (merged)
configs in WM objects and also adds support of per-display
configurations. Having full configs allows us to get
current applied config at any level.
Test: Manual tests pass. Added some new to WindowContainerTests.
Change-Id: I996770433c80da41265f3e14048bd23cead097f9
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; |