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