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