[framework] Migration of hidden APIs to System APIs

Bug: 199827901
Tag: #compatibility
Test: IOP, BCST, GTS
Merged-In: Ib0a205bc575e4cc3cf97eac539cd303acd878134
Change-Id: Ib0a205bc575e4cc3cf97eac539cd303acd878134
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 10f17d4..1f928c1 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -51,6 +51,7 @@
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void generateLocalOobData(int, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OobDataCallback);
     method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getActiveDevices(int);
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public long getDiscoveryEndMillis();
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<java.lang.Integer> getSupportedProfiles();
     method public boolean isBleScanAlwaysAvailable();
     method public boolean isLeEnabled();
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean removeActiveDevice(int);
@@ -146,8 +147,10 @@
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean connect(android.bluetooth.BluetoothDevice);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getAudioRouteAllowed();
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInbandRingingEnabled();
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int setAudioRouteAllowed(boolean);
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean startScoUsingVirtualVoiceCall();
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean stopScoUsingVirtualVoiceCall();
@@ -253,7 +256,10 @@
   }
 
   public final class BluetoothStatusCodes {
+    field public static final int ALLOWED = 400; // 0x190
     field public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000; // 0x3e8
+    field public static final int ERROR_TIMEOUT = 15; // 0xf
+    field public static final int NOT_ALLOWED = 401; // 0x191
   }
 
   public final class BluetoothUuid {
diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java
index 385755a..f420b94 100644
--- a/framework/java/android/bluetooth/BluetoothAdapter.java
+++ b/framework/java/android/bluetooth/BluetoothAdapter.java
@@ -2571,14 +2571,20 @@
      * BluetoothProfile}.
      * @hide
      */
-    @RequiresNoPermission
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
     public @NonNull List<Integer> getSupportedProfiles() {
         final ArrayList<Integer> supportedProfiles = new ArrayList<Integer>();
 
         try {
             synchronized (mManagerCallback) {
                 if (mService != null) {
-                    final long supportedProfilesBitMask = mService.getSupportedProfiles();
+                    final long supportedProfilesBitMask =
+                            mService.getSupportedProfiles(mAttributionSource);
 
                     for (int i = 0; i <= BluetoothProfile.MAX_PROFILE_ID; i++) {
                         if ((supportedProfilesBitMask & (1 << i)) != 0) {
@@ -2594,6 +2600,7 @@
             }
         } catch (RemoteException e) {
             Log.e(TAG, "getSupportedProfiles:", e);
+            e.rethrowFromSystemServer();
         }
         return supportedProfiles;
     }
diff --git a/framework/java/android/bluetooth/BluetoothHeadset.java b/framework/java/android/bluetooth/BluetoothHeadset.java
index 750e3a8..fcab7b7 100644
--- a/framework/java/android/bluetooth/BluetoothHeadset.java
+++ b/framework/java/android/bluetooth/BluetoothHeadset.java
@@ -18,6 +18,7 @@
 
 import static android.bluetooth.BluetoothUtils.getSyncTimeout;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -44,6 +45,8 @@
 
 import com.android.modules.utils.SynchronousResultReceiver;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
@@ -940,60 +943,99 @@
         return defaultValue;
     }
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            BluetoothStatusCodes.SUCCESS,
+            BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
+            BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
+            BluetoothStatusCodes.ERROR_TIMEOUT,
+            BluetoothStatusCodes.ALLOWED,
+            BluetoothStatusCodes.NOT_ALLOWED,
+    })
+    public @interface AudioRouteAllowedReturnValues {}
+
     /**
-     * Sets whether audio routing is allowed. When set to {@code false}, the AG will not route any
-     * audio to the HF unless explicitly told to.
-     * This method should be used in cases where the SCO channel is shared between multiple profiles
-     * and must be delegated by a source knowledgeable
-     * Note: This is an internal function and shouldn't be exposed
+     * Sets whether audio routing is allowed. When set to {@code false}, the AG
+     * will not route any audio to the HF unless explicitly told to. This method
+     * should be used in cases where the SCO channel is shared between multiple
+     * profiles and must be delegated by a source knowledgeable.
      *
-     * @param allowed {@code true} if the profile can reroute audio, {@code false} otherwise.
+     * @param allowed {@code true} if the profile can reroute audio,
+     * {@code false} otherwise.
+     * @return {@link BluetoothStatusCodes#SUCCESS} upon successful setting,
+     * otherwise an error code.
+     *
      * @hide
      */
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
-    public void setAudioRouteAllowed(boolean allowed) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @AudioRouteAllowedReturnValues int setAudioRouteAllowed(boolean allowed) {
         if (VDBG) log("setAudioRouteAllowed");
         final IBluetoothHeadset service = mService;
         if (service == null) {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) log(Log.getStackTraceString(new Throwable()));
-        } else if (isEnabled()) {
-            try {
-                final SynchronousResultReceiver recv = new SynchronousResultReceiver();
-                service.setAudioRouteAllowed(allowed, mAttributionSource, recv);
-                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
-            } catch (RemoteException | TimeoutException e) {
-                Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
-            }
+            return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
+        } else if (!isEnabled()) {
+            return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
         }
