diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/app/ContextImpl.java | 8 | ||||
-rw-r--r-- | core/java/android/content/Context.java | 10 | ||||
-rw-r--r-- | core/java/android/hardware/IUsbManager.aidl | 28 | ||||
-rw-r--r-- | core/java/android/hardware/UsbConstants.java | 63 | ||||
-rw-r--r-- | core/java/android/hardware/UsbDevice.aidl | 19 | ||||
-rw-r--r-- | core/java/android/hardware/UsbDevice.java | 314 | ||||
-rw-r--r-- | core/java/android/hardware/UsbEndpoint.aidl | 19 | ||||
-rw-r--r-- | core/java/android/hardware/UsbEndpoint.java | 176 | ||||
-rw-r--r-- | core/java/android/hardware/UsbInterface.aidl | 19 | ||||
-rw-r--r-- | core/java/android/hardware/UsbInterface.java | 159 | ||||
-rw-r--r-- | core/java/android/hardware/UsbManager.java | 139 | ||||
-rw-r--r-- | core/java/android/hardware/UsbRequest.java | 177 | ||||
-rw-r--r-- | core/jni/Android.mk | 3 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 4 | ||||
-rw-r--r-- | core/jni/android_hardware_UsbDevice.cpp | 239 | ||||
-rw-r--r-- | core/jni/android_hardware_UsbEndpoint.cpp | 124 | ||||
-rw-r--r-- | core/jni/android_hardware_UsbRequest.cpp | 217 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 2 |
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" /> |