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