am 78b8e1be: Merge "DO NOT MERGE: backport recent USB accessory changes from honeycomb" into gingerbread

* commit '78b8e1be97c61f7e0b28b145fadd0c646fd1c46b':
  DO NOT MERGE: backport recent USB accessory changes from honeycomb
This commit is contained in:
Mike Lockwood
2011-03-14 13:37:54 -07:00
committed by Android Git Automerger
17 changed files with 943 additions and 240 deletions

View File

@@ -1155,7 +1155,7 @@ class ContextImpl extends Context {
if (mUsbManager == null) { if (mUsbManager == null) {
IBinder b = ServiceManager.getService(USB_SERVICE); IBinder b = ServiceManager.getService(USB_SERVICE);
IUsbManager service = IUsbManager.Stub.asInterface(b); IUsbManager service = IUsbManager.Stub.asInterface(b);
mUsbManager = new UsbManager(service); mUsbManager = new UsbManager(this, service);
} }
} }
return mUsbManager; return mUsbManager;

View File

@@ -16,6 +16,7 @@
package android.hardware.usb; package android.hardware.usb;
import android.app.PendingIntent;
import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbAccessory;
import android.os.Bundle; import android.os.Bundle;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
@@ -36,12 +37,22 @@ interface IUsbManager
*/ */
void setAccessoryPackage(in UsbAccessory accessory, String packageName); void setAccessoryPackage(in UsbAccessory accessory, String packageName);
/* Returns true if the caller has permission to access the accessory. */
boolean hasAccessoryPermission(in UsbAccessory accessory);
/* Requests permission for the given package to access the accessory.
* Will display a system dialog to query the user if permission
* had not already been given. Result is returned via pi.
*/
void requestAccessoryPermission(in UsbAccessory accessory, String packageName,
in PendingIntent pi);
/* Grants permission for the given UID to access the accessory */ /* Grants permission for the given UID to access the accessory */
void grantAccessoryPermission(in UsbAccessory accessory, int uid); void grantAccessoryPermission(in UsbAccessory accessory, int uid);
/* Returns true if the USB manager has default preferences or permissions for the package */ /* Returns true if the USB manager has default preferences or permissions for the package */
boolean hasDefaults(String packageName, int uid); boolean hasDefaults(String packageName);
/* Clears default preferences and permissions for the package */ /* Clears default preferences and permissions for the package */
oneway void clearDefaults(String packageName, int uid); void clearDefaults(String packageName);
} }

View File

@@ -31,18 +31,21 @@ public class UsbAccessory implements Parcelable {
private final String mManufacturer; private final String mManufacturer;
private final String mModel; private final String mModel;
private final String mType; private final String mDescription;
private final String mVersion; private final String mVersion;
private final String mUri;
/** /**
* UsbAccessory should only be instantiated by UsbService implementation * UsbAccessory should only be instantiated by UsbService implementation
* @hide * @hide
*/ */
public UsbAccessory(String manufacturer, String model, String type, String version) { public UsbAccessory(String manufacturer, String model, String description,
String version, String uri) {
mManufacturer = manufacturer; mManufacturer = manufacturer;
mModel = model; mModel = model;
mType = type; mDescription = description;
mVersion = version; mVersion = version;
mUri = uri;
} }
/** /**
@@ -52,8 +55,9 @@ public class UsbAccessory implements Parcelable {
public UsbAccessory(String[] strings) { public UsbAccessory(String[] strings) {
mManufacturer = strings[0]; mManufacturer = strings[0];
mModel = strings[1]; mModel = strings[1];
mType = strings[2]; mDescription = strings[2];
mVersion = strings[3]; mVersion = strings[3];
mUri = strings[4];
} }
/** /**
@@ -75,12 +79,12 @@ public class UsbAccessory implements Parcelable {
} }
/** /**
* Returns the type of the accessory. * Returns a user visible description of the accessory.
* *
* @return the accessory type * @return the accessory description
*/ */
public String getType() { public String getDescription() {
return mType; return mDescription;
} }
/** /**
@@ -92,6 +96,17 @@ public class UsbAccessory implements Parcelable {
return mVersion; return mVersion;
} }
/**
* Returns the URI for the accessory.
* This is an optional URI that might show information about the accessory
* or provide the option to download an application for the accessory
*
* @return the accessory URI
*/
public String getUri() {
return mUri;
}
private static boolean compare(String s1, String s2) { private static boolean compare(String s1, String s2) {
if (s1 == null) return (s2 == null); if (s1 == null) return (s2 == null);
return s1.equals(s2); return s1.equals(s2);
@@ -103,18 +118,29 @@ public class UsbAccessory implements Parcelable {
UsbAccessory accessory = (UsbAccessory)obj; UsbAccessory accessory = (UsbAccessory)obj;
return (compare(mManufacturer, accessory.getManufacturer()) && return (compare(mManufacturer, accessory.getManufacturer()) &&
compare(mModel, accessory.getModel()) && compare(mModel, accessory.getModel()) &&
compare(mType, accessory.getType()) && compare(mDescription, accessory.getDescription()) &&
compare(mVersion, accessory.getVersion())); compare(mVersion, accessory.getVersion()) &&
compare(mUri, accessory.getUri()));
} }
return false; return false;
} }
@Override
public int hashCode() {
return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
(mModel == null ? 0 : mModel.hashCode()) ^
(mDescription == null ? 0 : mDescription.hashCode()) ^
(mVersion == null ? 0 : mVersion.hashCode()) ^
(mUri == null ? 0 : mUri.hashCode()));
}
@Override @Override
public String toString() { public String toString() {
return "UsbAccessory[mManufacturer=" + mManufacturer + return "UsbAccessory[mManufacturer=" + mManufacturer +
", mModel=" + mModel + ", mModel=" + mModel +
", mType=" + mType + ", mDescription=" + mDescription +
", mVersion=" + mVersion + "]"; ", mVersion=" + mVersion +
", mUri=" + mUri + "]";
} }
public static final Parcelable.Creator<UsbAccessory> CREATOR = public static final Parcelable.Creator<UsbAccessory> CREATOR =
@@ -122,9 +148,10 @@ public class UsbAccessory implements Parcelable {
public UsbAccessory createFromParcel(Parcel in) { public UsbAccessory createFromParcel(Parcel in) {
String manufacturer = in.readString(); String manufacturer = in.readString();
String model = in.readString(); String model = in.readString();
String type = in.readString(); String description = in.readString();
String version = in.readString(); String version = in.readString();
return new UsbAccessory(manufacturer, model, type, version); String uri = in.readString();
return new UsbAccessory(manufacturer, model, description, version, uri);
} }
public UsbAccessory[] newArray(int size) { public UsbAccessory[] newArray(int size) {
@@ -139,7 +166,8 @@ public class UsbAccessory implements Parcelable {
public void writeToParcel(Parcel parcel, int flags) { public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mManufacturer); parcel.writeString(mManufacturer);
parcel.writeString(mModel); parcel.writeString(mModel);
parcel.writeString(mType); parcel.writeString(mDescription);
parcel.writeString(mVersion); parcel.writeString(mVersion);
parcel.writeString(mUri);
} }
} }

View File

