Resolve BluetoothDevice hidden API usages by Settings

Bug: 143245666
Test: Manual
Change-Id: Id34eb275f604e61330aeb91401dc31aeca666b8f
This commit is contained in:
Rahul Sabnis
2019-12-04 16:09:44 -08:00
parent 0e3e2a73c6
commit d32a94d224
5 changed files with 91 additions and 106 deletions

View File

@@ -1343,15 +1343,24 @@ package android.bluetooth {
public final class BluetoothDevice implements android.os.Parcelable { public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
method public boolean cancelPairing();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getBatteryLevel();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getMessageAccessPermission();
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int); method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getPhonebookAccessPermission();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getSimAccessPermission();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isBondingInitiatedLocally();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setAlias(@NonNull String); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setAlias(@NonNull String);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMessageAccessPermission(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPin(@Nullable String);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSimAccessPermission(int);
field public static final int ACCESS_ALLOWED = 1; // 0x1 field public static final int ACCESS_ALLOWED = 1; // 0x1
field public static final int ACCESS_REJECTED = 2; // 0x2 field public static final int ACCESS_REJECTED = 2; // 0x2
field public static final int ACCESS_UNKNOWN = 0; // 0x0 field public static final int ACCESS_UNKNOWN = 0; // 0x0

View File

@@ -17,6 +17,7 @@
package android.bluetooth; package android.bluetooth;
import android.Manifest; import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
@@ -33,8 +34,12 @@ import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.UUID; import java.util.UUID;
/** /**
@@ -771,6 +776,13 @@ public final class BluetoothDevice implements Parcelable {
@UnsupportedAppUsage @UnsupportedAppUsage
public static final String EXTRA_SDP_SEARCH_STATUS = public static final String EXTRA_SDP_SEARCH_STATUS =
"android.bluetooth.device.extra.SDP_SEARCH_STATUS"; "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
/** @hide */
@IntDef(prefix = "ACCESS_", value = {ACCESS_UNKNOWN,
ACCESS_ALLOWED, ACCESS_REJECTED})
@Retention(RetentionPolicy.SOURCE)
public @interface AccessPermission{}
/** /**
* For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
* {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
@@ -1096,15 +1108,14 @@ public final class BluetoothDevice implements Parcelable {
/** /**
* Get the most recent identified battery level of this Bluetooth device * Get the most recent identified battery level of this Bluetooth device
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
* *
* @return Battery level in percents from 0 to 100, or {@link #BATTERY_LEVEL_UNKNOWN} if * @return Battery level in percents from 0 to 100, or {@link #BATTERY_LEVEL_UNKNOWN} if
* Bluetooth is disabled, or device is disconnected, or does not have any battery reporting * Bluetooth is disabled, or device is disconnected, or does not have any battery reporting
* service, or return value is invalid * service, or return value is invalid
* @hide * @hide
*/ */
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH) @RequiresPermission(Manifest.permission.BLUETOOTH)
@UnsupportedAppUsage
public int getBatteryLevel() { public int getBatteryLevel() {
final IBluetooth service = sService; final IBluetooth service = sService;
if (service == null) { if (service == null) {
@@ -1187,8 +1198,15 @@ public final class BluetoothDevice implements Parcelable {
return false; return false;
} }
/** @hide */ /**
@UnsupportedAppUsage * Gets whether bonding was initiated locally
*
* @return true if bonding is initiated locally, false otherwise
*
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
public boolean isBondingInitiatedLocally() { public boolean isBondingInitiatedLocally() {
final IBluetooth service = sService; final IBluetooth service = sService;
if (service == null) { if (service == null) {
@@ -1480,16 +1498,21 @@ public final class BluetoothDevice implements Parcelable {
return false; return false;
} }
/** @hide */ /**
@UnsupportedAppUsage * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
public boolean setPasskey(int passkey) { *
//TODO(BT) * @return true pin has been set false for error
/* * @hide
try { */
return sService.setPasskey(this, true, 4, passkey); @SystemApi
} catch (RemoteException e) {Log.e(TAG, "", e);}*/ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean setPin(@Nullable String pin) {
byte[] pinBytes = convertPinToBytes(pin);
if (pinBytes == null) {
return false; return false;
} }
return setPin(pinBytes);
}
/** /**
* Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing. * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
@@ -1511,22 +1534,18 @@ public final class BluetoothDevice implements Parcelable {
return false; return false;
} }
/** @hide */ /**
public boolean setRemoteOutOfBandData() { * Cancels pairing to this device
// TODO(BT) *
/* * @return true if pairing cancelled successfully, false otherwise
try { *
return sService.setRemoteOutOfBandData(this); * @hide
} catch (RemoteException e) {Log.e(TAG, "", e);}*/ */
return false; @SystemApi
} public boolean cancelPairing() {
/** @hide */
@UnsupportedAppUsage
public boolean cancelPairingUserInput() {
final IBluetooth service = sService; final IBluetooth service = sService;
if (service == null) { if (service == null) {
Log.e(TAG, "BT not enabled. Cannot create pairing user input"); Log.e(TAG, "BT not enabled. Cannot cancel pairing");
return false; return false;
} }
try { try {
@@ -1537,17 +1556,6 @@ public final class BluetoothDevice implements Parcelable {
return false; return false;
} }
/** @hide */
@UnsupportedAppUsage
public boolean isBluetoothDock() {
// TODO(BT)
/*
try {
return sService.isBluetoothDock(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}*/
return false;
}
boolean isBluetoothEnabled() { boolean isBluetoothEnabled() {
boolean ret = false; boolean ret = false;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -1558,13 +1566,14 @@ public final class BluetoothDevice implements Parcelable {
} }
/** /**
* Requires {@link android.Manifest.permission#BLUETOOTH}. * Gets whether the phonebook access is allowed for this bluetooth device
* *
* @return Whether the phonebook access is allowed to this device. Can be {@link * @return Whether the phonebook access is allowed to this device. Can be {@link
* #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
* @hide * @hide
*/ */
@UnsupportedAppUsage @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
public int getPhonebookAccessPermission() { public int getPhonebookAccessPermission() {
final IBluetooth service = sService; final IBluetooth service = sService;
if (service == null) { if (service == null) {
@@ -1667,14 +1676,14 @@ public final class BluetoothDevice implements Parcelable {
} }
/** /**
* Requires {@link android.Manifest.permission#BLUETOOTH}. * Gets whether message access is allowed to this bluetooth device
* *
* @return Whether the message access is allowed to this device. Can be {@link #ACCESS_UNKNOWN}, * @return Whether the message access is allowed to this device.
* {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
* @hide * @hide
*/ */
@UnsupportedAppUsage @SystemApi
public int getMessageAccessPermission() { @RequiresPermission(Manifest.permission.BLUETOOTH)
public @AccessPermission int getMessageAccessPermission() {
final IBluetooth service = sService; final IBluetooth service = sService;
if (service == null) { if (service == null) {
return ACCESS_UNKNOWN; return ACCESS_UNKNOWN;
@@ -1689,15 +1698,18 @@ public final class BluetoothDevice implements Parcelable {
/** /**
* Sets whether the message access is allowed to this device. * Sets whether the message access is allowed to this device.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
* *
* @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link * @param value is the value we are setting the message access permission to
* #ACCESS_REJECTED}.
* @return Whether the value has been successfully set. * @return Whether the value has been successfully set.
* @hide * @hide
*/ */
@UnsupportedAppUsage @SystemApi
public boolean setMessageAccessPermission(int value) { @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setMessageAccessPermission(@AccessPermission int value) {
// Validates param value is one of the accepted constants
if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) {
throw new IllegalArgumentException(value + "is not a valid AccessPermission value");
}
final IBluetooth service = sService; final IBluetooth service = sService;
if (service == null) { if (service == null) {
return false; return false;
@@ -1711,13 +1723,14 @@ public final class BluetoothDevice implements Parcelable {
} }
/** /**
* Requires {@link android.Manifest.permission#BLUETOOTH}. * Gets whether sim access is allowed for this bluetooth device
* *
* @return Whether the Sim access is allowed to this device. Can be {@link #ACCESS_UNKNOWN}, * @return Whether the Sim access is allowed to this device.
* {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
* @hide * @hide
*/ */
public int getSimAccessPermission() { @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
public @AccessPermission int getSimAccessPermission() {
final IBluetooth service = sService; final IBluetooth service = sService;
if (service == null) { if (service == null) {
return ACCESS_UNKNOWN; return ACCESS_UNKNOWN;
@@ -1732,14 +1745,14 @@ public final class BluetoothDevice implements Parcelable {
/** /**
* Sets whether the Sim access is allowed to this device. * Sets whether the Sim access is allowed to this device.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
* *
* @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
* #ACCESS_REJECTED}. * #ACCESS_REJECTED}.
* @return Whether the value has been successfully set. * @return Whether the value has been successfully set.
* @hide * @hide
*/ */
@UnsupportedAppUsage @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setSimAccessPermission(int value) { public boolean setSimAccessPermission(int value) {
final IBluetooth service = sService; final IBluetooth service = sService;
if (service == null) { if (service == null) {
@@ -1970,7 +1983,7 @@ public final class BluetoothDevice implements Parcelable {
* @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin. * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin.
* @hide * @hide
*/ */
@UnsupportedAppUsage @VisibleForTesting
public static byte[] convertPinToBytes(String pin) { public static byte[] convertPinToBytes(String pin) {
if (pin == null) { if (pin == null) {
return null; return null;

View File

@@ -176,14 +176,12 @@ public class BluetoothTestUtils extends Assert {
mDevice.setPin(mPin); mDevice.setPin(mPin);
break; break;
case BluetoothDevice.PAIRING_VARIANT_PASSKEY: case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
mDevice.setPasskey(mPasskey);
break; break;
case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION: case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
case BluetoothDevice.PAIRING_VARIANT_CONSENT: case BluetoothDevice.PAIRING_VARIANT_CONSENT:
mDevice.setPairingConfirmation(true); mDevice.setPairingConfirmation(true);
break; break;
case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT: case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
mDevice.setRemoteOutOfBandData();
break; break;
} }
} else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) { } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {

View File

@@ -645,14 +645,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
refresh(); refresh();
if (bondState == BluetoothDevice.BOND_BONDED) { if (bondState == BluetoothDevice.BOND_BONDED && mDevice.isBondingInitiatedLocally()) {
if (mDevice.isBluetoothDock()) {
onBondingDockConnect();
} else if (mDevice.isBondingInitiatedLocally()) {
connect(false); connect(false);
} }
} }
}
public BluetoothClass getBtClass() { public BluetoothClass getBtClass() {
return mDevice.getBluetoothClass(); return mDevice.getBluetoothClass();

View File

@@ -62,9 +62,6 @@ public class AudioDeviceInventory {
private @NonNull AudioDeviceBroker mDeviceBroker; private @NonNull AudioDeviceBroker mDeviceBroker;
// cache of the address of the last dock the device was connected to
private String mDockAddress;
// Monitoring of audio routes. Protected by mAudioRoutes. // Monitoring of audio routes. Protected by mAudioRoutes.
final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo(); final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers = final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers =
@@ -168,7 +165,7 @@ public class AudioDeviceInventory {
int a2dpVolume = btInfo.getVolume(); int a2dpVolume = btInfo.getVolume();
if (AudioService.DEBUG_DEVICES) { if (AudioService.DEBUG_DEVICES) {
Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state=" Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state="
+ state + " is dock=" + btDevice.isBluetoothDock() + " vol=" + a2dpVolume); + state + " vol=" + a2dpVolume);
} }
String address = btDevice.getAddress(); String address = btDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) { if (!BluetoothAdapter.checkBluetoothAddress(address)) {
@@ -195,34 +192,10 @@ public class AudioDeviceInventory {
if (a2dpCodec != di.mDeviceCodecFormat) { if (a2dpCodec != di.mDeviceCodecFormat) {
mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice); mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice);
} }
} else {
if (btDevice.isBluetoothDock()) {
if (state == BluetoothProfile.STATE_DISCONNECTED) {
// introduction of a delay for transient disconnections of docks when
// power is rapidly turned off/on, this message will be canceled if
// we reconnect the dock under a preset delay
makeA2dpDeviceUnavailableLater(address,
AudioDeviceBroker.BTA2DP_DOCK_TIMEOUT_MS);
// the next time isConnected is evaluated, it will be false for the dock
}
} else { } else {
makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat); makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
} }
} }
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
if (btDevice.isBluetoothDock()) {
// this could be a reconnection after a transient disconnection
mDeviceBroker.cancelA2dpDockTimeout();
mDockAddress = address;
} else {
// this could be a connection of another A2DP device before the timeout of
// a dock: cancel the dock timeout, and make the dock unavailable now
if (mDeviceBroker.hasScheduledA2dpDockTimeout() && mDockAddress != null) {
mDeviceBroker.cancelA2dpDockTimeout();
makeA2dpDeviceUnavailableNow(mDockAddress,
AudioSystem.AUDIO_FORMAT_DEFAULT);
}
}
if (a2dpVolume != -1) { if (a2dpVolume != -1) {
mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC, mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
// convert index to internal representation in VolumeStreamState // convert index to internal representation in VolumeStreamState
@@ -233,7 +206,6 @@ public class AudioDeviceInventory {
"onSetA2dpSinkConnectionState", a2dpCodec); "onSetA2dpSinkConnectionState", a2dpCodec);
} }
} }
}
/*package*/ void onSetA2dpSourceConnectionState( /*package*/ void onSetA2dpSourceConnectionState(
@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int state) { @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int state) {
@@ -672,9 +644,6 @@ public class AudioDeviceInventory {
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address)); DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
// Remove A2DP routes as well // Remove A2DP routes as well
setCurrentAudioRouteNameIfPossible(null); setCurrentAudioRouteNameIfPossible(null);
if (mDockAddress == address) {
mDockAddress = null;
}
} }
@GuardedBy("mConnectedDevices") @GuardedBy("mConnectedDevices")