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