+        try {
+            final SynchronousResultReceiver recv = new SynchronousResultReceiver();
+            service.setAudioRouteAllowed(allowed, mAttributionSource, recv);
+            recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
+            return BluetoothStatusCodes.SUCCESS;
+        } catch (TimeoutException e) {
+            Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+            return BluetoothStatusCodes.ERROR_TIMEOUT;
+        } catch (RemoteException e) {
+            Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+            e.rethrowFromSystemServer();
+        }
+        return BluetoothStatusCodes.ERROR_UNKNOWN;
     }
 
     /**
-     * Returns whether audio routing is allowed. see {@link #setAudioRouteAllowed(boolean)}.
-     * Note: This is an internal function and shouldn't be exposed
+     * @return {@link BluetoothStatusCodes#ALLOWED} if audio routing is allowed,
+     * {@link BluetoothStatusCodes#NOT_ALLOWED} if audio routing is not allowed, or
+     * an error code if an error occurs.
+     * see {@link #setAudioRouteAllowed(boolean)}.
      *
      * @hide
      */
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
-    public boolean getAudioRouteAllowed() {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @AudioRouteAllowedReturnValues int getAudioRouteAllowed() {
         if (VDBG) log("getAudioRouteAllowed");
         final IBluetoothHeadset service = mService;
-        final boolean defaultValue = false;
         if (service == null) {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) log(Log.getStackTraceString(new Throwable()));
-        } else if (isEnabled()) {
-            try {
-                final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
-                service.getAudioRouteAllowed(mAttributionSource, recv);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
-            } catch (RemoteException | TimeoutException e) {
-                Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
-            }
+            return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
+        } else if (!isEnabled()) {
+            return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
         }
-        return defaultValue;
+        try {
+            final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
+            service.getAudioRouteAllowed(mAttributionSource, recv);
+            return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false)
+                    ? BluetoothStatusCodes.ALLOWED : BluetoothStatusCodes.NOT_ALLOWED;
+        } catch (TimeoutException e) {
+            Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+            return BluetoothStatusCodes.ERROR_TIMEOUT;
+        } catch (RemoteException e) {
+            Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+            e.rethrowFromSystemServer();
+        }
+        return BluetoothStatusCodes.ERROR_UNKNOWN;
     }
 
     /**
diff --git a/framework/java/android/bluetooth/BluetoothStatusCodes.java b/framework/java/android/bluetooth/BluetoothStatusCodes.java
index 9dafa07..c6f6cde 100644
--- a/framework/java/android/bluetooth/BluetoothStatusCodes.java
+++ b/framework/java/android/bluetooth/BluetoothStatusCodes.java
@@ -96,6 +96,14 @@
     public static final int ERROR_FEATURE_NOT_SUPPORTED = 10;
 
     /**
+     * Error code indicating that the requested operation timed out.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_TIMEOUT = 15;
+
+    /**
      * A GATT writeCharacteristic request is not permitted on the remote device.
      */
     public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101;
@@ -106,6 +114,22 @@
     public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102;
 
     /**
+     * Indicates that the operation is allowed.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ALLOWED = 400;
+
+    /**
+     * Indicates that the operation is not allowed.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int NOT_ALLOWED = 401;
+
+    /**
      * If another application has already requested {@link OobData} then another fetch will be
      * disallowed until the callback is removed.
      *