无法在 Android 14 上向 USB 设备提供权限

问题描述 投票:0回答:1

我是 Android studio 的新手,我正在尝试使用 USB 读取连接到我的机器的旋转数据。 我可以使用 cat 命令从 /dev/ttyACM0 读取数据。

我已经创建了一个带有按钮和文本视图框作为计数器的基本应用程序,现在我尝试从旋钮获取USB数据并将其显示在文本视图框中作为计数器或字符。 我在遵循一些在线博客和 android studio 指南后编写了下面的代码。 https://developer.android.com/develop/connectivity/usb/host

当我尝试使用下面的代码读取数据时,我可以看到 requestPermission() 被调用,但是当我授予权限时 BroadcastReciever() 没有被调用并且什么也没有发生。

MainActivity.kt

package com.example.middisplaz

import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.hardware.usb.UsbConstants
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat

class MainActivity : AppCompatActivity() {
    @SuppressLint("CutPasteId")
    private val ACTION_USB_PERMISSION = "com.example.middisplaz.USB_PERMISSION"
    private var usbManager: UsbManager? = null
    private var device: UsbDevice? = null
    private var connection: UsbDeviceConnection? = null

    private val usbReceiver = object : BroadcastReceiver() {
        @RequiresApi(Build.VERSION_CODES.TIRAMISU)
        override fun onReceive(context: Context, intent: Intent) {
            val action = intent.action
            if (ACTION_USB_PERMISSION == action) {
                synchronized(this) {
                    val device = intent.getParcelableExtra(
                        UsbManager.EXTRA_DEVICE,
                        UsbDevice::class.java
                    )
                    if (intent.getBooleanExtra(
                            UsbManager.EXTRA_PERMISSION_GRANTED,
                            false
                        )
                    ) {
                        device?.apply {
                            setupDevice(this)
                        }
                    } else {
                        Log.d("USB", "Permission denied for device $device")
                    }
                }
            }
        }
    }

    private fun setupDevice(device: UsbDevice) {
        val usbInterface = device.getInterface(0)
        val endpoint = usbInterface.getEndpoint(0)

        connection = usbManager?.openDevice(device)
        connection?.claimInterface(usbInterface, true)

        Thread {
            val buffer = ByteArray(64)
            while (true) {
                val bytesRead = connection?.bulkTransfer(/* endpoint = */ endpoint,
                    /* buffer = */ buffer, /* length = */
                    buffer.size, /* timeout = */ 1000
                )

                if (bytesRead != null && bytesRead > 0) {
                    val receiveData = String(buffer, 0, bytesRead)
                    Log.d("USB", "Received: $receiveData")
                }
            }
        }.start()
    }


    @SuppressLint("NewApi")
    override fun onCreate(savedInstanceState: Bundle?) {
        var counter = 0
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
        val text = findViewById<TextView>(R.id.counterValue)

        val plusButton = findViewById<Button>(R.id.plusBtn)
        plusButton.setOnClickListener {
            counter++
            text.text = counter.toString()
        }

        val minusButton = findViewById<Button>(R.id.minusBtn)
        minusButton.setOnClickListener {
            counter--
            text.text = counter.toString()
        }

        val windowInsetsController =
            WindowCompat.getInsetsController(window, window.decorView)
        // Configure the behavior of the hidden system bars.
        windowInsetsController.systemBarsBehavior =
            WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())

        usbManager = getSystemService(USB_SERVICE) as UsbManager

        val filter = IntentFilter().apply {
            addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
            addAction(ACTION_USB_PERMISSION)
        }

