SpatialAudio: Add API to switch buffer size

Bug: 214615268
Test: Manually test signal passing from bluetooth/system to framework
Tag: #feature
Change-Id: Ie556c1d271b54834f360cf64249385fe44011181
diff --git a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
index 5e3a297..e8e2643 100644
--- a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -71,6 +71,7 @@
 static jmethodID method_aclStateChangeCallback;
 static jmethodID method_discoveryStateChangeCallback;
 static jmethodID method_linkQualityReportCallback;
+static jmethodID method_switchBufferSizeCallback;
 static jmethodID method_setWakeAlarm;
 static jmethodID method_acquireWakeLock;
 static jmethodID method_releaseWakeLock;
@@ -598,6 +599,34 @@
       (jint)negative_acknowledgement_count);
 }
 
+static void switch_buffer_size_callback(RawAddress* bd_addr,
+                                        bool is_low_latency_buffer_size) {
+
+  if (!bd_addr) {
+    ALOGE("Address is null in %s", __func__);
+    return;
+  }
+  CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid()) return;
+
+  ScopedLocalRef<jbyteArray> addr(
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
+  if (!addr.get()) {
+    ALOGE("Error while allocating in: %s", __func__);
+    return;
+  }
+
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
+                                 (jbyte*)bd_addr);
+
+  ALOGV("%s: SwitchBufferSizeCallback: %s", __func__,
+        is_low_latency_buffer_size ? "true" : "false");
+
+  sCallbackEnv->CallVoidMethod(
+      sJniCallbacksObj, method_switchBufferSizeCallback, addr.get(),
+      (jboolean)is_low_latency_buffer_size);
+}
+
 static void callback_thread_event(bt_cb_thread_evt event) {
   if (event == ASSOCIATE_JVM) {
     JavaVMAttachArgs args;
@@ -674,7 +703,8 @@
                                              le_test_mode_recv_callback,
                                              energy_info_recv_callback,
                                              link_quality_report_callback,
-                                             generate_local_oob_data_callback};
+                                             generate_local_oob_data_callback,
+                                             switch_buffer_size_callback};
 
 // The callback to call when the wake alarm fires.
 static alarm_cb sAlarmCallback;
@@ -893,6 +923,9 @@
   method_linkQualityReportCallback = env->GetMethodID(
       jniCallbackClass, "linkQualityReportCallback", "(JIIIIII)V");
 
+  method_switchBufferSizeCallback =
+      env->GetMethodID(jniCallbackClass, "switchBufferSizeCallback", "([BZ)V");
+
   method_setWakeAlarm = env->GetMethodID(clazz, "setWakeAlarm", "(JZ)Z");
   method_acquireWakeLock =
       env->GetMethodID(clazz, "acquireWakeLock", "(Ljava/lang/String;)Z");
diff --git a/android/app/res/values/config.xml b/android/app/res/values/config.xml
index 4653c91..1f86bc3 100644
--- a/android/app/res/values/config.xml
+++ b/android/app/res/values/config.xml
@@ -145,4 +145,10 @@
      -->
     <bool name="enable_gd_up_to_scanning_layer">true</bool>
 
+    <!-- Package of fastpair service -->
+    <string name="peripheral_link_package">com.google.android.gms</string>
+    <!-- Service name of fastpair-->
+    <string name="peripheral_link_service">.nearby.discovery.service.DiscoveryService</string>
+
+
 </resources>
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
index a206b7a..58faee2 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
@@ -811,6 +811,20 @@
         }
     }
 
