Merge "Resolve BluetoothDevice hidden API usages by Settings"
am: ce656f7754

Change-Id: I6c9af91fa6338246a872318038dad699c5c3fe04
diff --git a/api/system-current.txt b/api/system-current.txt
index ebfd55e..315103ab 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1343,15 +1343,24 @@
 
   public final class BluetoothDevice implements android.os.Parcelable {
     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 @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 isEncrypted();
     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) 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 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 setSimAccessPermission(int);
     field public static final int ACCESS_ALLOWED = 1; // 0x1
     field public static final int ACCESS_REJECTED = 2; // 0x2
     field public static final int ACCESS_UNKNOWN = 0; // 0x0
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 49187dc..323c7d1 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -17,6 +17,7 @@
 package android.bluetooth;
 
 import android.Manifest;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -33,8 +34,12 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.UUID;
 
 /**
@@ -771,6 +776,13 @@
     @UnsupportedAppUsage
     public static final String 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},
      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
@@ -1096,15 +1108,14 @@
 
     /**
      * 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
      * Bluetooth is disabled, or device is disconnected, or does not have any battery reporting
      * service, or return value is invalid
      * @hide
      */
+    @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    @UnsupportedAppUsage
     public int getBatteryLevel() {
         final IBluetooth service = sService;
         if (service == null) {
@@ -1187,8 +1198,15 @@
         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() {
         final IBluetooth service = sService;
         if (service == null) {
@@ -1480,15 +1498,20 @@
         return false;
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
-    public boolean setPasskey(int passkey) {
-        //TODO(BT)
-        /*
-        try {
-            return sService.setPasskey(this, true, 4, passkey);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}*/
-        return false;
+    /**
+     * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
+     *
+     * @return true pin has been set false for error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setPin(@Nullable String pin) {
+        byte[] pinBytes = convertPinToBytes(pin);
+        if (pinBytes == null) {
+            return false;
+        }
+        return setPin(pinBytes);
     }
 
     /**
@@ -1511,22 +1534,18 @@
         return false;
     }
 
-    /** @hide */
-    public boolean setRemoteOutOfBandData() {
-        // TODO(BT)
-        /*
-        try {
-          return sService.setRemoteOutOfBandData(this);
-      } catch (RemoteException e) {Log.e(TAG, "", e);}*/
-        return false;
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage
-    public boolean cancelPairingUserInput() {
+    /**
+     * Cancels pairing to this device
+     *
+     * @return true if pairing cancelled successfully, false otherwise
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean cancelPairing() {
         final IBluetooth service = sService;
         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;
         }
         try {
@@ -1537,17 +1556,6 @@
         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 ret = false;
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -1558,13 +1566,14 @@
     }
 
     /**
-     * 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
      * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public int getPhonebookAccessPermission() {
         final IBluetooth service = sService;
         if (service == null) {
@@ -1667,14 +1676,14 @@
     }
 
     /**
-     * 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},
-     * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
+     * @return Whether the message access is allowed to this device.
      * @hide
      */
-    @UnsupportedAppUsage
-    public int getMessageAccessPermission() {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public @AccessPermission int getMessageAccessPermission() {
         final IBluetooth service = sService;
         if (service == null) {
             return ACCESS_UNKNOWN;
@@ -1689,15 +1698,18 @@
 
     /**
      * 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
-     * #ACCESS_REJECTED}.
+     * @param value is the value we are setting the message access permission to
      * @return Whether the value has been successfully set.
      * @hide
      */
-    @UnsupportedAppUsage
-    public boolean setMessageAccessPermission(int value) {
+    @SystemApi
+    @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;
         if (service == null) {
             return false;
@@ -1711,13 +1723,14 @@
     }
 
     /**
-     * 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},
-     * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
+     * @return Whether the Sim access is allowed to this device.
      * @hide
      */
-    public int getSimAccessPermission() {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public @AccessPermission int getSimAccessPermission() {
         final IBluetooth service = sService;
         if (service == null) {
             return ACCESS_UNKNOWN;
@@ -1732,14 +1745,14 @@
 
     /**
      * 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
      * #ACCESS_REJECTED}.
      * @return Whether the value has been successfully set.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
     public boolean setSimAccessPermission(int value) {
         final IBluetooth service = sService;
         if (service == null) {
@@ -1970,7 +1983,7 @@
      * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin.
      * @hide
      */
-    @UnsupportedAppUsage
+    @VisibleForTesting
     public static byte[] convertPinToBytes(String pin) {
         if (pin == null) {
             return null;
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
index b906d84..ed613c3 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
@@ -176,14 +176,12 @@
                         mDevice.setPin(mPin);
                         break;
                     case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
-                        mDevice.setPasskey(mPasskey);
                         break;
                     case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
                     case BluetoothDevice.PAIRING_VARIANT_CONSENT:
                         mDevice.setPairingConfirmation(true);
                         break;
                     case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
-                        mDevice.setRemoteOutOfBandData();
                         break;
                 }
             } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index c1b89e6..abfee1d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -643,12 +643,8 @@
 
         refresh();
 
-        if (bondState == BluetoothDevice.BOND_BONDED) {
-            if (mDevice.isBluetoothDock()) {
-                onBondingDockConnect();
-            } else if (mDevice.isBondingInitiatedLocally()) {
-                connect(false);
-            }
+        if (bondState == BluetoothDevice.BOND_BONDED && mDevice.isBondingInitiatedLocally()) {
+            connect(false);
         }
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 37add3d..135f199d 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -62,9 +62,6 @@
 
     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.
     final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
     final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers =
@@ -168,7 +165,7 @@
         int a2dpVolume = btInfo.getVolume();
         if (AudioService.DEBUG_DEVICES) {
             Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state="
-                    + state + " is dock=" + btDevice.isBluetoothDock() + " vol=" + a2dpVolume);
+                    + state + " vol=" + a2dpVolume);
         }
         String address = btDevice.getAddress();
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
@@ -196,42 +193,17 @@
                         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 {
-                        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) {
-                    mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
-                            // convert index to internal representation in VolumeStreamState
-                            a2dpVolume * 10,
-                            AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
-                }
-                makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
-                        "onSetA2dpSinkConnectionState", a2dpCodec);
             }
+            if (a2dpVolume != -1) {
+                mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
+                        // convert index to internal representation in VolumeStreamState
+                        a2dpVolume * 10,
+                        AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
+            }
+            makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
+                    "onSetA2dpSinkConnectionState", a2dpCodec);
         }
     }
 
@@ -672,9 +644,6 @@
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         // Remove A2DP routes as well
         setCurrentAudioRouteNameIfPossible(null);
-        if (mDockAddress == address) {
-            mDockAddress = null;
-        }
     }
 
     @GuardedBy("mConnectedDevices")