am b0976320: Merge "DO NOT MERGE: Backport more USB accessory changes from honeycomb" into gingerbread

* commit 'b09763209980ff9210cc353f2410598220ec0480':
  DO NOT MERGE: Backport more USB accessory changes from honeycomb
This commit is contained in:
Mike Lockwood
2011-03-15 14:49:37 -07:00
committed by Android Git Automerger
15 changed files with 264 additions and 40 deletions

View File

@ -34,18 +34,20 @@ public class UsbAccessory implements Parcelable {
private final String mDescription;
private final String mVersion;
private final String mUri;
private final String mSerial;
/**
* UsbAccessory should only be instantiated by UsbService implementation
* @hide
*/
public UsbAccessory(String manufacturer, String model, String description,
String version, String uri) {
String version, String uri, String serial) {
mManufacturer = manufacturer;
mModel = model;
mDescription = description;
mVersion = version;
mUri = uri;
mSerial = serial;
}
/**
@ -58,6 +60,7 @@ public class UsbAccessory implements Parcelable {
mDescription = strings[2];
mVersion = strings[3];
mUri = strings[4];
mSerial = strings[5];
}
/**
@ -107,6 +110,17 @@ public class UsbAccessory implements Parcelable {
return mUri;
}
/**
* Returns the unique serial number for the accessory.
* This is an optional serial number that can be used to differentiate
* between individual accessories of the same model and manufacturer
*
* @return the unique serial number
*/
public String getSerial() {
return mSerial;
}
private static boolean compare(String s1, String s2) {
if (s1 == null) return (s2 == null);
return s1.equals(s2);
@ -120,7 +134,8 @@ public class UsbAccessory implements Parcelable {
compare(mModel, accessory.getModel()) &&
compare(mDescription, accessory.getDescription()) &&
compare(mVersion, accessory.getVersion()) &&
compare(mUri, accessory.getUri()));
compare(mUri, accessory.getUri()) &&
compare(mSerial, accessory.getSerial()));
}
return false;
}
@ -131,7 +146,8 @@ public class UsbAccessory implements Parcelable {
(mModel == null ? 0 : mModel.hashCode()) ^
(mDescription == null ? 0 : mDescription.hashCode()) ^
(mVersion == null ? 0 : mVersion.hashCode()) ^
(mUri == null ? 0 : mUri.hashCode()));
(mUri == null ? 0 : mUri.hashCode()) ^
(mSerial == null ? 0 : mSerial.hashCode()));
}
@Override
@ -140,7 +156,8 @@ public class UsbAccessory implements Parcelable {
", mModel=" + mModel +
", mDescription=" + mDescription +
", mVersion=" + mVersion +
", mUri=" + mUri + "]";
", mUri=" + mUri +
", mSerial=" + mSerial + "]";
}
public static final Parcelable.Creator<UsbAccessory> CREATOR =
@ -151,7 +168,8 @@ public class UsbAccessory implements Parcelable {
String description = in.readString();
String version = in.readString();
String uri = in.readString();
return new UsbAccessory(manufacturer, model, description, version, uri);
String serial = in.readString();
return new UsbAccessory(manufacturer, model, description, version, uri, serial);
}
public UsbAccessory[] newArray(int size) {
@ -169,5 +187,6 @@ public class UsbAccessory implements Parcelable {
parcel.writeString(mDescription);
parcel.writeString(mVersion);
parcel.writeString(mUri);
parcel.writeString(mSerial);
}
}

View File

