Android 屏蔽USB权限弹框

来源:互联网 发布:java在cmd中输入中文 编辑:程序博客网 时间:2024/06/08 19:03

最近在看Android USB主从设备通讯(下载Demo)相关的东西,调试时每次运行都弹下面的框,即使勾选“默认情况下用于该USB设备”,还是会弹出,在调试阶段频繁弹框影响开发效率。


下面分享下怎么屏蔽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);    }
getSettingsForUserUsbDevice成员函数

    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;        }    }
               c. frameworks/base/services/java/com/android/server/usb/UsbSettingsManager.java=>requestPermission

    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);    }
接着调成员函数requestPermissionDialog

    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);        }    }
由此看最终显示框的地方在SystemUI的UsbPermissionActivity。


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();        }    }
②. frameworks/base/core/java/android/hardware/usb/UsbDevice.java=>hasDevicePermission
    public boolean hasDevicePermission(UsbDevice device) {        final int userId = UserHandle.getCallingUserId();        return getSettingsForUser(userId).hasPermission(device);    }
③. frameworks/base/services/java/com/android/server/usb/UsbSettingsManager.java=>hasPermission

    // 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);
frameworks/base/core/res/res/values/config.xml

    <!-- 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>
哈哈,看看上面注释,这么改会引起CTS fail,这就看你的项目是否要过CTS了


    // 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);        }    }
这里就用上述第一种方式即可。


感觉自己好啰嗦哦(贴了不少代码),对你有帮助就好。