Android USB_DEVICE_ATTACHED持久权限

时间:2016-10-16 20:30:45

标签: android usb accessory

每次重新连接USB设备时,如何让Android不要求许可?我想让它记住USB设备的“默认使用”复选标记,这样我就不必每次都向同一设备授予权限。

我以编程方式检测USB设备(Android手机)何时连接到我的主机设备(Android手机),以便我可以将它们切换到AOA模式并将其用作附件。基本上我有两个Android手机和一个OTG线,我希望他们在彼此之间进行通信。

我有一个不断枚举附加USB设备的线程:

UsbManager manager = (UsbManager) 
                   context.getSystemService(Context.USB_SERVICE);
while (!m_stopRequested) {
  boolean shouldNotify = false;
  HashMap<String, UsbDevice> deviceMap = m_usbManager.getDeviceList();
  for (Entry<String, UsbDevice> entry : deviceMap) {
    UsbDevice device = entry.getValue();
    if (m_usbManager.hasPermission(device)) {
      int pid = device.getProductId();
      if (device.getVendorId() == VID_GOOGLE(0x18D1) && (pid == ACCESSORY_PID(0x2D01) || pid == ACCESSORY_PID_ALT(0x2D00))) {
        switchDeviceToAOAMode(device);
      }
    } else {
      m_usbManager.requestPermission(device);
    }
  }
  Thread.sleep(1000);
}

我还注册了BroadcastReceiver以接收USB_PERMISSION意图:

private final class USBReceiver extends BroadcastReceiver {

    public void onReceive(Context context, Intent intent) {
        MCSLogger.log(TAG, "Received permission result!");

        String action = intent.getAction();
        UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

        if (ACTION_USB_PERMISSION.equals(action)) {
            boolean res = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
            MCSLogger.log(TAG, "permission action for dev=" + device + " received " + res);
            int pid = device.getProductId();
            if (res && device.getVendorId() == VID_GOOGLE(0x18D1) && (pid == ACCESSORY_PID(0x2D01) || pid == ACCESSORY_PID_ALT(0x2D00))) {
              connectAccessory()
            }
        }
    }
};

这是我切换到AOA模式的方式:

  private boolean switchDeviceToAOAMode(UsbDeviceConnection connection) {
        byte ioBuffer[] = new byte[2];
        int devVersion;
        int response;
    enter code here
        response = connection.controlTransfer(0xC0, 51, 0, 0, ioBuffer, 2, 0);

        if (response < 0) {
            MCSLogger.log(TAG, "Error starting transfer control " + response);
            return false;
        }

        devVersion = ioBuffer[1] << 8 | ioBuffer[0];

        // sometimes hangs on the next transfer :( //WIN32 libusb only
        // SystemClock.sleep(1000);

        byte manufacturer[] = m_manufacturer.getBytes();
        response = connection.controlTransfer(0x40, 52, 0, 0, manufacturer, manufacturer.length, 0);
        if (response < 0) {
            MCSLogger.log(TAG, "Error transfering manufacturer " + response);
            return false;
        }
        byte modelName[] = m_modelName.getBytes();
        response = connection.controlTransfer(0x40, 52, 0, 1, modelName, modelName.length, 0);
        if (response < 0) {
            MCSLogger.log(TAG, "Error transfering modelName " + response);
            return false;
        }
        byte description[] = m_description.getBytes();
        response = connection.controlTransfer(0x40, 52, 0, 2, description, description.length, 0);
        if (response < 0) {
            MCSLogger.log(TAG, "Error transfering description " + response);
            return false;
        }
        byte version[] = m_version.getBytes();
        response = connection.controlTransfer(0x40, 52, 0, 3, version, version.length, 0);
        if (response < 0) {
            MCSLogger.log(TAG, "Error transfering version " + response);
            return false;
        }
        byte uri[] = m_uri.getBytes();
        response = connection.controlTransfer(0x40, 52, 0, 4, uri, uri.length, 0);
        if (response < 0) {
            MCSLogger.log(TAG, "Error transfering uri " + response);
            return false;
        }
        byte serialNumber[] = m_serialNumber.getBytes();
        response = connection.controlTransfer(0x40, 52, 0, 5, serialNumber, serialNumber.length, 0);
        if (response < 0) {
            MCSLogger.log(TAG, "Error transfering serialNumber " + response);
            return false;
        }

        MCSLogger.log(TAG, "Accessory Identification sent " + devVersion);

        response = connection.controlTransfer(0x40, 53, 0, 0, null, 0, 0);
        if (response < 0) {
            MCSLogger.log(TAG, "Error ending transfer control " + response);
            return false;
        }
        return true;
    }

