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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,6 +521,37 @@ public final class UsbDescriptorParser {
|
||||
return !descriptors.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user