@ -19,13 +19,14 @@ package com.android.future.usb;
/**
* A class representing a USB accessory.
*/
public final class UsbAccessory {
public class UsbAccessory {
private final String mManufacturer;
private final String mModel;
private final String mDescription;
private final String mVersion;
private final String mUri;
private final String mSerial;
/* package */ UsbAccessory(android.hardware.usb.UsbAccessory accessory) {
mManufacturer = accessory.getManufacturer();
@ -33,6 +34,7 @@ public final class UsbAccessory {
mDescription = accessory.getDescription();
mVersion = accessory.getVersion();
mUri = accessory.getUri();
mSerial = accessory.getSerial();
}
/**
@ -82,6 +84,17 @@ public final class UsbAccessory {
return mUri;
}
/**
* Returns the unique serial number for the accessory.
* This is an optional serial number that can be used to differentiate
* between individual accessories of the same model and manufacturer
*
* @return the unique serial number
*/
public String getSerial() {
return mSerial;
}
private static boolean compare(String s1, String s2) {
if (s1 == null) return (s2 == null);
return s1.equals(s2);
@ -95,7 +108,8 @@ public final class UsbAccessory {
compare(mModel, accessory.getModel()) &&
compare(mDescription, accessory.getDescription()) &&
compare(mVersion, accessory.getVersion()) &&
compare(mUri, accessory.getUri()));
compare(mUri, accessory.getUri()) &&
compare(mSerial, accessory.getSerial()));
}
return false;
}
@ -106,7 +120,8 @@ public final class UsbAccessory {
(mModel == null ? 0 : mModel.hashCode()) ^
(mDescription == null ? 0 : mDescription.hashCode()) ^
(mVersion == null ? 0 : mVersion.hashCode()) ^
(mUri == null ? 0 : mUri.hashCode()));
(mUri == null ? 0 : mUri.hashCode()) ^
(mSerial == null ? 0 : mSerial.hashCode()));
}
@Override
@ -115,6 +130,7 @@ public final class UsbAccessory {
", mModel=" + mModel +
", mDescription=" + mDescription +
", mVersion=" + mVersion +
", mUri=" + mUri + "]";
", mUri=" + mUri +
", mSerial=" + mSerial + "]";
}
}

View File

