1 /* 2 * Copyright (C) 2015 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.hardware.usb; 18 19 import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL; 20 import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_NOT_SUPPORTED; 21 import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_PORT_MISMATCH; 22 import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS; 23 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DETECTED; 24 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DISABLED; 25 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED; 26 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED; 27 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE; 28 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST; 29 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE; 30 import static android.hardware.usb.UsbPortStatus.MODE_AUDIO_ACCESSORY; 31 import static android.hardware.usb.UsbPortStatus.MODE_DEBUG_ACCESSORY; 32 import static android.hardware.usb.UsbPortStatus.MODE_DFP; 33 import static android.hardware.usb.UsbPortStatus.MODE_DUAL; 34 import static android.hardware.usb.UsbPortStatus.MODE_NONE; 35 import static android.hardware.usb.UsbPortStatus.MODE_UFP; 36 import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_DISCONNECTED; 37 import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN; 38 import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_CONNECTED; 39 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE; 40 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; 41 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE; 42 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_UNKNOWN; 43 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_ENABLED; 44 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_OVERHEAT; 45 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_CONTAMINANT; 46 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DOCK; 47 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE; 48 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DEBUG; 49 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DOCK_HOST_MODE; 50 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DOCK_DEVICE_MODE; 51 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY; 52 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_BC_1_2; 53 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP; 54 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_OTHER; 55 import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN; 56 import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE; 57 import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED; 58 import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_ENABLED; 59 60 import android.Manifest; 61 import android.annotation.CallbackExecutor; 62 import android.annotation.CheckResult; 63 import android.annotation.IntDef; 64 import android.annotation.NonNull; 65 import android.annotation.Nullable; 66 import android.annotation.RequiresPermission; 67 import android.annotation.SystemApi; 68 import android.hardware.usb.UsbOperationInternal; 69 import android.hardware.usb.V1_0.Constants; 70 import android.os.Binder; 71 import android.util.Log; 72 73 import com.android.internal.util.Preconditions; 74 75 import java.lang.annotation.Retention; 76 import java.lang.annotation.RetentionPolicy; 77 import java.util.Objects; 78 import java.util.concurrent.atomic.AtomicInteger; 79 import java.util.concurrent.Executor; 80 import java.util.function.Consumer; 81 82 /** 83 * Represents a physical USB port and describes its characteristics. 84 * 85 * @hide 86 */ 87 @SystemApi 88 public final class UsbPort { 89 private static final String TAG = "UsbPort"; 90 private final String mId; 91 private final int mSupportedModes; 92 private final UsbManager mUsbManager; 93 private final int mSupportedContaminantProtectionModes; 94 private final boolean mSupportsEnableContaminantPresenceProtection; 95 private final boolean mSupportsEnableContaminantPresenceDetection; 96 private final boolean mSupportsComplianceWarnings; 97 private final @AltModeType int mSupportedAltModes; 98 99 private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES; 100 /** 101 * Points to the first power role in the IUsb HAL. 102 */ 103 private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE; 104 105 /** 106 * Counter for tracking UsbOperation operations. 107 */ 108 private static final AtomicInteger sUsbOperationCount = new AtomicInteger(); 109 110 /** 111 * The {@link #enableUsbData} request was successfully completed. 112 */ 113 public static final int ENABLE_USB_DATA_SUCCESS = 0; 114 115 /** 116 * The {@link #enableUsbData} request failed due to internal error. 117 */ 118 public static final int ENABLE_USB_DATA_ERROR_INTERNAL = 1; 119 120 /** 121 * The {@link #enableUsbData} request failed as it's not supported. 122 */ 123 public static final int ENABLE_USB_DATA_ERROR_NOT_SUPPORTED = 2; 124 125 /** 126 * The {@link #enableUsbData} request failed as port id mismatched. 127 */ 128 public static final int ENABLE_USB_DATA_ERROR_PORT_MISMATCH = 3; 129 130 /** 131 * The {@link #enableUsbData} request failed due to other reasons. 132 */ 133 public static final int ENABLE_USB_DATA_ERROR_OTHER = 4; 134 135 /** @hide */ 136 @IntDef(prefix = { "ENABLE_USB_DATA_" }, value = { 137 ENABLE_USB_DATA_SUCCESS, 138 ENABLE_USB_DATA_ERROR_INTERNAL, 139 ENABLE_USB_DATA_ERROR_NOT_SUPPORTED, 140 ENABLE_USB_DATA_ERROR_PORT_MISMATCH, 141 ENABLE_USB_DATA_ERROR_OTHER 142 }) 143 @Retention(RetentionPolicy.SOURCE) 144 @interface EnableUsbDataStatus{} 145 146 /** 147 * The {@link #enableLimitPowerTransfer} request was successfully completed. 148 */ 149 public static final int ENABLE_LIMIT_POWER_TRANSFER_SUCCESS = 0; 150 151 /** 152 * The {@link #enableLimitPowerTransfer} request failed due to internal error. 153 */ 154 public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL = 1; 155 156 /** 157 * The {@link #enableLimitPowerTransfer} request failed as it's not supported. 158 */ 159 public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED = 2; 160 161 /** 162 * The {@link #enableLimitPowerTransfer} request failed as port id mismatched. 163 */ 164 public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH = 3; 165 166 /** 167 * The {@link #enableLimitPowerTransfer} request failed due to other reasons. 168 */ 169 public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER = 4; 170 171 /** @hide */ 172 @IntDef(prefix = { "ENABLE_LIMIT_POWER_TRANSFER_" }, value = { 173 ENABLE_LIMIT_POWER_TRANSFER_SUCCESS, 174 ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL, 175 ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED, 176 ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH, 177 ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER 178 }) 179 @Retention(RetentionPolicy.SOURCE) 180 @interface EnableLimitPowerTransferStatus{} 181 182 /** 183 * The {@link #enableUsbDataWhileDocked} request was successfully completed. 184 */ 185 public static final int ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS = 0; 186 187 /** 188 * The {@link #enableUsbDataWhileDocked} request failed due to internal error. 189 */ 190 public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL = 1; 191 192 /** 193 * The {@link #enableUsbDataWhileDocked} request failed as it's not supported. 194 */ 195 public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED = 2; 196 197 /** 198 * The {@link #enableUsbDataWhileDocked} request failed as port id mismatched. 199 */ 200 public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH = 3; 201 202 /** 203 * The {@link #enableUsbDataWhileDocked} request failed as data is still enabled. 204 */ 205 public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED = 4; 206 207 /** 208 * The {@link #enableUsbDataWhileDocked} request failed due to other reasons. 209 */ 210 public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER = 5; 211 212 /** 213 * The {@link #resetUsbPort} request was successfully completed. 214 */ 215 public static final int RESET_USB_PORT_SUCCESS = 0; 216 217 /** 218 * The {@link #resetUsbPort} request failed due to internal error. 219 */ 220 public static final int RESET_USB_PORT_ERROR_INTERNAL = 1; 221 222 /** 223 * The {@link #resetUsbPort} request failed as it's not supported. 224 */ 225 public static final int RESET_USB_PORT_ERROR_NOT_SUPPORTED = 2; 226 227 /** 228 * The {@link #resetUsbPort} request failed as port id mismatched. 229 */ 230 public static final int RESET_USB_PORT_ERROR_PORT_MISMATCH = 3; 231 232 /** 233 * The {@link #resetUsbPort} request failed due to other reasons. 234 */ 235 public static final int RESET_USB_PORT_ERROR_OTHER = 4; 236 237 /** @hide */ 238 @IntDef(prefix = { "RESET_USB_PORT_" }, value = { 239 RESET_USB_PORT_SUCCESS, 240 RESET_USB_PORT_ERROR_INTERNAL, 241 RESET_USB_PORT_ERROR_NOT_SUPPORTED, 242 RESET_USB_PORT_ERROR_PORT_MISMATCH, 243 RESET_USB_PORT_ERROR_OTHER 244 }) 245 @Retention(RetentionPolicy.SOURCE) 246 @interface ResetUsbPortStatus{} 247 248 /** @hide */ 249 @IntDef(prefix = { "ENABLE_USB_DATA_WHILE_DOCKED_" }, value = { 250 ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS, 251 ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL, 252 ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED, 253 ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH, 254 ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED, 255 ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER 256 }) 257 @Retention(RetentionPolicy.SOURCE) 258 @interface EnableUsbDataWhileDockedStatus{} 259 260 /** 261 * Indicates that the Alt Mode being described is DisplayPort. 262 */ 263 public static final int FLAG_ALT_MODE_TYPE_DISPLAYPORT = 1 << 0; 264 265 /** @hide */ 266 @IntDef(prefix = { "FLAG_ALT_MODE_TYPE_" }, flag = true, value = { 267 FLAG_ALT_MODE_TYPE_DISPLAYPORT, 268 }) 269 @Retention(RetentionPolicy.SOURCE) 270 public @interface AltModeType {} 271 272 /** @hide */ UsbPort(@onNull UsbManager usbManager, @NonNull String id, int supportedModes, int supportedContaminantProtectionModes, boolean supportsEnableContaminantPresenceProtection, boolean supportsEnableContaminantPresenceDetection)273 public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes, 274 int supportedContaminantProtectionModes, 275 boolean supportsEnableContaminantPresenceProtection, 276 boolean supportsEnableContaminantPresenceDetection) { 277 this(usbManager, id, supportedModes, supportedContaminantProtectionModes, 278 supportsEnableContaminantPresenceProtection, 279 supportsEnableContaminantPresenceDetection, 280 false, 0); 281 } 282 283 /** @hide */ UsbPort(@onNull UsbManager usbManager, @NonNull String id, int supportedModes, int supportedContaminantProtectionModes, boolean supportsEnableContaminantPresenceProtection, boolean supportsEnableContaminantPresenceDetection, boolean supportsComplianceWarnings, int supportedAltModes)284 public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes, 285 int supportedContaminantProtectionModes, 286 boolean supportsEnableContaminantPresenceProtection, 287 boolean supportsEnableContaminantPresenceDetection, 288 boolean supportsComplianceWarnings, 289 int supportedAltModes) { 290 Objects.requireNonNull(id); 291 Preconditions.checkFlagsArgument(supportedModes, 292 MODE_DFP | MODE_UFP | MODE_AUDIO_ACCESSORY | MODE_DEBUG_ACCESSORY); 293 294 mUsbManager = usbManager; 295 mId = id; 296 mSupportedModes = supportedModes; 297 mSupportedContaminantProtectionModes = supportedContaminantProtectionModes; 298 mSupportsEnableContaminantPresenceProtection = 299 supportsEnableContaminantPresenceProtection; 300 mSupportsEnableContaminantPresenceDetection = 301 supportsEnableContaminantPresenceDetection; 302 mSupportsComplianceWarnings = supportsComplianceWarnings; 303 mSupportedAltModes = supportedAltModes; 304 } 305 306 /** 307 * Gets the unique id of the port. 308 * 309 * @return The unique id of the port; not intended for display. 310 * 311 * @hide 312 */ getId()313 public String getId() { 314 return mId; 315 } 316 317 /** 318 * Gets the supported modes of the port. 319 * <p> 320 * The actual mode of the port may vary depending on what is plugged into it. 321 * </p> 322 * 323 * @return The supported modes: one of {@link UsbPortStatus#MODE_DFP}, 324 * {@link UsbPortStatus#MODE_UFP}, or {@link UsbPortStatus#MODE_DUAL}. 325 * 326 * @hide 327 */ getSupportedModes()328 public int getSupportedModes() { 329 return mSupportedModes; 330 } 331 332 /** 333 * Gets the supported port proctection modes when the port is contaminated. 334 * <p> 335 * The actual mode of the port is decided by the hardware 336 * </p> 337 * 338 * @hide 339 */ getSupportedContaminantProtectionModes()340 public int getSupportedContaminantProtectionModes() { 341 return mSupportedContaminantProtectionModes; 342 } 343 344 /** 345 * Tells if UsbService can enable/disable contaminant presence protection. 346 * 347 * @hide 348 */ supportsEnableContaminantPresenceProtection()349 public boolean supportsEnableContaminantPresenceProtection() { 350 return mSupportsEnableContaminantPresenceProtection; 351 } 352 353 /** 354 * Tells if UsbService can enable/disable contaminant presence detection. 355 * 356 * @hide 357 */ supportsEnableContaminantPresenceDetection()358 public boolean supportsEnableContaminantPresenceDetection() { 359 return mSupportsEnableContaminantPresenceDetection; 360 } 361 362 /** 363 * Gets the status of this USB port. 364 * 365 * @return The status of the this port, or {@code null} if port is unknown. 366 */ 367 @RequiresPermission(Manifest.permission.MANAGE_USB) getStatus()368 public @Nullable UsbPortStatus getStatus() { 369 return mUsbManager.getPortStatus(this); 370 } 371 372 /** 373 * Queries USB Port to see if the port is capable of identifying 374 * non compliant USB power source/cable/accessory. 375 * 376 * @return true when the UsbPort is capable of identifying 377 * non compliant USB power 378 * source/cable/accessory. 379 * @return false otherwise. 380 */ 381 @CheckResult 382 @RequiresPermission(Manifest.permission.MANAGE_USB) supportsComplianceWarnings()383 public boolean supportsComplianceWarnings() { 384 return mSupportsComplianceWarnings; 385 } 386 387 /** 388 * Returns all Alt Modes supported by the port. 389 * 390 * @hide 391 */ getSupportedAltModesMask()392 public @AltModeType int getSupportedAltModesMask() { 393 return mSupportedAltModes; 394 } 395 396 /** 397 * Returns whether all Alt Mode types in a given mask are supported 398 * by the port. 399 * 400 * @return true if all given Alt Modes are supported, false otherwise. 401 * 402 */ isAltModeSupported(@ltModeType int typeMask)403 public boolean isAltModeSupported(@AltModeType int typeMask) { 404 return (mSupportedAltModes & typeMask) == typeMask; 405 } 406 407 408 /** 409 * Sets the desired role combination of the port. 410 * <p> 411 * The supported role combinations depend on what is connected to the port and may be 412 * determined by consulting 413 * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}. 414 * </p><p> 415 * Note: This function is asynchronous and may fail silently without applying 416 * the operationed changes. If this function does cause a status change to occur then 417 * a {@link UsbManager#ACTION_USB_PORT_CHANGED} broadcast will be sent. 418 * </p> 419 * 420 * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE} or 421 * {@link UsbPortStatus#POWER_ROLE_SINK}, or 422 * {@link UsbPortStatus#POWER_ROLE_NONE} if no power role. 423 * @param dataRole The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST} or 424 * {@link UsbPortStatus#DATA_ROLE_DEVICE}, or 425 * {@link UsbPortStatus#DATA_ROLE_NONE} if no data role. 426 */ 427 @RequiresPermission(Manifest.permission.MANAGE_USB) setRoles(@sbPortStatus.UsbPowerRole int powerRole, @UsbPortStatus.UsbDataRole int dataRole)428 public void setRoles(@UsbPortStatus.UsbPowerRole int powerRole, 429 @UsbPortStatus.UsbDataRole int dataRole) { 430 UsbPort.checkRoles(powerRole, dataRole); 431 432 mUsbManager.setPortRoles(this, powerRole, dataRole); 433 } 434 435 /** 436 * Reset Usb data on the port. 437 * 438 * @param executor Executor for the callback. 439 * @param consumer A consumer that consumes the reset result. 440 * {@link #RESET_USB_PORT_SUCCESS} when request completes 441 * successfully or 442 * {@link #RESET_USB_PORT_ERROR_INTERNAL} when request 443 * fails due to internal error or 444 * {@link RESET_USB_PORT_ERROR_NOT_SUPPORTED} when not 445 * supported or 446 * {@link RESET_USB_PORT_ERROR_PORT_MISMATCH} when request 447 * fails due to port id mismatch or 448 * {@link RESET_USB_PORT_ERROR_OTHER} when fails due to 449 * other reasons. 450 */ 451 @CheckResult 452 @RequiresPermission(Manifest.permission.MANAGE_USB) resetUsbPort(@onNull @allbackExecutor Executor executor, @NonNull @ResetUsbPortStatus Consumer<Integer> consumer)453 public void resetUsbPort(@NonNull @CallbackExecutor Executor executor, 454 @NonNull @ResetUsbPortStatus Consumer<Integer> consumer) { 455 // UID is added To minimize operationID overlap between two different packages. 456 int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid(); 457 Log.i(TAG, "resetUsbPort opId:" + operationId); 458 UsbOperationInternal opCallback = 459 new UsbOperationInternal(operationId, mId, executor, consumer); 460 mUsbManager.resetUsbPort(this, operationId, opCallback); 461 } 462 463 /** 464 * Enables/Disables Usb data on the port. 465 * 466 * @param enable When true enables USB data if disabled. 467 * When false disables USB data if enabled. 468 * @return {@link #ENABLE_USB_DATA_SUCCESS} when request completes successfully or 469 * {@link #ENABLE_USB_DATA_ERROR_INTERNAL} when request fails due to internal 470 * error or 471 * {@link ENABLE_USB_DATA_ERROR_NOT_SUPPORTED} when not supported or 472 * {@link ENABLE_USB_DATA_ERROR_PORT_MISMATCH} when request fails due to port id 473 * mismatch or 474 * {@link ENABLE_USB_DATA_ERROR_OTHER} when fails due to other reasons. 475 */ 476 @CheckResult 477 @RequiresPermission(Manifest.permission.MANAGE_USB) enableUsbData(boolean enable)478 public @EnableUsbDataStatus int enableUsbData(boolean enable) { 479 // UID is added To minimize operationID overlap between two different packages. 480 int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid(); 481 Log.i(TAG, "enableUsbData opId:" + operationId 482 + " callingUid:" + Binder.getCallingUid()); 483 UsbOperationInternal opCallback = 484 new UsbOperationInternal(operationId, mId); 485 if (mUsbManager.enableUsbData(this, enable, operationId, opCallback) == true) { 486 opCallback.waitForOperationComplete(); 487 } 488 489 int result = opCallback.getStatus(); 490 switch (result) { 491 case USB_OPERATION_SUCCESS: 492 return ENABLE_USB_DATA_SUCCESS; 493 case USB_OPERATION_ERROR_INTERNAL: 494 return ENABLE_USB_DATA_ERROR_INTERNAL; 495 case USB_OPERATION_ERROR_NOT_SUPPORTED: 496 return ENABLE_USB_DATA_ERROR_NOT_SUPPORTED; 497 case USB_OPERATION_ERROR_PORT_MISMATCH: 498 return ENABLE_USB_DATA_ERROR_PORT_MISMATCH; 499 default: 500 return ENABLE_USB_DATA_ERROR_OTHER; 501 } 502 } 503 504 /** 505 * Enables Usb data when disabled due to {@link UsbPort#DATA_STATUS_DISABLED_DOCK} 506 * 507 * @return {@link #ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS} when request completes successfully or 508 * {@link #ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL} when request fails due to 509 * internal error or 510 * {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED} when not supported or 511 * {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH} when request fails due to 512 * port id mismatch or 513 * {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED} when request fails as data 514 * is still enabled or 515 * {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER} when fails due to other reasons. 516 */ 517 @CheckResult 518 @RequiresPermission(Manifest.permission.MANAGE_USB) enableUsbDataWhileDocked()519 public @EnableUsbDataWhileDockedStatus int enableUsbDataWhileDocked() { 520 // UID is added To minimize operationID overlap between two different packages. 521 int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid(); 522 Log.i(TAG, "enableUsbData opId:" + operationId 523 + " callingUid:" + Binder.getCallingUid()); 524 UsbPortStatus portStatus = getStatus(); 525 if (portStatus != null && 526 (portStatus.getUsbDataStatus() & DATA_STATUS_DISABLED_DOCK) != 527 DATA_STATUS_DISABLED_DOCK) { 528 return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED; 529 } 530 531 UsbOperationInternal opCallback = 532 new UsbOperationInternal(operationId, mId); 533 mUsbManager.enableUsbDataWhileDocked(this, operationId, opCallback); 534 opCallback.waitForOperationComplete(); 535 int result = opCallback.getStatus(); 536 switch (result) { 537 case USB_OPERATION_SUCCESS: 538 return ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS; 539 case USB_OPERATION_ERROR_INTERNAL: 540 return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL; 541 case USB_OPERATION_ERROR_NOT_SUPPORTED: 542 return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED; 543 case USB_OPERATION_ERROR_PORT_MISMATCH: 544 return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH; 545 default: 546 return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER; 547 } 548 } 549 550 /** 551 * Limits power transfer In and out of the port. 552 * <p> 553 * Disables charging and limits sourcing power(when permitted by the USB spec) until 554 * port disconnect event. 555 * </p> 556 * @param enable limits power transfer when true. 557 * @return {@link #ENABLE_LIMIT_POWER_TRANSFER_SUCCESS} when request completes successfully or 558 * {@link #ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL} when request fails due to 559 * internal error or 560 * {@link ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED} when not supported or 561 * {@link ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH} when request fails due to 562 * port id mismatch or 563 * {@link ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER} when fails due to other reasons. 564 */ 565 @CheckResult 566 @RequiresPermission(Manifest.permission.MANAGE_USB) enableLimitPowerTransfer(boolean enable)567 public @EnableLimitPowerTransferStatus int enableLimitPowerTransfer(boolean enable) { 568 // UID is added To minimize operationID overlap between two different packages. 569 int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid(); 570 Log.i(TAG, "enableLimitPowerTransfer opId:" + operationId 571 + " callingUid:" + Binder.getCallingUid()); 572 UsbOperationInternal opCallback = 573 new UsbOperationInternal(operationId, mId); 574 mUsbManager.enableLimitPowerTransfer(this, enable, operationId, opCallback); 575 opCallback.waitForOperationComplete(); 576 int result = opCallback.getStatus(); 577 switch (result) { 578 case USB_OPERATION_SUCCESS: 579 return ENABLE_LIMIT_POWER_TRANSFER_SUCCESS; 580 case USB_OPERATION_ERROR_INTERNAL: 581 return ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL; 582 case USB_OPERATION_ERROR_NOT_SUPPORTED: 583 return ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED; 584 case USB_OPERATION_ERROR_PORT_MISMATCH: 585 return ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH; 586 default: 587 return ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER; 588 } 589 } 590 591 /** 592 * @hide 593 **/ enableContaminantDetection(boolean enable)594 public void enableContaminantDetection(boolean enable) { 595 mUsbManager.enableContaminantDetection(this, enable); 596 } 597 /** 598 * Combines one power and one data role together into a unique value with 599 * exactly one bit set. This can be used to efficiently determine whether 600 * a combination of roles is supported by testing whether that bit is present 601 * in a bit-field. 602 * 603 * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE} 604 * or {@link UsbPortStatus#POWER_ROLE_SINK}, or 0 if no power role. 605 * @param dataRole The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST} 606 * or {@link UsbPortStatus#DATA_ROLE_DEVICE}, or 0 if no data role. 607 * @hide 608 */ combineRolesAsBit(int powerRole, int dataRole)609 public static int combineRolesAsBit(int powerRole, int dataRole) { 610 checkRoles(powerRole, dataRole); 611 final int index = ((powerRole - POWER_ROLE_OFFSET) * NUM_DATA_ROLES) + dataRole; 612 return 1 << index; 613 } 614 615 /** @hide */ modeToString(int mode)616 public static String modeToString(int mode) { 617 StringBuilder modeString = new StringBuilder(); 618 if (mode == MODE_NONE) { 619 return "none"; 620 } 621 622 if ((mode & MODE_DUAL) == MODE_DUAL) { 623 modeString.append("dual, "); 624 } else { 625 if ((mode & MODE_DFP) == MODE_DFP) { 626 modeString.append("dfp, "); 627 } else if ((mode & MODE_UFP) == MODE_UFP) { 628 modeString.append("ufp, "); 629 } 630 } 631 if ((mode & MODE_AUDIO_ACCESSORY) == MODE_AUDIO_ACCESSORY) { 632 modeString.append("audio_acc, "); 633 } 634 if ((mode & MODE_DEBUG_ACCESSORY) == MODE_DEBUG_ACCESSORY) { 635 modeString.append("debug_acc, "); 636 } 637 638 if (modeString.length() == 0) { 639 return Integer.toString(mode); 640 } 641 return modeString.substring(0, modeString.length() - 2); 642 } 643 644 /** @hide */ powerRoleToString(int role)645 public static String powerRoleToString(int role) { 646 switch (role) { 647 case POWER_ROLE_NONE: 648 return "no-power"; 649 case POWER_ROLE_SOURCE: 650 return "source"; 651 case POWER_ROLE_SINK: 652 return "sink"; 653 default: 654 return Integer.toString(role); 655 } 656 } 657 658 /** @hide */ dataRoleToString(int role)659 public static String dataRoleToString(int role) { 660 switch (role) { 661 case DATA_ROLE_NONE: 662 return "no-data"; 663 case DATA_ROLE_HOST: 664 return "host"; 665 case DATA_ROLE_DEVICE: 666 return "device"; 667 default: 668 return Integer.toString(role); 669 } 670 } 671 672 /** @hide */ contaminantPresenceStatusToString(int contaminantPresenceStatus)673 public static String contaminantPresenceStatusToString(int contaminantPresenceStatus) { 674 switch (contaminantPresenceStatus) { 675 case CONTAMINANT_DETECTION_NOT_SUPPORTED: 676 return "not-supported"; 677 case CONTAMINANT_DETECTION_DISABLED: 678 return "disabled"; 679 case CONTAMINANT_DETECTION_DETECTED: 680 return "detected"; 681 case CONTAMINANT_DETECTION_NOT_DETECTED: 682 return "not detected"; 683 default: 684 return Integer.toString(contaminantPresenceStatus); 685 } 686 } 687 688 /** @hide */ usbDataStatusToString(int usbDataStatus)689 public static String usbDataStatusToString(int usbDataStatus) { 690 StringBuilder statusString = new StringBuilder(); 691 692 if (usbDataStatus == DATA_STATUS_UNKNOWN) { 693 return "unknown"; 694 } 695 696 if ((usbDataStatus & DATA_STATUS_ENABLED) == DATA_STATUS_ENABLED) { 697 return "enabled"; 698 } 699 700 if ((usbDataStatus & DATA_STATUS_DISABLED_OVERHEAT) == DATA_STATUS_DISABLED_OVERHEAT) { 701 statusString.append("disabled-overheat, "); 702 } 703 704 if ((usbDataStatus & DATA_STATUS_DISABLED_CONTAMINANT) 705 == DATA_STATUS_DISABLED_CONTAMINANT) { 706 statusString.append("disabled-contaminant, "); 707 } 708 709 if ((usbDataStatus & DATA_STATUS_DISABLED_DOCK) == DATA_STATUS_DISABLED_DOCK) { 710 statusString.append("disabled-dock, "); 711 } 712 713 if ((usbDataStatus & DATA_STATUS_DISABLED_FORCE) == DATA_STATUS_DISABLED_FORCE) { 714 statusString.append("disabled-force, "); 715 } 716 717 if ((usbDataStatus & DATA_STATUS_DISABLED_DEBUG) == DATA_STATUS_DISABLED_DEBUG) { 718 statusString.append("disabled-debug, "); 719 } 720 721 if ((usbDataStatus & DATA_STATUS_DISABLED_DOCK_HOST_MODE) == 722 DATA_STATUS_DISABLED_DOCK_HOST_MODE) { 723 statusString.append("disabled-host-dock, "); 724 } 725 726 if ((usbDataStatus & DATA_STATUS_DISABLED_DOCK_DEVICE_MODE) == 727 DATA_STATUS_DISABLED_DOCK_DEVICE_MODE) { 728 statusString.append("disabled-device-dock, "); 729 } 730 return statusString.toString().replaceAll(", $", ""); 731 } 732 733 /** @hide */ powerBrickConnectionStatusToString(int powerBrickConnectionStatus)734 public static String powerBrickConnectionStatusToString(int powerBrickConnectionStatus) { 735 switch (powerBrickConnectionStatus) { 736 case POWER_BRICK_STATUS_UNKNOWN: 737 return "unknown"; 738 case POWER_BRICK_STATUS_CONNECTED: 739 return "connected"; 740 case POWER_BRICK_STATUS_DISCONNECTED: 741 return "disconnected"; 742 default: 743 return Integer.toString(powerBrickConnectionStatus); 744 } 745 } 746 747 /** @hide */ roleCombinationsToString(int combo)748 public static String roleCombinationsToString(int combo) { 749 StringBuilder result = new StringBuilder(); 750 result.append("["); 751 752 boolean first = true; 753 while (combo != 0) { 754 final int index = Integer.numberOfTrailingZeros(combo); 755 combo &= ~(1 << index); 756 final int powerRole = (index / NUM_DATA_ROLES + POWER_ROLE_OFFSET); 757 final int dataRole = index % NUM_DATA_ROLES; 758 if (first) { 759 first = false; 760 } else { 761 result.append(", "); 762 } 763 result.append(powerRoleToString(powerRole)); 764 result.append(':'); 765 result.append(dataRoleToString(dataRole)); 766 } 767 768 result.append("]"); 769 return result.toString(); 770 } 771 772 /** @hide */ complianceWarningsToString(@onNull int[] complianceWarnings)773 public static String complianceWarningsToString(@NonNull int[] complianceWarnings) { 774 StringBuilder complianceWarningString = new StringBuilder(); 775 complianceWarningString.append("["); 776 777 if (complianceWarnings != null) { 778 for (int warning : complianceWarnings) { 779 switch (warning) { 780 case UsbPortStatus.COMPLIANCE_WARNING_OTHER: 781 complianceWarningString.append("other, "); 782 break; 783 case UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY: 784 complianceWarningString.append("debug accessory, "); 785 break; 786 case UsbPortStatus.COMPLIANCE_WARNING_BC_1_2: 787 complianceWarningString.append("bc12, "); 788 break; 789 case UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP: 790 complianceWarningString.append("missing rp, "); 791 break; 792 default: 793 complianceWarningString.append(String.format("Unknown(%d), ", warning)); 794 break; 795 } 796 } 797 } 798 799 complianceWarningString.append("]"); 800 return complianceWarningString.toString().replaceAll(", ]$", "]"); 801 } 802 803 /** @hide */ dpAltModeStatusToString(int dpAltModeStatus)804 public static String dpAltModeStatusToString(int dpAltModeStatus) { 805 switch (dpAltModeStatus) { 806 case DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN: 807 return "Unknown"; 808 case DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE: 809 return "Not Capable"; 810 case DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED: 811 return "Capable-Disabled"; 812 case DISPLAYPORT_ALT_MODE_STATUS_ENABLED: 813 return "Enabled"; 814 default: 815 return Integer.toString(dpAltModeStatus); 816 } 817 } 818 819 /** @hide */ checkMode(int powerRole)820 public static void checkMode(int powerRole) { 821 Preconditions.checkArgumentInRange(powerRole, Constants.PortMode.NONE, 822 Constants.PortMode.NUM_MODES - 1, "portMode"); 823 } 824 825 /** @hide */ checkPowerRole(int dataRole)826 public static void checkPowerRole(int dataRole) { 827 Preconditions.checkArgumentInRange(dataRole, Constants.PortPowerRole.NONE, 828 Constants.PortPowerRole.NUM_POWER_ROLES - 1, "powerRole"); 829 } 830 831 /** @hide */ checkDataRole(int mode)832 public static void checkDataRole(int mode) { 833 Preconditions.checkArgumentInRange(mode, Constants.PortDataRole.NONE, 834 Constants.PortDataRole.NUM_DATA_ROLES - 1, "powerRole"); 835 } 836 837 /** @hide */ checkRoles(int powerRole, int dataRole)838 public static void checkRoles(int powerRole, int dataRole) { 839 Preconditions.checkArgumentInRange(powerRole, POWER_ROLE_NONE, POWER_ROLE_SINK, 840 "powerRole"); 841 Preconditions.checkArgumentInRange(dataRole, DATA_ROLE_NONE, DATA_ROLE_DEVICE, "dataRole"); 842 } 843 844 /** @hide */ isModeSupported(int mode)845 public boolean isModeSupported(int mode) { 846 if ((mSupportedModes & mode) == mode) return true; 847 return false; 848 } 849 850 @NonNull 851 @Override toString()852 public String toString() { 853 return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes) 854 + ", supportedContaminantProtectionModes=" + mSupportedContaminantProtectionModes 855 + ", supportsEnableContaminantPresenceProtection=" 856 + mSupportsEnableContaminantPresenceProtection 857 + ", supportsEnableContaminantPresenceDetection=" 858 + mSupportsEnableContaminantPresenceDetection 859 + ", supportsComplianceWarnings=" 860 + mSupportsComplianceWarnings; 861 } 862 } 863