How to receive USB connection status broadcast?

Gokul NC picture Gokul NC · Oct 9, 2016 · Viewed 13k times · Source

I am trying to detect USB connection in my app, that is, whether or not USB is connected to device.

It's being tested on Marshmallow 6.0.1 (sdk23)

But I'm unable to receive the broadcast actions ACTION_USB_DEVICE_ATTACHED or ACTION_USB_DEVICE_DETACHED..

I tried using both the dynamic way and the AndroidManifest.xml way, neither worked..

Here's my code:

AndroidManifest.xml :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.gokulnc.blah_blah"
    android:installLocation="auto"
    android:versionCode="15"
    android:versionName="1.5.1">

    <uses-feature android:name="android.hardware.usb.host" />

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="23" />

    <android:uses-permission android:name="android.permission.USB_PERMISSION" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:vmSafeMode="false">

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/DrawerTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <receiver android:name="mUsbReceiver">
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
            </intent-filter>
            </receiver>
        </activity>        
    </application>

</manifest>

MainActivity.java :

public class MainActivity extends AppCompatActivity {
    BroadcastReceiver mUsbReceiver;

    public void onCreate(Bundle savedInstanceState) {
        .....
        setBroadcastReceivers();
    }

    void setBroadcastReceivers() {
    //Reference: http://www.codepool.biz/how-to-monitor-usb-events-on-android.html

    mUsbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(LOG_TAG, "Received Broadcast: "+action);
            if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action) || UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {

                updateUSBstatus();
                Log.d(LOG_TAG, "USB Connected..");
            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action) || UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
                UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (device != null) {
                    updateUSBstatus();
                }
                Log.d(LOG_TAG, "USB Disconnected..");
            }
        }
    };

    IntentFilter filter = new IntentFilter();
    filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
    filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
    //filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
    //filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
    registerReceiver(mUsbReceiver , filter);
    Log.d(LOG_TAG, "mUsbReceiver Registered");
    }

    @Override
        public void onResume() {
            super.onResume();
            Log.d(LOG_TAG, "App Resumed..");
            //Refernce: https://stackoverflow.com/questions/18015656/cant-receive-broadcast-intent-of-usbmanager-action-usb-device-attached-usbmanag
            Intent intent = getIntent();
            if (intent != null) {
                if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
                    Toast.makeText(getApplicationContext(), "Attached", Toast.LENGTH_SHORT).show();
                } else if(intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
                    Toast.makeText(getApplicationContext(), "Detached", Toast.LENGTH_SHORT).show();
                }
            }
        }
}

I also checked this answer: Can't receive broadcast Intent of UsbManager.ACTION_USB_DEVICE_ATTACHED/UsbManager.ACTION_USB_DEVICE_DETACHED, but it didn't help..

Can someone please point out where I'm wrong??

Answer

Gokul NC picture Gokul NC · Oct 11, 2016

Maybe the reason it doesn't work is that since Android 6.0, the default USB mode is Charging and, maybe ACTION_USB_DEVICE_ATTACHED doesn't get fired up when connected in that mode..

Instead, now I have another solution:

String usbStateChangeAction = "android.hardware.usb.action.USB_STATE";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(LOG_TAG, "Received Broadcast: "+action);
        if(action.equalsIgnoreCase(usbStateChangeAction)) { //Check if change in USB state
            if(intent.getExtras().getBoolean("connected")) {
                // USB was connected
            } else {
                // USB was disconnected
            }
        }
    }

That is, the broadcast android.hardware.usb.action.USB_STATE is sent whenever there is a toggle in the USB state.

Unlike android.hardware.usb.action.USB_DEVICE_ATTACHED which is broadcasted only when something like a MTP mode is enable, android.hardware.usb.action.USB_STATE is broadcasted whenever it detects an USB connection that's capable of connecting to a host (say computer), irrespective of its current USB Mode like Charging, MTP or whatever.. (it's called USB config to be more precise)