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 com.android.tradefed.device.CollectingOutputReceiver; 20 import com.android.tradefed.device.DeviceNotAvailableException; 21 import com.android.tradefed.device.ITestDevice; 22 23 import java.awt.Rectangle; 24 import java.lang.Integer; 25 import java.lang.String; 26 import java.util.ArrayList; 27 import java.util.Collections; 28 import java.util.HashMap; 29 import java.util.LinkedList; 30 import java.util.List; 31 32 import java.util.Map; 33 import java.util.regex.Pattern; 34 import java.util.regex.Matcher; 35 36 import static android.server.cts.ActivityManagerTestBase.HOME_STACK_ID; 37 import static android.server.cts.ActivityManagerTestBase.RECENTS_STACK_ID; 38 import static android.server.cts.StateLogger.log; 39 import static android.server.cts.StateLogger.logE; 40 41 class ActivityManagerState { 42 public static final int DUMP_MODE_ACTIVITIES = 0; 43 44 public static final String STATE_RESUMED = "RESUMED"; 45 public static final String STATE_PAUSED = "PAUSED"; 46 public static final String STATE_STOPPED = "STOPPED"; 47 48 public static final String RESIZE_MODE_RESIZEABLE = "RESIZE_MODE_RESIZEABLE"; 49 50 private static final String DUMPSYS_ACTIVITY_ACTIVITIES = "dumpsys activity activities"; 51 52 // Copied from ActivityRecord.java 53 private static final int APPLICATION_ACTIVITY_TYPE = 0; 54 private static final int HOME_ACTIVITY_TYPE = 1; 55 private static final int RECENTS_ACTIVITY_TYPE = 2; 56 57 private final Pattern mDisplayIdPattern = Pattern.compile("Display #(\\d+).*"); 58 private final Pattern mStackIdPattern = Pattern.compile("Stack #(\\d+)\\:"); 59 private final Pattern mResumedActivityPattern = 60 Pattern.compile("ResumedActivity\\: ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)\\}"); 61 private final Pattern mFocusedStackPattern = 62 Pattern.compile("mFocusedStack=ActivityStack\\{(.+) stackId=(\\d+), (.+)\\}(.+)"); 63 64 private final Pattern[] mExtractStackExitPatterns = 65 { mStackIdPattern, mResumedActivityPattern, mFocusedStackPattern, mDisplayIdPattern }; 66 67 // Stacks in z-order with the top most at the front of the list, starting with primary display. 68 private final List<ActivityStack> mStacks = new ArrayList(); 69 // Stacks on all attached displays, in z-order with the top most at the front of the list. 70 private final Map<Integer, List<ActivityStack>> mDisplayStacks = new HashMap<>(); 71 private KeyguardControllerState mKeyguardControllerState; 72 private int mFocusedStackId = -1; 73 private String mResumedActivityRecord = null; 74 private final List<String> mResumedActivities = new ArrayList(); 75 private final LinkedList<String> mSysDump = new LinkedList(); 76 computeState(ITestDevice device)77 void computeState(ITestDevice device) throws DeviceNotAvailableException { 78 computeState(device, DUMP_MODE_ACTIVITIES); 79 } 80 computeState(ITestDevice device, int dumpMode)81 void computeState(ITestDevice device, int dumpMode) throws DeviceNotAvailableException { 82 // It is possible the system is in the middle of transition to the right state when we get 83 // the dump. We try a few times to get the information we need before giving up. 84 int retriesLeft = 3; 85 boolean retry = false; 86 String dump = null; 87 88 log("=============================="); 89 log(" ActivityManagerState "); 90 log("=============================="); 91 92 do { 93 if (retry) { 94 log("***Incomplete AM state. Retrying..."); 95 // Wait half a second between retries for activity manager to finish transitioning. 96 try { 97 Thread.sleep(500); 98 } catch (InterruptedException e) { 99 log(e.toString()); 100 // Well I guess we are not waiting... 101 } 102 } 103 104 final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver(); 105 String dumpsysCmd = ""; 106 switch (dumpMode) { 107 case DUMP_MODE_ACTIVITIES: 108 dumpsysCmd = DUMPSYS_ACTIVITY_ACTIVITIES; break; 109 } 110 device.executeShellCommand(dumpsysCmd, outputReceiver); 111 dump = outputReceiver.getOutput(); 112 parseSysDump(dump); 113 114 retry = mStacks.isEmpty() || mFocusedStackId == -1 || (mResumedActivityRecord == null 115 || mResumedActivities.isEmpty()) && !mKeyguardControllerState.keyguardShowing; 116 } while (retry && retriesLeft-- > 0); 117 118 if (retry) { 119 log(dump); 120 } 121 122 if (mStacks.isEmpty()) { 123 logE("No stacks found..."); 124 } 125 if (mFocusedStackId == -1) { 126 logE("No focused stack found..."); 127 } 128 if (mResumedActivityRecord == null) { 129 logE("No focused activity found..."); 130 } 131 if (mResumedActivities.isEmpty()) { 132 logE("No resumed activities found..."); 133 } 134 } 135 parseSysDump(String sysDump)136 private void parseSysDump(String sysDump) { 137 reset(); 138 139 Collections.addAll(mSysDump, sysDump.split("\\n")); 140 141 int currentDisplayId = 0; 142 while (!mSysDump.isEmpty()) { 143 final ActivityStack stack = ActivityStack.create(mSysDump, mStackIdPattern, 144 mExtractStackExitPatterns, currentDisplayId); 145 146 if (stack != null) { 147 mStacks.add(stack); 148 mDisplayStacks.get(currentDisplayId).add(stack); 149 if (stack.mResumedActivity != null) { 150 mResumedActivities.add(stack.mResumedActivity); 151 } 152 continue; 153 } 154 155 KeyguardControllerState controller = KeyguardControllerState.create( 156 mSysDump, new Pattern[0]); 157 if (controller != null) { 158 mKeyguardControllerState = controller; 159 continue; 160 } 161 162 final String line = mSysDump.pop().trim(); 163 164 Matcher matcher = mFocusedStackPattern.matcher(line); 165 if (matcher.matches()) { 166 log(line); 167 final String stackId = matcher.group(2); 168 log(stackId); 169 mFocusedStackId = Integer.parseInt(stackId); 170 continue; 171 } 172 173 matcher = mResumedActivityPattern.matcher(line); 174 if (matcher.matches()) { 175 log(line); 176 mResumedActivityRecord = matcher.group(3); 177 log(mResumedActivityRecord); 178 continue; 179 } 180 181 matcher = mDisplayIdPattern.matcher(line); 182 if (matcher.matches()) { 183 log(line); 184 final String displayId = matcher.group(1); 185 log(displayId); 186 currentDisplayId = Integer.parseInt(displayId); 187 mDisplayStacks.put(currentDisplayId, new ArrayList<>()); 188 } 189 } 190 } 191 reset()192 private void reset() { 193 mStacks.clear(); 194 mFocusedStackId = -1; 195 mResumedActivityRecord = null; 196 mResumedActivities.clear(); 197 mSysDump.clear(); 198 mKeyguardControllerState = null; 199 } 200 getFrontStackId(int displayId)201 int getFrontStackId(int displayId) { 202 return mDisplayStacks.get(displayId).get(0).mStackId; 203 } 204 getFocusedStackId()205 int getFocusedStackId() { 206 return mFocusedStackId; 207 } 208 getFocusedActivity()209 String getFocusedActivity() { 210 return mResumedActivityRecord; 211 } 212 getResumedActivity()213 String getResumedActivity() { 214 return mResumedActivities.get(0); 215 } 216 getResumedActivitiesCount()217 int getResumedActivitiesCount() { 218 return mResumedActivities.size(); 219 } 220 getKeyguardControllerState()221 public KeyguardControllerState getKeyguardControllerState() { 222 return mKeyguardControllerState; 223 } 224 containsStack(int stackId)225 boolean containsStack(int stackId) { 226 return getStackById(stackId) != null; 227 } 228 getStackById(int stackId)229 ActivityStack getStackById(int stackId) { 230 for (ActivityStack stack : mStacks) { 231 if (stackId == stack.mStackId) { 232 return stack; 233 } 234 } 235 return null; 236 } 237 getStackPosition(int stackId)238 int getStackPosition(int stackId) { 239 for (int i = 0; i < mStacks.size(); i++) { 240 if (stackId == mStacks.get(i).mStackId) { 241 return i; 242 } 243 } 244 return -1; 245 } 246 getStacks()247 List<ActivityStack> getStacks() { 248 return new ArrayList(mStacks); 249 } 250 getStackCount()251 int getStackCount() { 252 return mStacks.size(); 253 } 254 containsActivity(String activityName)255 boolean containsActivity(String activityName) { 256 for (ActivityStack stack : mStacks) { 257 for (ActivityTask task : stack.mTasks) { 258 for (Activity activity : task.mActivities) { 259 if (activity.name.equals(activityName)) { 260 return true; 261 } 262 } 263 } 264 } 265 return false; 266 } 267 isActivityVisible(String activityName)268 boolean isActivityVisible(String activityName) { 269 for (ActivityStack stack : mStacks) { 270 for (ActivityTask task : stack.mTasks) { 271 for (Activity activity : task.mActivities) { 272 if (activity.name.equals(activityName)) { 273 return activity.visible; 274 } 275 } 276 } 277 } 278 return false; 279 } 280 hasActivityState(String activityName, String activityState)281 boolean hasActivityState(String activityName, String activityState) { 282 String fullName = ActivityManagerTestBase.getActivityComponentName(activityName); 283 for (ActivityStack stack : mStacks) { 284 for (ActivityTask task : stack.mTasks) { 285 for (Activity activity : task.mActivities) { 286 if (activity.name.equals(fullName)) { 287 return activity.state.equals(activityState); 288 } 289 } 290 } 291 } 292 return false; 293 } 294 getActivityProcId(String activityName)295 int getActivityProcId(String activityName) { 296 for (ActivityStack stack : mStacks) { 297 for (ActivityTask task : stack.mTasks) { 298 for (Activity activity : task.mActivities) { 299 if (activity.name.equals(activityName)) { 300 return activity.procId; 301 } 302 } 303 } 304 } 305 return -1; 306 } 307 isHomeActivityVisible()308 boolean isHomeActivityVisible() { 309 final Activity homeActivity = getHomeActivity(); 310 return homeActivity != null && homeActivity.visible; 311 } 312 isRecentsActivityVisible()313 boolean isRecentsActivityVisible() { 314 final Activity recentsActivity = getRecentsActivity(); 315 return recentsActivity != null && recentsActivity.visible; 316 } 317 getHomeActivityName()318 String getHomeActivityName() { 319 Activity activity = getHomeActivity(); 320 if (activity == null) { 321 return null; 322 } 323 return activity.name; 324 } 325 getHomeTask()326 ActivityTask getHomeTask() { 327 ActivityStack homeStack = getStackById(HOME_STACK_ID); 328 if (homeStack != null) { 329 for (ActivityTask task : homeStack.mTasks) { 330 if (task.mTaskType == HOME_ACTIVITY_TYPE) { 331 return task; 332 } 333 } 334 return null; 335 } 336 return null; 337 } 338 getRecentsTask()339 ActivityTask getRecentsTask() { 340 ActivityStack recentsStack = getStackById(RECENTS_STACK_ID); 341 if (recentsStack != null) { 342 for (ActivityTask task : recentsStack.mTasks) { 343 if (task.mTaskType == RECENTS_ACTIVITY_TYPE) { 344 return task; 345 } 346 } 347 return null; 348 } 349 return null; 350 } 351 getHomeActivity()352 private Activity getHomeActivity() { 353 final ActivityTask homeTask = getHomeTask(); 354 return homeTask != null ? homeTask.mActivities.get(homeTask.mActivities.size() - 1) : null; 355 } 356 getRecentsActivity()357 private Activity getRecentsActivity() { 358 final ActivityTask recentsTask = getRecentsTask(); 359 return recentsTask != null ? recentsTask.mActivities.get(recentsTask.mActivities.size() - 1) 360 : null; 361 } 362 getTaskByActivityName(String activityName)363 ActivityTask getTaskByActivityName(String activityName) { 364 return getTaskByActivityName(activityName, -1); 365 } 366 getTaskByActivityName(String activityName, int stackId)367 ActivityTask getTaskByActivityName(String activityName, int stackId) { 368 String fullName = ActivityManagerTestBase.getActivityComponentName(activityName); 369 for (ActivityStack stack : mStacks) { 370 if (stackId == -1 || stackId == stack.mStackId) { 371 for (ActivityTask task : stack.mTasks) { 372 for (Activity activity : task.mActivities) { 373 if (activity.name.equals(fullName)) { 374 return task; 375 } 376 } 377 } 378 } 379 } 380 return null; 381 } 382 383 static class ActivityStack extends ActivityContainer { 384 385 private static final Pattern TASK_ID_PATTERN = Pattern.compile("Task id #(\\d+)"); 386 private static final Pattern RESUMED_ACTIVITY_PATTERN = Pattern.compile( 387 "mResumedActivity\\: ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)\\}"); 388 389 int mDisplayId; 390 int mStackId; 391 String mResumedActivity; 392 ArrayList<ActivityTask> mTasks = new ArrayList(); 393 ActivityStack()394 private ActivityStack() { 395 } 396 create(LinkedList<String> dump, Pattern stackIdPattern, Pattern[] exitPatterns, int displayId)397 static ActivityStack create(LinkedList<String> dump, Pattern stackIdPattern, 398 Pattern[] exitPatterns, int displayId) { 399 final String line = dump.peek().trim(); 400 401 final Matcher matcher = stackIdPattern.matcher(line); 402 if (!matcher.matches()) { 403 // Not a stack. 404 return null; 405 } 406 // For the stack Id line we just read. 407 dump.pop(); 408 409 final ActivityStack stack = new ActivityStack(); 410 stack.mDisplayId = displayId; 411 log(line); 412 final String stackId = matcher.group(1); 413 log(stackId); 414 stack.mStackId = Integer.parseInt(stackId); 415 stack.extract(dump, exitPatterns); 416 return stack; 417 } 418 extract(LinkedList<String> dump, Pattern[] exitPatterns)419 private void extract(LinkedList<String> dump, Pattern[] exitPatterns) { 420 421 final List<Pattern> taskExitPatterns = new ArrayList(); 422 Collections.addAll(taskExitPatterns, exitPatterns); 423 taskExitPatterns.add(TASK_ID_PATTERN); 424 taskExitPatterns.add(RESUMED_ACTIVITY_PATTERN); 425 final Pattern[] taskExitPatternsArray = 426 taskExitPatterns.toArray(new Pattern[taskExitPatterns.size()]); 427 428 while (!doneExtracting(dump, exitPatterns)) { 429 final ActivityTask task = 430 ActivityTask.create(dump, TASK_ID_PATTERN, taskExitPatternsArray); 431 432 if (task != null) { 433 mTasks.add(task); 434 continue; 435 } 436 437 final String line = dump.pop().trim(); 438 439 if (extractFullscreen(line)) { 440 continue; 441 } 442 443 if (extractBounds(line)) { 444 continue; 445 } 446 447 Matcher matcher = RESUMED_ACTIVITY_PATTERN.matcher(line); 448 if (matcher.matches()) { 449 log(line); 450 mResumedActivity = matcher.group(3); 451 log(mResumedActivity); 452 continue; 453 } 454 } 455 } 456 457 /** 458 * @return the bottom task in the stack. 459 */ getBottomTask()460 ActivityTask getBottomTask() { 461 if (!mTasks.isEmpty()) { 462 // NOTE: Unlike the ActivityManager internals, we dump the state from top to bottom, 463 // so the indices are inverted 464 return mTasks.get(mTasks.size() - 1); 465 } 466 return null; 467 } 468 469 /** 470 * @return the top task in the stack. 471 */ getTopTask()472 ActivityTask getTopTask() { 473 if (!mTasks.isEmpty()) { 474 // NOTE: Unlike the ActivityManager internals, we dump the state from top to bottom, 475 // so the indices are inverted 476 return mTasks.get(0); 477 } 478 return null; 479 } 480 getTasks()481 List<ActivityTask> getTasks() { 482 return new ArrayList(mTasks); 483 } 484 getTask(int taskId)485 ActivityTask getTask(int taskId) { 486 for (ActivityTask task : mTasks) { 487 if (taskId == task.mTaskId) { 488 return task; 489 } 490 } 491 return null; 492 } 493 } 494 495 static class ActivityTask extends ActivityContainer { 496 private static final Pattern TASK_RECORD_PATTERN = Pattern.compile("\\* TaskRecord\\" 497 + "{(\\S+) #(\\d+) (\\S+)=(\\S+) U=(\\d+) StackId=(\\d+) sz=(\\d+)\\}"); 498 499 private static final Pattern LAST_NON_FULLSCREEN_BOUNDS_PATTERN = Pattern.compile( 500 "mLastNonFullscreenBounds=Rect\\((\\d+), (\\d+) - (\\d+), (\\d+)\\)"); 501 502 private static final Pattern ORIG_ACTIVITY_PATTERN = Pattern.compile("origActivity=(\\S+)"); 503 private static final Pattern REAL_ACTIVITY_PATTERN = Pattern.compile("realActivity=(\\S+)"); 504 505 private static final Pattern ACTIVITY_NAME_PATTERN = Pattern.compile( 506 "\\* Hist #(\\d+)\\: ActivityRecord\\{(\\S+) u(\\d+) (\\S+) t(\\d+)\\}"); 507 508 private static final Pattern TASK_TYPE_PATTERN = Pattern.compile("autoRemoveRecents=(\\S+) " 509 + "isPersistable=(\\S+) numFullscreen=(\\d+) taskType=(\\d+) " 510 + "mTaskToReturnTo=(\\d+)"); 511 512 private static final Pattern RESIZABLE_PATTERN = Pattern.compile( 513 ".*mResizeMode=([^\\s]+).*"); 514 515 int mTaskId; 516 int mStackId; 517 Rectangle mLastNonFullscreenBounds; 518 String mRealActivity; 519 String mOrigActivity; 520 ArrayList<Activity> mActivities = new ArrayList(); 521 int mTaskType = -1; 522 int mReturnToType = -1; 523 private String mResizeMode; 524 ActivityTask()525 private ActivityTask() { 526 } 527 create( LinkedList<String> dump, Pattern taskIdPattern, Pattern[] exitPatterns)528 static ActivityTask create( 529 LinkedList<String> dump, Pattern taskIdPattern, Pattern[] exitPatterns) { 530 final String line = dump.peek().trim(); 531 532 final Matcher matcher = taskIdPattern.matcher(line); 533 if (!matcher.matches()) { 534 // Not a task. 535 return null; 536 } 537 // For the task Id line we just read. 538 dump.pop(); 539 540 final ActivityTask task = new ActivityTask(); 541 log(line); 542 final String taskId = matcher.group(1); 543 log(taskId); 544 task.mTaskId = Integer.parseInt(taskId); 545 task.extract(dump, exitPatterns); 546 return task; 547 } 548 extract(LinkedList<String> dump, Pattern[] exitPatterns)549 private void extract(LinkedList<String> dump, Pattern[] exitPatterns) { 550 final List<Pattern> activityExitPatterns = new ArrayList(); 551 Collections.addAll(activityExitPatterns, exitPatterns); 552 activityExitPatterns.add(ACTIVITY_NAME_PATTERN); 553 final Pattern[] activityExitPatternsArray = 554 activityExitPatterns.toArray(new Pattern[activityExitPatterns.size()]); 555 556 while (!doneExtracting(dump, exitPatterns)) { 557 final Activity activity = 558 Activity.create(dump, ACTIVITY_NAME_PATTERN, activityExitPatternsArray); 559 560 if (activity != null) { 561 mActivities.add(activity); 562 continue; 563 } 564 565 final String line = dump.pop().trim(); 566 567 if (extractFullscreen(line)) { 568 continue; 569 } 570 571 if (extractBounds(line)) { 572 continue; 573 } 574 575 if (extractMinimalSize(line)) { 576 continue; 577 } 578 579 Matcher matcher = TASK_RECORD_PATTERN.matcher(line); 580 if (matcher.matches()) { 581 log(line); 582 final String stackId = matcher.group(6); 583 mStackId = Integer.valueOf(stackId); 584 log(stackId); 585 continue; 586 } 587 588 matcher = LAST_NON_FULLSCREEN_BOUNDS_PATTERN.matcher(line); 589 if (matcher.matches()) { 590 log(line); 591 mLastNonFullscreenBounds = extractBounds(matcher); 592 } 593 594 matcher = REAL_ACTIVITY_PATTERN.matcher(line); 595 if (matcher.matches()) { 596 if (mRealActivity == null) { 597 log(line); 598 mRealActivity = matcher.group(1); 599 log(mRealActivity); 600 } 601 continue; 602 } 603 604 matcher = ORIG_ACTIVITY_PATTERN.matcher(line); 605 if (matcher.matches()) { 606 if (mOrigActivity == null) { 607 log(line); 608 mOrigActivity = matcher.group(1); 609 log(mOrigActivity); 610 } 611 continue; 612 } 613 614 matcher = TASK_TYPE_PATTERN.matcher(line); 615 if (matcher.matches()) { 616 log(line); 617 mTaskType = Integer.valueOf(matcher.group(4)); 618 mReturnToType = Integer.valueOf(matcher.group(5)); 619 continue; 620 } 621 622 matcher = RESIZABLE_PATTERN.matcher(line); 623 if (matcher.matches()) { 624 log(line); 625 mResizeMode = matcher.group(1); 626 log(mResizeMode); 627 continue; 628 } 629 } 630 } 631 getResizeMode()632 public String getResizeMode() { 633 return mResizeMode; 634 } 635 636 /** 637 * @return whether this task contains the given activity. 638 */ containsActivity(String activityName)639 public boolean containsActivity(String activityName) { 640 for (Activity activity : mActivities) { 641 if (activity.name.equals(activityName)) { 642 return true; 643 } 644 } 645 return false; 646 } 647 } 648 649 static class Activity { 650 private static final Pattern STATE_PATTERN = Pattern.compile("state=(\\S+).*"); 651 private static final Pattern VISIBILITY_PATTERN = Pattern.compile("keysPaused=(\\S+) " 652 + "inHistory=(\\S+) visible=(\\S+) sleeping=(\\S+) idle=(\\S+) " 653 + "mStartingWindowState=(\\S+)"); 654 private static final Pattern FRONT_OF_TASK_PATTERN = Pattern.compile("frontOfTask=(\\S+) " 655 + "task=TaskRecord\\{(\\S+) #(\\d+) A=(\\S+) U=(\\d+) StackId=(\\d+) sz=(\\d+)\\}"); 656 private static final Pattern PROCESS_RECORD_PATTERN = Pattern.compile( 657 "app=ProcessRecord\\{(\\S+) (\\d+):(\\S+)/(.+)\\}"); 658 659 String name; 660 String state; 661 boolean visible; 662 boolean frontOfTask; 663 int procId = -1; 664 Activity()665 private Activity() { 666 } 667 create( LinkedList<String> dump, Pattern activityNamePattern, Pattern[] exitPatterns)668 static Activity create( 669 LinkedList<String> dump, Pattern activityNamePattern, Pattern[] exitPatterns) { 670 final String line = dump.peek().trim(); 671 672 final Matcher matcher = activityNamePattern.matcher(line); 673 if (!matcher.matches()) { 674 // Not an activity. 675 return null; 676 } 677 // For the activity name line we just read. 678 dump.pop(); 679 680 final Activity activity = new Activity(); 681 log(line); 682 activity.name = matcher.group(4); 683 log(activity.name); 684 activity.extract(dump, exitPatterns); 685 return activity; 686 } 687 extract(LinkedList<String> dump, Pattern[] exitPatterns)688 private void extract(LinkedList<String> dump, Pattern[] exitPatterns) { 689 690 while (!doneExtracting(dump, exitPatterns)) { 691 final String line = dump.pop().trim(); 692 693 // Break the activity extraction once we hit an empty line 694 if (line.isEmpty()) { 695 break; 696 } 697 698 Matcher matcher = VISIBILITY_PATTERN.matcher(line); 699 if (matcher.matches()) { 700 log(line); 701 final String visibleString = matcher.group(3); 702 visible = Boolean.valueOf(visibleString); 703 log(visibleString); 704 continue; 705 } 706 707 matcher = STATE_PATTERN.matcher(line); 708 if (matcher.matches()) { 709 log(line); 710 state = matcher.group(1); 711 log(state); 712 continue; 713 } 714 715 matcher = PROCESS_RECORD_PATTERN.matcher(line); 716 if (matcher.matches()) { 717 log(line); 718 final String procIdString = matcher.group(2); 719 procId = Integer.valueOf(procIdString); 720 log(procIdString); 721 continue; 722 } 723 724 matcher = FRONT_OF_TASK_PATTERN.matcher(line); 725 if (matcher.matches()) { 726 log(line); 727 final String frontOfTaskString = matcher.group(1); 728 frontOfTask = Boolean.valueOf(frontOfTaskString); 729 log(frontOfTaskString); 730 continue; 731 } 732 } 733 } 734 } 735 736 static abstract class ActivityContainer { 737 protected static final Pattern FULLSCREEN_PATTERN = Pattern.compile("mFullscreen=(\\S+)"); 738 protected static final Pattern BOUNDS_PATTERN = 739 Pattern.compile("mBounds=Rect\\((\\d+), (\\d+) - (\\d+), (\\d+)\\)"); 740 protected static final Pattern MIN_WIDTH_PATTERN = 741 Pattern.compile("mMinWidth=(\\d+)"); 742 protected static final Pattern MIN_HEIGHT_PATTERN = 743 Pattern.compile("mMinHeight=(\\d+)"); 744 745 protected boolean mFullscreen; 746 protected Rectangle mBounds; 747 protected int mMinWidth = -1; 748 protected int mMinHeight = -1; 749 extractFullscreen(String line)750 boolean extractFullscreen(String line) { 751 final Matcher matcher = FULLSCREEN_PATTERN.matcher(line); 752 if (!matcher.matches()) { 753 return false; 754 } 755 log(line); 756 final String fullscreen = matcher.group(1); 757 log(fullscreen); 758 mFullscreen = Boolean.valueOf(fullscreen); 759 return true; 760 } 761 extractBounds(String line)762 boolean extractBounds(String line) { 763 final Matcher matcher = BOUNDS_PATTERN.matcher(line); 764 if (!matcher.matches()) { 765 return false; 766 } 767 log(line); 768 mBounds = extractBounds(matcher); 769 return true; 770 } 771 extractBounds(Matcher matcher)772 static Rectangle extractBounds(Matcher matcher) { 773 final int left = Integer.valueOf(matcher.group(1)); 774 final int top = Integer.valueOf(matcher.group(2)); 775 final int right = Integer.valueOf(matcher.group(3)); 776 final int bottom = Integer.valueOf(matcher.group(4)); 777 final Rectangle rect = new Rectangle(left, top, right - left, bottom - top); 778 779 log(rect.toString()); 780 return rect; 781 } 782 extractMinimalSize(String line)783 boolean extractMinimalSize(String line) { 784 final Matcher minWidthMatcher = MIN_WIDTH_PATTERN.matcher(line); 785 final Matcher minHeightMatcher = MIN_HEIGHT_PATTERN.matcher(line); 786 787 if (minWidthMatcher.matches()) { 788 log(line); 789 mMinWidth = Integer.valueOf(minWidthMatcher.group(1)); 790 } else if (minHeightMatcher.matches()) { 791 log(line); 792 mMinHeight = Integer.valueOf(minHeightMatcher.group(1)); 793 } else { 794 return false; 795 } 796 return true; 797 } 798 getBounds()799 Rectangle getBounds() { 800 return mBounds; 801 } 802 isFullscreen()803 boolean isFullscreen() { 804 return mFullscreen; 805 } 806 getMinWidth()807 int getMinWidth() { 808 return mMinWidth; 809 } 810 getMinHeight()811 int getMinHeight() { 812 return mMinHeight; 813 } 814 } 815 816 static class KeyguardControllerState { 817 private static final Pattern NAME_PATTERN = Pattern.compile("KeyguardController:"); 818 private static final Pattern SHOWING_PATTERN = Pattern.compile("mKeyguardShowing=(\\S+)"); 819 private static final Pattern OCCLUDED_PATTERN = Pattern.compile("mOccluded=(\\S+)"); 820 821 boolean keyguardShowing; 822 boolean keyguardOccluded; 823 KeyguardControllerState()824 private KeyguardControllerState() { 825 } 826 create(LinkedList<String> dump, Pattern[] exitPatterns)827 static KeyguardControllerState create(LinkedList<String> dump, Pattern[] exitPatterns) { 828 final String line = dump.peek().trim(); 829 830 final Matcher matcher = NAME_PATTERN.matcher(line); 831 if (!matcher.matches()) { 832 // Not KeyguardController 833 return null; 834 } 835 836 // For the KeyguardController line we just read. 837 dump.pop(); 838 839 final KeyguardControllerState controller = new KeyguardControllerState(); 840 controller.extract(dump, exitPatterns); 841 return controller; 842 } 843 extract(LinkedList<String> dump, Pattern[] exitPatterns)844 private void extract(LinkedList<String> dump, Pattern[] exitPatterns) { 845 846 while (!doneExtracting(dump, exitPatterns)) { 847 final String line = dump.pop().trim(); 848 849 Matcher matcher = SHOWING_PATTERN.matcher(line); 850 if (matcher.matches()) { 851 log(line); 852 final String showingString = matcher.group(1); 853 keyguardShowing = Boolean.valueOf(showingString); 854 log(showingString); 855 continue; 856 } 857 858 matcher = OCCLUDED_PATTERN.matcher(line); 859 if (matcher.matches()) { 860 log(line); 861 final String occludedString = matcher.group(1); 862 keyguardOccluded = Boolean.valueOf(occludedString); 863 log(occludedString); 864 continue; 865 } 866 } 867 } 868 } 869 doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns)870 static boolean doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns) { 871 if (dump.isEmpty()) { 872 return true; 873 } 874 final String line = dump.peek().trim(); 875 876 for (Pattern pattern : exitPatterns) { 877 if (pattern.matcher(line).matches()) { 878 return true; 879 } 880 } 881 return false; 882 } 883 } 884