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