am 9e8e4ea0: Merge changes Ib517e5e4,I93be7695,I49bf22a4 into honeycomb-mr1

* commit '9e8e4ea0a839b561d329758cddbfd0f7ea23f593':
  Close USB dialogs if their corresponding accessory or device has disconnected
  USB: Add API and dialog for apps to request permissions for USB devices and accessories
  UsbService: Automatically use system apps by default if it is the only choice
This commit is contained in:
Mike Lockwood
2011-03-09 03:54:28 -08:00
committed by Android Git Automerger
13 changed files with 700 additions and 115 deletions

View File

@ -95457,6 +95457,32 @@
visibility="public" visibility="public"
> >
</method> </method>
<method name="hasPermission"
return="boolean"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="device" type="android.hardware.usb.UsbDevice">
</parameter>
</method>
<method name="hasPermission"
return="boolean"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
</parameter>
</method>
<method name="isFunctionEnabled" <method name="isFunctionEnabled"
return="boolean" return="boolean"
abstract="false" abstract="false"
@ -95509,6 +95535,36 @@
<parameter name="device" type="android.hardware.usb.UsbDevice"> <parameter name="device" type="android.hardware.usb.UsbDevice">
</parameter> </parameter>
</method> </method>
<method name="requestPermission"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="device" type="android.hardware.usb.UsbDevice">
</parameter>
<parameter name="pi" type="android.app.PendingIntent">
</parameter>
</method>
<method name="requestPermission"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
</parameter>
<parameter name="pi" type="android.app.PendingIntent">
</parameter>
</method>
<field name="ACTION_USB_ACCESSORY_ATTACHED" <field name="ACTION_USB_ACCESSORY_ATTACHED"
type="java.lang.String" type="java.lang.String"
transient="false" transient="false"
@ -95586,6 +95642,17 @@
visibility="public" visibility="public"
> >
</field> </field>
<field name="EXTRA_PERMISSION_GRANTED"
type="java.lang.String"
transient="false"
volatile="false"
value="&quot;permission&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="USB_CONFIGURATION" <field name="USB_CONFIGURATION"
type="java.lang.String" type="java.lang.String"
transient="false" transient="false"
@ -267304,7 +267371,7 @@
deprecated="not deprecated" deprecated="not deprecated"
visibility="public" visibility="public"
> >
<parameter name="arg0" type="T"> <parameter name="t" type="T">
</parameter> </parameter>
</method> </method>
</interface> </interface>

View File

