USB device access pop-up suppression?
Asked Answered
O

2

55

When a USB device is connected to the Android tablet, a pop-up appears asking for user-permission. I want to suppress this as the client does not want it. How should I go about that?

In the code:

UsbManager.requestpermission(); 

is called to give the USB device temporary access.

This throws a pop-up. How do I suppress the pop-up or grant access to the user by default?

Owner answered 12/9, 2012 at 11:54 Comment(0)
P
112

When you request permission inside your app it seems that the checkbox "use by default for this USB device" does nothing (I am not sure why this checkbox even shows up on this popup.

Instead you should register an intent handler for your activity in the manifest:

<activity 
    ...
    ...
    >
    <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/usb_device_filter" />  
</activity>

You also have to create a filter file in your xml resources, eg res/xml/usb_device_filter:

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

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

The vendor-id and product-id here have to be given in decimal - above both the VID and PID are 0x6666.

What I have given above also works for a USB accessory (that is, where the accessory is the USB host and the android is the device) - in that case the intent-filter should register

<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />

and you also have to include the meta data filter in exactly the same way.

See http://developer.android.com/guide/topics/connectivity/usb/accessory.html and search for the section "Using an intent filter".

EDIT

To conclude - if you register the intent-filter against your activity, the USB permission window will be displayed immediately when the USB device/accessory is connected. If the user checks the "use by default for this USB device" box and then grants permission, this will be remembered and the permission dialog will not be displayed again (unless the app is uninstalled or the user clears the default action from the application manager).

I have put a tiny, terrible, working example project up here:

http://www.locusia.com/examples/permissionTest.zip

You will need to edit res/xml/usb_device_filter.xml, but otherwise this should allow you to test it out very quickly.

For services...

It seems that a service cannot receive the USB intents. I got around this by making a hidden activity which would then re-broadcast the intents.

I define it in my manifest like this:

<activity
    android:name=".activities.UsbEventReceiverActivity"
    android:label="YOUR APPLICATION NAME - This appears in the permission popup"
    android:theme="@style/Theme.Transparent" 
    android:noHistory="true"
    android:excludeFromRecents="true"
    android:taskAffinity="com.example.taskAffinityUsbEventReceiver"
    android:process=":UsbEventReceiverActivityProcess"
    android:exported="false"
    android:directBootAware="true"        
    >    
    <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/usb_device_filter" />  
</activity>

(I have a complex task/process layout in my service, YMMV in that area).

You may want the grant permission persist over reboot. You will need android:directBootAware="true" so that the USB_DEVICE_ATTACHED event is correctly received after boot / reboot

I defined the activity like this:

public class UsbEventReceiverActivity extends Activity
{   
    public static final String ACTION_USB_DEVICE_ATTACHED = "com.example.ACTION_USB_DEVICE_ATTACHED";
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
    }
    
    @Override
    protected void onResume()
    {
        super.onResume();
        
        Intent intent = getIntent();
        if (intent != null)
        {
            if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED))
            {
                Parcelable usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    
                // Create a new intent and put the usb device in as an extra
                Intent broadcastIntent = new Intent(ACTION_USB_DEVICE_ATTACHED);
                broadcastIntent.putExtra(UsbManager.EXTRA_DEVICE, usbDevice);
                    
                // Broadcast this event so we can receive it
                sendBroadcast(broadcastIntent);
            }
        }
        
        // Close the activity
        finish();
    }
}