+    void switchBufferSizeCallback(byte[] address, boolean isLowLatencyBufferSize) {
+        BluetoothDevice device = getDeviceFromByte(address);
+        // Send intent to fastpair
+        Intent switchBufferSizeIntent = new Intent(BluetoothDevice.ACTION_SWITCH_BUFFER_SIZE);
+        switchBufferSizeIntent.setClassName(
+                getString(com.android.bluetooth.R.string.peripheral_link_package),
+                getString(com.android.bluetooth.R.string.peripheral_link_package)
+                        + getString(com.android.bluetooth.R.string.peripheral_link_service));
+        switchBufferSizeIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+        switchBufferSizeIntent.putExtra(
+                BluetoothDevice.EXTRA_LOW_LATENCY_BUFFER_SIZE, isLowLatencyBufferSize);
+        sendBroadcast(switchBufferSizeIntent);
+    }
+
     /**
      * Enable/disable BluetoothInCallService
      *
diff --git a/android/app/src/com/android/bluetooth/btservice/JniCallbacks.java b/android/app/src/com/android/bluetooth/btservice/JniCallbacks.java
index 03d9264..5d7b49d 100644
--- a/android/app/src/com/android/bluetooth/btservice/JniCallbacks.java
+++ b/android/app/src/com/android/bluetooth/btservice/JniCallbacks.java
@@ -106,4 +106,8 @@
                 packets_not_receive_count, negative_acknowledgement_count);
     }
 
+    void switchBufferSizeCallback(byte[] mac_address, boolean is_low_latency_buffer_size) {
+        mAdapterService.switchBufferSizeCallback(mac_address, is_low_latency_buffer_size);
+    }
+
 }
diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java
index 4c138f8..89ec4b2 100644
--- a/framework/java/android/bluetooth/BluetoothDevice.java
+++ b/framework/java/android/bluetooth/BluetoothDevice.java
@@ -232,6 +232,25 @@
             "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED";
 
     /**
+     * Broadcast Action: Indicates the audio buffer size should be switched
+     * between a low latency buffer size and a higher and larger latency buffer size.
+     * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
+     * #EXTRA_LOW_LATENCY_BUFFER_SIZE}.
+     *
+     * @hide
+     */
+    @SuppressLint("ActionValue")
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @SystemApi
+    public static final String ACTION_SWITCH_BUFFER_SIZE =
+            "android.bluetooth.device.action.SWITCH_BUFFER_SIZE";
+
+    /**
      * Used as an Integer extra field in {@link #ACTION_BATTERY_LEVEL_CHANGED}
      * intent. It contains the most recently retrieved battery level information
      * ranging from 0% to 100% for a remote device, {@link #BATTERY_LEVEL_UNKNOWN}
@@ -310,6 +329,17 @@
      */
     public static final String EXTRA_PREVIOUS_BOND_STATE =
             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
+
+    /**
+     * Used as a boolean extra field to indicate if audio buffer size is low latency or not
+     *
+     * @hide
+     */
+    @SuppressLint("ActionValue")
+    @SystemApi
+    public static final String EXTRA_LOW_LATENCY_BUFFER_SIZE =
+            "android.bluetooth.device.extra.LOW_LATENCY_BUFFER_SIZE";
+
     /**
      * Indicates the remote device is not bonded (paired).
      * <p>There is no shared link key with the remote device, so communication
diff --git a/system/btif/include/btif_common.h b/system/btif/include/btif_common.h
index f932c04..3782b50 100644
--- a/system/btif/include/btif_common.h
+++ b/system/btif/include/btif_common.h
@@ -232,4 +232,7 @@
     int retransmission_count, int packets_not_receive_count,
     int negative_acknowledgement_count);
 
+void invoke_switch_buffer_size_cb(RawAddress remote_addr,
+                                     bool is_low_latency_buffer_size);
+
 #endif /* BTIF_COMMON_H */
diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc
index 9b5f5d3..7d7a2f8 100644
--- a/system/btif/src/bluetooth.cc
+++ b/system/btif/src/bluetooth.cc
@@ -895,3 +895,15 @@
           timestamp, report_id, rssi, snr, retransmission_count,
           packets_not_receive_count, negative_acknowledgement_count));
 }
+
+void invoke_switch_buffer_size_cb(RawAddress remote_addr,
+                                  bool is_low_latency_buffer_size) {
+  do_in_jni_thread(
+      FROM_HERE,
+      base::BindOnce(
+          [](RawAddress remote_addr, bool is_low_latency_buffer_size) {
+            HAL_CBACK(bt_hal_cbacks, switch_buffer_size_cb, &remote_addr,
+                      is_low_latency_buffer_size);
+          },
+          remote_addr, is_low_latency_buffer_size));
+}
diff --git a/system/gd/rust/topshim/src/btif.rs b/system/gd/rust/topshim/src/btif.rs
index 34283ff..e854f57 100644
--- a/system/gd/rust/topshim/src/btif.rs
+++ b/system/gd/rust/topshim/src/btif.rs
@@ -699,6 +699,7 @@
     // energy_info_cb
     // link_quality_report_cb
     // generate_local_oob_data_cb
+    // switch_buffer_size_cb
 }
 
 pub struct BaseCallbacksDispatcher {
@@ -814,6 +815,7 @@
             energy_info_cb: None,
             link_quality_report_cb: None,
             generate_local_oob_data_cb: None,
+            switch_buffer_size_cb: None,
         });
 
         let rawcb: *mut bindings::bt_callbacks_t = &mut *callbacks;
