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