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