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