summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java53
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java189
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);
+ }
+}