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