How to receive USB connection status broadcast?

16,027

Solution 1

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)

Solution 2

Here the perfect steps to check that external usb connection occur or not in android activity. Just Follow the steps one by one.

In Android Manifest file:

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

Inside your USB checking Activity Tag:

 <activity android:name=".USBEnabled">
        <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" />

    </activity>

Inside your connectivity checking USBEnabled class :

public class USBEnabled extends AppCompatActivity {
private static final String TAG = "UsbHost";

TextView mDeviceText;
Button mConnectButton;
UsbManager mUsbManager;
UsbDevice mDevice;
PendingIntent mPermissionIntent;

private static final int REQUEST_TYPE = 0x80;
private static final int REQUEST = 0x06;
private static final int REQ_VALUE = 0x200;
private static final int REQ_INDEX = 0x00;
private static final int LENGTH = 64;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_usbenabled);

    mDeviceText = (TextView) findViewById(R.id.text_status);
    mConnectButton = (Button) findViewById(R.id.button_connect);
    mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
}

@Override
protected void onRestart() {
    super.onRestart();
    recreate();
}

@Override
protected void onResume() {
    super.onResume();

    mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
    IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
    registerReceiver(mUsbReceiver, filter);
    updateDeviceList();
}

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(mUsbReceiver);
}

public void onConnectClick(View v) {
    if (mDevice == null) {
        return;
    }
    mUsbManager.requestPermission(mDevice, mPermissionIntent);
}


private static final String ACTION_USB_PERMISSION = "com.android.recipes.USB_PERMISSION";
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (ACTION_USB_PERMISSION.equals(action)) {
            UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

            if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
                    && device != null) {

                getDeviceStatus(device);
            } else {
                Log.d(TAG, "permission denied for device " + device);
            }
        }
    }
};


private void getDeviceStatus(UsbDevice device) {
    UsbDeviceConnection connection = mUsbManager.openDevice(device);
    byte[] buffer = new byte[LENGTH];
    connection.controlTransfer(REQUEST_TYPE, REQUEST, REQ_VALUE, REQ_INDEX,
            buffer, LENGTH, 2000);
    connection.close();
}

private void updateDeviceList() {
    HashMap<String, UsbDevice> connectedDevices = mUsbManager
            .getDeviceList();
    if (connectedDevices.isEmpty()) {
        mDevice = null;
        mDeviceText.setText("No Devices Currently Connected");
        mConnectButton.setEnabled(false);
    } else {
        for (UsbDevice device : connectedDevices.values()) {
            mDevice = device;
        }
        mDeviceText.setText("USB Device connected");
        mConnectButton.setEnabled(true);
    }
}}

Inside your class xml file :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<Button
    android:id="@+id/button_connect"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:onClick="onConnectClick"
    android:text="Connect" />

<TextView
    android:id="@+id/text_status"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="22dp" />

<TextView
    android:id="@+id/text_data"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="22dp" />
</LinearLayout>

Now create a new resource directory called xml and create new xml file called device_filter.xml with the following code.

<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device />
</resources>

Debug and run the application, it will show external usb device connectivity status without any error. I hope you will get output for your scenario.

Enjoy!!

Share:
16,027
Gokul NC
Author by

Gokul NC

A Computer Science Student aspiring to learn everything..

Updated on June 23, 2022

Comments

  • Gokul NC
    Gokul NC almost 2 years

    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??

    • Onik
      Onik over 7 years
      You use both dynamically and manifest defined receivers. Leave the dynamic one and let me know the result.
    • Gokul NC
      Gokul NC over 7 years
      I commented out the setBroadcastReceivers(); call (as in code snippet above), still doesn't work..
    • Onik
      Onik over 7 years
      You just did the opposite of what I said!)) Use setBroadcastReceivers() and comment out the receiver in the manifest file. Perhaps, I confused you, I meant "Leave untouched".
    • Gokul NC
      Gokul NC over 7 years
      Thanks for the response @Onik, I tried that, didn't help :(
  • Nikhil Kumar
    Nikhil Kumar almost 7 years
    Hey, a working answer to detect when a USB is connected. Any idea how to get device details? Using UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); in the receiver returns null
  • Octopus
    Octopus over 5 years
    Well, this code is alright. What it does though is it detects a global broadcast that a device is inserted and launches the app. The app itself though, still does not respond to broadcast actions ACTION_USB_DEVICE_ATTACHED or ACTION_USB_DEVICE_DETACHED as was asked in the OP, so it doesn't actually answer the question asked.
  • user149408
    user149408 about 5 years
    Actually, USB_STATE reports the state of connections where the Android device connects to a host (phone to PC), not of USB peripherals to the device via USB OTG.
  • Chetan Joshi
    Chetan Joshi over 3 years
    how to connect another android device through above code.