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