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