2 个答案:

答案 0 :(得分:2)

@Ender提供的答案是正确的,但是在更高版本的Android平台(7+)上,您还需要做另外一件事。

您需要确保已将android:directBootAware="true"添加到负责响应USB_ACCESSORY_ATTACHED / USB_DEVICE_ATTACHED权限的活动标签。

以下是该活动的有效清单部分:

    <activity android:name=".MainActivity"
              android:directBootAware="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>

            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>

        <intent-filter>
            <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                    android:resource="@xml/usb_device_filter" />
        </intent-filter>

    </activity>

来源:

https://github.com/dazza5000/USBPermissionTest/blob/master/app/src/main/AndroidManifest.xml

usb_device_filter.xml

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <usb-device vendor-id="2049" product-id="25"/>
</resources>

来源:

https://github.com/dazza5000/USBPermissionTest/blob/master/app/src/main/res/xml/usb_device_filter.xml

android:directBootAware="true"提示来自下面的链接,对此我非常感谢。

https://www.sdgsystems.com/post/android-usb-permissions

更多详细信息可以在这里找到:

https://issuetracker.google.com/issues/77658221

一个完整的工作项目在这里:

https://github.com/dazza5000/USBPermissionTest

根访问权限

如果您具有root用户访问权限,则可以创建文件并将其写入磁盘,然后重新启动设备,以便读取并设置默认权限。

这些是基本步骤:

private void grantUSBPermission(){     UsbManager usbManager =(UsbManager)getSystemService(Context.USB_SERVICE);

HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();

for (UsbDevice usbDevice : deviceList.values()) {
    if (usbDevice.getManufacturerName() != null && usbDevice.getManufacturerName().equalsIgnoreCase(MANUFACTURER)) {
        Boolean hasPermission = usbManager.hasPermission(usbDevice);
        // Log if USB manager explicitly reports no permission.
        if (!hasPermission) {
            Log.i("DARRAN", "USB Manager reporting no permission to reader.");
            DeviceFilter deviceFilter = new DeviceFilter(usbDevice);
            writeSettingsFile(deviceFilter);
        }
    }
}

}

private void writeSettingsFile(DeviceFilter deviceFilter) {
    PermissionUtil.writeSettingsLocked(getApplicationContext(), deviceFilter);
    RootUtil.executeAsRoot(COMMAND_COPY_USB_FILE);
    RootUtil.executeAsRoot(COMMAND_CHOWN_USB_FILE);
    RootUtil.executeAsRoot("reboot");
}

命令:

public static final String COMMAND_COPY_USB_FILE = "cp /sdcard/Android/data/com.whereisdarran.setusbdefault/files/usb_device_manager.xml /data/system/users/0/usb_device_manager.xml";
public static final String COMMAND_CHOWN_USB_FILE = "chown system:system /data/system/users/0/usb_device_manager.xml";

可以在这里找到完整的工作项目:

https://github.com/dazza5000/set-usb-default

此外,博客文章还有更多内容:

http://whereisdarran.com/2019/12/wip-how-to-programmatically-set-your-app-as-the-default-app-for-a-usb-device-on-android-root-required/

答案 1 :(得分:1)

在实现AOA时,有两种主要方法来获取USB数据传输的设备许可。

一种方法包括手动枚举所有连接的设备,找到所需的设备,通过UsbManager.requestPermission(Device device)方法直接请求权限,以及使用BroadcastReceiver处理结果广播。这是您编写的解决方案。虽然功能齐全且合规,但每次连接USB设备时,都会提示用户进行许可。用户的潜在烦恼。

另一种方法要简单得多,并且允许默认使用功能。它要求在AndroidManifest.xml中定义一个意图过滤器,如下所示:

<activity ...>
...
<intent-filter>
    <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter>

<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
    android:resource="@xml/accessory_filter" />

还有一个名为“ accessory_filter”的xml文件(只是一个建议,您可以随意命名)。这是一个示例annex_filter.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" /></resources>

意图过滤器将在设备连接时自动启动应用程序,并向用户显示使用您的应用程序作为所使用的特定设备的默认应用程序的选项。

此链接提供了更多信息:https://developer.android.com/guide/topics/connectivity/usb/accessory#manifest-example