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