Before you can connect to a USB device, you must first request permission to access it... after doing whatever is described in the link https://developer.android.com/guide/topics/connectivity/usb/host.html.
//Request user permission. The response will be received in the BroadcastReceiver
private void requestUserPermission(final UsbDevice usbDevice) {
PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0,
new Intent(UsbSerialService.INTENT_ACTION_USB_PERMISSION), 0);
mUsbManager.requestPermission(usbDevice, mPendingIntent);
}
Set up intent filters for the broadcast receiver...
public class UsbSerialService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
openSerialPort();
return Service.START_STICKY;
}
@Override
public void onCreate() {
//Initialize executors (using sequential executors to prevent concurrency issues)
mSerialPortExecutor = Executors.newSingleThreadExecutor();
//Initialize other variables
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
IntentFilter mUsbIntentFilter = new IntentFilter();
mUsbIntentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
mUsbIntentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
mUsbIntentFilter.addAction(UsbSerialService.INTENT_ACTION_USB_PERMISSION);
//Register a broadcast receiver to listen for Android system USB intents
getBaseContext().registerReceiver(mUsbReceiver, mUsbIntentFilter);
// whatever required to be performed here
super.onCreate();
}
@Override
public void onDestroy() {
closeSerialPort();
// whatever required to be performed here
super.onDestroy();
}
// the rest...
}
Below is the broadcast receiver...
//Different USB notifications are received here (USB attached, detached, permission responses)
private BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(UsbSerialService.TAG, "Intent Action: " + intent.getAction());
if (intent.getAction() != null && intent.getAction().equals(UsbSerialService.INTENT_ACTION_USB_PERMISSION)) {
boolean permissionGranted = false;
if (intent.getExtras() != null) {
permissionGranted = intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
}
if (permissionGranted) {
// User accepted our USB connection. Try to open the device as a USB port
getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_USB_PERMISSION_GRANTED)
.putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
.putExtra(UsbSerialService.EXTRA_USB_FAILED_STATE, UsbSerialService.isUsbFailed())
.putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
.putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
.putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
//Run USB port opening operation on a separate thread
mSerialPortExecutor.execute(new SerialPortOpener(device));
} else {
//Send out an intent to notify that the user denies access to the USB connection
getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_USB_PERMISSION_NOT_GRANTED)
.putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
.putExtra(UsbSerialService.EXTRA_USB_FAILED_STATE, UsbSerialService.isUsbFailed())
.putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
.putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
.putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
}
} else if (intent.getAction() != null && intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
// A USB device has been attached. Try to open it as a Serial port
closeSerialPort();
Log.d(UsbSerialService.TAG, "openSerialPort(USB) called upon attached");
openSerialPort();
} else if (intent.getAction() != null && intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
// @TODO Usb device disconnected. Stop listening for data input & close usb port
if (!Tools.isEmpty(UsbSerialService.getUsbId())) {
getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_USB_DISCONNECTED)
.putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
.putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
.putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
.putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
} else {
getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_USB_NOT_SUPPORTED)
.putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
.putExtra(UsbSerialService.EXTRA_USB_FAILED_STATE, UsbSerialService.isUsbFailed())
.putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
.putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
.putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
}
Log.e(UsbSerialService.TAG, "closeSerialPort(USB) called upon detached");
closeSerialPort();
}
}
};
The open USB device port method...
//Attempts to open the first encountered usb device connected, excluding usb root hubs
private void openSerialPort() {
if (!settings.isUsbDisabled()) {
Log.e(UsbSerialService.TAG, "openSerialPort(USB) is running...");
try {
HashMap<String, UsbDevice> usbDevices = mUsbManager.getDeviceList();
if (!usbDevices.isEmpty()) {
boolean deviceChosen = false;
if (!mSerialPortConnected) {
for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
UsbDevice usbDevice = entry.getValue();
//If there is a USB device connected, try to open it as a Serial port.
//1d6b Linux Foundation
// 0001 1.1 root hub
// 0002 2.0 root hub
// 0003 3.0 root hub
// 0100 PTP Gadget
// 0101 Audio Gadget
// 0102 EEM Gadget
// 0103 NCM (Ethernet) Gadget
// 0104 Multifunction Composite Gadget
// 0105 FunctionFS Gadget
// 0200 Qemu Audio Device
if (
(usbDevice.getVendorId() != 0x1d6b /*UsbId.VENDOR_LINUX*/
&& usbDevice.getProductId() != 0x0001
&& usbDevice.getProductId() != 0x0002
&& usbDevice.getProductId() != 0x0003)) {
if (Constants.ENABLE_USB_DEVICE_INFO) {
String info = String.format("DEV ID = %s\nVID = %d\nPID = %d",
usbDevice.getDeviceName(),
usbDevice.getVendorId(),
usbDevice.getProductId());
//do something to display USB device info...
}
requestUserPermission(usbDevice);
deviceChosen = true;
}
}
}
}
else {
//If there are no USB devices connected, notify other app components
getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_NO_USB)
.putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
.putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
.putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
.putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
}
} catch (NullPointerException e) {
//Catch statement to make it possible to run the app in an emulator (no USB)
e.printStackTrace();
}
}
else {
Log.e(UsbSerialService.TAG, "Invalid USB open state!");
}
}
The close USB device port method...
//Closes the USB serial connection
private void closeSerialPort() {
if (!settings.isUsbDisabled()) {
if (mSerialPortConnected) {
// Usb device disconnected. Stop listening for RAP input & close serial port
getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_USB_DISCONNECTED)
.putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
.putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
.putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
.putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
} else {
Log.e(UsbSerialService.TAG, "closeSerialPort(USB) is not running...");
}
//Run serial port closing operation on a separate thread
mSerialPortExecutor.execute(new SerialPortCloser());
} else {
Log.e(UsbSerialService.TAG, "Invalid USB close state!");
}
}
The UsbSerialService
mentioned in the preceding codes is my custom Service class that handles the serial connection to a USB device. It manages the push notification events and other behaviors as described in the intent names using another broadcast receiver.