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