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