@ -401,10 +401,10 @@ class ContextImpl extends Context {
return new UiModeManager(); return new UiModeManager();
}}); }});
registerService(USB_SERVICE, new StaticServiceFetcher() { registerService(USB_SERVICE, new ServiceFetcher() {
public Object createStaticService() { public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(USB_SERVICE); IBinder b = ServiceManager.getService(USB_SERVICE);
return new UsbManager(IUsbManager.Stub.asInterface(b)); return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
}}); }});
registerService(VIBRATOR_SERVICE, new ServiceFetcher() { registerService(VIBRATOR_SERVICE, new ServiceFetcher() {

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.hardware.usb.UsbDevice; import android.hardware.usb.UsbDevice;
import android.os.Bundle; import android.os.Bundle;
@ -50,6 +51,25 @@ 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 device. */
boolean hasDevicePermission(in UsbDevice device);
/* 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 device.
* Will display a system dialog to query the user if permission
* had not already been given.
*/
void requestDevicePermission(in UsbDevice device, String packageName, in PendingIntent pi);
/* 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 device */ /* Grants permission for the given UID to access the device */
void grantDevicePermission(in UsbDevice device, int uid); void grantDevicePermission(in UsbDevice device, int uid);

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;
@ -176,12 +178,24 @@ 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
* {#requestPermission(android.content.Context, android.hardware.usb.UsbDevice, android.app.PendingIntent)}
* or
* {#requestPermission(android.content.Context, android.hardware.usb.UsbAccessory, android.app.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;
} }
@ -245,7 +259,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;
} }
} }
@ -260,11 +274,87 @@ 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 device.
*
* @param device to check permissions for
* @return true if caller has permission
*/
public boolean hasPermission(UsbDevice device) {
try {
return mService.hasDevicePermission(device);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in hasPermission", e);
return false;
}
}
/**
* Returns true if the caller has permission to access 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 permission for the given package to access the device.
* 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 following extras will be added to pi:
* <ul>
* <li> {@link #EXTRA_DEVICE} containing the device passed into this call
* <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
* permission was granted by the user
* </ul>
*
* @param device to request permissions for
* @param pi PendingIntent for returning result
*/
public void requestPermission(UsbDevice device, PendingIntent pi) {
try {
mService.requestDevicePermission(device, mContext.getPackageName(), pi);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in requestPermission", e);
}
}
/**
* Requests 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 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

@ -1379,12 +1379,6 @@
android:excludeFromRecents="true"> android:excludeFromRecents="true">
</activity> </activity>
<activity android:name="com.android.server.usb.UsbResolverActivity"
android:theme="@style/Theme.Holo.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
<service android:name="com.android.server.LoadAverageService" <service android:name="com.android.server.LoadAverageService"
android:exported="true" /> android:exported="true" />

View File

@ -16,6 +16,7 @@
package android.mtp; package android.mtp;
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;
@ -41,6 +42,9 @@ public class MtpClient {
private static final String TAG = "MtpClient"; private static final String TAG = "MtpClient";
private static final String ACTION_USB_PERMISSION =
"android.mtp.MtpClient.action.USB_PERMISSION";
private final Context mContext; private final Context mContext;
private final UsbManager mUsbManager; private final UsbManager mUsbManager;
private final ArrayList<Listener> mListeners = new ArrayList<Listener>(); private final ArrayList<Listener> mListeners = new ArrayList<Listener>();
@ -49,31 +53,49 @@ public class MtpClient {
// mDevices is also used for synchronization in this class. // mDevices is also used for synchronization in this class.
private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>(); private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>();
private final PendingIntent mPermissionIntent;
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
String deviceName = usbDevice.getDeviceName(); String deviceName = usbDevice.getDeviceName();
synchronized (mDevices) { synchronized (mDevices) {
MtpDevice mtpDevice = mDevices.get(deviceName); MtpDevice mtpDevice = mDevices.get(deviceName);
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) { if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
if (mtpDevice == null) { if (mtpDevice == null) {
mtpDevice = openDeviceLocked(usbDevice); mtpDevice = openDeviceLocked(usbDevice);
} }
if (mtpDevice != null) { if (mtpDevice != null) {
mDevices.put(deviceName, mtpDevice);
for (Listener listener : mListeners) { for (Listener listener : mListeners) {
listener.deviceAdded(mtpDevice); listener.deviceAdded(mtpDevice);
} }
} }
} else if (mtpDevice != null) { } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
if (mtpDevice != null) {
mDevices.remove(deviceName); mDevices.remove(deviceName);
for (Listener listener : mListeners) { for (Listener listener : mListeners) {
listener.deviceRemoved(mtpDevice); listener.deviceRemoved(mtpDevice);
} }
} }
} else if (ACTION_USB_PERMISSION.equals(action)) {
boolean permission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED,
false);
Log.d(TAG, "ACTION_USB_PERMISSION: " + permission);
if (permission) {
if (mtpDevice == null) {
mtpDevice = openDeviceLocked(usbDevice);
}
if (mtpDevice != null) {
for (Listener listener : mListeners) {
listener.deviceAdded(mtpDevice);
}
}
}
}
} }
} }
}; };
@ -126,10 +148,11 @@ public class MtpClient {
public MtpClient(Context context) { public MtpClient(Context context) {
mContext = context; mContext = context;
mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE); mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(ACTION_USB_PERMISSION);
context.registerReceiver(mUsbReceiver, filter); context.registerReceiver(mUsbReceiver, filter);
} }
@ -142,11 +165,16 @@ public class MtpClient {
*/ */
private MtpDevice openDeviceLocked(UsbDevice usbDevice) { private MtpDevice openDeviceLocked(UsbDevice usbDevice) {
if (isCamera(usbDevice)) { if (isCamera(usbDevice)) {
if (!mUsbManager.hasPermission(usbDevice)) {
mUsbManager.requestPermission(usbDevice, mPermissionIntent);
} else {
MtpDevice mtpDevice = new MtpDevice(usbDevice); MtpDevice mtpDevice = new MtpDevice(usbDevice);
if (mtpDevice.open(mUsbManager)) { if (mtpDevice.open(mUsbManager)) {
mDevices.put(usbDevice.getDeviceName(), mtpDevice);
return mtpDevice; return mtpDevice;
} }
} }
}
return null; return null;
} }
@ -218,13 +246,8 @@ public class MtpClient {
// Query the USB manager since devices might have attached // Query the USB manager since devices might have attached
// before we added our listener. // before we added our listener.
for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) { for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
String deviceName = usbDevice.getDeviceName(); if (mDevices.get(usbDevice.getDeviceName()) == null) {
MtpDevice mtpDevice = mDevices.get(deviceName); openDeviceLocked(usbDevice);
if (mtpDevice == null) {
mtpDevice = openDeviceLocked(usbDevice);
}
if (mtpDevice != null) {
mDevices.put(deviceName, mtpDevice);
} }
} }

View File

@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.MANAGE_USB" />
<application <application
android:persistent="true" android:persistent="true"
@ -39,5 +40,22 @@
android:exported="true"> android:exported="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.Holo.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.Holo.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
</application> </application>
</manifest> </manifest>

View File

@ -115,4 +115,11 @@
<!-- Label of a toggle switch to disable use of the physical keyboard in favor of the IME. [CHAR LIMIT=25] --> <!-- Label of a toggle switch to disable use of the physical keyboard in favor of the IME. [CHAR LIMIT=25] -->
<string name="status_bar_use_physical_keyboard">Use physical keyboard</string> <string name="status_bar_use_physical_keyboard">Use physical keyboard</string>
<!-- Prompt for the USB device permission dialog [CHAR LIMIT=80] -->
<string name="usb_device_permission_prompt">Allow the application %1$s to access the USB device?</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>
</resources> </resources>

View File

@ -0,0 +1,67 @@
/*
* 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.UsbDevice;
import android.hardware.usb.UsbManager;
// This class is used to close UsbPermissionsActivity and UsbResolverActivity
// if their device/accessory is disconnected while the dialog is still open
class UsbDisconnectedReceiver extends BroadcastReceiver {
private final Activity mActivity;
private UsbDevice mDevice;
private UsbAccessory mAccessory;
public UsbDisconnectedReceiver(Activity activity, UsbDevice device) {
mActivity = activity;
mDevice = device;
IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED);
activity.registerReceiver(this, filter);
}
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_DEVICE_DETACHED.equals(action)) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null && device.equals(mDevice)) {
mActivity.finish();
}
} else 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,170 @@
/*
* 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.UsbDevice;
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 UsbDevice mDevice;
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();
mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
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;
if (mDevice == null) {
ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName);
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
} else {
ap.mMessage = getString(R.string.usb_device_permission_prompt, appName);
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
}
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 (mDevice != null) {
intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
if (mPermissionGranted) {
service.grantDevicePermission(mDevice, mUid);
if (mAlwaysCheck.isChecked()) {
service.setDevicePackage(mDevice, mPackageName);
}
}
}
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;
@ -39,6 +39,10 @@ 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 UsbDevice mDevice;
private UsbAccessory mAccessory;
private UsbDisconnectedReceiver mDisconnectedReceiver;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent(); Intent intent = getIntent();
@ -50,7 +54,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. */
@ -58,6 +61,27 @@ 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 */
); );
mDevice = (UsbDevice)target.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (mDevice != null) {
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
} else {
mAccessory = (UsbAccessory)target.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (mAccessory == null) {
Log.e(TAG, "no device or accessory");
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) {
@ -65,28 +89,24 @@ 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_DEVICE_ATTACHED.equals(action)) { if (mDevice != null) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
// grant permission for the device // grant permission for the device
service.grantDevicePermission(device, uid); service.grantDevicePermission(mDevice, uid);
// set or clear default setting // set or clear default setting
if (alwaysCheck) { if (alwaysCheck) {
service.setDevicePackage(device, ri.activityInfo.packageName); service.setDevicePackage(mDevice, ri.activityInfo.packageName);
} else { } else {
service.setDevicePackage(device, null); service.setDevicePackage(mDevice, null);
} }
} else if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) { } else if (mAccessory != null) {
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(
UsbManager.EXTRA_ACCESSORY);
// grant permission for the accessory // grant permission for the accessory
service.grantAccessoryPermission(accessory, uid); service.grantAccessoryPermission(mAccessory, uid);
// set or clear default setting // set or clear default setting
if (alwaysCheck) { if (alwaysCheck) {
service.setAccessoryPackage(accessory, ri.activityInfo.packageName); service.setAccessoryPackage(mAccessory, ri.activityInfo.packageName);
} else { } else {
service.setAccessoryPackage(accessory, null); service.setAccessoryPackage(mAccessory, null);
} }
} }

