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