@@ -17,6 +17,8 @@
package android.hardware.usb; package android.hardware.usb;
import android.app.PendingIntent;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
@@ -75,7 +77,7 @@ public class UsbManager {
* *
* This intent is sent when a USB accessory is detached. * This intent is sent when a USB accessory is detached.
* <ul> * <ul>
* <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.usb.UsbAccessory} * <li> {@link #EXTRA_ACCESSORY} containing the {@link UsbAccessory}
* for the attached accessory that was detached * for the attached accessory that was detached
* </ul> * </ul>
*/ */
@@ -145,12 +147,22 @@ public class UsbManager {
*/ */
public static final String EXTRA_ACCESSORY = "accessory"; public static final String EXTRA_ACCESSORY = "accessory";
private IUsbManager mService; /**
* Name of extra added to the {@link android.app.PendingIntent}
* passed into {@link #requestPermission(UsbDevice, PendingIntent)}
* or {@link #requestPermission(UsbAccessory, PendingIntent)}
* containing a boolean value indicating whether the user granted permission or not.
*/
public static final String EXTRA_PERMISSION_GRANTED = "permission";
private final Context mContext;
private final IUsbManager mService;
/** /**
* {@hide} * {@hide}
*/ */
public UsbManager(IUsbManager service) { public UsbManager(Context context, IUsbManager service) {
mContext = context;
mService = service; mService = service;
} }
@@ -169,7 +181,7 @@ public class UsbManager {
return new UsbAccessory[] { accessory }; return new UsbAccessory[] { accessory };
} }
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "RemoteException in getAccessoryList" , e); Log.e(TAG, "RemoteException in getAccessoryList", e);
return null; return null;
} }
} }
@@ -184,11 +196,55 @@ public class UsbManager {
try { try {
return mService.openAccessory(accessory); return mService.openAccessory(accessory);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "RemoteException in openAccessory" , e); Log.e(TAG, "RemoteException in openAccessory", e);
return null; return null;
} }
} }
/**
* Returns true if the caller has permission to access the accessory.
* Permission might have been granted temporarily via
* {@link #requestPermission(UsbAccessory, PendingIntent)} or
* by the user choosing the caller as the default application for the accessory.
*
* @param accessory to check permissions for
* @return true if caller has permission
*/
public boolean hasPermission(UsbAccessory accessory) {
try {
return mService.hasAccessoryPermission(accessory);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in hasPermission", e);
return false;
}
}
/**
* Requests temporary permission for the given package to access the accessory.
* This may result in a system dialog being displayed to the user
* if permission had not already been granted.
* Success or failure is returned via the {@link android.app.PendingIntent} pi.
* If successful, this grants the caller permission to access the accessory only
* until the device is disconnected.
*
* The following extras will be added to pi:
* <ul>
* <li> {@link #EXTRA_ACCESSORY} containing the accessory passed into this call
* <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
* permission was granted by the user
* </ul>
*
* @param accessory to request permissions for
* @param pi PendingIntent for returning result
*/
public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
try {
mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in requestPermission", e);
}
}
private static File getFunctionEnableFile(String function) { private static File getFunctionEnableFile(String function) {
return new File("/sys/class/usb_composite/" + function + "/enable"); return new File("/sys/class/usb_composite/" + function + "/enable");
} }

View File

@@ -23,14 +23,16 @@ public final class UsbAccessory {
private final String mManufacturer; private final String mManufacturer;
private final String mModel; private final String mModel;
private final String mType; private final String mDescription;
private final String mVersion; private final String mVersion;
private final String mUri;
/* package */ UsbAccessory(android.hardware.usb.UsbAccessory accessory) { /* package */ UsbAccessory(android.hardware.usb.UsbAccessory accessory) {
mManufacturer = accessory.getManufacturer(); mManufacturer = accessory.getManufacturer();
mModel = accessory.getModel(); mModel = accessory.getModel();
mType = accessory.getType(); mDescription = accessory.getDescription();
mVersion = accessory.getVersion(); mVersion = accessory.getVersion();
mUri = accessory.getUri();
} }
/** /**
@@ -52,12 +54,12 @@ public final class UsbAccessory {
} }
/** /**
* Returns the type of the accessory. * Returns a user visible description of the accessory.
* *
* @return the accessory type * @return the accessory description
*/ */
public String getType() { public String getDescription() {
return mType; return mDescription;
} }
/** /**
@@ -69,6 +71,17 @@ public final class UsbAccessory {
return mVersion; return mVersion;
} }
/**
* Returns the URI for the accessory.
* This is an optional URI that might show information about the accessory
* or provide the option to download an application for the accessory
*
* @return the accessory URI
*/
public String getUri() {
return mUri;
}
private static boolean compare(String s1, String s2) { private static boolean compare(String s1, String s2) {
if (s1 == null) return (s2 == null); if (s1 == null) return (s2 == null);
return s1.equals(s2); return s1.equals(s2);
@@ -80,17 +93,28 @@ public final class UsbAccessory {
UsbAccessory accessory = (UsbAccessory)obj; UsbAccessory accessory = (UsbAccessory)obj;
return (compare(mManufacturer, accessory.getManufacturer()) && return (compare(mManufacturer, accessory.getManufacturer()) &&
compare(mModel, accessory.getModel()) && compare(mModel, accessory.getModel()) &&
compare(mType, accessory.getType()) && compare(mDescription, accessory.getDescription()) &&
compare(mVersion, accessory.getVersion())); compare(mVersion, accessory.getVersion()) &&
compare(mUri, accessory.getUri()));
} }
return false; return false;
} }
@Override
public int hashCode() {
return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
(mModel == null ? 0 : mModel.hashCode()) ^
(mDescription == null ? 0 : mDescription.hashCode()) ^
(mVersion == null ? 0 : mVersion.hashCode()) ^
(mUri == null ? 0 : mUri.hashCode()));
}
@Override @Override
public String toString() { public String toString() {
return "UsbAccessory[mManufacturer=" + mManufacturer + return "UsbAccessory[mManufacturer=" + mManufacturer +
", mModel=" + mModel + ", mModel=" + mModel +
", mType=" + mType + ", mDescription=" + mDescription +
", mVersion=" + mVersion + "]"; ", mVersion=" + mVersion +
", mUri=" + mUri + "]";
} }
} }

View File

