WindowFrameTests.java revision 15dd7efeb7491b80add341b0599027e246d07c6f
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package com.android.server.wm; 18 19import org.junit.Before; 20import org.junit.Test; 21import org.junit.runner.RunWith; 22 23import android.content.Context; 24import android.graphics.Rect; 25import android.os.Binder; 26import android.platform.test.annotations.Presubmit; 27import android.support.test.InstrumentationRegistry; 28import android.support.test.filters.SmallTest; 29import android.support.test.runner.AndroidJUnit4; 30import android.view.Gravity; 31import android.view.IWindow; 32import android.view.WindowManager; 33 34import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; 35import static android.view.WindowManager.LayoutParams.FLAG_SCALED; 36import static android.view.WindowManager.LayoutParams.FILL_PARENT; 37import static org.junit.Assert.assertEquals; 38import static org.junit.Assert.assertTrue; 39 40/** 41 * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery. 42 * 43 * Build/Install/Run: bit FrameworksServicesTests:com.android.server.wm.WindowFrameTests 44 */ 45@SmallTest 46@Presubmit 47@RunWith(AndroidJUnit4.class) 48public class WindowFrameTests { 49 50 private static WindowManagerService sWm = null; 51 private WindowToken mWindowToken; 52 private final IWindow mIWindow = new TestIWindow(); 53 54 class WindowStateWithTask extends WindowState { 55 final Task mTask; 56 WindowStateWithTask(WindowManager.LayoutParams attrs, Task t) { 57 super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0); 58 mTask = t; 59 } 60 61 @Override 62 Task getTask() { 63 return mTask; 64 } 65 }; 66 67 class TaskWithBounds extends Task { 68 final Rect mBounds; 69 final Rect mInsetBounds = new Rect(); 70 boolean mFullscreenForTest = true; 71 TaskWithBounds(Rect bounds) { 72 super(0, mStubStack, 0, sWm, null, null, false); 73 mBounds = bounds; 74 } 75 @Override 76 void getBounds(Rect outBounds) { 77 outBounds.set(mBounds); 78 } 79 @Override 80 void getTempInsetBounds(Rect outBounds) { 81 outBounds.set(mInsetBounds); 82 } 83 @Override 84 boolean isFullscreen() { 85 return mFullscreenForTest; 86 } 87 } 88 89 TaskStack mStubStack; 90 91 @Before 92 public void setUp() throws Exception { 93 final Context context = InstrumentationRegistry.getTargetContext(); 94 sWm = TestWindowManagerPolicy.getWindowManagerService(context); 95 mWindowToken = new WindowToken(sWm, new Binder(), 0, false, 96 sWm.getDefaultDisplayContentLocked()); 97 mStubStack = new TaskStack(sWm, 0); 98 } 99 100 public void assertRect(Rect rect, int left, int top, int right, int bottom) { 101 assertEquals(left, rect.left); 102 assertEquals(top, rect.top); 103 assertEquals(right, rect.right); 104 assertEquals(bottom, rect.bottom); 105 } 106 107 @Test 108 public void testLayoutInFullscreenTaskInsets() throws Exception { 109 Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame 110 WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); 111 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; 112 113 final int bottomContentInset = 100; 114 final int topContentInset = 50; 115 final int bottomVisibleInset = 30; 116 final int topVisibleInset = 70; 117 final int leftStableInset = 20; 118 final int rightStableInset = 90; 119 120 // With no insets or system decor all the frames incoming from PhoneWindowManager 121 // are identical. 122 final Rect pf = new Rect(0, 0, 1000, 1000); 123 final Rect df = pf; 124 final Rect of = df; 125 final Rect cf = new Rect(pf); 126 // Produce some insets 127 cf.top += 50; 128 cf.bottom -= 100; 129 final Rect vf = new Rect(pf); 130 vf.top += topVisibleInset; 131 vf.bottom -= bottomVisibleInset; 132 final Rect sf = new Rect(pf); 133 sf.left += leftStableInset; 134 sf.right -= rightStableInset; 135 136 final Rect dcf = pf; 137 // When mFrame extends past cf, the content insets are 138 // the difference between mFrame and ContentFrame. Visible 139 // and stable frames work the same way. 140 w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null); 141 assertRect(w.mFrame,0, 0, 1000, 1000); 142 assertRect(w.mContentInsets, 0, topContentInset, 0, bottomContentInset); 143 assertRect(w.mVisibleInsets, 0, topVisibleInset, 0, bottomVisibleInset); 144 assertRect(w.mStableInsets, leftStableInset, 0, rightStableInset, 0); 145 // The frames remain as passed in shrunk to the window frame 146 assertTrue(cf.equals(w.getContentFrameLw())); 147 assertTrue(vf.equals(w.getVisibleFrameLw())); 148 assertTrue(sf.equals(w.getStableFrameLw())); 149 // On the other hand mFrame doesn't extend past cf we won't get any insets 150 w.mAttrs.x = 100; 151 w.mAttrs.y = 100; 152 w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT 153 w.mRequestedWidth = 100; 154 w.mRequestedHeight = 100; 155 w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null); 156 assertRect(w.mFrame, 100, 100, 200, 200); 157 assertRect(w.mContentInsets, 0, 0, 0, 0); 158 // In this case the frames are shrunk to the window frame. 159 assertTrue(w.mFrame.equals(w.getContentFrameLw())); 160 assertTrue(w.mFrame.equals(w.getVisibleFrameLw())); 161 assertTrue(w.mFrame.equals(w.getStableFrameLw())); 162 } 163 164 @Test 165 public void testLayoutInFullscreenTaskNoInsets() throws Exception { 166 Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame 167 WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); 168 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; 169 170 // With no insets or system decor all the frames incoming from PhoneWindowManager 171 // are identical. 172 final Rect pf = new Rect(0, 0, 1000, 1000); 173 174 // Here the window has FILL_PARENT, FILL_PARENT 175 // so we expect it to fill the entire available frame. 176 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); 177 assertRect(w.mFrame, 0, 0, 1000, 1000); 178 179 // It can select various widths and heights within the bounds. 180 // Strangely the window attribute width is ignored for normal windows 181 // and we use mRequestedWidth/mRequestedHeight 182 w.mAttrs.width = 300; 183 w.mAttrs.height = 300; 184 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); 185 // Explicit width and height without requested width/height 186 // gets us nothing. 187 assertRect(w.mFrame, 0, 0, 0, 0); 188 189 w.mRequestedWidth = 300; 190 w.mRequestedHeight = 300; 191 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); 192 // With requestedWidth/Height we can freely choose our size within the 193 // parent bounds. 194 assertRect(w.mFrame, 0, 0, 300, 300); 195 196 // With FLAG_SCALED though, requestedWidth/height is used to control 197 // the unscaled surface size, and mAttrs.width/height becomes the 198 // layout controller. 199 w.mAttrs.flags = WindowManager.LayoutParams.FLAG_SCALED; 200 w.mRequestedHeight = -1; 201 w.mRequestedWidth = -1; 202 w.mAttrs.width = 100; 203 w.mAttrs.height = 100; 204 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); 205 assertRect(w.mFrame, 0, 0, 100, 100); 206 w.mAttrs.flags = 0; 207 208 // But sizes too large will be clipped to the containing frame 209 w.mRequestedWidth = 1200; 210 w.mRequestedHeight = 1200; 211 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); 212 assertRect(w.mFrame, 0, 0, 1000, 1000); 213 214 // Before they are clipped though windows will be shifted 215 w.mAttrs.x = 300; 216 w.mAttrs.y = 300; 217 w.mRequestedWidth = 1000; 218 w.mRequestedHeight = 1000; 219 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); 220 assertRect(w.mFrame, 0, 0, 1000, 1000); 221 222 // If there is room to move around in the parent frame the window will be shifted according 223 // to gravity. 224 w.mAttrs.x = 0; 225 w.mAttrs.y = 0; 226 w.mRequestedWidth = 300; 227 w.mRequestedHeight = 300; 228 w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP; 229 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); 230 assertRect(w.mFrame, 700, 0, 1000, 300); 231 w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM; 232 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); 233 assertRect(w.mFrame, 700, 700, 1000, 1000); 234 // Window specified x and y are interpreted as offsets in the opposite 235 // direction of gravity 236 w.mAttrs.x = 100; 237 w.mAttrs.y = 100; 238 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); 239 assertRect(w.mFrame, 600, 600, 900, 900); 240 } 241 242 @Test 243 public void testLayoutNonfullscreenTask() { 244 final Rect taskBounds = new Rect(300, 300, 700, 700); 245 TaskWithBounds task = new TaskWithBounds(taskBounds); 246 task.mFullscreenForTest = false; 247 WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); 248 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; 249 250 final Rect pf = new Rect(0, 0, 1000, 1000); 251 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null); 252 // For non fullscreen tasks the containing frame is based off the 253 // task bounds not the parent frame. 254 assertRect(w.mFrame, 300, 300, 700, 700); 255 assertRect(w.getContentFrameLw(), 300, 300, 700, 700); 256 assertRect(w.mContentInsets, 0, 0, 0, 0); 257 258 pf.set(0, 0, 1000, 1000); 259 // We still produce insets against the containing frame the same way. 260 final Rect cf = new Rect(0, 0, 500, 500); 261 w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null); 262 assertRect(w.mFrame, 300, 300, 700, 700); 263 assertRect(w.getContentFrameLw(), 300, 300, 500, 500); 264 assertRect(w.mContentInsets, 0, 0, 200, 200); 265 266 pf.set(0, 0, 1000, 1000); 267 // However if we set temp inset bounds, the insets will be computed 268 // as if our window was laid out there, but it will be laid out according to 269 // the task bounds. 270 task.mInsetBounds.set(200, 200, 600, 600); 271 w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null); 272 assertRect(w.mFrame, 300, 300, 700, 700); 273 assertRect(w.getContentFrameLw(), 300, 300, 600, 600); 274 assertRect(w.mContentInsets, 0, 0, 100, 100); 275 } 276 277 private WindowState createWindow(Task task, int width, int height) { 278 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); 279 attrs.width = width; 280 attrs.height = height; 281 282 return new WindowStateWithTask(attrs, task); 283 } 284} 285