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