@@ -17,6 +17,7 @@
package com.android.future.usb; package com.android.future.usb;
import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.hardware.usb.IUsbManager; import android.hardware.usb.IUsbManager;
@@ -55,28 +56,39 @@ public class UsbManager {
public static final String ACTION_USB_ACCESSORY_DETACHED = public static final String ACTION_USB_ACCESSORY_DETACHED =
"android.hardware.usb.action.USB_ACCESSORY_DETACHED"; "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
/**
* Name of extra added to the {@link android.app.PendingIntent}
* passed into {#requestPermission} or {#requestPermission}
* containing a boolean value indicating whether the user granted permission or not.
*/
public static final String EXTRA_PERMISSION_GRANTED = "permission";
private final Context mContext;
private final IUsbManager mService; private final IUsbManager mService;
private UsbManager(IUsbManager service) { private UsbManager(Context context, IUsbManager service) {
mContext = context;
mService = service; mService = service;
} }
/** /**
* Returns a new instance of this class. * Returns a new instance of this class.
* *
* @param context the caller's {@link android.content.Context}
* @return UsbManager instance. * @return UsbManager instance.
*/ */
public static UsbManager getInstance() { public static UsbManager getInstance(Context context) {
IBinder b = ServiceManager.getService(Context.USB_SERVICE); IBinder b = ServiceManager.getService(Context.USB_SERVICE);
return new UsbManager(IUsbManager.Stub.asInterface(b)); return new UsbManager(context, IUsbManager.Stub.asInterface(b));
} }
/** /**
* Returns the {@link com.google.android.usb.UsbAccessory} for * Returns the {@link com.google.android.usb.UsbAccessory} for
* a {@link #ACTION_USB_ACCESSORY_ATTACHED} or {@link #ACTION_USB_ACCESSORY_ATTACHED} * a {@link #ACTION_USB_ACCESSORY_ATTACHED} or {@link #ACTION_USB_ACCESSORY_ATTACHED}
* broadcast Intent * broadcast Intent. This can also be used to retrieve the accessory from the result
* of a call to {#requestPermission}.
* *
* @return UsbAccessory for the broadcast. * @return UsbAccessory for the intent.
*/ */
public static UsbAccessory getAccessory(Intent intent) { public static UsbAccessory getAccessory(Intent intent) {
android.hardware.usb.UsbAccessory accessory = android.hardware.usb.UsbAccessory accessory =
@@ -118,10 +130,54 @@ public class UsbManager {
try { try {
return mService.openAccessory(new android.hardware.usb.UsbAccessory( return mService.openAccessory(new android.hardware.usb.UsbAccessory(
accessory.getManufacturer(),accessory.getModel(), accessory.getManufacturer(),accessory.getModel(),
accessory.getType(), accessory.getVersion())); accessory.getDescription(), accessory.getVersion(), accessory.getUri()));
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "RemoteException in openAccessory" , e); Log.e(TAG, "RemoteException in openAccessory" , e);
return null; return null;
} }
} }
/**
* Returns true if the caller has permission to access the accessory.
* Permission might have been granted temporarily via
* {@link #requestPermission(android.hardware.usb.UsbAccessory} or
* by the user choosing the caller as the default application for the accessory.
*
* @param accessory to check permissions for
* @return true if caller has permission
*/
public boolean hasPermission(UsbAccessory accessory) {
try {
return mService.hasAccessoryPermission(new android.hardware.usb.UsbAccessory(
accessory.getManufacturer(),accessory.getModel(),
accessory.getDescription(), accessory.getVersion(), accessory.getUri()));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in hasPermission", e);
return false;
}
}
/**
* Requests temporary permission for the given package to access the accessory.
* This may result in a system dialog being displayed to the user
* if permission had not already been granted.
* Success or failure is returned via the {@link android.app.PendingIntent} pi.
* The boolean extra {@link #EXTRA_PERMISSION_GRANTED} will be attached to the
* PendingIntent to indicate success or failure.
* If successful, this grants the caller permission to access the device only
* until the device is disconnected.
*
* @param accessory to request permissions for
* @param pi PendingIntent for returning result
*/
public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
try {
mService.requestAccessoryPermission(new android.hardware.usb.UsbAccessory(
accessory.getManufacturer(),accessory.getModel(),
accessory.getDescription(), accessory.getVersion(), accessory.getUri()),
mContext.getPackageName(), pi);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in requestPermission", e);
}
}
} }

View File

@@ -133,10 +133,19 @@ static int usb_device_added(const char *devname, void* client_data) {
} else { } else {
printf("Found possible android device - attempting to switch to accessory mode\n"); printf("Found possible android device - attempting to switch to accessory mode\n");
uint16_t protocol;
ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,
ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0);
if (ret == 2)
printf("device supports protocol version %d\n", protocol);
else
fprintf(stderr, "failed to read protocol version\n");
send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc."); send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc.");
send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat"); send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat");
send_string(device, ACCESSORY_STRING_TYPE, "Sample Program"); send_string(device, ACCESSORY_STRING_DESCRIPTION, "Sample Program");
send_string(device, ACCESSORY_STRING_VERSION, "1.0"); send_string(device, ACCESSORY_STRING_VERSION, "1.0");
send_string(device, ACCESSORY_STRING_URI, "http://www.android.com");
ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
ACCESSORY_START, 0, 0, 0, 0, 0); ACCESSORY_START, 0, 0, 0, 0, 0);

View File

