From 16a4e3cbf7068504e4628ed6e81e7700a6f8edbc Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 28 Oct 2016 11:45:22 -0700 Subject: Begin series of computeFrame unit tests Start with a fixture and some simple unit tests for WindowState.computeFrame. Test: bit FrameworksServicesTests:com.android.server.wm.WindowFrameTests Change-Id: I3176837ee60dbd474f22a3b1857f19b4e82afee7 --- .../com/android/server/wm/WindowFrameTests.java | 189 +++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java 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); + } +} -- cgit v1.2.3-59-g8ed1b