xseignard / cordovarduino

Cordova/Phonegap plugin for USB host serial communication from an Android device.
MIT License
166 stars 110 forks source link

Skip permission #31

Open rammere opened 9 years ago

rammere commented 9 years ago

Hi , Can we skip the permission ? so the user won't be prompted with permission dialog ? And thank you for your great plugin :D Regards,

xseignard commented 9 years ago

Hello @rammere You can add the following in your platforms/android/AndroidManifest.xml in the <activity> node

<intent-filter>
    <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" />

And add the following file named device_filter.xml in platforms/android/res/xml/

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <!-- arduino uno R3 -->
    <usb-device vendor-id="9025" product-id="0067" />
</resources>

Where the vendor id and product id of your serial device are in decimal format. (the example provided above shows VID and PID of arduino uno R3).

I'm still looking for a way to do that when you run a cordova build, if you have a clue, it's welcome.

Adding this to the plugin.xml doesn't seem to work.

Regards,

Xavier

xseignard commented 9 years ago

So it seems impossible from the config.xml or the plugin.xml, you would need a hook, please see http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/ for some doc about hooks

xseignard commented 9 years ago

Any update @rammere ?

xseignard commented 9 years ago

@rammere any updates?

xseignard commented 9 years ago

@rammere cough cough! :)

raumfisch commented 9 years ago

Hi, i am experiencing the same problem, the permission to connect to the device is asked every time and the setting to use this permission as a standard for this device seems to have no effect. I applied the settings recommended by xseignard in AndroidManifest.xml and device_filter.xml with no effects.

In the code snippets of the usb-serial-for-android libraries i found that manager.openDevice() is just called and requestPermission() is only called on a failure of this function. If i apply this with this module my app just crashes.

Do you have any hints what i'm doing wrong? Is there any further documentation on how to use this module? I'm using cordova with the ionic framework.

Thank you,

Jan

xseignard commented 9 years ago

The solution I provided should work. But if you say that manager.openDevice() would do the trick then we just need to implement it in the plugin.

It would be a simple and nice addition.

Is it something you could achieve @raumfisch ?

Regards

xseignard commented 8 years ago

@raumfisch any update?

nsted commented 8 years ago

Hi @xseignard. Thanks for a nice plugin. I also want to skip permissions, and was able to use your method above to automatically connect, but only when initially building the app and pushing to the device. On subsequent cycling of the USB OTG cable, the permission requests return even though it's the same arduino. I'm attempting to run my app in a pinned state (kiosk mode), which prevents system messages like the permissions to be displayed to the user, so ideally I'd like it to be handled automatically in the background.

xseignard commented 8 years ago

Hi @nsted I never experienced such behavior, I should check it again.

In the meantime, could you show me your code?

Regards

nsted commented 8 years ago

Hi @xseignard Thank you for offering to look at my code. After looking again, I realized that I made a mistake by listing the PID/VID in Hex as opposed to Decimal as you indicated should be done. I've updated the code, and it now works. Cheers!

xseignard commented 8 years ago

@nsted : glad to hear it works, have fun :)

jbprinsloo commented 8 years ago

Hi @xseignard Well done with an awesome plugin. I was hoping you would be you would be able to assist. I'm using the the same arduino and can connect with the HEX values that I received from lsusb -v VID=2a03 and PID=0043. According to this thread I need to insert the values in decimal. I converted the values with an online tool that gives me the decimal VID as 10755 and PID as 67. If I change these values it does not see the device ERROR:nodivice found. I have also tried different variations but still cant get the permission check bypassed. Any advice?

xseignard commented 8 years ago

@jbprinsloo did you try 10755 and 0067?

jbprinsloo commented 8 years ago

Hi @xseignard

Thanks for the reply. Still no luck. I'm new to this so not sure where to go next. I also tried to connect like this without the changes in the AndroidManifest and the Device filter

serial.requestPermission({ vid: '2a03', pid: '0043' }, .... --> Works (Perminant Permission Request)
serial.requestPermission({ vid: '10755', pid: '0067' },.... --> No Device error
serial.requestPermission({ vid: '10755', pid: '67' }, ....--> No Device error

Then I tried to connect with the changes in the manifest and device filter like this

 // request permission first
serial.requestPermission(
    // if user grants permission
    function (successMessage) {
        // open serial port
        serial.open( ....

AndriodManifest.xml Below

androidmanifest

device_filter.xml

devicefilter

Not sure where I'm going wrong :\

jbprinsloo commented 8 years ago

Hi @xseignard

Well after spending the weekend playing with different devices and trying multiple variations of the settings I have finally got it sorted and its working perfectly as expected. Feeling rather sheepish I was passing in the VID and PID as strings that made your plugin think that it was hex values. Apologies for waiting your time and thanks for making a great plugin.

xseignard commented 8 years ago

@jbprinsloo good to know! I'll try to update the docs to emphasis this subtle thing!

Have fun!

Regards

robindierckx commented 6 years ago

I wrote a hook for this in my project's hooks/after_platform_add folder. It certainly has some room for improvement, but it's a good start and works fine on my project.

#!/usr/bin/env node

var fs = require('fs'),
    parseString = require('xml2js').parseString,
    xml2js = require('xml2js');

var rootdir = process.argv[2];

if (rootdir) {

  // go through each of the platform directories that have been prepared
  var platforms = (process.env.CORDOVA_PLATFORMS ? process.env.CORDOVA_PLATFORMS.split(',') : []);
  for(var x=0; x<platforms.length; x++) {
    // open up the index.html file at the www root
    try {
      var platform = platforms[x].trim().toLowerCase();
      if(platform.includes('android')) {
        if (!fs.existsSync('platforms/android/res/xml/device_filter.xml')) {
          console.log("writing platforms/android/res/xml/device_filter.xml")
          fs.createReadStream('hooks/assets/device_filter.xml').pipe(fs.createWriteStream('platforms/android/res/xml/device_filter.xml'));
        }
        fs.readFile('platforms/android/AndroidManifest.xml', 'utf-8', function (err, data){
            if(err) console.log(err);
            // we then pass the data to our method here
            parseString(data, function(err, result){
                if(err) console.log("ERROR",err);
                // here we log the results of our xml string conversion
                //console.log(result); 
              var json = result;

              fs.readFile('hooks/assets/data_to_be_added.xml', 'utf-8', function(err, data_to_be_added){
                if(err) console.log("ERROR", err);
                parseString(data_to_be_added,function(err, result2){
                  if(err) console.log("ERROR",err);

                  var json_to_be_added = result2;
                  var activity = json.manifest.application[0].activity[0]

                  for (var property in json_to_be_added.body) {
                      if (json_to_be_added.body.hasOwnProperty(property)) {
                          if (activity.hasOwnProperty(property)) {
                            json.manifest.application[0].activity[0][property].push(json_to_be_added.body[property][0])
                          }
                          //if the property does not exist yet
                          else {
                            json.manifest.application[0].activity[0][property] = json_to_be_added.body[property];
                          }
                      }
                  }
                  // create a new builder object and then convert
                  // our json back to xml.
                  var builder = new xml2js.Builder();
                  var xml = builder.buildObject(json);

                  fs.writeFile('platforms/android/AndroidManifest.xml', xml, function(err, data){
                      if (err) console.log("error in writing xml file: ", err);
                      console.log("successfully written our update xml to file");
                  })
                })

              });  
            });
        }); 
      }

    } catch(e) {
      process.stdout.write(e);
    }
  }

}

With those two additional files in the following locations hooks/assets/device_filter.xml:

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <usb-device vendor-id="1027" product-id="24577" />
</resources>

and hooks/assets/data_to_be_added.xml

<?xml version="1.0" encoding="utf-8"?>

<body>
<intent-filter>
    <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" />
</body>
kgamecarter commented 6 years ago

If you have the option to compile the android system, then there's nothing you cannot do.

You can add

public void onStart() {
    super.onStart();
    mPermissionGranted = true;
    finish();
}

to frameworks/base/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java

to bypass the the permission confirmation popup.

robindierckx commented 6 years ago

The AndoidManifest workaround works fine on android 5. But the same build fails to hide the popup on Android 7. Any idea why ?

p0wdrdotcom commented 5 years ago

Thought I would put here that permission may be sorted by your cordova config like this

        <resource-file src="res/xml/device_filter.xml" target="res/xml/device_filter.xml" />
        <config-file parent="/manifest/application/activity" target="AndroidManifest.xml">
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>
        </config-file>
        <config-file parent="/manifest/application/activity" target="AndroidManifest.xml">
            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" />
        </config-file>

also update the namespaces in the config file to include the android namespace like this

<widget xmlns:android="http://schemas.android.com/apk/res/android">

in the root of the cordova project place a file with the right vendor and product id's.

similar to this

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <usb-device vendor-id="0403" product-id="6001" />
    <usb-device vendor-id="10c4" product-id="ea60" />
</resources>

This will allow cordova to make the changes to the manifest and add the device filter list. Once this happens permissions, are requested only once and will only be requested again if the app is uninstalled.

These changes are limited to your cordova application source code so you don't have to go hacking around in the android platform source.

There is potential for the plugin config to make these changes also.

dymdev commented 5 years ago

Hi p0wdrdotcom, I am newbie in cordova and I'm struggling to make your solution work. Could you point where to put your code:

`

    <config-file parent="/manifest/application/activity" target="AndroidManifest.xml">
        <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" />
    </config-file>`

I have tried in the config.xml inside <platform name="android"> but It do not compile. I will appreciate any help. Thank you

rexn8r commented 6 days ago

Hi @xseignard

I tried the suggestions to add the settings in the Androidmanifest.xml file but still the permission dialog appears on reboot.

My Androidmanifest.xml contains following settings;

above

<activity android:directBootAware="true" ....

My device_filter.xml file contains following nodes (with VID and PID in decimal/integer value;

Now when I call the serial.requestPermission plugin function with following code, the serial communication works fine but when the device is rebooted, the permission box shows up again;

serial.requestPermission({ vid: '1A86', //hex value pid: '7523', driver: 'Ch34xSerialDriver' // or any other }

If I try to use the VID and PID as integer as follows, 'No Device' found error comes up.

serial.requestPermission({ vid: 6790, //integer value pid: 7523, driver: 'Ch34xSerialDriver' // or any other }

how to resolve the issue?

Thanks R