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