USB device access pop-up suppression?

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>  

Leave a Comment