diff options
| -rw-r--r-- | services/core/java/com/android/server/wm/WindowState.java | 53 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java | 189 |
2 files changed, 216 insertions, 26 deletions
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index d7914545d8e3..59caa1433193 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -731,8 +731,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } @Override - public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf, Rect sf, - Rect osf) { + public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overscanFrame, + Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, + Rect outsetFrame) { if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) { // This window is being replaced and either already got information that it's being // removed or we are still waiting for some information. Because of this we don't @@ -768,10 +769,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final int layoutYDiff; if (fullscreenTask || layoutInParentFrame()) { // We use the parent frame as the containing frame for fullscreen and child windows - mContainingFrame.set(pf); - mDisplayFrame.set(df); - layoutDisplayFrame = df; - layoutContainingFrame = pf; + mContainingFrame.set(parentFrame); + mDisplayFrame.set(displayFrame); + layoutDisplayFrame = displayFrame; + layoutContainingFrame = parentFrame; layoutXDiff = 0; layoutYDiff = 0; } else { @@ -787,15 +788,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final WindowState imeWin = mService.mInputMethodWindow; // IME is up and obscuring this window. Adjust the window position so it is visible. if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this) { - if (windowsAreFloating && mContainingFrame.bottom > cf.bottom) { + if (windowsAreFloating && mContainingFrame.bottom > contentFrame.bottom) { // In freeform we want to move the top up directly. - // TODO: Investigate why this is cf not pf. - mContainingFrame.top -= mContainingFrame.bottom - cf.bottom; - } else if (mContainingFrame.bottom > pf.bottom) { + // TODO: Investigate why this is contentFrame not parentFrame. + mContainingFrame.top -= mContainingFrame.bottom - contentFrame.bottom; + } else if (mContainingFrame.bottom > parentFrame.bottom) { // But in docked we want to behave like fullscreen // and behave as if the task were given smaller bounds // for the purposes of layout. - mContainingFrame.bottom = pf.bottom; + mContainingFrame.bottom = parentFrame.bottom; } } @@ -804,7 +805,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // if it wasn't set already. No need to intersect it with the (visible) // "content frame" since it is allowed to be outside the visible desktop. if (mContainingFrame.isEmpty()) { - mContainingFrame.set(cf); + mContainingFrame.set(contentFrame); } } mDisplayFrame.set(mContainingFrame); @@ -812,22 +813,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP layoutYDiff = !mInsetFrame.isEmpty() ? mInsetFrame.top - mContainingFrame.top : 0; layoutContainingFrame = !mInsetFrame.isEmpty() ? mInsetFrame : mContainingFrame; mTmpRect.set(0, 0, dc.getDisplayInfo().logicalWidth, dc.getDisplayInfo().logicalHeight); - subtractInsets(mDisplayFrame, layoutContainingFrame, df, mTmpRect); + subtractInsets(mDisplayFrame, layoutContainingFrame, displayFrame, mTmpRect); if (!layoutInParentFrame()) { - subtractInsets(mContainingFrame, layoutContainingFrame, pf, mTmpRect); - subtractInsets(mInsetFrame, layoutContainingFrame, pf, mTmpRect); + subtractInsets(mContainingFrame, layoutContainingFrame, parentFrame, mTmpRect); + subtractInsets(mInsetFrame, layoutContainingFrame, parentFrame, mTmpRect); } - layoutDisplayFrame = df; + layoutDisplayFrame = displayFrame; layoutDisplayFrame.intersect(layoutContainingFrame); } final int pw = mContainingFrame.width(); final int ph = mContainingFrame.height(); - if (!mParentFrame.equals(pf)) { + if (!mParentFrame.equals(parentFrame)) { //Slog.i(TAG_WM, "Window " + this + " content frame from " + mParentFrame - // + " to " + pf); - mParentFrame.set(pf); + // + " to " + parentFrame); + mParentFrame.set(parentFrame); mContentChanged = true; } if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) { @@ -836,14 +837,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mContentChanged = true; } - mOverscanFrame.set(of); - mContentFrame.set(cf); - mVisibleFrame.set(vf); - mDecorFrame.set(dcf); - mStableFrame.set(sf); - final boolean hasOutsets = osf != null; + mOverscanFrame.set(overscanFrame); + mContentFrame.set(contentFrame); + mVisibleFrame.set(visibleFrame); + mDecorFrame.set(decorFrame); + mStableFrame.set(stableFrame); + final boolean hasOutsets = outsetFrame != null; if (hasOutsets) { - mOutsetFrame.set(osf); + mOutsetFrame.set(outsetFrame); } final int fw = mFrame.width(); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java new file mode 100644 index 000000000000..15cd55f37fb3 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import android.content.Context; +import android.graphics.Rect; +import android.os.Binder; +import android.platform.test.annotations.Presubmit; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.view.Gravity; +import android.view.IWindow; +import android.view.WindowManager; + +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static android.view.WindowManager.LayoutParams.FLAG_SCALED; +import static android.view.WindowManager.LayoutParams.FILL_PARENT; +import static org.junit.Assert.assertEquals; + +/** + * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery. + * + * Build/Install/Run: bit FrameworksServicesTests:com.android.server.wm.WindowFrameTests + */ +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class WindowFrameTests { + + private static WindowManagerService sWm = null; + private WindowToken mWindowToken; + private final IWindow mIWindow = new TestIWindow(); + + class WindowStateWithTask extends WindowState { + final Task mTask; + WindowStateWithTask(WindowManager.LayoutParams attrs, Task t) { + super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0); + mTask = t; + } + + @Override + Task getTask() { + return mTask; + } + }; + + class TaskWithBounds extends Task { + final Rect mBounds; + TaskWithBounds(Rect bounds) { + super(0, mStubStack, 0, sWm, null, null, false); + mBounds = bounds; + } + @Override + void getBounds(Rect outBounds) { + outBounds.set(mBounds); + } + @Override + void getTempInsetBounds(Rect outBounds) { + outBounds.setEmpty(); + } + @Override + boolean isFullscreen() { + return true; + } + } + + TaskStack mStubStack; + + @Before + public void setUp() throws Exception { + final Context context = InstrumentationRegistry.getTargetContext(); + sWm = TestWindowManagerPolicy.getWindowManagerService(context); + mWindowToken = new WindowToken(sWm, new Binder(), 0, false, + sWm.getDefaultDisplayContentLocked()); + mStubStack = new TaskStack(sWm, 0); + } + + public void assertRect(Rect rect, int left, int top, int right, int bottom) { + assertEquals(left, rect.left); + assertEquals(top, rect.top); + assertEquals(right, rect.right); + assertEquals(bottom, rect.bottom); + } + + @Test + public void testLayoutInFullscreenTaskNoInsets() throws Exception { + Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame + WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); + w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; + + // With no insets or system decor all the frames incoming from PhoneWindowManager + // are identical. + final Rect pf = new Rect(0, 0, 1000, 1000); + + // Here the window has FILL_PARENT, FILL_PARENT + // so we expect it to fill the entire available frame. + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); + assertRect(w.mFrame, 0, 0, 1000, 1000); + + // It can select various widths and heights within the bounds. + // Strangely the window attribute width is ignored for normal windows + // and we use mRequestedWidth/mRequestedHeight + w.mAttrs.width = 300; + w.mAttrs.height = 300; + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); + // Explicit width and height without requested width/height + // gets us nothing. + assertRect(w.mFrame, 0, 0, 0, 0); + + w.mRequestedWidth = 300; + w.mRequestedHeight = 300; + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); + // With requestedWidth/Height we can freely choose our size within the + // parent bounds. + assertRect(w.mFrame, 0, 0, 300, 300); + + // With FLAG_SCALED though, requestedWidth/height is used to control + // the unscaled surface size, and mAttrs.width/height becomes the + // layout controller. + w.mAttrs.flags = WindowManager.LayoutParams.FLAG_SCALED; + w.mRequestedHeight = -1; + w.mRequestedWidth = -1; + w.mAttrs.width = 100; + w.mAttrs.height = 100; + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); + assertRect(w.mFrame, 0, 0, 100, 100); + w.mAttrs.flags = 0; + + // But sizes too large will be clipped to the containing frame + w.mRequestedWidth = 1200; + w.mRequestedHeight = 1200; + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); + assertRect(w.mFrame, 0, 0, 1000, 1000); + + // Before they are clipped though windows will be shifted + w.mAttrs.x = 300; + w.mAttrs.y = 300; + w.mRequestedWidth = 1000; + w.mRequestedHeight = 1000; + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); + assertRect(w.mFrame, 0, 0, 1000, 1000); + + // If there is room to move around in the parent frame the window will be shifted according + // to gravity. + w.mAttrs.x = 0; + w.mAttrs.y = 0; + w.mRequestedWidth = 300; + w.mRequestedHeight = 300; + w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP; + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); + assertRect(w.mFrame, 700, 0, 1000, 300); + w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM; + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); + assertRect(w.mFrame, 700, 700, 1000, 1000); + // Window specified x and y are interpreted as offsets in the opposite + // direction of gravity + w.mAttrs.x = 100; + w.mAttrs.y = 100; + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); + assertRect(w.mFrame, 600, 600, 900, 900); + } + + private WindowState createWindow(Task task, int width, int height) { + final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); + attrs.width = width; + attrs.height = height; + + return new WindowStateWithTask(attrs, task); + } +} |