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