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