DisplayContent.java revision df88d73092c62a1a3cd2b2056ca63ae2e70cc238
1/* 2 * Copyright (C) 2012 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 static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; 20import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; 21import static com.android.server.wm.WindowManagerService.TAG; 22 23import android.graphics.Rect; 24import android.graphics.Region; 25import android.util.EventLog; 26import android.util.Slog; 27import android.view.Display; 28import android.view.DisplayInfo; 29import android.view.Surface; 30import com.android.server.EventLogTags; 31 32import java.io.PrintWriter; 33import java.util.ArrayList; 34 35class DisplayContentList extends ArrayList<DisplayContent> { 36} 37 38/** 39 * Utility class for keeping track of the WindowStates and other pertinent contents of a 40 * particular Display. 41 * 42 * IMPORTANT: No method from this class should ever be used without holding 43 * WindowManagerService.mWindowMap. 44 */ 45class DisplayContent { 46 47 /** Unique identifier of this stack. */ 48 private final int mDisplayId; 49 50 /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element 51 * from mDisplayWindows; */ 52 private WindowList mWindows = new WindowList(); 53 54 // This protects the following display size properties, so that 55 // getDisplaySize() doesn't need to acquire the global lock. This is 56 // needed because the window manager sometimes needs to use ActivityThread 57 // while it has its global state locked (for example to load animation 58 // resources), but the ActivityThread also needs get the current display 59 // size sometimes when it has its package lock held. 60 // 61 // These will only be modified with both mWindowMap and mDisplaySizeLock 62 // held (in that order) so the window manager doesn't need to acquire this 63 // lock when needing these values in its normal operation. 64 final Object mDisplaySizeLock = new Object(); 65 int mInitialDisplayWidth = 0; 66 int mInitialDisplayHeight = 0; 67 int mInitialDisplayDensity = 0; 68 int mBaseDisplayWidth = 0; 69 int mBaseDisplayHeight = 0; 70 int mBaseDisplayDensity = 0; 71 private final DisplayInfo mDisplayInfo = new DisplayInfo(); 72 private final Display mDisplay; 73 74 Rect mBaseDisplayRect = new Rect(); 75 Rect mContentRect = new Rect(); 76 77 // Accessed directly by all users. 78 boolean layoutNeeded; 79 int pendingLayoutChanges; 80 final boolean isDefaultDisplay; 81 82 /** 83 * Window tokens that are in the process of exiting, but still 84 * on screen for animations. 85 */ 86 final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>(); 87 88 /** 89 * Application tokens that are in the process of exiting, but still 90 * on screen for animations. 91 */ 92 final AppTokenList mExitingAppTokens = new AppTokenList(); 93 94 /** Array containing all TaskStacks on this display. Array 95 * is stored in display order with the current bottom stack at 0. */ 96 private ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>(); 97 98 /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack 99 * (except a future lockscreen TaskStack) moves to the top. */ 100 private TaskStack mHomeStack = null; 101 102 /** Detect user tapping outside of current focused stack bounds .*/ 103 StackTapPointerEventListener mTapDetector; 104 105 /** Detect user tapping outside of current focused stack bounds .*/ 106 Region mTouchExcludeRegion = new Region(); 107 108 /** Save allocating when retrieving tasks */ 109 private ArrayList<Task> mTaskHistory = new ArrayList<Task>(); 110 111 /** Save allocating when calculating rects */ 112 Rect mTmpRect = new Rect(); 113 114 final WindowManagerService mService; 115 116 /** 117 * @param display May not be null. 118 * @param service You know. 119 */ 120 DisplayContent(Display display, WindowManagerService service) { 121 mDisplay = display; 122 mDisplayId = display.getDisplayId(); 123 display.getDisplayInfo(mDisplayInfo); 124 isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY; 125 mService = service; 126 } 127 128 int getDisplayId() { 129 return mDisplayId; 130 } 131 132 WindowList getWindowList() { 133 return mWindows; 134 } 135 136 Display getDisplay() { 137 return mDisplay; 138 } 139 140 DisplayInfo getDisplayInfo() { 141 return mDisplayInfo; 142 } 143 144 /** 145 * Returns true if the specified UID has access to this display. 146 */ 147 public boolean hasAccess(int uid) { 148 return mDisplay.hasAccess(uid); 149 } 150 151 public boolean isPrivate() { 152 return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0; 153 } 154 155 /** 156 * Retrieve the tasks on this display in stack order from the bottommost TaskStack up. 157 * @return All the Tasks, in order, on this display. 158 */ 159 ArrayList<Task> getTasks() { 160 return mTaskHistory; 161 } 162 163 void addTask(Task task, boolean toTop) { 164 mTaskHistory.remove(task); 165 166 final int userId = task.mUserId; 167 int taskNdx; 168 final int numTasks = mTaskHistory.size(); 169 if (toTop) { 170 for (taskNdx = numTasks - 1; taskNdx >= 0; --taskNdx) { 171 if (mTaskHistory.get(taskNdx).mUserId == userId) { 172 break; 173 } 174 } 175 ++taskNdx; 176 } else { 177 for (taskNdx = 0; taskNdx < numTasks; ++taskNdx) { 178 if (mTaskHistory.get(taskNdx).mUserId == userId) { 179 break; 180 } 181 } 182 } 183 184 mTaskHistory.add(taskNdx, task); 185 EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx); 186 } 187 188 void removeTask(Task task) { 189 mTaskHistory.remove(task); 190 } 191 192 TaskStack getHomeStack() { 193 if (mHomeStack == null) { 194 Slog.e(TAG, "getHomeStack: Returning null from this=" + this); 195 } 196 return mHomeStack; 197 } 198 199 void updateDisplayInfo() { 200 // Save old size. 201 int oldWidth = mDisplayInfo.logicalWidth; 202 int oldHeight = mDisplayInfo.logicalHeight; 203 mDisplay.getDisplayInfo(mDisplayInfo); 204 205 for (int i = mStacks.size() - 1; i >= 0; --i) { 206 final TaskStack stack = mStacks.get(i); 207 if (!stack.isFullscreen()) { 208 stack.resizeBounds(oldWidth, oldHeight, mDisplayInfo.logicalWidth, 209 mDisplayInfo.logicalHeight); 210 } 211 } 212 } 213 214 void getLogicalDisplayRect(Rect out) { 215 updateDisplayInfo(); 216 // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked. 217 final int orientation = mDisplayInfo.rotation; 218 boolean rotated = (orientation == Surface.ROTATION_90 219 || orientation == Surface.ROTATION_270); 220 final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; 221 final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; 222 int width = mDisplayInfo.logicalWidth; 223 int left = (physWidth - width) / 2; 224 int height = mDisplayInfo.logicalHeight; 225 int top = (physHeight - height) / 2; 226 out.set(left, top, left + width, top + height); 227 } 228 229 /** @return The number of tokens in all of the Tasks on this display. */ 230 int numTokens() { 231 int count = 0; 232 for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { 233 count += mTaskHistory.get(taskNdx).mAppTokens.size(); 234 } 235 return count; 236 } 237 238 /** Refer to {@link WindowManagerService#attachStack(int, int)} */ 239 void attachStack(TaskStack stack) { 240 if (stack.mStackId == HOME_STACK_ID) { 241 if (mHomeStack != null) { 242 throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first."); 243 } 244 mHomeStack = stack; 245 } 246 mStacks.add(stack); 247 layoutNeeded = true; 248 } 249 250 void moveStack(TaskStack stack, boolean toTop) { 251 mStacks.remove(stack); 252 mStacks.add(toTop ? mStacks.size() : 0, stack); 253 } 254 255 void detachStack(TaskStack stack) { 256 for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { 257 final Task task = mTaskHistory.get(taskNdx); 258 if (task.mStack == stack) { 259 mService.tmpRemoveTaskWindowsLocked(task); 260 mTaskHistory.remove(taskNdx); 261 } 262 } 263 mStacks.remove(stack); 264 } 265 266 /** 267 * Propagate the new bounds to all child stacks. 268 * @param contentRect The bounds to apply at the top level. 269 */ 270 void resize(Rect contentRect) { 271 mContentRect.set(contentRect); 272 } 273 274 boolean getStackBounds(int stackId, Rect bounds) { 275 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 276 final TaskStack stack = mStacks.get(stackNdx); 277 if (stackId == stack.mStackId) { 278 bounds.set(stack.mBounds); 279 return true; 280 } 281 } 282 return false; 283 } 284 285 int stackIdFromPoint(int x, int y) { 286 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 287 final TaskStack stack = mStacks.get(stackNdx); 288 stack.getBounds(mTmpRect); 289 if (mTmpRect.contains(x, y)) { 290 return stack.mStackId; 291 } 292 } 293 return -1; 294 } 295 296 void setTouchExcludeRegion(TaskStack focusedStack) { 297 mTouchExcludeRegion.set(mBaseDisplayRect); 298 WindowList windows = getWindowList(); 299 for (int i = windows.size() - 1; i >= 0; --i) { 300 final WindowState win = windows.get(i); 301 final TaskStack stack = win.getStack(); 302 if (win.isVisibleLw() && stack != null && stack != focusedStack) { 303 mTmpRect.set(win.mVisibleFrame); 304 mTmpRect.intersect(win.mVisibleInsets); 305 mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE); 306 } 307 } 308 } 309 310 void switchUserStacks(int oldUserId, int newUserId) { 311 final WindowList windows = getWindowList(); 312 for (int i = 0; i < windows.size(); i++) { 313 final WindowState win = windows.get(i); 314 if (win.isHiddenFromUserLocked()) { 315 if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding " 316 + win + ", attrs=" + win.mAttrs.type + ", belonging to " 317 + win.mOwnerUid); 318 win.hideLw(false); 319 } 320 } 321 322 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 323 mStacks.get(stackNdx).switchUser(newUserId); 324 } 325 } 326 327 void resetAnimationBackgroundAnimator() { 328 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 329 mStacks.get(stackNdx).resetAnimationBackgroundAnimator(); 330 } 331 } 332 333 boolean animateDimLayers() { 334 boolean result = false; 335 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 336 result |= mStacks.get(stackNdx).animateDimLayers(); 337 } 338 return result; 339 } 340 341 void resetDimming() { 342 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 343 mStacks.get(stackNdx).resetDimmingTag(); 344 } 345 } 346 347 boolean isDimming() { 348 boolean result = false; 349 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 350 result |= mStacks.get(stackNdx).isDimming(); 351 } 352 return result; 353 } 354 355 void stopDimmingIfNeeded() { 356 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 357 mStacks.get(stackNdx).stopDimmingIfNeeded(); 358 } 359 } 360 361 void close() { 362 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 363 mStacks.get(stackNdx).close(); 364 } 365 } 366 367 public void dump(String prefix, PrintWriter pw) { 368 pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId); 369 final String subPrefix = " " + prefix; 370 pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x"); 371 pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity); 372 pw.print("dpi"); 373 if (mInitialDisplayWidth != mBaseDisplayWidth 374 || mInitialDisplayHeight != mBaseDisplayHeight 375 || mInitialDisplayDensity != mBaseDisplayDensity) { 376 pw.print(" base="); 377 pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight); 378 pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi"); 379 } 380 pw.print(" cur="); 381 pw.print(mDisplayInfo.logicalWidth); 382 pw.print("x"); pw.print(mDisplayInfo.logicalHeight); 383 pw.print(" app="); 384 pw.print(mDisplayInfo.appWidth); 385 pw.print("x"); pw.print(mDisplayInfo.appHeight); 386 pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth); 387 pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight); 388 pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth); 389 pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight); 390 pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded); 391 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 392 final TaskStack stack = mStacks.get(stackNdx); 393 pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId); 394 stack.dump(prefix + " ", pw); 395 } 396 int ndx = numTokens(); 397 if (ndx > 0) { 398 pw.println(); 399 pw.println(" Application tokens in Z order:"); 400 getTasks(); 401 for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { 402 AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens; 403 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { 404 final AppWindowToken wtoken = tokens.get(tokenNdx); 405 pw.print(" App #"); pw.print(ndx--); 406 pw.print(' '); pw.print(wtoken); pw.println(":"); 407 wtoken.dump(pw, " "); 408 } 409 } 410 } 411 if (mExitingTokens.size() > 0) { 412 pw.println(); 413 pw.println(" Exiting tokens:"); 414 for (int i=mExitingTokens.size()-1; i>=0; i--) { 415 WindowToken token = mExitingTokens.get(i); 416 pw.print(" Exiting #"); pw.print(i); 417 pw.print(' '); pw.print(token); 418 pw.println(':'); 419 token.dump(pw, " "); 420 } 421 } 422 if (mExitingAppTokens.size() > 0) { 423 pw.println(); 424 pw.println(" Exiting application tokens:"); 425 for (int i=mExitingAppTokens.size()-1; i>=0; i--) { 426 WindowToken token = mExitingAppTokens.get(i); 427 pw.print(" Exiting App #"); pw.print(i); 428 pw.print(' '); pw.print(token); 429 pw.println(':'); 430 token.dump(pw, " "); 431 } 432 } 433 pw.println(); 434 } 435 436 @Override 437 public String toString() { 438 return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks; 439 } 440} 441