diff options
20 files changed, 606 insertions, 955 deletions
diff --git a/api/current.xml b/api/current.xml index ace309b..fb4cdde 100644 --- a/api/current.xml +++ b/api/current.xml @@ -94880,13 +94880,13 @@ extends="java.lang.Object" abstract="false" static="false" - final="true" + final="false" deprecated="not deprecated" visibility="public" > <implements name="android.os.Parcelable"> </implements> -<method name="bulkTransfer" +<method name="describeContents" return="int" abstract="false" native="false" @@ -94896,17 +94896,9 @@ deprecated="not deprecated" visibility="public" > -<parameter name="endpoint" type="android.hardware.usb.UsbEndpoint"> -</parameter> -<parameter name="buffer" type="byte[]"> -</parameter> -<parameter name="length" type="int"> -</parameter> -<parameter name="timeout" type="int"> -</parameter> </method> -<method name="claimInterface" - return="boolean" +<method name="getDeviceClass" + return="int" abstract="false" native="false" synchronized="false" @@ -94915,13 +94907,9 @@ deprecated="not deprecated" visibility="public" > -<parameter name="intf" type="android.hardware.usb.UsbInterface"> -</parameter> -<parameter name="force" type="boolean"> -</parameter> </method> -<method name="close" - return="void" +<method name="getDeviceId" + return="int" abstract="false" native="false" synchronized="false" @@ -94931,33 +94919,21 @@ visibility="public" > </method> -<method name="controlTransfer" +<method name="getDeviceId" return="int" abstract="false" native="false" synchronized="false" - static="false" + static="true" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="requestType" type="int"> -</parameter> -<parameter name="request" type="int"> -</parameter> -<parameter name="value" type="int"> -</parameter> -<parameter name="index" type="int"> -</parameter> -<parameter name="buffer" type="byte[]"> -</parameter> -<parameter name="length" type="int"> -</parameter> -<parameter name="timeout" type="int"> +<parameter name="name" type="java.lang.String"> </parameter> </method> -<method name="describeContents" - return="int" +<method name="getDeviceName" + return="java.lang.String" abstract="false" native="false" synchronized="false" @@ -94967,18 +94943,20 @@ visibility="public" > </method> -<method name="getDeviceClass" - return="int" +<method name="getDeviceName" + return="java.lang.String" abstract="false" native="false" synchronized="false" - static="false" + static="true" final="false" deprecated="not deprecated" visibility="public" > +<parameter name="id" type="int"> +</parameter> </method> -<method name="getDeviceId" +<method name="getDeviceProtocol" return="int" abstract="false" native="false" @@ -94989,21 +94967,19 @@ visibility="public" > </method> -<method name="getDeviceId" +<method name="getDeviceSubclass" return="int" abstract="false" native="false" synchronized="false" - static="true" + static="false" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="name" type="java.lang.String"> -</parameter> </method> -<method name="getDeviceName" - return="java.lang.String" +<method name="getInterface" + return="android.hardware.usb.UsbInterface" abstract="false" native="false" synchronized="false" @@ -95012,21 +94988,21 @@ deprecated="not deprecated" visibility="public" > +<parameter name="index" type="int"> +</parameter> </method> -<method name="getDeviceName" - return="java.lang.String" +<method name="getInterfaceCount" + return="int" abstract="false" native="false" synchronized="false" - static="true" + static="false" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="id" type="int"> -</parameter> </method> -<method name="getDeviceProtocol" +<method name="getProductId" return="int" abstract="false" native="false" @@ -95037,7 +95013,7 @@ visibility="public" > </method> -<method name="getDeviceSubclass" +<method name="getVendorId" return="int" abstract="false" native="false" @@ -95048,8 +95024,8 @@ visibility="public" > </method> -<method name="getFileDescriptor" - return="int" +<method name="writeToParcel" + return="void" abstract="false" native="false" synchronized="false" @@ -95058,21 +95034,31 @@ deprecated="not deprecated" visibility="public" > +<parameter name="parcel" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> </method> -<method name="getInterface" - return="android.hardware.usb.UsbInterface" +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<class name="UsbDeviceConnection" + extends="java.lang.Object" abstract="false" - native="false" - synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="index" type="int"> -</parameter> -</method> -<method name="getInterfaceCount" +<method name="bulkTransfer" return="int" abstract="false" native="false" @@ -95082,9 +95068,17 @@ deprecated="not deprecated" visibility="public" > +<parameter name="endpoint" type="android.hardware.usb.UsbEndpoint"> +</parameter> +<parameter name="buffer" type="byte[]"> +</parameter> +<parameter name="length" type="int"> +</parameter> +<parameter name="timeout" type="int"> +</parameter> </method> -<method name="getProductId" - return="int" +<method name="claimInterface" + return="boolean" abstract="false" native="false" synchronized="false" @@ -95093,9 +95087,13 @@ deprecated="not deprecated" visibility="public" > +<parameter name="intf" type="android.hardware.usb.UsbInterface"> +</parameter> +<parameter name="force" type="boolean"> +</parameter> </method> -<method name="getSerial" - return="java.lang.String" +<method name="close" + return="void" abstract="false" native="false" synchronized="false" @@ -95105,7 +95103,7 @@ visibility="public" > </method> -<method name="getVendorId" +<method name="controlTransfer" return="int" abstract="false" native="false" @@ -95115,9 +95113,23 @@ deprecated="not deprecated" visibility="public" > +<parameter name="requestType" type="int"> +</parameter> +<parameter name="request" type="int"> +</parameter> +<parameter name="value" type="int"> +</parameter> +<parameter name="index" type="int"> +</parameter> +<parameter name="buffer" type="byte[]"> +</parameter> +<parameter name="length" type="int"> +</parameter> +<parameter name="timeout" type="int"> +</parameter> </method> -<method name="releaseInterface" - return="boolean" +<method name="getFileDescriptor" + return="int" abstract="false" native="false" synchronized="false" @@ -95126,11 +95138,9 @@ deprecated="not deprecated" visibility="public" > -<parameter name="intf" type="android.hardware.usb.UsbInterface"> -</parameter> </method> -<method name="requestWait" - return="android.hardware.usb.UsbRequest" +<method name="getSerial" + return="java.lang.String" abstract="false" native="false" synchronized="false" @@ -95140,8 +95150,8 @@ visibility="public" > </method> -<method name="writeToParcel" - return="void" +<method name="releaseInterface" + return="boolean" abstract="false" native="false" synchronized="false" @@ -95150,27 +95160,26 @@ deprecated="not deprecated" visibility="public" > -<parameter name="parcel" type="android.os.Parcel"> -</parameter> -<parameter name="flags" type="int"> +<parameter name="intf" type="android.hardware.usb.UsbInterface"> </parameter> </method> -<field name="CREATOR" - type="android.os.Parcelable.Creator" - transient="false" - volatile="false" - static="true" - final="true" +<method name="requestWait" + return="android.hardware.usb.UsbRequest" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" deprecated="not deprecated" visibility="public" > -</field> +</method> </class> <class name="UsbEndpoint" extends="java.lang.Object" abstract="false" static="false" - final="true" + final="false" deprecated="not deprecated" visibility="public" > @@ -95209,17 +95218,6 @@ visibility="public" > </method> -<method name="getDevice" - return="android.hardware.usb.UsbDevice" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> <method name="getDirection" return="int" abstract="false" @@ -95242,17 +95240,6 @@ visibility="public" > </method> -<method name="getInterface" - return="android.hardware.usb.UsbInterface" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> <method name="getInterval" return="int" abstract="false" @@ -95333,17 +95320,6 @@ visibility="public" > </method> -<method name="getDevice" - return="android.hardware.usb.UsbDevice" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> <method name="getEndpoint" return="android.hardware.usb.UsbEndpoint" abstract="false" @@ -95494,32 +95470,6 @@ <parameter name="accessory" type="android.hardware.usb.UsbAccessory"> </parameter> </method> -<method name="isFunctionEnabled" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="function" type="java.lang.String"> -</parameter> -</method> -<method name="isFunctionSupported" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="function" type="java.lang.String"> -</parameter> -</method> <method name="openAccessory" return="android.os.ParcelFileDescriptor" abstract="false" @@ -95534,7 +95484,7 @@ </parameter> </method> <method name="openDevice" - return="boolean" + return="android.hardware.usb.UsbDeviceConnection" abstract="false" native="false" synchronized="false" @@ -95620,17 +95570,6 @@ visibility="public" > </field> -<field name="ACTION_USB_STATE" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.hardware.usb.action.USB_STATE"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="EXTRA_ACCESSORY" type="java.lang.String" transient="false" @@ -95664,105 +95603,6 @@ visibility="public" > </field> -<field name="USB_CONFIGURATION" - type="java.lang.String" - transient="false" - volatile="false" - value=""configuration"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="USB_CONNECTED" - type="java.lang.String" - transient="false" - volatile="false" - value=""connected"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="USB_FUNCTION_ACCESSORY" - type="java.lang.String" - transient="false" - volatile="false" - value=""accessory"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="USB_FUNCTION_ADB" - type="java.lang.String" - transient="false" - volatile="false" - value=""adb"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="USB_FUNCTION_DISABLED" - type="java.lang.String" - transient="false" - volatile="false" - value=""disabled"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="USB_FUNCTION_ENABLED" - type="java.lang.String" - transient="false" - volatile="false" - value=""enabled"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="USB_FUNCTION_MASS_STORAGE" - type="java.lang.String" - transient="false" - volatile="false" - value=""mass_storage"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="USB_FUNCTION_MTP" - type="java.lang.String" - transient="false" - volatile="false" - value=""mtp"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="USB_FUNCTION_RNDIS" - type="java.lang.String" - transient="false" - volatile="false" - value=""rndis"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> </class> <class name="UsbRequest" extends="java.lang.Object" @@ -95834,6 +95674,8 @@ deprecated="not deprecated" visibility="public" > +<parameter name="connection" type="android.hardware.usb.UsbDeviceConnection"> +</parameter> <parameter name="endpoint" type="android.hardware.usb.UsbEndpoint"> </parameter> </method> @@ -112607,255 +112449,6 @@ </package> <package name="android.mtp" > -<class name="MtpClient" - extends="java.lang.Object" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="MtpClient" - type="android.mtp.MtpClient" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="context" type="android.content.Context"> -</parameter> -</constructor> -<method name="addListener" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="listener" type="android.mtp.MtpClient.Listener"> -</parameter> -</method> -<method name="close" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="deleteObject" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="deviceName" type="java.lang.String"> -</parameter> -<parameter name="objectHandle" type="int"> -</parameter> -</method> -<method name="getDevice" - return="android.mtp.MtpDevice" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="deviceName" type="java.lang.String"> -</parameter> -</method> -<method name="getDevice" - return="android.mtp.MtpDevice" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="id" type="int"> -</parameter> -</method> -<method name="getDeviceList" - return="java.util.List<android.mtp.MtpDevice>" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="getObject" - return="byte[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="deviceName" type="java.lang.String"> -</parameter> -<parameter name="objectHandle" type="int"> -</parameter> -<parameter name="objectSize" type="int"> -</parameter> -</method> -<method name="getObjectInfo" - return="android.mtp.MtpObjectInfo" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="deviceName" type="java.lang.String"> -</parameter> -<parameter name="objectHandle" type="int"> -</parameter> -</method> -<method name="getObjectList" - return="java.util.List<android.mtp.MtpObjectInfo>" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="deviceName" type="java.lang.String"> -</parameter> -<parameter name="storageId" type="int"> -</parameter> -<parameter name="objectHandle" type="int"> -</parameter> -</method> -<method name="getStorageList" - return="java.util.List<android.mtp.MtpStorageInfo>" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="deviceName" type="java.lang.String"> -</parameter> -</method> -<method name="getThumbnail" - return="byte[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="deviceName" type="java.lang.String"> -</parameter> -<parameter name="objectHandle" type="int"> -</parameter> -</method> -<method name="importFile" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="deviceName" type="java.lang.String"> -</parameter> -<parameter name="objectHandle" type="int"> -</parameter> -<parameter name="destPath" type="java.lang.String"> -</parameter> -</method> -<method name="isCamera" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="device" type="android.hardware.usb.UsbDevice"> -</parameter> -</method> -<method name="removeListener" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="listener" type="android.mtp.MtpClient.Listener"> -</parameter> -</method> -</class> -<interface name="MtpClient.Listener" - abstract="true" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="deviceAdded" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="device" type="android.mtp.MtpDevice"> -</parameter> -</method> -<method name="deviceRemoved" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="device" type="android.mtp.MtpDevice"> -</parameter> -</method> -</interface> <class name="MtpConstants" extends="java.lang.Object" abstract="false" @@ -113765,7 +113358,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="manager" type="android.hardware.usb.UsbManager"> +<parameter name="connection" type="android.hardware.usb.UsbDeviceConnection"> </parameter> </method> </class> @@ -267438,7 +267031,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="arg0" type="T"> +<parameter name="t" type="T"> </parameter> </method> </interface> diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java index 39254b38..9e536a7 100644 --- a/core/java/android/hardware/usb/UsbDevice.java +++ b/core/java/android/hardware/usb/UsbDevice.java @@ -19,33 +19,24 @@ package android.hardware.usb; 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 { +public 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() { - } - + private final String mName; + private final int mVendorId; + private final int mProductId; + private final int mClass; + private final int mSubclass; + private final int mProtocol; + private final Parcelable[] mInterfaces; /** * UsbDevice should only be instantiated by UsbService implementation @@ -150,114 +141,6 @@ public final class UsbDevice implements Parcelable { 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.usb.UsbInterface}. - * This must be done before sending or receiving data on any - * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface - * @param intf the interface to claim - * @param force true to disconnect kernel driver if necessary - * @return true if the interface was successfully claimed - */ - public boolean claimInterface(UsbInterface intf, boolean force) { - return native_claim_interface(intf.getId(), force); - } - - /** - * Releases exclusive access to a {@link android.hardware.usb.UsbInterface}. - * - * @return true if the interface was successfully released - */ - public boolean releaseInterface(UsbInterface intf) { - return native_release_interface(intf.getId()); - } - - /** - * Performs a control transaction on endpoint zero for this device. - * The direction of the transfer is determined by the request type. - * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is - * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write, - * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer - * is a read. - * - * @param requestType request type for this transaction - * @param request request ID for this transaction - * @param value value field for this transaction - * @param index index field for this transaction - * @param buffer buffer for data portion of transaction, - * or null if no data needs to be sent or received - * @param length the length of the data to send or receive - * @param timeout in milliseconds - * @return length of data transferred (or zero) for success, - * or negative value for failure - */ - public int controlTransfer(int requestType, int request, int value, - int index, byte[] buffer, int length, int timeout) { - return native_control_request(requestType, request, value, index, buffer, length, timeout); - } - - /** - * Performs a bulk transaction on the given endpoint. - * The direction of the transfer is determined by the direction of the endpoint - * - * @param endpoint the endpoint for this transaction - * @param buffer buffer for data to send or receive, - * @param length the length of the data to send or receive - * @param timeout in milliseconds - * @return length of data transferred (or zero) for success, - * or negative value for failure - */ - public int bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout) { - return native_bulk_request(endpoint.getAddress(), buffer, length, timeout); - } - - /** - * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation - * Note that this may return requests queued on multiple - * {@link android.hardware.usb.UsbEndpoint}s. - * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and - * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining - * how to process the result of this function. - * - * @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) { @@ -292,11 +175,7 @@ public final class UsbDevice implements Parcelable { 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; + return new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, interfaces); } public UsbDevice[] newArray(int size) { @@ -326,17 +205,6 @@ public final class UsbDevice implements Parcelable { 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, int timeout); - private native int native_bulk_request(int endpoint, byte[] buffer, int length, int timeout); - 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/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java new file mode 100644 index 0000000..876287c --- /dev/null +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.usb; + +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.FileDescriptor; + + +/** + * A class representing a USB device. + */ +public class UsbDeviceConnection { + + private static final String TAG = "UsbDeviceConnection"; + + private final UsbDevice mDevice; + + // used by the JNI code + private int mNativeContext; + + /** + * UsbDevice should only be instantiated by UsbService implementation + * @hide + */ + public UsbDeviceConnection(UsbDevice device) { + mDevice = device; + } + + /* package */ boolean open(String name, ParcelFileDescriptor pfd) { + return native_open(name, 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.usb.UsbInterface}. + * This must be done before sending or receiving data on any + * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface + * @param intf the interface to claim + * @param force true to disconnect kernel driver if necessary + * @return true if the interface was successfully claimed + */ + public boolean claimInterface(UsbInterface intf, boolean force) { + return native_claim_interface(intf.getId(), force); + } + + /** + * Releases exclusive access to a {@link android.hardware.usb.UsbInterface}. + * + * @return true if the interface was successfully released + */ + public boolean releaseInterface(UsbInterface intf) { + return native_release_interface(intf.getId()); + } + + /** + * Performs a control transaction on endpoint zero for this device. + * The direction of the transfer is determined by the request type. + * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is + * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write, + * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer + * is a read. + * + * @param requestType request type for this transaction + * @param request request ID for this transaction + * @param value value field for this transaction + * @param index index field for this transaction + * @param buffer buffer for data portion of transaction, + * or null if no data needs to be sent or received + * @param length the length of the data to send or receive + * @param timeout in milliseconds + * @return length of data transferred (or zero) for success, + * or negative value for failure + */ + public int controlTransfer(int requestType, int request, int value, + int index, byte[] buffer, int length, int timeout) { + return native_control_request(requestType, request, value, index, buffer, length, timeout); + } + + /** + * Performs a bulk transaction on the given endpoint. + * The direction of the transfer is determined by the direction of the endpoint + * + * @param endpoint the endpoint for this transaction + * @param buffer buffer for data to send or receive, + * @param length the length of the data to send or receive + * @param timeout in milliseconds + * @return length of data transferred (or zero) for success, + * or negative value for failure + */ + public int bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout) { + return native_bulk_request(endpoint.getAddress(), buffer, length, timeout); + } + + /** + * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation + * Note that this may return requests queued on multiple + * {@link android.hardware.usb.UsbEndpoint}s. + * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and + * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining + * how to process the result of this function. + * + * @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(); + } + + 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, int timeout); + private native int native_bulk_request(int endpoint, byte[] buffer, int length, int timeout); + private native UsbRequest native_request_wait(); + private native String native_get_serial(); +} diff --git a/core/java/android/hardware/usb/UsbEndpoint.java b/core/java/android/hardware/usb/UsbEndpoint.java index a48d88f..bc2c2c1 100644 --- a/core/java/android/hardware/usb/UsbEndpoint.java +++ b/core/java/android/hardware/usb/UsbEndpoint.java @@ -23,16 +23,12 @@ import android.os.Parcelable; /** * A class representing an endpoint on a {@link android.hardware.usb.UsbInterface}. */ -public final class UsbEndpoint implements Parcelable { +public class UsbEndpoint implements Parcelable { - private int mAddress; - private int mAttributes; - private int mMaxPacketSize; - private int mInterval; - private UsbInterface mInterface; - - private UsbEndpoint() { - } + private final int mAddress; + private final int mAttributes; + private final int mMaxPacketSize; + private final int mInterval; /** * UsbEndpoint should only be instantiated by UsbService implementation @@ -119,29 +115,6 @@ public final class UsbEndpoint implements Parcelable { return mInterval; } - /** - * Returns the {@link android.hardware.usb.UsbInterface} this endpoint belongs to. - * - * @return the endpoint's interface - */ - public UsbInterface getInterface() { - return mInterface; - } - - /** - * Returns the {@link android.hardware.usb.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 + diff --git a/core/java/android/hardware/usb/UsbInterface.java b/core/java/android/hardware/usb/UsbInterface.java index b3b0e81..2b4c7c0 100644 --- a/core/java/android/hardware/usb/UsbInterface.java +++ b/core/java/android/hardware/usb/UsbInterface.java @@ -25,15 +25,11 @@ import android.os.Parcelable; */ public class UsbInterface implements Parcelable { - private int mId; - private int mClass; - private int mSubclass; - private int mProtocol; - private UsbDevice mDevice; - private Parcelable[] mEndpoints; - - private UsbInterface() { - } + private final int mId; + private final int mClass; + private final int mSubclass; + private final int mProtocol; + private final Parcelable[] mEndpoints; /** * UsbInterface should only be instantiated by UsbService implementation @@ -104,20 +100,6 @@ public class UsbInterface implements Parcelable { return (UsbEndpoint)mEndpoints[index]; } - /** - * Returns the {@link android.hardware.usb.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 + @@ -133,11 +115,7 @@ public class UsbInterface implements Parcelable { 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; + return new UsbInterface(id, Class, subClass, protocol, endpoints); } public UsbInterface[] newArray(int size) { diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index e80c744..0e2cad8 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -55,6 +55,8 @@ public class UsbManager { * {@link #USB_FUNCTION_MASS_STORAGE}, {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS}, * {@link #USB_FUNCTION_MTP} and {@link #USB_FUNCTION_ACCESSORY}. * </ul> + * + * {@hide} */ public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE"; @@ -110,42 +112,56 @@ public class UsbManager { /** * Boolean extra indicating whether USB is connected or disconnected. * Used in extras for the {@link #ACTION_USB_STATE} broadcast. + * + * {@hide} */ public static final String USB_CONNECTED = "connected"; /** * Integer extra containing currently set USB configuration. * Used in extras for the {@link #ACTION_USB_STATE} broadcast. + * + * {@hide} */ public static final String USB_CONFIGURATION = "configuration"; /** * Name of the USB mass storage USB function. * Used in extras for the {@link #ACTION_USB_STATE} broadcast + * + * {@hide} */ public static final String USB_FUNCTION_MASS_STORAGE = "mass_storage"; /** * Name of the adb USB function. * Used in extras for the {@link #ACTION_USB_STATE} broadcast + * + * {@hide} */ public static final String USB_FUNCTION_ADB = "adb"; /** * Name of the RNDIS ethernet USB function. * Used in extras for the {@link #ACTION_USB_STATE} broadcast + * + * {@hide} */ public static final String USB_FUNCTION_RNDIS = "rndis"; /** * Name of the MTP USB function. * Used in extras for the {@link #ACTION_USB_STATE} broadcast + * + * {@hide} */ public static final String USB_FUNCTION_MTP = "mtp"; /** * Name of the Accessory USB function. * Used in extras for the {@link #ACTION_USB_STATE} broadcast + * + * {@hide} */ public static final String USB_FUNCTION_ACCESSORY = "accessory"; @@ -153,6 +169,8 @@ public class UsbManager { * Value indicating that a USB function is enabled. * Used in {@link #USB_CONFIGURATION} extras bundle for the * {@link #ACTION_USB_STATE} broadcast + * + * {@hide} */ public static final String USB_FUNCTION_ENABLED = "enabled"; @@ -160,6 +178,8 @@ public class UsbManager { * Value indicating that a USB function is disabled. * Used in {@link #USB_CONFIGURATION} extras bundle for the * {@link #ACTION_USB_STATE} broadcast + * + * {@hide} */ public static final String USB_FUNCTION_DISABLED = "disabled"; @@ -227,19 +247,22 @@ public class UsbManager { * @param device the device to open * @return true if we successfully opened the device */ - public boolean openDevice(UsbDevice device) { + public UsbDeviceConnection openDevice(UsbDevice device) { try { - ParcelFileDescriptor pfd = mService.openDevice(device.getDeviceName()); - if (pfd == null) { - return false; + String deviceName = device.getDeviceName(); + ParcelFileDescriptor pfd = mService.openDevice(deviceName); + if (pfd != null) { + UsbDeviceConnection connection = new UsbDeviceConnection(device); + boolean result = connection.open(deviceName, pfd); + pfd.close(); + if (result) { + return connection; + } } - boolean result = device.open(pfd); - pfd.close(); - return result; } catch (Exception e) { Log.e(TAG, "exception in UsbManager.openDevice", e); - return false; } + return null; } /** @@ -375,6 +398,8 @@ public class UsbManager { * * @param function name of the USB function * @return true if the USB function is supported. + * + * {@hide} */ public static boolean isFunctionSupported(String function) { return getFunctionEnableFile(function).exists(); @@ -385,6 +410,8 @@ public class UsbManager { * * @param function name of the USB function * @return true if the USB function is enabled. + * + * {@hide} */ public static boolean isFunctionEnabled(String function) { try { @@ -400,7 +427,7 @@ public class UsbManager { /** * Enables or disables a USB function. * - * @hide + * {@hide} */ public static boolean setFunctionEnabled(String function, boolean enable) { try { diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java index 80085c1..5fe6c8c 100644 --- a/core/java/android/hardware/usb/UsbRequest.java +++ b/core/java/android/hardware/usb/UsbRequest.java @@ -23,9 +23,9 @@ import java.nio.ByteBuffer; /** * A class representing USB request packet. * This can be used for both reading and writing data to or from a - * {@link android.hardware.usb.UsbDevice}. + * {@link android.hardware.usb.UsbDeviceConnection}. * UsbRequests are sent asynchronously via {@link #queue} and the results - * are read by {@link android.hardware.usb.UsbDevice#requestWait}. + * are read by {@link android.hardware.usb.UsbDeviceConnection#requestWait}. */ public class UsbRequest { @@ -53,10 +53,9 @@ public class UsbRequest { * @param endpoint the endpoint to be used for this request. * @return true if the request was successfully opened. */ - public boolean initialize(UsbEndpoint endpoint) { + public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint) { mEndpoint = endpoint; - return native_init(endpoint.getDevice(), - endpoint.getAddress(), endpoint.getAttributes(), + return native_init(connection, endpoint.getAddress(), endpoint.getAttributes(), endpoint.getMaxPacketSize(), endpoint.getInterval()); } @@ -94,7 +93,7 @@ public class UsbRequest { * This can be used in conjunction with {@link #setClientData} * to associate another object with this request, which can be useful for * maintaining state between calls to {@link #queue} and - * {@link android.hardware.usb.UsbDevice#requestWait} + * {@link android.hardware.usb.UsbDeviceConnection#requestWait} * * @return the client data for the request */ @@ -107,7 +106,7 @@ public class UsbRequest { * This can be used in conjunction with {@link #getClientData} * to associate another object with this request, which can be useful for * maintaining state between calls to {@link #queue} and - * {@link android.hardware.usb.UsbDevice#requestWait} + * {@link android.hardware.usb.UsbDeviceConnection#requestWait} * * @param data the client data for the request */ @@ -121,7 +120,7 @@ public class UsbRequest { * 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.usb.UsbDevice#requestWait} + * returned via {@link android.hardware.usb.UsbDeviceConnection#requestWait} * * @param buffer the buffer containing the bytes to write, or location to store * the results of a read @@ -166,8 +165,8 @@ public class UsbRequest { 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 boolean native_init(UsbDeviceConnection connection, int ep_address, + int ep_attributes, int ep_max_packet_size, int ep_interval); private native void native_close(); private native boolean native_queue_array(byte[] buffer, int length, boolean out); private native void native_dequeue_array(byte[] buffer, int length, boolean out); diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 2ed938a..1c4dc29 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -124,6 +124,7 @@ LOCAL_SRC_FILES:= \ android_hardware_Camera.cpp \ android_hardware_SensorManager.cpp \ android_hardware_UsbDevice.cpp \ + android_hardware_UsbDeviceConnection.cpp \ android_hardware_UsbRequest.cpp \ android_debug_JNITest.cpp \ android_util_FileObserver.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 878af3d..0e071a4 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -78,6 +78,7 @@ 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_UsbDeviceConnection(JNIEnv *env); extern int register_android_hardware_UsbRequest(JNIEnv *env); extern int register_android_media_AudioRecord(JNIEnv *env); @@ -1274,6 +1275,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_SensorManager), REG_JNI(register_android_hardware_UsbDevice), + REG_JNI(register_android_hardware_UsbDeviceConnection), REG_JNI(register_android_hardware_UsbRequest), REG_JNI(register_android_media_AudioRecord), REG_JNI(register_android_media_AudioSystem), diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp index b01820c..c2950ea 100644 --- a/core/jni/android_hardware_UsbDevice.cpp +++ b/core/jni/android_hardware_UsbDevice.cpp @@ -24,190 +24,8 @@ #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 jboolean -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 == 0; -} - -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, jint timeout) -{ - 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_control_transfer(device, requestType, request, - value, index, bufferBytes, length, timeout); - - if (bufferBytes) - env->ReleaseByteArrayElements(buffer, bufferBytes, 0); - - return result; -} - -static jint -android_hardware_UsbDevice_bulk_request(JNIEnv *env, jobject thiz, - jint endpoint, jbyteArray buffer, jint length, jint timeout) -{ - 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_bulk_transfer(device, endpoint, bufferBytes, length, timeout); - - 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) { @@ -227,21 +45,6 @@ android_hardware_UsbDevice_get_device_name(JNIEnv *env, jobject clazz, jint id) } 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[BII)I", - (void *)android_hardware_UsbDevice_control_request}, - {"native_bulk_request", "(I[BII)I", - (void *)android_hardware_UsbDevice_bulk_request}, - {"native_request_wait", "()Landroid/hardware/usb/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 }, @@ -256,11 +59,6 @@ int register_android_hardware_UsbDevice(JNIEnv *env) LOGE("Can't find android/hardware/usb/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/usb/UsbDevice", method_table, NELEM(method_table)); diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp new file mode 100644 index 0000000..ec36a38 --- /dev/null +++ b/core/jni/android_hardware_UsbDeviceConnection.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "UsbDeviceConnectionJNI" + +#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 connection) +{ + return (struct usb_device*)env->GetIntField(connection, field_context); +} + +static jboolean +android_hardware_UsbDeviceConnection_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_UsbDeviceConnection_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_UsbDeviceConnection_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 jboolean +android_hardware_UsbDeviceConnection_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 == 0; +} + +static jint +android_hardware_UsbDeviceConnection_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_UsbDeviceConnection_control_request(JNIEnv *env, jobject thiz, + jint requestType, jint request, jint value, jint index, + jbyteArray buffer, jint length, jint timeout) +{ + 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_control_transfer(device, requestType, request, + value, index, bufferBytes, length, timeout); + + if (bufferBytes) + env->ReleaseByteArrayElements(buffer, bufferBytes, 0); + + return result; +} + +static jint +android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz, + jint endpoint, jbyteArray buffer, jint length, jint timeout) +{ + 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_bulk_transfer(device, endpoint, bufferBytes, length, timeout); + + if (bufferBytes) + env->ReleaseByteArrayElements(buffer, bufferBytes, 0); + + return result; +} + +static jobject +android_hardware_UsbDeviceConnection_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_UsbDeviceConnection_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 JNINativeMethod method_table[] = { + {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z", + (void *)android_hardware_UsbDeviceConnection_open}, + {"native_close", "()V", (void *)android_hardware_UsbDeviceConnection_close}, + {"native_get_fd", "()I", (void *)android_hardware_UsbDeviceConnection_get_fd}, + {"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface}, + {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface}, + {"native_control_request", "(IIII[BII)I", + (void *)android_hardware_UsbDeviceConnection_control_request}, + {"native_bulk_request", "(I[BII)I", + (void *)android_hardware_UsbDeviceConnection_bulk_request}, + {"native_request_wait", "()Landroid/hardware/usb/UsbRequest;", + (void *)android_hardware_UsbDeviceConnection_request_wait}, + { "native_get_serial", "()Ljava/lang/String;", + (void*)android_hardware_UsbDeviceConnection_get_serial }, +}; + +int register_android_hardware_UsbDeviceConnection(JNIEnv *env) +{ + jclass clazz = env->FindClass("android/hardware/usb/UsbDeviceConnection"); + if (clazz == NULL) { + LOGE("Can't find android/hardware/usb/UsbDeviceConnection"); + return -1; + } + field_context = env->GetFieldID(clazz, "mNativeContext", "I"); + if (field_context == NULL) { + LOGE("Can't find UsbDeviceConnection.mNativeContext"); + return -1; + } + + return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDeviceConnection", + method_table, NELEM(method_table)); +} + diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp index b497adb..6bd67d1 100644 --- a/core/jni/android_hardware_UsbRequest.cpp +++ b/core/jni/android_hardware_UsbRequest.cpp @@ -35,8 +35,8 @@ 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); +// in android_hardware_UsbDeviceConnection.cpp +extern struct usb_device* get_device_from_object(JNIEnv* env, jobject connection); static jboolean android_hardware_UsbRequest_init(JNIEnv *env, jobject thiz, jobject java_device, @@ -107,7 +107,7 @@ android_hardware_UsbRequest_queue_array(JNIEnv *env, jobject thiz, } return false; } else { - // save a reference to ourselves so UsbDevice.waitRequest() can find us + // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us request->client_data = (void *)env->NewGlobalRef(thiz); return true; } @@ -155,7 +155,7 @@ android_hardware_UsbRequest_queue_direct(JNIEnv *env, jobject thiz, request->buffer = NULL; return false; } else { - // save a reference to ourselves so UsbDevice.waitRequest() can find us + // save a reference to ourselves so UsbDeviceConnection.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); @@ -187,7 +187,7 @@ android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz) } static JNINativeMethod method_table[] = { - {"native_init", "(Landroid/hardware/usb/UsbDevice;IIII)Z", + {"native_init", "(Landroid/hardware/usb/UsbDeviceConnection;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}, diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java index 22961d7f..db2cebd 100644 --- a/media/java/android/mtp/MtpDevice.java +++ b/media/java/android/mtp/MtpDevice.java @@ -17,7 +17,7 @@ package android.mtp; import android.hardware.usb.UsbDevice; -import android.hardware.usb.UsbManager; +import android.hardware.usb.UsbDeviceConnection; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -44,17 +44,20 @@ public final class MtpDevice { } /** - * Opens the MTP or PTP device and return an {@link android.mtp.MtpDevice} for it. + * Opens the MTP device. Once the device is open it takes ownership of the + * {@link android.hardware.usb.UsbDeviceConnection}. + * The connection will be closed when you call {@link #close()} + * The connection will also be closed if this method fails. * - * @param manager reference to {@link android.hardware.usb.UsbManager} + * @param connection an open {@link android.hardware.usb.UsbDeviceConnection} for the device * @return true if the device was successfully opened. */ - public boolean open(UsbManager manager) { - if (manager.openDevice(mDevice)) { - return native_open(mDevice.getDeviceName(), mDevice.getFileDescriptor()); - } else { - return false; + public boolean open(UsbDeviceConnection connection) { + boolean result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor()); + if (!result) { + connection.close(); } + return result; } /** diff --git a/media/tests/CameraBrowser/Android.mk b/media/tests/CameraBrowser/Android.mk index 1d81129..46596a7 100644 --- a/media/tests/CameraBrowser/Android.mk +++ b/media/tests/CameraBrowser/Android.mk @@ -7,4 +7,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := CameraBrowser +LOCAL_SDK_VERSION := current + include $(BUILD_PACKAGE) diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java index f642d93..af17ded 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java @@ -20,7 +20,6 @@ import android.app.ListActivity; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.mtp.MtpClient; import android.mtp.MtpDevice; import android.mtp.MtpDeviceInfo; import android.os.Bundle; @@ -79,8 +78,8 @@ public class CameraBrowser extends ListActivity implements MtpClient.Listener { view = (TwoLineListItem)convertView; } - TextView textView1 = (TextView)view.findViewById(com.android.internal.R.id.text1); - TextView textView2 = (TextView)view.findViewById(com.android.internal.R.id.text2); + TextView textView1 = (TextView)view.findViewById(android.R.id.text1); + TextView textView2 = (TextView)view.findViewById(android.R.id.text2); MtpDevice device = mDeviceList.get(position); MtpDeviceInfo info = device.getDeviceInfo(); if (info != null) { diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java index 6f1edfea..8075862 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java @@ -17,8 +17,6 @@ package com.android.camerabrowser; import android.app.Application; -import android.mtp.MtpClient; - public class CameraBrowserApplication extends Application { diff --git a/media/java/android/mtp/MtpClient.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/MtpClient.java index d25dcb9..edb5e37 100644 --- a/media/java/android/mtp/MtpClient.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/MtpClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.mtp; +package com.android.camerabrowser; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -23,8 +23,13 @@ import android.content.Intent; import android.content.IntentFilter; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; +import android.mtp.MtpDevice; +import android.mtp.MtpDeviceInfo; +import android.mtp.MtpObjectInfo; +import android.mtp.MtpStorageInfo; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -168,10 +173,13 @@ public class MtpClient { if (!mUsbManager.hasPermission(usbDevice)) { mUsbManager.requestPermission(usbDevice, mPermissionIntent); } else { - MtpDevice mtpDevice = new MtpDevice(usbDevice); - if (mtpDevice.open(mUsbManager)) { - mDevices.put(usbDevice.getDeviceName(), mtpDevice); - return mtpDevice; + UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice); + if (connection != null) { + MtpDevice mtpDevice = new MtpDevice(usbDevice); + if (mtpDevice.open(connection)) { + mDevices.put(usbDevice.getDeviceName(), mtpDevice); + return mtpDevice; + } } } } diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java index 82251d9..68fed7b 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.mtp.MtpClient; import android.mtp.MtpConstants; import android.mtp.MtpDevice; import android.mtp.MtpObjectInfo; diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java index e9ea9f3..ef69c44 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java @@ -23,7 +23,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.MediaScannerConnection; import android.media.MediaScannerConnection.MediaScannerConnectionClient; -import android.mtp.MtpClient; import android.mtp.MtpConstants; import android.mtp.MtpObjectInfo; import android.net.Uri; diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java index 7d5a5da..64320fe 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java @@ -19,7 +19,6 @@ package com.android.camerabrowser; import android.app.ListActivity; import android.content.Context; import android.content.Intent; -import android.mtp.MtpClient; import android.mtp.MtpDevice; import android.mtp.MtpStorageInfo; import android.os.Bundle; |