2

I'm stuck on figuring out how to ask for permission to access a USB com device, wait for the user input, then proceed accordingly if permission granted. I can't figure out what the "onRequestPermissionsResult" is for when UsbManager asks for permissions. I noticed that listener never gets called when UsbManager requests permission, so its not used in the way I originally thought.

This code is all in the MainActivity.

Here I'm setting my Intent for when my USB device is connected or disconnected, and initializing UsbManager. Note I'm not using LOGCAT to log debug messages because my Android device has to be disconnected from Android Studio to plug in the USB com device I'm developing the app for. Instead I'm logging to the app UI.

protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   DoIntent();

   m_manager = (UsbManager) getSystemService(Context.USB_SERVICE);
}
   private void DoIntent () {

      m_usbReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action) || UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
               try {
                  OnDeviceConnected();
                  // m_textViewDebug.setText("USB Connected");
               } catch (Exception e) {
                  m_textViewDebug.setText(e.getMessage());
               }
            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action) || UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
               m_port = null;
               m_serialIoManager = null;
               m_isInitialized = false;
               m_textViewDebug.setText("USB Disconnected");
            }
         }
      };

      IntentFilter filter = new IntentFilter();
      filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
      filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);

      registerReceiver(m_usbReceiver , filter);

Then here is what happens when a device is connected. I want to establish permission as soon as its connected.

   private void OnDeviceConnected () throws Exception {
      ProbeTable customTable = new ProbeTable();
      customTable.addProduct(0x239a, 0x800c, CdcAcmSerialDriver.class);
      UsbSerialProber prober = new UsbSerialProber(customTable);

      List<UsbSerialDriver> drivers = prober.findAllDrivers(m_manager);

      UsbDeviceConnection connection = null;
      UsbSerialDriver driver = drivers.get(0);

      PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
      m_manager.requestPermission(driver.getDevice(), usbPermissionIntent);

      /// Need some kind of pause or check for permissions here before executing forward.or
      /// handle everything after on a different routine called after permission has been selected.

      /// Continues to execute before user has time to respond to permissions.

      try {
         connection = m_manager.openDevice(driver.getDevice());
      } catch (Exception e) {
         throw new Exception(e.getMessage());
      }

      if (connection == null) {
         throw new Exception ("Could not open device.");
      }

      m_port = driver.getPorts().get(0);

      try {
         m_port.open(connection);
         m_port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
         m_port.setDTR(true);
      } catch (Exception e) {
         throw new Exception(e.getMessage());
      }

      m_serialIoManager = new SerialInputOutputManager(m_port, m_listener);
      m_executor.submit(m_serialIoManager);

      m_isInitialized = true;
   }

Then here is what I'm originally trying to do once permission has been granted. I can't get any logging message to appear from this scope, so I believe it's never being called and I'm using it incorrectly.

   @Override
   public void onRequestPermissionsResult(final int requestCode, String[] permissions, int[] grantResults) {

      MainActivity.this.runOnUiThread(new Runnable() {
         public void run() {
            /// Never gets called :/
            m_textViewDebug.setText(Integer.toString(requestCode));
         }
      });

      switch (requestCode) {
         case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            /// If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
               /// permission was granted, yay! Do the
               /// contacts-related task you need to do.
            } else {
               /// permission denied, boo! Disable the
               /// functionality that depends on this permission.
            }
            return;

         case USB_PERMISSION_GRANTED: { /// Not the real enum because I'm not sure where to find what it is.
            try {
               /// Need to somehow pass driver from OnDeviceConnected to this scope, or make it class property.
               connection = m_manager.openDevice(driver.getDevice());
           } catch (Exception e) {
              throw new Exception(e.getMessage());
           }

           if (connection == null) {
               throw new Exception ("Could not open device.");
           }

            m_port = driver.getPorts().get(0);

            try {
              m_port.open(connection);
              m_port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
              m_port.setDTR(true);
            } catch (Exception e) {
               throw new Exception(e.getMessage());
            }

            m_serialIoManager = new SerialInputOutputManager(m_port, m_listener);
            m_executor.submit(m_serialIoManager);

            m_isInitialized = true
         }

         /// other 'case' lines to check for other
         /// permissions this app might request.
      }
   }

I'm trying to log what requestCode is so I can write a case for whatever the USB permission code is. I can't find a compiled list anywhere in the docs of what all the options are that requestCode could be. MY_PERMISSIONS_REQUEST_READ_CONTACTS actually throws a compile error because I have no idea where it comes from. This guide isn't very detail with USB specifically. That guide is also where I got the switch statement in my above routine.

EDIT:

I tried messing around with UsbManager.EXTRA_PERMISSION_GRANTED to see if that could work. I added it as an action to my intent filter.

   IntentFilter filter = new IntentFilter();
   filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
   filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
   filter.addAction(UsbManager.EXTRA_PERMISSION_GRANTED);

   registerReceiver(m_usbReceiver, filter);

Then I'm logging what the action of the intent is coming into my Broadcast Receiver, but nothing happens when a USB permission is granted or denied.

enter image description here

What kind of action or event is triggered when "OK" is tapped in this above image? Been scratching my head at this for a few days poking at the API.

GhostRavenstorm
  • 634
  • 3
  • 9
  • 29

1 Answers1

2

I finally figured it out taking a closer look at this.

I have this before trying to establish an intent filter.

public static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
IntentFilter filter = new IntentFilter();

And I changed it to this.

private static final String ACTION_USB_PERMISSION = BuildConfig.APPLICATION_ID + ".USB_PERMISSION";
m_permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);

The key difference was that new IntentFilter needed that ACTION_USB_PERMISSION string.

Now in my Broadcast Receiver, I have this condition that is being called as expected.

else if (ACTION_USB_PERMISSION.equals(action)) {
   if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
      m_textViewDebug.setText("USB Permission Granted");
      try {
         OnDevicePermissionGranted();
      } catch (Exception e) {
         m_textViewDebug.setText(e.getMessage());
      }
   }
   else {
      m_textViewDebug.setText("USB Permission Denied");
   }
}

Took me a while to figure out how to use EXTRA_PERMISSION_GRANTED. When this here says "EXTRA_PERMISSION_GRANTED containing boolean indicating whether permission was granted by the user" I'm thinking this whole time I'm trying to find a boolean flag on some object to verify permission. I didn't realize I had to call a special method on the intent and supply that string to get my true or false. Seems very counter intuitive to me.

I realize the biggest mistake was not supplying the correct string when making the new intent filter. I found a bunch of other examples that had it without any arguments.

GhostRavenstorm
  • 634
  • 3
  • 9
  • 29