最近在看Android USB主从设备通讯(下载Demo)相关的东西,调试时每次运行都弹下面的框,即使勾选“默认情况下用于该USB设备”,还是会弹出,在调试阶段频繁弹框影响开发效率。
1. 做过相关开发的都见过下面代码
- // Check whether we have permission to access the device.
- if (!mUsbManager.hasPermission(device)) {
- Intent intent = new Intent(ACTION_USB_DEVICE_PERMISSION);
- intent.setPackage(getPackageName());
- PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
- intent, PendingIntent.FLAG_ONE_SHOT);
- mUsbManager.requestPermission(device, pendingIntent);
- return;
- }
2. 分析弹框流程
mUsbManager.requestPermission(UsbDevice device...);//以UsbDevice为例,UsbAccessory同理
a. frameworks/base/core/java/android/hardware/usb/UsbManager.java=>requestPermission
- public void requestPermission(UsbDevice device, PendingIntent pi) {
- try {
- mService.requestDevicePermission(device, mContext.getPackageName(), pi);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
b. frameworks/base/core/java/android/hardware/usb/UsbDevice.java=>requestDevicePermission
- @Override
- public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {
- final int userId = UserHandle.getCallingUserId();
- getSettingsForUser(userId).requestPermission(device, packageName, pi);
- }
- private UsbSettingsManager getSettingsForUser(int userId) {
- synchronized (mLock) {
- UsbSettingsManager settings = mSettingsByUser.get(userId);
- if (settings == null) {
- settings = new UsbSettingsManager(mContext, new UserHandle(userId));
- mSettingsByUser.put(userId, settings);
- }
- return settings;
- }
- }
- 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(mUserContext, 0, intent);
- } catch (PendingIntent.CanceledException e) {
- if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
- }
- return;
- }
- // start UsbPermissionActivity so user can choose an activity
- intent.putExtra(UsbManager.EXTRA_DEVICE, device);
- requestPermissionDialog(intent, packageName, pi);
- }
- private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {
- final 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(Intent.EXTRA_UID, uid);
- try {
- mUserContext.startActivityAsUser(intent, mUser);
- } catch (ActivityNotFoundException e) {
- Slog.e(TAG, "unable to start UsbPermissionActivity");
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
3. 屏蔽弹框
a. 看到有博客说在UsbPermissionActivity的onCreate显示Dialog(setupAlert)时替换点击确定的代码
相当于自动点击确定
- @Override
- public void onCreate(Bundle icicle) {
- ...
- //setupAlert();
- mPermissionGranted = true;
- finish();
- }
- @Override
- public void onCreate(Bundle icicle) {
- ...
- mAlwaysUse.setOnCheckedChangeListener(this);
- mAlwaysUse.setChecked(true);
- ...
- setupAlert();
- onClick(this, AlertDialog.BUTTON_POSITIVE);
- }
b. 直接让mUsbManager.hasPermission返回true(自动授权),不更彻底?!
下面列下函数调用关系
①. frameworks/base/core/java/android/hardware/usb/UsbManager.java=>hasPermission
- public boolean hasPermission(UsbDevice device) {
- try {
- return mService.hasDevicePermission(device);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- public boolean hasDevicePermission(UsbDevice device) {
- final int userId = UserHandle.getCallingUserId();
- return getSettingsForUser(userId).hasPermission(device);
- }
- // Android L(5.x)及之后的版本
- public boolean hasPermission(UsbDevice device) {
- synchronized (mLock) {
- int uid = Binder.getCallingUid();
- if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
- return true;
- }
- SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
- if (uidList == null) {
- return false;
- }
- return uidList.get(uid);
- }
- }
让条件(uid == Process.SYSTEM_UID || mDisablePermissionDialogs)为真即可
第一种方式:在AndroidManifest.xml里加上android:sharedUserId="android.uid.system",但是apk需打系统签名
第二种方式:让mDisablePermissionDialogs为真
- mDisablePermissionDialogs = context.getResources().getBoolean(
- com.android.internal.R.bool.config_disableUsbPermissionDialogs);
- <!-- If true, then we do not ask user for permission for apps to connect to USB devices.
- Do not set this to true for production devices. Doing so will cause you to fail CTS. -->
- <bool name="config_disableUsbPermissionDialogs">true</bool>
- // Android KK(4.4)及之前的版本
- public boolean hasPermission(UsbDevice device) {
- synchronized (mLock) {
- int uid = Binder.getCallingUid();
- if (uid == Process.SYSTEM_UID) {
- return true;
- }
- SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
- if (uidList == null) {
- return false;
- }
- return uidList.get(uid);
- }
- }