1 /* 2 * Copyright (C) 2010 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 com.android.tradefed.device; 18 19 import com.android.ddmlib.IDevice; 20 import com.android.tradefed.log.ITestLogger; 21 import com.android.tradefed.result.InputStreamSource; 22 import com.android.tradefed.util.Bugreport; 23 import com.android.tradefed.util.KeyguardControllerState; 24 25 import java.io.File; 26 import java.io.InputStream; 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.Set; 32 33 /** 34 * Provides an reliable and slightly higher level API to a ddmlib {@link IDevice}. 35 * <p/> 36 * Retries device commands for a configurable amount, and provides a device recovery 37 * interface for devices which are unresponsive. 38 */ 39 public interface ITestDevice extends INativeDevice { 40 41 public enum RecoveryMode { 42 /** don't attempt to recover device. */ 43 NONE, 44 /** recover device to online state only */ 45 ONLINE, 46 /** 47 * Recover device into fully testable state - framework is up, and external storage is 48 * mounted. 49 */ 50 AVAILABLE 51 } 52 53 /** 54 * A simple struct class to store information about a single mountpoint 55 */ 56 public static class MountPointInfo { 57 public String filesystem; 58 public String mountpoint; 59 public String type; 60 public List<String> options; 61 62 /** Simple constructor */ MountPointInfo()63 public MountPointInfo() {} 64 65 /** 66 * Convenience constructor to set all members 67 */ MountPointInfo(String filesystem, String mountpoint, String type, List<String> options)68 public MountPointInfo(String filesystem, String mountpoint, String type, 69 List<String> options) { 70 this.filesystem = filesystem; 71 this.mountpoint = mountpoint; 72 this.type = type; 73 this.options = options; 74 } 75 MountPointInfo(String filesystem, String mountpoint, String type, String optString)76 public MountPointInfo(String filesystem, String mountpoint, String type, String optString) { 77 this(filesystem, mountpoint, type, splitMountOptions(optString)); 78 } 79 splitMountOptions(String options)80 public static List<String> splitMountOptions(String options) { 81 List<String> list = Arrays.asList(options.split(",")); 82 return list; 83 } 84 85 @Override toString()86 public String toString() { 87 return String.format("%s %s %s %s", this.filesystem, this.mountpoint, this.type, 88 this.options); 89 } 90 } 91 92 /** A simple struct class to store information about a single APEX */ 93 public static class ApexInfo { 94 public final String name; 95 public final long versionCode; 96 public final String sourceDir; 97 ApexInfo(String name, long versionCode, String sourceDir)98 public ApexInfo(String name, long versionCode, String sourceDir) { 99 this.name = name; 100 this.versionCode = versionCode; 101 this.sourceDir = sourceDir; 102 } 103 ApexInfo(String name, long versionCode)104 public ApexInfo(String name, long versionCode) { 105 this(name, versionCode, ""); 106 } 107 108 @Override equals(Object other)109 public boolean equals(Object other) { 110 if (other != null && other instanceof ApexInfo) { 111 ApexInfo ai = (ApexInfo) other; 112 return name.equals(ai.name) && versionCode == ai.versionCode; 113 } 114 return false; 115 } 116 117 @Override hashCode()118 public int hashCode() { 119 // no need to consider versionCode here. 120 return name.hashCode(); 121 } 122 123 @Override toString()124 public String toString() { 125 return "packageName: " 126 + name 127 + ", versionCode: " 128 + versionCode 129 + ", sourceDir: " 130 + sourceDir; 131 } 132 } 133 134 /** 135 * Install an Android package on device. 136 * 137 * @param packageFile the apk file to install 138 * @param reinstall <code>true</code> if a reinstall should be performed 139 * @param extraArgs optional extra arguments to pass. See 'adb shell pm -h' for available 140 * options. 141 * @return a {@link String} with an error code, or <code>null</code> if success. 142 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 143 * recovered. 144 */ installPackage(File packageFile, boolean reinstall, String... extraArgs)145 public String installPackage(File packageFile, boolean reinstall, String... extraArgs) 146 throws DeviceNotAvailableException; 147 148 /** 149 * Install an Android package on device. 150 * 151 * <p>Note: Only use cases that requires explicit control of granting runtime permission at 152 * install time should call this function. 153 * 154 * @param packageFile the apk file to install 155 * @param reinstall <code>true</code> if a reinstall should be performed 156 * @param grantPermissions if all runtime permissions should be granted at install time 157 * @param extraArgs optional extra arguments to pass. See 'adb shell pm -h' for available 158 * options. 159 * @return a {@link String} with an error code, or <code>null</code> if success. 160 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 161 * recovered. 162 * @throws UnsupportedOperationException if runtime permission is not supported by the platform 163 * on device. 164 */ installPackage( File packageFile, boolean reinstall, boolean grantPermissions, String... extraArgs)165 public String installPackage( 166 File packageFile, boolean reinstall, boolean grantPermissions, String... extraArgs) 167 throws DeviceNotAvailableException; 168 169 /** 170 * Install an Android package on device for a given user. 171 * 172 * @param packageFile the apk file to install 173 * @param reinstall <code>true</code> if a reinstall should be performed 174 * @param userId the integer user id to install for. 175 * @param extraArgs optional extra arguments to pass. See 'adb shell pm -h' for available 176 * options. 177 * @return a {@link String} with an error code, or <code>null</code> if success. 178 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 179 * recovered. 180 */ installPackageForUser( File packageFile, boolean reinstall, int userId, String... extraArgs)181 public String installPackageForUser( 182 File packageFile, boolean reinstall, int userId, String... extraArgs) 183 throws DeviceNotAvailableException; 184 185 /** 186 * Install an Android package on device for a given user. 187 * 188 * <p>Note: Only use cases that requires explicit control of granting runtime permission at 189 * install time should call this function. 190 * 191 * @param packageFile the apk file to install 192 * @param reinstall <code>true</code> if a reinstall should be performed 193 * @param grantPermissions if all runtime permissions should be granted at install time 194 * @param userId the integer user id to install for. 195 * @param extraArgs optional extra arguments to pass. See 'adb shell pm -h' for available 196 * options. 197 * @return a {@link String} with an error code, or <code>null</code> if success. 198 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 199 * recovered. 200 * @throws UnsupportedOperationException if runtime permission is not supported by the platform 201 * on device. 202 */ installPackageForUser( File packageFile, boolean reinstall, boolean grantPermissions, int userId, String... extraArgs)203 public String installPackageForUser( 204 File packageFile, 205 boolean reinstall, 206 boolean grantPermissions, 207 int userId, 208 String... extraArgs) 209 throws DeviceNotAvailableException; 210 211 /** 212 * Uninstall an Android package from device. 213 * 214 * @param packageName the Android package to uninstall 215 * @return a {@link String} with an error code, or <code>null</code> if success. 216 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 217 * recovered. 218 */ uninstallPackage(String packageName)219 public String uninstallPackage(String packageName) throws DeviceNotAvailableException; 220 221 /** 222 * Uninstall an Android package from device for a given user. 223 * 224 * @param packageName the Android package to uninstall 225 * @param userId the integer user id to uninstall for. 226 * @return a {@link String} with an error code, or <code>null</code> if success. 227 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 228 * recovered. 229 */ uninstallPackageForUser(String packageName, int userId)230 public String uninstallPackageForUser(String packageName, int userId) 231 throws DeviceNotAvailableException; 232 233 /** 234 * Install an Android application made of several APK files (one main and extra split packages). 235 * See "https://developer.android.com/studio/build/configure-apk-splits" on how to split apk to 236 * several files. 237 * 238 * @param packageFiles the local apk files 239 * @param reinstall <code>true</code> if a reinstall should be performed 240 * @param extraArgs optional extra arguments to pass. See 'adb shell pm -h' for available 241 * options. 242 * @return a {@link String} with an error code, or <code>null</code> if success. 243 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 244 * recovered. 245 * @throws UnsupportedOperationException if runtime permission is not supported by the platform 246 * on device. 247 */ installPackages( List<File> packageFiles, boolean reinstall, String... extraArgs)248 public default String installPackages( 249 List<File> packageFiles, boolean reinstall, String... extraArgs) 250 throws DeviceNotAvailableException { 251 throw new UnsupportedOperationException("No support for Package Manager's features"); 252 } 253 254 /** 255 * Install an Android application made of several APK files (one main and extra split packages) 256 * that are sitting on the android device. See 257 * "https://developer.android.com/studio/build/configure-apk-splits" on how to split apk to 258 * several files. 259 * 260 * <p>Note: Only use cases that requires explicit control of granting runtime permission at 261 * install time should call this function. 262 * 263 * @param packageFiles the remote apk file paths to install 264 * @param reinstall <code>true</code> if a reinstall should be performed 265 * @param grantPermissions if all runtime permissions should be granted at install time 266 * @param extraArgs optional extra arguments to pass. See 'adb shell pm -h' for available 267 * options. 268 * @return a {@link String} with an error code, or <code>null</code> if success. 269 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 270 * recovered. 271 * @throws UnsupportedOperationException if runtime permission is not supported by the platform 272 * on device. 273 */ installPackages( List<File> packageFiles, boolean reinstall, boolean grantPermissions, String... extraArgs)274 public default String installPackages( 275 List<File> packageFiles, 276 boolean reinstall, 277 boolean grantPermissions, 278 String... extraArgs) 279 throws DeviceNotAvailableException { 280 throw new UnsupportedOperationException("No support for Package Manager's features"); 281 } 282 283 /** 284 * Install an Android application made of several APK files (one main and extra split packages) 285 * for a given user. See "https://developer.android.com/studio/build/configure-apk-splits" on 286 * how to split apk to several files. 287 * 288 * @param packageFiles the local apk files 289 * @param reinstall <code>true</code> if a reinstall should be performed 290 * @param userId the integer user id to install for. 291 * @param extraArgs optional extra arguments to pass. See 'adb shell pm -h' for available 292 * options. 293 * @return a {@link String} with an error code, or <code>null</code> if success. 294 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 295 * recovered. 296 * @throws UnsupportedOperationException if runtime permission is not supported by the platform 297 * on device. 298 */ installPackagesForUser( List<File> packageFiles, boolean reinstall, int userId, String... extraArgs)299 public default String installPackagesForUser( 300 List<File> packageFiles, boolean reinstall, int userId, String... extraArgs) 301 throws DeviceNotAvailableException { 302 throw new UnsupportedOperationException("No support for Package Manager's features"); 303 } 304 305 /** 306 * Install an Android application made of several APK files (one main and extra split packages) 307 * for a given user. See "https://developer.android.com/studio/build/configure-apk-splits" on 308 * how to split apk to several files. 309 * 310 * <p>Note: Only use cases that requires explicit control of granting runtime permission at 311 * install time should call this function. 312 * 313 * @param packageFiles the local apk files 314 * @param reinstall <code>true</code> if a reinstall should be performed 315 * @param grantPermissions if all runtime permissions should be granted at install time 316 * @param userId the integer user id to install for. 317 * @param extraArgs optional extra arguments to pass. See 'adb shell pm -h' for available 318 * options. 319 * @return a {@link String} with an error code, or <code>null</code> if success. 320 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 321 * recovered. 322 * @throws UnsupportedOperationException if runtime permission is not supported by the platform 323 * on device. 324 */ installPackagesForUser( List<File> packageFiles, boolean reinstall, boolean grantPermissions, int userId, String... extraArgs)325 public default String installPackagesForUser( 326 List<File> packageFiles, 327 boolean reinstall, 328 boolean grantPermissions, 329 int userId, 330 String... extraArgs) 331 throws DeviceNotAvailableException { 332 throw new UnsupportedOperationException("No support for Package Manager's features"); 333 } 334 335 /** 336 * Install an Android application made of several APK files (one main and extra split packages) 337 * that are sitting on the android device. See 338 * "https://developer.android.com/studio/build/configure-apk-splits" on how to split apk to 339 * several files. 340 * 341 * <p>Note: Only use cases that requires explicit control of granting runtime permission at 342 * install time should call this function. 343 * 344 * @param remoteApkPaths the remote apk file paths 345 * @param reinstall <code>true</code> if a reinstall should be performed 346 * @param grantPermissions if all runtime permissions should be granted at install time 347 * @param extraArgs optional extra arguments to pass. See 'adb shell pm -h' for available 348 * options. 349 * @return a {@link String} with an error code, or <code>null</code> if success. 350 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 351 * recovered. 352 * @throws UnsupportedOperationException if runtime permission is not supported by the platform 353 * on device. 354 */ installRemotePackages( List<String> remoteApkPaths, boolean reinstall, boolean grantPermissions, String... extraArgs)355 public default String installRemotePackages( 356 List<String> remoteApkPaths, 357 boolean reinstall, 358 boolean grantPermissions, 359 String... extraArgs) 360 throws DeviceNotAvailableException { 361 throw new UnsupportedOperationException("No support for Package Manager's features"); 362 } 363 364 /** 365 * Install an Android application made of several APK files (one main and extra split packages) 366 * that are sitting on the android device. See 367 * "https://developer.android.com/studio/build/configure-apk-splits" on how to split apk to 368 * several files. 369 * 370 * @param remoteApkPaths the remote apk file paths 371 * @param reinstall <code>true</code> if a reinstall should be performed 372 * @param extraArgs optional extra arguments to pass. See 'adb shell pm -h' for available 373 * options. 374 * @return a {@link String} with an error code, or <code>null</code> if success. 375 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 376 * recovered. 377 * @throws UnsupportedOperationException if runtime permission is not supported by the platform 378 * on device. 379 */ installRemotePackages( List<String> remoteApkPaths, boolean reinstall, String... extraArgs)380 public default String installRemotePackages( 381 List<String> remoteApkPaths, boolean reinstall, String... extraArgs) 382 throws DeviceNotAvailableException { 383 throw new UnsupportedOperationException("No support for Package Manager's features"); 384 } 385 386 387 /** 388 * Grabs a screenshot from the device. 389 * 390 * @return a {@link InputStreamSource} of the screenshot in png format, or <code>null</code> if 391 * the screenshot was not successful. 392 * @throws DeviceNotAvailableException 393 */ getScreenshot()394 public InputStreamSource getScreenshot() throws DeviceNotAvailableException; 395 396 /** 397 * Grabs a screenshot from the device. 398 * Recommended to use getScreenshot(format) instead with JPEG encoding for smaller size 399 * @param format supported PNG, JPEG 400 * @return a {@link InputStreamSource} of the screenshot in format, or <code>null</code> if 401 * the screenshot was not successful. 402 * @throws DeviceNotAvailableException 403 */ getScreenshot(String format)404 public InputStreamSource getScreenshot(String format) throws DeviceNotAvailableException; 405 406 /** 407 * Grabs a screenshot from the device. Recommended to use {@link #getScreenshot(String)} instead 408 * with JPEG encoding for smaller size. 409 * 410 * @param format supported PNG, JPEG 411 * @param rescale if screenshot should be rescaled to reduce the size of resulting image 412 * @return a {@link InputStreamSource} of the screenshot in format, or <code>null</code> if the 413 * screenshot was not successful. 414 * @throws DeviceNotAvailableException 415 */ getScreenshot(String format, boolean rescale)416 public InputStreamSource getScreenshot(String format, boolean rescale) 417 throws DeviceNotAvailableException; 418 419 /** 420 * Grabs a screenshot from the device given display id. Format is PNG. 421 * 422 * <p>TODO: extend the implementations above to support 'format' and 'rescale' 423 * 424 * @param displayId the display id of the screen to get screenshot from. 425 * @return a {@link InputStreamSource} of the screenshot in format, or <code>null</code> if the 426 * screenshot was not successful. 427 * @throws DeviceNotAvailableException 428 */ getScreenshot(long displayId)429 public InputStreamSource getScreenshot(long displayId) throws DeviceNotAvailableException; 430 431 /** 432 * Clears the last connected wifi network. This should be called when starting a new invocation 433 * to avoid connecting to the wifi network used in the previous test after device reboots. 434 */ clearLastConnectedWifiNetwork()435 public void clearLastConnectedWifiNetwork(); 436 437 /** 438 * Connects to a wifi network. 439 * <p/> 440 * Turns on wifi and blocks until a successful connection is made to the specified wifi network. 441 * Once a connection is made, the instance will try to restore the connection after every reboot 442 * until {@link ITestDevice#disconnectFromWifi()} or 443 * {@link ITestDevice#clearLastConnectedWifiNetwork()} is called. 444 * 445 * @param wifiSsid the wifi ssid to connect to 446 * @param wifiPsk PSK passphrase or null if unencrypted 447 * @return <code>true</code> if connected to wifi network successfully. <code>false</code> 448 * otherwise 449 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 450 * recovered. 451 */ connectToWifiNetwork(String wifiSsid, String wifiPsk)452 public boolean connectToWifiNetwork(String wifiSsid, String wifiPsk) 453 throws DeviceNotAvailableException; 454 455 /** 456 * Connects to a wifi network. 457 * <p/> 458 * Turns on wifi and blocks until a successful connection is made to the specified wifi network. 459 * Once a connection is made, the instance will try to restore the connection after every reboot 460 * until {@link ITestDevice#disconnectFromWifi()} or 461 * {@link ITestDevice#clearLastConnectedWifiNetwork()} is called. 462 * 463 * @param wifiSsid the wifi ssid to connect to 464 * @param wifiPsk PSK passphrase or null if unencrypted 465 * @param scanSsid whether to scan for hidden SSID for this network. 466 * @return <code>true</code> if connected to wifi network successfully. <code>false</code> 467 * otherwise 468 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 469 * recovered. 470 */ connectToWifiNetwork(String wifiSsid, String wifiPsk, boolean scanSsid)471 public boolean connectToWifiNetwork(String wifiSsid, String wifiPsk, boolean scanSsid) 472 throws DeviceNotAvailableException; 473 474 /** 475 * Connects to a wifi network. 476 * 477 * <p>Turns on wifi and blocks until a successful connection is made with one of the wifi 478 * networks given in the wifiSsidToPsk map. Once a connection is made, the instance will try to 479 * restore the connection after every reboot until {@link ITestDevice#disconnectFromWifi()} or 480 * {@link ITestDevice#clearLastConnectedWifiNetwork()} is called. 481 * 482 * @param wifiSsidToPsk A map of wifi SSIDs to passwords. 483 * @return <code>true</code> if connected to wifi network successfully. <code>false</code> 484 * otherwise 485 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 486 * recovered. 487 */ connectToWifiNetwork(Map<String, String> wifiSsidToPsk)488 public boolean connectToWifiNetwork(Map<String, String> wifiSsidToPsk) 489 throws DeviceNotAvailableException; 490 491 /** 492 * Connects to a wifi network. 493 * 494 * <p>Turns on wifi and blocks until a successful connection is made with one of the wifi 495 * networks given in the wifiSsidToPsk map. Once a connection is made, the instance will try to 496 * restore the connection after every reboot until {@link ITestDevice#disconnectFromWifi()} or 497 * {@link ITestDevice#clearLastConnectedWifiNetwork()} is called. 498 * 499 * @param wifiSsidToPsk A map of wifi SSIDs to passwords. 500 * @param scanSsid whether to scan for hidden SSIDs for this network. 501 * @return <code>true</code> if connected to wifi network successfully. <code>false</code> 502 * otherwise 503 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 504 * recovered. 505 */ connectToWifiNetwork(Map<String, String> wifiSsidToPsk, boolean scanSsid)506 public boolean connectToWifiNetwork(Map<String, String> wifiSsidToPsk, boolean scanSsid) 507 throws DeviceNotAvailableException; 508 509 /** 510 * A variant of {@link #connectToWifiNetwork(String, String)} that only connects if device 511 * currently does not have network connectivity. 512 * 513 * @param wifiSsid 514 * @param wifiPsk 515 * @return <code>true</code> if connected to wifi network successfully. <code>false</code> 516 * otherwise 517 * @throws DeviceNotAvailableException 518 */ connectToWifiNetworkIfNeeded(String wifiSsid, String wifiPsk)519 public boolean connectToWifiNetworkIfNeeded(String wifiSsid, String wifiPsk) 520 throws DeviceNotAvailableException; 521 522 /** 523 * A variant of {@link #connectToWifiNetwork(String, String)} that only connects if device 524 * currently does not have network connectivity. 525 * 526 * @param wifiSsid 527 * @param wifiPsk 528 * @param scanSsid whether to scan for hidden SSID for this network 529 * @return <code>true</code> if connected to wifi network successfully. <code>false</code> 530 * otherwise 531 * @throws DeviceNotAvailableException 532 */ connectToWifiNetworkIfNeeded(String wifiSsid, String wifiPsk, boolean scanSsid)533 public boolean connectToWifiNetworkIfNeeded(String wifiSsid, String wifiPsk, boolean scanSsid) 534 throws DeviceNotAvailableException; 535 536 /** 537 * Disconnects from a wifi network. 538 * <p/> 539 * Removes all networks from known networks list and disables wifi. 540 * 541 * @return <code>true</code> if disconnected from wifi network successfully. <code>false</code> 542 * if disconnect failed. 543 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 544 * recovered. 545 */ disconnectFromWifi()546 public boolean disconnectFromWifi() throws DeviceNotAvailableException; 547 548 /** 549 * Test if wifi is enabled. 550 * <p/> 551 * Checks if wifi is enabled on device. Useful for asserting wifi status before tests that 552 * shouldn't run with wifi, e.g. mobile data tests. 553 * 554 * @return <code>true</code> if wifi is enabled. <code>false</code> if disabled 555 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 556 * recovered. 557 */ isWifiEnabled()558 public boolean isWifiEnabled() throws DeviceNotAvailableException; 559 560 /** 561 * Gets the device's IP address. 562 * 563 * @return the device's IP address, or <code>null</code> if device has no IP address 564 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 565 * recovered. 566 */ getIpAddress()567 public String getIpAddress() throws DeviceNotAvailableException; 568 569 /** 570 * Enables network monitoring on device. 571 * 572 * @return <code>true</code> if monitoring is enabled successfully. <code>false</code> 573 * if it failed. 574 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 575 * recovered. 576 */ enableNetworkMonitor()577 public boolean enableNetworkMonitor() throws DeviceNotAvailableException; 578 579 /** 580 * Disables network monitoring on device. 581 * 582 * @return <code>true</code> if monitoring is disabled successfully. <code>false</code> 583 * if it failed. 584 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 585 * recovered. 586 */ disableNetworkMonitor()587 public boolean disableNetworkMonitor() throws DeviceNotAvailableException; 588 589 /** 590 * Check that device has network connectivity. 591 * 592 * @return <code>true</code> if device has a working network connection, 593 * <code>false</code> overwise. 594 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 595 * recovered. 596 */ checkConnectivity()597 public boolean checkConnectivity() throws DeviceNotAvailableException; 598 599 /** 600 * Attempt to dismiss any error dialogs currently displayed on device UI. 601 * 602 * @return <code>true</code> if no dialogs were present or dialogs were successfully cleared. 603 * <code>false</code> otherwise. 604 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 605 * recovered. 606 */ clearErrorDialogs()607 public boolean clearErrorDialogs() throws DeviceNotAvailableException; 608 609 /** 610 * Return an object to get the current state of the keyguard or null if not supported. 611 * 612 * @return a {@link KeyguardControllerState} containing a snapshot of the state of the keyguard 613 * and returns Null if the Keyguard query is not supported. 614 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 615 * recovered. 616 */ getKeyguardState()617 public KeyguardControllerState getKeyguardState() throws DeviceNotAvailableException; 618 619 /** 620 * Fetch the test options for the device. 621 * 622 * @return {@link TestDeviceOptions} related to the device under test. 623 */ getOptions()624 public TestDeviceOptions getOptions(); 625 626 /** 627 * Fetch the application package names present on the device. 628 * 629 * @return {@link Set} of {@link String} package names currently installed on the device. 630 * @throws DeviceNotAvailableException 631 */ getInstalledPackageNames()632 public Set<String> getInstalledPackageNames() throws DeviceNotAvailableException; 633 634 /** 635 * Query the device for a given package name to check if it's currently installed or not. 636 * 637 * @return True if the package is reported as installed. False otherwise. 638 * @throws DeviceNotAvailableException 639 */ isPackageInstalled(String packageName)640 public boolean isPackageInstalled(String packageName) throws DeviceNotAvailableException; 641 642 /** 643 * Query the device for a given package name and given user id to check if it's currently 644 * installed or not for that user. 645 * 646 * @param packageName the package we are checking if it's installed. 647 * @param userId The user id we are checking the package is installed for. If null, primary user 648 * zero will be used. 649 * @return True if the package is reported as installed. False otherwise. 650 * @throws DeviceNotAvailableException 651 */ isPackageInstalled(String packageName, String userId)652 public boolean isPackageInstalled(String packageName, String userId) 653 throws DeviceNotAvailableException; 654 655 /** 656 * Fetch the information about APEXes activated on the device. 657 * 658 * @return {@link Set} of {@link ApexInfo} currently activated on the device 659 * @throws DeviceNotAvailableException 660 */ getActiveApexes()661 public Set<ApexInfo> getActiveApexes() throws DeviceNotAvailableException; 662 663 /** 664 * Get the information about the mainline modules installed on the device. 665 * 666 * @return {@link Set} of {@link String} mainline modules currently installed on the device. 667 * @throws DeviceNotAvailableException 668 */ getMainlineModuleInfo()669 public Set<String> getMainlineModuleInfo() throws DeviceNotAvailableException; 670 671 /** 672 * Fetch the application package names that can be uninstalled. This is presently defined as 673 * non-system packages, and updated system packages. 674 * 675 * @return {@link Set} of uninstallable {@link String} package names currently installed on the 676 * device. 677 * @throws DeviceNotAvailableException 678 */ getUninstallablePackageNames()679 public Set<String> getUninstallablePackageNames() throws DeviceNotAvailableException; 680 681 /** 682 * Fetch information about a package installed on device. 683 * 684 * @return the {@link PackageInfo} or <code>null</code> if information could not be retrieved 685 * @throws DeviceNotAvailableException 686 */ getAppPackageInfo(String packageName)687 public PackageInfo getAppPackageInfo(String packageName) throws DeviceNotAvailableException; 688 689 /** 690 * Fetch information of packages installed on the device. 691 * 692 * @return {@link List} of {@link PackageInfo}s installed on the device. 693 * @throws DeviceNotAvailableException 694 */ getAppPackageInfos()695 public List<PackageInfo> getAppPackageInfos() throws DeviceNotAvailableException; 696 697 /** 698 * Determines if multi user is supported. 699 * 700 * @return true if multi user is supported, false otherwise 701 * @throws DeviceNotAvailableException 702 */ isMultiUserSupported()703 public boolean isMultiUserSupported() throws DeviceNotAvailableException; 704 705 /** Returns whether the device uses headless system user mode. */ isHeadlessSystemUserMode()706 public boolean isHeadlessSystemUserMode() throws DeviceNotAvailableException; 707 708 /** Returns whether it's allowed to switch to the headless SYSTEM user. */ canSwitchToHeadlessSystemUser()709 public boolean canSwitchToHeadlessSystemUser() throws DeviceNotAvailableException; 710 711 /** 712 * Returns whether the main user is a permanent admin and can't be deleted or downgraded to 713 * non-admin status. 714 */ isMainUserPermanentAdmin()715 public boolean isMainUserPermanentAdmin() throws DeviceNotAvailableException; 716 717 /** 718 * Create a user with a given name and default flags 0. 719 * 720 * @param name of the user to create on the device 721 * @return the integer for the user id created 722 * @throws DeviceNotAvailableException 723 */ createUser(String name)724 public int createUser(String name) throws DeviceNotAvailableException, IllegalStateException; 725 726 /** 727 * Create a user with a given name and the provided flags 728 * 729 * @param name of the user to create on the device 730 * @param guest enable the user flag --guest during creation 731 * @param ephemeral enable the user flag --ephemeral during creation 732 * @return id of the created user 733 * @throws DeviceNotAvailableException 734 */ createUser(String name, boolean guest, boolean ephemeral)735 public int createUser(String name, boolean guest, boolean ephemeral) 736 throws DeviceNotAvailableException, IllegalStateException; 737 738 /** 739 * Create a user with a given name and the provided flags 740 * 741 * @param name of the user to create on the device 742 * @param guest enable the user flag --guest during creation 743 * @param ephemeral enable the user flag --ephemeral during creation 744 * @param forTesting enable the test flag --for-testing during creation 745 * @return id of the created user 746 * @throws DeviceNotAvailableException 747 */ createUser(String name, boolean guest, boolean ephemeral, boolean forTesting)748 public int createUser(String name, boolean guest, boolean ephemeral, boolean forTesting) 749 throws DeviceNotAvailableException, IllegalStateException; 750 751 /** 752 * Create a user with a given name and default flags 0. 753 * 754 * @param name of the user to create on the device 755 * @return the integer for the user id created or -1 for error. 756 * @throws DeviceNotAvailableException 757 */ createUserNoThrow(String name)758 public int createUserNoThrow(String name) throws DeviceNotAvailableException; 759 760 /** 761 * Remove a given user from the device. 762 * 763 * @param userId of the user to remove 764 * @return true if we were successful in removing the user, false otherwise. 765 * @throws DeviceNotAvailableException 766 */ removeUser(int userId)767 public boolean removeUser(int userId) throws DeviceNotAvailableException; 768 769 /** 770 * Gets the list of users on the device. Will throw {@link DeviceRuntimeException} if output 771 * from device is not as expected. 772 * 773 * @return the list of user ids. 774 * @throws DeviceNotAvailableException 775 * @throws DeviceRuntimeException 776 */ listUsers()777 ArrayList<Integer> listUsers() throws DeviceNotAvailableException; 778 779 /** 780 * Gets the Map of useId to {@link UserInfo} on the device. Will throw {@link 781 * DeviceRuntimeException} if output from device is not as expected. 782 * 783 * @return the list of UserInfo objects. 784 * @throws DeviceNotAvailableException 785 * @throws DeviceRuntimeException 786 */ getUserInfos()787 public Map<Integer, UserInfo> getUserInfos() throws DeviceNotAvailableException; 788 789 /** 790 * Get the maximum number of supported users. Defaults to 0. 791 * 792 * @return an integer indicating the number of supported users 793 * @throws DeviceNotAvailableException 794 */ getMaxNumberOfUsersSupported()795 public int getMaxNumberOfUsersSupported() throws DeviceNotAvailableException; 796 797 /** 798 * Get the maximum number of supported simultaneously running users. Defaults to 0. 799 * 800 * @return an integer indicating the number of simultaneously running users 801 * @throws DeviceNotAvailableException 802 */ getMaxNumberOfRunningUsersSupported()803 public int getMaxNumberOfRunningUsersSupported() throws DeviceNotAvailableException; 804 805 /** 806 * Starts a given user in the background if it is currently stopped. If the user is already 807 * running in the background, this method is a NOOP. 808 * @param userId of the user to start in the background 809 * @return true if the user was successfully started in the background. 810 * @throws DeviceNotAvailableException 811 */ startUser(int userId)812 public boolean startUser(int userId) throws DeviceNotAvailableException; 813 814 /** 815 * Starts a given user in the background if it is currently stopped. If the user is already 816 * running in the background, this method is a NOOP. Possible to provide extra flag to wait for 817 * the operation to have effect. 818 * 819 * @param userId of the user to start in the background 820 * @param waitFlag will make the command wait until user is started and unlocked. 821 * @return true if the user was successfully started in the background. 822 * @throws DeviceNotAvailableException 823 */ startUser(int userId, boolean waitFlag)824 public boolean startUser(int userId, boolean waitFlag) throws DeviceNotAvailableException; 825 826 /** 827 * Starts a given user in the background, visible in the given display (i.e., allowing the user 828 * to launch activities in that display). 829 * 830 * <p><b>NOTE: </b>this command doesn't check if the user exists, display is available, {@link 831 * #isVisibleBackgroundUsersSupported() device supports such feature}, etc. 832 * 833 * @param userId of the user to start in the background 834 * @param displayId display to start user visible on 835 * @param waitFlag will make the command wait until user is started and unlocked. 836 * @return {@code true} if the user was successfully started visible in the background. 837 */ startVisibleBackgroundUser(int userId, int displayId, boolean waitFlag)838 public boolean startVisibleBackgroundUser(int userId, int displayId, boolean waitFlag) 839 throws DeviceNotAvailableException; 840 841 /** 842 * Stops a given user. If the user is already stopped, this method is a NOOP. 843 * Cannot stop current and system user. 844 * 845 * @param userId of the user to stop. 846 * @return true if the user was successfully stopped. 847 * @throws DeviceNotAvailableException 848 */ stopUser(int userId)849 public boolean stopUser(int userId) throws DeviceNotAvailableException; 850 851 /** 852 * Stop a given user. Possible to provide extra flags to wait for the operation to have effect, 853 * and force terminate the user. Cannot stop current and system user. 854 * 855 * @param userId of the user to stop. 856 * @param waitFlag will make the command wait until user is stopped. 857 * @param forceFlag will force stop the user. 858 * @return true if the user was successfully stopped. 859 * @throws DeviceNotAvailableException 860 */ stopUser(int userId, boolean waitFlag, boolean forceFlag)861 public boolean stopUser(int userId, boolean waitFlag, boolean forceFlag) 862 throws DeviceNotAvailableException; 863 864 /** 865 * Returns whether the device allow users to be started visible in the background. 866 * 867 * <p>If it does, you could call {@link #startVisibleBackgroundUser(int, int, boolean)}, passing 868 * a display returned by {@link #listDisplayIdsForStartingVisibleBackgroundUsers()}. 869 */ isVisibleBackgroundUsersSupported()870 public boolean isVisibleBackgroundUsersSupported() throws DeviceNotAvailableException; 871 872 /** 873 * Returns whether the device allow users to be started visible in the background in the {@link 874 * java.android.view.Display#DEFAULT_DISPLAY}. 875 * 876 * <p>If it does, you could call {@link #startVisibleBackgroundUser(int, int, boolean)}, passing 877 * a display returned by {@link #listDisplayIdsForStartingVisibleBackgroundUsers()} (which 878 * should include {@link java.android.view.Display#DEFAULT_DISPLAY}). 879 */ isVisibleBackgroundUsersOnDefaultDisplaySupported()880 public boolean isVisibleBackgroundUsersOnDefaultDisplaySupported() 881 throws DeviceNotAvailableException; 882 883 /** 884 * Returns the primary user id. 885 * 886 * @return the userId of the primary user if there is one, and null if there is no primary user. 887 * @throws DeviceNotAvailableException 888 * @throws DeviceRuntimeException if the output from the device is not as expected. 889 */ getPrimaryUserId()890 public Integer getPrimaryUserId() throws DeviceNotAvailableException; 891 892 /** 893 * Returns the main user id. 894 * 895 * @return the userId of the main user if there is one, and null if there is no main user. 896 * @throws DeviceNotAvailableException 897 * @throws DeviceRuntimeException if the output from the device is not as expected. 898 */ getMainUserId()899 public Integer getMainUserId() throws DeviceNotAvailableException; 900 901 /** 902 * Return the id of the current running user. In case of error, return -10000. 903 * 904 * @throws DeviceNotAvailableException 905 */ getCurrentUser()906 public int getCurrentUser() throws DeviceNotAvailableException; 907 908 /** 909 * Checks if the given user is visible. 910 * 911 * <p>A "visible" user is a user that is interacting with the "human" user and hence is able to 912 * launch launch activities (typically in the default display). 913 */ isUserVisible(int userId)914 public boolean isUserVisible(int userId) throws DeviceNotAvailableException; 915 916 /** 917 * Checks if the given user is visible in the given display. 918 * 919 * <p>A "visible" user is a user that is interacting with the "human" user and hence is able to 920 * launch launch activities in that display. 921 */ isUserVisibleOnDisplay(int userId, int displayId)922 public boolean isUserVisibleOnDisplay(int userId, int displayId) 923 throws DeviceNotAvailableException; 924 925 /** 926 * Find and return the flags of a given user. 927 * Flags are defined in "android.content.pm.UserInfo" class in Android Open Source Project. 928 * 929 * @return the flags associated with the userId provided if found, -10000 in any other cases. 930 * @throws DeviceNotAvailableException 931 */ getUserFlags(int userId)932 public int getUserFlags(int userId) throws DeviceNotAvailableException; 933 934 /** 935 * Return whether the specified user is a secondary user according to it's flags. 936 * 937 * @return true if the user is secondary, false otherwise. 938 * @throws DeviceNotAvailableException 939 */ isUserSecondary(int userId)940 public boolean isUserSecondary(int userId) throws DeviceNotAvailableException; 941 942 /** 943 * Return the serial number associated to the userId if found, -10000 in any other cases. 944 * 945 * @throws DeviceNotAvailableException 946 */ getUserSerialNumber(int userId)947 public int getUserSerialNumber(int userId) throws DeviceNotAvailableException; 948 949 /** 950 * Switch to another userId with a default timeout. {@link #switchUser(int, long)}. 951 * 952 * @return True if the new userId matches the userId provider. False otherwise. 953 * @throws DeviceNotAvailableException 954 */ switchUser(int userId)955 public boolean switchUser(int userId) throws DeviceNotAvailableException; 956 957 /** 958 * Switch to another userId with the provided timeout as deadline. 959 * Attempt to disable keyguard after user change is successful. 960 * 961 * @param timeout to wait before returning false for switch-user failed. 962 * @return True if the new userId matches the userId provider. False otherwise. 963 * @throws DeviceNotAvailableException 964 */ switchUser(int userId, long timeout)965 public boolean switchUser(int userId, long timeout) throws DeviceNotAvailableException; 966 967 /** 968 * Check if a given user is running. 969 * 970 * @return True if the user is running, false in every other cases. 971 * @throws DeviceNotAvailableException 972 */ isUserRunning(int userId)973 public boolean isUserRunning(int userId) throws DeviceNotAvailableException; 974 975 /** 976 * Check if a feature is available on a device. 977 * 978 * @param feature which format should be "feature:<name>" or "<name>" directly. 979 * @return True if feature is found, false otherwise. 980 * @throws DeviceNotAvailableException 981 */ hasFeature(String feature)982 public boolean hasFeature(String feature) throws DeviceNotAvailableException; 983 984 /** 985 * See {@link #getSetting(int, String, String)} and performed on system user. 986 * 987 * @throws DeviceNotAvailableException 988 */ getSetting(String namespace, String key)989 public String getSetting(String namespace, String key) throws DeviceNotAvailableException; 990 991 /** 992 * Return the value of the requested setting. 993 * namespace must be one of: {"system", "secure", "global"} 994 * 995 * @return the value associated with the namespace:key of a user. Null if not found. 996 * @throws DeviceNotAvailableException 997 */ getSetting(int userId, String namespace, String key)998 public String getSetting(int userId, String namespace, String key) 999 throws DeviceNotAvailableException; 1000 1001 /** 1002 * Return key value pairs of requested namespace. 1003 * 1004 * @param namespace must be one of {"system", "secure", "global"} 1005 * @return the map of key value pairs. Null if namespace is not supported. 1006 * @throws DeviceNotAvailableException 1007 */ getAllSettings(String namespace)1008 public Map<String, String> getAllSettings(String namespace) throws DeviceNotAvailableException; 1009 1010 /** 1011 * See {@link #setSetting(int, String, String, String)} and performed on system user. 1012 * 1013 * @throws DeviceNotAvailableException 1014 */ setSetting(String namespace, String key, String value)1015 public void setSetting(String namespace, String key, String value) 1016 throws DeviceNotAvailableException; 1017 1018 /** 1019 * Add a setting value to the namespace of a given user. Some settings will only be available 1020 * after a reboot. 1021 * namespace must be one of: {"system", "secure", "global"} 1022 * 1023 * @throws DeviceNotAvailableException 1024 */ setSetting(int userId, String namespace, String key, String value)1025 public void setSetting(int userId, String namespace, String key, String value) 1026 throws DeviceNotAvailableException; 1027 1028 /** 1029 * Find and return the android-id associated to a userId, null if not found. 1030 * 1031 * @throws DeviceNotAvailableException 1032 */ getAndroidId(int userId)1033 public String getAndroidId(int userId) throws DeviceNotAvailableException; 1034 1035 /** 1036 * Create a Map of android ids found matching user ids. There is no insurance that each user 1037 * id will found an android id associated in this function so some user ids may match null. 1038 * 1039 * @return Map of android ids found matching user ids. 1040 * @throws DeviceNotAvailableException 1041 */ getAndroidIds()1042 public Map<Integer, String> getAndroidIds() throws DeviceNotAvailableException; 1043 1044 /** 1045 * Set a device admin component as device owner in given user. 1046 * 1047 * @param componentName of device admin to be device owner. 1048 * @param userId of the user that the device owner lives in. 1049 * @return True if it is successful, false otherwise. 1050 * @throws DeviceNotAvailableException 1051 */ setDeviceOwner(String componentName, int userId)1052 public boolean setDeviceOwner(String componentName, int userId) 1053 throws DeviceNotAvailableException; 1054 1055 /** 1056 * Remove given device admin in given user and return {@code true} if it is successful, {@code 1057 * false} otherwise. 1058 * 1059 * @param componentName of device admin to be removed. 1060 * @param userId of user that the device admin lives in. 1061 * @return True if it is successful, false otherwise. 1062 * @throws DeviceNotAvailableException 1063 */ removeAdmin(String componentName, int userId)1064 public boolean removeAdmin(String componentName, int userId) throws DeviceNotAvailableException; 1065 1066 /** 1067 * Remove all existing device profile owners with the best effort. 1068 * 1069 * @throws DeviceNotAvailableException 1070 */ removeOwners()1071 public void removeOwners() throws DeviceNotAvailableException; 1072 1073 /** 1074 * Attempts to disable the keyguard. 1075 * <p> 1076 * First wait for the input dispatch to become ready, this happens around the same time when the 1077 * device reports BOOT_COMPLETE, apparently asynchronously, because current framework 1078 * implementation has occasional race condition. Then command is sent to dismiss keyguard (works 1079 * on non-secure ones only) 1080 */ disableKeyguard()1081 public void disableKeyguard() throws DeviceNotAvailableException; 1082 1083 /** 1084 * Attempt to dump the heap from the system_server. It is the caller responsibility to clean up 1085 * the dumped file. 1086 * 1087 * @param process the name of the device process to dumpheap on. 1088 * @param devicePath the path on the device where to put the dump. This must be a location where 1089 * permissions allow it. 1090 * @return the {@link File} containing the report. Null if something failed. 1091 * @throws DeviceNotAvailableException 1092 */ dumpHeap(String process, String devicePath)1093 public File dumpHeap(String process, String devicePath) throws DeviceNotAvailableException; 1094 1095 /** 1096 * Collect the list of available displays id on the device as reported by "dumpsys 1097 * SurfaceFlinger". 1098 * 1099 * @return The list of displays. Default always returns the default display 0. 1100 * @throws DeviceNotAvailableException 1101 */ listDisplayIds()1102 public Set<Long> listDisplayIds() throws DeviceNotAvailableException; 1103 1104 /** 1105 * Gets the list of displays that can be used to {@link #startVisibleBackgroundUser(int, int, 1106 * boolean) start a user visible in the background}. 1107 */ listDisplayIdsForStartingVisibleBackgroundUsers()1108 public Set<Integer> listDisplayIdsForStartingVisibleBackgroundUsers() 1109 throws DeviceNotAvailableException; 1110 1111 /** 1112 * Returns the list of foldable states on the device. Can be obtained with "cmd device_state 1113 * print-states". 1114 * 1115 * @throws DeviceNotAvailableException 1116 */ getFoldableStates()1117 public Set<DeviceFoldableState> getFoldableStates() throws DeviceNotAvailableException; 1118 1119 /** 1120 * Returns the current foldable state of the device or null if some issues occurred. 1121 * 1122 * @throws DeviceNotAvailableException 1123 */ getCurrentFoldableState()1124 public DeviceFoldableState getCurrentFoldableState() throws DeviceNotAvailableException; 1125 1126 /** 1127 * Helper method to determine if file on device exists for a given user. 1128 * 1129 * @param deviceFilePath the absolute path of file on device to check 1130 * @param userId The user id against which to check file existence 1131 * @return <code>true</code> if file exists, <code>false</code> otherwise. 1132 * @throws DeviceNotAvailableException if connection with device is lost and cannot be 1133 * recovered. 1134 */ doesFileExist(String deviceFilePath, int userId)1135 public boolean doesFileExist(String deviceFilePath, int userId) 1136 throws DeviceNotAvailableException; 1137 1138 /** 1139 * Registers a {@link IDeviceActionReceiver} for this device. 1140 * 1141 * <p>All registered {@link IDeviceActionReceiver}s will be notified before a device action 1142 * starts and after the device action ends. 1143 * 1144 * @param deviceActionReceiver A {@link IDeviceActionReceiver} which will be registered. 1145 */ registerDeviceActionReceiver(IDeviceActionReceiver deviceActionReceiver)1146 public void registerDeviceActionReceiver(IDeviceActionReceiver deviceActionReceiver); 1147 1148 /** 1149 * Removes the registered {@link IDeviceActionReceiver}. 1150 * 1151 * @param deviceActionReceiver A {@link IDeviceActionReceiver} which will be removed. 1152 */ deregisterDeviceActionReceiver(IDeviceActionReceiver deviceActionReceiver)1153 public void deregisterDeviceActionReceiver(IDeviceActionReceiver deviceActionReceiver); 1154 1155 /** 1156 * Retrieves a bugreport from the device. 1157 * 1158 * <p>The implementation of this is guaranteed to continue to work on a device without an sdcard 1159 * (or where the sdcard is not yet mounted). 1160 * 1161 * @return An {@link InputStreamSource} which will produce the bugreport contents on demand. In 1162 * case of failure, the {@code InputStreamSource} will produce an empty {@link InputStream}. 1163 */ getBugreport()1164 public InputStreamSource getBugreport(); 1165 1166 /** 1167 * Retrieves a bugreportz from the device. Zip format bugreport contains the main bugreport and 1168 * other log files that are useful for debugging. 1169 * 1170 * <p>Only supported for 'adb version' > 1.0.36 1171 * 1172 * @return a {@link InputStreamSource} of the zip file containing the bugreportz, return null in 1173 * case of failure. 1174 */ getBugreportz()1175 public InputStreamSource getBugreportz(); 1176 1177 /** 1178 * Helper method to take a bugreport and log it to the reporters. 1179 * 1180 * @param dataName name under which the bugreport will be reported. 1181 * @param listener an {@link ITestLogger} to log the bugreport. 1182 * @return True if the logging was successful, false otherwise. 1183 */ logBugreport(String dataName, ITestLogger listener)1184 public boolean logBugreport(String dataName, ITestLogger listener); 1185 1186 /** 1187 * Take a bugreport and returns it inside a {@link Bugreport} object to handle it. Return null 1188 * in case of issue. File referenced in the Bugreport object need to be cleaned via {@link 1189 * Bugreport#close()}. 1190 */ takeBugreport()1191 public Bugreport takeBugreport(); 1192 1193 /** Notify the device to wait for snapuserd completion. */ notifySnapuserd(SnapuserdWaitPhase waitPhase)1194 public default void notifySnapuserd(SnapuserdWaitPhase waitPhase) { 1195 // Empty on purpose 1196 } 1197 1198 /** If expected, wait for snapuserd to complete. */ waitForSnapuserd(SnapuserdWaitPhase currentPhase)1199 public default void waitForSnapuserd(SnapuserdWaitPhase currentPhase) 1200 throws DeviceNotAvailableException { 1201 // Empty on purpose 1202 } 1203 } 1204