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 18 package android.hardware.usb; 19 20 import com.android.internal.util.Preconditions; 21 22 import android.app.PendingIntent; 23 import android.content.Context; 24 import android.os.Bundle; 25 import android.os.ParcelFileDescriptor; 26 import android.os.Process; 27 import android.os.RemoteException; 28 import android.util.Log; 29 30 import java.util.HashMap; 31 32 /** 33 * This class allows you to access the state of USB and communicate with USB devices. 34 * Currently only host mode is supported in the public API. 35 * 36 * <p>You can obtain an instance of this class by calling 37 * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. 38 * 39 * {@samplecode 40 * UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);} 41 * 42 * <div class="special reference"> 43 * <h3>Developer Guides</h3> 44 * <p>For more information about communicating with USB hardware, read the 45 * <a href="{@docRoot}guide/topics/usb/index.html">USB</a> developer guide.</p> 46 * </div> 47 */ 48 public class UsbManager { 49 private static final String TAG = "UsbManager"; 50 51 /** 52 * Broadcast Action: A sticky broadcast for USB state change events when in device mode. 53 * 54 * This is a sticky broadcast for clients that includes USB connected/disconnected state, 55 * <ul> 56 * <li> {@link #USB_CONNECTED} boolean indicating whether USB is connected or disconnected. 57 * <li> {@link #USB_HOST_CONNECTED} boolean indicating whether USB is connected or 58 * disconnected as host. 59 * <li> {@link #USB_CONFIGURED} boolean indicating whether USB is configured. 60 * currently zero if not configured, one for configured. 61 * <li> {@link #USB_FUNCTION_ADB} boolean extra indicating whether the 62 * adb function is enabled 63 * <li> {@link #USB_FUNCTION_RNDIS} boolean extra indicating whether the 64 * RNDIS ethernet function is enabled 65 * <li> {@link #USB_FUNCTION_MTP} boolean extra indicating whether the 66 * MTP function is enabled 67 * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the 68 * PTP function is enabled 69 * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the 70 * accessory function is enabled 71 * <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the 72 * audio source function is enabled 73 * <li> {@link #USB_FUNCTION_MIDI} boolean extra indicating whether the 74 * MIDI function is enabled 75 * </ul> 76 * If the sticky intent has not been found, that indicates USB is disconnected, 77 * USB is not configued, MTP function is enabled, and all the other functions are disabled. 78 * 79 * {@hide} 80 */ 81 public static final String ACTION_USB_STATE = 82 "android.hardware.usb.action.USB_STATE"; 83 84 /** 85 * Broadcast Action: A broadcast for USB port changes. 86 * 87 * This intent is sent when a USB port is added, removed, or changes state. 88 * <ul> 89 * <li> {@link #EXTRA_PORT} containing the {@link android.hardware.usb.UsbPort} 90 * for the port. 91 * <li> {@link #EXTRA_PORT_STATUS} containing the {@link android.hardware.usb.UsbPortStatus} 92 * for the port, or null if the port has been removed 93 * </ul> 94 * 95 * @hide 96 */ 97 public static final String ACTION_USB_PORT_CHANGED = 98 "android.hardware.usb.action.USB_PORT_CHANGED"; 99 100 /** 101 * Broadcast Action: A broadcast for USB device attached event. 102 * 103 * This intent is sent when a USB device is attached to the USB bus when in host mode. 104 * <ul> 105 * <li> {@link #EXTRA_DEVICE} containing the {@link android.hardware.usb.UsbDevice} 106 * for the attached device 107 * </ul> 108 */ 109 public static final String ACTION_USB_DEVICE_ATTACHED = 110 "android.hardware.usb.action.USB_DEVICE_ATTACHED"; 111 112 /** 113 * Broadcast Action: A broadcast for USB device detached event. 114 * 115 * This intent is sent when a USB device is detached from the USB bus when in host mode. 116 * <ul> 117 * <li> {@link #EXTRA_DEVICE} containing the {@link android.hardware.usb.UsbDevice} 118 * for the detached device 119 * </ul> 120 */ 121 public static final String ACTION_USB_DEVICE_DETACHED = 122 "android.hardware.usb.action.USB_DEVICE_DETACHED"; 123 124 /** 125 * Broadcast Action: A broadcast for USB accessory attached event. 126 * 127 * This intent is sent when a USB accessory is attached. 128 * <ul> 129 * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.usb.UsbAccessory} 130 * for the attached accessory 131 * </ul> 132 */ 133 public static final String ACTION_USB_ACCESSORY_ATTACHED = 134 "android.hardware.usb.action.USB_ACCESSORY_ATTACHED"; 135 136 /** 137 * Broadcast Action: A broadcast for USB accessory detached event. 138 * 139 * This intent is sent when a USB accessory is detached. 140 * <ul> 141 * <li> {@link #EXTRA_ACCESSORY} containing the {@link UsbAccessory} 142 * for the attached accessory that was detached 143 * </ul> 144 */ 145 public static final String ACTION_USB_ACCESSORY_DETACHED = 146 "android.hardware.usb.action.USB_ACCESSORY_DETACHED"; 147 148 /** 149 * Boolean extra indicating whether USB is connected or disconnected. 150 * Used in extras for the {@link #ACTION_USB_STATE} broadcast. 151 * 152 * {@hide} 153 */ 154 public static final String USB_CONNECTED = "connected"; 155 156 /** 157 * Boolean extra indicating whether USB is connected or disconnected as host. 158 * Used in extras for the {@link #ACTION_USB_STATE} broadcast. 159 * 160 * {@hide} 161 */ 162 public static final String USB_HOST_CONNECTED = "host_connected"; 163 164 /** 165 * Boolean extra indicating whether USB is configured. 166 * Used in extras for the {@link #ACTION_USB_STATE} broadcast. 167 * 168 * {@hide} 169 */ 170 public static final String USB_CONFIGURED = "configured"; 171 172 /** 173 * Boolean extra indicating whether confidential user data, such as photos, should be 174 * made available on the USB connection. This variable will only be set when the user 175 * has explicitly asked for this data to be unlocked. 176 * Used in extras for the {@link #ACTION_USB_STATE} broadcast. 177 * 178 * {@hide} 179 */ 180 public static final String USB_DATA_UNLOCKED = "unlocked"; 181 182 /** 183 * A placeholder indicating that no USB function is being specified. 184 * Used to distinguish between selecting no function vs. the default function in 185 * {@link #setCurrentFunction(String)}. 186 * 187 * {@hide} 188 */ 189 public static final String USB_FUNCTION_NONE = "none"; 190 191 /** 192 * Name of the adb USB function. 193 * Used in extras for the {@link #ACTION_USB_STATE} broadcast 194 * 195 * {@hide} 196 */ 197 public static final String USB_FUNCTION_ADB = "adb"; 198 199 /** 200 * Name of the RNDIS ethernet USB function. 201 * Used in extras for the {@link #ACTION_USB_STATE} broadcast 202 * 203 * {@hide} 204 */ 205 public static final String USB_FUNCTION_RNDIS = "rndis"; 206 207 /** 208 * Name of the MTP USB function. 209 * Used in extras for the {@link #ACTION_USB_STATE} broadcast 210 * 211 * {@hide} 212 */ 213 public static final String USB_FUNCTION_MTP = "mtp"; 214 215 /** 216 * Name of the PTP USB function. 217 * Used in extras for the {@link #ACTION_USB_STATE} broadcast 218 * 219 * {@hide} 220 */ 221 public static final String USB_FUNCTION_PTP = "ptp"; 222 223 /** 224 * Name of the audio source USB function. 225 * Used in extras for the {@link #ACTION_USB_STATE} broadcast 226 * 227 * {@hide} 228 */ 229 public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source"; 230 231 /** 232 * Name of the MIDI USB function. 233 * Used in extras for the {@link #ACTION_USB_STATE} broadcast 234 * 235 * {@hide} 236 */ 237 public static final String USB_FUNCTION_MIDI = "midi"; 238 239 /** 240 * Name of the Accessory USB function. 241 * Used in extras for the {@link #ACTION_USB_STATE} broadcast 242 * 243 * {@hide} 244 */ 245 public static final String USB_FUNCTION_ACCESSORY = "accessory"; 246 247 /** 248 * Name of extra for {@link #ACTION_USB_PORT_CHANGED} 249 * containing the {@link UsbPort} object for the port. 250 * 251 * @hide 252 */ 253 public static final String EXTRA_PORT = "port"; 254 255 /** 256 * Name of extra for {@link #ACTION_USB_PORT_CHANGED} 257 * containing the {@link UsbPortStatus} object for the port, or null if the port 258 * was removed. 259 * 260 * @hide 261 */ 262 public static final String EXTRA_PORT_STATUS = "portStatus"; 263 264 /** 265 * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} and 266 * {@link #ACTION_USB_DEVICE_DETACHED} broadcasts 267 * containing the {@link UsbDevice} object for the device. 268 */ 269 public static final String EXTRA_DEVICE = "device"; 270 271 /** 272 * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} and 273 * {@link #ACTION_USB_ACCESSORY_DETACHED} broadcasts 274 * containing the {@link UsbAccessory} object for the accessory. 275 */ 276 public static final String EXTRA_ACCESSORY = "accessory"; 277 278 /** 279 * Name of extra added to the {@link android.app.PendingIntent} 280 * passed into {@link #requestPermission(UsbDevice, PendingIntent)} 281 * or {@link #requestPermission(UsbAccessory, PendingIntent)} 282 * containing a boolean value indicating whether the user granted permission or not. 283 */ 284 public static final String EXTRA_PERMISSION_GRANTED = "permission"; 285 286 private final Context mContext; 287 private final IUsbManager mService; 288 289 /** 290 * {@hide} 291 */ UsbManager(Context context, IUsbManager service)292 public UsbManager(Context context, IUsbManager service) { 293 mContext = context; 294 mService = service; 295 } 296 297 /** 298 * Returns a HashMap containing all USB devices currently attached. 299 * USB device name is the key for the returned HashMap. 300 * The result will be empty if no devices are attached, or if 301 * USB host mode is inactive or unsupported. 302 * 303 * @return HashMap containing all connected USB devices. 304 */ getDeviceList()305 public HashMap<String,UsbDevice> getDeviceList() { 306 Bundle bundle = new Bundle(); 307 try { 308 mService.getDeviceList(bundle); 309 HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>(); 310 for (String name : bundle.keySet()) { 311 result.put(name, (UsbDevice)bundle.get(name)); 312 } 313 return result; 314 } catch (RemoteException e) { 315 throw e.rethrowFromSystemServer(); 316 } 317 } 318 319 /** 320 * Opens the device so it can be used to send and receive 321 * data using {@link android.hardware.usb.UsbRequest}. 322 * 323 * @param device the device to open 324 * @return a {@link UsbDeviceConnection}, or {@code null} if open failed 325 */ openDevice(UsbDevice device)326 public UsbDeviceConnection openDevice(UsbDevice device) { 327 try { 328 String deviceName = device.getDeviceName(); 329 ParcelFileDescriptor pfd = mService.openDevice(deviceName); 330 if (pfd != null) { 331 UsbDeviceConnection connection = new UsbDeviceConnection(device); 332 boolean result = connection.open(deviceName, pfd); 333 pfd.close(); 334 if (result) { 335 return connection; 336 } 337 } 338 } catch (Exception e) { 339 Log.e(TAG, "exception in UsbManager.openDevice", e); 340 } 341 return null; 342 } 343 344 /** 345 * Returns a list of currently attached USB accessories. 346 * (in the current implementation there can be at most one) 347 * 348 * @return list of USB accessories, or null if none are attached. 349 */ getAccessoryList()350 public UsbAccessory[] getAccessoryList() { 351 try { 352 UsbAccessory accessory = mService.getCurrentAccessory(); 353 if (accessory == null) { 354 return null; 355 } else { 356 return new UsbAccessory[] { accessory }; 357 } 358 } catch (RemoteException e) { 359 throw e.rethrowFromSystemServer(); 360 } 361 } 362 363 /** 364 * Opens a file descriptor for reading and writing data to the USB accessory. 365 * 366 * @param accessory the USB accessory to open 367 * @return file descriptor, or null if the accessor could not be opened. 368 */ openAccessory(UsbAccessory accessory)369 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { 370 try { 371 return mService.openAccessory(accessory); 372 } catch (RemoteException e) { 373 throw e.rethrowFromSystemServer(); 374 } 375 } 376 377 /** 378 * Returns true if the caller has permission to access the device. 379 * Permission might have been granted temporarily via 380 * {@link #requestPermission(UsbDevice, PendingIntent)} or 381 * by the user choosing the caller as the default application for the device. 382 * 383 * @param device to check permissions for 384 * @return true if caller has permission 385 */ hasPermission(UsbDevice device)386 public boolean hasPermission(UsbDevice device) { 387 try { 388 return mService.hasDevicePermission(device); 389 } catch (RemoteException e) { 390 throw e.rethrowFromSystemServer(); 391 } 392 } 393 394 /** 395 * Returns true if the caller has permission to access the accessory. 396 * Permission might have been granted temporarily via 397 * {@link #requestPermission(UsbAccessory, PendingIntent)} or 398 * by the user choosing the caller as the default application for the accessory. 399 * 400 * @param accessory to check permissions for 401 * @return true if caller has permission 402 */ hasPermission(UsbAccessory accessory)403 public boolean hasPermission(UsbAccessory accessory) { 404 try { 405 return mService.hasAccessoryPermission(accessory); 406 } catch (RemoteException e) { 407 throw e.rethrowFromSystemServer(); 408 } 409 } 410 411 /** 412 * Requests temporary permission for the given package to access the device. 413 * This may result in a system dialog being displayed to the user 414 * if permission had not already been granted. 415 * Success or failure is returned via the {@link android.app.PendingIntent} pi. 416 * If successful, this grants the caller permission to access the device only 417 * until the device is disconnected. 418 * 419 * The following extras will be added to pi: 420 * <ul> 421 * <li> {@link #EXTRA_DEVICE} containing the device passed into this call 422 * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether 423 * permission was granted by the user 424 * </ul> 425 * 426 * @param device to request permissions for 427 * @param pi PendingIntent for returning result 428 */ requestPermission(UsbDevice device, PendingIntent pi)429 public void requestPermission(UsbDevice device, PendingIntent pi) { 430 try { 431 mService.requestDevicePermission(device, mContext.getPackageName(), pi); 432 } catch (RemoteException e) { 433 throw e.rethrowFromSystemServer(); 434 } 435 } 436 437 /** 438 * Requests temporary permission for the given package to access the accessory. 439 * This may result in a system dialog being displayed to the user 440 * if permission had not already been granted. 441 * Success or failure is returned via the {@link android.app.PendingIntent} pi. 442 * If successful, this grants the caller permission to access the accessory only 443 * until the device is disconnected. 444 * 445 * The following extras will be added to pi: 446 * <ul> 447 * <li> {@link #EXTRA_ACCESSORY} containing the accessory passed into this call 448 * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether 449 * permission was granted by the user 450 * </ul> 451 * 452 * @param accessory to request permissions for 453 * @param pi PendingIntent for returning result 454 */ requestPermission(UsbAccessory accessory, PendingIntent pi)455 public void requestPermission(UsbAccessory accessory, PendingIntent pi) { 456 try { 457 mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi); 458 } catch (RemoteException e) { 459 throw e.rethrowFromSystemServer(); 460 } 461 } 462 463 /** 464 * Grants permission for USB device without showing system dialog. 465 * Only system components can call this function. 466 * @param device to request permissions for 467 * 468 * {@hide} 469 */ grantPermission(UsbDevice device)470 public void grantPermission(UsbDevice device) { 471 try { 472 mService.grantDevicePermission(device, Process.myUid()); 473 } catch (RemoteException e) { 474 throw e.rethrowFromSystemServer(); 475 } 476 } 477 478 /** 479 * Returns true if the specified USB function is currently enabled when in device mode. 480 * <p> 481 * USB functions represent interfaces which are published to the host to access 482 * services offered by the device. 483 * </p> 484 * 485 * @param function name of the USB function 486 * @return true if the USB function is enabled 487 * 488 * {@hide} 489 */ isFunctionEnabled(String function)490 public boolean isFunctionEnabled(String function) { 491 try { 492 return mService.isFunctionEnabled(function); 493 } catch (RemoteException e) { 494 throw e.rethrowFromSystemServer(); 495 } 496 } 497 498 /** 499 * Sets the current USB function when in device mode. 500 * <p> 501 * USB functions represent interfaces which are published to the host to access 502 * services offered by the device. 503 * </p><p> 504 * This method is intended to select among primary USB functions. The system may 505 * automatically activate additional functions such as {@link #USB_FUNCTION_ADB} 506 * or {@link #USB_FUNCTION_ACCESSORY} based on other settings and states. 507 * </p><p> 508 * The allowed values are: {@link #USB_FUNCTION_NONE}, {@link #USB_FUNCTION_AUDIO_SOURCE}, 509 * {@link #USB_FUNCTION_MIDI}, {@link #USB_FUNCTION_MTP}, {@link #USB_FUNCTION_PTP}, 510 * or {@link #USB_FUNCTION_RNDIS}. 511 * </p><p> 512 * Note: This function is asynchronous and may fail silently without applying 513 * the requested changes. 514 * </p> 515 * 516 * @param function name of the USB function, or null to restore the default function 517 * 518 * {@hide} 519 */ setCurrentFunction(String function)520 public void setCurrentFunction(String function) { 521 try { 522 mService.setCurrentFunction(function); 523 } catch (RemoteException e) { 524 throw e.rethrowFromSystemServer(); 525 } 526 } 527 528 /** 529 * Sets whether USB data (for example, MTP exposed pictures) should be made available 530 * on the USB connection when in device mode. Unlocking usb data should only be done with 531 * user involvement, since exposing pictures or other data could leak sensitive 532 * user information. 533 * 534 * {@hide} 535 */ setUsbDataUnlocked(boolean unlocked)536 public void setUsbDataUnlocked(boolean unlocked) { 537 try { 538 mService.setUsbDataUnlocked(unlocked); 539 } catch (RemoteException e) { 540 throw e.rethrowFromSystemServer(); 541 } 542 } 543 544 /** 545 * Returns a list of physical USB ports on the device. 546 * <p> 547 * This list is guaranteed to contain all dual-role USB Type C ports but it might 548 * be missing other ports depending on whether the kernel USB drivers have been 549 * updated to publish all of the device's ports through the new "dual_role_usb" 550 * device class (which supports all types of ports despite its name). 551 * </p> 552 * 553 * @return The list of USB ports, or null if none. 554 * 555 * @hide 556 */ getPorts()557 public UsbPort[] getPorts() { 558 try { 559 return mService.getPorts(); 560 } catch (RemoteException e) { 561 throw e.rethrowFromSystemServer(); 562 } 563 } 564 565 /** 566 * Gets the status of the specified USB port. 567 * 568 * @param port The port to query. 569 * @return The status of the specified USB port, or null if unknown. 570 * 571 * @hide 572 */ getPortStatus(UsbPort port)573 public UsbPortStatus getPortStatus(UsbPort port) { 574 Preconditions.checkNotNull(port, "port must not be null"); 575 576 try { 577 return mService.getPortStatus(port.getId()); 578 } catch (RemoteException e) { 579 throw e.rethrowFromSystemServer(); 580 } 581 } 582 583 /** 584 * Sets the desired role combination of the port. 585 * <p> 586 * The supported role combinations depend on what is connected to the port and may be 587 * determined by consulting 588 * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}. 589 * </p><p> 590 * Note: This function is asynchronous and may fail silently without applying 591 * the requested changes. If this function does cause a status change to occur then 592 * a {@link #ACTION_USB_PORT_CHANGED} broadcast will be sent. 593 * </p> 594 * 595 * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE} 596 * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role. 597 * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST} 598 * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role. 599 * 600 * @hide 601 */ setPortRoles(UsbPort port, int powerRole, int dataRole)602 public void setPortRoles(UsbPort port, int powerRole, int dataRole) { 603 Preconditions.checkNotNull(port, "port must not be null"); 604 UsbPort.checkRoles(powerRole, dataRole); 605 606 try { 607 mService.setPortRoles(port.getId(), powerRole, dataRole); 608 } catch (RemoteException e) { 609 throw e.rethrowFromSystemServer(); 610 } 611 } 612 613 /** @hide */ addFunction(String functions, String function)614 public static String addFunction(String functions, String function) { 615 if (USB_FUNCTION_NONE.equals(functions)) { 616 return function; 617 } 618 if (!containsFunction(functions, function)) { 619 if (functions.length() > 0) { 620 functions += ","; 621 } 622 functions += function; 623 } 624 return functions; 625 } 626 627 /** @hide */ removeFunction(String functions, String function)628 public static String removeFunction(String functions, String function) { 629 String[] split = functions.split(","); 630 for (int i = 0; i < split.length; i++) { 631 if (function.equals(split[i])) { 632 split[i] = null; 633 } 634 } 635 if (split.length == 1 && split[0] == null) { 636 return USB_FUNCTION_NONE; 637 } 638 StringBuilder builder = new StringBuilder(); 639 for (int i = 0; i < split.length; i++) { 640 String s = split[i]; 641 if (s != null) { 642 if (builder.length() > 0) { 643 builder.append(","); 644 } 645 builder.append(s); 646 } 647 } 648 return builder.toString(); 649 } 650 651 /** @hide */ containsFunction(String functions, String function)652 public static boolean containsFunction(String functions, String function) { 653 int index = functions.indexOf(function); 654 if (index < 0) return false; 655 if (index > 0 && functions.charAt(index - 1) != ',') return false; 656 int charAfter = index + function.length(); 657 if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false; 658 return true; 659 } 660 } 661