diff --git a/system/include/hardware/bluetooth.h b/system/include/hardware/bluetooth.h
index c174d91..d907dbe 100644
--- a/system/include/hardware/bluetooth.h
+++ b/system/include/hardware/bluetooth.h
@@ -469,6 +469,10 @@
     int retransmission_count, int packets_not_receive_count,
     int negative_acknowledgement_count);
 
+/** Switch the buffer size callback */
+typedef void (*switch_buffer_size_callback)(RawAddress* remote_addr,
+                                            bool is_low_latency_buffer_size);
+
 typedef enum { ASSOCIATE_JVM, DISASSOCIATE_JVM } bt_cb_thread_evt;
 
 /** Thread Associate/Disassociate JVM Callback */
@@ -526,6 +530,7 @@
   energy_info_callback energy_info_cb;
   link_quality_report_callback link_quality_report_cb;
   generate_local_oob_data_callback generate_local_oob_data_cb;
+  switch_buffer_size_callback switch_buffer_size_cb;
 } bt_callbacks_t;
 
 typedef void (*alarm_cb)(void* data);
diff --git a/system/service/hal/bluetooth_interface.cc b/system/service/hal/bluetooth_interface.cc
index 2e5b83a..c47a3ed 100644
--- a/system/service/hal/bluetooth_interface.cc
+++ b/system/service/hal/bluetooth_interface.cc
@@ -217,6 +217,16 @@
       packets_not_receive_count, negative_acknowledgement_count));
 }
 
+void SwitchBufferSizeCallback(RawAddress* remote_addr,
+                              bool is_low_latency_buffer_size) {
+  shared_lock<shared_mutex_impl> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  LOG(WARNING) << __func__ << " - is_low_latency_buffer_size: "
+               << is_low_latency_buffer_size;
+  FOR_EACH_BLUETOOTH_OBSERVER(
+      SwitchBufferSizeCallback(remote_addr, is_low_latency_buffer_size));
+}
+
 // The HAL Bluetooth DM callbacks.
 bt_callbacks_t bt_callbacks = {
     sizeof(bt_callbacks_t),
@@ -235,7 +245,8 @@
     nullptr, /* le_test_mode_cb */
     nullptr, /* energy_info_cb */
     LinkQualityReportCallback,
-    nullptr /* generate_local_oob_data_cb */
+    nullptr /* generate_local_oob_data_cb */,
+    SwitchBufferSizeCallback
 };
 
 bt_os_callouts_t bt_os_callouts = {sizeof(bt_os_callouts_t),
@@ -425,6 +436,11 @@
   // Do nothing.
 }
 
+void BluetoothInterface::Observer::SwitchBufferSizeCallback(
+    RawAddress* /* remote_addr */, bool /* is_low_latency_buffer_size */) {
+  // Do nothing.
+}
+
 // static
 bool BluetoothInterface::Initialize() {
   unique_lock<shared_mutex_impl> lock(g_instance_lock);
diff --git a/system/service/hal/bluetooth_interface.h b/system/service/hal/bluetooth_interface.h
index 0390cb0..50c35f6 100644
--- a/system/service/hal/bluetooth_interface.h
+++ b/system/service/hal/bluetooth_interface.h
@@ -83,6 +83,9 @@
         int retransmission_count, int packets_not_receive_count,
         int negative_acknowledgement_count);
 
+    virtual void SwitchBufferSizeCallback(RawAddress* remote_addr,
+                                          bool is_low_latency_buffer_size);
+
     // TODO(armansito): Complete the list of callbacks.
   };
 
diff --git a/system/test/headless/headless.cc b/system/test/headless/headless.cc
index fd6a35e..d9b12fd 100644
--- a/system/test/headless/headless.cc
+++ b/system/test/headless/headless.cc
@@ -136,6 +136,12 @@
   LOG_INFO("%s", __func__);
 }
 
+/** Switch buffer size callback */
+void switch_buffer_size(RawAddress* remote_addr,
+                        bool is_low_latency_buffer_size) {
+  LOG_INFO("%s", __func__);
+}
+
 void thread_event(bt_cb_thread_evt evt) { LOG_INFO("%s", __func__); }
 
 void dut_mode_recv(uint16_t opcode, uint8_t* buf, uint8_t len) {
@@ -169,6 +175,7 @@
     .le_test_mode_cb = le_test_mode,
     .energy_info_cb = energy_info,
     .link_quality_report_cb = link_quality_report,
+    .switch_buffer_size_cb = switch_buffer_size,
 };
 // HAL HARDWARE CALLBACKS