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