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 17 package android.server.cts; 18 19 import static android.server.cts.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID; 20 import static android.server.cts.StateLogger.log; 21 import static android.server.cts.StateLogger.logE; 22 23 import com.android.tradefed.device.CollectingOutputReceiver; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.device.ITestDevice; 26 27 import java.awt.*; 28 import java.util.ArrayList; 29 import java.util.Collections; 30 import java.util.Comparator; 31 import java.util.HashMap; 32 import java.util.LinkedList; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.regex.Matcher; 36 import java.util.regex.Pattern; 37 38 public class WindowManagerState { 39 40 public static final String TRANSIT_ACTIVITY_OPEN = "TRANSIT_ACTIVITY_OPEN"; 41 public static final String TRANSIT_ACTIVITY_CLOSE = "TRANSIT_ACTIVITY_CLOSE"; 42 public static final String TRANSIT_TASK_OPEN = "TRANSIT_TASK_OPEN"; 43 public static final String TRANSIT_TASK_CLOSE = "TRANSIT_TASK_CLOSE"; 44 45 public static final String TRANSIT_WALLPAPER_OPEN = "TRANSIT_WALLPAPER_OPEN"; 46 public static final String TRANSIT_WALLPAPER_CLOSE = "TRANSIT_WALLPAPER_CLOSE"; 47 public static final String TRANSIT_WALLPAPER_INTRA_OPEN = "TRANSIT_WALLPAPER_INTRA_OPEN"; 48 public static final String TRANSIT_WALLPAPER_INTRA_CLOSE = "TRANSIT_WALLPAPER_INTRA_CLOSE"; 49 50 public static final String TRANSIT_KEYGUARD_GOING_AWAY = "TRANSIT_KEYGUARD_GOING_AWAY"; 51 public static final String TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 52 "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER"; 53 public static final String TRANSIT_KEYGUARD_OCCLUDE = "TRANSIT_KEYGUARD_OCCLUDE"; 54 public static final String TRANSIT_KEYGUARD_UNOCCLUDE = "TRANSIT_KEYGUARD_UNOCCLUDE"; 55 56 public static final String APP_STATE_IDLE = "APP_STATE_IDLE"; 57 58 private static final String DUMPSYS_WINDOW = "dumpsys window -a"; 59 60 private static final Pattern sWindowPattern = 61 Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+)\\}\\:"); 62 private static final Pattern sStartingWindowPattern = 63 Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) Starting (.+)\\}\\:"); 64 private static final Pattern sExitingWindowPattern = 65 Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+) EXITING\\}\\:"); 66 private static final Pattern sDebuggerWindowPattern = 67 Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) Waiting For Debugger: (.+)\\}\\:"); 68 69 private static final Pattern sFocusedWindowPattern = Pattern.compile( 70 "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) (\\S+)\\}"); 71 private static final Pattern sAppErrorFocusedWindowPattern = Pattern.compile( 72 "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) Application Error\\: (\\S+)\\}"); 73 private static final Pattern sWaitingForDebuggerFocusedWindowPattern = Pattern.compile( 74 "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) Waiting For Debugger\\: (\\S+)\\}"); 75 76 private static final Pattern sFocusedAppPattern = 77 Pattern.compile("mFocusedApp=AppWindowToken\\{(.+) token=Token\\{(.+) " 78 + "ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)"); 79 private static final Pattern sStableBoundsPattern = Pattern.compile( 80 "mStable=\\((\\d+),(\\d+)\\)-\\((\\d+),(\\d+)\\)"); 81 private static final Pattern sDefaultPinnedStackBoundsPattern = Pattern.compile( 82 "defaultBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]"); 83 private static final Pattern sPinnedStackMovementBoundsPattern = Pattern.compile( 84 "movementBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]"); 85 private static final Pattern sRotationPattern = Pattern.compile( 86 "mRotation=(\\d).*"); 87 private static final Pattern sLastOrientationPattern = Pattern.compile( 88 ".*mLastOrientation=(\\d)"); 89 90 private static final Pattern sLastAppTransitionPattern = 91 Pattern.compile("mLastUsedAppTransition=(.+)"); 92 private static final Pattern sAppTransitionStatePattern = 93 Pattern.compile("mAppTransitionState=(.+)"); 94 95 private static final Pattern sStackIdPattern = Pattern.compile("mStackId=(\\d+)"); 96 97 private static final Pattern sInputMethodWindowPattern = 98 Pattern.compile("mInputMethodWindow=Window\\{([0-9a-fA-F]+) u\\d+ .+\\}.*"); 99 100 private static final Pattern sDisplayIdPattern = 101 Pattern.compile("Display: mDisplayId=(\\d+)"); 102 103 private static final Pattern sDisplayFrozenPattern = 104 Pattern.compile("mDisplayFrozen=([a-z]*) .*"); 105 106 private static final Pattern sDockedStackMinimizedPattern = 107 Pattern.compile("mMinimizedDock=([a-z]*)"); 108 109 private static final Pattern[] sExtractStackExitPatterns = { 110 sStackIdPattern, sWindowPattern, sStartingWindowPattern, sExitingWindowPattern, 111 sDebuggerWindowPattern, sFocusedWindowPattern, sAppErrorFocusedWindowPattern, 112 sWaitingForDebuggerFocusedWindowPattern, 113 sFocusedAppPattern, sLastAppTransitionPattern, sDefaultPinnedStackBoundsPattern, 114 sPinnedStackMovementBoundsPattern, sDisplayIdPattern, sDockedStackMinimizedPattern}; 115 116 // Windows in z-order with the top most at the front of the list. 117 private List<WindowState> mWindowStates = new ArrayList(); 118 // Stacks in z-order with the top most at the front of the list, starting with primary display. 119 private final List<WindowStack> mStacks = new ArrayList(); 120 // Stacks on all attached displays, in z-order with the top most at the front of the list. 121 private final Map<Integer, List<WindowStack>> mDisplayStacks 122 = new HashMap<>(); 123 private List<Display> mDisplays = new ArrayList(); 124 private String mFocusedWindow = null; 125 private String mFocusedApp = null; 126 private String mLastTransition = null; 127 private String mAppTransitionState = null; 128 private String mInputMethodWindowAppToken = null; 129 private Rectangle mStableBounds = new Rectangle(); 130 private final Rectangle mDefaultPinnedStackBounds = new Rectangle(); 131 private final Rectangle mPinnedStackMovementBounds = new Rectangle(); 132 private final LinkedList<String> mSysDump = new LinkedList(); 133 private int mRotation; 134 private int mLastOrientation; 135 private boolean mDisplayFrozen; 136 private boolean mIsDockedStackMinimized; 137 computeState(ITestDevice device)138 void computeState(ITestDevice device) throws DeviceNotAvailableException { 139 // It is possible the system is in the middle of transition to the right state when we get 140 // the dump. We try a few times to get the information we need before giving up. 141 int retriesLeft = 3; 142 boolean retry = false; 143 String dump = null; 144 145 log("=============================="); 146 log(" WindowManagerState "); 147 log("=============================="); 148 do { 149 if (retry) { 150 log("***Incomplete WM state. Retrying..."); 151 // Wait half a second between retries for window manager to finish transitioning... 152 try { 153 Thread.sleep(500); 154 } catch (InterruptedException e) { 155 log(e.toString()); 156 // Well I guess we are not waiting... 157 } 158 } 159 160 final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver(); 161 device.executeShellCommand(DUMPSYS_WINDOW, outputReceiver); 162 dump = outputReceiver.getOutput(); 163 parseSysDump(dump); 164 165 retry = mWindowStates.isEmpty() || mFocusedApp == null; 166 } while (retry && retriesLeft-- > 0); 167 168 if (retry) { 169 log(dump); 170 } 171 172 if (mWindowStates.isEmpty()) { 173 logE("No Windows found..."); 174 } 175 if (mFocusedWindow == null) { 176 logE("No Focused Window..."); 177 } 178 if (mFocusedApp == null) { 179 logE("No Focused App..."); 180 } 181 } 182 parseSysDump(String sysDump)183 private void parseSysDump(String sysDump) { 184 reset(); 185 186 Collections.addAll(mSysDump, sysDump.split("\\n")); 187 188 int currentDisplayId = DEFAULT_DISPLAY_ID; 189 while (!mSysDump.isEmpty()) { 190 final Display display = 191 Display.create(mSysDump, sExtractStackExitPatterns); 192 if (display != null) { 193 log(display.toString()); 194 mDisplays.add(display); 195 currentDisplayId = display.mDisplayId; 196 mDisplayStacks.put(currentDisplayId, new ArrayList<>()); 197 continue; 198 } 199 200 final WindowStack stack = 201 WindowStack.create(mSysDump, sStackIdPattern, sExtractStackExitPatterns); 202 203 if (stack != null) { 204 mStacks.add(stack); 205 mDisplayStacks.get(currentDisplayId).add(stack); 206 continue; 207 } 208 209 210 final WindowState ws = WindowState.create(mSysDump, sExtractStackExitPatterns); 211 if (ws != null) { 212 log(ws.toString()); 213 214 // Check to see if we are in the middle of transitioning. If we are, we want to 215 // skip dumping until window manager is done transitioning windows. 216 if (ws.isStartingWindow()) { 217 log("Skipping dump due to starting window transition..."); 218 return; 219 } 220 221 if (ws.isExitingWindow()) { 222 log("Skipping dump due to exiting window transition..."); 223 return; 224 } 225 226 mWindowStates.add(ws); 227 continue; 228 } 229 230 final String line = mSysDump.pop().trim(); 231 232 Matcher matcher = sFocusedWindowPattern.matcher(line); 233 if (matcher.matches()) { 234 log(line); 235 final String focusedWindow = matcher.group(3); 236 log(focusedWindow); 237 mFocusedWindow = focusedWindow; 238 continue; 239 } 240 241 matcher = sAppErrorFocusedWindowPattern.matcher(line); 242 if (matcher.matches()) { 243 log(line); 244 final String focusedWindow = matcher.group(3); 245 log(focusedWindow); 246 mFocusedWindow = focusedWindow; 247 continue; 248 } 249 250 matcher = sWaitingForDebuggerFocusedWindowPattern.matcher(line); 251 if (matcher.matches()) { 252 log(line); 253 final String focusedWindow = matcher.group(3); 254 log(focusedWindow); 255 mFocusedWindow = focusedWindow; 256 continue; 257 } 258 259 matcher = sFocusedAppPattern.matcher(line); 260 if (matcher.matches()) { 261 log(line); 262 final String focusedApp = matcher.group(5); 263 log(focusedApp); 264 mFocusedApp = focusedApp; 265 continue; 266 } 267 268 matcher = sAppTransitionStatePattern.matcher(line); 269 if (matcher.matches()) { 270 log(line); 271 final String appTransitionState = matcher.group(1); 272 log(appTransitionState); 273 mAppTransitionState = appTransitionState; 274 continue; 275 } 276 277 matcher = sLastAppTransitionPattern.matcher(line); 278 if (matcher.matches()) { 279 log(line); 280 final String lastAppTransitionPattern = matcher.group(1); 281 log(lastAppTransitionPattern); 282 mLastTransition = lastAppTransitionPattern; 283 continue; 284 } 285 286 matcher = sStableBoundsPattern.matcher(line); 287 if (matcher.matches()) { 288 log(line); 289 int left = Integer.parseInt(matcher.group(1)); 290 int top = Integer.parseInt(matcher.group(2)); 291 int right = Integer.parseInt(matcher.group(3)); 292 int bottom = Integer.parseInt(matcher.group(4)); 293 mStableBounds.setBounds(left, top, right - left, bottom - top); 294 log(mStableBounds.toString()); 295 continue; 296 } 297 298 matcher = sDefaultPinnedStackBoundsPattern.matcher(line); 299 if (matcher.matches()) { 300 log(line); 301 int left = Integer.parseInt(matcher.group(1)); 302 int top = Integer.parseInt(matcher.group(2)); 303 int right = Integer.parseInt(matcher.group(3)); 304 int bottom = Integer.parseInt(matcher.group(4)); 305 mDefaultPinnedStackBounds.setBounds(left, top, right - left, bottom - top); 306 log(mDefaultPinnedStackBounds.toString()); 307 continue; 308 } 309 310 matcher = sPinnedStackMovementBoundsPattern.matcher(line); 311 if (matcher.matches()) { 312 log(line); 313 int left = Integer.parseInt(matcher.group(1)); 314 int top = Integer.parseInt(matcher.group(2)); 315 int right = Integer.parseInt(matcher.group(3)); 316 int bottom = Integer.parseInt(matcher.group(4)); 317 mPinnedStackMovementBounds.setBounds(left, top, right - left, bottom - top); 318 log(mPinnedStackMovementBounds.toString()); 319 continue; 320 } 321 322 matcher = sInputMethodWindowPattern.matcher(line); 323 if (matcher.matches()) { 324 log(line); 325 mInputMethodWindowAppToken = matcher.group(1); 326 log(mInputMethodWindowAppToken); 327 continue; 328 } 329 330 matcher = sRotationPattern.matcher(line); 331 if (matcher.matches()) { 332 log(line); 333 mRotation = Integer.parseInt(matcher.group(1)); 334 continue; 335 } 336 337 matcher = sLastOrientationPattern.matcher(line); 338 if (matcher.matches()) { 339 log(line); 340 mLastOrientation = Integer.parseInt(matcher.group(1)); 341 continue; 342 } 343 344 matcher = sDisplayFrozenPattern.matcher(line); 345 if (matcher.matches()) { 346 log(line); 347 mDisplayFrozen = Boolean.parseBoolean(matcher.group(1)); 348 continue; 349 } 350 351 matcher = sDockedStackMinimizedPattern.matcher(line); 352 if (matcher.matches()) { 353 log(line); 354 mIsDockedStackMinimized = Boolean.parseBoolean(matcher.group(1)); 355 continue; 356 } 357 } 358 } 359 getMatchingWindowTokens(final String windowName, List<String> tokenList)360 void getMatchingWindowTokens(final String windowName, List<String> tokenList) { 361 tokenList.clear(); 362 363 for (WindowState ws : mWindowStates) { 364 if (windowName.equals(ws.getName())) { 365 tokenList.add(ws.getToken()); 366 } 367 } 368 } 369 getMatchingVisibleWindowState(final String windowName, List<WindowState> windowList)370 void getMatchingVisibleWindowState(final String windowName, List<WindowState> windowList) { 371 windowList.clear(); 372 for (WindowState ws : mWindowStates) { 373 if (ws.isShown() && windowName.equals(ws.getName())) { 374 windowList.add(ws); 375 } 376 } 377 } 378 getPrefixMatchingVisibleWindowState(final String windowName, List<WindowState> windowList)379 void getPrefixMatchingVisibleWindowState(final String windowName, List<WindowState> windowList) { 380 windowList.clear(); 381 for (WindowState ws : mWindowStates) { 382 if (ws.isShown() && ws.getName().startsWith(windowName)) { 383 windowList.add(ws); 384 } 385 } 386 } 387 getWindowByPackageName(String packageName, int windowType)388 WindowState getWindowByPackageName(String packageName, int windowType) { 389 for (WindowState ws : mWindowStates) { 390 final String name = ws.getName(); 391 if (name == null || !name.contains(packageName)) { 392 continue; 393 } 394 if (windowType != ws.getType()) { 395 continue; 396 } 397 return ws; 398 } 399 400 return null; 401 } 402 getWindowsByPackageName(String packageName, List<Integer> restrictToTypeList, List<WindowState> outWindowList)403 void getWindowsByPackageName(String packageName, List<Integer> restrictToTypeList, 404 List<WindowState> outWindowList) { 405 outWindowList.clear(); 406 for (WindowState ws : mWindowStates) { 407 final String name = ws.getName(); 408 if (name == null || !name.contains(packageName)) { 409 continue; 410 } 411 if (restrictToTypeList != null && !restrictToTypeList.contains(ws.getType())) { 412 continue; 413 } 414 outWindowList.add(ws); 415 } 416 } 417 sortWindowsByLayer(List<WindowState> windows)418 void sortWindowsByLayer(List<WindowState> windows) { 419 windows.sort(Comparator.comparingInt(WindowState::getLayer)); 420 } 421 getWindowStateForAppToken(String appToken)422 WindowState getWindowStateForAppToken(String appToken) { 423 for (WindowState ws : mWindowStates) { 424 if (ws.getToken().equals(appToken)) { 425 return ws; 426 } 427 } 428 return null; 429 } 430 getDisplay(int displayId)431 Display getDisplay(int displayId) { 432 for (Display display : mDisplays) { 433 if (displayId == display.getDisplayId()) { 434 return display; 435 } 436 } 437 return null; 438 } 439 getFrontWindow()440 String getFrontWindow() { 441 if (mWindowStates == null || mWindowStates.isEmpty()) { 442 return null; 443 } 444 return mWindowStates.get(0).getName(); 445 } 446 getFocusedWindow()447 String getFocusedWindow() { 448 return mFocusedWindow; 449 } 450 getFocusedApp()451 String getFocusedApp() { 452 return mFocusedApp; 453 } 454 getLastTransition()455 String getLastTransition() { 456 return mLastTransition; 457 } 458 getAppTransitionState()459 String getAppTransitionState() { 460 return mAppTransitionState; 461 } 462 getFrontStackId(int displayId)463 int getFrontStackId(int displayId) { 464 return mDisplayStacks.get(displayId).get(0).mStackId; 465 } 466 getRotation()467 public int getRotation() { 468 return mRotation; 469 } 470 getLastOrientation()471 int getLastOrientation() { 472 return mLastOrientation; 473 } 474 containsStack(int stackId)475 boolean containsStack(int stackId) { 476 for (WindowStack stack : mStacks) { 477 if (stackId == stack.mStackId) { 478 return true; 479 } 480 } 481 return false; 482 } 483 484 /** Check if there exists a window record with matching windowName. */ containsWindow(String windowName)485 boolean containsWindow(String windowName) { 486 for (WindowState window : mWindowStates) { 487 if (window.getName().equals(windowName)) { 488 return true; 489 } 490 } 491 return false; 492 } 493 494 /** Check if at least one window which matches provided window name is visible. */ isWindowVisible(String windowName)495 boolean isWindowVisible(String windowName) { 496 for (WindowState window : mWindowStates) { 497 if (window.getName().equals(windowName)) { 498 if (window.isShown()) { 499 return true; 500 } 501 } 502 } 503 return false; 504 } 505 allWindowsVisible(String windowName)506 boolean allWindowsVisible(String windowName) { 507 boolean allVisible = false; 508 for (WindowState window : mWindowStates) { 509 if (window.getName().equals(windowName)) { 510 if (!window.isShown()) { 511 log("[VISIBLE] not visible" + windowName); 512 return false; 513 } 514 log("[VISIBLE] visible" + windowName); 515 allVisible = true; 516 } 517 } 518 return allVisible; 519 } 520 getStack(int stackId)521 WindowStack getStack(int stackId) { 522 for (WindowStack stack : mStacks) { 523 if (stackId == stack.mStackId) { 524 return stack; 525 } 526 } 527 return null; 528 } 529 530 getStackPosition(int stackId)531 int getStackPosition(int stackId) { 532 for (int i = 0; i < mStacks.size(); i++) { 533 if (stackId == mStacks.get(i).mStackId) { 534 return i; 535 } 536 } 537 return -1; 538 } 539 getInputMethodWindowState()540 WindowState getInputMethodWindowState() { 541 return getWindowStateForAppToken(mInputMethodWindowAppToken); 542 } 543 getStableBounds()544 Rectangle getStableBounds() { 545 return mStableBounds; 546 } 547 getDefaultPinnedStackBounds()548 Rectangle getDefaultPinnedStackBounds() { 549 return mDefaultPinnedStackBounds; 550 } 551 getPinnedStackMomentBounds()552 Rectangle getPinnedStackMomentBounds() { 553 return mPinnedStackMovementBounds; 554 } 555 findFirstWindowWithType(int type)556 WindowState findFirstWindowWithType(int type) { 557 for (WindowState window : mWindowStates) { 558 if (window.getType() == type) { 559 return window; 560 } 561 } 562 return null; 563 } 564 isDisplayFrozen()565 public boolean isDisplayFrozen() { 566 return mDisplayFrozen; 567 } 568 isDockedStackMinimized()569 public boolean isDockedStackMinimized() { 570 return mIsDockedStackMinimized; 571 } 572 reset()573 private void reset() { 574 mSysDump.clear(); 575 mStacks.clear(); 576 mDisplays.clear(); 577 mWindowStates.clear(); 578 mFocusedWindow = null; 579 mFocusedApp = null; 580 mInputMethodWindowAppToken = null; 581 } 582 583 static class WindowStack extends WindowContainer { 584 585 private static final Pattern sTaskIdPattern = Pattern.compile("taskId=(\\d+)"); 586 private static final Pattern sWindowAnimationBackgroundSurfacePattern = 587 Pattern.compile("mWindowAnimationBackgroundSurface:"); 588 589 int mStackId; 590 ArrayList<WindowTask> mTasks = new ArrayList(); 591 boolean mWindowAnimationBackgroundSurfaceShowing; 592 WindowStack()593 private WindowStack() { 594 595 } 596 create( LinkedList<String> dump, Pattern stackIdPattern, Pattern[] exitPatterns)597 static WindowStack create( 598 LinkedList<String> dump, Pattern stackIdPattern, Pattern[] exitPatterns) { 599 final String line = dump.peek().trim(); 600 601 final Matcher matcher = stackIdPattern.matcher(line); 602 if (!matcher.matches()) { 603 // Not a stack. 604 return null; 605 } 606 // For the stack Id line we just read. 607 dump.pop(); 608 609 final WindowStack stack = new WindowStack(); 610 log(line); 611 final String stackId = matcher.group(1); 612 log(stackId); 613 stack.mStackId = Integer.parseInt(stackId); 614 stack.extract(dump, exitPatterns); 615 return stack; 616 } 617 extract(LinkedList<String> dump, Pattern[] exitPatterns)618 void extract(LinkedList<String> dump, Pattern[] exitPatterns) { 619 620 final List<Pattern> taskExitPatterns = new ArrayList(); 621 Collections.addAll(taskExitPatterns, exitPatterns); 622 taskExitPatterns.add(sTaskIdPattern); 623 taskExitPatterns.add(sWindowAnimationBackgroundSurfacePattern); 624 final Pattern[] taskExitPatternsArray = 625 taskExitPatterns.toArray(new Pattern[taskExitPatterns.size()]); 626 627 while (!doneExtracting(dump, exitPatterns)) { 628 final WindowTask task = 629 WindowTask.create(dump, sTaskIdPattern, taskExitPatternsArray); 630 631 if (task != null) { 632 mTasks.add(task); 633 continue; 634 } 635 636 final String line = dump.pop().trim(); 637 638 if (extractFullscreen(line)) { 639 continue; 640 } 641 642 if (extractBounds(line)) { 643 continue; 644 } 645 646 if (extractWindowAnimationBackgroundSurface(line)) { 647 continue; 648 } 649 } 650 } 651 extractWindowAnimationBackgroundSurface(String line)652 boolean extractWindowAnimationBackgroundSurface(String line) { 653 if (sWindowAnimationBackgroundSurfacePattern.matcher(line).matches()) { 654 log(line); 655 mWindowAnimationBackgroundSurfaceShowing = true; 656 return true; 657 } 658 return false; 659 } 660 getTask(int taskId)661 WindowTask getTask(int taskId) { 662 for (WindowTask task : mTasks) { 663 if (taskId == task.mTaskId) { 664 return task; 665 } 666 } 667 return null; 668 } 669 isWindowAnimationBackgroundSurfaceShowing()670 boolean isWindowAnimationBackgroundSurfaceShowing() { 671 return mWindowAnimationBackgroundSurfaceShowing; 672 } 673 } 674 675 static class WindowTask extends WindowContainer { 676 private static final Pattern sTempInsetBoundsPattern = 677 Pattern.compile("mTempInsetBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]"); 678 679 private static final Pattern sAppTokenPattern = Pattern.compile( 680 "Activity #(\\d+) AppWindowToken\\{(\\S+) token=Token\\{(\\S+) " 681 + "ActivityRecord\\{(\\S+) u(\\d+) (\\S+) t(\\d+)\\}\\}\\}"); 682 683 684 int mTaskId; 685 Rectangle mTempInsetBounds; 686 List<String> mAppTokens = new ArrayList(); 687 WindowTask()688 private WindowTask() { 689 } 690 create( LinkedList<String> dump, Pattern taskIdPattern, Pattern[] exitPatterns)691 static WindowTask create( 692 LinkedList<String> dump, Pattern taskIdPattern, Pattern[] exitPatterns) { 693 final String line = dump.peek().trim(); 694 695 final Matcher matcher = taskIdPattern.matcher(line); 696 if (!matcher.matches()) { 697 // Not a task. 698 return null; 699 } 700 // For the task Id line we just read. 701 dump.pop(); 702 703 final WindowTask task = new WindowTask(); 704 log(line); 705 final String taskId = matcher.group(1); 706 log(taskId); 707 task.mTaskId = Integer.parseInt(taskId); 708 task.extract(dump, exitPatterns); 709 return task; 710 } 711 extract(LinkedList<String> dump, Pattern[] exitPatterns)712 private void extract(LinkedList<String> dump, Pattern[] exitPatterns) { 713 while (!doneExtracting(dump, exitPatterns)) { 714 final String line = dump.pop().trim(); 715 716 if (extractFullscreen(line)) { 717 continue; 718 } 719 720 if (extractBounds(line)) { 721 continue; 722 } 723 724 Matcher matcher = sTempInsetBoundsPattern.matcher(line); 725 if (matcher.matches()) { 726 log(line); 727 mTempInsetBounds = extractBounds(matcher); 728 } 729 730 matcher = sAppTokenPattern.matcher(line); 731 if (matcher.matches()) { 732 log(line); 733 final String appToken = matcher.group(6); 734 log(appToken); 735 mAppTokens.add(appToken); 736 continue; 737 } 738 } 739 } 740 } 741 742 static abstract class WindowContainer { 743 protected static final Pattern sFullscreenPattern = Pattern.compile("mFillsParent=(\\S+)"); 744 protected static final Pattern sBoundsPattern = 745 Pattern.compile("mBounds=\\[(-?\\d+),(-?\\d+)\\]\\[(-?\\d+),(-?\\d+)\\]"); 746 747 protected boolean mFullscreen; 748 protected Rectangle mBounds; 749 doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns)750 static boolean doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns) { 751 if (dump.isEmpty()) { 752 return true; 753 } 754 final String line = dump.peek().trim(); 755 756 for (Pattern pattern : exitPatterns) { 757 if (pattern.matcher(line).matches()) { 758 return true; 759 } 760 } 761 return false; 762 } 763 extractFullscreen(String line)764 boolean extractFullscreen(String line) { 765 final Matcher matcher = sFullscreenPattern.matcher(line); 766 if (!matcher.matches()) { 767 return false; 768 } 769 log(line); 770 final String fullscreen = matcher.group(1); 771 log(fullscreen); 772 mFullscreen = Boolean.valueOf(fullscreen); 773 return true; 774 } 775 extractBounds(String line)776 boolean extractBounds(String line) { 777 final Matcher matcher = sBoundsPattern.matcher(line); 778 if (!matcher.matches()) { 779 return false; 780 } 781 log(line); 782 mBounds = extractBounds(matcher); 783 return true; 784 } 785 extractBounds(Matcher matcher)786 static Rectangle extractBounds(Matcher matcher) { 787 final int left = Integer.valueOf(matcher.group(1)); 788 final int top = Integer.valueOf(matcher.group(2)); 789 final int right = Integer.valueOf(matcher.group(3)); 790 final int bottom = Integer.valueOf(matcher.group(4)); 791 final Rectangle rect = new Rectangle(left, top, right - left, bottom - top); 792 793 log(rect.toString()); 794 return rect; 795 } 796 extractMultipleBounds(Matcher matcher, int groupIndex, Rectangle... rectList)797 static void extractMultipleBounds(Matcher matcher, int groupIndex, Rectangle... rectList) { 798 for (Rectangle rect : rectList) { 799 if (rect == null) { 800 return; 801 } 802 final int left = Integer.valueOf(matcher.group(groupIndex++)); 803 final int top = Integer.valueOf(matcher.group(groupIndex++)); 804 final int right = Integer.valueOf(matcher.group(groupIndex++)); 805 final int bottom = Integer.valueOf(matcher.group(groupIndex++)); 806 rect.setBounds(left, top, right - left, bottom - top); 807 } 808 } 809 getBounds()810 Rectangle getBounds() { 811 return mBounds; 812 } 813 isFullscreen()814 boolean isFullscreen() { 815 return mFullscreen; 816 } 817 } 818 819 static class Display extends WindowContainer { 820 private static final String TAG = "[Display] "; 821 822 private static final Pattern sDisplayInfoPattern = 823 Pattern.compile("(.+) (\\d+)dpi cur=(\\d+)x(\\d+) app=(\\d+)x(\\d+) (.+)"); 824 825 private final int mDisplayId; 826 private Rectangle mDisplayRect = new Rectangle(); 827 private Rectangle mAppRect = new Rectangle(); 828 private int mDpi; 829 Display(int displayId)830 private Display(int displayId) { 831 mDisplayId = displayId; 832 } 833 getDisplayId()834 int getDisplayId() { 835 return mDisplayId; 836 } 837 getDpi()838 int getDpi() { 839 return mDpi; 840 } 841 getDisplayRect()842 Rectangle getDisplayRect() { 843 return mDisplayRect; 844 } 845 getAppRect()846 Rectangle getAppRect() { 847 return mAppRect; 848 } 849 create(LinkedList<String> dump, Pattern[] exitPatterns)850 static Display create(LinkedList<String> dump, Pattern[] exitPatterns) { 851 // TODO: exit pattern for displays? 852 final String line = dump.peek().trim(); 853 854 Matcher matcher = sDisplayIdPattern.matcher(line); 855 if (!matcher.matches()) { 856 return null; 857 } 858 859 log(TAG + "DISPLAY_ID: " + line); 860 dump.pop(); 861 862 final int displayId = Integer.valueOf(matcher.group(1)); 863 final Display display = new Display(displayId); 864 display.extract(dump, exitPatterns); 865 return display; 866 } 867 extract(LinkedList<String> dump, Pattern[] exitPatterns)868 private void extract(LinkedList<String> dump, Pattern[] exitPatterns) { 869 while (!doneExtracting(dump, exitPatterns)) { 870 final String line = dump.pop().trim(); 871 872 final Matcher matcher = sDisplayInfoPattern.matcher(line); 873 if (matcher.matches()) { 874 log(TAG + "DISPLAY_INFO: " + line); 875 mDpi = Integer.valueOf(matcher.group(2)); 876 877 final int displayWidth = Integer.valueOf(matcher.group(3)); 878 final int displayHeight = Integer.valueOf(matcher.group(4)); 879 mDisplayRect.setBounds(0, 0, displayWidth, displayHeight); 880 881 final int appWidth = Integer.valueOf(matcher.group(5)); 882 final int appHeight = Integer.valueOf(matcher.group(6)); 883 mAppRect.setBounds(0, 0, appWidth, appHeight); 884 885 // break as we don't need other info for now 886 break; 887 } 888 // Extract other info here if needed 889 } 890 } 891 892 @Override toString()893 public String toString() { 894 return "Display #" + mDisplayId + ": mDisplayRect=" + mDisplayRect 895 + " mAppRect=" + mAppRect; 896 } 897 } 898 899 public static class WindowState extends WindowContainer { 900 private static final String TAG = "[WindowState] "; 901 902 public static final int TYPE_WALLPAPER = 2013; 903 904 private static final int WINDOW_TYPE_NORMAL = 0; 905 private static final int WINDOW_TYPE_STARTING = 1; 906 private static final int WINDOW_TYPE_EXITING = 2; 907 private static final int WINDOW_TYPE_DEBUGGER = 3; 908 909 private static final String RECT_STR = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]"; 910 private static final String NEGATIVE_VALUES_ALLOWED_RECT_STR = 911 "\\[([-\\d]+),([-\\d]+)\\]\\[([-\\d]+),([-\\d]+)\\]"; 912 private static final Pattern sMainFramePattern = Pattern.compile("mFrame=" + RECT_STR + ".+"); 913 private static final Pattern sFramePattern = 914 Pattern.compile("Frames: containing=" + RECT_STR + " parent=" + RECT_STR); 915 private static final Pattern sContentFramePattern = 916 Pattern.compile("content=" + RECT_STR + " .+"); 917 private static final Pattern sWindowAssociationPattern = 918 Pattern.compile("mDisplayId=(\\d+) stackId=(\\d+) (.+)"); 919 private static final Pattern sSurfaceInsetsPattern = 920 Pattern.compile("Cur insets.+surface=" + RECT_STR + ".+"); 921 private static final Pattern sContentInsetsPattern = 922 Pattern.compile("Cur insets.+content=" + NEGATIVE_VALUES_ALLOWED_RECT_STR + ".+"); 923 private static final Pattern sGivenContentInsetsPattern = 924 Pattern.compile("mGivenContentInsets=" + RECT_STR + ".+"); 925 private static final Pattern sCropPattern = 926 Pattern.compile(".+mLastClipRect=" + RECT_STR + ".*"); 927 private static final Pattern sSurfacePattern = 928 Pattern.compile("Surface: shown=(\\S+) layer=(\\d+) alpha=[\\d.]+ rect=\\([\\d.-]+,[\\d.-]+\\) [\\d.]+ x [\\d.]+.*"); 929 private static final Pattern sAttrsPattern= 930 Pattern.compile("mAttrs=WM\\.LayoutParams\\{.*ty=(\\d+).*\\}"); 931 932 933 private final String mName; 934 private final String mAppToken; 935 private final int mWindowType; 936 private int mType; 937 private int mDisplayId; 938 private int mStackId; 939 private int mLayer; 940 private boolean mShown; 941 private Rectangle mContainingFrame = new Rectangle(); 942 private Rectangle mParentFrame = new Rectangle(); 943 private Rectangle mContentFrame = new Rectangle(); 944 private Rectangle mFrame = new Rectangle(); 945 private Rectangle mSurfaceInsets = new Rectangle(); 946 private Rectangle mContentInsets = new Rectangle(); 947 private Rectangle mGivenContentInsets = new Rectangle(); 948 private Rectangle mCrop = new Rectangle(); 949 950 WindowState(Matcher matcher, int windowType)951 private WindowState(Matcher matcher, int windowType) { 952 mName = matcher.group(4); 953 mAppToken = matcher.group(2); 954 mWindowType = windowType; 955 } 956 getName()957 public String getName() { 958 return mName; 959 } 960 getToken()961 String getToken() { 962 return mAppToken; 963 } 964 isStartingWindow()965 boolean isStartingWindow() { 966 return mWindowType == WINDOW_TYPE_STARTING; 967 } 968 isExitingWindow()969 boolean isExitingWindow() { 970 return mWindowType == WINDOW_TYPE_EXITING; 971 } 972 isDebuggerWindow()973 boolean isDebuggerWindow() { 974 return mWindowType == WINDOW_TYPE_DEBUGGER; 975 } 976 getDisplayId()977 int getDisplayId() { 978 return mDisplayId; 979 } 980 getStackId()981 int getStackId() { 982 return mStackId; 983 } 984 getLayer()985 int getLayer() { 986 return mLayer; 987 } 988 getContainingFrame()989 Rectangle getContainingFrame() { 990 return mContainingFrame; 991 } 992 getFrame()993 Rectangle getFrame() { 994 return mFrame; 995 } 996 getSurfaceInsets()997 Rectangle getSurfaceInsets() { 998 return mSurfaceInsets; 999 } 1000 getContentInsets()1001 Rectangle getContentInsets() { 1002 return mContentInsets; 1003 } 1004 getGivenContentInsets()1005 Rectangle getGivenContentInsets() { 1006 return mGivenContentInsets; 1007 } 1008 getContentFrame()1009 Rectangle getContentFrame() { 1010 return mContentFrame; 1011 } 1012 getParentFrame()1013 Rectangle getParentFrame() { 1014 return mParentFrame; 1015 } 1016 getCrop()1017 Rectangle getCrop() { 1018 return mCrop; 1019 } 1020 isShown()1021 boolean isShown() { 1022 return mShown; 1023 } 1024 getType()1025 int getType() { 1026 return mType; 1027 } 1028 create(LinkedList<String> dump, Pattern[] exitPatterns)1029 static WindowState create(LinkedList<String> dump, Pattern[] exitPatterns) { 1030 final String line = dump.peek().trim(); 1031 1032 Matcher matcher = sWindowPattern.matcher(line); 1033 if (!matcher.matches()) { 1034 return null; 1035 } 1036 1037 log(TAG + "WINDOW: " + line); 1038 dump.pop(); 1039 1040 final WindowState window; 1041 Matcher specialMatcher; 1042 if ((specialMatcher = sStartingWindowPattern.matcher(line)).matches()) { 1043 log(TAG + "STARTING: " + line); 1044 window = new WindowState(specialMatcher, WINDOW_TYPE_STARTING); 1045 } else if ((specialMatcher = sExitingWindowPattern.matcher(line)).matches()) { 1046 log(TAG + "EXITING: " + line); 1047 window = new WindowState(specialMatcher, WINDOW_TYPE_EXITING); 1048 } else if ((specialMatcher = sDebuggerWindowPattern.matcher(line)).matches()) { 1049 log(TAG + "DEBUGGER: " + line); 1050 window = new WindowState(specialMatcher, WINDOW_TYPE_DEBUGGER); 1051 } else { 1052 window = new WindowState(matcher, WINDOW_TYPE_NORMAL); 1053 } 1054 1055 window.extract(dump, exitPatterns); 1056 return window; 1057 } 1058 extract(LinkedList<String> dump, Pattern[] exitPatterns)1059 private void extract(LinkedList<String> dump, Pattern[] exitPatterns) { 1060 while (!doneExtracting(dump, exitPatterns)) { 1061 final String line = dump.pop().trim(); 1062 1063 Matcher matcher = sWindowAssociationPattern.matcher(line); 1064 if (matcher.matches()) { 1065 log(TAG + "WINDOW_ASSOCIATION: " + line); 1066 mDisplayId = Integer.valueOf(matcher.group(1)); 1067 mStackId = Integer.valueOf(matcher.group(2)); 1068 continue; 1069 } 1070 1071 matcher = sMainFramePattern.matcher(line); 1072 if (matcher.matches()) { 1073 log(TAG + "MAIN WINDOW FRAME: " + line); 1074 mFrame = extractBounds(matcher); 1075 continue; 1076 } 1077 1078 matcher = sFramePattern.matcher(line); 1079 if (matcher.matches()) { 1080 log(TAG + "FRAME: " + line); 1081 extractMultipleBounds(matcher, 1, mContainingFrame, mParentFrame); 1082 continue; 1083 } 1084 1085 matcher = sContentFramePattern.matcher(line); 1086 if (matcher.matches()) { 1087 log(TAG + "CONTENT FRAME: " + line); 1088 mContentFrame = extractBounds(matcher); 1089 } 1090 1091 matcher = sSurfaceInsetsPattern.matcher(line); 1092 if (matcher.matches()) { 1093 log(TAG + "INSETS: " + line); 1094 mSurfaceInsets = extractBounds(matcher); 1095 } 1096 1097 matcher = sContentInsetsPattern.matcher(line); 1098 if (matcher.matches()) { 1099 log(TAG + "CONTENT INSETS: " + line); 1100 mContentInsets = extractBounds(matcher); 1101 } 1102 1103 matcher = sCropPattern.matcher(line); 1104 if (matcher.matches()) { 1105 log(TAG + "CROP: " + line); 1106 mCrop = extractBounds(matcher); 1107 } 1108 1109 matcher = sSurfacePattern.matcher(line); 1110 if (matcher.matches()) { 1111 log(TAG + "SURFACE: " + line); 1112 mShown = Boolean.valueOf(matcher.group(1)); 1113 mLayer = Integer.valueOf(matcher.group(2)); 1114 } 1115 1116 matcher = sAttrsPattern.matcher(line); 1117 if (matcher.matches()) { 1118 log(TAG + "ATTRS: " + line); 1119 mType = Integer.valueOf(matcher.group(1)); 1120 } 1121 1122 matcher = sGivenContentInsetsPattern.matcher(line); 1123 if (matcher.matches()) { 1124 log(TAG + "GIVEN CONTENT INSETS: " + line); 1125 mGivenContentInsets = extractBounds(matcher); 1126 } 1127 1128 // Extract other info here if needed 1129 } 1130 } 1131 getWindowTypeSuffix(int windowType)1132 private static String getWindowTypeSuffix(int windowType) { 1133 switch (windowType) { 1134 case WINDOW_TYPE_STARTING: return " STARTING"; 1135 case WINDOW_TYPE_EXITING: return " EXITING"; 1136 case WINDOW_TYPE_DEBUGGER: return " DEBUGGER"; 1137 default: break; 1138 } 1139 return ""; 1140 } 1141 1142 @Override toString()1143 public String toString() { 1144 return "WindowState: {" + mAppToken + " " + mName 1145 + getWindowTypeSuffix(mWindowType) + "}" + " type=" + mType 1146 + " cf=" + mContainingFrame + " pf=" + mParentFrame; 1147 } 1148 } 1149 } 1150