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