summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/app/ContextImpl.java8
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/hardware/IUsbManager.aidl28
-rw-r--r--core/java/android/hardware/UsbConstants.java63
-rw-r--r--core/java/android/hardware/UsbDevice.aidl19
-rw-r--r--core/java/android/hardware/UsbDevice.java314
-rw-r--r--core/java/android/hardware/UsbEndpoint.aidl19
-rw-r--r--core/java/android/hardware/UsbEndpoint.java176
-rw-r--r--core/java/android/hardware/UsbInterface.aidl19
-rw-r--r--core/java/android/hardware/UsbInterface.java159
-rw-r--r--core/java/android/hardware/UsbManager.java139
-rw-r--r--core/java/android/hardware/UsbRequest.java177
-rw-r--r--core/jni/Android.mk3
-rw-r--r--core/jni/AndroidRuntime.cpp4
-rw-r--r--core/jni/android_hardware_UsbDevice.cpp239
-rw-r--r--core/jni/android_hardware_UsbEndpoint.cpp124
-rw-r--r--core/jni/android_hardware_UsbRequest.cpp217
-rw-r--r--core/res/AndroidManifest.xml2
18 files changed, 1717 insertions, 3 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 6f63990..8737e93 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -41,7 +41,9 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.hardware.IUsbManager;
import android.hardware.SensorManager;
+import android.hardware.UsbManager;
import android.location.CountryDetector;
import android.location.ICountryDetector;
import android.location.ILocationManager;
@@ -399,6 +401,12 @@ class ContextImpl extends Context {
return new UiModeManager();
}});
+ registerService(USB_SERVICE, new StaticServiceFetcher() {
+ public Object createStaticService() {
+ IBinder b = ServiceManager.getService(USB_SERVICE);
+ return new UsbManager(IUsbManager.Stub.asInterface(b));
+ }});
+
registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new Vibrator();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d14cf4d..051ae9e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1663,6 +1663,16 @@ public abstract class Context {
public static final String SIP_SERVICE = "sip";
/**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.hardware.UsbManager} for access to USB devices (as a USB host)
+ * and for controlling this device's behavior as a USB device.
+ *
+ * @see #getSystemService
+ * @see android.harware.UsbManager
+ */
+ public static final String USB_SERVICE = "usb";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/hardware/IUsbManager.aidl b/core/java/android/hardware/IUsbManager.aidl
new file mode 100644
index 0000000..b50b6b9
--- /dev/null
+++ b/core/java/android/hardware/IUsbManager.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+/** @hide */
+interface IUsbManager
+{
+ /* Returns a list of all currently attached USB devices */
+ void getDeviceList(out Bundle devices);
+ ParcelFileDescriptor openDevice(String deviceName);
+}
diff --git a/core/java/android/hardware/UsbConstants.java b/core/java/android/hardware/UsbConstants.java
new file mode 100644
index 0000000..29a335c
--- /dev/null
+++ b/core/java/android/hardware/UsbConstants.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+/**
+ * Contains constants for the USB protocol.
+ * These constants correspond to definitions in linux/usb/ch9.h in the linux kernel.
+ */
+public final class UsbConstants {
+
+ public static final int USB_ENDPOINT_DIR_MASK = 0x80;
+ public static final int USB_DIR_OUT = 0;
+ public static final int USB_DIR_IN = 0x80;
+
+ public static final int USB_TYPE_MASK = (0x03 << 5);
+ public static final int USB_TYPE_STANDARD = (0x00 << 5);
+ public static final int USB_TYPE_CLASS = (0x01 << 5);
+ public static final int USB_TYPE_VENDOR = (0x02 << 5);
+ public static final int USB_TYPE_RESERVED = (0x03 << 5);
+
+ public static final int USB_ENDPOINT_NUMBER_MASK = 0x0f;
+
+ // flags for endpoint attributes
+ public static final int USB_ENDPOINT_XFERTYPE_MASK = 0x03;
+ public static final int USB_ENDPOINT_XFER_CONTROL = 0;
+ public static final int USB_ENDPOINT_XFER_ISOC = 1;
+ public static final int USB_ENDPOINT_XFER_BULK = 2;
+ public static final int USB_ENDPOINT_XFER_INT = 3;
+
+ public static final int USB_CLASS_PER_INTERFACE = 0;
+ public static final int USB_CLASS_AUDIO = 1;
+ public static final int USB_CLASS_COMM = 2;
+ public static final int USB_CLASS_HID = 3;
+ public static final int USB_CLASS_PHYSICA = 5;
+ public static final int USB_CLASS_STILL_IMAGE = 6;
+ public static final int USB_CLASS_PRINTER = 7;
+ public static final int USB_CLASS_MASS_STORAGE = 8;
+ public static final int USB_CLASS_HUB = 9;
+ public static final int USB_CLASS_CDC_DATA = 0x0a;
+ public static final int USB_CLASS_CSCID = 0x0b;
+ public static final int USB_CLASS_CONTENT_SEC = 0x0d;
+ public static final int USB_CLASS_VIDEO = 0x0e;
+ public static final int USB_CLASS_WIRELESS_CONTROLLER = 0xe0;
+ public static final int USB_CLASS_MISC = 0xef;
+ public static final int USB_CLASS_APP_SPEC = 0xfe;
+ public static final int USB_CLASS_VENDOR_SPEC = 0xff;
+ public static final int USB_SUBCLASS_VENDOR_SPEC = 0xff;
+
+} \ No newline at end of file
diff --git a/core/java/android/hardware/UsbDevice.aidl b/core/java/android/hardware/UsbDevice.aidl
new file mode 100644
index 0000000..6dfd43f
--- /dev/null
+++ b/core/java/android/hardware/UsbDevice.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable UsbDevice;
diff --git a/core/java/android/hardware/UsbDevice.java b/core/java/android/hardware/UsbDevice.java
new file mode 100644
index 0000000..e6b38be
--- /dev/null
+++ b/core/java/android/hardware/UsbDevice.java
@@ -0,0 +1,314 @@
+/*
+ * 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;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+
+
+/**
+ * A class representing a USB device.
+ */
+public final class UsbDevice implements Parcelable {
+
+ private static final String TAG = "UsbDevice";
+
+ private String mName;
+ private int mVendorId;
+ private int mProductId;
+ private int mClass;
+ private int mSubclass;
+ private int mProtocol;
+ private Parcelable[] mInterfaces;
+
+ // used by the JNI code
+ private int mNativeContext;
+
+ private UsbDevice() {
+ }
+
+
+ /**
+ * UsbDevice should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbDevice(String name, int vendorId, int productId,
+ int Class, int subClass, int protocol, Parcelable[] interfaces) {
+ mName = name;
+ mVendorId = vendorId;
+ mProductId = productId;
+ mClass = Class;
+ mSubclass = subClass;
+ mProtocol = protocol;
+ mInterfaces = interfaces;
+ }
+
+ /**
+ * 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 String getDeviceName() {
+ return mName;
+ }
+
+ /**
+ * 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 android.hardware.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 subclass field.
+ *
+ * @return the device's protocol
+ */
+ public int getDeviceProtocol() {
+ return mProtocol;
+ }
+
+ /**
+ * Returns the number of {@link android.hardware.UsbInterface}s this device contains.
+ *
+ * @return the number of interfaces
+ */
+ public int getInterfaceCount() {
+ return mInterfaces.length;
+ }
+
+ /**
+ * Returns the {@link android.hardware.UsbInterface} at the given index.
+ *
+ * @return the interface
+ */
+ public UsbInterface getInterface(int index) {
+ return (UsbInterface)mInterfaces[index];
+ }
+
+ /* package */ boolean open(ParcelFileDescriptor pfd) {
+ return native_open(mName, pfd.getFileDescriptor());
+ }
+
+ /**
+ * Releases all system resources related to the device.
+ */
+ public void close() {
+ native_close();
+ }
+
+ /**
+ * Returns an integer 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
+ */
+ public int getFileDescriptor() {
+ return native_get_fd();
+ }
+
+ /**
+ * Claims exclusive access to a {@link android.hardware.UsbInterface}.
+ * This must be done before sending or receiving data on any
+ * {@link android.hardware.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.UsbInterface}.
+ *
+ * @return true if the interface was successfully released
+ */
+ public boolean releaseInterface(UsbInterface intf) {
+ return native_release_interface(intf.getId());
+ }
+
+ /**
+ * Performs a control transaction on endpoint zero for this device.
+ *
+ * @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
+ * @return length of data transferred (or zero) for success,
+ * or negative value for failure
+ */
+ public int sendControlRequest(int requestType, int request, int value,
+ int index, byte[] buffer, int length) {
+ return native_control_request(requestType, request, value, index, buffer, length);
+ }
+
+ /**
+ * Waits for the result of a {@link android.hardware.UsbRequest#queue} operation
+ * Note that this may return requests queued on multiple {@link android.hardware.UsbEndpoint}s.
+ * When multiple endpoints are in use, {@link android.hardware.UsbRequest#getEndpoint} and
+ * {@link android.hardware.UsbRequest#getClientData} can be useful in determining how to process
+ * the result of this function.
+ *
+ * @return a completed USB request, or null if an error occurred
+ */
+ public UsbRequest requestWait() {
+ UsbRequest request = native_request_wait();
+ if (request != null) {
+ request.dequeue();
+ }
+ 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();
+ }
+
+ @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 String toString() {
+ return "UsbDevice[mName=" + mName + ",mVendorId=" + mVendorId +
+ ",mProductId=" + mProductId + ",mClass=" + mClass +
+ ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
+ ",mInterfaces=" + mInterfaces + "]";
+ }
+
+ 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();
+ Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader());
+ UsbDevice result = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, interfaces);
+ for (int i = 0; i < interfaces.length; i++) {
+ ((UsbInterface)interfaces[i]).setDevice(result);
+ }
+ return result;
+ }
+
+ 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.writeParcelableArray(mInterfaces, 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 native boolean native_open(String deviceName, FileDescriptor pfd);
+ private native void native_close();
+ private native int native_get_fd();
+ private native boolean native_claim_interface(int interfaceID, boolean force);
+ private native boolean native_release_interface(int interfaceID);
+ private native int native_control_request(int requestType, int request, int value,
+ int index, byte[] buffer, int length);
+ private native UsbRequest native_request_wait();
+ private native String native_get_serial();
+
+ private static native int native_get_device_id(String name);
+ private static native String native_get_device_name(int id);
+}
diff --git a/core/java/android/hardware/UsbEndpoint.aidl b/core/java/android/hardware/UsbEndpoint.aidl
new file mode 100644
index 0000000..51fc67b
--- /dev/null
+++ b/core/java/android/hardware/UsbEndpoint.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable UsbEndpoint;
diff --git a/core/java/android/hardware/UsbEndpoint.java b/core/java/android/hardware/UsbEndpoint.java
new file mode 100644
index 0000000..8d4099d
--- /dev/null
+++ b/core/java/android/hardware/UsbEndpoint.java
@@ -0,0 +1,176 @@
+/*
+ * 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;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class representing an endpoint on a {@link android.hardware.UsbInterface}.
+ */
+public final class UsbEndpoint implements Parcelable {
+
+ private int mAddress;
+ private int mAttributes;
+ private int mMaxPacketSize;
+ private int mInterval;
+ private UsbInterface mInterface;
+
+ private UsbEndpoint() {
+ }
+
+ /**
+ * 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.
+ *
+ * @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 android.hardware.UsbConstants#USB_DIR_OUT}
+ * if the direction is host to device, and
+ * {@link android.hardware.UsbConstants#USB_DIR_IN} if the
+ * direction is device to host.
+ *
+ * @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 android.hardware.UsbConstants#USB_ENDPOINT_XFER_CONTROL} (endpoint zero)
+ * <li>{@link android.hardware.UsbConstants#USB_ENDPOINT_XFER_ISOC} (isochronous endpoint)
+ * <li>{@link android.hardware.UsbConstants#USB_ENDPOINT_XFER_BULK} (bulk endpoint)
+ * <li>{@link android.hardware.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;
+ }
+
+ /**
+ * Returns the {@link android.hardware.UsbInterface} this endpoint belongs to.
+ *
+ * @return the endpoint's interface
+ */
+ public UsbInterface getInterface() {
+ return mInterface;
+ }
+
+ /**
+ * Returns the {@link android.hardware.UsbDevice} this endpoint belongs to.
+ *
+ * @return the endpoint's device
+ */
+ public UsbDevice getDevice() {
+ return mInterface.getDevice();
+ }
+
+ // only used for parcelling
+ /* package */ void setInterface(UsbInterface intf) {
+ mInterface = intf;
+ }
+
+ @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/core/java/android/hardware/UsbInterface.aidl b/core/java/android/hardware/UsbInterface.aidl
new file mode 100644
index 0000000..a715ccd
--- /dev/null
+++ b/core/java/android/hardware/UsbInterface.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable UsbInterface;
diff --git a/core/java/android/hardware/UsbInterface.java b/core/java/android/hardware/UsbInterface.java
new file mode 100644
index 0000000..deef81f
--- /dev/null
+++ b/core/java/android/hardware/UsbInterface.java
@@ -0,0 +1,159 @@
+/*
+ * 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;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class representing an interface on a {@link android.hardware.UsbDevice}.
+ */
+public final class UsbInterface implements Parcelable {
+
+ private int mId;
+ private int mClass;
+ private int mSubclass;
+ private int mProtocol;
+ private UsbDevice mDevice;
+ private Parcelable[] mEndpoints;
+
+ private UsbInterface() {
+ }
+
+ /**
+ * UsbInterface should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbInterface(int id, int Class, int subClass, int protocol,
+ Parcelable[] endpoints) {
+ mId = id;
+ mClass = Class;
+ mSubclass = subClass;
+ mProtocol = protocol;
+ mEndpoints = endpoints;
+ }
+
+ /**
+ * Returns the interface's ID field.
+ *
+ * @return the interface's ID
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the interface's class field.
+ * Some useful constants for USB classes can be found in
+ * {@link android.hardware.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.UsbEndpoint}s this interface contains.
+ *
+ * @return the number of endpoints
+ */
+ public int getEndpointCount() {
+ return mEndpoints.length;
+ }
+
+ /**
+ * Returns the {@link android.hardware.UsbEndpoint} at the given index.
+ *
+ * @return the endpoint
+ */
+ public UsbEndpoint getEndpoint(int index) {
+ return (UsbEndpoint)mEndpoints[index];
+ }
+
+ /**
+ * Returns the {@link android.hardware.UsbDevice} this interface belongs to.
+ *
+ * @return the interface's device
+ */
+ public UsbDevice getDevice() {
+ return mDevice;
+ }
+
+ // only used for parcelling
+ /* package */ void setDevice(UsbDevice device) {
+ mDevice = device;
+ }
+
+ @Override
+ public String toString() {
+ return "UsbInterface[mId=" + mId + ",mClass=" + mClass +
+ ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
+ ",mEndpoints=" + mEndpoints + "]";
+ }
+
+ public static final Parcelable.Creator<UsbInterface> CREATOR =
+ new Parcelable.Creator<UsbInterface>() {
+ public UsbInterface createFromParcel(Parcel in) {
+ int id = in.readInt();
+ int Class = in.readInt();
+ int subClass = in.readInt();
+ int protocol = in.readInt();
+ Parcelable[] endpoints = in.readParcelableArray(UsbEndpoint.class.getClassLoader());
+ UsbInterface result = new UsbInterface(id, Class, subClass, protocol, endpoints);
+ for (int i = 0; i < endpoints.length; i++) {
+ ((UsbEndpoint)endpoints[i]).setInterface(result);
+ }
+ return result;
+ }
+
+ 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(mClass);
+ parcel.writeInt(mSubclass);
+ parcel.writeInt(mProtocol);
+ parcel.writeParcelableArray(mEndpoints, 0);
+ }
+}
diff --git a/core/java/android/hardware/UsbManager.java b/core/java/android/hardware/UsbManager.java
index 18790d2..8fad210 100644
--- a/core/java/android/hardware/UsbManager.java
+++ b/core/java/android/hardware/UsbManager.java
@@ -17,17 +17,31 @@
package android.hardware;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.util.HashMap;
/**
- * Class for accessing USB state information.
- * @hide
+ * This class allows you to access the state of USB, both in host and device mode.
+ *
+ * <p>You can obtain an instance of this class by calling
+ * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
+ *
+ * {@samplecode
+ * UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+ * }
*/
public class UsbManager {
+ private static final String TAG = "UsbManager";
+
/**
- * Broadcast Action: A sticky broadcast for USB state change events.
+ * 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,
* the USB configuration that is currently set and a bundle containing name/value pairs
@@ -39,6 +53,22 @@ public class UsbManager {
public static final String ACTION_USB_STATE =
"android.hardware.action.USB_STATE";
+ /**
+ * 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.
+ */
+ public static final String ACTION_USB_DEVICE_ATTACHED =
+ "android.hardware.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.
+ */
+ public static final String ACTION_USB_DEVICE_DETACHED =
+ "android.hardware.action.USB_DEVICE_DETACHED";
+
/**
* Boolean extra indicating whether USB is connected or disconnected.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
@@ -87,6 +117,103 @@ public class UsbManager {
*/
public static final String USB_FUNCTION_DISABLED = "disabled";
+ /**
+ * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} and
+ * {@link #ACTION_USB_DEVICE_DETACHED} broadcasts
+ * containing the device's ID (String).
+ */
+ public static final String EXTRA_DEVICE_NAME = "device_name";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
+ * containing the device's vendor ID (int).
+ */
+ public static final String EXTRA_VENDOR_ID = "vendor_id";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
+ * containing the device's product ID (int).
+ */
+ public static final String EXTRA_PRODUCT_ID = "product_id";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
+ * containing the device's class (int).
+ */
+ public static final String EXTRA_DEVICE_CLASS = "device_class";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
+ * containing the device's class (int).
+ */
+ public static final String EXTRA_DEVICE_SUBCLASS = "device_subclass";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
+ * containing the device's class (int).
+ */
+ public static final String EXTRA_DEVICE_PROTOCOL = "device_protocol";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
+ * containing the UsbDevice object for the device.
+ */
+ public static final String EXTRA_DEVICE = "device";
+
+ private IUsbManager mService;
+
+ /**
+ * {@hide}
+ */
+ public UsbManager(IUsbManager service) {
+ 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() {
+ Bundle bundle = new Bundle();
+ try {
+ mService.getDeviceList(bundle);
+ HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>();
+ for (String name : bundle.keySet()) {
+ result.put(name, (UsbDevice)bundle.get(name));
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getDeviceList", e);
+ return null;
+ }
+ }
+
+ /**
+ * Opens the device so it can be used to send and receive
+ * data using {@link android.hardware.UsbRequest}.
+ *
+ * @param device the device to open
+ * @return true if we successfully opened the device
+ */
+ public boolean openDevice(UsbDevice device) {
+ try {
+ ParcelFileDescriptor pfd = mService.openDevice(device.getDeviceName());
+ if (pfd == null) {
+ return false;
+ }
+ boolean result = device.open(pfd);
+ pfd.close();
+ return result;
+ } catch (Exception e) {
+ Log.e(TAG, "exception in UsbManager.openDevice", e);
+ return false;
+ }
+ }
+
private static File getFunctionEnableFile(String function) {
return new File("/sys/class/usb_composite/" + function + "/enable");
}
@@ -94,6 +221,9 @@ public class UsbManager {
/**
* Returns true if the specified USB function is supported by the kernel.
* Note that a USB function maybe supported but disabled.
+ *
+ * @param function name of the USB function
+ * @return true if the USB function is supported.
*/
public static boolean isFunctionSupported(String function) {
return getFunctionEnableFile(function).exists();
@@ -101,6 +231,9 @@ public class UsbManager {
/**
* Returns true if the specified USB function is currently enabled.
+ *
+ * @param function name of the USB function
+ * @return true if the USB function is enabled.
*/
public static boolean isFunctionEnabled(String function) {
try {
diff --git a/core/java/android/hardware/UsbRequest.java b/core/java/android/hardware/UsbRequest.java
new file mode 100644
index 0000000..ae3a289
--- /dev/null
+++ b/core/java/android/hardware/UsbRequest.java
@@ -0,0 +1,177 @@
+/*
+ * 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;
+
+import android.util.Log;
+
+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.UsbDevice}.
+ * UsbRequests are sent asynchronously via {@link #queue} and the results
+ * are read by {@link android.hardware.UsbDevice#requestWait}.
+ */
+public class UsbRequest {
+
+ private static final String TAG = "UsbRequest";
+
+ // used by the JNI code
+ private int mNativeContext;
+
+ private UsbEndpoint mEndpoint;
+
+ // for temporarily saving current buffer across queue and dequeue
+ private ByteBuffer mBuffer;
+ private int mLength;
+
+ // for client use
+ private Object mClientData;
+
+ 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(UsbEndpoint endpoint) {
+ mEndpoint = endpoint;
+ return native_init(endpoint.getDevice(),
+ endpoint.getAddress(), endpoint.getAttributes(),
+ endpoint.getMaxPacketSize(), endpoint.getInterval());
+ }
+
+ /**
+ * Releases all resources related to this request.
+ */
+ public void close() {
+ mEndpoint = null;
+ native_close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mEndpoint != null) {
+ Log.v(TAG, "endpoint still open in finalize(): " + this);
+ 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.UsbDevice#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.UsbDevice#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.
+ * 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, we return true and the result will be
+ * returned via {@link android.hardware.UsbDevice#requestWait}
+ *
+ * @param buffer the buffer containing the bytes to write, or location to store
+ * the results of a read
+ * @param length number of bytes to read or write
+ * @return true if the queueing operation succeeded
+ */
+ public boolean queue(ByteBuffer buffer, int length) {
+ boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
+ boolean result;
+ 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) {
+ // save our buffer for when the request has completed
+ mBuffer = buffer;
+ mLength = length;
+ }
+ return result;
+ }
+
+ /* package */ void dequeue() {
+ boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
+ if (mBuffer.isDirect()) {
+ native_dequeue_direct();
+ } else {
+ native_dequeue_array(mBuffer.array(), mLength, out);
+ }
+ 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(UsbDevice device, int ep_address, int ep_attributes,
+ int ep_max_packet_size, int ep_interval);
+ private native void native_close();
+ private native boolean native_queue_array(byte[] buffer, int length, boolean out);
+ private native void native_dequeue_array(byte[] buffer, int length, boolean out);
+ private native boolean native_queue_direct(ByteBuffer buffer, int length, boolean out);
+ private native void native_dequeue_direct();
+ private native boolean native_cancel();
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c635b39..d1e7e5c 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -124,6 +124,8 @@ LOCAL_SRC_FILES:= \
android_media_ToneGenerator.cpp \
android_hardware_Camera.cpp \
android_hardware_SensorManager.cpp \
+ android_hardware_UsbDevice.cpp \
+ android_hardware_UsbRequest.cpp \
android_debug_JNITest.cpp \
android_util_FileObserver.cpp \
android/opengl/poly_clip.cpp.arm \
@@ -202,6 +204,7 @@ LOCAL_SHARED_LIBRARIES := \
libwpa_client \
libjpeg \
libnfc_ndef \
+ libusbhost \
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 342b884..c1c6c91 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -77,6 +77,8 @@ extern int register_android_opengl_jni_GLES20(JNIEnv* env);
extern int register_android_hardware_Camera(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
+extern int register_android_hardware_UsbDevice(JNIEnv *env);
+extern int register_android_hardware_UsbRequest(JNIEnv *env);
extern int register_android_media_AudioRecord(JNIEnv *env);
extern int register_android_media_AudioSystem(JNIEnv *env);
@@ -1275,6 +1277,8 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_SensorManager),
+ REG_JNI(register_android_hardware_UsbDevice),
+ REG_JNI(register_android_hardware_UsbRequest),
REG_JNI(register_android_media_AudioRecord),
REG_JNI(register_android_media_AudioSystem),
REG_JNI(register_android_media_AudioTrack),
diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp
new file mode 100644
index 0000000..22cf387
--- /dev/null
+++ b/core/jni/android_hardware_UsbDevice.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "UsbDeviceJNI"
+
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <usbhost/usbhost.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+using namespace android;
+
+static jfieldID field_context;
+
+struct usb_device* get_device_from_object(JNIEnv* env, jobject javaDevice)
+{
+ return (struct usb_device*)env->GetIntField(javaDevice, field_context);
+}
+
+// in android_hardware_UsbEndpoint.cpp
+extern struct usb_endpoint* get_endpoint_from_object(JNIEnv* env, jobject javaEndpoint);
+
+static jboolean
+android_hardware_UsbDevice_open(JNIEnv *env, jobject thiz, jstring deviceName,
+ jobject fileDescriptor)
+{
+ int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
+ fd = dup(fd);
+ if (fd < 0)
+ return false;
+
+ const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
+ struct usb_device* device = usb_device_new(deviceNameStr, fd);
+ if (device) {
+ env->SetIntField(thiz, field_context, (int)device);
+ } else {
+ LOGE("usb_device_open failed for %s", deviceNameStr);
+ close(fd);
+ }
+
+ env->ReleaseStringUTFChars(deviceName, deviceNameStr);
+ return (device != NULL);
+}
+
+static void
+android_hardware_UsbDevice_close(JNIEnv *env, jobject thiz)
+{
+ LOGD("close\n");
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (device) {
+ usb_device_close(device);
+ env->SetIntField(thiz, field_context, 0);
+ }
+}
+
+static jint
+android_hardware_UsbDevice_get_fd(JNIEnv *env, jobject thiz)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_get_fd");
+ return -1;
+ }
+ return usb_device_get_fd(device);
+}
+
+static jint
+android_hardware_UsbDevice_claim_interface(JNIEnv *env, jobject thiz, int interfaceID, jboolean force)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_claim_interface");
+ return -1;
+ }
+
+ int ret = usb_device_claim_interface(device, interfaceID);
+ if (ret && force && errno == EBUSY) {
+ // disconnect kernel driver and try again
+ usb_device_connect_kernel_driver(device, interfaceID, false);
+ ret = usb_device_claim_interface(device, interfaceID);
+ }
+ return ret;
+}
+
+static jint
+android_hardware_UsbDevice_release_interface(JNIEnv *env, jobject thiz, int interfaceID)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_release_interface");
+ return -1;
+ }
+ int ret = usb_device_release_interface(device, interfaceID);
+ if (ret == 0) {
+ // allow kernel to reconnect its driver
+ usb_device_connect_kernel_driver(device, interfaceID, true);
+ }
+ return ret;
+}
+
+static jint
+android_hardware_UsbDevice_control_request(JNIEnv *env, jobject thiz,
+ jint requestType, jint request, jint value, jint index,
+ jbyteArray buffer, jint length)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_control_request");
+ return -1;
+ }
+
+ jbyte* bufferBytes = NULL;
+ if (buffer) {
+ if (env->GetArrayLength(buffer) < length) {
+ env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL);
+ return -1;
+ }
+ bufferBytes = env->GetByteArrayElements(buffer, 0);
+ }
+
+ jint result = usb_device_send_control(device, requestType, request,
+ value, index, length, bufferBytes);
+
+ if (bufferBytes)
+ env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
+
+ return result;
+}
+
+static jobject
+android_hardware_UsbDevice_request_wait(JNIEnv *env, jobject thiz)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_request_wait");
+ return NULL;
+ }
+
+ struct usb_request* request = usb_request_wait(device);
+ if (request)
+ return (jobject)request->client_data;
+ else
+ return NULL;
+}
+
+static jstring
+android_hardware_UsbDevice_get_serial(JNIEnv *env, jobject thiz)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_request_wait");
+ return NULL;
+ }
+ char* serial = usb_device_get_serial(device);
+ if (!serial)
+ return NULL;
+ jstring result = env->NewStringUTF(serial);
+ free(serial);
+ return result;
+}
+
+static jint
+android_hardware_UsbDevice_get_device_id(JNIEnv *env, jobject clazz, jstring name)
+{
+ const char *nameStr = env->GetStringUTFChars(name, NULL);
+ int id = usb_device_get_unique_id_from_name(nameStr);
+ env->ReleaseStringUTFChars(name, nameStr);
+ return id;
+}
+
+static jstring
+android_hardware_UsbDevice_get_device_name(JNIEnv *env, jobject clazz, jint id)
+{
+ char* name = usb_device_get_name_from_unique_id(id);
+ jstring result = env->NewStringUTF(name);
+ free(name);
+ return result;
+}
+
+static JNINativeMethod method_table[] = {
+ {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
+ (void *)android_hardware_UsbDevice_open},
+ {"native_close", "()V", (void *)android_hardware_UsbDevice_close},
+ {"native_get_fd", "()I", (void *)android_hardware_UsbDevice_get_fd},
+ {"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDevice_claim_interface},
+ {"native_release_interface","(I)Z", (void *)android_hardware_UsbDevice_release_interface},
+ {"native_control_request", "(IIII[BI)I",
+ (void *)android_hardware_UsbDevice_control_request},
+ {"native_request_wait", "()Landroid/hardware/UsbRequest;",
+ (void *)android_hardware_UsbDevice_request_wait},
+ { "native_get_serial", "()Ljava/lang/String;",
+ (void*)android_hardware_UsbDevice_get_serial },
+
+ // static methods
+ { "native_get_device_id", "(Ljava/lang/String;)I",
+ (void*)android_hardware_UsbDevice_get_device_id },
+ { "native_get_device_name", "(I)Ljava/lang/String;",
+ (void*)android_hardware_UsbDevice_get_device_name },
+};
+
+int register_android_hardware_UsbDevice(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("android/hardware/UsbDevice");
+ if (clazz == NULL) {
+ LOGE("Can't find android/hardware/UsbDevice");
+ return -1;
+ }
+ field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_context == NULL) {
+ LOGE("Can't find UsbDevice.mNativeContext");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/hardware/UsbDevice",
+ method_table, NELEM(method_table));
+}
+
diff --git a/core/jni/android_hardware_UsbEndpoint.cpp b/core/jni/android_hardware_UsbEndpoint.cpp
new file mode 100644
index 0000000..00c8235
--- /dev/null
+++ b/core/jni/android_hardware_UsbEndpoint.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "UsbEndpoint"
+
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <usbhost/usbhost.h>
+
+#include <stdio.h>
+
+using namespace android;
+
+static jfieldID field_context;
+static jfieldID field_address;
+static jfieldID field_attributes;
+static jfieldID field_max_packet_size;
+static jfieldID field_interval;
+
+struct usb_endpoint* get_endpoint_from_object(JNIEnv* env, jobject javaEndpoint)
+{
+ return (struct usb_endpoint*)env->GetIntField(javaEndpoint, field_context);
+}
+
+// in android_hardware_UsbDevice.cpp
+extern struct usb_device* get_device_from_object(JNIEnv* env, jobject javaDevice);
+
+static jboolean
+android_hardware_UsbEndpoint_init(JNIEnv *env, jobject thiz, jobject javaDevice)
+{
+ LOGD("open\n");
+
+ struct usb_device* device = get_device_from_object(env, javaDevice);
+ if (!device) {
+ LOGE("device null in native_init");
+ return false;
+ }
+
+ // construct an endpoint descriptor from the Java object fields
+ struct usb_endpoint_descriptor desc;
+ desc.bLength = USB_DT_ENDPOINT_SIZE;
+ desc.bDescriptorType = USB_DT_ENDPOINT;
+ desc.bEndpointAddress = env->GetIntField(thiz, field_address);
+ desc.bmAttributes = env->GetIntField(thiz, field_attributes);
+ desc.wMaxPacketSize = env->GetIntField(thiz, field_max_packet_size);
+ desc.bInterval = env->GetIntField(thiz, field_interval);
+
+ struct usb_endpoint* endpoint = usb_endpoint_init(device, &desc);
+ if (endpoint)
+ env->SetIntField(thiz, field_context, (int)device);
+ return (endpoint != NULL);
+}
+
+static void
+android_hardware_UsbEndpoint_close(JNIEnv *env, jobject thiz)
+{
+ LOGD("close\n");
+ struct usb_endpoint* endpoint = get_endpoint_from_object(env, thiz);
+ if (endpoint) {
+ usb_endpoint_close(endpoint);
+ env->SetIntField(thiz, field_context, 0);
+ }
+}
+
+static JNINativeMethod method_table[] = {
+ {"native_init", "(Landroid/hardware/UsbDevice;)Z",
+ (void *)android_hardware_UsbEndpoint_init},
+ {"native_close", "()V", (void *)android_hardware_UsbEndpoint_close},
+};
+
+int register_android_hardware_UsbEndpoint(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("android/hardware/UsbEndpoint");
+ if (clazz == NULL) {
+ LOGE("Can't find android/hardware/UsbEndpoint");
+ return -1;
+ }
+ field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_context == NULL) {
+ LOGE("Can't find UsbEndpoint.mNativeContext");
+ return -1;
+ }
+ field_address = env->GetFieldID(clazz, "mAddress", "I");
+ if (field_address == NULL) {
+ LOGE("Can't find UsbEndpoint.mAddress");
+ return -1;
+ }
+ field_attributes = env->GetFieldID(clazz, "mAttributes", "I");
+ if (field_attributes == NULL) {
+ LOGE("Can't find UsbEndpoint.mAttributes");
+ return -1;
+ }
+ field_max_packet_size = env->GetFieldID(clazz, "mMaxPacketSize", "I");
+ if (field_max_packet_size == NULL) {
+ LOGE("Can't find UsbEndpoint.mMaxPacketSize");
+ return -1;
+ }
+ field_interval = env->GetFieldID(clazz, "mInterval", "I");
+ if (field_interval == NULL) {
+ LOGE("Can't find UsbEndpoint.mInterval");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/hardware/UsbEndpoint",
+ method_table, NELEM(method_table));
+}
+
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
new file mode 100644
index 0000000..710afae
--- /dev/null
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "UsbRequestJNI"
+
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <usbhost/usbhost.h>
+
+#include <stdio.h>
+
+using namespace android;
+
+static jfieldID field_context;
+
+struct usb_request* get_request_from_object(JNIEnv* env, jobject java_request)
+{
+ return (struct usb_request*)env->GetIntField(java_request, field_context);
+}
+
+// in android_hardware_UsbDevice.cpp
+extern struct usb_device* get_device_from_object(JNIEnv* env, jobject java_device);
+
+static jboolean
+android_hardware_UsbRequest_init(JNIEnv *env, jobject thiz, jobject java_device,
+ jint ep_address, jint ep_attributes, jint ep_max_packet_size, jint ep_interval)
+{
+ LOGD("init\n");
+
+ struct usb_device* device = get_device_from_object(env, java_device);
+ if (!device) {
+ LOGE("device null in native_init");
+ return false;
+ }
+
+ // construct an endpoint descriptor from the Java object fields
+ struct usb_endpoint_descriptor desc;
+ desc.bLength = USB_DT_ENDPOINT_SIZE;
+ desc.bDescriptorType = USB_DT_ENDPOINT;
+ desc.bEndpointAddress = ep_address;
+ desc.bmAttributes = ep_attributes;
+ desc.wMaxPacketSize = ep_max_packet_size;
+ desc.bInterval = ep_interval;
+
+ struct usb_request* request = usb_request_new(device, &desc);
+ if (request)
+ env->SetIntField(thiz, field_context, (int)request);
+ return (request != NULL);
+}
+
+static void
+android_hardware_UsbRequest_close(JNIEnv *env, jobject thiz)
+{
+ LOGD("close\n");
+ struct usb_request* request = get_request_from_object(env, thiz);
+ if (request) {
+ usb_request_free(request);
+ env->SetIntField(thiz, field_context, 0);
+ }
+}
+
+static jboolean
+android_hardware_UsbRequest_queue_array(JNIEnv *env, jobject thiz,
+ jbyteArray buffer, jint length, jboolean out)
+{
+ struct usb_request* request = get_request_from_object(env, thiz);
+ if (!request) {
+ LOGE("request is closed in native_queue");
+ return false;
+ }
+
+ if (buffer && length) {
+ request->buffer = malloc(length);
+ if (!request->buffer)
+ return false;
+ if (out) {
+ // copy data from Java buffer to native buffer
+ env->GetByteArrayRegion(buffer, 0, length, (jbyte *)request->buffer);
+ }
+ } else {
+ request->buffer = NULL;
+ }
+ request->buffer_length = length;
+
+ if (usb_request_queue(request)) {
+ if (request->buffer) {
+ // free our buffer if usb_request_queue fails
+ free(request->buffer);
+ request->buffer = NULL;
+ }
+ return false;
+ } else {
+ // save a reference to ourselves so UsbDevice.waitRequest() can find us
+ request->client_data = (void *)env->NewGlobalRef(thiz);
+ return true;
+ }
+}
+
+static void
+android_hardware_UsbRequest_dequeue_array(JNIEnv *env, jobject thiz,
+ jbyteArray buffer, jint length, jboolean out)
+{
+ struct usb_request* request = get_request_from_object(env, thiz);
+ if (!request) {
+ LOGE("request is closed in native_dequeue");
+ return;
+ }
+
+ if (buffer && length && request->buffer && !out) {
+ // copy data from native buffer to Java buffer
+ env->SetByteArrayRegion(buffer, 0, length, (jbyte *)request->buffer);
+ }
+ free(request->buffer);
+ env->DeleteGlobalRef((jobject)request->client_data);
+
+}
+
+static jboolean
+android_hardware_UsbRequest_queue_direct(JNIEnv *env, jobject thiz,
+ jobject buffer, jint length, jboolean out)
+{
+ struct usb_request* request = get_request_from_object(env, thiz);
+ if (!request) {
+ LOGE("request is closed in native_queue");
+ return false;
+ }
+
+ if (buffer && length) {
+ request->buffer = env->GetDirectBufferAddress(buffer);
+ if (!request->buffer)
+ return false;
+ } else {
+ request->buffer = NULL;
+ }
+ request->buffer_length = length;
+
+ if (usb_request_queue(request)) {
+ request->buffer = NULL;
+ return false;
+ } else {
+ // save a reference to ourselves so UsbDevice.waitRequest() can find us
+ // we also need this to make sure our native buffer is not deallocated
+ // while IO is active
+ request->client_data = (void *)env->NewGlobalRef(thiz);
+ return true;
+ }
+}
+
+static void
+android_hardware_UsbRequest_dequeue_direct(JNIEnv *env, jobject thiz)
+{
+ struct usb_request* request = get_request_from_object(env, thiz);
+ if (!request) {
+ LOGE("request is closed in native_dequeue");
+ return;
+ }
+ // all we need to do is delete our global ref
+ env->DeleteGlobalRef((jobject)request->client_data);
+}
+
+static jboolean
+android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz)
+{
+ struct usb_request* request = get_request_from_object(env, thiz);
+ if (!request) {
+ LOGE("request is closed in native_cancel");
+ return false;
+ }
+ return (usb_request_cancel(request) == 0);
+}
+
+static JNINativeMethod method_table[] = {
+ {"native_init", "(Landroid/hardware/UsbDevice;IIII)Z",
+ (void *)android_hardware_UsbRequest_init},
+ {"native_close", "()V", (void *)android_hardware_UsbRequest_close},
+ {"native_queue_array", "([BIZ)Z", (void *)android_hardware_UsbRequest_queue_array},
+ {"native_dequeue_array", "([BIZ)V", (void *)android_hardware_UsbRequest_dequeue_array},
+ {"native_queue_direct", "(Ljava/nio/ByteBuffer;IZ)Z",
+ (void *)android_hardware_UsbRequest_queue_direct},
+ {"native_dequeue_direct", "()V", (void *)android_hardware_UsbRequest_dequeue_direct},
+ {"native_cancel", "()Z", (void *)android_hardware_UsbRequest_cancel},
+};
+
+int register_android_hardware_UsbRequest(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("android/hardware/UsbRequest");
+ if (clazz == NULL) {
+ LOGE("Can't find android/hardware/UsbRequest");
+ return -1;
+ }
+ field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_context == NULL) {
+ LOGE("Can't find UsbRequest.mNativeContext");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/hardware/UsbRequest",
+ method_table, NELEM(method_table));
+}
+
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 25d3aca..a184a5c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -85,6 +85,8 @@
<protected-broadcast android:name="android.hardware.action.USB_CONNECTED" />
<protected-broadcast android:name="android.hardware.action.USB_DISCONNECTED" />
<protected-broadcast android:name="android.hardware.action.USB_STATE" />
+ <protected-broadcast android:name="android.hardware.action.USB_DEVICE_ATTACHED" />
+ <protected-broadcast android:name="android.hardware.action.USB_DEVICE_DETACHED" />
<protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
<protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />