首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Android USB_DEVICE_ATTACHED持久权限

Android USB_DEVICE_ATTACHED持久权限
EN

Stack Overflow用户
提问于 2016-10-16 20:30:44
回答 2查看 7.6K关注 0票数 12

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

我以编程方式检测当USB设备(android手机)连接到我的主机设备(android手机),以便我可以切换到AOA模式,并使用它们作为附件。基本上我有两部Android手机和一条OTG电缆,我希望它们能够相互通信。

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

代码语言:javascript
运行
复制
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意图:

代码语言:javascript
运行
复制
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模式的方法:

代码语言:javascript
运行
复制
  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;
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-07-17 15:10:28

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

一种方法包括手动枚举所有连接的设备,查找所需的设备,通过UsbManager.requestPermission(设备设备)方法直接请求许可,以及使用BroadcastReceiver处理结果广播。这就是你写的解决方案。在功能和遵从性的同时,每次连接USB设备时,它都会提示用户获得许可;这是用户潜在的烦恼源。

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

代码语言:javascript
运行
复制
<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文件(只是一个建议,您可以随意命名它)。下面是一个示例accessory_filter.xml文件:

代码语言:javascript
运行
复制
<?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

票数 6
EN

Stack Overflow用户

发布于 2019-07-30 23:05:55

@Ender提供的答案是正确的,但在安卓平台(7+)的后期版本中,您还需要做一件事。

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

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

代码语言:javascript
运行
复制
    <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

代码语言:javascript
运行
复制
<?xml version="1.0" encoding="utf-8"?>

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

来源:

filter.xml

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

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

更多细节可以在这里找到:

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

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

https://github.com/dazza5000/USBPermissionTest

根访问

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

这些是基本步骤:

私有grantUSBPermission() { UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

代码语言:javascript
运行
复制
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);
        }
    }
}

}

代码语言:javascript
运行
复制
private void writeSettingsFile(DeviceFilter deviceFilter) {
    PermissionUtil.writeSettingsLocked(getApplicationContext(), deviceFilter);
    RootUtil.executeAsRoot(COMMAND_COPY_USB_FILE);
    RootUtil.executeAsRoot(COMMAND_CHOWN_USB_FILE);
    RootUtil.executeAsRoot("reboot");
}

命令:

代码语言:javascript
运行
复制
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/

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40075128

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档