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