summaryrefslogtreecommitdiff
path: root/android/hardware/usb
diff options
context:
space:
mode:
authorJustin Klaassen <justinklaassen@google.com>2017-09-15 17:58:39 -0400
committerJustin Klaassen <justinklaassen@google.com>2017-09-15 17:58:39 -0400
commit10d07c88d69cc64f73a069163e7ea5ba2519a099 (patch)
tree8dbd149eb350320a29c3d10e7ad3201de1c5cbee /android/hardware/usb
parent677516fb6b6f207d373984757d3d9450474b6b00 (diff)
downloadandroid-28-10d07c88d69cc64f73a069163e7ea5ba2519a099.tar.gz
Import Android SDK Platform PI [4335822]
/google/data/ro/projects/android/fetch_artifact \ --bid 4335822 \ --target sdk_phone_armv7-win_sdk \ sdk-repo-linux-sources-4335822.zip AndroidVersion.ApiLevel has been modified to appear as 28 Change-Id: Ic8f04be005a71c2b9abeaac754d8da8d6f9a2c32
Diffstat (limited to 'android/hardware/usb')
-rw-r--r--android/hardware/usb/UsbAccessory.java220
-rw-r--r--android/hardware/usb/UsbConfiguration.java185
-rw-r--r--android/hardware/usb/UsbConstants.java183
-rw-r--r--android/hardware/usb/UsbDevice.java344
-rw-r--r--android/hardware/usb/UsbDeviceConnection.java377
-rw-r--r--android/hardware/usb/UsbEndpoint.java161
-rw-r--r--android/hardware/usb/UsbInterface.java198
-rw-r--r--android/hardware/usb/UsbManager.java737
-rw-r--r--android/hardware/usb/UsbPort.java305
-rw-r--r--android/hardware/usb/UsbPortStatus.java144
-rw-r--r--android/hardware/usb/UsbRequest.java359
11 files changed, 3213 insertions, 0 deletions
diff --git a/android/hardware/usb/UsbAccessory.java b/android/hardware/usb/UsbAccessory.java
new file mode 100644
index 00000000..4aeb40c1
--- /dev/null
+++ b/android/hardware/usb/UsbAccessory.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
+/**
+ * A class representing a USB accessory, which is an external hardware component
+ * that communicates with an android application over USB.
+ * The accessory is the USB host and android the device side of the USB connection.
+ *
+ * <p>When the accessory connects, it reports its manufacturer and model names,
+ * the version of the accessory, and a user visible description of the accessory to the device.
+ * The manufacturer, model and version strings are used by the USB Manager to choose
+ * an appropriate application for the accessory.
+ * The accessory may optionally provide a unique serial number
+ * and a URL to for the accessory's website to the device as well.
+ *
+ * <p>An instance of this class is sent to the application via the
+ * {@link UsbManager#ACTION_USB_ACCESSORY_ATTACHED} Intent.
+ * The application can then call {@link UsbManager#openAccessory} to open a file descriptor
+ * for reading and writing data to and from the accessory.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about communicating with USB hardware, read the
+ * <a href="{@docRoot}guide/topics/usb/index.html">USB</a> developer guide.</p>
+ * </div>
+ */
+public class UsbAccessory implements Parcelable {
+
+ private static final String TAG = "UsbAccessory";
+
+ private final @NonNull String mManufacturer;
+ private final @NonNull String mModel;
+ private final @Nullable String mDescription;
+ private final @Nullable String mVersion;
+ private final @Nullable String mUri;
+ private final @Nullable String mSerial;
+
+ /** @hide */
+ public static final int MANUFACTURER_STRING = 0;
+ /** @hide */
+ public static final int MODEL_STRING = 1;
+ /** @hide */
+ public static final int DESCRIPTION_STRING = 2;
+ /** @hide */
+ public static final int VERSION_STRING = 3;
+ /** @hide */
+ public static final int URI_STRING = 4;
+ /** @hide */
+ public static final int SERIAL_STRING = 5;
+
+ /**
+ * UsbAccessory should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbAccessory(@NonNull String manufacturer, @NonNull String model,
+ @Nullable String description, @Nullable String version, @Nullable String uri,
+ @Nullable String serial) {
+ mManufacturer = Preconditions.checkNotNull(manufacturer);
+ mModel = Preconditions.checkNotNull(model);
+ mDescription = description;
+ mVersion = version;
+ mUri = uri;
+ mSerial = serial;
+ }
+
+ /**
+ * UsbAccessory should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbAccessory(String[] strings) {
+ this(strings[MANUFACTURER_STRING], strings[MODEL_STRING], strings[DESCRIPTION_STRING],
+ strings[VERSION_STRING], strings[URI_STRING], strings[SERIAL_STRING]);
+ }
+
+ /**
+ * Returns the manufacturer name of the accessory.
+ *
+ * @return the accessory manufacturer
+ */
+ public @NonNull String getManufacturer() {
+ return mManufacturer;
+ }
+
+ /**
+ * Returns the model name of the accessory.
+ *
+ * @return the accessory model
+ */
+ public @NonNull String getModel() {
+ return mModel;
+ }
+
+ /**
+ * Returns a user visible description of the accessory.
+ *
+ * @return the accessory description, or {@code null} if not set
+ */
+ public @Nullable String getDescription() {
+ return mDescription;
+ }
+
+ /**
+ * Returns the version of the accessory.
+ *
+ * @return the accessory version, or {@code null} if not set
+ */
+ public @Nullable String getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Returns the URI for the accessory.
+ * This is an optional URI that might show information about the accessory
+ * or provide the option to download an application for the accessory
+ *
+ * @return the accessory URI, or {@code null} if not set
+ */
+ public @Nullable String getUri() {
+ return mUri;
+ }
+
+ /**
+ * Returns the unique serial number for the accessory.
+ * This is an optional serial number that can be used to differentiate
+ * between individual accessories of the same model and manufacturer
+ *
+ * @return the unique serial number, or {@code null} if not set
+ */
+ public @Nullable String getSerial() {
+ return mSerial;
+ }
+
+ private static boolean compare(String s1, String s2) {
+ if (s1 == null) return (s2 == null);
+ return s1.equals(s2);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof UsbAccessory) {
+ UsbAccessory accessory = (UsbAccessory)obj;
+ return (compare(mManufacturer, accessory.getManufacturer()) &&
+ compare(mModel, accessory.getModel()) &&
+ compare(mDescription, accessory.getDescription()) &&
+ compare(mVersion, accessory.getVersion()) &&
+ compare(mUri, accessory.getUri()) &&
+ compare(mSerial, accessory.getSerial()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return mManufacturer.hashCode() ^ mModel.hashCode() ^
+ (mDescription == null ? 0 : mDescription.hashCode()) ^
+ (mVersion == null ? 0 : mVersion.hashCode()) ^
+ (mUri == null ? 0 : mUri.hashCode()) ^ (mSerial == null ? 0 : mSerial.hashCode());
+ }
+
+ @Override
+ public String toString() {
+ return "UsbAccessory[mManufacturer=" + mManufacturer +
+ ", mModel=" + mModel +
+ ", mDescription=" + mDescription +
+ ", mVersion=" + mVersion +
+ ", mUri=" + mUri +
+ ", mSerial=" + mSerial + "]";
+ }
+
+ public static final Parcelable.Creator<UsbAccessory> CREATOR =
+ new Parcelable.Creator<UsbAccessory>() {
+ public UsbAccessory createFromParcel(Parcel in) {
+ String manufacturer = in.readString();
+ String model = in.readString();
+ String description = in.readString();
+ String version = in.readString();
+ String uri = in.readString();
+ String serial = in.readString();
+ return new UsbAccessory(manufacturer, model, description, version, uri, serial);
+ }
+
+ public UsbAccessory[] newArray(int size) {
+ return new UsbAccessory[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mManufacturer);
+ parcel.writeString(mModel);
+ parcel.writeString(mDescription);
+ parcel.writeString(mVersion);
+ parcel.writeString(mUri);
+ parcel.writeString(mSerial);
+ }
+}
diff --git a/android/hardware/usb/UsbConfiguration.java b/android/hardware/usb/UsbConfiguration.java
new file mode 100644
index 00000000..a1715708
--- /dev/null
+++ b/android/hardware/usb/UsbConfiguration.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
+/**
+ * A class representing a configuration on a {@link UsbDevice}.
+ * A USB configuration can have one or more interfaces, each one providing a different
+ * piece of functionality, separate from the other interfaces.
+ * An interface will have one or more {@link UsbEndpoint}s, which are the
+ * channels by which the host transfers data with the device.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about communicating with USB hardware, read the
+ * <a href="{@docRoot}guide/topics/usb/index.html">USB</a> developer guide.</p>
+ * </div>
+ */
+public class UsbConfiguration implements Parcelable {
+
+ private final int mId;
+ private final @Nullable String mName;
+ private final int mAttributes;
+ private final int mMaxPower;
+
+ /** All interfaces for this config, only null during creation */
+ private @Nullable Parcelable[] mInterfaces;
+
+ /**
+ * Mask for "self-powered" bit in the configuration's attributes.
+ */
+ private static final int ATTR_SELF_POWERED = 1 << 6;
+
+ /**
+ * Mask for "remote wakeup" bit in the configuration's attributes.
+ */
+ private static final int ATTR_REMOTE_WAKEUP = 1 << 5;
+
+ /**
+ * UsbConfiguration should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbConfiguration(int id, @Nullable String name, int attributes, int maxPower) {
+ mId = id;
+ mName = name;
+ mAttributes = attributes;
+ mMaxPower = maxPower;
+ }
+
+ /**
+ * Returns the configuration's ID field.
+ * This is an integer that uniquely identifies the configuration on the device.
+ *
+ * @return the configuration's ID
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the configuration's name.
+ *
+ * @return the configuration's name, or {@code null} if the property could not be read
+ */
+ public @Nullable String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the self-powered attribute value configuration's attributes field.
+ * This attribute indicates that the device has a power source other than the USB connection.
+ *
+ * @return the configuration's self-powered attribute
+ */
+ public boolean isSelfPowered() {
+ return (mAttributes & ATTR_SELF_POWERED) != 0;
+ }
+
+ /**
+ * Returns the remote-wakeup attribute value configuration's attributes field.
+ * This attributes that the device may signal the host to wake from suspend.
+ *
+ * @return the configuration's remote-wakeup attribute
+ */
+ public boolean isRemoteWakeup() {
+ return (mAttributes & ATTR_REMOTE_WAKEUP) != 0;
+ }
+
+ /**
+ * Returns the configuration's max power consumption, in milliamps.
+ *
+ * @return the configuration's max power
+ */
+ public int getMaxPower() {
+ return mMaxPower * 2;
+ }
+
+ /**
+ * Returns the number of {@link UsbInterface}s this configuration contains.
+ *
+ * @return the number of endpoints
+ */
+ public int getInterfaceCount() {
+ return mInterfaces.length;
+ }
+
+ /**
+ * Returns the {@link UsbInterface} at the given index.
+ *
+ * @return the interface
+ */
+ public @NonNull UsbInterface getInterface(int index) {
+ return (UsbInterface)mInterfaces[index];
+ }
+
+ /**
+ * Only used by UsbService implementation
+ * @hide
+ */
+ public void setInterfaces(@NonNull Parcelable[] interfaces) {
+ mInterfaces = Preconditions.checkArrayElementsNotNull(interfaces, "interfaces");
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("UsbConfiguration[mId=" + mId +
+ ",mName=" + mName + ",mAttributes=" + mAttributes +
+ ",mMaxPower=" + mMaxPower + ",mInterfaces=[");
+ for (int i = 0; i < mInterfaces.length; i++) {
+ builder.append("\n");
+ builder.append(mInterfaces[i].toString());
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+ public static final Parcelable.Creator<UsbConfiguration> CREATOR =
+ new Parcelable.Creator<UsbConfiguration>() {
+ public UsbConfiguration createFromParcel(Parcel in) {
+ int id = in.readInt();
+ String name = in.readString();
+ int attributes = in.readInt();
+ int maxPower = in.readInt();
+ Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader());
+ UsbConfiguration configuration = new UsbConfiguration(id, name, attributes, maxPower);
+ configuration.setInterfaces(interfaces);
+ return configuration;
+ }
+
+ public UsbConfiguration[] newArray(int size) {
+ return new UsbConfiguration[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mId);
+ parcel.writeString(mName);
+ parcel.writeInt(mAttributes);
+ parcel.writeInt(mMaxPower);
+ parcel.writeParcelableArray(mInterfaces, 0);
+ }
+}
diff --git a/android/hardware/usb/UsbConstants.java b/android/hardware/usb/UsbConstants.java
new file mode 100644
index 00000000..0e8d47ca
--- /dev/null
+++ b/android/hardware/usb/UsbConstants.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+/**
+ * Contains constants for the USB protocol.
+ * These constants correspond to definitions in linux/usb/ch9.h in the linux kernel.
+ */
+public final class UsbConstants {
+
+ /**
+ * Bitmask used for extracting the {@link UsbEndpoint} direction from its address field.
+ * @see UsbEndpoint#getAddress
+ * @see UsbEndpoint#getDirection
+ * @see #USB_DIR_OUT
+ * @see #USB_DIR_IN
+ *
+ */
+ public static final int USB_ENDPOINT_DIR_MASK = 0x80;
+ /**
+ * Used to signify direction of data for a {@link UsbEndpoint} is OUT (host to device)
+ * @see UsbEndpoint#getDirection
+ */
+ public static final int USB_DIR_OUT = 0;
+ /**
+ * Used to signify direction of data for a {@link UsbEndpoint} is IN (device to host)
+ * @see UsbEndpoint#getDirection
+ */
+ public static final int USB_DIR_IN = 0x80;
+
+ /**
+ * Bitmask used for extracting the {@link UsbEndpoint} number its address field.
+ * @see UsbEndpoint#getAddress
+ * @see UsbEndpoint#getEndpointNumber
+ */
+ public static final int USB_ENDPOINT_NUMBER_MASK = 0x0f;
+
+ /**
+ * Bitmask used for extracting the {@link UsbEndpoint} type from its address field.
+ * @see UsbEndpoint#getAddress
+ * @see UsbEndpoint#getType
+ * @see #USB_ENDPOINT_XFER_CONTROL
+ * @see #USB_ENDPOINT_XFER_ISOC
+ * @see #USB_ENDPOINT_XFER_BULK
+ * @see #USB_ENDPOINT_XFER_INT
+ */
+ public static final int USB_ENDPOINT_XFERTYPE_MASK = 0x03;
+ /**
+ * Control endpoint type (endpoint zero)
+ * @see UsbEndpoint#getType
+ */
+ public static final int USB_ENDPOINT_XFER_CONTROL = 0;
+ /**
+ * Isochronous endpoint type (currently not supported)
+ * @see UsbEndpoint#getType
+ */
+ public static final int USB_ENDPOINT_XFER_ISOC = 1;
+ /**
+ * Bulk endpoint type
+ * @see UsbEndpoint#getType
+ */
+ public static final int USB_ENDPOINT_XFER_BULK = 2;
+ /**
+ * Interrupt endpoint type
+ * @see UsbEndpoint#getType
+ */
+ public static final int USB_ENDPOINT_XFER_INT = 3;
+
+
+ /**
+ * Bitmask used for encoding the request type for a control request on endpoint zero.
+ */
+ public static final int USB_TYPE_MASK = (0x03 << 5);
+ /**
+ * Used to specify that an endpoint zero control request is a standard request.
+ */
+ public static final int USB_TYPE_STANDARD = (0x00 << 5);
+ /**
+ * Used to specify that an endpoint zero control request is a class specific request.
+ */
+ public static final int USB_TYPE_CLASS = (0x01 << 5);
+ /**
+ * Used to specify that an endpoint zero control request is a vendor specific request.
+ */
+ public static final int USB_TYPE_VENDOR = (0x02 << 5);
+ /**
+ * Reserved endpoint zero control request type (currently unused).
+ */
+ public static final int USB_TYPE_RESERVED = (0x03 << 5);
+
+
+ /**
+ * USB class indicating that the class is determined on a per-interface basis.
+ */
+ public static final int USB_CLASS_PER_INTERFACE = 0;
+ /**
+ * USB class for audio devices.
+ */
+ public static final int USB_CLASS_AUDIO = 1;
+ /**
+ * USB class for communication devices.
+ */
+ public static final int USB_CLASS_COMM = 2;
+ /**
+ * USB class for human interface devices (for example, mice and keyboards).
+ */
+ public static final int USB_CLASS_HID = 3;
+ /**
+ * USB class for physical devices.
+ */
+ public static final int USB_CLASS_PHYSICA = 5;
+ /**
+ * USB class for still image devices (digital cameras).
+ */
+ public static final int USB_CLASS_STILL_IMAGE = 6;
+ /**
+ * USB class for printers.
+ */
+ public static final int USB_CLASS_PRINTER = 7;
+ /**
+ * USB class for mass storage devices.
+ */
+ public static final int USB_CLASS_MASS_STORAGE = 8;
+ /**
+ * USB class for USB hubs.
+ */
+ public static final int USB_CLASS_HUB = 9;
+ /**
+ * USB class for CDC devices (communications device class).
+ */
+ public static final int USB_CLASS_CDC_DATA = 0x0a;
+ /**
+ * USB class for content smart card devices.
+ */
+ public static final int USB_CLASS_CSCID = 0x0b;
+ /**
+ * USB class for content security devices.
+ */
+ public static final int USB_CLASS_CONTENT_SEC = 0x0d;
+ /**
+ * USB class for video devices.
+ */
+ public static final int USB_CLASS_VIDEO = 0x0e;
+ /**
+ * USB class for wireless controller devices.
+ */
+ public static final int USB_CLASS_WIRELESS_CONTROLLER = 0xe0;
+ /**
+ * USB class for wireless miscellaneous devices.
+ */
+ public static final int USB_CLASS_MISC = 0xef;
+ /**
+ * Application specific USB class.
+ */
+ public static final int USB_CLASS_APP_SPEC = 0xfe;
+ /**
+ * Vendor specific USB class.
+ */
+ public static final int USB_CLASS_VENDOR_SPEC = 0xff;
+
+ /**
+ * Boot subclass for HID devices.
+ */
+ public static final int USB_INTERFACE_SUBCLASS_BOOT = 1;
+ /**
+ * Vendor specific USB subclass.
+ */
+ public static final int USB_SUBCLASS_VENDOR_SPEC = 0xff;
+}
diff --git a/android/hardware/usb/UsbDevice.java b/android/hardware/usb/UsbDevice.java
new file mode 100644
index 00000000..1e983016
--- /dev/null
+++ b/android/hardware/usb/UsbDevice.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
+/**
+ * This class represents a USB device attached to the android device with the android device
+ * acting as the USB host.
+ * Each device contains one or more {@link UsbInterface}s, each of which contains a number of
+ * {@link UsbEndpoint}s (the channels via which data is transmitted over USB).
+ *
+ * <p> This class contains information (along with {@link UsbInterface} and {@link UsbEndpoint})
+ * that describes the capabilities of the USB device.
+ * To communicate with the device, you open a {@link UsbDeviceConnection} for the device
+ * and use {@link UsbRequest} to send and receive data on an endpoint.
+ * {@link UsbDeviceConnection#controlTransfer} is used for control requests on endpoint zero.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about communicating with USB hardware, read the
+ * <a href="{@docRoot}guide/topics/connectivity/usb/index.html">USB</a> developer guide.</p>
+ * </div>
+ */
+public class UsbDevice implements Parcelable {
+
+ private static final String TAG = "UsbDevice";
+ private static final boolean DEBUG = false;
+
+ private final @NonNull String mName;
+ private final @Nullable String mManufacturerName;
+ private final @Nullable String mProductName;
+ private final @NonNull String mVersion;
+ private final @Nullable String mSerialNumber;
+ private final int mVendorId;
+ private final int mProductId;
+ private final int mClass;
+ private final int mSubclass;
+ private final int mProtocol;
+
+ /** All configurations for this device, only null during creation */
+ private @Nullable Parcelable[] mConfigurations;
+
+ /** All interfaces on the device. Initialized on first call to getInterfaceList */
+ private @Nullable UsbInterface[] mInterfaces;
+
+ /**
+ * UsbDevice should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbDevice(@NonNull String name, int vendorId, int productId, int Class, int subClass,
+ int protocol, @Nullable String manufacturerName, @Nullable String productName,
+ @NonNull String version, @Nullable String serialNumber) {
+ mName = Preconditions.checkNotNull(name);
+ mVendorId = vendorId;
+ mProductId = productId;
+ mClass = Class;
+ mSubclass = subClass;
+ mProtocol = protocol;
+ mManufacturerName = manufacturerName;
+ mProductName = productName;
+ mVersion = Preconditions.checkStringNotEmpty(version);
+ mSerialNumber = serialNumber;
+ }
+
+ /**
+ * Returns the name of the device.
+ * In the standard implementation, this is the path of the device file
+ * for the device in the usbfs file system.
+ *
+ * @return the device name
+ */
+ public @NonNull String getDeviceName() {
+ return mName;
+ }
+
+ /**
+ * Returns the manufacturer name of the device.
+ *
+ * @return the manufacturer name, or {@code null} if the property could not be read
+ */
+ public @Nullable String getManufacturerName() {
+ return mManufacturerName;
+ }
+
+ /**
+ * Returns the product name of the device.
+ *
+ * @return the product name, or {@code null} if the property could not be read
+ */
+ public @Nullable String getProductName() {
+ return mProductName;
+ }
+
+ /**
+ * Returns the version number of the device.
+ *
+ * @return the device version
+ */
+ public @NonNull String getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Returns the serial number of the device.
+ *
+ * @return the serial number name, or {@code null} if the property could not be read
+ */
+ public @Nullable String getSerialNumber() {
+ return mSerialNumber;
+ }
+
+ /**
+ * Returns a unique integer ID for the device.
+ * This is a convenience for clients that want to use an integer to represent
+ * the device, rather than the device name.
+ * IDs are not persistent across USB disconnects.
+ *
+ * @return the device ID
+ */
+ public int getDeviceId() {
+ return getDeviceId(mName);
+ }
+
+ /**
+ * Returns a vendor ID for the device.
+ *
+ * @return the device vendor ID
+ */
+ public int getVendorId() {
+ return mVendorId;
+ }
+
+ /**
+ * Returns a product ID for the device.
+ *
+ * @return the device product ID
+ */
+ public int getProductId() {
+ return mProductId;
+ }
+
+ /**
+ * Returns the devices's class field.
+ * Some useful constants for USB device classes can be found in {@link UsbConstants}.
+ *
+ * @return the devices's class
+ */
+ public int getDeviceClass() {
+ return mClass;
+ }
+
+ /**
+ * Returns the device's subclass field.
+ *
+ * @return the device's subclass
+ */
+ public int getDeviceSubclass() {
+ return mSubclass;
+ }
+
+ /**
+ * Returns the device's protocol field.
+ *
+ * @return the device's protocol
+ */
+ public int getDeviceProtocol() {
+ return mProtocol;
+ }
+
+ /**
+ * Returns the number of {@link UsbConfiguration}s this device contains.
+ *
+ * @return the number of configurations
+ */
+ public int getConfigurationCount() {
+ return mConfigurations.length;
+ }
+
+ /**
+ * Returns the {@link UsbConfiguration} at the given index.
+ *
+ * @return the configuration
+ */
+ public @NonNull UsbConfiguration getConfiguration(int index) {
+ return (UsbConfiguration)mConfigurations[index];
+ }
+
+ private @Nullable UsbInterface[] getInterfaceList() {
+ if (mInterfaces == null) {
+ int configurationCount = mConfigurations.length;
+ int interfaceCount = 0;
+ for (int i = 0; i < configurationCount; i++) {
+ UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i];
+ interfaceCount += configuration.getInterfaceCount();
+ }
+
+ mInterfaces = new UsbInterface[interfaceCount];
+ int offset = 0;
+ for (int i = 0; i < configurationCount; i++) {
+ UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i];
+ interfaceCount = configuration.getInterfaceCount();
+ for (int j = 0; j < interfaceCount; j++) {
+ mInterfaces[offset++] = configuration.getInterface(j);
+ }
+ }
+ }
+
+ return mInterfaces;
+ }
+
+ /**
+ * Returns the number of {@link UsbInterface}s this device contains.
+ * For devices with multiple configurations, you will probably want to use
+ * {@link UsbConfiguration#getInterfaceCount} instead.
+ *
+ * @return the number of interfaces
+ */
+ public int getInterfaceCount() {
+ return getInterfaceList().length;
+ }
+
+ /**
+ * Returns the {@link UsbInterface} at the given index.
+ * For devices with multiple configurations, you will probably want to use
+ * {@link UsbConfiguration#getInterface} instead.
+ *
+ * @return the interface
+ */
+ public @NonNull UsbInterface getInterface(int index) {
+ return getInterfaceList()[index];
+ }
+
+ /**
+ * Only used by UsbService implementation
+ * @hide
+ */
+ public void setConfigurations(@NonNull Parcelable[] configuration) {
+ mConfigurations = Preconditions.checkArrayElementsNotNull(configuration, "configuration");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof UsbDevice) {
+ return ((UsbDevice)o).mName.equals(mName);
+ } else if (o instanceof String) {
+ return ((String)o).equals(mName);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return mName.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("UsbDevice[mName=" + mName +
+ ",mVendorId=" + mVendorId + ",mProductId=" + mProductId +
+ ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
+ ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName +
+ ",mVersion=" + mVersion + ",mSerialNumber=" + mSerialNumber + ",mConfigurations=[");
+ for (int i = 0; i < mConfigurations.length; i++) {
+ builder.append("\n");
+ builder.append(mConfigurations[i].toString());
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+ public static final Parcelable.Creator<UsbDevice> CREATOR =
+ new Parcelable.Creator<UsbDevice>() {
+ public UsbDevice createFromParcel(Parcel in) {
+ String name = in.readString();
+ int vendorId = in.readInt();
+ int productId = in.readInt();
+ int clasz = in.readInt();
+ int subClass = in.readInt();
+ int protocol = in.readInt();
+ String manufacturerName = in.readString();
+ String productName = in.readString();
+ String version = in.readString();
+ String serialNumber = in.readString();
+ Parcelable[] configurations = in.readParcelableArray(UsbInterface.class.getClassLoader());
+ UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol,
+ manufacturerName, productName, version, serialNumber);
+ device.setConfigurations(configurations);
+ return device;
+ }
+
+ public UsbDevice[] newArray(int size) {
+ return new UsbDevice[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mName);
+ parcel.writeInt(mVendorId);
+ parcel.writeInt(mProductId);
+ parcel.writeInt(mClass);
+ parcel.writeInt(mSubclass);
+ parcel.writeInt(mProtocol);
+ parcel.writeString(mManufacturerName);
+ parcel.writeString(mProductName);
+ parcel.writeString(mVersion);
+ parcel.writeString(mSerialNumber);
+ parcel.writeParcelableArray(mConfigurations, 0);
+ }
+
+ public static int getDeviceId(String name) {
+ return native_get_device_id(name);
+ }
+
+ public static String getDeviceName(int id) {
+ return native_get_device_name(id);
+ }
+
+ private static native int native_get_device_id(String name);
+ private static native String native_get_device_name(int id);
+}
diff --git a/android/hardware/usb/UsbDeviceConnection.java b/android/hardware/usb/UsbDeviceConnection.java
new file mode 100644
index 00000000..5b15c0d2
--- /dev/null
+++ b/android/hardware/usb/UsbDeviceConnection.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+
+import com.android.internal.util.Preconditions;
+
+import dalvik.system.CloseGuard;
+
+import java.io.FileDescriptor;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This class is used for sending and receiving data and control messages to a USB device.
+ * Instances of this class are created by {@link UsbManager#openDevice}.
+ */
+public class UsbDeviceConnection {
+
+ private static final String TAG = "UsbDeviceConnection";
+
+ private final UsbDevice mDevice;
+
+ private Context mContext;
+
+ // used by the JNI code
+ private long mNativeContext;
+
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ /**
+ * UsbDevice should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbDeviceConnection(UsbDevice device) {
+ mDevice = device;
+ }
+
+ /* package */ boolean open(String name, ParcelFileDescriptor pfd, @NonNull Context context) {
+ mContext = context.getApplicationContext();
+ boolean wasOpened = native_open(name, pfd.getFileDescriptor());
+
+ if (wasOpened) {
+ mCloseGuard.open("close");
+ }
+
+ return wasOpened;
+ }
+
+ /**
+ * @return The application context the connection was created for.
+ *
+ * @hide
+ */
+ public @Nullable Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Releases all system resources related to the device.
+ * Once the object is closed it cannot be used again.
+ * The client must call {@link UsbManager#openDevice} again
+ * to retrieve a new instance to reestablish communication with the device.
+ */
+ public void close() {
+ if (mNativeContext != 0) {
+ native_close();
+ mCloseGuard.close();
+ }
+ }
+
+ /**
+ * Returns the native file descriptor for the device, or
+ * -1 if the device is not opened.
+ * This is intended for passing to native code to access the device.
+ *
+ * @return the native file descriptor
+ */
+ public int getFileDescriptor() {
+ return native_get_fd();
+ }
+
+ /**
+ * Returns the raw USB descriptors for the device.
+ * This can be used to access descriptors not supported directly
+ * via the higher level APIs.
+ *
+ * @return raw USB descriptors
+ */
+ public byte[] getRawDescriptors() {
+ return native_get_desc();
+ }
+
+ /**
+ * Claims exclusive access to a {@link android.hardware.usb.UsbInterface}.
+ * This must be done before sending or receiving data on any
+ * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface.
+ *
+ * @param intf the interface to claim
+ * @param force true to disconnect kernel driver if necessary
+ * @return true if the interface was successfully claimed
+ */
+ public boolean claimInterface(UsbInterface intf, boolean force) {
+ return native_claim_interface(intf.getId(), force);
+ }
+
+ /**
+ * Releases exclusive access to a {@link android.hardware.usb.UsbInterface}.
+ *
+ * @return true if the interface was successfully released
+ */
+ public boolean releaseInterface(UsbInterface intf) {
+ return native_release_interface(intf.getId());
+ }
+
+ /**
+ * Sets the current {@link android.hardware.usb.UsbInterface}.
+ * Used to select between two interfaces with the same ID but different alternate setting.
+ *
+ * @return true if the interface was successfully selected
+ */
+ public boolean setInterface(UsbInterface intf) {
+ return native_set_interface(intf.getId(), intf.getAlternateSetting());
+ }
+
+ /**
+ * Sets the device's current {@link android.hardware.usb.UsbConfiguration}.
+ *
+ * @return true if the configuration was successfully set
+ */
+ public boolean setConfiguration(UsbConfiguration configuration) {
+ return native_set_configuration(configuration.getId());
+ }
+
+ /**
+ * Performs a control transaction on endpoint zero for this device.
+ * The direction of the transfer is determined by the request type.
+ * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
+ * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
+ * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
+ * is a read.
+ * <p>
+ * This method transfers data starting from index 0 in the buffer.
+ * To specify a different offset, use
+ * {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}.
+ * </p>
+ *
+ * @param requestType request type for this transaction
+ * @param request request ID for this transaction
+ * @param value value field for this transaction
+ * @param index index field for this transaction
+ * @param buffer buffer for data portion of transaction,
+ * or null if no data needs to be sent or received
+ * @param length the length of the data to send or receive
+ * @param timeout in milliseconds
+ * @return length of data transferred (or zero) for success,
+ * or negative value for failure
+ */
+ public int controlTransfer(int requestType, int request, int value,
+ int index, byte[] buffer, int length, int timeout) {
+ return controlTransfer(requestType, request, value, index, buffer, 0, length, timeout);
+ }
+
+ /**
+ * Performs a control transaction on endpoint zero for this device.
+ * The direction of the transfer is determined by the request type.
+ * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
+ * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
+ * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
+ * is a read.
+ *
+ * @param requestType request type for this transaction
+ * @param request request ID for this transaction
+ * @param value value field for this transaction
+ * @param index index field for this transaction
+ * @param buffer buffer for data portion of transaction,
+ * or null if no data needs to be sent or received
+ * @param offset the index of the first byte in the buffer to send or receive
+ * @param length the length of the data to send or receive
+ * @param timeout in milliseconds
+ * @return length of data transferred (or zero) for success,
+ * or negative value for failure
+ */
+ public int controlTransfer(int requestType, int request, int value, int index,
+ byte[] buffer, int offset, int length, int timeout) {
+ checkBounds(buffer, offset, length);
+ return native_control_request(requestType, request, value, index,
+ buffer, offset, length, timeout);
+ }
+
+ /**
+ * Performs a bulk transaction on the given endpoint.
+ * The direction of the transfer is determined by the direction of the endpoint.
+ * <p>
+ * This method transfers data starting from index 0 in the buffer.
+ * To specify a different offset, use
+ * {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)}.
+ * </p>
+ *
+ * @param endpoint the endpoint for this transaction
+ * @param buffer buffer for data to send or receive; can be {@code null} to wait for next
+ * transaction without reading data
+ * @param length the length of the data to send or receive
+ * @param timeout in milliseconds, 0 is infinite
+ * @return length of data transferred (or zero) for success,
+ * or negative value for failure
+ */
+ public int bulkTransfer(UsbEndpoint endpoint,
+ byte[] buffer, int length, int timeout) {
+ return bulkTransfer(endpoint, buffer, 0, length, timeout);
+ }
+
+ /**
+ * Performs a bulk transaction on the given endpoint.
+ * The direction of the transfer is determined by the direction of the endpoint.
+ *
+ * @param endpoint the endpoint for this transaction
+ * @param buffer buffer for data to send or receive
+ * @param offset the index of the first byte in the buffer to send or receive
+ * @param length the length of the data to send or receive
+ * @param timeout in milliseconds, 0 is infinite
+ * @return length of data transferred (or zero) for success,
+ * or negative value for failure
+ */
+ public int bulkTransfer(UsbEndpoint endpoint,
+ byte[] buffer, int offset, int length, int timeout) {
+ checkBounds(buffer, offset, length);
+ return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout);
+ }
+
+ /**
+ * Reset USB port for the connected device.
+ *
+ * @return true if reset succeeds.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SuppressLint("Doclava125")
+ public boolean resetDevice() {
+ return native_reset_device();
+ }
+
+ /**
+ * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation
+ * <p>Note that this may return requests queued on multiple
+ * {@link android.hardware.usb.UsbEndpoint}s. When multiple endpoints are in use,
+ * {@link android.hardware.usb.UsbRequest#getEndpoint} and {@link
+ * android.hardware.usb.UsbRequest#getClientData} can be useful in determining how to process
+ * the result of this function.</p>
+ *
+ * @return a completed USB request, or null if an error occurred
+ *
+ * @throws IllegalArgumentException Before API {@value Build.VERSION_CODES#O}: if the number of
+ * bytes read or written is more than the limit of the
+ * request's buffer. The number of bytes is determined by the
+ * {@code length} parameter of
+ * {@link UsbRequest#queue(ByteBuffer, int)}
+ * @throws BufferOverflowException In API {@value Build.VERSION_CODES#O} and after: if the
+ * number of bytes read or written is more than the limit of the
+ * request's buffer. The number of bytes is determined by the
+ * {@code length} parameter of
+ * {@link UsbRequest#queue(ByteBuffer, int)}
+ */
+ public UsbRequest requestWait() {
+ UsbRequest request = null;
+ try {
+ // -1 is special value indicating infinite wait
+ request = native_request_wait(-1);
+ } catch (TimeoutException e) {
+ // Does not happen, infinite timeout
+ }
+
+ if (request != null) {
+ request.dequeue(
+ mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O);
+ }
+ return request;
+ }
+
+ /**
+ * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation
+ * <p>Note that this may return requests queued on multiple
+ * {@link android.hardware.usb.UsbEndpoint}s. When multiple endpoints are in use,
+ * {@link android.hardware.usb.UsbRequest#getEndpoint} and {@link
+ * android.hardware.usb.UsbRequest#getClientData} can be useful in determining how to process
+ * the result of this function.</p>
+ * <p>Android processes {@link UsbRequest UsbRequests} asynchronously. Hence it is not
+ * guaranteed that {@link #requestWait(long) requestWait(0)} returns a request that has been
+ * queued right before even if the request could have been processed immediately.</p>
+ *
+ * @param timeout timeout in milliseconds. If 0 this method does not wait.
+ *
+ * @return a completed USB request, or {@code null} if an error occurred
+ *
+ * @throws BufferOverflowException if the number of bytes read or written is more than the
+ * limit of the request's buffer. The number of bytes is
+ * determined by the {@code length} parameter of
+ * {@link UsbRequest#queue(ByteBuffer, int)}
+ * @throws TimeoutException if no request was received in {@code timeout} milliseconds.
+ */
+ public UsbRequest requestWait(long timeout) throws TimeoutException {
+ timeout = Preconditions.checkArgumentNonnegative(timeout, "timeout");
+
+ UsbRequest request = native_request_wait(timeout);
+ if (request != null) {
+ request.dequeue(true);
+ }
+ return request;
+ }
+
+ /**
+ * Returns the serial number for the device.
+ * This will return null if the device has not been opened.
+ *
+ * @return the device serial number
+ */
+ public String getSerial() {
+ return native_get_serial();
+ }
+
+ private static void checkBounds(byte[] buffer, int start, int length) {
+ final int bufferLength = (buffer != null ? buffer.length : 0);
+ if (length < 0 || start < 0 || start + length > bufferLength) {
+ throw new IllegalArgumentException("Buffer start or length out of bounds.");
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private native boolean native_open(String deviceName, FileDescriptor pfd);
+ private native void native_close();
+ private native int native_get_fd();
+ private native byte[] native_get_desc();
+ private native boolean native_claim_interface(int interfaceID, boolean force);
+ private native boolean native_release_interface(int interfaceID);
+ private native boolean native_set_interface(int interfaceID, int alternateSetting);
+ private native boolean native_set_configuration(int configurationID);
+ private native int native_control_request(int requestType, int request, int value,
+ int index, byte[] buffer, int offset, int length, int timeout);
+ private native int native_bulk_request(int endpoint, byte[] buffer,
+ int offset, int length, int timeout);
+ private native UsbRequest native_request_wait(long timeout) throws TimeoutException;
+ private native String native_get_serial();
+ private native boolean native_reset_device();
+}
diff --git a/android/hardware/usb/UsbEndpoint.java b/android/hardware/usb/UsbEndpoint.java
new file mode 100644
index 00000000..c346700a
--- /dev/null
+++ b/android/hardware/usb/UsbEndpoint.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class representing an endpoint on a {@link UsbInterface}.
+ * Endpoints are the channels for sending and receiving data over USB.
+ * Typically bulk endpoints are used for sending non-trivial amounts of data.
+ * Interrupt endpoints are used for sending small amounts of data, typically events,
+ * separately from the main data streams.
+ * The endpoint zero is a special endpoint for control messages sent from the host
+ * to device.
+ * Isochronous endpoints are currently unsupported.
+ */
+public class UsbEndpoint implements Parcelable {
+
+ private final int mAddress;
+ private final int mAttributes;
+ private final int mMaxPacketSize;
+ private final int mInterval;
+
+ /**
+ * UsbEndpoint should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbEndpoint(int address, int attributes, int maxPacketSize, int interval) {
+ mAddress = address;
+ mAttributes = attributes;
+ mMaxPacketSize = maxPacketSize;
+ mInterval = interval;
+ }
+
+ /**
+ * Returns the endpoint's address field.
+ * The address is a bitfield containing both the endpoint number
+ * as well as the data direction of the endpoint.
+ * the endpoint number and direction can also be accessed via
+ * {@link #getEndpointNumber} and {@link #getDirection}.
+ *
+ * @return the endpoint's address
+ */
+ public int getAddress() {
+ return mAddress;
+ }
+
+ /**
+ * Extracts the endpoint's endpoint number from its address
+ *
+ * @return the endpoint's endpoint number
+ */
+ public int getEndpointNumber() {
+ return mAddress & UsbConstants.USB_ENDPOINT_NUMBER_MASK;
+ }
+
+ /**
+ * Returns the endpoint's direction.
+ * Returns {@link UsbConstants#USB_DIR_OUT}
+ * if the direction is host to device, and
+ * {@link UsbConstants#USB_DIR_IN} if the
+ * direction is device to host.
+ * @see UsbConstants#USB_DIR_IN
+ * @see UsbConstants#USB_DIR_OUT
+ *
+ * @return the endpoint's direction
+ */
+ public int getDirection() {
+ return mAddress & UsbConstants.USB_ENDPOINT_DIR_MASK;
+ }
+
+ /**
+ * Returns the endpoint's attributes field.
+ *
+ * @return the endpoint's attributes
+ */
+ public int getAttributes() {
+ return mAttributes;
+ }
+
+ /**
+ * Returns the endpoint's type.
+ * Possible results are:
+ * <ul>
+ * <li>{@link UsbConstants#USB_ENDPOINT_XFER_CONTROL} (endpoint zero)
+ * <li>{@link UsbConstants#USB_ENDPOINT_XFER_ISOC} (isochronous endpoint)
+ * <li>{@link UsbConstants#USB_ENDPOINT_XFER_BULK} (bulk endpoint)
+ * <li>{@link UsbConstants#USB_ENDPOINT_XFER_INT} (interrupt endpoint)
+ * </ul>
+ *
+ * @return the endpoint's type
+ */
+ public int getType() {
+ return mAttributes & UsbConstants.USB_ENDPOINT_XFERTYPE_MASK;
+ }
+
+ /**
+ * Returns the endpoint's maximum packet size.
+ *
+ * @return the endpoint's maximum packet size
+ */
+ public int getMaxPacketSize() {
+ return mMaxPacketSize;
+ }
+
+ /**
+ * Returns the endpoint's interval field.
+ *
+ * @return the endpoint's interval
+ */
+ public int getInterval() {
+ return mInterval;
+ }
+
+ @Override
+ public String toString() {
+ return "UsbEndpoint[mAddress=" + mAddress + ",mAttributes=" + mAttributes +
+ ",mMaxPacketSize=" + mMaxPacketSize + ",mInterval=" + mInterval +"]";
+ }
+
+ public static final Parcelable.Creator<UsbEndpoint> CREATOR =
+ new Parcelable.Creator<UsbEndpoint>() {
+ public UsbEndpoint createFromParcel(Parcel in) {
+ int address = in.readInt();
+ int attributes = in.readInt();
+ int maxPacketSize = in.readInt();
+ int interval = in.readInt();
+ return new UsbEndpoint(address, attributes, maxPacketSize, interval);
+ }
+
+ public UsbEndpoint[] newArray(int size) {
+ return new UsbEndpoint[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mAddress);
+ parcel.writeInt(mAttributes);
+ parcel.writeInt(mMaxPacketSize);
+ parcel.writeInt(mInterval);
+ }
+}
diff --git a/android/hardware/usb/UsbInterface.java b/android/hardware/usb/UsbInterface.java
new file mode 100644
index 00000000..4b5278c7
--- /dev/null
+++ b/android/hardware/usb/UsbInterface.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
+/**
+ * A class representing an interface on a {@link UsbDevice}.
+ * USB devices can have one or more interfaces, each one providing a different
+ * piece of functionality, separate from the other interfaces.
+ * An interface will have one or more {@link UsbEndpoint}s, which are the
+ * channels by which the host transfers data with the device.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about communicating with USB hardware, read the
+ * <a href="{@docRoot}guide/topics/usb/index.html">USB</a> developer guide.</p>
+ * </div>
+ */
+public class UsbInterface implements Parcelable {
+
+ private final int mId;
+ private final int mAlternateSetting;
+ private @Nullable final String mName;
+ private final int mClass;
+ private final int mSubclass;
+ private final int mProtocol;
+
+ /** All endpoints of this interface, only null during creation */
+ private Parcelable[] mEndpoints;
+
+ /**
+ * UsbInterface should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbInterface(int id, int alternateSetting, @Nullable String name,
+ int Class, int subClass, int protocol) {
+ mId = id;
+ mAlternateSetting = alternateSetting;
+ mName = name;
+ mClass = Class;
+ mSubclass = subClass;
+ mProtocol = protocol;
+ }
+
+ /**
+ * Returns the interface's bInterfaceNumber field.
+ * This is an integer that along with the alternate setting uniquely identifies
+ * the interface on the device.
+ *
+ * @return the interface's ID
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the interface's bAlternateSetting field.
+ * This is an integer that along with the ID uniquely identifies
+ * the interface on the device.
+ * {@link UsbDeviceConnection#setInterface} can be used to switch between
+ * two interfaces with the same ID but different alternate setting.
+ *
+ * @return the interface's alternate setting
+ */
+ public int getAlternateSetting() {
+ return mAlternateSetting;
+ }
+
+ /**
+ * Returns the interface's name.
+ *
+ * @return the interface's name, or {@code null} if the property could not be read
+ */
+ public @Nullable String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the interface's class field.
+ * Some useful constants for USB classes can be found in {@link UsbConstants}
+ *
+ * @return the interface's class
+ */
+ public int getInterfaceClass() {
+ return mClass;
+ }
+
+ /**
+ * Returns the interface's subclass field.
+ *
+ * @return the interface's subclass
+ */
+ public int getInterfaceSubclass() {
+ return mSubclass;
+ }
+
+ /**
+ * Returns the interface's protocol field.
+ *
+ * @return the interface's protocol
+ */
+ public int getInterfaceProtocol() {
+ return mProtocol;
+ }
+
+ /**
+ * Returns the number of {@link android.hardware.usb.UsbEndpoint}s this interface contains.
+ *
+ * @return the number of endpoints
+ */
+ public int getEndpointCount() {
+ return mEndpoints.length;
+ }
+
+ /**
+ * Returns the {@link android.hardware.usb.UsbEndpoint} at the given index.
+ *
+ * @return the endpoint
+ */
+ public UsbEndpoint getEndpoint(int index) {
+ return (UsbEndpoint)mEndpoints[index];
+ }
+
+ /**
+ * Only used by UsbService implementation
+ * @hide
+ */
+ public void setEndpoints(Parcelable[] endpoints) {
+ mEndpoints = Preconditions.checkArrayElementsNotNull(endpoints, "endpoints");
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("UsbInterface[mId=" + mId +
+ ",mAlternateSetting=" + mAlternateSetting +
+ ",mName=" + mName + ",mClass=" + mClass +
+ ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
+ ",mEndpoints=[");
+ for (int i = 0; i < mEndpoints.length; i++) {
+ builder.append("\n");
+ builder.append(mEndpoints[i].toString());
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+ public static final Parcelable.Creator<UsbInterface> CREATOR =
+ new Parcelable.Creator<UsbInterface>() {
+ public UsbInterface createFromParcel(Parcel in) {
+ int id = in.readInt();
+ int alternateSetting = in.readInt();
+ String name = in.readString();
+ int Class = in.readInt();
+ int subClass = in.readInt();
+ int protocol = in.readInt();
+ Parcelable[] endpoints = in.readParcelableArray(UsbEndpoint.class.getClassLoader());
+ UsbInterface intf = new UsbInterface(id, alternateSetting, name, Class, subClass, protocol);
+ intf.setEndpoints(endpoints);
+ return intf;
+ }
+
+ public UsbInterface[] newArray(int size) {
+ return new UsbInterface[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mId);
+ parcel.writeInt(mAlternateSetting);
+ parcel.writeString(mName);
+ parcel.writeInt(mClass);
+ parcel.writeInt(mSubclass);
+ parcel.writeInt(mProtocol);
+ parcel.writeParcelableArray(mEndpoints, 0);
+ }
+}
diff --git a/android/hardware/usb/UsbManager.java b/android/hardware/usb/UsbManager.java
new file mode 100644
index 00000000..595d8571
--- /dev/null
+++ b/android/hardware/usb/UsbManager.java
@@ -0,0 +1,737 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.hardware.usb;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.HashMap;
+
+/**
+ * This class allows you to access the state of USB and communicate with USB devices.
+ * Currently only host mode is supported in the public API.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about communicating with USB hardware, read the
+ * <a href="{@docRoot}guide/topics/connectivity/usb/index.html">USB developer guide</a>.</p>
+ * </div>
+ */
+@SystemService(Context.USB_SERVICE)
+public class UsbManager {
+ private static final String TAG = "UsbManager";
+
+ /**
+ * Broadcast Action: A sticky broadcast for USB state change events when in device mode.
+ *
+ * This is a sticky broadcast for clients that includes USB connected/disconnected state,
+ * <ul>
+ * <li> {@link #USB_CONNECTED} boolean indicating whether USB is connected or disconnected.
+ * <li> {@link #USB_HOST_CONNECTED} boolean indicating whether USB is connected or
+ * disconnected as host.
+ * <li> {@link #USB_CONFIGURED} boolean indicating whether USB is configured.
+ * currently zero if not configured, one for configured.
+ * <li> {@link #USB_FUNCTION_ADB} boolean extra indicating whether the
+ * adb function is enabled
+ * <li> {@link #USB_FUNCTION_RNDIS} boolean extra indicating whether the
+ * RNDIS ethernet function is enabled
+ * <li> {@link #USB_FUNCTION_MTP} boolean extra indicating whether the
+ * MTP function is enabled
+ * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the
+ * PTP function is enabled
+ * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the
+ * accessory function is enabled
+ * <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the
+ * audio source function is enabled
+ * <li> {@link #USB_FUNCTION_MIDI} boolean extra indicating whether the
+ * MIDI function is enabled
+ * </ul>
+ * If the sticky intent has not been found, that indicates USB is disconnected,
+ * USB is not configued, MTP function is enabled, and all the other functions are disabled.
+ *
+ * {@hide}
+ */
+ public static final String ACTION_USB_STATE =
+ "android.hardware.usb.action.USB_STATE";
+
+ /**
+ * Broadcast Action: A broadcast for USB port changes.
+ *
+ * This intent is sent when a USB port is added, removed, or changes state.
+ * <ul>
+ * <li> {@link #EXTRA_PORT} containing the {@link android.hardware.usb.UsbPort}
+ * for the port.
+ * <li> {@link #EXTRA_PORT_STATUS} containing the {@link android.hardware.usb.UsbPortStatus}
+ * for the port, or null if the port has been removed
+ * </ul>
+ *
+ * @hide
+ */
+ public static final String ACTION_USB_PORT_CHANGED =
+ "android.hardware.usb.action.USB_PORT_CHANGED";
+
+ /**
+ * Broadcast Action: A broadcast for USB device attached event.
+ *
+ * This intent is sent when a USB device is attached to the USB bus when in host mode.
+ * <ul>
+ * <li> {@link #EXTRA_DEVICE} containing the {@link android.hardware.usb.UsbDevice}
+ * for the attached device
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_DEVICE_ATTACHED =
+ "android.hardware.usb.action.USB_DEVICE_ATTACHED";
+
+ /**
+ * Broadcast Action: A broadcast for USB device detached event.
+ *
+ * This intent is sent when a USB device is detached from the USB bus when in host mode.
+ * <ul>
+ * <li> {@link #EXTRA_DEVICE} containing the {@link android.hardware.usb.UsbDevice}
+ * for the detached device
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_DEVICE_DETACHED =
+ "android.hardware.usb.action.USB_DEVICE_DETACHED";
+
+ /**
+ * Broadcast Action: A broadcast for USB accessory attached event.
+ *
+ * This intent is sent when a USB accessory is attached.
+ * <ul>
+ * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.usb.UsbAccessory}
+ * for the attached accessory
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_ACCESSORY_ATTACHED =
+ "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
+
+ /**
+ * Broadcast Action: A broadcast for USB accessory detached event.
+ *
+ * This intent is sent when a USB accessory is detached.
+ * <ul>
+ * <li> {@link #EXTRA_ACCESSORY} containing the {@link UsbAccessory}
+ * for the attached accessory that was detached
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_ACCESSORY_DETACHED =
+ "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
+
+ /**
+ * Boolean extra indicating whether USB is connected or disconnected.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+ *
+ * {@hide}
+ */
+ public static final String USB_CONNECTED = "connected";
+
+ /**
+ * Boolean extra indicating whether USB is connected or disconnected as host.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+ *
+ * {@hide}
+ */
+ public static final String USB_HOST_CONNECTED = "host_connected";
+
+ /**
+ * Boolean extra indicating whether USB is configured.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+ *
+ * {@hide}
+ */
+ public static final String USB_CONFIGURED = "configured";
+
+ /**
+ * Boolean extra indicating whether confidential user data, such as photos, should be
+ * made available on the USB connection. This variable will only be set when the user
+ * has explicitly asked for this data to be unlocked.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+ *
+ * {@hide}
+ */
+ public static final String USB_DATA_UNLOCKED = "unlocked";
+
+ /**
+ * Boolean extra indicating whether the intent represents a change in the usb
+ * configuration (as opposed to a state update).
+ *
+ * {@hide}
+ */
+ public static final String USB_CONFIG_CHANGED = "config_changed";
+
+ /**
+ * A placeholder indicating that no USB function is being specified.
+ * Used to distinguish between selecting no function vs. the default function in
+ * {@link #setCurrentFunction(String)}.
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_NONE = "none";
+
+ /**
+ * Name of the adb USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_ADB = "adb";
+
+ /**
+ * Name of the RNDIS ethernet USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_RNDIS = "rndis";
+
+ /**
+ * Name of the MTP USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_MTP = "mtp";
+
+ /**
+ * Name of the PTP USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_PTP = "ptp";
+
+ /**
+ * Name of the audio source USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
+
+ /**
+ * Name of the MIDI USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_MIDI = "midi";
+
+ /**
+ * Name of the Accessory USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_ACCESSORY = "accessory";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_PORT_CHANGED}
+ * containing the {@link UsbPort} object for the port.
+ *
+ * @hide
+ */
+ public static final String EXTRA_PORT = "port";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_PORT_CHANGED}
+ * containing the {@link UsbPortStatus} object for the port, or null if the port
+ * was removed.
+ *
+ * @hide
+ */
+ public static final String EXTRA_PORT_STATUS = "portStatus";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} and
+ * {@link #ACTION_USB_DEVICE_DETACHED} broadcasts
+ * containing the {@link UsbDevice} object for the device.
+ */
+ public static final String EXTRA_DEVICE = "device";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} and
+ * {@link #ACTION_USB_ACCESSORY_DETACHED} broadcasts
+ * containing the {@link UsbAccessory} object for the accessory.
+ */
+ public static final String EXTRA_ACCESSORY = "accessory";
+
+ /**
+ * Name of extra added to the {@link android.app.PendingIntent}
+ * passed into {@link #requestPermission(UsbDevice, PendingIntent)}
+ * or {@link #requestPermission(UsbAccessory, PendingIntent)}
+ * containing a boolean value indicating whether the user granted permission or not.
+ */
+ public static final String EXTRA_PERMISSION_GRANTED = "permission";
+
+ private final Context mContext;
+ private final IUsbManager mService;
+
+ /**
+ * {@hide}
+ */
+ public UsbManager(Context context, IUsbManager service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Returns a HashMap containing all USB devices currently attached.
+ * USB device name is the key for the returned HashMap.
+ * The result will be empty if no devices are attached, or if
+ * USB host mode is inactive or unsupported.
+ *
+ * @return HashMap containing all connected USB devices.
+ */
+ public HashMap<String,UsbDevice> getDeviceList() {
+ HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>();
+ if (mService == null) {
+ return result;
+ }
+ Bundle bundle = new Bundle();
+ try {
+ mService.getDeviceList(bundle);
+ for (String name : bundle.keySet()) {
+ result.put(name, (UsbDevice)bundle.get(name));
+ }
+ return result;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Opens the device so it can be used to send and receive
+ * data using {@link android.hardware.usb.UsbRequest}.
+ *
+ * @param device the device to open
+ * @return a {@link UsbDeviceConnection}, or {@code null} if open failed
+ */
+ public UsbDeviceConnection openDevice(UsbDevice device) {
+ try {
+ String deviceName = device.getDeviceName();
+ ParcelFileDescriptor pfd = mService.openDevice(deviceName);
+ if (pfd != null) {
+ UsbDeviceConnection connection = new UsbDeviceConnection(device);
+ boolean result = connection.open(deviceName, pfd, mContext);
+ pfd.close();
+ if (result) {
+ return connection;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "exception in UsbManager.openDevice", e);
+ }
+ return null;
+ }
+
+ /**
+ * Returns a list of currently attached USB accessories.
+ * (in the current implementation there can be at most one)
+ *
+ * @return list of USB accessories, or null if none are attached.
+ */
+ public UsbAccessory[] getAccessoryList() {
+ if (mService == null) {
+ return null;
+ }
+ try {
+ UsbAccessory accessory = mService.getCurrentAccessory();
+ if (accessory == null) {
+ return null;
+ } else {
+ return new UsbAccessory[] { accessory };
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Opens a file descriptor for reading and writing data to the USB accessory.
+ *
+ * @param accessory the USB accessory to open
+ * @return file descriptor, or null if the accessor could not be opened.
+ */
+ public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
+ try {
+ return mService.openAccessory(accessory);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns true if the caller has permission to access the device.
+ * Permission might have been granted temporarily via
+ * {@link #requestPermission(UsbDevice, PendingIntent)} or
+ * by the user choosing the caller as the default application for the device.
+ *
+ * @param device to check permissions for
+ * @return true if caller has permission
+ */
+ public boolean hasPermission(UsbDevice device) {
+ if (mService == null) {
+ return false;
+ }
+ try {
+ return mService.hasDevicePermission(device);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns true if the caller has permission to access the accessory.
+ * Permission might have been granted temporarily via
+ * {@link #requestPermission(UsbAccessory, PendingIntent)} or
+ * by the user choosing the caller as the default application for the accessory.
+ *
+ * @param accessory to check permissions for
+ * @return true if caller has permission
+ */
+ public boolean hasPermission(UsbAccessory accessory) {
+ if (mService == null) {
+ return false;
+ }
+ try {
+ return mService.hasAccessoryPermission(accessory);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Requests temporary permission for the given package to access the device.
+ * This may result in a system dialog being displayed to the user
+ * if permission had not already been granted.
+ * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+ * If successful, this grants the caller permission to access the device only
+ * until the device is disconnected.
+ *
+ * The following extras will be added to pi:
+ * <ul>
+ * <li> {@link #EXTRA_DEVICE} containing the device passed into this call
+ * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
+ * permission was granted by the user
+ * </ul>
+ *
+ * @param device to request permissions for
+ * @param pi PendingIntent for returning result
+ */
+ public void requestPermission(UsbDevice device, PendingIntent pi) {
+ try {
+ mService.requestDevicePermission(device, mContext.getPackageName(), pi);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Requests temporary permission for the given package to access the accessory.
+ * This may result in a system dialog being displayed to the user
+ * if permission had not already been granted.
+ * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+ * If successful, this grants the caller permission to access the accessory only
+ * until the device is disconnected.
+ *
+ * The following extras will be added to pi:
+ * <ul>
+ * <li> {@link #EXTRA_ACCESSORY} containing the accessory passed into this call
+ * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
+ * permission was granted by the user
+ * </ul>
+ *
+ * @param accessory to request permissions for
+ * @param pi PendingIntent for returning result
+ */
+ public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
+ try {
+ mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Grants permission for USB device without showing system dialog.
+ * Only system components can call this function.
+ * @param device to request permissions for
+ *
+ * {@hide}
+ */
+ public void grantPermission(UsbDevice device) {
+ grantPermission(device, Process.myUid());
+ }
+
+ /**
+ * Grants permission for USB device to given uid without showing system dialog.
+ * Only system components can call this function.
+ * @param device to request permissions for
+ * @uid uid to give permission
+ *
+ * {@hide}
+ */
+ public void grantPermission(UsbDevice device, int uid) {
+ try {
+ mService.grantDevicePermission(device, uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Grants permission to specified package for USB device without showing system dialog.
+ * Only system components can call this function, as it requires the MANAGE_USB permission.
+ * @param device to request permissions for
+ * @param packageName of package to grant permissions
+ *
+ * {@hide}
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
+ public void grantPermission(UsbDevice device, String packageName) {
+ try {
+ int uid = mContext.getPackageManager()
+ .getPackageUidAsUser(packageName, mContext.getUserId());
+ grantPermission(device, uid);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Package " + packageName + " not found.", e);
+ }
+ }
+
+ /**
+ * Returns true if the specified USB function is currently enabled when in device mode.
+ * <p>
+ * USB functions represent interfaces which are published to the host to access
+ * services offered by the device.
+ * </p>
+ *
+ * @param function name of the USB function
+ * @return true if the USB function is enabled
+ *
+ * {@hide}
+ */
+ public boolean isFunctionEnabled(String function) {
+ if (mService == null) {
+ return false;
+ }
+ try {
+ return mService.isFunctionEnabled(function);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the current USB function when in device mode.
+ * <p>
+ * USB functions represent interfaces which are published to the host to access
+ * services offered by the device.
+ * </p><p>
+ * This method is intended to select among primary USB functions. The system may
+ * automatically activate additional functions such as {@link #USB_FUNCTION_ADB}
+ * or {@link #USB_FUNCTION_ACCESSORY} based on other settings and states.
+ * </p><p>
+ * The allowed values are: {@link #USB_FUNCTION_NONE}, {@link #USB_FUNCTION_AUDIO_SOURCE},
+ * {@link #USB_FUNCTION_MIDI}, {@link #USB_FUNCTION_MTP}, {@link #USB_FUNCTION_PTP},
+ * or {@link #USB_FUNCTION_RNDIS}.
+ * </p><p>
+ * Also sets whether USB data (for example, MTP exposed pictures) should be made available
+ * on the USB connection when in device mode. Unlocking usb data should only be done with
+ * user involvement, since exposing pictures or other data could leak sensitive
+ * user information.
+ * </p><p>
+ * Note: This function is asynchronous and may fail silently without applying
+ * the requested changes.
+ * </p>
+ *
+ * @param function name of the USB function, or null to restore the default function
+ * @param usbDataUnlocked whether user data is accessible
+ *
+ * {@hide}
+ */
+ public void setCurrentFunction(String function, boolean usbDataUnlocked) {
+ try {
+ mService.setCurrentFunction(function, usbDataUnlocked);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns a list of physical USB ports on the device.
+ * <p>
+ * This list is guaranteed to contain all dual-role USB Type C ports but it might
+ * be missing other ports depending on whether the kernel USB drivers have been
+ * updated to publish all of the device's ports through the new "dual_role_usb"
+ * device class (which supports all types of ports despite its name).
+ * </p>
+ *
+ * @return The list of USB ports, or null if none.
+ *
+ * @hide
+ */
+ public UsbPort[] getPorts() {
+ if (mService == null) {
+ return null;
+ }
+ try {
+ return mService.getPorts();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the status of the specified USB port.
+ *
+ * @param port The port to query.
+ * @return The status of the specified USB port, or null if unknown.
+ *
+ * @hide
+ */
+ public UsbPortStatus getPortStatus(UsbPort port) {
+ Preconditions.checkNotNull(port, "port must not be null");
+
+ try {
+ return mService.getPortStatus(port.getId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the desired role combination of the port.
+ * <p>
+ * The supported role combinations depend on what is connected to the port and may be
+ * determined by consulting
+ * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}.
+ * </p><p>
+ * Note: This function is asynchronous and may fail silently without applying
+ * the requested changes. If this function does cause a status change to occur then
+ * a {@link #ACTION_USB_PORT_CHANGED} broadcast will be sent.
+ * </p>
+ *
+ * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE}
+ * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role.
+ * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST}
+ * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role.
+ *
+ * @hide
+ */
+ public void setPortRoles(UsbPort port, int powerRole, int dataRole) {
+ Preconditions.checkNotNull(port, "port must not be null");
+ UsbPort.checkRoles(powerRole, dataRole);
+
+ Log.d(TAG, "setPortRoles Package:" + mContext.getPackageName());
+ try {
+ mService.setPortRoles(port.getId(), powerRole, dataRole);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the component that will handle USB device connection.
+ * <p>
+ * Setting component allows to specify external USB host manager to handle use cases, where
+ * selection dialog for an activity that will handle USB device is undesirable.
+ * Only system components can call this function, as it requires the MANAGE_USB permission.
+ *
+ * @param usbDeviceConnectionHandler The component to handle usb connections,
+ * {@code null} to unset.
+ *
+ * {@hide}
+ */
+ public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
+ try {
+ mService.setUsbDeviceConnectionHandler(usbDeviceConnectionHandler);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public static String addFunction(String functions, String function) {
+ if (USB_FUNCTION_NONE.equals(functions)) {
+ return function;
+ }
+ if (!containsFunction(functions, function)) {
+ if (functions.length() > 0) {
+ functions += ",";
+ }
+ functions += function;
+ }
+ return functions;
+ }
+
+ /** @hide */
+ public static String removeFunction(String functions, String function) {
+ String[] split = functions.split(",");
+ for (int i = 0; i < split.length; i++) {
+ if (function.equals(split[i])) {
+ split[i] = null;
+ }
+ }
+ if (split.length == 1 && split[0] == null) {
+ return USB_FUNCTION_NONE;
+ }
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < split.length; i++) {
+ String s = split[i];
+ if (s != null) {
+ if (builder.length() > 0) {
+ builder.append(",");
+ }
+ builder.append(s);
+ }
+ }
+ return builder.toString();
+ }
+
+ /** @hide */
+ public static boolean containsFunction(String functions, String function) {
+ int index = functions.indexOf(function);
+ if (index < 0) return false;
+ if (index > 0 && functions.charAt(index - 1) != ',') return false;
+ int charAfter = index + function.length();
+ if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
+ return true;
+ }
+}
diff --git a/android/hardware/usb/UsbPort.java b/android/hardware/usb/UsbPort.java
new file mode 100644
index 00000000..afdb2022
--- /dev/null
+++ b/android/hardware/usb/UsbPort.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.hardware.usb.V1_0.Constants;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Represents a physical USB port and describes its characteristics.
+ * <p>
+ * This object is immutable.
+ * </p>
+ *
+ * @hide
+ */
+public final class UsbPort implements Parcelable {
+ private final String mId;
+ private final int mSupportedModes;
+
+ public static final int MODE_NONE = Constants.PortMode.NONE;
+ /**
+ * Mode bit: This USB port can act as a downstream facing port (host).
+ * <p>
+ * Implies that the port supports the {@link #POWER_ROLE_SOURCE} and {@link #DATA_ROLE_HOST}
+ * combination of roles (and possibly others as well).
+ * </p>
+ */
+ public static final int MODE_DFP = Constants.PortMode.DFP;
+
+ /**
+ * Mode bit: This USB port can act as an upstream facing port (device).
+ * <p>
+ * Implies that the port supports the {@link #POWER_ROLE_SINK} and {@link #DATA_ROLE_DEVICE}
+ * combination of roles (and possibly others as well).
+ * </p>
+ */
+ public static final int MODE_UFP = Constants.PortMode.UFP;
+
+ /**
+ * Mode bit: This USB port can act either as an downstream facing port (host) or as
+ * an upstream facing port (device).
+ * <p>
+ * Implies that the port supports the {@link #POWER_ROLE_SOURCE} and {@link #DATA_ROLE_HOST}
+ * combination of roles and the {@link #POWER_ROLE_SINK} and {@link #DATA_ROLE_DEVICE}
+ * combination of roles (and possibly others as well).
+ * </p>
+ */
+ public static final int MODE_DUAL = Constants.PortMode.DRP;
+
+ /**
+ * Mode bit: This USB port can support USB Type-C Audio accessory.
+ */
+ public static final int MODE_AUDIO_ACCESSORY =
+ android.hardware.usb.V1_1.Constants.PortMode_1_1.AUDIO_ACCESSORY;
+
+ /**
+ * Mode bit: This USB port can support USB Type-C debug accessory.
+ */
+ public static final int MODE_DEBUG_ACCESSORY =
+ android.hardware.usb.V1_1.Constants.PortMode_1_1.DEBUG_ACCESSORY;
+
+ /**
+ * Power role: This USB port does not have a power role.
+ */
+ public static final int POWER_ROLE_NONE = Constants.PortPowerRole.NONE;
+
+ /**
+ * Power role: This USB port can act as a source (provide power).
+ */
+ public static final int POWER_ROLE_SOURCE = Constants.PortPowerRole.SOURCE;
+
+ /**
+ * Power role: This USB port can act as a sink (receive power).
+ */
+ public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK;
+
+ /**
+ * Power role: This USB port does not have a data role.
+ */
+ public static final int DATA_ROLE_NONE = Constants.PortDataRole.NONE;
+
+ /**
+ * Data role: This USB port can act as a host (access data services).
+ */
+ public static final int DATA_ROLE_HOST = Constants.PortDataRole.HOST;
+
+ /**
+ * Data role: This USB port can act as a device (offer data services).
+ */
+ public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE;
+
+ private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES;
+ /**
+ * Points to the first power role in the IUsb HAL.
+ */
+ private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE;
+
+ /** @hide */
+ public UsbPort(String id, int supportedModes) {
+ mId = id;
+ mSupportedModes = supportedModes;
+ }
+
+ /**
+ * Gets the unique id of the port.
+ *
+ * @return The unique id of the port; not intended for display.
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Gets the supported modes of the port.
+ * <p>
+ * The actual mode of the port may vary depending on what is plugged into it.
+ * </p>
+ *
+ * @return The supported modes: one of {@link #MODE_DFP}, {@link #MODE_UFP}, or
+ * {@link #MODE_DUAL}.
+ */
+ public int getSupportedModes() {
+ return mSupportedModes;
+ }
+
+ /**
+ * Combines one power and one data role together into a unique value with
+ * exactly one bit set. This can be used to efficiently determine whether
+ * a combination of roles is supported by testing whether that bit is present
+ * in a bit-field.
+ *
+ * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE}
+ * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role.
+ * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST}
+ * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role.
+ * @hide
+ */
+ public static int combineRolesAsBit(int powerRole, int dataRole) {
+ checkRoles(powerRole, dataRole);
+ final int index = ((powerRole - POWER_ROLE_OFFSET) * NUM_DATA_ROLES) + dataRole;
+ return 1 << index;
+ }
+
+ /** @hide */
+ public static String modeToString(int mode) {
+ StringBuilder modeString = new StringBuilder();
+ if (mode == MODE_NONE) {
+ return "none";
+ }
+
+ if ((mode & MODE_DUAL) == MODE_DUAL) {
+ modeString.append("dual, ");
+ } else {
+ if ((mode & MODE_DFP) == MODE_DFP) {
+ modeString.append("dfp, ");
+ } else if ((mode & MODE_UFP) == MODE_UFP) {
+ modeString.append("ufp, ");
+ }
+ }
+ if ((mode & MODE_AUDIO_ACCESSORY) == MODE_AUDIO_ACCESSORY) {
+ modeString.append("audio_acc, ");
+ }
+ if ((mode & MODE_DEBUG_ACCESSORY) == MODE_DEBUG_ACCESSORY) {
+ modeString.append("debug_acc, ");
+ }
+
+ if (modeString.length() == 0) {
+ return Integer.toString(mode);
+ }
+ return modeString.substring(0, modeString.length() - 2);
+ }
+
+ /** @hide */
+ public static String powerRoleToString(int role) {
+ switch (role) {
+ case POWER_ROLE_NONE:
+ return "no-power";
+ case POWER_ROLE_SOURCE:
+ return "source";
+ case POWER_ROLE_SINK:
+ return "sink";
+ default:
+ return Integer.toString(role);
+ }
+ }
+
+ /** @hide */
+ public static String dataRoleToString(int role) {
+ switch (role) {
+ case DATA_ROLE_NONE:
+ return "no-data";
+ case DATA_ROLE_HOST:
+ return "host";
+ case DATA_ROLE_DEVICE:
+ return "device";
+ default:
+ return Integer.toString(role);
+ }
+ }
+
+ /** @hide */
+ public static String roleCombinationsToString(int combo) {
+ StringBuilder result = new StringBuilder();
+ result.append("[");
+
+ boolean first = true;
+ while (combo != 0) {
+ final int index = Integer.numberOfTrailingZeros(combo);
+ combo &= ~(1 << index);
+ final int powerRole = (index / NUM_DATA_ROLES + POWER_ROLE_OFFSET);
+ final int dataRole = index % NUM_DATA_ROLES;
+ if (first) {
+ first = false;
+ } else {
+ result.append(", ");
+ }
+ result.append(powerRoleToString(powerRole));
+ result.append(':');
+ result.append(dataRoleToString(dataRole));
+ }
+
+ result.append("]");
+ return result.toString();
+ }
+
+ /** @hide */
+ public static void checkMode(int powerRole) {
+ Preconditions.checkArgumentInRange(powerRole, Constants.PortMode.NONE,
+ Constants.PortMode.NUM_MODES - 1, "portMode");
+ }
+
+ /** @hide */
+ public static void checkPowerRole(int dataRole) {
+ Preconditions.checkArgumentInRange(dataRole, Constants.PortPowerRole.NONE,
+ Constants.PortPowerRole.NUM_POWER_ROLES - 1, "powerRole");
+ }
+
+ /** @hide */
+ public static void checkDataRole(int mode) {
+ Preconditions.checkArgumentInRange(mode, Constants.PortDataRole.NONE,
+ Constants.PortDataRole.NUM_DATA_ROLES - 1, "powerRole");
+ }
+
+ /** @hide */
+ public static void checkRoles(int powerRole, int dataRole) {
+ Preconditions.checkArgumentInRange(powerRole, POWER_ROLE_NONE, POWER_ROLE_SINK,
+ "powerRole");
+ Preconditions.checkArgumentInRange(dataRole, DATA_ROLE_NONE, DATA_ROLE_DEVICE, "dataRole");
+ }
+
+ /** @hide */
+ public boolean isModeSupported(int mode) {
+ if ((mSupportedModes & mode) == mode) return true;
+ return false;
+ }
+
+
+ @Override
+ public String toString() {
+ return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes) + "}";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mId);
+ dest.writeInt(mSupportedModes);
+ }
+
+ public static final Parcelable.Creator<UsbPort> CREATOR =
+ new Parcelable.Creator<UsbPort>() {
+ @Override
+ public UsbPort createFromParcel(Parcel in) {
+ String id = in.readString();
+ int supportedModes = in.readInt();
+ return new UsbPort(id, supportedModes);
+ }
+
+ @Override
+ public UsbPort[] newArray(int size) {
+ return new UsbPort[size];
+ }
+ };
+}
diff --git a/android/hardware/usb/UsbPortStatus.java b/android/hardware/usb/UsbPortStatus.java
new file mode 100644
index 00000000..5c0e81ad
--- /dev/null
+++ b/android/hardware/usb/UsbPortStatus.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Describes the status of a USB port.
+ * <p>
+ * This object is immutable.
+ * </p>
+ *
+ * @hide
+ */
+public final class UsbPortStatus implements Parcelable {
+ private final int mCurrentMode;
+ private final int mCurrentPowerRole;
+ private final int mCurrentDataRole;
+ private final int mSupportedRoleCombinations;
+
+ /** @hide */
+ public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
+ int supportedRoleCombinations) {
+ mCurrentMode = currentMode;
+ mCurrentPowerRole = currentPowerRole;
+ mCurrentDataRole = currentDataRole;
+ mSupportedRoleCombinations = supportedRoleCombinations;
+ }
+
+ /**
+ * Returns true if there is anything connected to the port.
+ *
+ * @return True if there is anything connected to the port.
+ */
+ public boolean isConnected() {
+ return mCurrentMode != 0;
+ }
+
+ /**
+ * Gets the current mode of the port.
+ *
+ * @return The current mode: {@link UsbPort#MODE_DFP}, {@link UsbPort#MODE_UFP},
+ * or 0 if nothing is connected.
+ */
+ public int getCurrentMode() {
+ return mCurrentMode;
+ }
+
+ /**
+ * Gets the current power role of the port.
+ *
+ * @return The current power role: {@link UsbPort#POWER_ROLE_SOURCE},
+ * {@link UsbPort#POWER_ROLE_SINK}, or 0 if nothing is connected.
+ */
+ public int getCurrentPowerRole() {
+ return mCurrentPowerRole;
+ }
+
+ /**
+ * Gets the current data role of the port.
+ *
+ * @return The current data role: {@link UsbPort#DATA_ROLE_HOST},
+ * {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if nothing is connected.
+ */
+ public int getCurrentDataRole() {
+ return mCurrentDataRole;
+ }
+
+ /**
+ * Returns true if the specified power and data role combination is supported
+ * given what is currently connected to the port.
+ *
+ * @param powerRole The power role to check: {@link UsbPort#POWER_ROLE_SOURCE}
+ * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role.
+ * @param dataRole The data role to check: either {@link UsbPort#DATA_ROLE_HOST}
+ * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role.
+ */
+ public boolean isRoleCombinationSupported(int powerRole, int dataRole) {
+ return (mSupportedRoleCombinations &
+ UsbPort.combineRolesAsBit(powerRole, dataRole)) != 0;
+ }
+
+ /** @hide */
+ public int getSupportedRoleCombinations() {
+ return mSupportedRoleCombinations;
+ }
+
+ @Override
+ public String toString() {
+ return "UsbPortStatus{connected=" + isConnected()
+ + ", currentMode=" + UsbPort.modeToString(mCurrentMode)
+ + ", currentPowerRole=" + UsbPort.powerRoleToString(mCurrentPowerRole)
+ + ", currentDataRole=" + UsbPort.dataRoleToString(mCurrentDataRole)
+ + ", supportedRoleCombinations="
+ + UsbPort.roleCombinationsToString(mSupportedRoleCombinations)
+ + "}";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mCurrentMode);
+ dest.writeInt(mCurrentPowerRole);
+ dest.writeInt(mCurrentDataRole);
+ dest.writeInt(mSupportedRoleCombinations);
+ }
+
+ public static final Parcelable.Creator<UsbPortStatus> CREATOR =
+ new Parcelable.Creator<UsbPortStatus>() {
+ @Override
+ public UsbPortStatus createFromParcel(Parcel in) {
+ int currentMode = in.readInt();
+ int currentPowerRole = in.readInt();
+ int currentDataRole = in.readInt();
+ int supportedRoleCombinations = in.readInt();
+ return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
+ supportedRoleCombinations);
+ }
+
+ @Override
+ public UsbPortStatus[] newArray(int size) {
+ return new UsbPortStatus[size];
+ }
+ };
+}
diff --git a/android/hardware/usb/UsbRequest.java b/android/hardware/usb/UsbRequest.java
new file mode 100644
index 00000000..2e8f8e12
--- /dev/null
+++ b/android/hardware/usb/UsbRequest.java
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.annotation.Nullable;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import dalvik.system.CloseGuard;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+/**
+ * A class representing USB request packet.
+ * This can be used for both reading and writing data to or from a
+ * {@link android.hardware.usb.UsbDeviceConnection}.
+ * UsbRequests can be used to transfer data on bulk and interrupt endpoints.
+ * Requests on bulk endpoints can be sent synchronously via {@link UsbDeviceConnection#bulkTransfer}
+ * or asynchronously via {@link #queue} and {@link UsbDeviceConnection#requestWait}.
+ * Requests on interrupt endpoints are only send and received asynchronously.
+ *
+ * <p>Requests on endpoint zero are not supported by this class;
+ * use {@link UsbDeviceConnection#controlTransfer} for endpoint zero requests instead.
+ */
+public class UsbRequest {
+
+ private static final String TAG = "UsbRequest";
+
+ // From drivers/usb/core/devio.c
+ private static final int MAX_USBFS_BUFFER_SIZE = 16384;
+
+ // used by the JNI code
+ private long mNativeContext;
+
+ private UsbEndpoint mEndpoint;
+
+ /** The buffer that is currently being read / written */
+ private ByteBuffer mBuffer;
+
+ /** The amount of data to read / write when using {@link #queue} */
+ private int mLength;
+
+ // for client use
+ private Object mClientData;
+
+ // Prevent the connection from being finalized
+ private UsbDeviceConnection mConnection;
+
+ /**
+ * Whether this buffer was {@link #queue(ByteBuffer) queued using the new behavior} or
+ * {@link #queue(ByteBuffer, int) queued using the deprecated behavior}.
+ */
+ private boolean mIsUsingNewQueue;
+
+ /** Temporary buffer than might be used while buffer is enqueued */
+ private ByteBuffer mTempBuffer;
+
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ /**
+ * Lock for queue, enqueue and dequeue, so a queue operation can be finished by a dequeue
+ * operation on a different thread.
+ */
+ private final Object mLock = new Object();
+
+ public UsbRequest() {
+ }
+
+ /**
+ * Initializes the request so it can read or write data on the given endpoint.
+ * Whether the request allows reading or writing depends on the direction of the endpoint.
+ *
+ * @param endpoint the endpoint to be used for this request.
+ * @return true if the request was successfully opened.
+ */
+ public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint) {
+ mEndpoint = endpoint;
+ mConnection = Preconditions.checkNotNull(connection, "connection");
+
+ boolean wasInitialized = native_init(connection, endpoint.getAddress(),
+ endpoint.getAttributes(), endpoint.getMaxPacketSize(), endpoint.getInterval());
+
+ if (wasInitialized) {
+ mCloseGuard.open("close");
+ }
+
+ return wasInitialized;
+ }
+
+ /**
+ * Releases all resources related to this request.
+ */
+ public void close() {
+ if (mNativeContext != 0) {
+ mEndpoint = null;
+ mConnection = null;
+ native_close();
+ mCloseGuard.close();
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Returns the endpoint for the request, or null if the request is not opened.
+ *
+ * @return the request's endpoint
+ */
+ public UsbEndpoint getEndpoint() {
+ return mEndpoint;
+ }
+
+ /**
+ * Returns the client data for the request.
+ * This can be used in conjunction with {@link #setClientData}
+ * to associate another object with this request, which can be useful for
+ * maintaining state between calls to {@link #queue} and
+ * {@link android.hardware.usb.UsbDeviceConnection#requestWait}
+ *
+ * @return the client data for the request
+ */
+ public Object getClientData() {
+ return mClientData;
+ }
+
+ /**
+ * Sets the client data for the request.
+ * This can be used in conjunction with {@link #getClientData}
+ * to associate another object with this request, which can be useful for
+ * maintaining state between calls to {@link #queue} and
+ * {@link android.hardware.usb.UsbDeviceConnection#requestWait}
+ *
+ * @param data the client data for the request
+ */
+ public void setClientData(Object data) {
+ mClientData = data;
+ }
+
+ /**
+ * Queues the request to send or receive data on its endpoint.
+ * <p>For OUT endpoints, the given buffer data will be sent on the endpoint. For IN endpoints,
+ * the endpoint will attempt to read the given number of bytes into the specified buffer. If the
+ * queueing operation is successful, return true. The result will be returned via
+ * {@link UsbDeviceConnection#requestWait}</p>
+ *
+ * @param buffer the buffer containing the bytes to write, or location to store the results of a
+ * read. Position and array offset will be ignored and assumed to be 0. Limit and
+ * capacity will be ignored. Once the request
+ * {@link UsbDeviceConnection#requestWait() is processed} the position will be set
+ * to the number of bytes read/written.
+ * @param length number of bytes to read or write.
+ *
+ * @return true if the queueing operation succeeded
+ *
+ * @deprecated Use {@link #queue(ByteBuffer)} instead.
+ */
+ @Deprecated
+ public boolean queue(ByteBuffer buffer, int length) {
+ boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
+ boolean result;
+
+ synchronized (mLock) {
+ // save our buffer for when the request has completed
+ mBuffer = buffer;
+ mLength = length;
+
+ // Note: On a buffer slice we lost the capacity information about the underlying buffer,
+ // hence we cannot check if the access would be a data leak/memory corruption.
+
+ if (buffer.isDirect()) {
+ result = native_queue_direct(buffer, length, out);
+ } else if (buffer.hasArray()) {
+ result = native_queue_array(buffer.array(), length, out);
+ } else {
+ throw new IllegalArgumentException("buffer is not direct and has no array");
+ }
+ if (!result) {
+ mBuffer = null;
+ mLength = 0;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Queues the request to send or receive data on its endpoint.
+ *
+ * <p>For OUT endpoints, the remaining bytes of the buffer will be sent on the endpoint. For IN
+ * endpoints, the endpoint will attempt to fill the remaining bytes of the buffer. If the
+ * queueing operation is successful, return true. The result will be returned via
+ * {@link UsbDeviceConnection#requestWait}</p>
+ *
+ * @param buffer the buffer containing the bytes to send, or the buffer to fill. The state
+ * of the buffer is undefined until the request is returned by
+ * {@link UsbDeviceConnection#requestWait}. If the request failed the buffer
+ * will be unchanged; if the request succeeded the position of the buffer is
+ * incremented by the number of bytes sent/received.
+ *
+ * @return true if the queueing operation succeeded
+ */
+ public boolean queue(@Nullable ByteBuffer buffer) {
+ // Request need to be initialized
+ Preconditions.checkState(mNativeContext != 0, "request is not initialized");
+
+ // Request can not be currently queued
+ Preconditions.checkState(!mIsUsingNewQueue, "this request is currently queued");
+
+ boolean isSend = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
+ boolean wasQueued;
+
+ synchronized (mLock) {
+ mBuffer = buffer;
+
+ if (buffer == null) {
+ // Null buffers enqueue empty USB requests which is supported
+ mIsUsingNewQueue = true;
+ wasQueued = native_queue(null, 0, 0);
+ } else {
+ // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
+ Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
+ "number of remaining bytes");
+
+ // Can not receive into read-only buffers.
+ Preconditions.checkArgument(!(buffer.isReadOnly() && !isSend), "buffer can not be "
+ + "read-only when receiving data");
+
+ if (!buffer.isDirect()) {
+ mTempBuffer = ByteBuffer.allocateDirect(mBuffer.remaining());
+
+ if (isSend) {
+ // Copy buffer into temporary buffer
+ mBuffer.mark();
+ mTempBuffer.put(mBuffer);
+ mTempBuffer.flip();
+ mBuffer.reset();
+ }
+
+ // Send/Receive into the temp buffer instead
+ buffer = mTempBuffer;
+ }
+
+ mIsUsingNewQueue = true;
+ wasQueued = native_queue(buffer, buffer.position(), buffer.remaining());
+ }
+ }
+
+ if (!wasQueued) {
+ mIsUsingNewQueue = false;
+ mTempBuffer = null;
+ mBuffer = null;
+ }
+
+ return wasQueued;
+ }
+
+ /* package */ void dequeue(boolean useBufferOverflowInsteadOfIllegalArg) {
+ boolean isSend = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
+ int bytesTransferred;
+
+ synchronized (mLock) {
+ if (mIsUsingNewQueue) {
+ bytesTransferred = native_dequeue_direct();
+ mIsUsingNewQueue = false;
+
+ if (mBuffer == null) {
+ // Nothing to do
+ } else if (mTempBuffer == null) {
+ mBuffer.position(mBuffer.position() + bytesTransferred);
+ } else {
+ mTempBuffer.limit(bytesTransferred);
+
+ // The user might have modified mBuffer which might make put/position fail.
+ // Changing the buffer while a request is in flight is not supported. Still,
+ // make sure to free mTempBuffer correctly.
+ try {
+ if (isSend) {
+ mBuffer.position(mBuffer.position() + bytesTransferred);
+ } else {
+ // Copy temp buffer back into original buffer
+ mBuffer.put(mTempBuffer);
+ }
+ } finally {
+ mTempBuffer = null;
+ }
+ }
+ } else {
+ if (mBuffer.isDirect()) {
+ bytesTransferred = native_dequeue_direct();
+ } else {
+ bytesTransferred = native_dequeue_array(mBuffer.array(), mLength, isSend);
+ }
+ if (bytesTransferred >= 0) {
+ int bytesToStore = Math.min(bytesTransferred, mLength);
+ try {
+ mBuffer.position(bytesToStore);
+ } catch (IllegalArgumentException e) {
+ if (useBufferOverflowInsteadOfIllegalArg) {
+ Log.e(TAG, "Buffer " + mBuffer + " does not have enough space to read "
+ + bytesToStore + " bytes", e);
+ throw new BufferOverflowException();
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+
+ mBuffer = null;
+ mLength = 0;
+ }
+ }
+
+ /**
+ * Cancels a pending queue operation.
+ *
+ * @return true if cancelling succeeded
+ */
+ public boolean cancel() {
+ return native_cancel();
+ }
+
+ private native boolean native_init(UsbDeviceConnection connection, int ep_address,
+ int ep_attributes, int ep_max_packet_size, int ep_interval);
+ private native void native_close();
+ private native boolean native_queue(ByteBuffer buffer, int offset, int length);
+ private native boolean native_queue_array(byte[] buffer, int length, boolean out);
+ private native int native_dequeue_array(byte[] buffer, int length, boolean out);
+ private native boolean native_queue_direct(ByteBuffer buffer, int length, boolean out);
+ private native int native_dequeue_direct();
+ private native boolean native_cancel();
+}