        registerReceiver(usbReceiver, filter, RECEIVER_NOT_EXPORTED)
        val deviceList = usbManager!!.deviceList
        for (deviceEntry in deviceList.values) {
            Log.d("USB", "Device name : ${deviceEntry.deviceName}")
            if (deviceEntry.deviceClass == UsbConstants.USB_CLASS_COMM) {
                device = deviceEntry
                requestPermission(device!!)
                break
            }
        }
    }

    @SuppressLint("MutableImplicitPendingIntent")
    private fun requestPermission(device: UsbDevice) {
        val permissionIntent = PendingIntent.getBroadcast(
            this, 0, Intent(ACTION_USB_PERMISSION),
            PendingIntent.FLAG_IMMUTABLE
        )
        usbManager!!.requestPermission(device, permissionIntent)
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(usbReceiver)
        connection?.close()
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.MANAGE_USB"
        tools:ignore="ProtectedPermissions" />
    <uses-permission android:name="android.permission.USB_PERMISSION" />
    <uses-feature android:name="android.hardware.usb.host" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MidDisplaz"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

        </activity>
    </application>

</manifest>

任何有关为什么没有调用 BroadcastReciever 或 onReceiver() 的信息,我们将不胜感激。

谢谢

尝试了上面给出的代码。

android usb android-permissions enumeration
1个回答
0
投票

您似乎遇到了 Android 应用程序中的 USB 权限未触发

BroadcastReceiver
的问题。以下是一些需要检查的要点以及解决问题的建议:

  1. 接收者的意图过滤器: 确保您正确注册接收器并且其在

    IntentFilter
    中具有正确的操作。您的过滤器中有
    ACTION_USB_PERMISSION
    ,这是正确的,但也可以考虑添加
    UsbManager.ACTION_USB_PERMISSION
    。除非您想单独处理设备连接,否则可能不需要在初始设置中过滤
    ACTION_USB_DEVICE_ATTACHED

    您可以将过滤器更改为:

    val filter = IntentFilter().apply {
        addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
        addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
        addAction(ACTION_USB_PERMISSION)
    }
    
  2. 待定意向标志: 从 API 级别 23 (Android 6.0) 开始,使用

    PendingIntent.FLAG_IMMUTABLE
    是合适的,但对于较低版本,您可以考虑使用
    PendingIntent.FLAG_UPDATE_CURRENT
    以获得更好的兼容性,尽管它应该按原样工作。

    按如下方式更改您的

    createPendingIntent
    方法:

    val permissionIntent = PendingIntent.getBroadcast(
        this, 0, Intent(ACTION_USB_PERMISSION),
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )
    
  3. 在正确的上下文中请求权限: 确保仅在检查设备确实有效(非空)后才调用

    requestPermission(device!!)
    。当 USB 设备已被识别时,请仔细检查是否在正确的位置请求权限。

  4. 测试设备: 验证您的设备是否确实正在建立连接。有时,USB 设备可能无法在某些 Android 设备上生成预期的权限请求。如果可能,请在其他设备上进行测试或使用已知可以正常工作的其他 USB 设备。

  5. 清单中的权限: 清单中的

    USB_PERMISSION
    权限不是标准权限,但
    MANAGE_USB
    允许应用程序管理 USB 设备。但是,您不需要
    android.permission.USB_PERMISSION
    ,因为它不是公认的标准权限。线路可以安全移除。

  6. USB 接口和端点: 确保您从

    UsbDevice
    获得正确的接口和端点。您可以使用以下方式记录可用的接口和端点:

    for (i in 0 until device.interfaceCount) {
        val intf = device.getInterface(i)
        Log.d("USB", "Interface $i: ${intf.toString()}")
        for (j in 0 until intf.endpointCount) {
            val ep = intf.getEndpoint(j)
            Log.d("USB", "Endpoint $j: ${ep.toString()}")
        }
    }
    
  7. 权限调试: 在

    onReceive
    BroadcastReceiver
    功能中添加一些日志记录,以验证是否收到意图以及正在处理哪个操作:

    Log.d("USB Receiver", "Action Received: $action")
    

如果这些步骤不能解决问题,请考虑实施错误检查,以防 USB 连接丢失或请求连接后设备变得不可用,并查找可能指示失败原因的 logcat 消息。

通过确保这些方面,您可以潜在地解决为什么

BroadcastReceiver
没有按预期被调用的原因。

© www.soinside.com 2019 - 2024. All rights reserved.