Notify the user when an unsupported accessory is attached
This CL pops up a notification to the user when the device does not
support Analog Type-C headphones but the user connects one.
i.e when the Usb port status reports currentMode=audio_acc, but
audio_acc is not present in the supportedModes list.
Bug: 36604276
Test: Manually test inserting an Audio accessory
Change-Id: If514b9f238da196a7157e1aacb6d7690fde66f21
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e633d66..9848485 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3155,6 +3155,11 @@
<string name="usb_accessory_notification_title">Connected to a USB accessory</string>
<!-- See USB_PREFERENCES. This is the message. -->
<string name="usb_notification_message">Tap for more options.</string>
+ <!-- USB_PREFERENCES: Notification for when a type-c USB audio accessory is attached but not supported. This is the title -->
+ <string name="usb_unsupported_audio_accessory_title">Audio accessory not supported</string>
+ <!-- Message of notification shown when a type-c USB audio accessory is attached but not supported. -->
+ <string name="usb_unsupported_audio_accessory_message">Tap for more info</string>
+
<!-- Title of notification shown when ADB is actively connected to the phone. -->
<string name="adb_active_notification_title">USB debugging connected</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bd70ca8..ca78efd 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1958,6 +1958,8 @@
<java-symbol type="string" name="usb_ptp_notification_title" />
<java-symbol type="string" name="usb_midi_notification_title" />
<java-symbol type="string" name="usb_supplying_notification_title" />
+ <java-symbol type="string" name="usb_unsupported_audio_accessory_title" />
+ <java-symbol type="string" name="usb_unsupported_audio_accessory_message" />
<java-symbol type="string" name="config_UsbDeviceConnectionHandling_component" />
<java-symbol type="string" name="vpn_text" />
<java-symbol type="string" name="vpn_text_long" />
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 53b3fe9..ac544e8 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -180,6 +180,9 @@
// Package: android
NOTE_FOREGROUND_SERVICES = 40;
+ // Inform the user that the connected audio accessory is not supported
+ NOTE_USB_AUDIO_ACCESSORY_NOT_SUPPORTED = 41;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 3b4fd04..84a2e8b 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -424,6 +424,8 @@
private boolean mSinkPower;
private boolean mConfigured;
private boolean mUsbDataUnlocked;
+ private boolean mAudioAccessoryConnected;
+ private boolean mAudioAccessorySupported;
private String mCurrentFunctions;
private boolean mCurrentFunctionsApplied;
private UsbAccessory mCurrentAccessory;
@@ -534,30 +536,13 @@
}
public void updateHostState(UsbPort port, UsbPortStatus status) {
- boolean hostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST;
- boolean sourcePower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE;
- boolean sinkPower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SINK;
- // Ideally we want to see if PR_SWAP and DR_SWAP is supported.
- // But, this should be suffice, since, all four combinations are only supported
- // when PR_SWAP and DR_SWAP are supported.
- boolean supportsAllCombinations = status.isRoleCombinationSupported(
- UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST)
- && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_HOST)
- && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE,
- UsbPort.DATA_ROLE_DEVICE)
- && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_HOST);
-
if (DEBUG) {
Slog.i(TAG, "updateHostState " + port + " status=" + status);
}
SomeArgs args = SomeArgs.obtain();
- args.argi1 = hostConnected ? 1 : 0;
- args.argi2 = sourcePower ? 1 : 0;
- args.argi3 = sinkPower ? 1 : 0;
- args.argi4 = supportsAllCombinations ? 1 : 0;
+ args.arg1 = port;
+ args.arg2 = status;
removeMessages(MSG_UPDATE_PORT_STATE);
Message msg = obtainMessage(MSG_UPDATE_PORT_STATE, args);
@@ -931,10 +916,26 @@
case MSG_UPDATE_PORT_STATE:
SomeArgs args = (SomeArgs) msg.obj;
boolean prevHostConnected = mHostConnected;
- mHostConnected = (args.argi1 == 1);
- mSourcePower = (args.argi2 == 1);
- mSinkPower = (args.argi3 == 1);
- mSupportsAllCombinations = (args.argi4 == 1);
+ UsbPort port = (UsbPort) args.arg1;
+ UsbPortStatus status = (UsbPortStatus) args.arg2;
+ mHostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST;
+ mSourcePower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE;
+ mSinkPower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SINK;
+ mAudioAccessoryConnected =
+ (status.getCurrentMode() == UsbPort.MODE_AUDIO_ACCESSORY);
+ mAudioAccessorySupported = port.isModeSupported(UsbPort.MODE_AUDIO_ACCESSORY);
+ // Ideally we want to see if PR_SWAP and DR_SWAP is supported.
+ // But, this should be suffice, since, all four combinations are only supported
+ // when PR_SWAP and DR_SWAP are supported.
+ mSupportsAllCombinations = status.isRoleCombinationSupported(
+ UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST)
+ && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK,
+ UsbPort.DATA_ROLE_HOST)
+ && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE,
+ UsbPort.DATA_ROLE_DEVICE)
+ && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK,
+ UsbPort.DATA_ROLE_HOST);
+
args.recycle();
updateUsbNotification(false);
if (mBootCompleted) {
@@ -1076,7 +1077,10 @@
int id = 0;
int titleRes = 0;
Resources r = mContext.getResources();
- if (mConnected) {
+ if (mAudioAccessoryConnected && !mAudioAccessorySupported) {
+ titleRes = com.android.internal.R.string.usb_unsupported_audio_accessory_title;
+ id = SystemMessage.NOTE_USB_AUDIO_ACCESSORY_NOT_SUPPORTED;
+ } else if (mConnected) {
if (!mUsbDataUnlocked) {
if (mSourcePower) {
titleRes = com.android.internal.R.string.usb_supplying_notification_title;
@@ -1123,18 +1127,43 @@
mUsbNotificationId = 0;
}
if (id != 0) {
- CharSequence message = r.getText(
- com.android.internal.R.string.usb_notification_message);
+ CharSequence message;
CharSequence title = r.getText(titleRes);
+ PendingIntent pi;
+ String channel;
- Intent intent = Intent.makeRestartActivityTask(
- new ComponentName("com.android.settings",
- "com.android.settings.deviceinfo.UsbModeChooserActivity"));
- PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
- intent, 0, null, UserHandle.CURRENT);
+ if (titleRes
+ != com.android.internal.R.string
+ .usb_unsupported_audio_accessory_title) {
+ Intent intent = Intent.makeRestartActivityTask(
+ new ComponentName("com.android.settings",
+ "com.android.settings.deviceinfo.UsbModeChooserActivity"));
+ pi = PendingIntent.getActivityAsUser(mContext, 0,
+ intent, 0, null, UserHandle.CURRENT);
+ channel = SystemNotificationChannels.USB;
+ message = r.getText(
+ com.android.internal.R.string.usb_notification_message);
+ } else {
+ final Intent intent = new Intent();
+ intent.setClassName("com.android.settings",
+ "com.android.settings.HelpTrampoline");
+ intent.putExtra(Intent.EXTRA_TEXT,
+ "help_url_audio_accessory_not_supported");
+
+ if (mContext.getPackageManager().resolveActivity(intent, 0) != null) {
+ pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+ } else {
+ pi = null;
+ }
+
+ channel = SystemNotificationChannels.ALERTS;
+ message = r.getText(
+ com.android.internal.R.string
+ .usb_unsupported_audio_accessory_message);
+ }
Notification notification =
- new Notification.Builder(mContext, SystemNotificationChannels.USB)
+ new Notification.Builder(mContext, channel)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
@@ -1148,6 +1177,7 @@
.setContentIntent(pi)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.build();
+
mNotificationManager.notifyAsUser(null, id, notification,
UserHandle.ALL);
mUsbNotificationId = id;
@@ -1230,6 +1260,8 @@
pw.println(" mSinkPower: " + mSinkPower);
pw.println(" mUsbCharging: " + mUsbCharging);
pw.println(" mHideUsbNotification: " + mHideUsbNotification);
+ pw.println(" mAudioAccessoryConnected: " + mAudioAccessoryConnected);
+
try {
pw.println(" Kernel state: "
+ FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());