Listen to USB device de/attach event. (#1961)
* Listen to USB device de/attach event.
With listening to USB device de/attach event, disconnect
test can well sync on the peripherals plug state.
diff --git a/apps/OboeTester/app/build.gradle b/apps/OboeTester/app/build.gradle
index d930cd8..5f90160 100644
--- a/apps/OboeTester/app/build.gradle
+++ b/apps/OboeTester/app/build.gradle
@@ -6,8 +6,8 @@
applicationId = "com.mobileer.oboetester"
minSdkVersion 23
targetSdkVersion 34
- versionCode 80
- versionName "2.5.9"
+ versionCode 81
+ versionName "2.5.10"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java
index a314d1a..9e4d880 100644
--- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java
@@ -20,6 +20,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
@@ -49,6 +54,7 @@
private volatile boolean mTestFailed;
private volatile boolean mSkipTest;
private volatile int mPlugCount;
+ private volatile int mUsbDeviceAttachedCount;
private volatile int mPlugState;
private volatile int mPlugMicrophone;
private BroadcastReceiver mPluginReceiver = new PluginBroadcastReceiver();
@@ -64,13 +70,34 @@
public class PluginBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- mPlugMicrophone = intent.getIntExtra("microphone", -1);
- mPlugState = intent.getIntExtra("state", -1);
- mPlugCount++;
+ switch (intent.getAction()) {
+ case Intent.ACTION_HEADSET_PLUG: {
+ mPlugMicrophone = intent.getIntExtra("microphone", -1);
+ mPlugState = intent.getIntExtra("state", -1);
+ mPlugCount++;
+ } break;
+ case UsbManager.ACTION_USB_DEVICE_ATTACHED:
+ case UsbManager.ACTION_USB_DEVICE_DETACHED: {
+ UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ final boolean hasAudioPlayback =
+ containsAudioStreamingInterface(device, UsbConstants.USB_DIR_OUT);
+ final boolean hasAudioCapture =
+ containsAudioStreamingInterface(device, UsbConstants.USB_DIR_IN);
+ if (hasAudioPlayback || hasAudioCapture) {
+ mPlugState =
+ intent.getAction() == UsbManager.ACTION_USB_DEVICE_ATTACHED ? 1 : 0;
+ mUsbDeviceAttachedCount++;
+ mPlugMicrophone = hasAudioCapture ? 1 : 0;
+ }
+ } break;
+ default:
+ break;
+ }
runOnUiThread(new Runnable() {
@Override
public void run() {
String message = "HEADSET_PLUG #" + mPlugCount
+ + ", USB_DEVICE_DE/ATTACHED #" + mUsbDeviceAttachedCount
+ ", mic = " + mPlugMicrophone
+ ", state = " + mPlugState;
mPlugTextView.setText(message);
@@ -78,6 +105,33 @@
}
});
}
+
+ private static final int AUDIO_STREAMING_SUB_CLASS = 2;
+
+ /**
+ * Figure out if an UsbDevice contains audio input/output streaming interface or not.
+ *
+ * @param device the given UsbDevice
+ * @param direction the direction of the audio streaming interface
+ * @return true if the UsbDevice contains the audio input/output streaming interface.
+ */
+ private boolean containsAudioStreamingInterface(UsbDevice device, int direction) {
+ final int interfaceCount = device.getInterfaceCount();
+ for (int i = 0; i < interfaceCount; ++i) {
+ UsbInterface usbInterface = device.getInterface(i);
+ if (usbInterface.getInterfaceClass() != UsbConstants.USB_CLASS_AUDIO
+ && usbInterface.getInterfaceSubclass() != AUDIO_STREAMING_SUB_CLASS) {
+ continue;
+ }
+ final int endpointCount = usbInterface.getEndpointCount();
+ for (int j = 0; j < endpointCount; ++j) {
+ if (usbInterface.getEndpoint(j).getDirection() == direction) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
@Override
@@ -152,6 +206,8 @@
public void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
+ filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+ filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
this.registerReceiver(mPluginReceiver, filter);
}
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_test_disconnect.xml b/apps/OboeTester/app/src/main/res/layout/activity_test_disconnect.xml
index c09bda0..345e820 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_test_disconnect.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_test_disconnect.xml
@@ -24,7 +24,7 @@
android:id="@+id/text_plug_events"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:lines="1"
+ android:lines="2"
android:text="plug #"
android:textSize="18sp"
android:textStyle="bold"