Android - How can I synchronize UsbManager::requestPermission?

Viewed 19

I have the following code:

public final static @NonNull String ACTION_USB_PERMISSION = "blah blah";
public final @NonNull Object permissionLock = new Object();
public final @NonNull AtomicBoolean didReceiverReceive = new AtomicBoolean(false);

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            didReceiverReceive.set(true);
            synchronized (permissionLock) {
                permissionLock.notifyAll();
            }
        }
    }, new IntentFilter(ACTION_USB_PERMISSION));
    final @NonNull UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
    final @NonNull UsbDevice usbDevice = usbManager.getDeviceList().values().stream().findFirst().get();
    // For the sake of requesting permission, assume
    //  usbDevice != null; (and unwrapping the Optional<UsbDevice> was successful)
    //  usbManager.hasPermission(usbDevice) == false;
    // We need to request permission!
    synchronized (permissionLock) {
        usbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE));
        /* CASE 1: assume UsbManager::requestPermission is asynchronous
         * THIS CAUSES DEADLOCK! THIS IS BAD
        try {
            permissionLock.wait();
        } catch (InterruptedException ie) {
            // this never happens btw
            throw new RuntimeException(ie);
        }
         */
        /* CASE 2: assume UsbManager::requestPermission is synchronous
         * THIS THROWS AN ASSERTION ERROR! THIS IS BAD
        assert didReceiverReceive.get();
         */
    }
    // TODO how do I safely block execution of the Thread that calls onCreate until the USB-permission broadcast receiver receives the broadcast intent?
}

I tried two things (named CASE 1 and CASE 2), which are in the onCreate method in the location in which they were invoked.

I was expecting that UsbManager::requestPermission was either asynchronous or synchronous. Pretty reasonable, no? It turns out it is semi-synchronous for lack of a better word. What happens is that the UsbManager seems to schedule the broadcast/permission request to be executed at some time in the future, but not necessarily on a different thread. This thread that it uses to schedule the broadcast/permission request is the same that calls onCreate, regardless of whether or not I put usbManager.requestPermission(...) in a new Thread. Consequently, I simply cannot create a scenario in which the USB-permission broadcast receiver's onReceive method is invoked appropriately before the onCreate method terminates.

0 Answers
Related