diff options
author | Paul McLean <pmclean@google.com> | 2019-09-23 08:28:41 -0600 |
---|---|---|
committer | Paul McLean <pmclean@google.com> | 2019-10-03 11:54:05 -0600 |
commit | d33645321723b04823ba03c4ce1d10b0ef56e6a5 (patch) | |
tree | 16160bef3a1f823fc27ccc423b7f39bd75001c03 | |
parent | 4252183449824d77f5c4035e8c12bf504619a5b1 (diff) |
Adding additional prompt to UsbPermissionsDialg for audio devices.
To support, adding members to UsbDevice to mark devices as having audio
playback and audio capture capabilities.
Bug: 136080195
Test: Run "UsbAccess" test bed. Connect audio and non-audio USB devices
and see the additional prompt shown/not-shown.
Change-Id: Ie7c614d9ed30a163c350b18a54b8a9115698779d
6 files changed, 101 insertions, 24 deletions
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java index 08c9eea6e012..43336682e45f 100644 --- a/core/java/android/hardware/usb/UsbDevice.java +++ b/core/java/android/hardware/usb/UsbDevice.java @@ -60,6 +60,9 @@ public class UsbDevice implements Parcelable { private final int mClass; private final int mSubclass; private final int mProtocol; + private final boolean mHasAudioPlayback; + private final boolean mHasAudioCapture; + /** All interfaces on the device. Initialized on first call to getInterfaceList */ @UnsupportedAppUsage @@ -73,7 +76,8 @@ public class UsbDevice implements Parcelable { private UsbDevice(@NonNull String name, int vendorId, int productId, int Class, int subClass, int protocol, @Nullable String manufacturerName, @Nullable String productName, @NonNull String version, @NonNull UsbConfiguration[] configurations, - @NonNull IUsbSerialReader serialNumberReader) { + @NonNull IUsbSerialReader serialNumberReader, + boolean hasAudioPlayback, boolean hasAudioCapture) { mName = Preconditions.checkNotNull(name); mVendorId = vendorId; mProductId = productId; @@ -85,6 +89,8 @@ public class UsbDevice implements Parcelable { mVersion = Preconditions.checkStringNotEmpty(version); mConfigurations = Preconditions.checkArrayElementsNotNull(configurations, "configurations"); mSerialNumberReader = Preconditions.checkNotNull(serialNumberReader); + mHasAudioPlayback = hasAudioPlayback; + mHasAudioCapture = hasAudioCapture; // Make sure the binder belongs to the system if (ActivityThread.isSystem()) { @@ -214,6 +220,16 @@ public class UsbDevice implements Parcelable { return mConfigurations.length; } + /** @hide */ + public boolean getHasAudioPlayback() { + return mHasAudioPlayback; + } + + /** @hide */ + public boolean getHasAudioCapture() { + return mHasAudioCapture; + } + /** * Returns the {@link UsbConfiguration} at the given index. * @@ -286,12 +302,14 @@ public class UsbDevice implements Parcelable { @Override public String toString() { - StringBuilder builder = new StringBuilder("UsbDevice[mName=" + mName + - ",mVendorId=" + mVendorId + ",mProductId=" + mProductId + - ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + - ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName + - ",mVersion=" + mVersion + ",mSerialNumberReader=" + mSerialNumberReader - + ",mConfigurations=["); + StringBuilder builder = new StringBuilder("UsbDevice[mName=" + mName + + ",mVendorId=" + mVendorId + ",mProductId=" + mProductId + + ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + + ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName + + ",mVersion=" + mVersion + ",mSerialNumberReader=" + mSerialNumberReader + + ", mHasAudioPlayback=" + mHasAudioPlayback + + ", mHasAudioCapture=" + mHasAudioCapture + + ", mConfigurations=["); for (int i = 0; i < mConfigurations.length; i++) { builder.append("\n"); builder.append(mConfigurations[i].toString()); @@ -316,9 +334,13 @@ public class UsbDevice implements Parcelable { IUsbSerialReader.Stub.asInterface(in.readStrongBinder()); UsbConfiguration[] configurations = in.readParcelableArray( UsbConfiguration.class.getClassLoader(), UsbConfiguration.class); + // Capabilities + boolean hasAudioPlayback = in.readInt() == 1; + boolean hasAudioCapture = in.readInt() == 1; UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, - manufacturerName, productName, version, configurations, - serialNumberReader); + manufacturerName, productName, version, configurations, serialNumberReader, + hasAudioPlayback, hasAudioCapture); + return device; } @@ -343,6 +365,8 @@ public class UsbDevice implements Parcelable { parcel.writeString(mVersion); parcel.writeStrongBinder(mSerialNumberReader.asBinder()); parcel.writeParcelableArray(mConfigurations, 0); + parcel.writeInt(mHasAudioPlayback ? 1 : 0); + parcel.writeInt(mHasAudioCapture ? 1 : 0); } public static int getDeviceId(String name) { @@ -370,6 +394,8 @@ public class UsbDevice implements Parcelable { private final @Nullable String mProductName; private final @NonNull String mVersion; private final @NonNull UsbConfiguration[] mConfigurations; + private final boolean mHasAudioPlayback; + private final boolean mHasAudioCapture; // Temporary storage for serial number. Serial number reader need to be wrapped in a // IUsbSerialReader as they might be used as PII. @@ -378,7 +404,8 @@ public class UsbDevice implements Parcelable { public Builder(@NonNull String name, int vendorId, int productId, int Class, int subClass, int protocol, @Nullable String manufacturerName, @Nullable String productName, @NonNull String version, @NonNull UsbConfiguration[] configurations, - @Nullable String serialNumber) { + @Nullable String serialNumber, + boolean hasAudioPlayback, boolean hasAudioCapture) { mName = Preconditions.checkNotNull(name); mVendorId = vendorId; mProductId = productId; @@ -390,6 +417,8 @@ public class UsbDevice implements Parcelable { mVersion = Preconditions.checkStringNotEmpty(version); mConfigurations = configurations; this.serialNumber = serialNumber; + mHasAudioPlayback = hasAudioPlayback; + mHasAudioCapture = hasAudioCapture; } /** @@ -401,7 +430,8 @@ public class UsbDevice implements Parcelable { */ public UsbDevice build(@NonNull IUsbSerialReader serialReader) { return new UsbDevice(mName, mVendorId, mProductId, mClass, mSubclass, mProtocol, - mManufacturerName, mProductName, mVersion, mConfigurations, serialReader); + mManufacturerName, mProductName, mVersion, mConfigurations, serialReader, + mHasAudioPlayback, mHasAudioCapture); } } } diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 97e2f0f6562b..0be84eec7149 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -118,10 +118,13 @@ <string name="status_bar_use_physical_keyboard">Physical keyboard</string> <!-- Prompt for the USB device permission dialog [CHAR LIMIT=80] --> - <string name="usb_device_permission_prompt">Allow <xliff:g id="application">%1$s</xliff:g> to access <xliff:g id="usb_device">%2$s</xliff:g>?</string> + <string name="usb_device_permission_prompt">Allow <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to access <xliff:g id="usb_device" example="USB Headphones">%2$s</xliff:g>?</string> + + <!-- Checkbox label for USB device dialogs with warning text for USB device dialogs. [CHAR LIMIT=200]--> + <string name="usb_device_permission_prompt_warn">Allow <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to access <xliff:g id="usb_device" example="USB Headphones">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device.</string> <!-- Prompt for the USB accessory permission dialog [CHAR LIMIT=80] --> - <string name="usb_accessory_permission_prompt">Allow <xliff:g id="application">%1$s</xliff:g> to access <xliff:g id="usb_accessory">%2$s</xliff:g>?</string> + <string name="usb_accessory_permission_prompt">Allow <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to access <xliff:g id="usb_accessory" example="USB Dock">%2$s</xliff:g>?</string> <!-- Prompt for the USB device confirm dialog [CHAR LIMIT=80] --> <string name="usb_device_confirm_prompt">Open <xliff:g id="application">%1$s</xliff:g> to handle <xliff:g id="usb_device">%2$s</xliff:g>?</string> diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java index a46f018af816..cd1f0cc13297 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java @@ -21,6 +21,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.PermissionChecker; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.hardware.usb.IUsbManager; @@ -84,14 +85,27 @@ public class UsbPermissionActivity extends AlertActivity final AlertController.AlertParams ap = mAlertParams; ap.mTitle = appName; if (mDevice == null) { + // Accessory Case + ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName, mAccessory.getDescription()); mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory); } else { - ap.mMessage = getString(R.string.usb_device_permission_prompt, appName, - mDevice.getProductName()); + boolean hasRecordPermission = + PermissionChecker.checkPermission( + this, android.Manifest.permission.RECORD_AUDIO, -1, aInfo.uid, + mPackageName) + == android.content.pm.PackageManager.PERMISSION_GRANTED; + boolean isAudioCaptureDevice = mDevice.getHasAudioCapture(); + boolean useRecordWarning = isAudioCaptureDevice && !hasRecordPermission; + + int strID = useRecordWarning + ? R.string.usb_device_permission_prompt_warn + : R.string.usb_device_permission_prompt; + ap.mMessage = getString(strID, appName, mDevice.getProductName()); mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice); } + ap.mPositiveButtonText = getString(android.R.string.ok); ap.mNegativeButtonText = getString(android.R.string.cancel); ap.mPositiveButtonListener = this; diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index e899dff5e5a2..047fcecd5a5b 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -386,7 +386,7 @@ public class UsbHostManager { return false; } - UsbDevice.Builder newDeviceBuilder = parser.toAndroidUsbDevice(); + UsbDevice.Builder newDeviceBuilder = parser.toAndroidUsbDeviceBuilder(); if (newDeviceBuilder == null) { Slog.e(TAG, "Couldn't create UsbDevice object."); // Tracking diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java index 6ffbd43a7b1a..8e7babb40fc0 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -309,17 +309,17 @@ public final class UsbDescriptorParser { /** * @hide */ - public UsbDevice.Builder toAndroidUsbDevice() { + public UsbDevice.Builder toAndroidUsbDeviceBuilder() { if (mDeviceDescriptor == null) { Log.e(TAG, "toAndroidUsbDevice() ERROR - No Device Descriptor"); return null; } - UsbDevice.Builder device = mDeviceDescriptor.toAndroid(this); - if (device == null) { + UsbDevice.Builder builder = mDeviceDescriptor.toAndroid(this); + if (builder == null) { Log.e(TAG, "toAndroidUsbDevice() ERROR Creating Device"); } - return device; + return builder; } /** @@ -524,6 +524,37 @@ public final class UsbDescriptorParser { /** * @hide */ + public boolean hasAudioTerminal(int subType) { + for (UsbDescriptor descriptor : mDescriptors) { + if (descriptor instanceof UsbACInterface) { + if (((UsbACInterface) descriptor).getSubclass() + == UsbDescriptor.AUDIO_AUDIOCONTROL + && ((UsbACInterface) descriptor).getSubtype() + == subType) { + return true; + } + } + } + return false; + } + + /** + * @hide + */ + public boolean hasAudioPlayback() { + return hasAudioTerminal(UsbACInterface.ACI_OUTPUT_TERMINAL); + } + + /** + * @hide + */ + public boolean hasAudioCapture() { + return hasAudioTerminal(UsbACInterface.ACI_INPUT_TERMINAL); + } + + /** + * @hide + */ public boolean hasHIDInterface() { ArrayList<UsbDescriptor> descriptors = getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_HID); diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java index e6e10fef9f9a..9735502a4f69 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java @@ -156,11 +156,10 @@ public final class UsbDeviceDescriptor extends UsbDescriptor { for (int index = 0; index < mConfigDescriptors.size(); index++) { configs[index] = mConfigDescriptors.get(index).toAndroid(parser); } - UsbDevice.Builder device = new UsbDevice.Builder(parser.getDeviceAddr(), mVendorID, - mProductID, mDevClass, mDevSubClass, mProtocol, mfgName, prodName, versionString, - configs, serialStr); - return device; + return new UsbDevice.Builder(parser.getDeviceAddr(), mVendorID, + mProductID, mDevClass, mDevSubClass, mProtocol, mfgName, prodName, versionString, + configs, serialStr, parser.hasAudioPlayback(), parser.hasAudioCapture()); } @Override |