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