View File

@ -16,11 +16,13 @@
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.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;
@ -602,50 +604,20 @@ class UsbDeviceSettingsManager {
} }
public void deviceAttached(UsbDevice device) { public void deviceAttached(UsbDevice device) {
Intent deviceIntent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED); Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
deviceIntent.putExtra(UsbManager.EXTRA_DEVICE, device); intent.putExtra(UsbManager.EXTRA_DEVICE, device);
deviceIntent.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 = getDeviceMatchesLocked(device, deviceIntent); matches = getDeviceMatchesLocked(device, 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 = mDevicePreferenceMap.get(new DeviceFilter(device)); defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
} }
int count = matches.size(); resolveActivity(intent, matches, defaultPackage, device, null);
// 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 {
deviceIntent.setComponent(new ComponentName(
defaultPackage, rInfo.activityInfo.name));
mContext.startActivity(deviceIntent);
} 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, deviceIntent);
intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches);
try {
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(TAG, "unable to start UsbResolverActivity");
}
} }
public void deviceDetached(UsbDevice device) { public void deviceDetached(UsbDevice device) {
@ -656,49 +628,86 @@ 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));
} }
resolveActivity(intent, matches, defaultPackage, null, accessory);
}
private void resolveActivity(Intent intent, ArrayList<ResolveInfo> matches,
String defaultPackage, UsbDevice device, UsbAccessory accessory) {
int count = matches.size(); int count = matches.size();
// don't show the resolver activity if there are no choices available // don't show the resolver activity if there are no choices available
if (count == 0) return; if (count == 0) return;
if (defaultPackage != null) { 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;
int uid = rInfo.activityInfo.applicationInfo.uid;
// grant permission
if (device != null) {
grantDevicePermission(device, uid);
} else if (accessory != null) {
grantAccessoryPermission(accessory, uid);
}
}
}
if (defaultRI == null && defaultPackage != null) {
// look for default activity
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
ResolveInfo rInfo = matches.get(i); ResolveInfo rInfo = matches.get(i);
if (rInfo.activityInfo != null && if (rInfo.activityInfo != null &&
defaultPackage.equals(rInfo.activityInfo.packageName)) { defaultPackage.equals(rInfo.activityInfo.packageName)) {
defaultRI = rInfo;
break;
}
}
}
if (defaultRI != null) {
// start default activity directly
try { try {
accessoryIntent.setComponent(new ComponentName( intent.setComponent(
defaultPackage, rInfo.activityInfo.name)); new ComponentName(defaultRI.activityInfo.packageName,
mContext.startActivity(accessoryIntent); defaultRI.activityInfo.name));
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
Log.e(TAG, "startActivity failed", e); Log.e(TAG, "startActivity failed", e);
} }
return; } else {
} long identity = Binder.clearCallingIdentity();
}
}
Intent intent = new Intent(mContext, UsbResolverActivity.class); // start UsbResolverActivity so user can choose an activity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Intent resolverIntent = new Intent();
resolverIntent.setClassName("com.android.systemui",
intent.putExtra(Intent.EXTRA_INTENT, accessoryIntent); "com.android.systemui.usb.UsbResolverActivity");
intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches); resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
resolverIntent.putParcelableArrayListExtra("rlist", matches);
try { try {
mContext.startActivity(intent); mContext.startActivity(resolverIntent);
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
Log.w(TAG, "unable to start UsbResolverActivity"); Log.e(TAG, "unable to start UsbResolverActivity");
} finally {
Binder.restoreCallingIdentity(identity);
}
} }
} }
@ -709,40 +718,121 @@ class UsbDeviceSettingsManager {
mContext.sendBroadcast(intent); mContext.sendBroadcast(intent);
} }
public void checkPermission(UsbDevice device) { public boolean hasPermission(UsbDevice device) {
if (device == null) return;
synchronized (mLock) { synchronized (mLock) {
ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(Binder.getCallingUid()); ArrayList<DeviceFilter> filterList =
mDevicePermissionMap.get(Binder.getCallingUid());
if (filterList != null) { if (filterList != null) {
int count = filterList.size(); int count = filterList.size();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
DeviceFilter filter = filterList.get(i); DeviceFilter filter = filterList.get(i);
if (filter.equals(device)) { if (filter.equals(device)) {
// permission allowed // permission allowed
return; return true;
} }
} }
} }
} }
throw new SecurityException("User has not given permission to device " + device); return false;
} }
public void checkPermission(UsbAccessory accessory) { public boolean hasPermission(UsbAccessory accessory) {
if (accessory == null) return;
synchronized (mLock) { synchronized (mLock) {
ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(Binder.getCallingUid()); ArrayList<AccessoryFilter> filterList =
mAccessoryPermissionMap.get(Binder.getCallingUid());
if (filterList != null) { if (filterList != null) {
int count = filterList.size(); int count = filterList.size();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
AccessoryFilter filter = filterList.get(i); AccessoryFilter filter = filterList.get(i);
if (filter.equals(accessory)) { if (filter.equals(accessory)) {
// permission allowed // permission allowed
return true;
}
}
}
}
return false;
}
public void checkPermission(UsbDevice device) {
if (!hasPermission(device)) {
throw new SecurityException("User has not given permission to device " + device);
}
}
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 = mContext.getPackageManager().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(UsbDevice device, String packageName, PendingIntent pi) {
Intent intent = new Intent();
// respond immediately if permission has already been granted
if (hasPermission(device)) {
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
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; return;
} }
// start UsbPermissionActivity so user can choose an activity
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
requestPermissionDialog(intent, packageName, pi);
} }
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;
} }
throw new SecurityException("User has not given permission to accessory " + accessory);
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
requestPermissionDialog(intent, packageName, pi);
} }
public void setDevicePackage(UsbDevice device, String packageName) { public void setDevicePackage(UsbDevice device, String packageName) {

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;
@ -454,6 +455,24 @@ public class UsbService extends IUsbManager.Stub {
mDeviceManager.setAccessoryPackage(accessory, packageName); mDeviceManager.setAccessoryPackage(accessory, packageName);
} }
public boolean hasDevicePermission(UsbDevice device) {
return mDeviceManager.hasPermission(device);
}
public boolean hasAccessoryPermission(UsbAccessory accessory) {
return mDeviceManager.hasPermission(accessory);
}
public void requestDevicePermission(UsbDevice device, String packageName,
PendingIntent pi) {
mDeviceManager.requestPermission(device, packageName, pi);
}
public void requestAccessoryPermission(UsbAccessory accessory, String packageName,
PendingIntent pi) {
mDeviceManager.requestPermission(accessory, packageName, pi);
}
public void grantDevicePermission(UsbDevice device, int uid) { public void grantDevicePermission(UsbDevice device, int uid) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
mDeviceManager.grantDevicePermission(device, uid); mDeviceManager.grantDevicePermission(device, uid);