@@ -17,9 +17,11 @@
package com.android.accessorychat; package com.android.accessorychat;
import android.app.Activity; import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
@@ -42,18 +44,47 @@ import java.io.IOException;
public class AccessoryChat extends Activity implements Runnable, TextView.OnEditorActionListener { public class AccessoryChat extends Activity implements Runnable, TextView.OnEditorActionListener {
private static final String TAG = "AccessoryChat"; private static final String TAG = "AccessoryChat";
TextView mLog;
EditText mEditText; private static final String ACTION_USB_PERMISSION =
ParcelFileDescriptor mFileDescriptor; "com.android.accessorychat.action.USB_PERMISSION";
FileInputStream mInputStream;
FileOutputStream mOutputStream; private TextView mLog;
private EditText mEditText;
private ParcelFileDescriptor mFileDescriptor;
private FileInputStream mInputStream;
private FileOutputStream mOutputStream;
private UsbManager mUsbManager;
private PendingIntent mPermissionIntent;
private boolean mPermissionRequestPending;
private static final int MESSAGE_LOG = 1; private static final int MESSAGE_LOG = 1;
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
synchronized (this) {
UsbAccessory accessory = UsbManager.getAccessory(intent);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
openAccessory(accessory);
} else {
Log.d(TAG, "permission denied for accessory " + accessory);
}
mPermissionRequestPending = false;
}
}
}
};
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
mUsbManager = UsbManager.getInstance(this);
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
setContentView(R.layout.accessory_chat); setContentView(R.layout.accessory_chat);
mLog = (TextView)findViewById(R.id.log); mLog = (TextView)findViewById(R.id.log);
mEditText = (EditText)findViewById(R.id.message); mEditText = (EditText)findViewById(R.id.message);
@@ -66,21 +97,20 @@ public class AccessoryChat extends Activity implements Runnable, TextView.OnEdit
Intent intent = getIntent(); Intent intent = getIntent();
Log.d(TAG, "intent: " + intent); Log.d(TAG, "intent: " + intent);
UsbManager manager = UsbManager.getInstance(); UsbAccessory[] accessories = mUsbManager.getAccessoryList();
UsbAccessory[] accessories = manager.getAccessoryList();
UsbAccessory accessory = (accessories == null ? null : accessories[0]); UsbAccessory accessory = (accessories == null ? null : accessories[0]);
if (accessory != null) { if (accessory != null) {
mFileDescriptor = manager.openAccessory(accessory); if (mUsbManager.hasPermission(accessory)) {
if (mFileDescriptor != null) { openAccessory(accessory);
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Thread thread = new Thread(null, this, "AccessoryChat");
thread.start();
} else { } else {
Log.d(TAG, "openAccessory fail"); synchronized (mUsbReceiver) {
if (!mPermissionRequestPending) {
mUsbManager.requestPermission(accessory, mPermissionIntent);
mPermissionRequestPending = true;
}
}
} }
} else { } else {
Log.d(TAG, "mAccessory is null"); Log.d(TAG, "mAccessory is null");
} }
} }
@@ -100,9 +130,24 @@ public class AccessoryChat extends Activity implements Runnable, TextView.OnEdit
@Override @Override
public void onDestroy() { public void onDestroy() {
unregisterReceiver(mUsbReceiver);
super.onDestroy(); super.onDestroy();
} }
private void openAccessory(UsbAccessory accessory) {
mFileDescriptor = mUsbManager.openAccessory(accessory);
if (mFileDescriptor != null) {
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Thread thread = new Thread(null, this, "AccessoryChat");
thread.start();
Log.d(TAG, "openAccessory succeeded");
} else {
Log.d(TAG, "openAccessory fail");
}
}
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE && mOutputStream != null) { if (actionId == EditorInfo.IME_ACTION_DONE && mOutputStream != null) {
try { try {

View File

@@ -5,6 +5,7 @@
> >
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<uses-permission android:name="android.permission.MANAGE_USB" />
<application <application
android:persistent="true" android:persistent="true"
@@ -25,5 +26,31 @@
android:excludeFromRecents="true"> android:excludeFromRecents="true">
</activity> </activity>
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbPermissionActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
android:theme="@*android:style/Theme.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbResolverActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
android:theme="@*android:style/Theme.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbAccessoryUriActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
android:theme="@*android:style/Theme.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
</application> </application>
</manifest> </manifest>

View File

@@ -51,4 +51,19 @@
power usage activity to find out what drained the battery. --> power usage activity to find out what drained the battery. -->
<string name="battery_low_why">Battery use</string> <string name="battery_low_why">Battery use</string>
<!-- Prompt for the USB accessory permission dialog [CHAR LIMIT=80] -->
<string name="usb_accessory_permission_prompt">Allow the application %1$s to access the USB accessory?</string>
<!-- Prompt for the USB accessory URI dialog [CHAR LIMIT=80] -->
<string name="usb_accessory_uri_prompt">Additional information for this device may be found at: %1$s</string>
<!-- Title for USB accessory dialog. Used when the name of the accessory cannot be determined. [CHAR LIMIT=50] -->
<string name="title_usb_accessory">USB accessory</string>
<!-- View button label for USB dialogs. [CHAR LIMIT=15] -->
<string name="label_view">View</string>
<!-- Ignore button label for USB dialogs. [CHAR LIMIT=15] -->
<string name="label_ignore">Ignore</string>
</resources> </resources>

View File

@@ -0,0 +1,100 @@
/*
* 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 com.android.systemui.usb;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.util.Log;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.systemui.R;
/**
* If the attached USB accessory has a URL associated with it, and that URL is valid,
* show this dialog to the user to allow them to optionally visit that URL for more
* information or software downloads.
* Otherwise (no valid URL) this activity does nothing at all, finishing immediately.
*/
public class UsbAccessoryUriActivity extends AlertActivity
implements DialogInterface.OnClickListener {
private static final String TAG = "UsbAccessoryUriActivity";
private UsbAccessory mAccessory;
private Uri mUri;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = getIntent();
mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
String uriString = intent.getStringExtra("uri");
mUri = (uriString == null ? null : Uri.parse(uriString));
// sanity check before displaying dialog
if (mUri == null) {
Log.e(TAG, "could not parse Uri " + uriString);
finish();
return;
}
String scheme = mUri.getScheme();
if (!"http".equals(scheme) && !"https".equals(scheme)) {
Log.e(TAG, "Uri not http or https: " + mUri);
finish();
return;
}
final AlertController.AlertParams ap = mAlertParams;
ap.mTitle = mAccessory.getDescription();
if (ap.mTitle == null || ap.mTitle.length() == 0) {
ap.mTitle = getString(R.string.title_usb_accessory);
}
ap.mMessage = getString(R.string.usb_accessory_uri_prompt, mUri);
ap.mPositiveButtonText = getString(R.string.label_view);
ap.mNegativeButtonText = getString(R.string.label_ignore);
ap.mPositiveButtonListener = this;
ap.mNegativeButtonListener = this;
setupAlert();
}
public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) {
// launch the browser
Intent intent = new Intent(Intent.ACTION_VIEW, mUri);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "startActivity failed for " + mUri);
}
}
finish();
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.usb;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
// This class is used to close UsbPermissionsActivity and UsbResolverActivity
// if their accessory is disconnected while the dialog is still open
class UsbDisconnectedReceiver extends BroadcastReceiver {
private final Activity mActivity;
private UsbAccessory mAccessory;
public UsbDisconnectedReceiver(Activity activity, UsbAccessory accessory) {
mActivity = activity;
mAccessory = accessory;
IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
activity.registerReceiver(this, filter);
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
UsbAccessory accessory =
(UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (accessory != null && accessory.equals(mAccessory)) {
mActivity.finish();
}
}
}
}

View File

@@ -0,0 +1,153 @@
/*
* 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 com.android.systemui.usb;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.systemui.R;
public class UsbPermissionActivity extends AlertActivity
implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
private static final String TAG = "UsbPermissionActivity";
private CheckBox mAlwaysCheck;
private TextView mClearDefaultHint;
private UsbAccessory mAccessory;
private PendingIntent mPendingIntent;
private String mPackageName;
private int mUid;
private boolean mPermissionGranted;
private UsbDisconnectedReceiver mDisconnectedReceiver;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = getIntent();
mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT);
mUid = intent.getIntExtra("uid", 0);
mPackageName = intent.getStringExtra("package");
PackageManager packageManager = getPackageManager();
ApplicationInfo aInfo;
try {
aInfo = packageManager.getApplicationInfo(mPackageName, 0);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "unable to look up package name", e);
finish();
return;
}
String appName = aInfo.loadLabel(packageManager).toString();
final AlertController.AlertParams ap = mAlertParams;
ap.mIcon = aInfo.loadIcon(packageManager);
ap.mTitle = appName;
ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName);
ap.mPositiveButtonText = getString(com.android.internal.R.string.ok);
ap.mNegativeButtonText = getString(com.android.internal.R.string.cancel);
ap.mPositiveButtonListener = this;
ap.mNegativeButtonListener = this;
// add "always use" checkbox
LayoutInflater inflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
mAlwaysCheck = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
mAlwaysCheck.setText(com.android.internal.R.string.alwaysUse);
mAlwaysCheck.setOnCheckedChangeListener(this);
mClearDefaultHint = (TextView)ap.mView.findViewById(
com.android.internal.R.id.clearDefaultHint);
mClearDefaultHint.setVisibility(View.GONE);
setupAlert();
}
@Override
public void onDestroy() {
IBinder b = ServiceManager.getService(USB_SERVICE);
IUsbManager service = IUsbManager.Stub.asInterface(b);
// send response via pending intent
Intent intent = new Intent();
try {
if (mAccessory != null) {
intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
if (mPermissionGranted) {
service.grantAccessoryPermission(mAccessory, mUid);
if (mAlwaysCheck.isChecked()) {
service.setAccessoryPackage(mAccessory, mPackageName);
}
}
}
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, mPermissionGranted);
mPendingIntent.send(this, 0, intent);
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "PendingIntent was cancelled");
} catch (RemoteException e) {
Log.e(TAG, "IUsbService connection failed", e);
}
if (mDisconnectedReceiver != null) {
unregisterReceiver(mDisconnectedReceiver);
}
super.onDestroy();
}
public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) {
mPermissionGranted = true;
}
finish();
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mClearDefaultHint == null) return;
if(isChecked) {
mClearDefaultHint.setVisibility(View.VISIBLE);
} else {
mClearDefaultHint.setVisibility(View.GONE);
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.server.usb; package com.android.systemui.usb;
import com.android.internal.app.ResolverActivity; import com.android.internal.app.ResolverActivity;
@@ -38,6 +38,9 @@ public class UsbResolverActivity extends ResolverActivity {
public static final String TAG = "UsbResolverActivity"; public static final String TAG = "UsbResolverActivity";
public static final String EXTRA_RESOLVE_INFOS = "rlist"; public static final String EXTRA_RESOLVE_INFOS = "rlist";
private UsbAccessory mAccessory;
private UsbDisconnectedReceiver mDisconnectedReceiver;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent(); Intent intent = getIntent();
@@ -49,7 +52,6 @@ public class UsbResolverActivity extends ResolverActivity {
} }
Intent target = (Intent)targetParcelable; Intent target = (Intent)targetParcelable;
ArrayList<ResolveInfo> rList = intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS); ArrayList<ResolveInfo> rList = intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS);
Log.d(TAG, "rList.size() " + rList.size());
CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity); CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity);
super.onCreate(savedInstanceState, target, title, null, rList, super.onCreate(savedInstanceState, target, title, null, rList,
true, /* Set alwaysUseOption to true to enable "always use this app" checkbox. */ true, /* Set alwaysUseOption to true to enable "always use this app" checkbox. */
@@ -57,6 +59,22 @@ public class UsbResolverActivity extends ResolverActivity {
This is necessary because this activity is needed for the user to allow This is necessary because this activity is needed for the user to allow
the application permission to access the device */ the application permission to access the device */
); );
mAccessory = (UsbAccessory)target.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (mAccessory == null) {
Log.e(TAG, "accessory is null");
finish();
return;
}
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
}
@Override
protected void onDestroy() {
if (mDisconnectedReceiver != null) {
unregisterReceiver(mDisconnectedReceiver);
}
super.onDestroy();
} }
protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) { protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
@@ -64,19 +82,14 @@ public class UsbResolverActivity extends ResolverActivity {
IBinder b = ServiceManager.getService(USB_SERVICE); IBinder b = ServiceManager.getService(USB_SERVICE);
IUsbManager service = IUsbManager.Stub.asInterface(b); IUsbManager service = IUsbManager.Stub.asInterface(b);
int uid = ri.activityInfo.applicationInfo.uid; int uid = ri.activityInfo.applicationInfo.uid;
String action = intent.getAction();
if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) { // grant permission for the accessory
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra( service.grantAccessoryPermission(mAccessory, uid);
UsbManager.EXTRA_ACCESSORY); // set or clear default setting
// grant permission for the accessory if (alwaysCheck) {
service.grantAccessoryPermission(accessory, uid); service.setAccessoryPackage(mAccessory, ri.activityInfo.packageName);
// set or clear default setting } else {
if (alwaysCheck) { service.setAccessoryPackage(mAccessory, null);
service.setAccessoryPackage(accessory, ri.activityInfo.packageName);
} else {
service.setAccessoryPackage(accessory, null);
}
} }
try { try {

View File

@@ -16,11 +16,14 @@
package com.android.server.usb; package com.android.server.usb;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
@@ -31,7 +34,7 @@ import android.os.Binder;
import android.os.FileUtils; import android.os.FileUtils;
import android.os.Process; import android.os.Process;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseBooleanArray;
import android.util.Xml; import android.util.Xml;
import com.android.internal.content.PackageMonitor; import com.android.internal.content.PackageMonitor;
@@ -60,10 +63,11 @@ class UsbDeviceSettingsManager {
private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml"); private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml");
private final Context mContext; private final Context mContext;
private final PackageManager mPackageManager;
// maps UID to user approved USB accessories // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory
private final SparseArray<ArrayList<AccessoryFilter>> mAccessoryPermissionMap = private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
new SparseArray<ArrayList<AccessoryFilter>>(); new HashMap<UsbAccessory, SparseBooleanArray>();
// Maps AccessoryFilter to user preferred application package // Maps AccessoryFilter to user preferred application package
private final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap = private final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap =
new HashMap<AccessoryFilter, String>(); new HashMap<AccessoryFilter, String>();
@@ -79,22 +83,18 @@ class UsbDeviceSettingsManager {
public final String mManufacturer; public final String mManufacturer;
// USB accessory model (or null for unspecified) // USB accessory model (or null for unspecified)
public final String mModel; public final String mModel;
// USB accessory type (or null for unspecified)
public final String mType;
// USB accessory version (or null for unspecified) // USB accessory version (or null for unspecified)
public final String mVersion; public final String mVersion;
public AccessoryFilter(String manufacturer, String model, String type, String version) { public AccessoryFilter(String manufacturer, String model, String version) {
mManufacturer = manufacturer; mManufacturer = manufacturer;
mModel = model; mModel = model;
mType = type;
mVersion = version; mVersion = version;
} }
public AccessoryFilter(UsbAccessory accessory) { public AccessoryFilter(UsbAccessory accessory) {
mManufacturer = accessory.getManufacturer(); mManufacturer = accessory.getManufacturer();
mModel = accessory.getModel(); mModel = accessory.getModel();
mType = accessory.getType();
mVersion = accessory.getVersion(); mVersion = accessory.getVersion();
} }
@@ -102,7 +102,6 @@ class UsbDeviceSettingsManager {
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
String manufacturer = null; String manufacturer = null;
String model = null; String model = null;
String type = null;
String version = null; String version = null;
int count = parser.getAttributeCount(); int count = parser.getAttributeCount();
@@ -114,13 +113,11 @@ class UsbDeviceSettingsManager {
manufacturer = value; manufacturer = value;
} else if ("model".equals(name)) { } else if ("model".equals(name)) {
model = value; model = value;
} else if ("type".equals(name)) {
type = value;
} else if ("version".equals(name)) { } else if ("version".equals(name)) {
version = value; version = value;
} }
} }
return new AccessoryFilter(manufacturer, model, type, version); return new AccessoryFilter(manufacturer, model, version);
} }
public void write(XmlSerializer serializer)throws IOException { public void write(XmlSerializer serializer)throws IOException {
@@ -131,9 +128,6 @@ class UsbDeviceSettingsManager {
if (mModel != null) { if (mModel != null) {
serializer.attribute(null, "model", mModel); serializer.attribute(null, "model", mModel);
} }
if (mType != null) {
serializer.attribute(null, "type", mType);
}
if (mVersion != null) { if (mVersion != null) {
serializer.attribute(null, "version", mVersion); serializer.attribute(null, "version", mVersion);
} }
@@ -143,29 +137,33 @@ class UsbDeviceSettingsManager {
public boolean matches(UsbAccessory acc) { public boolean matches(UsbAccessory acc) {
if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false; if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
if (mModel != null && !acc.getModel().equals(mModel)) return false; if (mModel != null && !acc.getModel().equals(mModel)) return false;
if (mType != null && !acc.getType().equals(mType)) return false;
if (mVersion != null && !acc.getVersion().equals(mVersion)) return false; if (mVersion != null && !acc.getVersion().equals(mVersion)) return false;
return true; return true;
} }
public boolean matches(AccessoryFilter f) {
if (mManufacturer != null && !f.mManufacturer.equals(mManufacturer)) return false;
if (mModel != null && !f.mModel.equals(mModel)) return false;
if (mVersion != null && !f.mVersion.equals(mVersion)) return false;
return true;
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
// can't compare if we have wildcard strings // can't compare if we have wildcard strings
if (mManufacturer == null || mModel == null || mType == null || mVersion == null) { if (mManufacturer == null || mModel == null || mVersion == null) {
return false; return false;
} }
if (obj instanceof AccessoryFilter) { if (obj instanceof AccessoryFilter) {
AccessoryFilter filter = (AccessoryFilter)obj; AccessoryFilter filter = (AccessoryFilter)obj;
return (mManufacturer.equals(filter.mManufacturer) && return (mManufacturer.equals(filter.mManufacturer) &&
mModel.equals(filter.mModel) && mModel.equals(filter.mModel) &&
mType.equals(filter.mType) &&
mVersion.equals(filter.mVersion)); mVersion.equals(filter.mVersion));
} }
if (obj instanceof UsbAccessory) { if (obj instanceof UsbAccessory) {
UsbAccessory accessory = (UsbAccessory)obj; UsbAccessory accessory = (UsbAccessory)obj;
return (mManufacturer.equals(accessory.getManufacturer()) && return (mManufacturer.equals(accessory.getManufacturer()) &&
mModel.equals(accessory.getModel()) && mModel.equals(accessory.getModel()) &&
mType.equals(accessory.getType()) &&
mVersion.equals(accessory.getVersion())); mVersion.equals(accessory.getVersion()));
} }
return false; return false;
@@ -175,7 +173,6 @@ class UsbDeviceSettingsManager {
public int hashCode() { public int hashCode() {
return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^ return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
(mModel == null ? 0 : mModel.hashCode()) ^ (mModel == null ? 0 : mModel.hashCode()) ^
(mType == null ? 0 : mType.hashCode()) ^
(mVersion == null ? 0 : mVersion.hashCode())); (mVersion == null ? 0 : mVersion.hashCode()));
} }
@@ -183,59 +180,35 @@ class UsbDeviceSettingsManager {
public String toString() { public String toString() {
return "AccessoryFilter[mManufacturer=\"" + mManufacturer + return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
"\", mModel=\"" + mModel + "\", mModel=\"" + mModel +
"\", mType=\"" + mType +
"\", mVersion=\"" + mVersion + "\"]"; "\", mVersion=\"" + mVersion + "\"]";
} }
} }
private class MyPackageMonitor extends PackageMonitor { private class MyPackageMonitor extends PackageMonitor {
public void onPackageRemoved(String packageName, int uid) {
synchronized (mLock) { public void onPackageAdded(String packageName, int uid) {
// clear all activity preferences for the package handlePackageUpdate(packageName);
if (clearPackageDefaultsLocked(packageName)) {
writeSettingsLocked();
}
}
} }
public void onUidRemoved(int uid) { public void onPackageChanged(String packageName, int uid, String[] components) {
synchronized (mLock) { handlePackageUpdate(packageName);
// clear all permissions for the UID }
if (clearUidDefaultsLocked(uid)) {
writeSettingsLocked(); public void onPackageRemoved(String packageName, int uid) {
} clearDefaults(packageName);
}
} }
} }
MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
public UsbDeviceSettingsManager(Context context) { public UsbDeviceSettingsManager(Context context) {
mContext = context; mContext = context;
mPackageManager = context.getPackageManager();
synchronized (mLock) { synchronized (mLock) {
readSettingsLocked(); readSettingsLocked();
} }
mPackageMonitor.register(context, true); mPackageMonitor.register(context, true);
} }
private void readAccessoryPermission(XmlPullParser parser)
throws XmlPullParserException, IOException {
int uid = -1;
ArrayList<AccessoryFilter> filters = new ArrayList<AccessoryFilter>();
int count = parser.getAttributeCount();
for (int i = 0; i < count; i++) {
if ("uid".equals(parser.getAttributeName(i))) {
uid = Integer.parseInt(parser.getAttributeValue(i));
break;
}
}
XmlUtils.nextElement(parser);
while ("usb-accessory".equals(parser.getName())) {
filters.add(AccessoryFilter.read(parser));
XmlUtils.nextElement(parser);
}
mAccessoryPermissionMap.put(uid, filters);
}
private void readPreference(XmlPullParser parser) private void readPreference(XmlPullParser parser)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
String packageName = null; String packageName = null;
@@ -264,9 +237,7 @@ class UsbDeviceSettingsManager {
XmlUtils.nextElement(parser); XmlUtils.nextElement(parser);
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
String tagName = parser.getName(); String tagName = parser.getName();
if ("accessory-permission".equals(tagName)) { if ("preference".equals(tagName)) {
readAccessoryPermission(parser);
} else if ("preference".equals(tagName)) {
readPreference(parser); readPreference(parser);
} else { } else {
XmlUtils.nextElement(parser); XmlUtils.nextElement(parser);
@@ -299,19 +270,6 @@ class UsbDeviceSettingsManager {
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, "settings"); serializer.startTag(null, "settings");
int count = mAccessoryPermissionMap.size();
for (int i = 0; i < count; i++) {
int uid = mAccessoryPermissionMap.keyAt(i);
ArrayList<AccessoryFilter> filters = mAccessoryPermissionMap.valueAt(i);
serializer.startTag(null, "accessory-permission");
serializer.attribute(null, "uid", Integer.toString(uid));
int filterCount = filters.size();
for (int j = 0; j < filterCount; j++) {
filters.get(j).write(serializer);
}
serializer.endTag(null, "accessory-permission");
}
for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) { for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
serializer.startTag(null, "preference"); serializer.startTag(null, "preference");
serializer.attribute(null, "package", mAccessoryPreferenceMap.get(filter)); serializer.attribute(null, "package", mAccessoryPreferenceMap.get(filter));
@@ -335,11 +293,10 @@ class UsbDeviceSettingsManager {
private boolean packageMatchesLocked(ResolveInfo info, String metaDataName, private boolean packageMatchesLocked(ResolveInfo info, String metaDataName,
UsbAccessory accessory) { UsbAccessory accessory) {
ActivityInfo ai = info.activityInfo; ActivityInfo ai = info.activityInfo;
PackageManager pm = mContext.getPackageManager();
XmlResourceParser parser = null; XmlResourceParser parser = null;
try { try {
parser = ai.loadXmlMetaData(pm, metaDataName); parser = ai.loadXmlMetaData(mPackageManager, metaDataName);
if (parser == null) { if (parser == null) {
Log.w(TAG, "no meta-data for " + info); Log.w(TAG, "no meta-data for " + info);
return false; return false;
@@ -367,8 +324,7 @@ class UsbDeviceSettingsManager {
private final ArrayList<ResolveInfo> getAccessoryMatchesLocked( private final ArrayList<ResolveInfo> getAccessoryMatchesLocked(
UsbAccessory accessory, Intent intent) { UsbAccessory accessory, Intent intent) {
ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>(); ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
PackageManager pm = mContext.getPackageManager(); List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,
PackageManager.GET_META_DATA); PackageManager.GET_META_DATA);
int count = resolveInfos.size(); int count = resolveInfos.size();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
@@ -381,75 +337,247 @@ class UsbDeviceSettingsManager {
} }
public void accessoryAttached(UsbAccessory accessory) { public void accessoryAttached(UsbAccessory accessory) {
Intent accessoryIntent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED); Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
accessoryIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
accessoryIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ArrayList<ResolveInfo> matches; ArrayList<ResolveInfo> matches;
String defaultPackage; String defaultPackage;
synchronized (mLock) { synchronized (mLock) {
matches = getAccessoryMatchesLocked(accessory, accessoryIntent); matches = getAccessoryMatchesLocked(accessory, intent);
// Launch our default activity directly, if we have one. // Launch our default activity directly, if we have one.
// Otherwise we will start the UsbResolverActivity to allow the user to choose. // Otherwise we will start the UsbResolverActivity to allow the user to choose.
defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory)); defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
} }
int count = matches.size(); resolveActivity(intent, matches, defaultPackage, accessory);
// don't show the resolver activity if there are no choices available
if (count == 0) return;
if (defaultPackage != null) {
for (int i = 0; i < count; i++) {
ResolveInfo rInfo = matches.get(i);
if (rInfo.activityInfo != null &&
defaultPackage.equals(rInfo.activityInfo.packageName)) {
try {
accessoryIntent.setComponent(new ComponentName(
defaultPackage, rInfo.activityInfo.name));
mContext.startActivity(accessoryIntent);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "startActivity failed", e);
}
return;
}
}
}
Intent intent = new Intent(mContext, UsbResolverActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_INTENT, accessoryIntent);
intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches);
try {
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(TAG, "unable to start UsbResolverActivity");
}
} }
public void accessoryDetached(UsbAccessory accessory) { public void accessoryDetached(UsbAccessory accessory) {
// clear temporary permissions for the accessory
mAccessoryPermissionMap.remove(accessory);
Intent intent = new Intent( Intent intent = new Intent(
UsbManager.ACTION_USB_ACCESSORY_DETACHED); UsbManager.ACTION_USB_ACCESSORY_DETACHED);
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
mContext.sendBroadcast(intent); mContext.sendBroadcast(intent);
} }
public void checkPermission(UsbAccessory accessory) { private void resolveActivity(Intent intent, ArrayList<ResolveInfo> matches,
if (accessory == null) return; String defaultPackage, UsbAccessory accessory) {
synchronized (mLock) { int count = matches.size();
ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(Binder.getCallingUid());
if (filterList != null) { // don't show the resolver activity if there are no choices available
int count = filterList.size(); if (count == 0) {
for (int i = 0; i < count; i++) { if (accessory != null) {
AccessoryFilter filter = filterList.get(i); String uri = accessory.getUri();
if (filter.equals(accessory)) { if (uri != null && uri.length() > 0) {
// permission allowed // display URI to user
return; // start UsbResolverActivity so user can choose an activity
Intent dialogIntent = new Intent();
dialogIntent.setClassName("com.android.systemui",
"com.android.systemui.usb.UsbAccessoryUriActivity");
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
dialogIntent.putExtra("uri", uri);
try {
mContext.startActivity(dialogIntent);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "unable to start UsbAccessoryUriActivity");
} }
} }
} }
// do nothing
return;
} }
throw new SecurityException("User has not given permission to accessory " + accessory);
ResolveInfo defaultRI = null;
if (count == 1 && defaultPackage == null) {
// Check to see if our single choice is on the system partition.
// If so, treat it as our default without calling UsbResolverActivity
ResolveInfo rInfo = matches.get(0);
if (rInfo.activityInfo != null &&
rInfo.activityInfo.applicationInfo != null &&
(rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
defaultRI = rInfo;
}
}
if (defaultRI == null && defaultPackage != null) {
// look for default activity
for (int i = 0; i < count; i++) {
ResolveInfo rInfo = matches.get(i);
if (rInfo.activityInfo != null &&
defaultPackage.equals(rInfo.activityInfo.packageName)) {
defaultRI = rInfo;
break;
}
}
}
if (defaultRI != null) {
// grant permission for default activity
grantAccessoryPermission(accessory, defaultRI.activityInfo.applicationInfo.uid);
// start default activity directly
try {
intent.setComponent(
new ComponentName(defaultRI.activityInfo.packageName,
defaultRI.activityInfo.name));
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "startActivity failed", e);
}
} else {
// start UsbResolverActivity so user can choose an activity
Intent resolverIntent = new Intent();
resolverIntent.setClassName("com.android.systemui",
"com.android.systemui.usb.UsbResolverActivity");
resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
resolverIntent.putParcelableArrayListExtra("rlist", matches);
try {
mContext.startActivity(resolverIntent);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "unable to start UsbResolverActivity");
}
}
}
private boolean clearCompatibleMatchesLocked(String packageName, AccessoryFilter filter) {
boolean changed = false;
for (AccessoryFilter test : mAccessoryPreferenceMap.keySet()) {
if (filter.matches(test)) {
mAccessoryPreferenceMap.remove(test);
changed = true;
}
}
return changed;
}
private boolean handlePackageUpdateLocked(String packageName, ActivityInfo aInfo,
String metaDataName) {
XmlResourceParser parser = null;
boolean changed = false;
try {
parser = aInfo.loadXmlMetaData(mPackageManager, metaDataName);
if (parser == null) return false;
XmlUtils.nextElement(parser);
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
String tagName = parser.getName();
if ("usb-accessory".equals(tagName)) {
AccessoryFilter filter = AccessoryFilter.read(parser);
if (clearCompatibleMatchesLocked(packageName, filter)) {
changed = true;
}
}
XmlUtils.nextElement(parser);
}
} catch (Exception e) {
Log.w(TAG, "Unable to load component info " + aInfo.toString(), e);
} finally {
if (parser != null) parser.close();
}
return changed;
}
// Check to see if the package supports any USB devices or accessories.
// If so, clear any non-matching preferences for matching devices/accessories.
private void handlePackageUpdate(String packageName) {
synchronized (mLock) {
PackageInfo info;
boolean changed = false;
try {
info = mPackageManager.getPackageInfo(packageName,
PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
return;
}
ActivityInfo[] activities = info.activities;
if (activities == null) return;
for (int i = 0; i < activities.length; i++) {
// check for meta-data, both for devices and accessories
if (handlePackageUpdateLocked(packageName, activities[i],
UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
changed = true;
}
}
if (changed) {
writeSettingsLocked();
}
}
}
public boolean hasPermission(UsbAccessory accessory) {
synchronized (mLock) {
SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
if (uidList == null) {
return false;
}
return uidList.get(Binder.getCallingUid());
}
}
public void checkPermission(UsbAccessory accessory) {
if (!hasPermission(accessory)) {
throw new SecurityException("User has not given permission to accessory " + accessory);
}
}
private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {
int uid = Binder.getCallingUid();
// compare uid with packageName to foil apps pretending to be someone else
try {
ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
if (aInfo.uid != uid) {
throw new IllegalArgumentException("package " + packageName +
" does not match caller's uid " + uid);
}
} catch (PackageManager.NameNotFoundException e) {
throw new IllegalArgumentException("package " + packageName + " not found");
}
long identity = Binder.clearCallingIdentity();
intent.setClassName("com.android.systemui",
"com.android.systemui.usb.UsbPermissionActivity");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_INTENT, pi);
intent.putExtra("package", packageName);
intent.putExtra("uid", uid);
try {
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "unable to start UsbPermissionActivity");
} finally {
Binder.restoreCallingIdentity(identity);
}
}
public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) {
Intent intent = new Intent();
// respond immediately if permission has already been granted
if (hasPermission(accessory)) {
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
try {
pi.send(mContext, 0, intent);
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "requestPermission PendingIntent was cancelled");
}
return;
}
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
requestPermissionDialog(intent, packageName, pi);
} }
public void setAccessoryPackage(UsbAccessory accessory, String packageName) { public void setAccessoryPackage(UsbAccessory accessory, String packageName) {
@@ -472,49 +600,29 @@ class UsbDeviceSettingsManager {
public void grantAccessoryPermission(UsbAccessory accessory, int uid) { public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
synchronized (mLock) { synchronized (mLock) {
ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(uid); SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
if (filterList == null) { if (uidList == null) {
filterList = new ArrayList<AccessoryFilter>(); uidList = new SparseBooleanArray(1);
mAccessoryPermissionMap.put(uid, filterList); mAccessoryPermissionMap.put(accessory, uidList);
} else {
int count = filterList.size();
for (int i = 0; i < count; i++) {
if (filterList.get(i).equals(accessory)) return;
}
} }
filterList.add(new AccessoryFilter(accessory)); uidList.put(uid, true);
writeSettingsLocked();
} }
} }
public boolean hasDefaults(String packageName, int uid) { public boolean hasDefaults(String packageName) {
synchronized (mLock) { synchronized (mLock) {
if (mAccessoryPermissionMap.get(uid) != null) return true; return mAccessoryPreferenceMap.values().contains(packageName);
if (mAccessoryPreferenceMap.values().contains(packageName)) return true;
return false;
} }
} }
public void clearDefaults(String packageName, int uid) { public void clearDefaults(String packageName) {
synchronized (mLock) { synchronized (mLock) {
boolean packageCleared = clearPackageDefaultsLocked(packageName); if (clearPackageDefaultsLocked(packageName)) {
boolean uidCleared = clearUidDefaultsLocked(uid);
if (packageCleared || uidCleared) {
writeSettingsLocked(); writeSettingsLocked();
} }
} }
} }
private boolean clearUidDefaultsLocked(int uid) {
boolean cleared = false;
int index = mAccessoryPermissionMap.indexOfKey(uid);
if (index >= 0) {
mAccessoryPermissionMap.removeAt(index);
cleared = true;
}
return cleared;
}
private boolean clearPackageDefaultsLocked(String packageName) { private boolean clearPackageDefaultsLocked(String packageName) {
boolean cleared = false; boolean cleared = false;
synchronized (mLock) { synchronized (mLock) {
@@ -536,14 +644,14 @@ class UsbDeviceSettingsManager {
public void dump(FileDescriptor fd, PrintWriter pw) { public void dump(FileDescriptor fd, PrintWriter pw) {
synchronized (mLock) { synchronized (mLock) {
pw.println(" Accessory permissions:"); pw.println(" Accessory permissions:");
int count = mAccessoryPermissionMap.size(); for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
for (int i = 0; i < count; i++) { pw.print(" " + accessory + ": ");
int uid = mAccessoryPermissionMap.keyAt(i); SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
pw.println(" " + "uid " + uid + ":"); int count = uidList.size();
ArrayList<AccessoryFilter> filters = mAccessoryPermissionMap.valueAt(i); for (int i = 0; i < count; i++) {
for (AccessoryFilter filter : filters) { pw.print(Integer.toString(uidList.keyAt(i)) + " ");
pw.println(" " + filter);
} }
pw.println("");
} }
pw.println(" Accessory preferences:"); pw.println(" Accessory preferences:");
for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) { for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {

View File

@@ -16,6 +16,7 @@
package com.android.server.usb; package com.android.server.usb;
import android.app.PendingIntent;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -267,10 +268,7 @@ public class UsbService extends IUsbManager.Stub {
/* returns the currently attached USB accessory (device mode) */ /* returns the currently attached USB accessory (device mode) */
public UsbAccessory getCurrentAccessory() { public UsbAccessory getCurrentAccessory() {
synchronized (mLock) { return mCurrentAccessory;
mDeviceManager.checkPermission(mCurrentAccessory);
return mCurrentAccessory;
}
} }
/* opens the currently attached USB accessory (device mode) */ /* opens the currently attached USB accessory (device mode) */
@@ -294,19 +292,28 @@ public class UsbService extends IUsbManager.Stub {
mDeviceManager.setAccessoryPackage(accessory, packageName); mDeviceManager.setAccessoryPackage(accessory, packageName);
} }
public boolean hasAccessoryPermission(UsbAccessory accessory) {
return mDeviceManager.hasPermission(accessory);
}
public void requestAccessoryPermission(UsbAccessory accessory, String packageName,
PendingIntent pi) {
mDeviceManager.requestPermission(accessory, packageName, pi);
}
public void grantAccessoryPermission(UsbAccessory accessory, int uid) { public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
mDeviceManager.grantAccessoryPermission(accessory, uid); mDeviceManager.grantAccessoryPermission(accessory, uid);
} }
public boolean hasDefaults(String packageName, int uid) { public boolean hasDefaults(String packageName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
return mDeviceManager.hasDefaults(packageName, uid); return mDeviceManager.hasDefaults(packageName);
} }
public void clearDefaults(String packageName, int uid) { public void clearDefaults(String packageName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
mDeviceManager.clearDefaults(packageName, uid); mDeviceManager.clearDefaults(packageName);
} }
/* /*

View File

@@ -63,7 +63,6 @@ static void set_accessory_string(JNIEnv *env, int fd, int cmd, jobjectArray strA
buffer[0] = 0; buffer[0] = 0;
int length = ioctl(fd, cmd, buffer); int length = ioctl(fd, cmd, buffer);
if (buffer[0]) { if (buffer[0]) {
LOGD("string %d: %s", index, buffer);
jstring obj = env->NewStringUTF(buffer); jstring obj = env->NewStringUTF(buffer);
env->SetObjectArrayElement(strArray, index, obj); env->SetObjectArrayElement(strArray, index, obj);
env->DeleteLocalRef(obj); env->DeleteLocalRef(obj);
@@ -73,19 +72,19 @@ static void set_accessory_string(JNIEnv *env, int fd, int cmd, jobjectArray strA
static jobjectArray android_server_UsbService_getAccessoryStrings(JNIEnv *env, jobject thiz) static jobjectArray android_server_UsbService_getAccessoryStrings(JNIEnv *env, jobject thiz)
{ {
LOGD("getAccessoryStrings");
int fd = open(DRIVER_NAME, O_RDWR); int fd = open(DRIVER_NAME, O_RDWR);
if (fd < 0) { if (fd < 0) {
LOGE("could not open %s", DRIVER_NAME); LOGE("could not open %s", DRIVER_NAME);
return NULL; return NULL;
} }
jclass stringClass = env->FindClass("java/lang/String"); jclass stringClass = env->FindClass("java/lang/String");
jobjectArray strArray = env->NewObjectArray(4, stringClass, NULL); jobjectArray strArray = env->NewObjectArray(5, stringClass, NULL);
if (!strArray) goto out; if (!strArray) goto out;
set_accessory_string(env, fd, ACCESSORY_GET_STRING_MANUFACTURER, strArray, 0); 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_MODEL, strArray, 1);
set_accessory_string(env, fd, ACCESSORY_GET_STRING_TYPE, strArray, 2); set_accessory_string(env, fd, ACCESSORY_GET_STRING_DESCRIPTION, strArray, 2);
set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3); set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3);
set_accessory_string(env, fd, ACCESSORY_GET_STRING_URI, strArray, 4);
out: out:
close(fd); close(fd);