diff options
-rw-r--r-- | api/current.xml | 209 | ||||
-rw-r--r-- | core/java/android/hardware/IUsbManager.aidl | 3 | ||||
-rw-r--r-- | core/java/android/hardware/UsbAccessory.aidl | 19 | ||||
-rw-r--r-- | core/java/android/hardware/UsbAccessory.java | 131 | ||||
-rw-r--r-- | core/java/android/hardware/UsbManager.java | 149 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 4 | ||||
-rw-r--r-- | services/java/com/android/server/UsbService.java | 131 | ||||
-rw-r--r-- | services/jni/com_android_server_UsbService.cpp | 66 |
8 files changed, 670 insertions, 42 deletions
diff --git a/api/current.xml b/api/current.xml index b136915..3164a09 100644 --- a/api/current.xml +++ b/api/current.xml @@ -94108,6 +94108,97 @@ > </field> </class> +<class name="UsbAccessory" + extends="java.lang.Object" + abstract="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.os.Parcelable"> +</implements> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getManufacturer" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getModel" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getType" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getVersion" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="parcel" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<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="UsbConstants" extends="java.lang.Object" abstract="false" @@ -95058,6 +95149,17 @@ deprecated="not deprecated" visibility="public" > +<method name="getAccessoryList" + return="android.hardware.UsbAccessory[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getDeviceList" return="java.util.HashMap<java.lang.String, android.hardware.UsbDevice>" abstract="false" @@ -95095,6 +95197,19 @@ <parameter name="function" type="java.lang.String"> </parameter> </method> +<method name="openAccessory" + return="android.os.ParcelFileDescriptor" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="accessory" type="android.hardware.UsbAccessory"> +</parameter> +</method> <method name="openDevice" return="boolean" abstract="false" @@ -95108,6 +95223,28 @@ <parameter name="device" type="android.hardware.UsbDevice"> </parameter> </method> +<field name="ACTION_USB_ACCESSORY_ATTACHED" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.hardware.action.USB_ACCESSORY_ATTACHED"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_USB_ACCESSORY_DETACHED" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.hardware.action.USB_ACCESSORY_DETACHED"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="ACTION_USB_DEVICE_ATTACHED" type="java.lang.String" transient="false" @@ -95141,6 +95278,61 @@ visibility="public" > </field> +<field name="EXTRA_ACCESSORY" + type="java.lang.String" + transient="false" + volatile="false" + value=""accessory"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_ACCESSORY_MANUFACTURER" + type="java.lang.String" + transient="false" + volatile="false" + value=""accessory-manufacturer"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_ACCESSORY_PRODUCT" + type="java.lang.String" + transient="false" + volatile="false" + value=""accessory-product"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_ACCESSORY_TYPE" + type="java.lang.String" + transient="false" + volatile="false" + value=""accessory-type"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_ACCESSORY_VERSION" + type="java.lang.String" + transient="false" + volatile="false" + value=""accessory-version"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="EXTRA_DEVICE" type="java.lang.String" transient="false" @@ -95240,6 +95432,17 @@ 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" @@ -237385,7 +237588,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="s" type="java.lang.String"> +<parameter name="key" type="java.lang.String"> </parameter> </method> <method name="describeContents" @@ -237420,7 +237623,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="s" type="java.lang.String"> +<parameter name="key" type="java.lang.String"> </parameter> </method> <method name="getIconResId" @@ -265596,7 +265799,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/IUsbManager.aidl b/core/java/android/hardware/IUsbManager.aidl index b50b6b9..6c99ab3 100644 --- a/core/java/android/hardware/IUsbManager.aidl +++ b/core/java/android/hardware/IUsbManager.aidl @@ -16,6 +16,7 @@ package android.hardware; +import android.hardware.UsbAccessory; import android.os.Bundle; import android.os.ParcelFileDescriptor; @@ -25,4 +26,6 @@ interface IUsbManager /* Returns a list of all currently attached USB devices */ void getDeviceList(out Bundle devices); ParcelFileDescriptor openDevice(String deviceName); + UsbAccessory getCurrentAccessory(); + ParcelFileDescriptor openAccessory(); } diff --git a/core/java/android/hardware/UsbAccessory.aidl b/core/java/android/hardware/UsbAccessory.aidl new file mode 100644 index 0000000..97a777b --- /dev/null +++ b/core/java/android/hardware/UsbAccessory.aidl @@ -0,0 +1,19 @@ +/* + * 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; + +parcelable UsbAccessory; diff --git a/core/java/android/hardware/UsbAccessory.java b/core/java/android/hardware/UsbAccessory.java new file mode 100644 index 0000000..71672fa --- /dev/null +++ b/core/java/android/hardware/UsbAccessory.java @@ -0,0 +1,131 @@ +/* + * 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; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +/** + * A class representing a USB accessory. + */ +public final class UsbAccessory implements Parcelable { + + private static final String TAG = "UsbAccessory"; + + private String mManufacturer; + private String mModel; + private String mType; + private String mVersion; + + private UsbAccessory() { + } + + /** + * UsbAccessory should only be instantiated by UsbService implementation + * @hide + */ + public UsbAccessory(String manufacturer, String model, String type, String version) { + mManufacturer = manufacturer; + mModel = model; + mType = type; + mVersion = version; + } + + /** + * UsbAccessory should only be instantiated by UsbService implementation + * @hide + */ + public UsbAccessory(String[] strings) { + mManufacturer = strings[0]; + mModel = strings[1]; + mType = strings[2]; + mVersion = strings[3]; + } + + /** + * Returns the manufacturer of the accessory. + * + * @return the accessory manufacturer + */ + public String getManufacturer() { + return mManufacturer; + } + + /** + * Returns the model name of the accessory. + * + * @return the accessory model + */ + public String getModel() { + return mModel; + } + + /** + * Returns the type of the accessory. + * + * @return the accessory type + */ + public String getType() { + return mType; + } + + /** + * Returns the version of the accessory. + * + * @return the accessory version + */ + public String getVersion() { + return mVersion; + } + + @Override + public String toString() { + return "UsbAccessory[mManufacturer=" + mManufacturer + + ", mModel=" + mModel + + ", mType=" + mType + + ", mVersion=" + mVersion + "]"; + } + + public static final Parcelable.Creator<UsbAccessory> CREATOR = + new Parcelable.Creator<UsbAccessory>() { + public UsbAccessory createFromParcel(Parcel in) { + String manufacturer = in.readString(); + String model = in.readString(); + String type = in.readString(); + String version = in.readString(); + return new UsbAccessory(manufacturer, model, type, version); + } + + public UsbAccessory[] newArray(int size) { + return new UsbAccessory[size]; + } + }; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mManufacturer); + parcel.writeString(mModel); + parcel.writeString(mType); + parcel.writeString(mVersion); + } +} diff --git a/core/java/android/hardware/UsbManager.java b/core/java/android/hardware/UsbManager.java index 8fad210..0f616ff 100644 --- a/core/java/android/hardware/UsbManager.java +++ b/core/java/android/hardware/UsbManager.java @@ -24,6 +24,7 @@ import android.util.Log; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; @@ -44,11 +45,14 @@ public class UsbManager { * Broadcast Action: A sticky broadcast for USB state change events when in device mode. * * This is a sticky broadcast for clients that includes USB connected/disconnected state, - * the USB configuration that is currently set and a bundle containing name/value pairs - * with the names of the functions and a value of either {@link #USB_FUNCTION_ENABLED} - * or {@link #USB_FUNCTION_DISABLED}. - * Possible USB function names include {@link #USB_FUNCTION_MASS_STORAGE}, - * {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS} and {@link #USB_FUNCTION_MTP}. + * <ul> + * <li> {@link #USB_CONNECTED} boolean indicating whether USB is connected or disconnected. + * <li> {@link #USB_CONFIGURATION} a Bundle containing name/value pairs where the name + * is the name of a USB function and the value is either {@link #USB_FUNCTION_ENABLED} + * or {@link #USB_FUNCTION_DISABLED}. The possible function names include + * {@link #USB_FUNCTION_MASS_STORAGE}, {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS}, + * {@link #USB_FUNCTION_MTP} and {@link #USB_FUNCTION_ACCESSORY}. + * </ul> */ public static final String ACTION_USB_STATE = "android.hardware.action.USB_STATE"; @@ -57,6 +61,16 @@ public class UsbManager { * Broadcast Action: A broadcast for USB device attached event. * * This intent is sent when a USB device is attached to the USB bus when in host mode. + * <ul> + * <li> {@link #EXTRA_DEVICE_NAME} containing the device's name (String) + * <li> {@link #EXTRA_VENDOR_ID} containing the device's vendor ID (Integer) + * <li> {@link #EXTRA_PRODUCT_ID} containing the device's product ID (Integer) + * <li> {@link #EXTRA_DEVICE_CLASS} } containing the device class (Integer) + * <li> {@link #EXTRA_DEVICE_SUBCLASS} containing the device subclass (Integer) + * <li> {@link #EXTRA_DEVICE_PROTOCOL} containing the device protocol (Integer) + * <li> {@link #EXTRA_DEVICE} containing the {@link android.hardware.UsbDevice} + * for the attached device + * </ul> */ public static final String ACTION_USB_DEVICE_ATTACHED = "android.hardware.action.USB_DEVICE_ATTACHED"; @@ -65,10 +79,41 @@ public class UsbManager { * Broadcast Action: A broadcast for USB device detached event. * * This intent is sent when a USB device is detached from the USB bus when in host mode. + * <ul> + * <li> {@link #EXTRA_DEVICE_NAME} containing the device's name (String) + * </ul> */ public static final String ACTION_USB_DEVICE_DETACHED = "android.hardware.action.USB_DEVICE_DETACHED"; + /** + * Broadcast Action: A broadcast for USB accessory attached event. + * + * This intent is sent when a USB accessory is attached. + * <ul> + * <li> {@link #EXTRA_ACCESSORY_MANUFACTURER} containing the accessory's manufacturer (String) + * <li> {@link #EXTRA_ACCESSORY_PRODUCT} containing the accessory's product name (String) + * <li> {@link #EXTRA_ACCESSORY_TYPE} containing the accessory's type (String) + * <li> {@link #EXTRA_ACCESSORY_VERSION} containing the accessory's version (String) + * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.UsbAccessory} + * for the attached accessory + * </ul> + */ + public static final String ACTION_USB_ACCESSORY_ATTACHED = + "android.hardware.action.USB_ACCESSORY_ATTACHED"; + + /** + * Broadcast Action: A broadcast for USB accessory detached event. + * + * This intent is sent when a USB accessory is detached. + * <ul> + * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.UsbAccessory} + * for the attached accessory that was detached + * </ul> + */ + public static final String ACTION_USB_ACCESSORY_DETACHED = + "android.hardware.action.USB_ACCESSORY_DETACHED"; + /** * Boolean extra indicating whether USB is connected or disconnected. * Used in extras for the {@link #ACTION_USB_STATE} broadcast. @@ -106,14 +151,22 @@ public class UsbManager { public static final String USB_FUNCTION_MTP = "mtp"; /** - * Value indicating that a USB function is enabled. + * Name of the Accessory USB function. * Used in extras for the {@link #ACTION_USB_STATE} broadcast */ + public static final String USB_FUNCTION_ACCESSORY = "accessory"; + + /** + * Value indicating that a USB function is enabled. + * Used in {@link #USB_CONFIGURATION} extras bundle for the + * {@link #ACTION_USB_STATE} broadcast + */ public static final String USB_FUNCTION_ENABLED = "enabled"; /** * Value indicating that a USB function is disabled. - * Used in extras for the {@link #ACTION_USB_STATE} broadcast + * Used in {@link #USB_CONFIGURATION} extras bundle for the + * {@link #ACTION_USB_STATE} broadcast */ public static final String USB_FUNCTION_DISABLED = "disabled"; @@ -158,8 +211,39 @@ public class UsbManager { * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast * containing the UsbDevice object for the device. */ + public static final String EXTRA_DEVICE = "device"; + /** + * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} broadcast + * containing the UsbAccessory object for the accessory. + */ + public static final String EXTRA_ACCESSORY = "accessory"; + + /** + * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} broadcast + * containing the accessory's manufacturer name. + */ + public static final String EXTRA_ACCESSORY_MANUFACTURER = "accessory-manufacturer"; + + /** + * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} broadcast + * containing the accessory's product name. + */ + public static final String EXTRA_ACCESSORY_PRODUCT = "accessory-product"; + + /** + * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} broadcast + * containing the accessory's type. + */ + public static final String EXTRA_ACCESSORY_TYPE = "accessory-type"; + + /** + * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} broadcast + * containing the accessory's version. + */ + public static final String EXTRA_ACCESSORY_VERSION = "accessory-version"; + private IUsbManager mService; /** @@ -214,6 +298,41 @@ public class UsbManager { } } + /** + * Returns a list of currently attached USB accessories. + * (in the current implementation there can be at most one) + * + * @return list of USB accessories, or null if none are attached. + */ + public UsbAccessory[] getAccessoryList() { + try { + UsbAccessory accessory = mService.getCurrentAccessory(); + if (accessory == null) { + return null; + } else { + return new UsbAccessory[] { accessory }; + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in openAccessory" , e); + return null; + } + } + + /** + * Opens a file descriptor for reading and writing data to the USB accessory. + * + * @param accessory the USB accessory to open + * @return file descriptor, or null if the accessor could not be opened. + */ + public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { + try { + return mService.openAccessory(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in openAccessory" , e); + return null; + } + } + private static File getFunctionEnableFile(String function) { return new File("/sys/class/usb_composite/" + function + "/enable"); } @@ -245,4 +364,20 @@ public class UsbManager { return false; } } + + /** + * Enables or disables a USB function. + * + * @hide + */ + public static boolean setFunctionEnabled(String function, boolean enable) { + try { + FileOutputStream stream = new FileOutputStream(getFunctionEnableFile(function)); + stream.write(enable ? '1' : '0'); + stream.close(); + return true; + } catch (IOException e) { + return false; + } + } } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 8e8383a..1df6fe5 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -82,9 +82,9 @@ <protected-broadcast android:name="android.bluetooth.device.action.PAIRING_REQUEST" /> <protected-broadcast android:name="android.bluetooth.device.action.PAIRING_CANCEL" /> - <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_ACCESSORY_ATTACHED" /> + <protected-broadcast android:name="android.hardware.action.USB_ACCESSORY_ATTACHED" /> <protected-broadcast android:name="android.hardware.action.USB_DEVICE_ATTACHED" /> <protected-broadcast android:name="android.hardware.action.USB_DEVICE_DETACHED" /> diff --git a/services/java/com/android/server/UsbService.java b/services/java/com/android/server/UsbService.java index 460fd4d..af4c425 100644 --- a/services/java/com/android/server/UsbService.java +++ b/services/java/com/android/server/UsbService.java @@ -20,6 +20,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.hardware.IUsbManager; +import android.hardware.UsbAccessory; import android.hardware.UsbConstants; import android.hardware.UsbDevice; import android.hardware.UsbEndpoint; @@ -78,18 +79,63 @@ class UsbService extends IUsbManager.Stub { private int mLastConfiguration = -1; // lists of enabled and disabled USB functions (for USB device mode) + // synchronize on mEnabledFunctions when using either of these lists private final ArrayList<String> mEnabledFunctions = new ArrayList<String>(); private final ArrayList<String> mDisabledFunctions = new ArrayList<String>(); + // contains all connected USB devices (for USB host mode) private final HashMap<String,UsbDevice> mDevices = new HashMap<String,UsbDevice>(); // USB busses to exclude from USB host support private final String[] mHostBlacklist; private boolean mSystemReady; + private UsbAccessory mCurrentAccessory; private final Context mContext; + private final void functionEnabled(String function, boolean enabled) { + synchronized (mEnabledFunctions) { + if (enabled) { + if (!mEnabledFunctions.contains(function)) { + mEnabledFunctions.add(function); + } + mDisabledFunctions.remove(function); + } else { + if (!mDisabledFunctions.contains(function)) { + mDisabledFunctions.add(function); + } + mEnabledFunctions.remove(function); + } + } + + if (enabled && UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) { + String[] strings = nativeGetAccessoryStrings(); + if (strings != null) { + Log.d(TAG, "entering USB accessory mode"); + mCurrentAccessory = new UsbAccessory(strings); + Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED); + intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory); + // add strings as separate extras to allow filtering + if (strings[0] != null) { + intent.putExtra(UsbManager.EXTRA_ACCESSORY_MANUFACTURER, strings[0]); + } + if (strings[1] != null) { + intent.putExtra(UsbManager.EXTRA_ACCESSORY_PRODUCT, strings[1]); + } + if (strings[2] != null) { + intent.putExtra(UsbManager.EXTRA_ACCESSORY_TYPE, strings[2]); + } + if (strings[3] != null) { + intent.putExtra(UsbManager.EXTRA_ACCESSORY_VERSION, strings[3]); + } + mContext.sendBroadcast(intent); + } else { + Log.e(TAG, "nativeGetAccessoryStrings failed"); + } + } + } + private final UEventObserver mUEventObserver = new UEventObserver() { @Override public void onUEvent(UEventObserver.UEvent event) { @@ -127,17 +173,7 @@ class UsbService extends IUsbManager.Stub { // Note: we do not broadcast a change when a function is enabled or disabled. // We just record the state change for the next broadcast. boolean enabled = "1".equals(enabledStr); - if (enabled) { - if (!mEnabledFunctions.contains(function)) { - mEnabledFunctions.add(function); - } - mDisabledFunctions.remove(function); - } else { - if (!mDisabledFunctions.contains(function)) { - mDisabledFunctions.add(function); - } - mEnabledFunctions.remove(function); - } + functionEnabled(function, enabled); } } } @@ -182,18 +218,20 @@ class UsbService extends IUsbManager.Stub { return; try { - File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles(); - for (int i = 0; i < files.length; i++) { - File file = new File(files[i], "enable"); - FileReader reader = new FileReader(file); - int len = reader.read(buffer, 0, 1024); - reader.close(); - int value = Integer.valueOf((new String(buffer, 0, len)).trim()); - String functionName = files[i].getName(); - if (value == 1) { - mEnabledFunctions.add(functionName); - } else { - mDisabledFunctions.add(functionName); + synchronized (mEnabledFunctions) { + File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles(); + for (int i = 0; i < files.length; i++) { + File file = new File(files[i], "enable"); + FileReader reader = new FileReader(file); + int len = reader.read(buffer, 0, 1024); + reader.close(); + int value = Integer.valueOf((new String(buffer, 0, len)).trim()); + String functionName = files[i].getName(); + if (value == 1) { + mEnabledFunctions.add(functionName); + } else { + mDisabledFunctions.add(functionName); + } } } } catch (FileNotFoundException e) { @@ -359,19 +397,32 @@ class UsbService extends IUsbManager.Stub { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); if (mDevices.get(deviceName) == null) { // if it is not in mDevices, it either does not exist or is blacklisted - throw new IllegalArgumentException("device " + deviceName + " does not exist or is restricted"); + throw new IllegalArgumentException( + "device " + deviceName + " does not exist or is restricted"); } return nativeOpenDevice(deviceName); } + public UsbAccessory getCurrentAccessory() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); + return mCurrentAccessory; + } + + public ParcelFileDescriptor openAccessory() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); + return nativeOpenAccessory(); + } + private final Handler mHandler = new Handler() { private void addEnabledFunctions(Intent intent) { + synchronized (mEnabledFunctions) { // include state of all USB functions in our extras - for (int i = 0; i < mEnabledFunctions.size(); i++) { - intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED); - } - for (int i = 0; i < mDisabledFunctions.size(); i++) { - intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED); + for (int i = 0; i < mEnabledFunctions.size(); i++) { + intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED); + } + for (int i = 0; i < mDisabledFunctions.size(); i++) { + intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED); + } } } @@ -381,6 +432,26 @@ class UsbService extends IUsbManager.Stub { case MSG_UPDATE: synchronized (this) { if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) { + if (mConnected == 0 && mCurrentAccessory != null) { + // turn off accessory mode when we are disconnected + if (UsbManager.setFunctionEnabled( + UsbManager.USB_FUNCTION_ACCESSORY, false)) { + Log.d(TAG, "exited USB accessory mode"); + + Intent intent = new Intent( + UsbManager.ACTION_USB_ACCESSORY_DETACHED); + intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory); + mContext.sendBroadcast(intent); + mCurrentAccessory = null; + + // this will cause an immediate reset of the USB bus, + // so there is no point in sending the + // function disabled broadcast. + return; + } else { + Log.e(TAG, "could not disable USB_FUNCTION_ACCESSORY"); + } + } final ContentResolver cr = mContext.getContentResolver(); if (Settings.Secure.getInt(cr, @@ -408,4 +479,6 @@ class UsbService extends IUsbManager.Stub { private native void monitorUsbHostBus(); private native ParcelFileDescriptor nativeOpenDevice(String deviceName); + private native String[] nativeGetAccessoryStrings(); + private native ParcelFileDescriptor nativeOpenAccessory(); } diff --git a/services/jni/com_android_server_UsbService.cpp b/services/jni/com_android_server_UsbService.cpp index ef22111..192daaf 100644 --- a/services/jni/com_android_server_UsbService.cpp +++ b/services/jni/com_android_server_UsbService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -26,6 +26,13 @@ #include <stdio.h> #include <asm/byteorder.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/usb/f_accessory.h> + +#define DRIVER_NAME "/dev/usb_accessory" namespace android { @@ -164,10 +171,67 @@ static jobject android_server_UsbService_openDevice(JNIEnv *env, jobject thiz, j gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); } +static void set_accessory_string(JNIEnv *env, int fd, int cmd, jobjectArray strArray, int index) +{ + char buffer[256]; + + buffer[0] = 0; + int length = ioctl(fd, cmd, buffer); + LOGD("ioctl returned %d", length); + if (buffer[0]) { + jstring obj = env->NewStringUTF(buffer); + env->SetObjectArrayElement(strArray, index, obj); + env->DeleteLocalRef(obj); + } +} + + +static jobjectArray android_server_UsbService_getAccessoryStrings(JNIEnv *env, jobject thiz) +{ + int fd = open(DRIVER_NAME, O_RDWR); + if (fd < 0) { + LOGE("could not open %s", DRIVER_NAME); + return NULL; + } + jclass stringClass = env->FindClass("java/lang/String"); + jobjectArray strArray = env->NewObjectArray(4, stringClass, NULL); + if (!strArray) goto out; + set_accessory_string(env, fd, ACCESSORY_GET_STRING_MANUFACTURER, strArray, 0); + set_accessory_string(env, fd, ACCESSORY_GET_STRING_MODEL, strArray, 1); + set_accessory_string(env, fd, ACCESSORY_GET_STRING_TYPE, strArray, 2); + set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3); + +out: + close(fd); + return strArray; +} + +static jobject android_server_UsbService_openAccessory(JNIEnv *env, jobject thiz) +{ + int fd = open(DRIVER_NAME, O_RDWR); + if (fd < 0) { + LOGE("could not open %s", DRIVER_NAME); + return NULL; + } + jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass, + gFileDescriptorOffsets.mConstructor); + if (fileDescriptor != NULL) { + env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, fd); + } else { + return NULL; + } + return env->NewObject(gParcelFileDescriptorOffsets.mClass, + gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); +} + static JNINativeMethod method_table[] = { { "monitorUsbHostBus", "()V", (void*)android_server_UsbService_monitorUsbHostBus }, { "nativeOpenDevice", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", (void*)android_server_UsbService_openDevice }, + { "nativeGetAccessoryStrings", "()[Ljava/lang/String;", + (void*)android_server_UsbService_getAccessoryStrings }, + { "nativeOpenAccessory","()Landroid/os/ParcelFileDescriptor;", + (void*)android_server_UsbService_openAccessory }, }; int register_android_server_UsbService(JNIEnv *env) |