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