Android USB_DEVICE_ATTACHED持久权限

Iva*_*lov 7 usb android 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);
}
Run Code Online (Sandbox Code Playgroud)

我还注册了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()
            }
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

这是我切换到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;
    }
Run Code Online (Sandbox Code Playgroud)

daz*_*000 7

@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>
Run Code Online (Sandbox Code Playgroud)

来源:

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>
Run Code Online (Sandbox Code Playgroud)

来源:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

}

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

命令:

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";
Run Code Online (Sandbox Code Playgroud)

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

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/

  • 只有这样写才有效: &lt;intent-filter&gt; &lt;action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /&gt; &lt;/intent-filter&gt; &lt;meta-data android:name="android .hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" /&gt; (2认同)

End*_*der 6

在实现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" />
Run Code Online (Sandbox Code Playgroud)

以及一个名为“accessory_filter”的 xml 文件(只是一个建议,您可以将其命名为任何您想要的名称)。这是一个示例accessory_filter.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" /></resources>
Run Code Online (Sandbox Code Playgroud)

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

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