And the last piece of the puzzle, the transparent theme (I'm not sure but you could probably use the built in android translucent theme) - res/values/styles.xml:

<?xml version="1.0" encoding="utf-8"?>  
    <resources>  
    <style name="Theme.Transparent" parent="android:Theme">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:backgroundDimEnabled">false</item>
        <item name="android:windowAnimationStyle">@null</item>
    </style>  
</resources>  
Peary answered 1/3, 2013 at 5:22 Comment(35)
For USB Host Mode this information is given in developer.android.com/guide/topics/connectivity/usb/host.html. The "Working with Devices" section on that page says the application has to "2. Ask the user for permission to connect to the USB device, if not already obtained." The OP's question (and mine!) is how to indicate that permission has already been granted so that the pop-up NEVER happens and the app can use the device immediately.Karakul
@Karakul when you say that "permission has already been granted" what exactly do you mean? If permission is already granted, then the function UsbManger.hasPermission() (pass either an accessory or device) will return true, and you can just open and use the accessory/device. There is no way to suppress the popup completely - it will have to show at least once and the user will have to check the box to "use by default for this device" and press yes/ok/accept - note that you MUST register the intent-filter against an activity for the permission to be remembered against your application.Peary
I just added another paragraph to my answer above because maybe it wasn't entirely clear before.Peary
Okay, I understand that android has to ask at least once, but I can't get that to happen - it asks every time the device is removed and reinserted. The reason for that, I think you're saying, is because the app calls RequestPermission. I need to reply purely on the event filter.Karakul
But that doesn't quite answer everything, because this seems to contradict the "Using an intent filter" section in developer.android.com/guide/topics/connectivity/usb/host.html - "If users accept, your application automatically has permission to access the device until the device is disconnected". That's pretty explicit about permission being lost when the device is disconnected. However, if you read that section closely then it doesn't mention the "use by default" tick box, so is that the final missing piece of magic that will make this work the way I want?Karakul
In conclusion, if I do everything EXACTLY as you've said, will it work so that if I plug in the USB device once, before my app has run, tick the checkbox and tap OK, then I will NEVER be asked for permission again, through USB device removal and tablet reboots, until the app is reinstalled or upgraded?Karakul
Yes, I have tested on the Galaxy S3 (Android 4.1.1), Galaxy Note (4.0.4) and Nexus 7 (4.2.2) - The permission needs to be accepted only once provided the checkbox is checked - and this will be remembered even through a reboot/power cycle.Peary
@Karakul I edited my answer, I put up a very small demo project which will let you test out the concept before you go refactoring your code.Peary
You've been amazingly helpful and patient. I'll get my SW guys to check this out.Karakul
That's quite alright - most places I can help on SO have got many people putting in answers already, so when I do come across something I know I try to help out as much as I can :)Peary
Okay, so you app works as advertised, but you're using an activity whereas my code is a service, and putting the intent-filter in the <service> ... </service> section of the AndroidManifect.xml file doesn't appear to be having any effect. Also the message I get is different - your test app gets "Open MainActivity when this USB device is connected?" while mine says "Allow the app APPNAME to access the USB device?"Karakul
Looking at #13466603, the answer suggests using the UMS_CONNECTED and UMS_DISCONNECTED intents instead. Would that help in my case?Karakul
Please see the new info at the end of my answer - I hope it works for you.Peary
Looks plausible. Thanks once again for your efforts. I'll let you know how we get on!Karakul
How does auto permission granting work in this case - does the Service get it because it's part of the same APK as the Activity?Karakul
I'm not sure - are permissions even granted on an "app" by "app" basis? Android doesn't really have the concept of an "app" outside of "everything is defined in the same manifest" - if I said I knew I'd only be guessing! All I know is, it works, even if the service and the activity run in separate tasks and processes.Peary
I guess that's what I meant by "part of the same APK". So if the service and the activity are defined in the same AndroidManifest.xml (and I guess there's only one of those in a APK file) then auto-permission granting works. Lovely!! Now if I could only get StackOverflow to email me when new comments were posted then I'd be in heaven :-)Karakul
Ahah - found it. Under StackExchange to the left of the bar at the top of the page, not anything to do with my profile - go figure!Karakul
@WayneUroda i have tried your example and I got success to integrate in my code and USB dialog is not appear for second time but here is one more problem with activity, activity where I have make IntentFilter of USB Attached its start if i am in another screen. here I dont want to start that if i am on another activityIreneirenic
@NikPatel My example covers this - just use the instructions "for services" - this creates a hidden activity (doesn't show up in history, doesn't show up on screen) which is finished immediately upon starting.Peary
@WayneUroda can you please elaborateIreneirenic
@NikPatel make a hidden activity - that is, one which doesn't show up in the history (android:noHistory="true" android:excludeFromRecents="true" in your manifest) and then have the activity finish itself in the onresume function (so that the activity is never active/on top). Also you can give the activity a transparent theme with no animation so that the OS doesn't draw the transitions. It is up to you how you want the activity to perform its work - it could spawn a new thread, broadcast an intent to another part of your app, or something else entirely.Peary
@WayneUroda yap I will try for same and let you know thanks :)Ireneirenic
here is one problem with application , I want to show dialog when print is out. so in actual when i am print out there should be visible my dialog and when i am on another activity and plug the usb cable there should not be cause any effect... after try this example I am still not achieve it. can you please help me out thisIreneirenic
@WayneUroda: Once the usb connection between android and the usb device is establishment,will this connection last forever? I tested my code by initiating a successful connection and kept it like that overnight.Next day I see that I am not able to send any data over the usb connection.I assume the connection died after sometime.Is this normal,or do I need to send any dummy signals at periodic intervals between the android and usb device to keep the connection in the live/active state ?Darmit
@WayneUroda: Also,in my case I am having a broadcast receiver instead of an activity/service,which listens to usb attached/permission intent.So far everything is working fine & my receiver does receive those intents on device reboot.I just need to disable the re-occurance of the usb permissions popup.Do I need to use that transparent activity for my case? Also, will this popup re-occur when the app is updated? Kindly assist me,as I am very close to getting a soln.Thanks.Darmit
Thanks, almost works for me. In order to start the service, however, I had to make the Intent an explicit one (supplying this, null, MyService.class as extra arguments) and use startService() rather then sendBroadcast()—only then would the service actually start.Door
I have used this invisible activity for a few years. But now, one problem rises that usb_device_filter.xml 's device is used for several apps. Then when I plug-in USB, the activity chooser will be shown, I have to choose the one which is the invisible activity, otherwise, the premission have no chance to be granted. Therefore, I would like to know if I can use a receiver but not an invisible activity (we already know service not work)? Can an receiver declared on manifest can be launched from usb device(defined on usb_device_filter.xml) pluging-in?Xever
I have followed this and used the correct Vendor ID and Product ID, but still every time that the USB device (an Arduino Teensy) is unplugged from the phone the app requires permission again. Is there something I am missing. For more details I started a new question: https://mcmap.net/q/339171/-android-app-won-39-t-remember-usb-permissionKlong
for me it works, but if the device restarted confirmation dialog steel show's up. I have installed app to the System/priv-app folderLeveille
@WayneUroda how to remember permission after rebooting?Precisian
@WayneUroda, Hi, I am using a fragment where I ask for USB permission for Biometric device. Now, If I use your code, I need to pass intent filter to it's Activity and that leads me to that particular Activity if I follow your steps in permission dialog. Please guide me on how I can do that in a fragmentProlongation
fyi: you can find out the vendor id and product id from adb logcat. just connect the device and check thereTartlet
Now, I need to develop which is not root or in /syste/priv-app/ . Everytime on reboot, the permission is forgotten..any solution?Xever
ok. Found out from another answer on here . I think most people want it so I go edit to add this.Xever
M
0

Official android docs says:

When users connect a device that matches your device filter, the system presents them with a dialog that asks if they want to start your application. If users accept, your application automatically has permission to access the device until the device is disconnected.

If you also check box to remember device, permission is granted until app uninstalls or data is deleted trough app manager.

So you must do:

  1. Add intent-filter as Wayne says, (and delete all about permissions in your main activity).
  2. Install app and CLOSE IT.
  3. Unplug and plug your usb.
  4. Accept permission and check box to remember device.
Molest answered 7/5, 2019 at 23:5 Comment(4)
Do you have a suggestion if you expect the USB cable to already be plugged in on power up? I have implemented this approach, and it works great if I plug in the USB cable after power up, but in my case I'm expecting the cable to remain plugged in all the time.Preoccupancy
Nope, until you do it at least first time because event is on device attached...Molest
@RyanTensmeyer Did you figure out a solution for this scenario?Forklift
@Forklift I found a work around (well my friend did, we were working on this together). Unfortunately I got busy and didn't ever really understand how he did it. I know he ended up doing something that required him to restart UI, but that's all I remember. Sorry I'm not more help.Preoccupancy

© 2022 - 2024 — McMap. All rights reserved.