@ -130,7 +130,8 @@ public class UsbManager {
try {
return mService.openAccessory(new android.hardware.usb.UsbAccessory(
accessory.getManufacturer(),accessory.getModel(),
accessory.getDescription(), accessory.getVersion(), accessory.getUri()));
accessory.getDescription(), accessory.getVersion(),
accessory.getUri(), accessory.getSerial()));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in openAccessory" , e);
return null;
@ -150,7 +151,8 @@ public class UsbManager {
try {
return mService.hasAccessoryPermission(new android.hardware.usb.UsbAccessory(
accessory.getManufacturer(),accessory.getModel(),
accessory.getDescription(), accessory.getVersion(), accessory.getUri()));
accessory.getDescription(), accessory.getVersion(),
accessory.getUri(), accessory.getSerial()));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in hasPermission", e);
return false;
@ -174,7 +176,8 @@ public class UsbManager {
try {
mService.requestAccessoryPermission(new android.hardware.usb.UsbAccessory(
accessory.getManufacturer(),accessory.getModel(),
accessory.getDescription(), accessory.getVersion(), accessory.getUri()),
accessory.getDescription(), accessory.getVersion(),
accessory.getUri(), accessory.getSerial()),
mContext.getPackageName(), pi);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in requestPermission", e);

View File

@ -21,7 +21,7 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := AccessoryChatGB
LOCAL_PACKAGE_NAME := AccessoryChat
LOCAL_JAVA_LIBRARIES := com.android.future.usb.accessory

View File

@ -17,10 +17,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.accessorychat">
<application>
<application android:label="Accessory Chat">
<uses-library android:name="com.android.future.usb.accessory" />
<activity android:name="AccessoryChat" android:label="Accessory Chat GB">
<activity android:name="AccessoryChat" android:label="Accessory Chat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />

View File

@ -24,6 +24,7 @@
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <time.h>
#include <usbhost/usbhost.h>
#include <linux/usb/f_accessory.h>
@ -65,9 +66,20 @@ static void* write_thread(void* arg) {
return NULL;
}
static void milli_sleep(int millis) {
struct timespec tm;
tm.tv_sec = 0;
tm.tv_nsec = millis * 1000000;
nanosleep(&tm, NULL);
}
static void send_string(struct usb_device *device, int index, const char* string) {
int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 0);
// some devices can't handle back-to-back requests, so delay a bit
milli_sleep(10);
}
static int usb_device_added(const char *devname, void* client_data) {
@ -143,9 +155,10 @@ static int usb_device_added(const char *devname, void* client_data) {
send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc.");
send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat");
send_string(device, ACCESSORY_STRING_DESCRIPTION, "Sample Program");
send_string(device, ACCESSORY_STRING_DESCRIPTION, "Accessory Chat");
send_string(device, ACCESSORY_STRING_VERSION, "1.0");
send_string(device, ACCESSORY_STRING_URI, "http://www.android.com");
send_string(device, ACCESSORY_STRING_SERIAL, "1234567890");
ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
ACCESSORY_START, 0, 0, 0, 0, 0);

View File

@ -135,6 +135,7 @@ public class AccessoryChat extends Activity implements Runnable, TextView.OnEdit
}
private void openAccessory(UsbAccessory accessory) {
Log.d(TAG, "openAccessory: " + accessory);
mFileDescriptor = mUsbManager.openAccessory(accessory);
if (mFileDescriptor != null) {
FileDescriptor fd = mFileDescriptor.getFileDescriptor();

View File

@ -26,6 +26,15 @@
android:excludeFromRecents="true">
</activity>
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbConfirmActivity"
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.UsbPermissionActivity"
android:exported="true"

View File

@ -54,8 +54,14 @@
<!-- 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 device confirm dialog [CHAR LIMIT=80] -->
<string name="usb_device_confirm_prompt">Open %1$s when this USB device is connected?</string>
<!-- Prompt for the USB accessory confirm dialog [CHAR LIMIT=80] -->
<string name="usb_accessory_confirm_prompt">Open %1$s when this USB accessory is connected?</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>
<string name="usb_accessory_uri_prompt">Additional information for this USB accessory 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>
@ -63,7 +69,7 @@
<!-- 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>
<!-- Checkbox label for USB accessory dialogs. [CHAR LIMIT=50] -->
<string name="always_use_accessory">Use by default for this USB accessory</string>
</resources>

View File

@ -76,7 +76,7 @@ public class UsbAccessoryUriActivity extends AlertActivity
}
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.mNegativeButtonText = getString(android.R.string.cancel);
ap.mPositiveButtonListener = this;
ap.mNegativeButtonListener = this;

View File

@ -0,0 +1,143 @@
/*
* 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.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
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 UsbConfirmActivity extends AlertActivity
implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
private static final String TAG = "UsbConfirmActivity";
private CheckBox mAlwaysUse;
private TextView mClearDefaultHint;
private UsbAccessory mAccessory;
private ResolveInfo mResolveInfo;
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);
mResolveInfo = (ResolveInfo)intent.getParcelableExtra("rinfo");
PackageManager packageManager = getPackageManager();
String appName = mResolveInfo.loadLabel(packageManager).toString();
final AlertController.AlertParams ap = mAlertParams;
ap.mIcon = mResolveInfo.loadIcon(packageManager);
ap.mTitle = appName;
ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName);
ap.mPositiveButtonText = getString(android.R.string.ok);
ap.mNegativeButtonText = getString(android.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);
mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
mAlwaysUse.setText(R.string.always_use_accessory);
mAlwaysUse.setOnCheckedChangeListener(this);
mClearDefaultHint = (TextView)ap.mView.findViewById(
com.android.internal.R.id.clearDefaultHint);
mClearDefaultHint.setVisibility(View.GONE);
setupAlert();
}
@Override
protected void onDestroy() {
if (mDisconnectedReceiver != null) {
unregisterReceiver(mDisconnectedReceiver);
}
super.onDestroy();
}
public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) {
try {
IBinder b = ServiceManager.getService(USB_SERVICE);
IUsbManager service = IUsbManager.Stub.asInterface(b);
int uid = mResolveInfo.activityInfo.applicationInfo.uid;
boolean alwaysUse = mAlwaysUse.isChecked();
Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(
new ComponentName(mResolveInfo.activityInfo.packageName,
mResolveInfo.activityInfo.name));
// grant permission for the accessory
service.grantAccessoryPermission(mAccessory, uid);
// set or clear default setting
if (alwaysUse) {
service.setAccessoryPackage(mAccessory,
mResolveInfo.activityInfo.packageName);
} else {
service.setAccessoryPackage(mAccessory, null);
}
startActivity(intent);
} catch (Exception e) {
Log.e(TAG, "Unable to start activity", e);
}
}
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

@ -48,7 +48,7 @@ public class UsbPermissionActivity extends AlertActivity
private static final String TAG = "UsbPermissionActivity";
private CheckBox mAlwaysCheck;
private CheckBox mAlwaysUse;
private TextView mClearDefaultHint;
private UsbAccessory mAccessory;
private PendingIntent mPendingIntent;
@ -83,8 +83,8 @@ public class UsbPermissionActivity extends AlertActivity
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.mPositiveButtonText = getString(android.R.string.ok);
ap.mNegativeButtonText = getString(android.R.string.cancel);
ap.mPositiveButtonListener = this;
ap.mNegativeButtonListener = this;
@ -92,9 +92,9 @@ public class UsbPermissionActivity extends AlertActivity
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);
mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
mAlwaysUse.setText(R.string.always_use_accessory);
mAlwaysUse.setOnCheckedChangeListener(this);
mClearDefaultHint = (TextView)ap.mView.findViewById(
com.android.internal.R.id.clearDefaultHint);
mClearDefaultHint.setVisibility(View.GONE);
@ -115,7 +115,7 @@ public class UsbPermissionActivity extends AlertActivity
intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
if (mPermissionGranted) {
service.grantAccessoryPermission(mAccessory, mUid);
if (mAlwaysCheck.isChecked()) {
if (mAlwaysUse.isChecked()) {
service.setAccessoryPackage(mAccessory, mPackageName);
}
}

View File

@ -30,6 +30,9 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.widget.CheckBox;
import com.android.systemui.R;
import java.util.ArrayList;
@ -54,11 +57,12 @@ public class UsbResolverActivity extends ResolverActivity {
ArrayList<ResolveInfo> rList = intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS);
CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity);
super.onCreate(savedInstanceState, target, title, null, rList,
true, /* Set alwaysUseOption to true to enable "always use this app" checkbox. */
true /* Set alwaysChoose to display activity when only one choice is available.
This is necessary because this activity is needed for the user to allow
the application permission to access the device */
);
true /* Set alwaysUseOption to true to enable "always use this app" checkbox. */ );
CheckBox alwaysUse = (CheckBox)findViewById(com.android.internal.R.id.alwaysUse);
if (alwaysUse != null) {
alwaysUse.setText(R.string.always_use_accessory);
}
mAccessory = (UsbAccessory)target.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (mAccessory == null) {

View File

@ -430,17 +430,26 @@ class UsbDeviceSettingsManager {
Log.e(TAG, "startActivity failed", e);
}
} else {
// start UsbResolverActivity so user can choose an activity
Intent resolverIntent = new Intent();
resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (count == 1) {
// start UsbConfirmActivity if there is only one choice
resolverIntent.setClassName("com.android.systemui",
"com.android.systemui.usb.UsbConfirmActivity");
resolverIntent.putExtra("rinfo", matches.get(0));
resolverIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
} else {
// start UsbResolverActivity so user can choose an activity
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);
resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
}
try {
mContext.startActivity(resolverIntent);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "unable to start UsbResolverActivity");
Log.e(TAG, "unable to start activity " + resolverIntent);
}
}
}

View File

@ -78,13 +78,14 @@ static jobjectArray android_server_UsbService_getAccessoryStrings(JNIEnv *env, j
return NULL;
}
jclass stringClass = env->FindClass("java/lang/String");
jobjectArray strArray = env->NewObjectArray(5, stringClass, NULL);
jobjectArray strArray = env->NewObjectArray(6, 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_DESCRIPTION, strArray, 2);
set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3);
set_accessory_string(env, fd, ACCESSORY_GET_STRING_URI, strArray, 4);
set_accessory_string(env, fd, ACCESSORY_GET_STRING_SERIAL, strArray, 5);
out:
close(fd);