From 607710ad12a7503c3b84c34430d1716fe7264f20 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 9 Mar 2011 16:43:35 -0500 Subject: [PATCH 1/3] UsbService: Don't require permissions for UsbManager.getCurrentAccessory() Permission check should only happen in openAccessory() Otherwise an application will not be able to check for the current accessory and ask for permissions (if it is a suitable match for the application) BUG: 4069037 Change-Id: If5b44ebda2e8077598d96629163cc74aa336589e Signed-off-by: Mike Lockwood --- services/java/com/android/server/usb/UsbService.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java index 71f2a9b04782e..8b419f3b036b6 100644 --- a/services/java/com/android/server/usb/UsbService.java +++ b/services/java/com/android/server/usb/UsbService.java @@ -423,10 +423,7 @@ public class UsbService extends IUsbManager.Stub { /* returns the currently attached USB accessory (device mode) */ public UsbAccessory getCurrentAccessory() { - synchronized (mLock) { - mDeviceManager.checkPermission(mCurrentAccessory); - return mCurrentAccessory; - } + return mCurrentAccessory; } /* opens the currently attached USB accessory (device mode) */ From 580b64111788fd312697d4fe60017127877dadf4 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 9 Mar 2011 16:46:35 -0500 Subject: [PATCH 2/3] Update USB accessory compatibility library to support new requestPermission API BUG: 4069037 Change-Id: Ieadb86fed577eeb7697d524e8a684ea6ea632f39 Signed-off-by: Mike Lockwood --- .../com/android/future/usb/UsbManager.java | 66 ++++++++++++++-- .../android/accessorychat/AccessoryChat.java | 77 +++++++++++++++---- 2 files changed, 122 insertions(+), 21 deletions(-) diff --git a/libs/usb/src/com/android/future/usb/UsbManager.java b/libs/usb/src/com/android/future/usb/UsbManager.java index f74b291e70358..33eb3ee688aad 100644 --- a/libs/usb/src/com/android/future/usb/UsbManager.java +++ b/libs/usb/src/com/android/future/usb/UsbManager.java @@ -17,6 +17,7 @@ package com.android.future.usb; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.hardware.usb.IUsbManager; @@ -55,28 +56,39 @@ public class UsbManager { public static final String 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 UsbManager(IUsbManager service) { + private UsbManager(Context context, IUsbManager service) { + mContext = context; mService = service; } /** * Returns a new instance of this class. * + * @param context the caller's {@link android.content.Context} * @return UsbManager instance. */ - public static UsbManager getInstance() { + public static UsbManager getInstance(Context context) { 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 * 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) { android.hardware.usb.UsbAccessory accessory = @@ -124,4 +136,48 @@ public class UsbManager { 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.getType(), accessory.getVersion())); + } 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.getType(), accessory.getVersion()), + mContext.getPackageName(), pi); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in requestPermission", e); + } + } } diff --git a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java index 5cf02c7f50bed..f9a5bf433cc96 100644 --- a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java +++ b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java @@ -17,9 +17,11 @@ package com.android.accessorychat; import android.app.Activity; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -42,18 +44,47 @@ import java.io.IOException; public class AccessoryChat extends Activity implements Runnable, TextView.OnEditorActionListener { private static final String TAG = "AccessoryChat"; - TextView mLog; - EditText mEditText; - ParcelFileDescriptor mFileDescriptor; - FileInputStream mInputStream; - FileOutputStream mOutputStream; + + private static final String ACTION_USB_PERMISSION = + "com.android.accessorychat.action.USB_PERMISSION"; + + 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 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 public void onCreate(Bundle 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); mLog = (TextView)findViewById(R.id.log); mEditText = (EditText)findViewById(R.id.message); @@ -66,21 +97,20 @@ public class AccessoryChat extends Activity implements Runnable, TextView.OnEdit Intent intent = getIntent(); Log.d(TAG, "intent: " + intent); - UsbManager manager = UsbManager.getInstance(); - UsbAccessory[] accessories = manager.getAccessoryList(); + UsbAccessory[] accessories = mUsbManager.getAccessoryList(); UsbAccessory accessory = (accessories == null ? null : accessories[0]); if (accessory != null) { - mFileDescriptor = manager.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(); + if (mUsbManager.hasPermission(accessory)) { + openAccessory(accessory); } else { - Log.d(TAG, "openAccessory fail"); + synchronized (mUsbReceiver) { + if (!mPermissionRequestPending) { + mUsbManager.requestPermission(accessory, mPermissionIntent); + mPermissionRequestPending = true; + } + } } - } else { + } else { Log.d(TAG, "mAccessory is null"); } } @@ -100,9 +130,24 @@ public class AccessoryChat extends Activity implements Runnable, TextView.OnEdit @Override public void onDestroy() { + unregisterReceiver(mUsbReceiver); 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) { if (actionId == EditorInfo.IME_ACTION_DONE && mOutputStream != null) { try { From b966b9d9e882835691e5adda292d89dd704df71c Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 9 Mar 2011 17:28:33 -0500 Subject: [PATCH 3/3] MTP: Convert date created and modified values from seconds to milliseconds BUG: 4026365 Change-Id: Ifd78cca305299ed1cedd6595609d9bf8d520cd8e Signed-off-by: Mike Lockwood --- media/jni/android_mtp_MtpDevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp index fd3266592ca0b..f5fcb4eb9b627 100644 --- a/media/jni/android_mtp_MtpDevice.cpp +++ b/media/jni/android_mtp_MtpDevice.cpp @@ -311,9 +311,9 @@ android_mtp_MtpDevice_get_object_info(JNIEnv *env, jobject thiz, jint objectID) if (objectInfo->mName) env->SetObjectField(info, field_objectInfo_name, env->NewStringUTF(objectInfo->mName)); if (objectInfo->mDateCreated) - env->SetLongField(info, field_objectInfo_dateCreated, objectInfo->mDateCreated); + env->SetLongField(info, field_objectInfo_dateCreated, objectInfo->mDateCreated * 1000LL); if (objectInfo->mDateModified) - env->SetLongField(info, field_objectInfo_dateModified, objectInfo->mDateModified); + env->SetLongField(info, field_objectInfo_dateModified, objectInfo->mDateModified * 1000LL); if (objectInfo->mKeywords) env->SetObjectField(info, field_objectInfo_keywords, env->NewStringUTF(objectInfo->mKeywords));