一、出现权限弹窗:拔插USB设备,弹出权限申请框,通过用户确认或拒绝权限。
二、USB授权方式:(参考google官方文档)
1.minfest中进行权限配置
<manifest ...>
<uses-feature android:name="android.hardware.usb.host" />
<uses-sdk android:minSdkVersion="12" />
...
<application>
<activity ...>
...
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
</application>
</manifest>
2.res/xml/device_filter.xml
配置文件为需要过滤设备的pid以及vid
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>
3.
注册广播以及建立广播接收,当监听到USB的插入动作时,通过UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)从 Intent 获取代表所连接设备:
匹配是否为目的usb,使用usbManager.requestPermission(device, permissionIntent)获取权限弹窗,进行授权。
.Java代码示例:
private final String ACTION_USB_PERMISSION = "com.exmple.USB_PERMISSION";
private static final int VID =1234 ;
private static final int PID = 5678;
private BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action))//是否接收到自定义广播
{
synchronized (this)
{
UsbDevice device = (UsbDevice)
intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))//是否授权成功
{
if(device != null){
openDevice();
}
}
else
{
Log.e("Rechar","device not permission, device info:" + device.toString());
}
}
}
else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action))
{
UsbDevice device = (UsbDevice)
intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
assert device != null;
if (VID == device.getVendorId() && PID == device.getProductId())
{
closeDevice();
openDeviceAndRequestDevice();
}
}
else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action))
{
UsbDevice device = (UsbDevice)
intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
assert device != null;
if (VID == device.getVendorId() && PID == device.getProductId())
{
closeDevice();
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(mUsbReceiver, filter);//注册广播
}
@Override
protected void onDestroy()
{
super.onDestroy();
unregisterReceiver(mUsbReceiver);
}
private void openDeviceAndRequestDevice()
{
UsbManager usbManager = (UsbManager)this.getSystemService(Context.USB_SERVICE);
for (UsbDevice device : usbManager.getDeviceList().values())
{
if (device.getVendorId() == VID && device.getProductId() == PID)
{
Intent intent = new Intent(ACTION_USB_PERMISSION);//发送自定义广播
PendingIntent pendingIntent =
PendingIntent.getBroadcast(getApplicationContext(), 0, intent, 0);
usbManager.requestPermission(device, pendingIntent);//弹出权限框,进行权限申请
}
}
}
private void openDevice()
{
Log.e("Rechar", "openDevice: " );
Toast.makeText(this,"openDevice",Toast.LENGTH_LONG).show();
}
private void closeDevice()
{
Log.e("Rechar", "closeDevice: " );
Toast.makeText(this,"closeDevice",Toast.LENGTH_LONG).show();
}
}
4.以上已完成USB的授权。但在开发过程中发现usb-HID并不能弹出权限框,且自动拒绝了权限。分析了系统源码:先判断USB的权限,若没有会return ,再判断camera的权限若没有回return。因此在代码中加入camera的权限后获取到了权限弹框。系统源码如下:
public void requestPermission(UsbDevice device, String packageName, PendingIntent pi, int uid) {
Intent intent = new Intent();
// respond immediately if permission has already been granted
if (hasPermission(device, packageName, uid)) {
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;
}
if (isCameraDevicePresent(device)) {
if (!isCameraPermissionGranted(packageName, uid)) {
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
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);
}
但是我暂时没有想明白,HID和camera的关系所在,系统代码为何这么写,希望知道的大佬指教一下。谢谢!附上当时参考usb流程解析的网站(usb流程解析),为了防止该网站内容被删除,将该内容附在下面以供参考:
USB请求权限流程
1. 新建activity,获取UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE)
2. 获取所以的USB设备HashMap<String, UsbDevice> map = usbManager.getDeviceList()
3. 过滤别的USB设备,拿到自己USB的USBDevice类,然后请求USB权限,usbManager.requestPermission(usbDevice, pendingIntent);并注册一个回调意图,用来判断用户是否授予权限
4. UsbManager类的requestPermission方法会调用mService. requestDevicePermission
5.mService是IUsbManager的对象,而IUsbManager是一个AIDL接口https://www.androidos.net.cn/android/8.0.0_r4/xref/frameworks/base/core/java/android/hardware/usb/IUsbManager.aidl
UsbService是它的实现类,所以最终是调用的UsbService的requestDevicePermission方法
6. 在requestDevicePermission方法里面调用的getSettingsForUser(userId).requestPermission
7. getSettingsForUser(userId)其实是去获取UsbUserSettingsManager实例,所以是调用的UsbUserSettingsManager的requestPermission方法
8. 在requestPermission方法里面首先会进行判断是否拥有USB权限,如果有就回调广播直接return返回的。如果没有那就判断是否有相机权限,如果没有权限回调广播直接return的。注意从始至终是没有发送用户拒绝的广播的
9. 接着会调用自身的requestPermissionDialog方法,在requestPermissionDialog方法里面又会去调用mUsbPermissionManager.requestPermissionDialog方法
10.最终在UsbPermissionManager类的requestPermissionDialog方法中调用startActivityAsUser 启动UsbPermissionActivity权限申请对话框
11.监听弹出权限对话框的onclick方法,如果点击的授权,那就在UsbPermissionActivity的onDestory里面回调最开始的广播,通知我们的应用,用户授予的权限。