summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2011-02-16 12:42:35 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-02-16 12:42:35 -0800
commit984dd8a206e782027c2b0c866aa845e6d236f218 (patch)
treebc19dd5e86fe963321b06b72b09479a6a6725907
parentca20af0c2990a969f1a793821d2ee239b0310d45 (diff)
parent9182d3c4eb1f9065cb33df5a3594969dd0d42acc (diff)
downloadframeworks_base-984dd8a206e782027c2b0c866aa845e6d236f218.zip
frameworks_base-984dd8a206e782027c2b0c866aa845e6d236f218.tar.gz
frameworks_base-984dd8a206e782027c2b0c866aa845e6d236f218.tar.bz2
Merge "UsbManager: New APIs for USB accessories"
-rw-r--r--api/current.xml209
-rw-r--r--core/java/android/hardware/IUsbManager.aidl3
-rw-r--r--core/java/android/hardware/UsbAccessory.aidl19
-rw-r--r--core/java/android/hardware/UsbAccessory.java131
-rw-r--r--core/java/android/hardware/UsbManager.java149
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--services/java/com/android/server/UsbService.java131
-rw-r--r--services/jni/com_android_server_UsbService.cpp66
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&lt;java.lang.String, android.hardware.UsbDevice&gt;"
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="&quot;android.hardware.action.USB_ACCESSORY_ATTACHED&quot;"
+ 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="&quot;android.hardware.action.USB_ACCESSORY_DETACHED&quot;"
+ 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="&quot;accessory&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_ACCESSORY_MANUFACTURER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accessory-manufacturer&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_ACCESSORY_PRODUCT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accessory-product&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_ACCESSORY_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accessory-type&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_ACCESSORY_VERSION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accessory-version&quot;"
+ 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="&quot;accessory&quot;"
+ 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)