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