androidkotlinandroid-usb

PendingIntent not Triggered for USB Permission Request in Android


I am trying to request USB permission in my Android app and communicate with USB devices. However, after the USB permission request popup is shown and the user grants permission, the UsbBroadcastReceiver does not trigger, and the PendingIntent that I set up for the broadcast isn't received.

class MainActivity : ComponentActivity() {

    private val ACTION_USB_PERMISSION = BuildConfig.APPLICATION_ID + ".USB_PERMISSION"
    private lateinit var usbReceiver: UsbBroadcastReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        usbReceiver = UsbBroadcastReceiver()


        val permissionIntent = PendingIntent.getBroadcast(
            this,
            0,
            Intent(ACTION_USB_PERMISSION), 
            PendingIntent.FLAG_IMMUTABLE
        )
        
        val usbManager = getSystemService(Context.USB_SERVICE) as UsbManager
        usbManager.deviceList.values.forEach { device ->
            if (!usbManager.hasPermission(device)) {
                Log.d("USB_REQUEST", "Requesting permission for device: ${device.deviceName}")
                usbManager.requestPermission(device, permissionIntent)
            }
        }
        
        val filter = IntentFilter().apply {
            addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
            addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
            addAction(ACTION_USB_PERMISSION)
        }
        registerReceiver(usbReceiver, filter, RECEIVER_NOT_EXPORTED)
        
        setContent {
            SampleTestAppTheme {
                Scaffold { innerPadding ->
                    Box(
                        modifier = Modifier
                            .padding(innerPadding)
                            .fillMaxSize()
                    ) {
                        Text("USB Communication Example", modifier = Modifier.padding(16.dp))
                    }
                }
            }
        }
    }
}

class UsbBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val action = intent.action
        Log.d("USB_RECEIVER", "Received Action: $action")

        when (action) {
            BuildConfig.APPLICATION_ID + ".USB_PERMISSION" -> {
                val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    Log.d("USB_RECEIVER", "Permission granted for device: ${device?.deviceName}")
                    // Set up USB communication here
                } else {
                    Log.e("USB_RECEIVER", "Permission denied for device: ${device?.deviceName}")
                }
            }
            UsbManager.ACTION_USB_DEVICE_ATTACHED -> {
                Log.d("USB_RECEIVER", "USB Device Attached")
            }
            UsbManager.ACTION_USB_DEVICE_DETACHED -> {
                Log.d("USB_RECEIVER", "USB Device Detached")
            }
        }
    }
}

I expected the UsbBroadcastReceiver to trigger when the user grants/denied permission for a USB device.


Solution

  • It does not trigger because you have an immutable implicit intent:

     val permissionIntent = PendingIntent.getBroadcast(
                this,
                0,
                Intent(ACTION_USB_PERMISSION), 
                PendingIntent.FLAG_IMMUTABLE
            )
    

    To fix this, make the intent explicit and mutable:

     val permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION).apply {
                setPackage(this.packageName)
            }, PendingIntent.FLAG_MUTABLE)