UsbManager.java revision 9eb014aeb0630dab9210f8eb8b6c2f4250d5990e
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 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 */
44public class UsbManager {
45    private static final String TAG = "UsbManager";
46
47   /**
48     * Broadcast Action:  A sticky broadcast for USB state change events when in device mode.
49     *
50     * This is a sticky broadcast for clients that includes USB connected/disconnected state,
51     * <ul>
52     * <li> {@link #USB_CONNECTED} boolean indicating whether USB is connected or disconnected.
53     * <li> {@link #USB_CONFIGURATION} integer containing current USB configuration
54     * currently zero if not configured, one for configured.
55     * <li> {@link #USB_FUNCTION_MASS_STORAGE} boolean extra indicating whether the
56     * mass storage function is enabled
57     * <li> {@link #USB_FUNCTION_ADB} boolean extra indicating whether the
58     * adb function is enabled
59     * <li> {@link #USB_FUNCTION_RNDIS} boolean extra indicating whether the
60     * RNDIS ethernet function is enabled
61     * <li> {@link #USB_FUNCTION_MTP} boolean extra indicating whether the
62     * MTP function is enabled
63     * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the
64     * PTP function is enabled
65     * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the
66     * accessory function is enabled
67     * </ul>
68     *
69     * {@hide}
70     */
71    public static final String ACTION_USB_STATE =
72            "android.hardware.usb.action.USB_STATE";
73
74   /**
75     * Broadcast Action:  A broadcast for USB device attached event.
76     *
77     * This intent is sent when a USB device is attached to the USB bus when in host mode.
78     * <ul>
79     * <li> {@link #EXTRA_DEVICE} containing the {@link android.hardware.usb.UsbDevice}
80     * for the attached device
81     * </ul>
82     */
83    public static final String ACTION_USB_DEVICE_ATTACHED =
84            "android.hardware.usb.action.USB_DEVICE_ATTACHED";
85
86   /**
87     * Broadcast Action:  A broadcast for USB device detached event.
88     *
89     * This intent is sent when a USB device is detached from the USB bus when in host mode.
90     * <ul>
91     * <li> {@link #EXTRA_DEVICE} containing the {@link android.hardware.usb.UsbDevice}
92     * for the detached device
93     * </ul>
94     */
95    public static final String ACTION_USB_DEVICE_DETACHED =
96            "android.hardware.usb.action.USB_DEVICE_DETACHED";
97
98   /**
99     * Broadcast Action:  A broadcast for USB accessory attached event.
100     *
101     * This intent is sent when a USB accessory is attached.
102     * <ul>
103     * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.usb.UsbAccessory}
104     * for the attached accessory
105     * </ul>
106     */
107    public static final String ACTION_USB_ACCESSORY_ATTACHED =
108            "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
109
110   /**
111     * Broadcast Action:  A broadcast for USB accessory detached event.
112     *
113     * This intent is sent when a USB accessory is detached.
114     * <ul>
115     * <li> {@link #EXTRA_ACCESSORY} containing the {@link UsbAccessory}
116     * for the attached accessory that was detached
117     * </ul>
118     */
119    public static final String ACTION_USB_ACCESSORY_DETACHED =
120            "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
121
122    /**
123     * Boolean extra indicating whether USB is connected or disconnected.
124     * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
125     *
126     * {@hide}
127     */
128    public static final String USB_CONNECTED = "connected";
129
130    /**
131     * Integer extra containing currently set USB configuration.
132     * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
133     *
134     * {@hide}
135     */
136    public static final String USB_CONFIGURATION = "configuration";
137
138    /**
139     * Name of the USB mass storage USB function.
140     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
141     *
142     * {@hide}
143     */
144    public static final String USB_FUNCTION_MASS_STORAGE = "mass_storage";
145
146    /**
147     * Name of the adb USB function.
148     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
149     *
150     * {@hide}
151     */
152    public static final String USB_FUNCTION_ADB = "adb";
153
154    /**
155     * Name of the RNDIS ethernet USB function.
156     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
157     *
158     * {@hide}
159     */
160    public static final String USB_FUNCTION_RNDIS = "rndis";
161
162    /**
163     * Name of the MTP USB function.
164     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
165     *
166     * {@hide}
167     */
168    public static final String USB_FUNCTION_MTP = "mtp";
169
170    /**
171     * Name of the PTP USB function.
172     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
173     *
174     * {@hide}
175     */
176    public static final String USB_FUNCTION_PTP = "ptp";
177
178    /**
179     * Name of the Accessory USB function.
180     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
181     *
182     * {@hide}
183     */
184    public static final String USB_FUNCTION_ACCESSORY = "accessory";
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