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