1 /* 2 * Copyright (C) 2006 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.app; 18 19 import android.content.ActivityNotFoundException; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.content.pm.ActivityInfo; 25 import android.content.res.Configuration; 26 import android.hardware.input.InputManager; 27 import android.os.Bundle; 28 import android.os.Debug; 29 import android.os.IBinder; 30 import android.os.Looper; 31 import android.os.MessageQueue; 32 import android.os.PerformanceCollector; 33 import android.os.PersistableBundle; 34 import android.os.Process; 35 import android.os.RemoteException; 36 import android.os.ServiceManager; 37 import android.os.SystemClock; 38 import android.os.UserHandle; 39 import android.util.AndroidRuntimeException; 40 import android.util.Log; 41 import android.view.IWindowManager; 42 import android.view.InputDevice; 43 import android.view.KeyCharacterMap; 44 import android.view.KeyEvent; 45 import android.view.MotionEvent; 46 import android.view.ViewConfiguration; 47 import android.view.Window; 48 import com.android.internal.content.ReferrerIntent; 49 50 import java.io.File; 51 import java.util.ArrayList; 52 import java.util.List; 53 54 /** 55 * Base class for implementing application instrumentation code. When running 56 * with instrumentation turned on, this class will be instantiated for you 57 * before any of the application code, allowing you to monitor all of the 58 * interaction the system has with the application. An Instrumentation 59 * implementation is described to the system through an AndroidManifest.xml's 60 * <instrumentation> tag. 61 */ 62 public class Instrumentation { 63 64 /** 65 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 66 * identifies the class that is writing the report. This can be used to provide more structured 67 * logging or reporting capabilities in the IInstrumentationWatcher. 68 */ 69 public static final String REPORT_KEY_IDENTIFIER = "id"; 70 /** 71 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 72 * identifies a string which can simply be printed to the output stream. Using these streams 73 * provides a "pretty printer" version of the status & final packets. Any bundles including 74 * this key should also include the complete set of raw key/value pairs, so that the 75 * instrumentation can also be launched, and results collected, by an automated system. 76 */ 77 public static final String REPORT_KEY_STREAMRESULT = "stream"; 78 79 private static final String TAG = "Instrumentation"; 80 81 private final Object mSync = new Object(); 82 private ActivityThread mThread = null; 83 private MessageQueue mMessageQueue = null; 84 private Context mInstrContext; 85 private Context mAppContext; 86 private ComponentName mComponent; 87 private Thread mRunner; 88 private List<ActivityWaiter> mWaitingActivities; 89 private List<ActivityMonitor> mActivityMonitors; 90 private IInstrumentationWatcher mWatcher; 91 private IUiAutomationConnection mUiAutomationConnection; 92 private boolean mAutomaticPerformanceSnapshots = false; 93 private PerformanceCollector mPerformanceCollector; 94 private Bundle mPerfMetrics = new Bundle(); 95 private UiAutomation mUiAutomation; 96 Instrumentation()97 public Instrumentation() { 98 } 99 100 /** 101 * Called when the instrumentation is starting, before any application code 102 * has been loaded. Usually this will be implemented to simply call 103 * {@link #start} to begin the instrumentation thread, which will then 104 * continue execution in {@link #onStart}. 105 * 106 * <p>If you do not need your own thread -- that is you are writing your 107 * instrumentation to be completely asynchronous (returning to the event 108 * loop so that the application can run), you can simply begin your 109 * instrumentation here, for example call {@link Context#startActivity} to 110 * begin the appropriate first activity of the application. 111 * 112 * @param arguments Any additional arguments that were supplied when the 113 * instrumentation was started. 114 */ onCreate(Bundle arguments)115 public void onCreate(Bundle arguments) { 116 } 117 118 /** 119 * Create and start a new thread in which to run instrumentation. This new 120 * thread will call to {@link #onStart} where you can implement the 121 * instrumentation. 122 */ start()123 public void start() { 124 if (mRunner != null) { 125 throw new RuntimeException("Instrumentation already started"); 126 } 127 mRunner = new InstrumentationThread("Instr: " + getClass().getName()); 128 mRunner.start(); 129 } 130 131 /** 132 * Method where the instrumentation thread enters execution. This allows 133 * you to run your instrumentation code in a separate thread than the 134 * application, so that it can perform blocking operation such as 135 * {@link #sendKeySync} or {@link #startActivitySync}. 136 * 137 * <p>You will typically want to call finish() when this function is done, 138 * to end your instrumentation. 139 */ onStart()140 public void onStart() { 141 } 142 143 /** 144 * This is called whenever the system captures an unhandled exception that 145 * was thrown by the application. The default implementation simply 146 * returns false, allowing normal system handling of the exception to take 147 * place. 148 * 149 * @param obj The client object that generated the exception. May be an 150 * Application, Activity, BroadcastReceiver, Service, or null. 151 * @param e The exception that was thrown. 152 * 153 * @return To allow normal system exception process to occur, return false. 154 * If true is returned, the system will proceed as if the exception 155 * didn't happen. 156 */ onException(Object obj, Throwable e)157 public boolean onException(Object obj, Throwable e) { 158 return false; 159 } 160 161 /** 162 * Provide a status report about the application. 163 * 164 * @param resultCode Current success/failure of instrumentation. 165 * @param results Any results to send back to the code that started the instrumentation. 166 */ sendStatus(int resultCode, Bundle results)167 public void sendStatus(int resultCode, Bundle results) { 168 if (mWatcher != null) { 169 try { 170 mWatcher.instrumentationStatus(mComponent, resultCode, results); 171 } 172 catch (RemoteException e) { 173 mWatcher = null; 174 } 175 } 176 } 177 178 /** 179 * Terminate instrumentation of the application. This will cause the 180 * application process to exit, removing this instrumentation from the next 181 * time the application is started. 182 * 183 * @param resultCode Overall success/failure of instrumentation. 184 * @param results Any results to send back to the code that started the 185 * instrumentation. 186 */ finish(int resultCode, Bundle results)187 public void finish(int resultCode, Bundle results) { 188 if (mAutomaticPerformanceSnapshots) { 189 endPerformanceSnapshot(); 190 } 191 if (mPerfMetrics != null) { 192 if (results == null) { 193 results = new Bundle(); 194 } 195 results.putAll(mPerfMetrics); 196 } 197 if (mUiAutomation != null) { 198 mUiAutomation.disconnect(); 199 mUiAutomation = null; 200 } 201 mThread.finishInstrumentation(resultCode, results); 202 } 203 setAutomaticPerformanceSnapshots()204 public void setAutomaticPerformanceSnapshots() { 205 mAutomaticPerformanceSnapshots = true; 206 mPerformanceCollector = new PerformanceCollector(); 207 } 208 startPerformanceSnapshot()209 public void startPerformanceSnapshot() { 210 if (!isProfiling()) { 211 mPerformanceCollector.beginSnapshot(null); 212 } 213 } 214 endPerformanceSnapshot()215 public void endPerformanceSnapshot() { 216 if (!isProfiling()) { 217 mPerfMetrics = mPerformanceCollector.endSnapshot(); 218 } 219 } 220 221 /** 222 * Called when the instrumented application is stopping, after all of the 223 * normal application cleanup has occurred. 224 */ onDestroy()225 public void onDestroy() { 226 } 227 228 /** 229 * Return the Context of this instrumentation's package. Note that this is 230 * often different than the Context of the application being 231 * instrumentated, since the instrumentation code often lives is a 232 * different package than that of the application it is running against. 233 * See {@link #getTargetContext} to retrieve a Context for the target 234 * application. 235 * 236 * @return The instrumentation's package context. 237 * 238 * @see #getTargetContext 239 */ getContext()240 public Context getContext() { 241 return mInstrContext; 242 } 243 244 /** 245 * Returns complete component name of this instrumentation. 246 * 247 * @return Returns the complete component name for this instrumentation. 248 */ getComponentName()249 public ComponentName getComponentName() { 250 return mComponent; 251 } 252 253 /** 254 * Return a Context for the target application being instrumented. Note 255 * that this is often different than the Context of the instrumentation 256 * code, since the instrumentation code often lives is a different package 257 * than that of the application it is running against. See 258 * {@link #getContext} to retrieve a Context for the instrumentation code. 259 * 260 * @return A Context in the target application. 261 * 262 * @see #getContext 263 */ getTargetContext()264 public Context getTargetContext() { 265 return mAppContext; 266 } 267 268 /** 269 * Check whether this instrumentation was started with profiling enabled. 270 * 271 * @return Returns true if profiling was enabled when starting, else false. 272 */ isProfiling()273 public boolean isProfiling() { 274 return mThread.isProfiling(); 275 } 276 277 /** 278 * This method will start profiling if isProfiling() returns true. You should 279 * only call this method if you set the handleProfiling attribute in the 280 * manifest file for this Instrumentation to true. 281 */ startProfiling()282 public void startProfiling() { 283 if (mThread.isProfiling()) { 284 File file = new File(mThread.getProfileFilePath()); 285 file.getParentFile().mkdirs(); 286 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024); 287 } 288 } 289 290 /** 291 * Stops profiling if isProfiling() returns true. 292 */ stopProfiling()293 public void stopProfiling() { 294 if (mThread.isProfiling()) { 295 Debug.stopMethodTracing(); 296 } 297 } 298 299 /** 300 * Force the global system in or out of touch mode. This can be used if 301 * your instrumentation relies on the UI being in one more or the other 302 * when it starts. 303 * 304 * @param inTouch Set to true to be in touch mode, false to be in 305 * focus mode. 306 */ setInTouchMode(boolean inTouch)307 public void setInTouchMode(boolean inTouch) { 308 try { 309 IWindowManager.Stub.asInterface( 310 ServiceManager.getService("window")).setInTouchMode(inTouch); 311 } catch (RemoteException e) { 312 // Shouldn't happen! 313 } 314 } 315 316 /** 317 * Schedule a callback for when the application's main thread goes idle 318 * (has no more events to process). 319 * 320 * @param recipient Called the next time the thread's message queue is 321 * idle. 322 */ waitForIdle(Runnable recipient)323 public void waitForIdle(Runnable recipient) { 324 mMessageQueue.addIdleHandler(new Idler(recipient)); 325 mThread.getHandler().post(new EmptyRunnable()); 326 } 327 328 /** 329 * Synchronously wait for the application to be idle. Can not be called 330 * from the main application thread -- use {@link #start} to execute 331 * instrumentation in its own thread. 332 */ waitForIdleSync()333 public void waitForIdleSync() { 334 validateNotAppThread(); 335 Idler idler = new Idler(null); 336 mMessageQueue.addIdleHandler(idler); 337 mThread.getHandler().post(new EmptyRunnable()); 338 idler.waitForIdle(); 339 } 340 341 /** 342 * Execute a call on the application's main thread, blocking until it is 343 * complete. Useful for doing things that are not thread-safe, such as 344 * looking at or modifying the view hierarchy. 345 * 346 * @param runner The code to run on the main thread. 347 */ runOnMainSync(Runnable runner)348 public void runOnMainSync(Runnable runner) { 349 validateNotAppThread(); 350 SyncRunnable sr = new SyncRunnable(runner); 351 mThread.getHandler().post(sr); 352 sr.waitForComplete(); 353 } 354 355 /** 356 * Start a new activity and wait for it to begin running before returning. 357 * In addition to being synchronous, this method as some semantic 358 * differences from the standard {@link Context#startActivity} call: the 359 * activity component is resolved before talking with the activity manager 360 * (its class name is specified in the Intent that this method ultimately 361 * starts), and it does not allow you to start activities that run in a 362 * different process. In addition, if the given Intent resolves to 363 * multiple activities, instead of displaying a dialog for the user to 364 * select an activity, an exception will be thrown. 365 * 366 * <p>The function returns as soon as the activity goes idle following the 367 * call to its {@link Activity#onCreate}. Generally this means it has gone 368 * through the full initialization including {@link Activity#onResume} and 369 * drawn and displayed its initial window. 370 * 371 * @param intent Description of the activity to start. 372 * 373 * @see Context#startActivity 374 */ startActivitySync(Intent intent)375 public Activity startActivitySync(Intent intent) { 376 validateNotAppThread(); 377 378 synchronized (mSync) { 379 intent = new Intent(intent); 380 381 ActivityInfo ai = intent.resolveActivityInfo( 382 getTargetContext().getPackageManager(), 0); 383 if (ai == null) { 384 throw new RuntimeException("Unable to resolve activity for: " + intent); 385 } 386 String myProc = mThread.getProcessName(); 387 if (!ai.processName.equals(myProc)) { 388 // todo: if this intent is ambiguous, look here to see if 389 // there is a single match that is in our package. 390 throw new RuntimeException("Intent in process " 391 + myProc + " resolved to different process " 392 + ai.processName + ": " + intent); 393 } 394 395 intent.setComponent(new ComponentName( 396 ai.applicationInfo.packageName, ai.name)); 397 final ActivityWaiter aw = new ActivityWaiter(intent); 398 399 if (mWaitingActivities == null) { 400 mWaitingActivities = new ArrayList(); 401 } 402 mWaitingActivities.add(aw); 403 404 getTargetContext().startActivity(intent); 405 406 do { 407 try { 408 mSync.wait(); 409 } catch (InterruptedException e) { 410 } 411 } while (mWaitingActivities.contains(aw)); 412 413 return aw.activity; 414 } 415 } 416 417 /** 418 * Information about a particular kind of Intent that is being monitored. 419 * An instance of this class is added to the 420 * current instrumentation through {@link #addMonitor}; after being added, 421 * when a new activity is being started the monitor will be checked and, if 422 * matching, its hit count updated and (optionally) the call stopped and a 423 * canned result returned. 424 * 425 * <p>An ActivityMonitor can also be used to look for the creation of an 426 * activity, through the {@link #waitForActivity} method. This will return 427 * after a matching activity has been created with that activity object. 428 */ 429 public static class ActivityMonitor { 430 private final IntentFilter mWhich; 431 private final String mClass; 432 private final ActivityResult mResult; 433 private final boolean mBlock; 434 435 436 // This is protected by 'Instrumentation.this.mSync'. 437 /*package*/ int mHits = 0; 438 439 // This is protected by 'this'. 440 /*package*/ Activity mLastActivity = null; 441 442 /** 443 * Create a new ActivityMonitor that looks for a particular kind of 444 * intent to be started. 445 * 446 * @param which The set of intents this monitor is responsible for. 447 * @param result A canned result to return if the monitor is hit; can 448 * be null. 449 * @param block Controls whether the monitor should block the activity 450 * start (returning its canned result) or let the call 451 * proceed. 452 * 453 * @see Instrumentation#addMonitor 454 */ ActivityMonitor( IntentFilter which, ActivityResult result, boolean block)455 public ActivityMonitor( 456 IntentFilter which, ActivityResult result, boolean block) { 457 mWhich = which; 458 mClass = null; 459 mResult = result; 460 mBlock = block; 461 } 462 463 /** 464 * Create a new ActivityMonitor that looks for a specific activity 465 * class to be started. 466 * 467 * @param cls The activity class this monitor is responsible for. 468 * @param result A canned result to return if the monitor is hit; can 469 * be null. 470 * @param block Controls whether the monitor should block the activity 471 * start (returning its canned result) or let the call 472 * proceed. 473 * 474 * @see Instrumentation#addMonitor 475 */ ActivityMonitor( String cls, ActivityResult result, boolean block)476 public ActivityMonitor( 477 String cls, ActivityResult result, boolean block) { 478 mWhich = null; 479 mClass = cls; 480 mResult = result; 481 mBlock = block; 482 } 483 484 /** 485 * Retrieve the filter associated with this ActivityMonitor. 486 */ getFilter()487 public final IntentFilter getFilter() { 488 return mWhich; 489 } 490 491 /** 492 * Retrieve the result associated with this ActivityMonitor, or null if 493 * none. 494 */ getResult()495 public final ActivityResult getResult() { 496 return mResult; 497 } 498 499 /** 500 * Check whether this monitor blocks activity starts (not allowing the 501 * actual activity to run) or allows them to execute normally. 502 */ isBlocking()503 public final boolean isBlocking() { 504 return mBlock; 505 } 506 507 /** 508 * Retrieve the number of times the monitor has been hit so far. 509 */ getHits()510 public final int getHits() { 511 return mHits; 512 } 513 514 /** 515 * Retrieve the most recent activity class that was seen by this 516 * monitor. 517 */ getLastActivity()518 public final Activity getLastActivity() { 519 return mLastActivity; 520 } 521 522 /** 523 * Block until an Activity is created that matches this monitor, 524 * returning the resulting activity. 525 * 526 * @return Activity 527 */ waitForActivity()528 public final Activity waitForActivity() { 529 synchronized (this) { 530 while (mLastActivity == null) { 531 try { 532 wait(); 533 } catch (InterruptedException e) { 534 } 535 } 536 Activity res = mLastActivity; 537 mLastActivity = null; 538 return res; 539 } 540 } 541 542 /** 543 * Block until an Activity is created that matches this monitor, 544 * returning the resulting activity or till the timeOut period expires. 545 * If the timeOut expires before the activity is started, return null. 546 * 547 * @param timeOut Time to wait before the activity is created. 548 * 549 * @return Activity 550 */ waitForActivityWithTimeout(long timeOut)551 public final Activity waitForActivityWithTimeout(long timeOut) { 552 synchronized (this) { 553 if (mLastActivity == null) { 554 try { 555 wait(timeOut); 556 } catch (InterruptedException e) { 557 } 558 } 559 if (mLastActivity == null) { 560 return null; 561 } else { 562 Activity res = mLastActivity; 563 mLastActivity = null; 564 return res; 565 } 566 } 567 } 568 match(Context who, Activity activity, Intent intent)569 final boolean match(Context who, 570 Activity activity, 571 Intent intent) { 572 synchronized (this) { 573 if (mWhich != null 574 && mWhich.match(who.getContentResolver(), intent, 575 true, "Instrumentation") < 0) { 576 return false; 577 } 578 if (mClass != null) { 579 String cls = null; 580 if (activity != null) { 581 cls = activity.getClass().getName(); 582 } else if (intent.getComponent() != null) { 583 cls = intent.getComponent().getClassName(); 584 } 585 if (cls == null || !mClass.equals(cls)) { 586 return false; 587 } 588 } 589 if (activity != null) { 590 mLastActivity = activity; 591 notifyAll(); 592 } 593 return true; 594 } 595 } 596 } 597 598 /** 599 * Add a new {@link ActivityMonitor} that will be checked whenever an 600 * activity is started. The monitor is added 601 * after any existing ones; the monitor will be hit only if none of the 602 * existing monitors can themselves handle the Intent. 603 * 604 * @param monitor The new ActivityMonitor to see. 605 * 606 * @see #addMonitor(IntentFilter, ActivityResult, boolean) 607 * @see #checkMonitorHit 608 */ addMonitor(ActivityMonitor monitor)609 public void addMonitor(ActivityMonitor monitor) { 610 synchronized (mSync) { 611 if (mActivityMonitors == null) { 612 mActivityMonitors = new ArrayList(); 613 } 614 mActivityMonitors.add(monitor); 615 } 616 } 617 618 /** 619 * A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that 620 * creates an intent filter matching {@link ActivityMonitor} for you and 621 * returns it. 622 * 623 * @param filter The set of intents this monitor is responsible for. 624 * @param result A canned result to return if the monitor is hit; can 625 * be null. 626 * @param block Controls whether the monitor should block the activity 627 * start (returning its canned result) or let the call 628 * proceed. 629 * 630 * @return The newly created and added activity monitor. 631 * 632 * @see #addMonitor(ActivityMonitor) 633 * @see #checkMonitorHit 634 */ addMonitor( IntentFilter filter, ActivityResult result, boolean block)635 public ActivityMonitor addMonitor( 636 IntentFilter filter, ActivityResult result, boolean block) { 637 ActivityMonitor am = new ActivityMonitor(filter, result, block); 638 addMonitor(am); 639 return am; 640 } 641 642 /** 643 * A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that 644 * creates a class matching {@link ActivityMonitor} for you and returns it. 645 * 646 * @param cls The activity class this monitor is responsible for. 647 * @param result A canned result to return if the monitor is hit; can 648 * be null. 649 * @param block Controls whether the monitor should block the activity 650 * start (returning its canned result) or let the call 651 * proceed. 652 * 653 * @return The newly created and added activity monitor. 654 * 655 * @see #addMonitor(ActivityMonitor) 656 * @see #checkMonitorHit 657 */ addMonitor( String cls, ActivityResult result, boolean block)658 public ActivityMonitor addMonitor( 659 String cls, ActivityResult result, boolean block) { 660 ActivityMonitor am = new ActivityMonitor(cls, result, block); 661 addMonitor(am); 662 return am; 663 } 664 665 /** 666 * Test whether an existing {@link ActivityMonitor} has been hit. If the 667 * monitor has been hit at least <var>minHits</var> times, then it will be 668 * removed from the activity monitor list and true returned. Otherwise it 669 * is left as-is and false is returned. 670 * 671 * @param monitor The ActivityMonitor to check. 672 * @param minHits The minimum number of hits required. 673 * 674 * @return True if the hit count has been reached, else false. 675 * 676 * @see #addMonitor 677 */ checkMonitorHit(ActivityMonitor monitor, int minHits)678 public boolean checkMonitorHit(ActivityMonitor monitor, int minHits) { 679 waitForIdleSync(); 680 synchronized (mSync) { 681 if (monitor.getHits() < minHits) { 682 return false; 683 } 684 mActivityMonitors.remove(monitor); 685 } 686 return true; 687 } 688 689 /** 690 * Wait for an existing {@link ActivityMonitor} to be hit. Once the 691 * monitor has been hit, it is removed from the activity monitor list and 692 * the first created Activity object that matched it is returned. 693 * 694 * @param monitor The ActivityMonitor to wait for. 695 * 696 * @return The Activity object that matched the monitor. 697 */ waitForMonitor(ActivityMonitor monitor)698 public Activity waitForMonitor(ActivityMonitor monitor) { 699 Activity activity = monitor.waitForActivity(); 700 synchronized (mSync) { 701 mActivityMonitors.remove(monitor); 702 } 703 return activity; 704 } 705 706 /** 707 * Wait for an existing {@link ActivityMonitor} to be hit till the timeout 708 * expires. Once the monitor has been hit, it is removed from the activity 709 * monitor list and the first created Activity object that matched it is 710 * returned. If the timeout expires, a null object is returned. 711 * 712 * @param monitor The ActivityMonitor to wait for. 713 * @param timeOut The timeout value in secs. 714 * 715 * @return The Activity object that matched the monitor. 716 */ waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut)717 public Activity waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut) { 718 Activity activity = monitor.waitForActivityWithTimeout(timeOut); 719 synchronized (mSync) { 720 mActivityMonitors.remove(monitor); 721 } 722 return activity; 723 } 724 725 /** 726 * Remove an {@link ActivityMonitor} that was previously added with 727 * {@link #addMonitor}. 728 * 729 * @param monitor The monitor to remove. 730 * 731 * @see #addMonitor 732 */ removeMonitor(ActivityMonitor monitor)733 public void removeMonitor(ActivityMonitor monitor) { 734 synchronized (mSync) { 735 mActivityMonitors.remove(monitor); 736 } 737 } 738 739 /** 740 * Execute a particular menu item. 741 * 742 * @param targetActivity The activity in question. 743 * @param id The identifier associated with the menu item. 744 * @param flag Additional flags, if any. 745 * @return Whether the invocation was successful (for example, it could be 746 * false if item is disabled). 747 */ invokeMenuActionSync(Activity targetActivity, int id, int flag)748 public boolean invokeMenuActionSync(Activity targetActivity, 749 int id, int flag) { 750 class MenuRunnable implements Runnable { 751 private final Activity activity; 752 private final int identifier; 753 private final int flags; 754 boolean returnValue; 755 756 public MenuRunnable(Activity _activity, int _identifier, 757 int _flags) { 758 activity = _activity; 759 identifier = _identifier; 760 flags = _flags; 761 } 762 763 public void run() { 764 Window win = activity.getWindow(); 765 766 returnValue = win.performPanelIdentifierAction( 767 Window.FEATURE_OPTIONS_PANEL, 768 identifier, 769 flags); 770 } 771 772 } 773 MenuRunnable mr = new MenuRunnable(targetActivity, id, flag); 774 runOnMainSync(mr); 775 return mr.returnValue; 776 } 777 778 /** 779 * Show the context menu for the currently focused view and executes a 780 * particular context menu item. 781 * 782 * @param targetActivity The activity in question. 783 * @param id The identifier associated with the context menu item. 784 * @param flag Additional flags, if any. 785 * @return Whether the invocation was successful (for example, it could be 786 * false if item is disabled). 787 */ invokeContextMenuAction(Activity targetActivity, int id, int flag)788 public boolean invokeContextMenuAction(Activity targetActivity, int id, int flag) { 789 validateNotAppThread(); 790 791 // Bring up context menu for current focus. 792 // It'd be nice to do this through code, but currently ListView depends on 793 // long press to set metadata for its selected child 794 795 final KeyEvent downEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER); 796 sendKeySync(downEvent); 797 798 // Need to wait for long press 799 waitForIdleSync(); 800 try { 801 Thread.sleep(ViewConfiguration.getLongPressTimeout()); 802 } catch (InterruptedException e) { 803 Log.e(TAG, "Could not sleep for long press timeout", e); 804 return false; 805 } 806 807 final KeyEvent upEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER); 808 sendKeySync(upEvent); 809 810 // Wait for context menu to appear 811 waitForIdleSync(); 812 813 class ContextMenuRunnable implements Runnable { 814 private final Activity activity; 815 private final int identifier; 816 private final int flags; 817 boolean returnValue; 818 819 public ContextMenuRunnable(Activity _activity, int _identifier, 820 int _flags) { 821 activity = _activity; 822 identifier = _identifier; 823 flags = _flags; 824 } 825 826 public void run() { 827 Window win = activity.getWindow(); 828 returnValue = win.performContextMenuIdentifierAction( 829 identifier, 830 flags); 831 } 832 833 } 834 835 ContextMenuRunnable cmr = new ContextMenuRunnable(targetActivity, id, flag); 836 runOnMainSync(cmr); 837 return cmr.returnValue; 838 } 839 840 /** 841 * Sends the key events corresponding to the text to the app being 842 * instrumented. 843 * 844 * @param text The text to be sent. 845 */ sendStringSync(String text)846 public void sendStringSync(String text) { 847 if (text == null) { 848 return; 849 } 850 KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); 851 852 KeyEvent[] events = keyCharacterMap.getEvents(text.toCharArray()); 853 854 if (events != null) { 855 for (int i = 0; i < events.length; i++) { 856 // We have to change the time of an event before injecting it because 857 // all KeyEvents returned by KeyCharacterMap.getEvents() have the same 858 // time stamp and the system rejects too old events. Hence, it is 859 // possible for an event to become stale before it is injected if it 860 // takes too long to inject the preceding ones. 861 sendKeySync(KeyEvent.changeTimeRepeat(events[i], SystemClock.uptimeMillis(), 0)); 862 } 863 } 864 } 865 866 /** 867 * Send a key event to the currently focused window/view and wait for it to 868 * be processed. Finished at some point after the recipient has returned 869 * from its event processing, though it may <em>not</em> have completely 870 * finished reacting from the event -- for example, if it needs to update 871 * its display as a result, it may still be in the process of doing that. 872 * 873 * @param event The event to send to the current focus. 874 */ sendKeySync(KeyEvent event)875 public void sendKeySync(KeyEvent event) { 876 validateNotAppThread(); 877 878 long downTime = event.getDownTime(); 879 long eventTime = event.getEventTime(); 880 int action = event.getAction(); 881 int code = event.getKeyCode(); 882 int repeatCount = event.getRepeatCount(); 883 int metaState = event.getMetaState(); 884 int deviceId = event.getDeviceId(); 885 int scancode = event.getScanCode(); 886 int source = event.getSource(); 887 int flags = event.getFlags(); 888 if (source == InputDevice.SOURCE_UNKNOWN) { 889 source = InputDevice.SOURCE_KEYBOARD; 890 } 891 if (eventTime == 0) { 892 eventTime = SystemClock.uptimeMillis(); 893 } 894 if (downTime == 0) { 895 downTime = eventTime; 896 } 897 KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState, 898 deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source); 899 InputManager.getInstance().injectInputEvent(newEvent, 900 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); 901 } 902 903 /** 904 * Sends an up and down key event sync to the currently focused window. 905 * 906 * @param key The integer keycode for the event. 907 */ sendKeyDownUpSync(int key)908 public void sendKeyDownUpSync(int key) { 909 sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, key)); 910 sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, key)); 911 } 912 913 /** 914 * Higher-level method for sending both the down and up key events for a 915 * particular character key code. Equivalent to creating both KeyEvent 916 * objects by hand and calling {@link #sendKeySync}. The event appears 917 * as if it came from keyboard 0, the built in one. 918 * 919 * @param keyCode The key code of the character to send. 920 */ sendCharacterSync(int keyCode)921 public void sendCharacterSync(int keyCode) { 922 sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode)); 923 sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, keyCode)); 924 } 925 926 /** 927 * Dispatch a pointer event. Finished at some point after the recipient has 928 * returned from its event processing, though it may <em>not</em> have 929 * completely finished reacting from the event -- for example, if it needs 930 * to update its display as a result, it may still be in the process of 931 * doing that. 932 * 933 * @param event A motion event describing the pointer action. (As noted in 934 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use 935 * {@link SystemClock#uptimeMillis()} as the timebase. 936 */ sendPointerSync(MotionEvent event)937 public void sendPointerSync(MotionEvent event) { 938 validateNotAppThread(); 939 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) { 940 event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 941 } 942 InputManager.getInstance().injectInputEvent(event, 943 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); 944 } 945 946 /** 947 * Dispatch a trackball event. Finished at some point after the recipient has 948 * returned from its event processing, though it may <em>not</em> have 949 * completely finished reacting from the event -- for example, if it needs 950 * to update its display as a result, it may still be in the process of 951 * doing that. 952 * 953 * @param event A motion event describing the trackball action. (As noted in 954 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use 955 * {@link SystemClock#uptimeMillis()} as the timebase. 956 */ sendTrackballEventSync(MotionEvent event)957 public void sendTrackballEventSync(MotionEvent event) { 958 validateNotAppThread(); 959 if ((event.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) { 960 event.setSource(InputDevice.SOURCE_TRACKBALL); 961 } 962 InputManager.getInstance().injectInputEvent(event, 963 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); 964 } 965 966 /** 967 * Perform instantiation of the process's {@link Application} object. The 968 * default implementation provides the normal system behavior. 969 * 970 * @param cl The ClassLoader with which to instantiate the object. 971 * @param className The name of the class implementing the Application 972 * object. 973 * @param context The context to initialize the application with 974 * 975 * @return The newly instantiated Application object. 976 */ newApplication(ClassLoader cl, String className, Context context)977 public Application newApplication(ClassLoader cl, String className, Context context) 978 throws InstantiationException, IllegalAccessException, 979 ClassNotFoundException { 980 return newApplication(cl.loadClass(className), context); 981 } 982 983 /** 984 * Perform instantiation of the process's {@link Application} object. The 985 * default implementation provides the normal system behavior. 986 * 987 * @param clazz The class used to create an Application object from. 988 * @param context The context to initialize the application with 989 * 990 * @return The newly instantiated Application object. 991 */ newApplication(Class<?> clazz, Context context)992 static public Application newApplication(Class<?> clazz, Context context) 993 throws InstantiationException, IllegalAccessException, 994 ClassNotFoundException { 995 Application app = (Application)clazz.newInstance(); 996 app.attach(context); 997 return app; 998 } 999 1000 /** 1001 * Perform calling of the application's {@link Application#onCreate} 1002 * method. The default implementation simply calls through to that method. 1003 * 1004 * <p>Note: This method will be called immediately after {@link #onCreate(Bundle)}. 1005 * Often instrumentation tests start their test thread in onCreate(); you 1006 * need to be careful of races between these. (Well between it and 1007 * everything else, but let's start here.) 1008 * 1009 * @param app The application being created. 1010 */ callApplicationOnCreate(Application app)1011 public void callApplicationOnCreate(Application app) { 1012 app.onCreate(); 1013 } 1014 1015 /** 1016 * Perform instantiation of an {@link Activity} object. This method is intended for use with 1017 * unit tests, such as android.test.ActivityUnitTestCase. The activity will be useable 1018 * locally but will be missing some of the linkages necessary for use within the sytem. 1019 * 1020 * @param clazz The Class of the desired Activity 1021 * @param context The base context for the activity to use 1022 * @param token The token for this activity to communicate with 1023 * @param application The application object (if any) 1024 * @param intent The intent that started this Activity 1025 * @param info ActivityInfo from the manifest 1026 * @param title The title, typically retrieved from the ActivityInfo record 1027 * @param parent The parent Activity (if any) 1028 * @param id The embedded Id (if any) 1029 * @param lastNonConfigurationInstance Arbitrary object that will be 1030 * available via {@link Activity#getLastNonConfigurationInstance() 1031 * Activity.getLastNonConfigurationInstance()}. 1032 * @return Returns the instantiated activity 1033 * @throws InstantiationException 1034 * @throws IllegalAccessException 1035 */ newActivity(Class<?> clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance)1036 public Activity newActivity(Class<?> clazz, Context context, 1037 IBinder token, Application application, Intent intent, ActivityInfo info, 1038 CharSequence title, Activity parent, String id, 1039 Object lastNonConfigurationInstance) throws InstantiationException, 1040 IllegalAccessException { 1041 Activity activity = (Activity)clazz.newInstance(); 1042 ActivityThread aThread = null; 1043 activity.attach(context, aThread, this, token, 0, application, intent, 1044 info, title, parent, id, 1045 (Activity.NonConfigurationInstances)lastNonConfigurationInstance, 1046 new Configuration(), null, null); 1047 return activity; 1048 } 1049 1050 /** 1051 * Perform instantiation of the process's {@link Activity} object. The 1052 * default implementation provides the normal system behavior. 1053 * 1054 * @param cl The ClassLoader with which to instantiate the object. 1055 * @param className The name of the class implementing the Activity 1056 * object. 1057 * @param intent The Intent object that specified the activity class being 1058 * instantiated. 1059 * 1060 * @return The newly instantiated Activity object. 1061 */ newActivity(ClassLoader cl, String className, Intent intent)1062 public Activity newActivity(ClassLoader cl, String className, 1063 Intent intent) 1064 throws InstantiationException, IllegalAccessException, 1065 ClassNotFoundException { 1066 return (Activity)cl.loadClass(className).newInstance(); 1067 } 1068 prePerformCreate(Activity activity)1069 private void prePerformCreate(Activity activity) { 1070 if (mWaitingActivities != null) { 1071 synchronized (mSync) { 1072 final int N = mWaitingActivities.size(); 1073 for (int i=0; i<N; i++) { 1074 final ActivityWaiter aw = mWaitingActivities.get(i); 1075 final Intent intent = aw.intent; 1076 if (intent.filterEquals(activity.getIntent())) { 1077 aw.activity = activity; 1078 mMessageQueue.addIdleHandler(new ActivityGoing(aw)); 1079 } 1080 } 1081 } 1082 } 1083 } 1084 postPerformCreate(Activity activity)1085 private void postPerformCreate(Activity activity) { 1086 if (mActivityMonitors != null) { 1087 synchronized (mSync) { 1088 final int N = mActivityMonitors.size(); 1089 for (int i=0; i<N; i++) { 1090 final ActivityMonitor am = mActivityMonitors.get(i); 1091 am.match(activity, activity, activity.getIntent()); 1092 } 1093 } 1094 } 1095 } 1096 1097 /** 1098 * Perform calling of an activity's {@link Activity#onCreate} 1099 * method. The default implementation simply calls through to that method. 1100 * 1101 * @param activity The activity being created. 1102 * @param icicle The previously frozen state (or null) to pass through to onCreate(). 1103 */ callActivityOnCreate(Activity activity, Bundle icicle)1104 public void callActivityOnCreate(Activity activity, Bundle icicle) { 1105 prePerformCreate(activity); 1106 activity.performCreate(icicle); 1107 postPerformCreate(activity); 1108 } 1109 1110 /** 1111 * Perform calling of an activity's {@link Activity#onCreate} 1112 * method. The default implementation simply calls through to that method. 1113 * @param activity The activity being created. 1114 * @param icicle The previously frozen state (or null) to pass through to 1115 * @param persistentState The previously persisted state (or null) 1116 */ callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState)1117 public void callActivityOnCreate(Activity activity, Bundle icicle, 1118 PersistableBundle persistentState) { 1119 prePerformCreate(activity); 1120 activity.performCreate(icicle, persistentState); 1121 postPerformCreate(activity); 1122 } 1123 callActivityOnDestroy(Activity activity)1124 public void callActivityOnDestroy(Activity activity) { 1125 // TODO: the following block causes intermittent hangs when using startActivity 1126 // temporarily comment out until root cause is fixed (bug 2630683) 1127 // if (mWaitingActivities != null) { 1128 // synchronized (mSync) { 1129 // final int N = mWaitingActivities.size(); 1130 // for (int i=0; i<N; i++) { 1131 // final ActivityWaiter aw = mWaitingActivities.get(i); 1132 // final Intent intent = aw.intent; 1133 // if (intent.filterEquals(activity.getIntent())) { 1134 // aw.activity = activity; 1135 // mMessageQueue.addIdleHandler(new ActivityGoing(aw)); 1136 // } 1137 // } 1138 // } 1139 // } 1140 1141 activity.performDestroy(); 1142 1143 if (mActivityMonitors != null) { 1144 synchronized (mSync) { 1145 final int N = mActivityMonitors.size(); 1146 for (int i=0; i<N; i++) { 1147 final ActivityMonitor am = mActivityMonitors.get(i); 1148 am.match(activity, activity, activity.getIntent()); 1149 } 1150 } 1151 } 1152 } 1153 1154 /** 1155 * Perform calling of an activity's {@link Activity#onRestoreInstanceState} 1156 * method. The default implementation simply calls through to that method. 1157 * 1158 * @param activity The activity being restored. 1159 * @param savedInstanceState The previously saved state being restored. 1160 */ callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState)1161 public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) { 1162 activity.performRestoreInstanceState(savedInstanceState); 1163 } 1164 1165 /** 1166 * Perform calling of an activity's {@link Activity#onRestoreInstanceState} 1167 * method. The default implementation simply calls through to that method. 1168 * 1169 * @param activity The activity being restored. 1170 * @param savedInstanceState The previously saved state being restored. 1171 * @param persistentState The previously persisted state (or null) 1172 */ callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState, PersistableBundle persistentState)1173 public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState, 1174 PersistableBundle persistentState) { 1175 activity.performRestoreInstanceState(savedInstanceState, persistentState); 1176 } 1177 1178 /** 1179 * Perform calling of an activity's {@link Activity#onPostCreate} method. 1180 * The default implementation simply calls through to that method. 1181 * 1182 * @param activity The activity being created. 1183 * @param icicle The previously frozen state (or null) to pass through to 1184 * onPostCreate(). 1185 */ callActivityOnPostCreate(Activity activity, Bundle icicle)1186 public void callActivityOnPostCreate(Activity activity, Bundle icicle) { 1187 activity.onPostCreate(icicle); 1188 } 1189 1190 /** 1191 * Perform calling of an activity's {@link Activity#onPostCreate} method. 1192 * The default implementation simply calls through to that method. 1193 * 1194 * @param activity The activity being created. 1195 * @param icicle The previously frozen state (or null) to pass through to 1196 * onPostCreate(). 1197 */ callActivityOnPostCreate(Activity activity, Bundle icicle, PersistableBundle persistentState)1198 public void callActivityOnPostCreate(Activity activity, Bundle icicle, 1199 PersistableBundle persistentState) { 1200 activity.onPostCreate(icicle, persistentState); 1201 } 1202 1203 /** 1204 * Perform calling of an activity's {@link Activity#onNewIntent} 1205 * method. The default implementation simply calls through to that method. 1206 * 1207 * @param activity The activity receiving a new Intent. 1208 * @param intent The new intent being received. 1209 */ callActivityOnNewIntent(Activity activity, Intent intent)1210 public void callActivityOnNewIntent(Activity activity, Intent intent) { 1211 activity.onNewIntent(intent); 1212 } 1213 1214 /** 1215 * @hide 1216 */ callActivityOnNewIntent(Activity activity, ReferrerIntent intent)1217 public void callActivityOnNewIntent(Activity activity, ReferrerIntent intent) { 1218 final String oldReferrer = activity.mReferrer; 1219 try { 1220 if (intent != null) { 1221 activity.mReferrer = intent.mReferrer; 1222 } 1223 callActivityOnNewIntent(activity, intent != null ? new Intent(intent) : null); 1224 } finally { 1225 activity.mReferrer = oldReferrer; 1226 } 1227 } 1228 1229 /** 1230 * Perform calling of an activity's {@link Activity#onStart} 1231 * method. The default implementation simply calls through to that method. 1232 * 1233 * @param activity The activity being started. 1234 */ callActivityOnStart(Activity activity)1235 public void callActivityOnStart(Activity activity) { 1236 activity.onStart(); 1237 } 1238 1239 /** 1240 * Perform calling of an activity's {@link Activity#onRestart} 1241 * method. The default implementation simply calls through to that method. 1242 * 1243 * @param activity The activity being restarted. 1244 */ callActivityOnRestart(Activity activity)1245 public void callActivityOnRestart(Activity activity) { 1246 activity.onRestart(); 1247 } 1248 1249 /** 1250 * Perform calling of an activity's {@link Activity#onResume} method. The 1251 * default implementation simply calls through to that method. 1252 * 1253 * @param activity The activity being resumed. 1254 */ callActivityOnResume(Activity activity)1255 public void callActivityOnResume(Activity activity) { 1256 activity.mResumed = true; 1257 activity.onResume(); 1258 1259 if (mActivityMonitors != null) { 1260 synchronized (mSync) { 1261 final int N = mActivityMonitors.size(); 1262 for (int i=0; i<N; i++) { 1263 final ActivityMonitor am = mActivityMonitors.get(i); 1264 am.match(activity, activity, activity.getIntent()); 1265 } 1266 } 1267 } 1268 } 1269 1270 /** 1271 * Perform calling of an activity's {@link Activity#onStop} 1272 * method. The default implementation simply calls through to that method. 1273 * 1274 * @param activity The activity being stopped. 1275 */ callActivityOnStop(Activity activity)1276 public void callActivityOnStop(Activity activity) { 1277 activity.onStop(); 1278 } 1279 1280 /** 1281 * Perform calling of an activity's {@link Activity#onSaveInstanceState} 1282 * method. The default implementation simply calls through to that method. 1283 * 1284 * @param activity The activity being saved. 1285 * @param outState The bundle to pass to the call. 1286 */ callActivityOnSaveInstanceState(Activity activity, Bundle outState)1287 public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) { 1288 activity.performSaveInstanceState(outState); 1289 } 1290 1291 /** 1292 * Perform calling of an activity's {@link Activity#onSaveInstanceState} 1293 * method. The default implementation simply calls through to that method. 1294 * @param activity The activity being saved. 1295 * @param outState The bundle to pass to the call. 1296 * @param outPersistentState The persistent bundle to pass to the call. 1297 */ callActivityOnSaveInstanceState(Activity activity, Bundle outState, PersistableBundle outPersistentState)1298 public void callActivityOnSaveInstanceState(Activity activity, Bundle outState, 1299 PersistableBundle outPersistentState) { 1300 activity.performSaveInstanceState(outState, outPersistentState); 1301 } 1302 1303 /** 1304 * Perform calling of an activity's {@link Activity#onPause} method. The 1305 * default implementation simply calls through to that method. 1306 * 1307 * @param activity The activity being paused. 1308 */ callActivityOnPause(Activity activity)1309 public void callActivityOnPause(Activity activity) { 1310 activity.performPause(); 1311 } 1312 1313 /** 1314 * Perform calling of an activity's {@link Activity#onUserLeaveHint} method. 1315 * The default implementation simply calls through to that method. 1316 * 1317 * @param activity The activity being notified that the user has navigated away 1318 */ callActivityOnUserLeaving(Activity activity)1319 public void callActivityOnUserLeaving(Activity activity) { 1320 activity.performUserLeaving(); 1321 } 1322 1323 /* 1324 * Starts allocation counting. This triggers a gc and resets the counts. 1325 */ startAllocCounting()1326 public void startAllocCounting() { 1327 // Before we start trigger a GC and reset the debug counts. Run the 1328 // finalizers and another GC before starting and stopping the alloc 1329 // counts. This will free up any objects that were just sitting around 1330 // waiting for their finalizers to be run. 1331 Runtime.getRuntime().gc(); 1332 Runtime.getRuntime().runFinalization(); 1333 Runtime.getRuntime().gc(); 1334 1335 Debug.resetAllCounts(); 1336 1337 // start the counts 1338 Debug.startAllocCounting(); 1339 } 1340 1341 /* 1342 * Stops allocation counting. 1343 */ stopAllocCounting()1344 public void stopAllocCounting() { 1345 Runtime.getRuntime().gc(); 1346 Runtime.getRuntime().runFinalization(); 1347 Runtime.getRuntime().gc(); 1348 Debug.stopAllocCounting(); 1349 } 1350 1351 /** 1352 * If Results already contains Key, it appends Value to the key's ArrayList 1353 * associated with the key. If the key doesn't already exist in results, it 1354 * adds the key/value pair to results. 1355 */ addValue(String key, int value, Bundle results)1356 private void addValue(String key, int value, Bundle results) { 1357 if (results.containsKey(key)) { 1358 List<Integer> list = results.getIntegerArrayList(key); 1359 if (list != null) { 1360 list.add(value); 1361 } 1362 } else { 1363 ArrayList<Integer> list = new ArrayList<Integer>(); 1364 list.add(value); 1365 results.putIntegerArrayList(key, list); 1366 } 1367 } 1368 1369 /** 1370 * Returns a bundle with the current results from the allocation counting. 1371 */ getAllocCounts()1372 public Bundle getAllocCounts() { 1373 Bundle results = new Bundle(); 1374 results.putLong("global_alloc_count", Debug.getGlobalAllocCount()); 1375 results.putLong("global_alloc_size", Debug.getGlobalAllocSize()); 1376 results.putLong("global_freed_count", Debug.getGlobalFreedCount()); 1377 results.putLong("global_freed_size", Debug.getGlobalFreedSize()); 1378 results.putLong("gc_invocation_count", Debug.getGlobalGcInvocationCount()); 1379 return results; 1380 } 1381 1382 /** 1383 * Returns a bundle with the counts for various binder counts for this process. Currently the only two that are 1384 * reported are the number of send and the number of received transactions. 1385 */ getBinderCounts()1386 public Bundle getBinderCounts() { 1387 Bundle results = new Bundle(); 1388 results.putLong("sent_transactions", Debug.getBinderSentTransactions()); 1389 results.putLong("received_transactions", Debug.getBinderReceivedTransactions()); 1390 return results; 1391 } 1392 1393 /** 1394 * Description of a Activity execution result to return to the original 1395 * activity. 1396 */ 1397 public static final class ActivityResult { 1398 /** 1399 * Create a new activity result. See {@link Activity#setResult} for 1400 * more information. 1401 * 1402 * @param resultCode The result code to propagate back to the 1403 * originating activity, often RESULT_CANCELED or RESULT_OK 1404 * @param resultData The data to propagate back to the originating 1405 * activity. 1406 */ ActivityResult(int resultCode, Intent resultData)1407 public ActivityResult(int resultCode, Intent resultData) { 1408 mResultCode = resultCode; 1409 mResultData = resultData; 1410 } 1411 1412 /** 1413 * Retrieve the result code contained in this result. 1414 */ getResultCode()1415 public int getResultCode() { 1416 return mResultCode; 1417 } 1418 1419 /** 1420 * Retrieve the data contained in this result. 1421 */ getResultData()1422 public Intent getResultData() { 1423 return mResultData; 1424 } 1425 1426 private final int mResultCode; 1427 private final Intent mResultData; 1428 } 1429 1430 /** 1431 * Execute a startActivity call made by the application. The default 1432 * implementation takes care of updating any active {@link ActivityMonitor} 1433 * objects and dispatches this call to the system activity manager; you can 1434 * override this to watch for the application to start an activity, and 1435 * modify what happens when it does. 1436 * 1437 * <p>This method returns an {@link ActivityResult} object, which you can 1438 * use when intercepting application calls to avoid performing the start 1439 * activity action but still return the result the application is 1440 * expecting. To do this, override this method to catch the call to start 1441 * activity so that it returns a new ActivityResult containing the results 1442 * you would like the application to see, and don't call up to the super 1443 * class. Note that an application is only expecting a result if 1444 * <var>requestCode</var> is >= 0. 1445 * 1446 * <p>This method throws {@link android.content.ActivityNotFoundException} 1447 * if there was no Activity found to run the given Intent. 1448 * 1449 * @param who The Context from which the activity is being started. 1450 * @param contextThread The main thread of the Context from which the activity 1451 * is being started. 1452 * @param token Internal token identifying to the system who is starting 1453 * the activity; may be null. 1454 * @param target Which activity is performing the start (and thus receiving 1455 * any result); may be null if this call is not being made 1456 * from an activity. 1457 * @param intent The actual Intent to start. 1458 * @param requestCode Identifier for this request's result; less than zero 1459 * if the caller is not expecting a result. 1460 * @param options Addition options. 1461 * 1462 * @return To force the return of a particular result, return an 1463 * ActivityResult object containing the desired data; otherwise 1464 * return null. The default implementation always returns null. 1465 * 1466 * @throws android.content.ActivityNotFoundException 1467 * 1468 * @see Activity#startActivity(Intent) 1469 * @see Activity#startActivityForResult(Intent, int) 1470 * @see Activity#startActivityFromChild 1471 * 1472 * {@hide} 1473 */ execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options)1474 public ActivityResult execStartActivity( 1475 Context who, IBinder contextThread, IBinder token, Activity target, 1476 Intent intent, int requestCode, Bundle options) { 1477 IApplicationThread whoThread = (IApplicationThread) contextThread; 1478 if (mActivityMonitors != null) { 1479 synchronized (mSync) { 1480 final int N = mActivityMonitors.size(); 1481 for (int i=0; i<N; i++) { 1482 final ActivityMonitor am = mActivityMonitors.get(i); 1483 if (am.match(who, null, intent)) { 1484 am.mHits++; 1485 if (am.isBlocking()) { 1486 return requestCode >= 0 ? am.getResult() : null; 1487 } 1488 break; 1489 } 1490 } 1491 } 1492 } 1493 try { 1494 intent.migrateExtraStreamToClipData(); 1495 intent.prepareToLeaveProcess(); 1496 int result = ActivityManagerNative.getDefault() 1497 .startActivity(whoThread, who.getBasePackageName(), intent, 1498 intent.resolveTypeIfNeeded(who.getContentResolver()), 1499 token, target != null ? target.mEmbeddedID : null, 1500 requestCode, 0, null, options); 1501 checkStartActivityResult(result, intent); 1502 } catch (RemoteException e) { 1503 } 1504 return null; 1505 } 1506 1507 /** 1508 * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)}, 1509 * but accepts an array of activities to be started. Note that active 1510 * {@link ActivityMonitor} objects only match against the first activity in 1511 * the array. 1512 * 1513 * {@hide} 1514 */ execStartActivities(Context who, IBinder contextThread, IBinder token, Activity target, Intent[] intents, Bundle options)1515 public void execStartActivities(Context who, IBinder contextThread, 1516 IBinder token, Activity target, Intent[] intents, Bundle options) { 1517 execStartActivitiesAsUser(who, contextThread, token, target, intents, options, 1518 UserHandle.myUserId()); 1519 } 1520 1521 /** 1522 * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)}, 1523 * but accepts an array of activities to be started. Note that active 1524 * {@link ActivityMonitor} objects only match against the first activity in 1525 * the array. 1526 * 1527 * {@hide} 1528 */ execStartActivitiesAsUser(Context who, IBinder contextThread, IBinder token, Activity target, Intent[] intents, Bundle options, int userId)1529 public void execStartActivitiesAsUser(Context who, IBinder contextThread, 1530 IBinder token, Activity target, Intent[] intents, Bundle options, 1531 int userId) { 1532 IApplicationThread whoThread = (IApplicationThread) contextThread; 1533 if (mActivityMonitors != null) { 1534 synchronized (mSync) { 1535 final int N = mActivityMonitors.size(); 1536 for (int i=0; i<N; i++) { 1537 final ActivityMonitor am = mActivityMonitors.get(i); 1538 if (am.match(who, null, intents[0])) { 1539 am.mHits++; 1540 if (am.isBlocking()) { 1541 return; 1542 } 1543 break; 1544 } 1545 } 1546 } 1547 } 1548 try { 1549 String[] resolvedTypes = new String[intents.length]; 1550 for (int i=0; i<intents.length; i++) { 1551 intents[i].migrateExtraStreamToClipData(); 1552 intents[i].prepareToLeaveProcess(); 1553 resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver()); 1554 } 1555 int result = ActivityManagerNative.getDefault() 1556 .startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes, 1557 token, options, userId); 1558 checkStartActivityResult(result, intents[0]); 1559 } catch (RemoteException e) { 1560 } 1561 } 1562 1563 /** 1564 * Like {@link #execStartActivity(android.content.Context, android.os.IBinder, 1565 * android.os.IBinder, Fragment, android.content.Intent, int, android.os.Bundle)}, 1566 * but for calls from a {#link Fragment}. 1567 * 1568 * @param who The Context from which the activity is being started. 1569 * @param contextThread The main thread of the Context from which the activity 1570 * is being started. 1571 * @param token Internal token identifying to the system who is starting 1572 * the activity; may be null. 1573 * @param target Which fragment is performing the start (and thus receiving 1574 * any result). 1575 * @param intent The actual Intent to start. 1576 * @param requestCode Identifier for this request's result; less than zero 1577 * if the caller is not expecting a result. 1578 * 1579 * @return To force the return of a particular result, return an 1580 * ActivityResult object containing the desired data; otherwise 1581 * return null. The default implementation always returns null. 1582 * 1583 * @throws android.content.ActivityNotFoundException 1584 * 1585 * @see Activity#startActivity(Intent) 1586 * @see Activity#startActivityForResult(Intent, int) 1587 * @see Activity#startActivityFromChild 1588 * 1589 * {@hide} 1590 */ execStartActivity( Context who, IBinder contextThread, IBinder token, Fragment target, Intent intent, int requestCode, Bundle options)1591 public ActivityResult execStartActivity( 1592 Context who, IBinder contextThread, IBinder token, Fragment target, 1593 Intent intent, int requestCode, Bundle options) { 1594 IApplicationThread whoThread = (IApplicationThread) contextThread; 1595 if (mActivityMonitors != null) { 1596 synchronized (mSync) { 1597 final int N = mActivityMonitors.size(); 1598 for (int i=0; i<N; i++) { 1599 final ActivityMonitor am = mActivityMonitors.get(i); 1600 if (am.match(who, null, intent)) { 1601 am.mHits++; 1602 if (am.isBlocking()) { 1603 return requestCode >= 0 ? am.getResult() : null; 1604 } 1605 break; 1606 } 1607 } 1608 } 1609 } 1610 try { 1611 intent.migrateExtraStreamToClipData(); 1612 intent.prepareToLeaveProcess(); 1613 int result = ActivityManagerNative.getDefault() 1614 .startActivity(whoThread, who.getBasePackageName(), intent, 1615 intent.resolveTypeIfNeeded(who.getContentResolver()), 1616 token, target != null ? target.mWho : null, 1617 requestCode, 0, null, options); 1618 checkStartActivityResult(result, intent); 1619 } catch (RemoteException e) { 1620 } 1621 return null; 1622 } 1623 1624 /** 1625 * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)}, 1626 * but for starting as a particular user. 1627 * 1628 * @param who The Context from which the activity is being started. 1629 * @param contextThread The main thread of the Context from which the activity 1630 * is being started. 1631 * @param token Internal token identifying to the system who is starting 1632 * the activity; may be null. 1633 * @param target Which fragment is performing the start (and thus receiving 1634 * any result). 1635 * @param intent The actual Intent to start. 1636 * @param requestCode Identifier for this request's result; less than zero 1637 * if the caller is not expecting a result. 1638 * 1639 * @return To force the return of a particular result, return an 1640 * ActivityResult object containing the desired data; otherwise 1641 * return null. The default implementation always returns null. 1642 * 1643 * @throws android.content.ActivityNotFoundException 1644 * 1645 * @see Activity#startActivity(Intent) 1646 * @see Activity#startActivityForResult(Intent, int) 1647 * @see Activity#startActivityFromChild 1648 * 1649 * {@hide} 1650 */ execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options, UserHandle user)1651 public ActivityResult execStartActivity( 1652 Context who, IBinder contextThread, IBinder token, Activity target, 1653 Intent intent, int requestCode, Bundle options, UserHandle user) { 1654 IApplicationThread whoThread = (IApplicationThread) contextThread; 1655 if (mActivityMonitors != null) { 1656 synchronized (mSync) { 1657 final int N = mActivityMonitors.size(); 1658 for (int i=0; i<N; i++) { 1659 final ActivityMonitor am = mActivityMonitors.get(i); 1660 if (am.match(who, null, intent)) { 1661 am.mHits++; 1662 if (am.isBlocking()) { 1663 return requestCode >= 0 ? am.getResult() : null; 1664 } 1665 break; 1666 } 1667 } 1668 } 1669 } 1670 try { 1671 intent.migrateExtraStreamToClipData(); 1672 intent.prepareToLeaveProcess(); 1673 int result = ActivityManagerNative.getDefault() 1674 .startActivityAsUser(whoThread, who.getBasePackageName(), intent, 1675 intent.resolveTypeIfNeeded(who.getContentResolver()), 1676 token, target != null ? target.mEmbeddedID : null, 1677 requestCode, 0, null, options, user.getIdentifier()); 1678 checkStartActivityResult(result, intent); 1679 } catch (RemoteException e) { 1680 } 1681 return null; 1682 } 1683 1684 /** 1685 * Special version! 1686 * @hide 1687 */ execStartActivityAsCaller( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options, int userId)1688 public ActivityResult execStartActivityAsCaller( 1689 Context who, IBinder contextThread, IBinder token, Activity target, 1690 Intent intent, int requestCode, Bundle options, int userId) { 1691 IApplicationThread whoThread = (IApplicationThread) contextThread; 1692 if (mActivityMonitors != null) { 1693 synchronized (mSync) { 1694 final int N = mActivityMonitors.size(); 1695 for (int i=0; i<N; i++) { 1696 final ActivityMonitor am = mActivityMonitors.get(i); 1697 if (am.match(who, null, intent)) { 1698 am.mHits++; 1699 if (am.isBlocking()) { 1700 return requestCode >= 0 ? am.getResult() : null; 1701 } 1702 break; 1703 } 1704 } 1705 } 1706 } 1707 try { 1708 intent.migrateExtraStreamToClipData(); 1709 intent.prepareToLeaveProcess(); 1710 int result = ActivityManagerNative.getDefault() 1711 .startActivityAsCaller(whoThread, who.getBasePackageName(), intent, 1712 intent.resolveTypeIfNeeded(who.getContentResolver()), 1713 token, target != null ? target.mEmbeddedID : null, 1714 requestCode, 0, null, options, userId); 1715 checkStartActivityResult(result, intent); 1716 } catch (RemoteException e) { 1717 } 1718 return null; 1719 } 1720 1721 /** 1722 * Special version! 1723 * @hide 1724 */ execStartActivityFromAppTask( Context who, IBinder contextThread, IAppTask appTask, Intent intent, Bundle options)1725 public void execStartActivityFromAppTask( 1726 Context who, IBinder contextThread, IAppTask appTask, 1727 Intent intent, Bundle options) { 1728 IApplicationThread whoThread = (IApplicationThread) contextThread; 1729 if (mActivityMonitors != null) { 1730 synchronized (mSync) { 1731 final int N = mActivityMonitors.size(); 1732 for (int i=0; i<N; i++) { 1733 final ActivityMonitor am = mActivityMonitors.get(i); 1734 if (am.match(who, null, intent)) { 1735 am.mHits++; 1736 if (am.isBlocking()) { 1737 return; 1738 } 1739 break; 1740 } 1741 } 1742 } 1743 } 1744 try { 1745 intent.migrateExtraStreamToClipData(); 1746 intent.prepareToLeaveProcess(); 1747 int result = appTask.startActivity(whoThread.asBinder(), who.getBasePackageName(), 1748 intent, intent.resolveTypeIfNeeded(who.getContentResolver()), options); 1749 checkStartActivityResult(result, intent); 1750 } catch (RemoteException e) { 1751 } 1752 return; 1753 } 1754 init(ActivityThread thread, Context instrContext, Context appContext, ComponentName component, IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection)1755 /*package*/ final void init(ActivityThread thread, 1756 Context instrContext, Context appContext, ComponentName component, 1757 IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection) { 1758 mThread = thread; 1759 mMessageQueue = mThread.getLooper().myQueue(); 1760 mInstrContext = instrContext; 1761 mAppContext = appContext; 1762 mComponent = component; 1763 mWatcher = watcher; 1764 mUiAutomationConnection = uiAutomationConnection; 1765 } 1766 1767 /** @hide */ checkStartActivityResult(int res, Object intent)1768 public static void checkStartActivityResult(int res, Object intent) { 1769 if (res >= ActivityManager.START_SUCCESS) { 1770 return; 1771 } 1772 1773 switch (res) { 1774 case ActivityManager.START_INTENT_NOT_RESOLVED: 1775 case ActivityManager.START_CLASS_NOT_FOUND: 1776 if (intent instanceof Intent && ((Intent)intent).getComponent() != null) 1777 throw new ActivityNotFoundException( 1778 "Unable to find explicit activity class " 1779 + ((Intent)intent).getComponent().toShortString() 1780 + "; have you declared this activity in your AndroidManifest.xml?"); 1781 throw new ActivityNotFoundException( 1782 "No Activity found to handle " + intent); 1783 case ActivityManager.START_PERMISSION_DENIED: 1784 throw new SecurityException("Not allowed to start activity " 1785 + intent); 1786 case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: 1787 throw new AndroidRuntimeException( 1788 "FORWARD_RESULT_FLAG used while also requesting a result"); 1789 case ActivityManager.START_NOT_ACTIVITY: 1790 throw new IllegalArgumentException( 1791 "PendingIntent is not an activity"); 1792 case ActivityManager.START_NOT_VOICE_COMPATIBLE: 1793 throw new SecurityException( 1794 "Starting under voice control not allowed for: " + intent); 1795 default: 1796 throw new AndroidRuntimeException("Unknown error code " 1797 + res + " when starting " + intent); 1798 } 1799 } 1800 validateNotAppThread()1801 private final void validateNotAppThread() { 1802 if (Looper.myLooper() == Looper.getMainLooper()) { 1803 throw new RuntimeException( 1804 "This method can not be called from the main application thread"); 1805 } 1806 } 1807 1808 /** 1809 * Gets the {@link UiAutomation} instance. 1810 * <p> 1811 * <strong>Note:</strong> The APIs exposed via the returned {@link UiAutomation} 1812 * work across application boundaries while the APIs exposed by the instrumentation 1813 * do not. For example, {@link Instrumentation#sendPointerSync(MotionEvent)} will 1814 * not allow you to inject the event in an app different from the instrumentation 1815 * target, while {@link UiAutomation#injectInputEvent(android.view.InputEvent, boolean)} 1816 * will work regardless of the current application. 1817 * </p> 1818 * <p> 1819 * A typical test case should be using either the {@link UiAutomation} or 1820 * {@link Instrumentation} APIs. Using both APIs at the same time is not 1821 * a mistake by itself but a client has to be aware of the APIs limitations. 1822 * </p> 1823 * @return The UI automation instance. 1824 * 1825 * @see UiAutomation 1826 */ getUiAutomation()1827 public UiAutomation getUiAutomation() { 1828 if (mUiAutomationConnection != null) { 1829 if (mUiAutomation == null) { 1830 mUiAutomation = new UiAutomation(getTargetContext().getMainLooper(), 1831 mUiAutomationConnection); 1832 mUiAutomation.connect(); 1833 } 1834 return mUiAutomation; 1835 } 1836 return null; 1837 } 1838 1839 private final class InstrumentationThread extends Thread { InstrumentationThread(String name)1840 public InstrumentationThread(String name) { 1841 super(name); 1842 } run()1843 public void run() { 1844 try { 1845 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 1846 } catch (RuntimeException e) { 1847 Log.w(TAG, "Exception setting priority of instrumentation thread " 1848 + Process.myTid(), e); 1849 } 1850 if (mAutomaticPerformanceSnapshots) { 1851 startPerformanceSnapshot(); 1852 } 1853 onStart(); 1854 } 1855 } 1856 1857 private static final class EmptyRunnable implements Runnable { run()1858 public void run() { 1859 } 1860 } 1861 1862 private static final class SyncRunnable implements Runnable { 1863 private final Runnable mTarget; 1864 private boolean mComplete; 1865 SyncRunnable(Runnable target)1866 public SyncRunnable(Runnable target) { 1867 mTarget = target; 1868 } 1869 run()1870 public void run() { 1871 mTarget.run(); 1872 synchronized (this) { 1873 mComplete = true; 1874 notifyAll(); 1875 } 1876 } 1877 waitForComplete()1878 public void waitForComplete() { 1879 synchronized (this) { 1880 while (!mComplete) { 1881 try { 1882 wait(); 1883 } catch (InterruptedException e) { 1884 } 1885 } 1886 } 1887 } 1888 } 1889 1890 private static final class ActivityWaiter { 1891 public final Intent intent; 1892 public Activity activity; 1893 ActivityWaiter(Intent _intent)1894 public ActivityWaiter(Intent _intent) { 1895 intent = _intent; 1896 } 1897 } 1898 1899 private final class ActivityGoing implements MessageQueue.IdleHandler { 1900 private final ActivityWaiter mWaiter; 1901 ActivityGoing(ActivityWaiter waiter)1902 public ActivityGoing(ActivityWaiter waiter) { 1903 mWaiter = waiter; 1904 } 1905 queueIdle()1906 public final boolean queueIdle() { 1907 synchronized (mSync) { 1908 mWaitingActivities.remove(mWaiter); 1909 mSync.notifyAll(); 1910 } 1911 return false; 1912 } 1913 } 1914 1915 private static final class Idler implements MessageQueue.IdleHandler { 1916 private final Runnable mCallback; 1917 private boolean mIdle; 1918 Idler(Runnable callback)1919 public Idler(Runnable callback) { 1920 mCallback = callback; 1921 mIdle = false; 1922 } 1923 queueIdle()1924 public final boolean queueIdle() { 1925 if (mCallback != null) { 1926 mCallback.run(); 1927 } 1928 synchronized (this) { 1929 mIdle = true; 1930 notifyAll(); 1931 } 1932 return false; 1933 } 1934 waitForIdle()1935 public void waitForIdle() { 1936 synchronized (this) { 1937 while (!mIdle) { 1938 try { 1939 wait(); 1940 } catch (InterruptedException e) { 1941 } 1942 } 1943 } 1944 } 1945 } 1946 } 1947