Merge "mcp: Synchronize mPendingStateRequest list access"
diff --git a/Android.bp b/Android.bp
index dc523cc..347b22b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,7 +51,7 @@
         "libbluetooth_headers",
     ],
     include_dirs: [
-        "system/bt/types",
+        "packages/modules/Bluetooth/system/types",
     ],
     shared_libs: [
         "libbase",
diff --git a/OWNERS b/OWNERS
index 2c1bdc4..cc15db5 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1 +1 @@
-include platform/system/bt:/OWNERS
+include platform/packages/modules/Bluetooth:/OWNERS
diff --git a/jni/com_android_bluetooth_btservice_AdapterService.cpp b/jni/com_android_bluetooth_btservice_AdapterService.cpp
index 40be390..bbf46bb 100644
--- a/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -67,6 +67,7 @@
 static jmethodID method_pinRequestCallback;
 static jmethodID method_sspRequestCallback;
 static jmethodID method_bondStateChangeCallback;
+static jmethodID method_addressConsolidateCallback;
 static jmethodID method_aclStateChangeCallback;
 static jmethodID method_discoveryStateChangeCallback;
 static jmethodID method_linkQualityReportCallback;
@@ -302,6 +303,34 @@
                                (jint)fail_reason);
 }
 
+static void address_consolidate_callback(RawAddress* main_bd_addr,
+                                         RawAddress* secondary_bd_addr) {
+  CallbackEnv sCallbackEnv(__func__);
+
+  ScopedLocalRef<jbyteArray> main_addr(
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
+  if (!main_addr.get()) {
+    ALOGE("Address allocation failed in %s", __func__);
+    return;
+  }
+  sCallbackEnv->SetByteArrayRegion(main_addr.get(), 0, sizeof(RawAddress),
+                                   (jbyte*)main_bd_addr);
+
+  ScopedLocalRef<jbyteArray> secondary_addr(
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
+  if (!secondary_addr.get()) {
+    ALOGE("Address allocation failed in %s", __func__);
+    return;
+  }
+
+  sCallbackEnv->SetByteArrayRegion(secondary_addr.get(), 0, sizeof(RawAddress),
+                                   (jbyte*)secondary_bd_addr);
+
+  sCallbackEnv->CallVoidMethod(sJniCallbacksObj,
+                               method_addressConsolidateCallback,
+                               main_addr.get(), secondary_addr.get());
+}
+
 static void acl_state_changed_callback(bt_status_t status, RawAddress* bd_addr,
                                        bt_acl_state_t state,
                                        int transport_link_type,
@@ -629,15 +658,23 @@
       p_energy_info->idle_time, p_energy_info->energy_used, array.get());
 }
 
-static bt_callbacks_t sBluetoothCallbacks = {
-    sizeof(sBluetoothCallbacks),  adapter_state_change_callback,
-    adapter_properties_callback,  remote_device_properties_callback,
-    device_found_callback,        discovery_state_changed_callback,
-    pin_request_callback,         ssp_request_callback,
-    bond_state_changed_callback,  acl_state_changed_callback,
-    callback_thread_event,        dut_mode_recv_callback,
-    le_test_mode_recv_callback,   energy_info_recv_callback,
-    link_quality_report_callback, generate_local_oob_data_callback};
+static bt_callbacks_t sBluetoothCallbacks = {sizeof(sBluetoothCallbacks),
+                                             adapter_state_change_callback,
+                                             adapter_properties_callback,
+                                             remote_device_properties_callback,
+                                             device_found_callback,
+                                             discovery_state_changed_callback,
+                                             pin_request_callback,
+                                             ssp_request_callback,
+                                             bond_state_changed_callback,
+                                             address_consolidate_callback,
+                                             acl_state_changed_callback,
+                                             callback_thread_event,
+                                             dut_mode_recv_callback,
+                                             le_test_mode_recv_callback,
+                                             energy_info_recv_callback,
+                                             link_quality_report_callback,
+                                             generate_local_oob_data_callback};
 
 // The callback to call when the wake alarm fires.
 static alarm_cb sAlarmCallback;
@@ -847,6 +884,9 @@
   method_bondStateChangeCallback =
       env->GetMethodID(jniCallbackClass, "bondStateChangeCallback", "(I[BII)V");
 
+  method_addressConsolidateCallback = env->GetMethodID(
+      jniCallbackClass, "addressConsolidateCallback", "([B[B)V");
+
   method_aclStateChangeCallback =
       env->GetMethodID(jniCallbackClass, "aclStateChangeCallback", "(I[BIII)V");
 
diff --git a/jni/com_android_bluetooth_gatt.cpp b/jni/com_android_bluetooth_gatt.cpp
index bf6cba8..642e589 100644
--- a/jni/com_android_bluetooth_gatt.cpp
+++ b/jni/com_android_bluetooth_gatt.cpp
@@ -302,12 +302,22 @@
                                conn_id, status, p_data->handle, jb.get());
 }
 
-void btgattc_write_characteristic_cb(int conn_id, int status, uint16_t handle) {
+void btgattc_write_characteristic_cb(int conn_id, int status, uint16_t handle,
+                                     uint16_t len, const uint8_t* value) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
+  ScopedLocalRef<jbyteArray> jb(sCallbackEnv.get(), NULL);
+  if (status == 0) {  // Success
+    jb.reset(sCallbackEnv->NewByteArray(len));
+    sCallbackEnv->SetByteArrayRegion(jb.get(), 0, len, (jbyte*)value);
+  } else {
+    uint8_t value = 0;
+    jb.reset(sCallbackEnv->NewByteArray(1));
+    sCallbackEnv->SetByteArrayRegion(jb.get(), 0, 1, (jbyte*)&value);
+  }
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWriteCharacteristic,
-                               conn_id, status, handle);
+                               conn_id, status, handle, jb.get());
 }
 
 void btgattc_execute_write_cb(int conn_id, int status) {
@@ -336,12 +346,22 @@
                                status, p_data.handle, jb.get());
 }
 
-void btgattc_write_descriptor_cb(int conn_id, int status, uint16_t handle) {
+void btgattc_write_descriptor_cb(int conn_id, int status, uint16_t handle,
+                                 uint16_t len, const uint8_t* value) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
+  ScopedLocalRef<jbyteArray> jb(sCallbackEnv.get(), NULL);
+  if (status == 0) {  // Success
+    jb.reset(sCallbackEnv->NewByteArray(len));
+    sCallbackEnv->SetByteArrayRegion(jb.get(), 0, len, (jbyte*)value);
+  } else {
+    uint8_t value = 0;
+    jb.reset(sCallbackEnv->NewByteArray(1));
+    sCallbackEnv->SetByteArrayRegion(jb.get(), 0, 1, (jbyte*)&value);
+  }
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWriteDescriptor, conn_id,
-                               status, handle);
+                               status, handle, jb.get());
 }
 
 void btgattc_remote_rssi_cb(int client_if, const RawAddress& bda, int rssi,
@@ -983,7 +1003,7 @@
   method_onReadCharacteristic =
       env->GetMethodID(clazz, "onReadCharacteristic", "(III[B)V");
   method_onWriteCharacteristic =
-      env->GetMethodID(clazz, "onWriteCharacteristic", "(III)V");
+      env->GetMethodID(clazz, "onWriteCharacteristic", "(III[B)V");
   method_onExecuteCompleted =
       env->GetMethodID(clazz, "onExecuteCompleted", "(II)V");
   method_onSearchCompleted =
@@ -991,7 +1011,7 @@
   method_onReadDescriptor =
       env->GetMethodID(clazz, "onReadDescriptor", "(III[B)V");
   method_onWriteDescriptor =
-      env->GetMethodID(clazz, "onWriteDescriptor", "(III)V");
+      env->GetMethodID(clazz, "onWriteDescriptor", "(III[B)V");
   method_onNotify =
       env->GetMethodID(clazz, "onNotify", "(ILjava/lang/String;IZ[B)V");
   method_onRegisterForNotifications =
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index 542509e..557f3b2 100644
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -37,6 +37,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.media.AudioManager;
+import android.media.BtProfileConnectionInfo;
 import android.os.HandlerThread;
 import android.util.Log;
 
@@ -462,13 +463,10 @@
             // device, the user has explicitly switched the output to the local device and music
             // should continue playing. Otherwise, the remote device has been indeed disconnected
             // and audio should be suspended before switching the output to the local device.
-            boolean suppressNoisyIntent = !forceStopPlayingAudio
-                    && (getConnectionState(previousActiveDevice)
-                    == BluetoothProfile.STATE_CONNECTED);
-            Log.i(TAG, "removeActiveDevice: suppressNoisyIntent=" + suppressNoisyIntent);
-            mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
-                    previousActiveDevice, BluetoothProfile.STATE_DISCONNECTED,
-                    BluetoothProfile.A2DP, suppressNoisyIntent, -1);
+            boolean stopAudio = forceStopPlayingAudio || (getConnectionState(previousActiveDevice)
+                        != BluetoothProfile.STATE_CONNECTED);
+            mAudioManager.handleBluetoothActiveDeviceChanged(null, previousActiveDevice,
+                    BtProfileConnectionInfo.a2dpInfo(!stopAudio, -1));
 
             synchronized (mStateMachines) {
                 // Make sure the Active device in native layer is set to null and audio is off
@@ -552,13 +550,6 @@
             // This needs to happen before we inform the audio manager that the device
             // disconnected. Please see comment in updateAndBroadcastActiveDevice() for why.
             updateAndBroadcastActiveDevice(device);
-            // Make sure the Audio Manager knows the previous Active device is disconnected,
-            // and the new Active device is connected.
-            if (previousActiveDevice != null) {
-                mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
-                        previousActiveDevice, BluetoothProfile.STATE_DISCONNECTED,
-                        BluetoothProfile.A2DP, true, -1);
-            }
 
             BluetoothDevice newActiveDevice = null;
             synchronized (mStateMachines) {
@@ -583,13 +574,13 @@
                 rememberedVolume = mFactory.getAvrcpTargetService()
                         .getRememberedVolumeForDevice(newActiveDevice);
             }
-            mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
-                    newActiveDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP,
-                    true, rememberedVolume);
-            // Inform the Audio Service about the codec configuration
+            // Make sure the Audio Manager knows the previous Active device is disconnected,
+            // and the new Active device is connected.
+            // And inform the Audio Service about the codec configuration
             // change, so the Audio Service can reset accordingly the audio
             // feeding parameters in the Audio HAL to the Bluetooth stack.
-            mAudioManager.handleBluetoothA2dpDeviceConfigChange(newActiveDevice);
+            mAudioManager.handleBluetoothActiveDeviceChanged(newActiveDevice, previousActiveDevice,
+                    BtProfileConnectionInfo.a2dpInfo(true, rememberedVolume));
         }
         return true;
     }
@@ -972,8 +963,13 @@
         // Inform the Audio Service about the codec configuration change,
         // so the Audio Service can reset accordingly the audio feeding
         // parameters in the Audio HAL to the Bluetooth stack.
-        if (isActiveDevice(device) && !sameAudioFeedingParameters) {
-            mAudioManager.handleBluetoothA2dpDeviceConfigChange(device);
+        // Until we are able to detect from device_port_proxy if the config has changed or not,
+        // the Bluetooth stack can only disable the audio session and need to ask audioManager to
+        // restart the session even if feeding parameter are the same. (sameAudioFeedingParameters
+        // is left unused until there)
+        if (isActiveDevice(device)) {
+            mAudioManager.handleBluetoothActiveDeviceChanged(device, device,
+                    BtProfileConnectionInfo.a2dpInfo(false, -1));
         }
     }
 
diff --git a/src/com/android/bluetooth/a2dpsink/OWNERS b/src/com/android/bluetooth/a2dpsink/OWNERS
index 06dc3f8..fd47bd7 100644
--- a/src/com/android/bluetooth/a2dpsink/OWNERS
+++ b/src/com/android/bluetooth/a2dpsink/OWNERS
@@ -1 +1 @@
-include platform/system/bt:/OWNERS_automotive
+include platform/packages/modules/Bluetooth:/OWNERS_automotive
diff --git a/src/com/android/bluetooth/audio_util/helpers/PlayStatus.java b/src/com/android/bluetooth/audio_util/helpers/PlayStatus.java
index 922b151..75a760b 100644
--- a/src/com/android/bluetooth/audio_util/helpers/PlayStatus.java
+++ b/src/com/android/bluetooth/audio_util/helpers/PlayStatus.java
@@ -31,7 +31,7 @@
     static final byte REV_SEEK = 4;
     static final byte ERROR = -1;
 
-    public long position = 0xFFFFFFFFFFFFFFFFL;
+    public long position = 0;
     public long duration = 0x00L;
     public byte state = STOPPED;
 
@@ -41,7 +41,7 @@
         if (state == null) return ret;
 
         ret.state = playbackStateToAvrcpState(state.getState());
-        ret.position = state.getPosition();
+        ret.position = (state.getPosition() > 0) ? state.getPosition() : 0;
         ret.duration = duration;
         return ret;
     }
diff --git a/src/com/android/bluetooth/avrcpcontroller/OWNERS b/src/com/android/bluetooth/avrcpcontroller/OWNERS
index 06dc3f8..fd47bd7 100644
--- a/src/com/android/bluetooth/avrcpcontroller/OWNERS
+++ b/src/com/android/bluetooth/avrcpcontroller/OWNERS
@@ -1 +1 @@
-include platform/system/bt:/OWNERS_automotive
+include platform/packages/modules/Bluetooth:/OWNERS_automotive
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 9c4f6bb..f735641 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -98,6 +98,7 @@
 import com.android.bluetooth.Utils;
 import com.android.bluetooth.a2dp.A2dpService;
 import com.android.bluetooth.a2dpsink.A2dpSinkService;
+import com.android.bluetooth.btservice.MetricsLogger;
 import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
 import com.android.bluetooth.btservice.activityattribution.ActivityAttributionService;
 import com.android.bluetooth.btservice.bluetoothkeystore.BluetoothKeystoreService;
@@ -305,6 +306,8 @@
 
     private volatile boolean mTestModeEnabled = false;
 
+    private MetricsLogger mMetricsLogger;
+
     /**
      * Register a {@link ProfileService} with AdapterService.
      *
@@ -445,6 +448,7 @@
     @Override
     public void onCreate() {
         super.onCreate();
+        initMetricsLogger();
         debugLog("onCreate()");
         mDeviceConfigListener.start();
         mRemoteDevices = new RemoteDevices(this, Looper.getMainLooper());
@@ -456,8 +460,6 @@
         mJniCallbacks = new JniCallbacks(this, mAdapterProperties);
         mBluetoothKeystoreService = new BluetoothKeystoreService(isCommonCriteriaMode());
         mBluetoothKeystoreService.start();
-        mActivityAttributionService = new ActivityAttributionService();
-        mActivityAttributionService.start();
         int configCompareResult = mBluetoothKeystoreService.getCompareResult();
 
         // Start tracking Binder latency for the bluetooth process.
@@ -512,6 +514,9 @@
 
         mBluetoothSocketManagerBinder = new BluetoothSocketManagerBinder(this);
 
+        mActivityAttributionService = new ActivityAttributionService();
+        mActivityAttributionService.start();
+
         setAdapterService(this);
 
         invalidateBluetoothCaches();
@@ -582,6 +587,27 @@
         }
     };
 
+    private boolean initMetricsLogger() {
+        if (mMetricsLogger != null) {
+            return false;
+        }
+        mMetricsLogger = MetricsLogger.getInstance();
+        return mMetricsLogger.init(this);
+    }
+
+    private boolean closeMetricsLogger() {
+        if (mMetricsLogger == null) {
+            return false;
+        }
+        boolean result = mMetricsLogger.close();
+        mMetricsLogger = null;
+        return result;
+    }
+
+    public void setMetricsLogger(MetricsLogger metricsLogger) {
+        mMetricsLogger = metricsLogger;
+    }
+
     void bringUpBle() {
         debugLog("bleOnProcessStart()");
 
@@ -776,6 +802,8 @@
             return;
         }
 
+        closeMetricsLogger();
+
         clearAdapterService(this);
 
         mCleaningUp = true;
@@ -3817,7 +3845,7 @@
             initFlags.add(String.format("%s=%s", LOGGING_DEBUG_DISABLED_FOR_TAGS_FLAG,
                     debugLoggingDisabledTags));
         }
-        if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH, BTAA_HCI_LOG_FLAG, false)) {
+        if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH, BTAA_HCI_LOG_FLAG, true)) {
             initFlags.add(String.format("%s=%s", BTAA_HCI_LOG_FLAG, "true"));
         }
         return initFlags.toArray(new String[0]);
diff --git a/src/com/android/bluetooth/btservice/Config.java b/src/com/android/bluetooth/btservice/Config.java
index f4f6413..6b6f1cb 100644
--- a/src/com/android/bluetooth/btservice/Config.java
+++ b/src/com/android/bluetooth/btservice/Config.java
@@ -17,6 +17,7 @@
 package com.android.bluetooth.btservice;
 
 import android.bluetooth.BluetoothProfile;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
@@ -221,6 +222,11 @@
         if (systemConfigManager == null) {
             return null;
         }
-        return systemConfigManager.getEnabledComponentOverrides(ctx.getPackageName());
+        List<String> enabledComponent = new ArrayList<>();
+        for (ComponentName comp :
+                systemConfigManager.getEnabledComponentOverrides(ctx.getPackageName())) {
+            enabledComponent.add(comp.getClassName());
+        }
+        return enabledComponent;
     }
 }
diff --git a/src/com/android/bluetooth/btservice/JniCallbacks.java b/src/com/android/bluetooth/btservice/JniCallbacks.java
index f00353a..03d9264 100644
--- a/src/com/android/bluetooth/btservice/JniCallbacks.java
+++ b/src/com/android/bluetooth/btservice/JniCallbacks.java
@@ -67,6 +67,10 @@
         mBondStateMachine.bondStateChangeCallback(status, address, newState, hciReason);
     }
 
+    void addressConsolidateCallback(byte[] mainAddress, byte[] secondaryAddress) {
+        mRemoteDevices.addressConsolidateCallback(mainAddress, secondaryAddress);
+    }
+
     void aclStateChangeCallback(int status, byte[] address, int newState,
             int transportLinkType, int hciReason) {
         mRemoteDevices.aclStateChangeCallback(status, address, newState,
diff --git a/src/com/android/bluetooth/btservice/MetricsLogger.java b/src/com/android/bluetooth/btservice/MetricsLogger.java
index b8a3d18..e47b303 100644
--- a/src/com/android/bluetooth/btservice/MetricsLogger.java
+++ b/src/com/android/bluetooth/btservice/MetricsLogger.java
@@ -15,18 +15,113 @@
  */
 package com.android.bluetooth.btservice;
 
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemClock;
+import android.util.Log;
+
 import com.android.bluetooth.BluetoothMetricsProto.BluetoothLog;
 import com.android.bluetooth.BluetoothMetricsProto.ProfileConnectionStats;
 import com.android.bluetooth.BluetoothMetricsProto.ProfileId;
+import com.android.bluetooth.BluetoothStatsLog;
 
 import java.util.HashMap;
 
 /**
- * Class with static methods for logging metrics data
+ * Class of Bluetooth Metrics
  */
 public class MetricsLogger {
+    private static final String TAG = "BluetoothMetricsLogger";
+
+    public static final boolean DEBUG = false;
+
+    /**
+     * Intent indicating Bluetooth counter metrics should send logs to BluetoothStatsLog
+     */
+    public static final String BLUETOOTH_COUNTER_METRICS_ACTION =
+            "com.android.bluetooth.map.BLUETOOTH_COUNTER_METRICS_ACTION";
+    // 6 hours timeout for counter metrics
+    private static final long BLUETOOTH_COUNTER_METRICS_ACTION_DURATION_MILLIS = 6L * 3600L * 1000L;
+
     private static final HashMap<ProfileId, Integer> sProfileConnectionCounts = new HashMap<>();
 
+    HashMap<Integer, Long> mCounters = new HashMap<>();
+    private static MetricsLogger sInstance = null;
+    private Context mContext = null;
+    private AlarmManager mAlarmManager = null;
+    private boolean mInitialized = false;
+    static final private Object mLock = new Object();
+
+    private BroadcastReceiver mDrainReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (DEBUG) {
+                Log.d(TAG, "onReceive: " + action);
+            }
+            if (action.equals(BLUETOOTH_COUNTER_METRICS_ACTION)) {
+                drainBufferedCounters();
+            }
+        }
+    };
+
+    public static MetricsLogger getInstance() {
+        if (sInstance == null) {
+            synchronized (mLock) {
+                if (sInstance == null) {
+                    sInstance = new MetricsLogger();
+                }
+            }
+        }
+        return sInstance;
+    }
+
+    public boolean isInitialized() {
+        return mInitialized;
+    }
+
+    public boolean init(Context context) {
+        if (mInitialized) {
+            return false;
+        }
+        mInitialized = true;
+        mContext = context;
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BLUETOOTH_COUNTER_METRICS_ACTION);
+        mContext.registerReceiver(mDrainReceiver, filter);
+        scheduleDrains();
+        return true;
+    }
+
+    public boolean count(int key, long count) {
+        if (!mInitialized) {
+            Log.w(TAG, "MetricsLogger isn't initialized");
+            return false;
+        }
+        if (count <= 0) {
+            Log.w(TAG, "count is not larger than 0. count: " + count + " key: " + key);
+            return false;
+        }
+        long total = 0;
+
+        synchronized (mLock) {
+            if (mCounters.containsKey(key)) {
+                total = mCounters.get(key);
+            }
+            if (Long.MAX_VALUE - total < count) {
+                Log.w(TAG, "count overflows. count: " + count + " current total: " + total);
+                mCounters.put(key, Long.MAX_VALUE);
+                return false;
+            }
+            mCounters.put(key, total + count);
+        }
+        return true;
+    }
+
     /**
      * Log profile connection event by incrementing an internal counter for that profile.
      * This log persists over adapter enable/disable and only get cleared when metrics are
@@ -57,4 +152,60 @@
             sProfileConnectionCounts.clear();
         }
     }
+
+    protected void scheduleDrains() {
+        if (DEBUG) {
+            Log.d(TAG, "setCounterMetricsAlarm()");
+        }
+        if (mAlarmManager == null) {
+            mAlarmManager = mContext.getSystemService(AlarmManager.class);
+        }
+        mAlarmManager.setRepeating(
+                AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                SystemClock.elapsedRealtime(),
+                BLUETOOTH_COUNTER_METRICS_ACTION_DURATION_MILLIS,
+                getDrainIntent());
+    }
+
+    protected void writeCounter(int key, long count) {
+        BluetoothStatsLog.write(
+                BluetoothStatsLog.BLUETOOTH_CODE_PATH_COUNTER, key, count);
+    }
+
+    protected void drainBufferedCounters() {
+        Log.i(TAG, "drainBufferedCounters().");
+        synchronized (mLock) {
+            // send mCounters to westworld
+            for (int key : mCounters.keySet()) {
+                writeCounter(key, mCounters.get(key));
+            }
+            mCounters.clear();
+        }
+    }
+
+    public boolean close() {
+        if (!mInitialized) {
+            return false;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "close()");
+        }
+        cancelPendingDrain();
+        drainBufferedCounters();
+        mAlarmManager = null;
+        mContext = null;
+        mInitialized = false;
+        return true;
+    }
+    protected void cancelPendingDrain() {
+        PendingIntent pIntent = getDrainIntent();
+        pIntent.cancel();
+        mAlarmManager.cancel(pIntent);
+    }
+
+    private PendingIntent getDrainIntent() {
+        Intent counterMetricsIntent = new Intent(BLUETOOTH_COUNTER_METRICS_ACTION);
+        return PendingIntent.getBroadcast(
+                mContext, 0, counterMetricsIntent, PendingIntent.FLAG_IMMUTABLE);
+    }
 }
diff --git a/src/com/android/bluetooth/btservice/PhonePolicy.java b/src/com/android/bluetooth/btservice/PhonePolicy.java
index 9529c51..94a5355 100644
--- a/src/com/android/bluetooth/btservice/PhonePolicy.java
+++ b/src/com/android/bluetooth/btservice/PhonePolicy.java
@@ -19,12 +19,14 @@
 import android.annotation.RequiresPermission;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
+import android.bluetooth.BluetoothVolumeControl;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -39,10 +41,13 @@
 import com.android.bluetooth.Utils;
 import com.android.bluetooth.a2dp.A2dpService;
 import com.android.bluetooth.btservice.storage.DatabaseManager;
+import com.android.bluetooth.csip.CsipSetCoordinatorService;
 import com.android.bluetooth.hearingaid.HearingAidService;
 import com.android.bluetooth.hfp.HeadsetService;
 import com.android.bluetooth.hid.HidHostService;
+import com.android.bluetooth.le_audio.LeAudioService;
 import com.android.bluetooth.pan.PanService;
+import com.android.bluetooth.vc.VolumeControlService;
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -118,11 +123,21 @@
                             BluetoothProfile.A2DP, -1, // No-op argument
                             intent).sendToTarget();
                     break;
+                case BluetoothCsipSetCoordinator.ACTION_CSIS_CONNECTION_STATE_CHANGED:
+                    mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED,
+                            BluetoothProfile.CSIP_SET_COORDINATOR, -1, // No-op argument
+                            intent).sendToTarget();
+                    break;
                 case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED:
                     mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED,
                             BluetoothProfile.LE_AUDIO, -1, // No-op argument
                             intent).sendToTarget();
                     break;
+                case BluetoothVolumeControl.ACTION_CONNECTION_STATE_CHANGED:
+                    mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED,
+                            BluetoothProfile.VOLUME_CONTROL, -1, // No-op argument
+                            intent).sendToTarget();
+                    break;
                 case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
                     mHandler.obtainMessage(MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED,
                             BluetoothProfile.A2DP, -1, // No-op argument
@@ -242,6 +257,8 @@
         filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
+        filter.addAction(BluetoothCsipSetCoordinator.ACTION_CSIS_CONNECTION_STATE_CHANGED);
+        filter.addAction(BluetoothVolumeControl.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
         filter.addAction(BluetoothDevice.ACTION_UUID);
         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
@@ -274,6 +291,11 @@
         HeadsetService headsetService = mFactory.getHeadsetService();
         PanService panService = mFactory.getPanService();
         HearingAidService hearingAidService = mFactory.getHearingAidService();
+        LeAudioService leAudioService = mFactory.getLeAudioService();
+        CsipSetCoordinatorService csipSetCooridnatorService =
+             mFactory.getCsipSetCoordinatorService();
+        VolumeControlService volumeControlService =
+             mFactory.getVolumeControlService();
 
         // Set profile priorities only for the profiles discovered on the remote device.
         // This avoids needless auto-connect attempts to profiles non-existent on the remote device
@@ -302,6 +324,14 @@
                     BluetoothProfile.A2DP, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
         }
 
+        if ((csipSetCooridnatorService != null)
+                && (Utils.arrayContains(uuids, BluetoothUuid.COORDINATED_SET))
+                && (csipSetCooridnatorService.getConnectionPolicy(device)
+                        == BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) {
+            mAdapterService.getDatabase().setProfileConnectionPolicy(device,
+                    BluetoothProfile.CSIP_SET_COORDINATOR, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        }
+
         if ((panService != null) && (Utils.arrayContains(uuids, BluetoothUuid.PANU) && (
                 panService.getConnectionPolicy(device)
                         == BluetoothProfile.CONNECTION_POLICY_UNKNOWN)
@@ -311,6 +341,14 @@
                     BluetoothProfile.PAN, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
         }
 
+        if ((leAudioService != null) && Utils.arrayContains(uuids,
+                BluetoothUuid.LE_AUDIO) && (leAudioService.getConnectionPolicy(device)
+                == BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) {
+            debugLog("setting le audio profile priority for device " + device);
+            mAdapterService.getDatabase().setProfileConnectionPolicy(device,
+                    BluetoothProfile.LE_AUDIO, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        }
+
         if ((hearingAidService != null) && Utils.arrayContains(uuids,
                 BluetoothUuid.HEARING_AID) && (hearingAidService.getConnectionPolicy(device)
                 == BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) {
@@ -318,6 +356,14 @@
             mAdapterService.getDatabase().setProfileConnectionPolicy(device,
                     BluetoothProfile.HEARING_AID, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
         }
+
+        if ((volumeControlService != null) && Utils.arrayContains(uuids,
+                BluetoothUuid.VOLUME_CONTROL) && (volumeControlService.getConnectionPolicy(device)
+                == BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) {
+            debugLog("setting volume control profile priority for device " + device);
+            mAdapterService.getDatabase().setProfileConnectionPolicy(device,
+                    BluetoothProfile.VOLUME_CONTROL, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        }
     }
 
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
@@ -326,7 +372,9 @@
         debugLog("processProfileStateChanged, device=" + device + ", profile=" + profileId + ", "
                 + prevState + " -> " + nextState);
         if (((profileId == BluetoothProfile.A2DP) || (profileId == BluetoothProfile.HEADSET)
-                || (profileId == BluetoothProfile.LE_AUDIO))) {
+                || (profileId == BluetoothProfile.LE_AUDIO)
+                || (profileId == BluetoothProfile.CSIP_SET_COORDINATOR)
+                || (profileId == BluetoothProfile.VOLUME_CONTROL))) {
             if (nextState == BluetoothProfile.STATE_CONNECTED) {
                 switch (profileId) {
                     case BluetoothProfile.A2DP:
@@ -339,7 +387,9 @@
                 connectOtherProfile(device);
             }
             if (nextState == BluetoothProfile.STATE_DISCONNECTED) {
-                if (profileId == BluetoothProfile.A2DP) {
+                if (profileId == BluetoothProfile.A2DP
+                        && (prevState == BluetoothProfile.STATE_CONNECTING
+                        || prevState == BluetoothProfile.STATE_DISCONNECTING)) {
                     mDatabaseManager.setDisconnection(device);
                 }
                 handleAllProfilesDisconnected(device);
@@ -373,6 +423,9 @@
         HeadsetService hsService = mFactory.getHeadsetService();
         A2dpService a2dpService = mFactory.getA2dpService();
         PanService panService = mFactory.getPanService();
+        LeAudioService leAudioService = mFactory.getLeAudioService();
+        CsipSetCoordinatorService csipSetCooridnatorService =
+        mFactory.getCsipSetCoordinatorService();
 
         if (hsService != null) {
             List<BluetoothDevice> hsConnDevList = hsService.getConnectedDevices();
@@ -384,11 +437,21 @@
             allProfilesEmpty &= a2dpConnDevList.isEmpty();
             atLeastOneProfileConnectedForDevice |= a2dpConnDevList.contains(device);
         }
+        if (csipSetCooridnatorService != null) {
+            List<BluetoothDevice> csipConnDevList = csipSetCooridnatorService.getConnectedDevices();
+            allProfilesEmpty &= csipConnDevList.isEmpty();
+            atLeastOneProfileConnectedForDevice |= csipConnDevList.contains(device);
+        }
         if (panService != null) {
             List<BluetoothDevice> panConnDevList = panService.getConnectedDevices();
             allProfilesEmpty &= panConnDevList.isEmpty();
             atLeastOneProfileConnectedForDevice |= panConnDevList.contains(device);
         }
+        if (leAudioService != null) {
+            List<BluetoothDevice> leAudioConnDevList = leAudioService.getConnectedDevices();
+            allProfilesEmpty &= leAudioConnDevList.isEmpty();
+            atLeastOneProfileConnectedForDevice |= leAudioConnDevList.contains(device);
+        }
 
         if (!atLeastOneProfileConnectedForDevice) {
             // Consider this device as fully disconnected, don't bother connecting others
@@ -505,6 +568,11 @@
         HeadsetService hsService = mFactory.getHeadsetService();
         A2dpService a2dpService = mFactory.getA2dpService();
         PanService panService = mFactory.getPanService();
+        LeAudioService leAudioService = mFactory.getLeAudioService();
+        CsipSetCoordinatorService csipSetCooridnatorService =
+            mFactory.getCsipSetCoordinatorService();
+        VolumeControlService volumeControlService =
+            mFactory.getVolumeControlService();
 
         if (hsService != null) {
             if (!mHeadsetRetrySet.contains(device) && (hsService.getConnectionPolicy(device)
@@ -538,6 +606,36 @@
                 panService.connect(device);
             }
         }
+        if (leAudioService != null) {
+            List<BluetoothDevice> leAudioConnDevList = leAudioService.getConnectedDevices();
+            if (!leAudioConnDevList.contains(device) && (leAudioService.getConnectionPolicy(device)
+                    == BluetoothProfile.CONNECTION_POLICY_ALLOWED)
+                    && (leAudioService.getConnectionState(device)
+                    == BluetoothProfile.STATE_DISCONNECTED)) {
+                debugLog("Retrying connection to LEAudio with device " + device);
+                leAudioService.connect(device);
+            }
+        }
+        if (csipSetCooridnatorService != null) {
+            List<BluetoothDevice> csipConnDevList = csipSetCooridnatorService.getConnectedDevices();
+            if (!csipConnDevList.contains(device) && (csipSetCooridnatorService.getConnectionPolicy(device)
+                    == BluetoothProfile.CONNECTION_POLICY_ALLOWED)
+                    && (csipSetCooridnatorService.getConnectionState(device)
+                    == BluetoothProfile.STATE_DISCONNECTED)) {
+                debugLog("Retrying connection to CSIP with device " + device);
+                csipSetCooridnatorService.connect(device);
+            }
+        }
+        if (volumeControlService != null) {
+            List<BluetoothDevice> vcConnDevList = volumeControlService.getConnectedDevices();
+            if (!vcConnDevList.contains(device) && (volumeControlService.getConnectionPolicy(device)
+                    == BluetoothProfile.CONNECTION_POLICY_ALLOWED)
+                    && (volumeControlService.getConnectionState(device)
+                    == BluetoothProfile.STATE_DISCONNECTED)) {
+                debugLog("Retrying connection to CSIP with device " + device);
+                volumeControlService.connect(device);
+            }
+        }
     }
 
     private static void debugLog(String msg) {
diff --git a/src/com/android/bluetooth/btservice/RemoteDevices.java b/src/com/android/bluetooth/btservice/RemoteDevices.java
index a28105a..e6812ee 100644
--- a/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -600,6 +600,9 @@
                             if (sAdapterService.getState() == BluetoothAdapter.STATE_ON) {
                                 sAdapterService.deviceUuidUpdated(bdDevice);
                                 sendUuidIntent(bdDevice, device);
+                            } else if (sAdapterService.getState()
+                                    == BluetoothAdapter.STATE_BLE_ON) {
+                                sAdapterService.deviceUuidUpdated(bdDevice);
                             }
                             break;
                         case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE:
@@ -664,6 +667,19 @@
         }
     }
 
+    void addressConsolidateCallback(byte[] mainAddress, byte[] secondaryAddress) {
+        BluetoothDevice device = getDevice(mainAddress);
+        if (device == null) {
+            errorLog("addressConsolidateCallback: device is NULL, address="
+                    + Utils.getAddressStringFromByte(mainAddress) + ", secondaryAddress="
+                            + Utils.getAddressStringFromByte(secondaryAddress));
+            return;
+        }
+        Log.d(TAG, "addressConsolidateCallback device: " + device + ", secondaryAddress:"
+                + Utils.getAddressStringFromByte(secondaryAddress));
+        // TODO
+    }
+
     void aclStateChangeCallback(int status, byte[] address, int newState,
                                 int transportLinkType, int hciReason) {
         BluetoothDevice device = getDevice(address);
diff --git a/src/com/android/bluetooth/btservice/ServiceFactory.java b/src/com/android/bluetooth/btservice/ServiceFactory.java
index fd1b6d8..6842dc0 100644
--- a/src/com/android/bluetooth/btservice/ServiceFactory.java
+++ b/src/com/android/bluetooth/btservice/ServiceFactory.java
@@ -18,6 +18,7 @@
 
 import com.android.bluetooth.a2dp.A2dpService;
 import com.android.bluetooth.avrcp.AvrcpTargetService;
+import com.android.bluetooth.csip.CsipSetCoordinatorService;
 import com.android.bluetooth.hearingaid.HearingAidService;
 import com.android.bluetooth.hfp.HeadsetService;
 import com.android.bluetooth.hid.HidDeviceService;
@@ -25,6 +26,7 @@
 import com.android.bluetooth.le_audio.LeAudioService;
 import com.android.bluetooth.mcp.McpService;
 import com.android.bluetooth.pan.PanService;
+import com.android.bluetooth.vc.VolumeControlService;
 
 // Factory class to create instances of static services. Useful in mocking the service objects.
 public class ServiceFactory {
@@ -32,6 +34,10 @@
         return A2dpService.getA2dpService();
     }
 
+    public CsipSetCoordinatorService getCsipSetCoordinatorService() {
+        return CsipSetCoordinatorService.getCsipSetCoordinatorService();
+    }
+
     public HeadsetService getHeadsetService() {
         return HeadsetService.getHeadsetService();
     }
@@ -63,4 +69,8 @@
     public McpService getMcpService() {
         return McpService.getMcpService();
     }
+
+    public VolumeControlService getVolumeControlService() {
+        return VolumeControlService.getVolumeControlService();
+    }
 }
diff --git a/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java b/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
index 61f4cdf..3b8a9bb 100644
--- a/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
+++ b/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
@@ -284,7 +284,7 @@
         return true;
     }
 
-    List<BluetoothDevice> getConnectedDevices() {
+    public List<BluetoothDevice> getConnectedDevices() {
         enforceCallingOrSelfPermission(BLUETOOTH_CONNECT, "Need BLUETOOTH_CONNECT permission");
         synchronized (mStateMachines) {
             List<BluetoothDevice> devices = new ArrayList<>();
@@ -599,7 +599,9 @@
 
         for (Map.Entry<Executor, IBluetoothCsipSetCoordinatorCallback> entry :
                 mCallbacks.get(uuid).entrySet()) {
-            Log.e(TAG, " executing " + uuid + " " + entry.getKey());
+            if (DBG) {
+                Log.d(TAG, " executing " + uuid + " " + entry.getKey());
+            }
             try {
                 executeCallback(entry.getKey(), entry.getValue(), device, groupId);
             } catch (RemoteException e) {
diff --git a/src/com/android/bluetooth/gatt/CallbackInfo.java b/src/com/android/bluetooth/gatt/CallbackInfo.java
index 330422d..f6035b3 100644
--- a/src/com/android/bluetooth/gatt/CallbackInfo.java
+++ b/src/com/android/bluetooth/gatt/CallbackInfo.java
@@ -26,16 +26,38 @@
     public String address;
     public int status;
     public int handle;
+    public byte[] value;
 
-    CallbackInfo(String address, int status, int handle) {
+    static class Builder {
+        private String mAddress;
+        private int mStatus;
+        private int mHandle;
+        private byte[] mValue;
+
+        Builder(String address, int status) {
+            mAddress = address;
+            mStatus = status;
+        }
+
+        Builder setHandle(int handle) {
+            mHandle = handle;
+            return this;
+        }
+
+        Builder setValue(byte[] value) {
+            mValue = value;
+            return this;
+        }
+
+        CallbackInfo build() {
+            return new CallbackInfo(mAddress, mStatus, mHandle, mValue);
+        }
+    }
+
+    private CallbackInfo(String address, int status, int handle, byte[] value) {
         this.address = address;
         this.status = status;
         this.handle = handle;
     }
-
-    CallbackInfo(String address, int status) {
-        this.address = address;
-        this.status = status;
-    }
 }
 
diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java
index 17f7fca..e7b6aac 100644
--- a/src/com/android/bluetooth/gatt/GattService.java
+++ b/src/com/android/bluetooth/gatt/GattService.java
@@ -30,6 +30,7 @@
 import android.bluetooth.BluetoothGattDescriptor;
 import android.bluetooth.BluetoothGattService;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
 import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothGattCallback;
 import android.bluetooth.IBluetoothGattServerCallback;
@@ -734,7 +735,7 @@
                 int authReq, byte[] value, AttributionSource attributionSource) {
             GattService service = getService();
             if (service == null) {
-                return BluetoothGatt.GATT_WRITE_REQUEST_FAIL;
+                return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
             }
             return service.writeCharacteristic(clientIf, address, handle, writeType, authReq, value,
                     attributionSource);
@@ -751,13 +752,14 @@
         }
 
         @Override
-        public void writeDescriptor(int clientIf, String address, int handle, int authReq,
+        public int writeDescriptor(int clientIf, String address, int handle, int authReq,
                 byte[] value, AttributionSource attributionSource) {
             GattService service = getService();
             if (service == null) {
-                return;
+                return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
             }
-            service.writeDescriptor(clientIf, address, handle, authReq, value, attributionSource);
+            return service.writeDescriptor(clientIf, address, handle, authReq, value,
+                    attributionSource);
         }
 
         @Override
@@ -1694,7 +1696,8 @@
         }
     }
 
-    void onWriteCharacteristic(int connId, int status, int handle) throws RemoteException {
+    void onWriteCharacteristic(int connId, int status, int handle, byte[] data)
+            throws RemoteException {
         String address = mClientMap.addressByConnId(connId);
         synchronized (mPermits) {
             Log.d(TAG, "onWriteCharacteristic() - increasing permit for address="
@@ -1703,7 +1706,8 @@
         }
 
         if (VDBG) {
-            Log.d(TAG, "onWriteCharacteristic() - address=" + address + ", status=" + status);
+            Log.d(TAG, "onWriteCharacteristic() - address=" + address + ", status=" + status
+                    + ", length=" + data.length);
         }
 
         ClientMap.App app = mClientMap.getByConnId(connId);
@@ -1712,12 +1716,15 @@
         }
 
         if (!app.isCongested) {
-            app.callback.onCharacteristicWrite(address, status, handle);
+            app.callback.onCharacteristicWrite(address, status, handle, data);
         } else {
             if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
                 status = BluetoothGatt.GATT_SUCCESS;
             }
-            CallbackInfo callbackInfo = new CallbackInfo(address, status, handle);
+            CallbackInfo callbackInfo = new CallbackInfo.Builder(address, status)
+                    .setHandle(handle)
+                    .setValue(data)
+                    .build();
             app.queueCallback(callbackInfo);
         }
     }
@@ -1749,16 +1756,18 @@
         }
     }
 
-    void onWriteDescriptor(int connId, int status, int handle) throws RemoteException {
+    void onWriteDescriptor(int connId, int status, int handle, byte[] data)
+            throws RemoteException {
         String address = mClientMap.addressByConnId(connId);
 
         if (VDBG) {
-            Log.d(TAG, "onWriteDescriptor() - address=" + address + ", status=" + status);
+            Log.d(TAG, "onWriteDescriptor() - address=" + address + ", status=" + status
+                    + ", length=" + data.length);
         }
 
         ClientMap.App app = mClientMap.getByConnId(connId);
         if (app != null) {
-            app.callback.onDescriptorWrite(address, status, handle);
+            app.callback.onDescriptorWrite(address, status, handle, data);
         }
     }
 
@@ -2181,7 +2190,7 @@
                     return;
                 }
                 app.callback.onCharacteristicWrite(callbackInfo.address, callbackInfo.status,
-                        callbackInfo.handle);
+                        callbackInfo.handle, callbackInfo.value);
             }
         }
     }
@@ -2915,7 +2924,7 @@
             byte[] value, AttributionSource attributionSource) {
         if (!Utils.checkConnectPermissionForDataDelivery(
                 this, attributionSource, "GattService writeCharacteristic")) {
-            return BluetoothGatt.GATT_WRITE_REQUEST_FAIL;
+            return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
         }
 
         if (VDBG) {
@@ -2929,12 +2938,12 @@
         Integer connId = mClientMap.connIdByAddress(clientIf, address);
         if (connId == null) {
             Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
-            return BluetoothGatt.GATT_WRITE_REQUEST_FAIL;
+            return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
         }
 
         if (!permissionCheck(connId, handle)) {
             Log.w(TAG, "writeCharacteristic() - permission check failed!");
-            return BluetoothGatt.GATT_WRITE_REQUEST_FAIL;
+            return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION;
         }
 
         Log.d(TAG, "writeCharacteristic() - trying to acquire permit.");
@@ -2943,19 +2952,19 @@
             AtomicBoolean atomicBoolean = mPermits.get(address);
             if (atomicBoolean == null) {
                 Log.d(TAG, "writeCharacteristic() -  atomicBoolean uninitialized!");
-                return BluetoothGatt.GATT_WRITE_REQUEST_FAIL;
+                return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
             }
 
             boolean success = atomicBoolean.get();
             if (!success) {
-                 Log.d(TAG, "writeCharacteristic() - no permit available.");
-                 return BluetoothGatt.GATT_WRITE_REQUEST_BUSY;
+                Log.d(TAG, "writeCharacteristic() - no permit available.");
+                return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY;
             }
             atomicBoolean.set(false);
         }
 
         gattClientWriteCharacteristicNative(connId, handle, writeType, authReq, value);
-        return BluetoothGatt.GATT_WRITE_REQUEST_SUCCESS;
+        return BluetoothStatusCodes.SUCCESS;
     }
 
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@@ -2985,11 +2994,11 @@
     }
 
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
-    void writeDescriptor(int clientIf, String address, int handle, int authReq, byte[] value,
+    int writeDescriptor(int clientIf, String address, int handle, int authReq, byte[] value,
             AttributionSource attributionSource) {
         if (!Utils.checkConnectPermissionForDataDelivery(
                 this, attributionSource, "GattService writeDescriptor")) {
-            return;
+            return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
         }
         if (VDBG) {
             Log.d(TAG, "writeDescriptor() - address=" + address);
@@ -2998,15 +3007,16 @@
         Integer connId = mClientMap.connIdByAddress(clientIf, address);
         if (connId == null) {
             Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
-            return;
+            return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
         }
 
         if (!permissionCheck(connId, handle)) {
             Log.w(TAG, "writeDescriptor() - permission check failed!");
-            return;
+            return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION;
         }
 
         gattClientWriteDescriptorNative(connId, handle, authReq, value);
+        return BluetoothStatusCodes.SUCCESS;
     }
 
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@@ -3410,7 +3420,7 @@
             if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
                 status = BluetoothGatt.GATT_SUCCESS;
             }
-            app.queueCallback(new CallbackInfo(address, status));
+            app.queueCallback(new CallbackInfo.Builder(address, status).build());
         }
     }
 
diff --git a/src/com/android/bluetooth/hearingaid/HearingAidService.java b/src/com/android/bluetooth/hearingaid/HearingAidService.java
index 2ab14cb..6199ff1 100644
--- a/src/com/android/bluetooth/hearingaid/HearingAidService.java
+++ b/src/com/android/bluetooth/hearingaid/HearingAidService.java
@@ -30,6 +30,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.media.AudioManager;
+import android.media.BtProfileConnectionInfo;
 import android.os.HandlerThread;
 import android.os.ParcelUuid;
 import android.util.Log;
@@ -694,30 +695,15 @@
                 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions());
 
-        if (device == null) {
-            if (DBG) {
-                Log.d(TAG, "Set Hearing Aid audio to disconnected");
-            }
-            boolean suppressNoisyIntent =
-                    (getConnectionState(mPreviousAudioDevice) == BluetoothProfile.STATE_CONNECTED);
-            mAudioManager.setBluetoothHearingAidDeviceConnectionState(
-                    mPreviousAudioDevice, BluetoothProfile.STATE_DISCONNECTED,
-                    suppressNoisyIntent, 0);
-            mPreviousAudioDevice = null;
-        } else {
-            if (DBG) {
-                Log.d(TAG, "Set Hearing Aid audio to connected");
-            }
-            if (mPreviousAudioDevice != null) {
-                mAudioManager.setBluetoothHearingAidDeviceConnectionState(
-                        mPreviousAudioDevice, BluetoothProfile.STATE_DISCONNECTED,
-                        true, 0);
-            }
-            mAudioManager.setBluetoothHearingAidDeviceConnectionState(
-                    device, BluetoothProfile.STATE_CONNECTED,
-                    true, 0);
-            mPreviousAudioDevice = device;
+        boolean stopAudio = device == null
+                && (getConnectionState(mPreviousAudioDevice) != BluetoothProfile.STATE_CONNECTED);
+        if (DBG) {
+            Log.d(TAG, "Hearing Aid audio: " + mPreviousAudioDevice + " -> " + device
+                    + ". Stop audio: " + stopAudio);
         }
+        mAudioManager.handleBluetoothActiveDeviceChanged(device, mPreviousAudioDevice,
+                BtProfileConnectionInfo.hearingAidInfo(!stopAudio));
+        mPreviousAudioDevice = device;
     }
 
     // Remove state machine if the bonding for a device is removed
diff --git a/src/com/android/bluetooth/hfp/HeadsetPhoneState.java b/src/com/android/bluetooth/hfp/HeadsetPhoneState.java
index 50094cf1..4bf7530 100644
--- a/src/com/android/bluetooth/hfp/HeadsetPhoneState.java
+++ b/src/com/android/bluetooth/hfp/HeadsetPhoneState.java
@@ -70,6 +70,8 @@
     private final HashMap<BluetoothDevice, Integer> mDeviceEventMap = new HashMap<>();
     private PhoneStateListener mPhoneStateListener;
     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
+    // TODO(b/205585585): Re-enable SignalStrengthUpdateRequest to support "always report signal
+    // strength" when the crash is fixed.
 
     HeadsetPhoneState(HeadsetService headsetService) {
         Objects.requireNonNull(headsetService, "headsetService is null");
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
index 9548eac..7c3784e 100644
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -1645,7 +1645,7 @@
             // Suspend A2DP when call about is about to become active
             if (mActiveDevice != null && callState != HeadsetHalConstants.CALL_STATE_DISCONNECTED
                     && !mSystemInterface.isCallIdle() && isCallIdleBefore) {
-                mSystemInterface.getAudioManager().setParameters("A2dpSuspended=true");
+                mSystemInterface.getAudioManager().setA2dpSuspended(true);
             }
         });
         doForEachConnectedStateMachine(
@@ -1655,7 +1655,7 @@
             if (callState == HeadsetHalConstants.CALL_STATE_IDLE
                     && mSystemInterface.isCallIdle() && !isAudioOn()) {
                 // Resume A2DP when call ended and SCO is not connected
-                mSystemInterface.getAudioManager().setParameters("A2dpSuspended=false");
+                mSystemInterface.getAudioManager().setA2dpSuspended(false);
             }
         });
 
@@ -1813,7 +1813,7 @@
                 }
                 // Unsuspend A2DP when SCO connection is gone and call state is idle
                 if (mSystemInterface.isCallIdle()) {
-                    mSystemInterface.getAudioManager().setParameters("A2dpSuspended=false");
+                    mSystemInterface.getAudioManager().setA2dpSuspended(false);
                 }
             }
         }
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index cddb9cc..369b5d5 100644
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -80,12 +80,6 @@
     private static final String TAG = "HeadsetStateMachine";
     private static final boolean DBG = false;
 
-    private static final String HEADSET_NAME = "bt_headset_name";
-    private static final String HEADSET_NREC = "bt_headset_nrec";
-    private static final String HEADSET_WBS = "bt_wbs";
-    private static final String HEADSET_AUDIO_FEATURE_ON = "on";
-    private static final String HEADSET_AUDIO_FEATURE_OFF = "off";
-
     static final int CONNECT = 1;
     static final int DISCONNECT = 2;
     static final int CONNECT_AUDIO = 3;
@@ -147,8 +141,9 @@
     private HeadsetAgIndicatorEnableState mAgIndicatorEnableState;
     // The timestamp when the device entered connecting/connected state
     private long mConnectingTimestampMs = Long.MIN_VALUE;
-    // Audio Parameters like NREC
-    private final HashMap<String, String> mAudioParams = new HashMap<>();
+    // Audio Parameters
+    private boolean mHasNrecEnabled = false;
+    private boolean mHasWbsEnabled = false;
     // AT Phone book keeps a group of states used by AT+CPBR commands
     private final AtPhonebook mPhonebook;
     // HSP specific
@@ -227,7 +222,8 @@
         if (mPhonebook != null) {
             mPhonebook.cleanup();
         }
-        mAudioParams.clear();
+        mHasWbsEnabled = false;
+        mHasNrecEnabled = false;
     }
 
     public void dump(StringBuilder sb) {
@@ -322,8 +318,7 @@
             BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_SCO_CONNECTION_STATE_CHANGED,
                     mAdapterService.obfuscateAddress(device),
                     getConnectionStateFromAudioState(toState),
-                    TextUtils.equals(mAudioParams.get(HEADSET_WBS), HEADSET_AUDIO_FEATURE_ON)
-                            ? BluetoothHfpProtoEnums.SCO_CODEC_MSBC
+                    mHasWbsEnabled ? BluetoothHfpProtoEnums.SCO_CODEC_MSBC
                             : BluetoothHfpProtoEnums.SCO_CODEC_CVSD,
                     mAdapterService.getMetricId(device));
             mHeadsetService.onAudioStateChangedFromStateMachine(device, fromState, toState);
@@ -456,7 +451,8 @@
             mPhonebook.resetAtState();
             updateAgIndicatorEnableState(null);
             mNeedDialingOutReply = false;
-            mAudioParams.clear();
+            mHasWbsEnabled = false;
+            mHasNrecEnabled = false;
             broadcastStateTransitions();
             // Remove the state machine for unbonded devices
             if (mPrevState != null
@@ -864,6 +860,11 @@
                     break;
                 }
                 case DEVICE_STATE_CHANGED:
+                    if (mDeviceSilenced) {
+                        stateLogW("DEVICE_STATE_CHANGED: " + mDevice
+                                + " is silenced, skip notify state changed.");
+                        break;
+                    }
                     mNativeInterface.notifyDeviceStatus(mDevice, (HeadsetDeviceState) message.obj);
                     break;
                 case SEND_CCLC_RESPONSE:
@@ -1083,9 +1084,9 @@
                 break;
                 case CONNECT_AUDIO:
                     stateLogD("CONNECT_AUDIO, device=" + mDevice);
-                    mSystemInterface.getAudioManager().setParameters("A2dpSuspended=true");
+                    mSystemInterface.getAudioManager().setA2dpSuspended(true);
                     if (!mNativeInterface.connectAudio(mDevice)) {
-                        mSystemInterface.getAudioManager().setParameters("A2dpSuspended=false");
+                        mSystemInterface.getAudioManager().setA2dpSuspended(false);
                         stateLogE("Failed to connect SCO audio for " + mDevice);
                         // No state change involved, fire broadcast immediately
                         broadcastAudioState(mDevice, BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
@@ -1530,15 +1531,12 @@
     }
 
     private void setAudioParameters() {
-        String keyValuePairs = String.join(";", new String[]{
-                HEADSET_NAME + "=" + getCurrentDeviceName(),
-                HEADSET_NREC + "=" + mAudioParams.getOrDefault(HEADSET_NREC,
-                        HEADSET_AUDIO_FEATURE_OFF),
-                HEADSET_WBS + "=" + mAudioParams.getOrDefault(HEADSET_WBS,
-                        HEADSET_AUDIO_FEATURE_OFF)
-        });
-        Log.i(TAG, "setAudioParameters for " + mDevice + ": " + keyValuePairs);
-        mSystemInterface.getAudioManager().setParameters(keyValuePairs);
+        AudioManager am = mSystemInterface.getAudioManager();
+        Log.i(TAG, "setAudioParameters for " + mDevice + ":"
+                + " Name=" + getCurrentDeviceName()
+                + " hasNrecEnabled=" + mHasNrecEnabled
+                + " hasWbsEnabled=" + mHasWbsEnabled);
+        am.setBluetoothHeadsetProperties(getCurrentDeviceName(), mHasNrecEnabled, mHasWbsEnabled);
     }
 
     private String parseUnknownAt(String atString) {
@@ -1667,32 +1665,28 @@
     }
 
     private void processNoiseReductionEvent(boolean enable) {
-        String prevNrec = mAudioParams.getOrDefault(HEADSET_NREC, HEADSET_AUDIO_FEATURE_OFF);
-        String newNrec = enable ? HEADSET_AUDIO_FEATURE_ON : HEADSET_AUDIO_FEATURE_OFF;
-        mAudioParams.put(HEADSET_NREC, newNrec);
-        log("processNoiseReductionEvent: " + HEADSET_NREC + " change " + prevNrec + " -> "
-                + newNrec);
+        log("processNoiseReductionEvent: " + mHasNrecEnabled + " -> " + enable);
+        mHasNrecEnabled = enable;
         if (getAudioState() == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
             setAudioParameters();
         }
     }
 
     private void processWBSEvent(int wbsConfig) {
-        String prevWbs = mAudioParams.getOrDefault(HEADSET_WBS, HEADSET_AUDIO_FEATURE_OFF);
+        boolean prevWbs = mHasWbsEnabled;
         switch (wbsConfig) {
             case HeadsetHalConstants.BTHF_WBS_YES:
-                mAudioParams.put(HEADSET_WBS, HEADSET_AUDIO_FEATURE_ON);
+                mHasWbsEnabled = true;
                 break;
             case HeadsetHalConstants.BTHF_WBS_NO:
             case HeadsetHalConstants.BTHF_WBS_NONE:
-                mAudioParams.put(HEADSET_WBS, HEADSET_AUDIO_FEATURE_OFF);
+                mHasWbsEnabled = false;
                 break;
             default:
                 Log.e(TAG, "processWBSEvent: unknown wbsConfig " + wbsConfig);
                 return;
         }
-        log("processWBSEvent: " + HEADSET_NREC + " change " + prevWbs + " -> " + mAudioParams.get(
-                HEADSET_WBS));
+        log("processWBSEvent: " + prevWbs + " -> " + mHasWbsEnabled);
     }
 
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@@ -2075,7 +2069,7 @@
             events |= PhoneStateListener.LISTEN_SERVICE_STATE;
         }
         if (mAgIndicatorEnableState != null && mAgIndicatorEnableState.signal) {
-            events |= PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH;
+            events |= PhoneStateListener.LISTEN_SIGNAL_STRENGTHS;
         }
         mSystemInterface.getHeadsetPhoneState().listenForPhoneState(mDevice, events);
     }
diff --git a/src/com/android/bluetooth/hfpclient/HeadsetClientService.java b/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
index 23e8e58..8c45847 100644
--- a/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
+++ b/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
@@ -111,7 +111,7 @@
                 Log.e(TAG, "AudioManager service doesn't exist?");
             } else {
                 // start AudioManager in a known state
-                mAudioManager.setParameters("hfp_enable=false");
+                mAudioManager.setHfpEnabled(false);
             }
 
             mSmFactory = new HeadsetClientStateMachineFactory();
@@ -200,7 +200,7 @@
                                 "Setting volume to audio manager: " + streamValue + " hands free: "
                                         + hfVol);
                     }
-                    mAudioManager.setParameters("hfp_volume=" + hfVol);
+                    mAudioManager.setHfpVolume(hfVol);
                     synchronized (mStateMachineMap) {
                         for (HeadsetClientStateMachine sm : mStateMachineMap.values()) {
                             if (sm != null) {
diff --git a/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java b/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
index 9f724a6..13eeee9 100644
--- a/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
+++ b/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
@@ -815,9 +815,9 @@
         }
         logD("hfp_enable=" + enable);
         if (enable && !sAudioIsRouted) {
-            mAudioManager.setParameters("hfp_enable=true");
+            mAudioManager.setHfpEnabled(true);
         } else if (!enable) {
-            mAudioManager.setParameters("hfp_enable=false");
+            mAudioManager.setHfpEnabled(false);
         }
         sAudioIsRouted = enable;
     }
@@ -1592,7 +1592,7 @@
                     // routing is handled by the bluetooth stack itself. The only reason to do so is
                     // because Bluetooth SCO connection from the HF role is not entirely supported
                     // for routing and volume purposes.
-                    // NOTE: All calls here are routed via the setParameters which changes the
+                    // NOTE: All calls here are routed via AudioManager methods which changes the
                     // routing at the Audio HAL level.
 
                     if (mService.isScoRouted()) {
@@ -1614,15 +1614,15 @@
                     logD("hfp_enable=true mAudioWbs is " + mAudioWbs);
                     if (mAudioWbs) {
                         logD("Setting sampling rate as 16000");
-                        mAudioManager.setParameters("hfp_set_sampling_rate=16000");
+                        mAudioManager.setHfpSamplingRate(16000);
                     } else {
                         logD("Setting sampling rate as 8000");
-                        mAudioManager.setParameters("hfp_set_sampling_rate=8000");
+                        mAudioManager.setHfpSamplingRate(8000);
                     }
                     logD("hf_volume " + hfVol);
                     routeHfpAudio(true);
                     mAudioFocusRequest = requestAudioFocus();
-                    mAudioManager.setParameters("hfp_volume=" + hfVol);
+                    mAudioManager.setHfpVolume(hfVol);
                     transitionTo(mAudioOn);
                     break;
 
diff --git a/src/com/android/bluetooth/hfpclient/OWNERS b/src/com/android/bluetooth/hfpclient/OWNERS
index 06dc3f8..fd47bd7 100644
--- a/src/com/android/bluetooth/hfpclient/OWNERS
+++ b/src/com/android/bluetooth/hfpclient/OWNERS
@@ -1 +1 @@
-include platform/system/bt:/OWNERS_automotive
+include platform/packages/modules/Bluetooth:/OWNERS_automotive
diff --git a/src/com/android/bluetooth/le_audio/LeAudioService.java b/src/com/android/bluetooth/le_audio/LeAudioService.java
index b03b161..77bc559 100644
--- a/src/com/android/bluetooth/le_audio/LeAudioService.java
+++ b/src/com/android/bluetooth/le_audio/LeAudioService.java
@@ -23,16 +23,12 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
-import android.bluetooth.BluetoothVolumeControl;
-import android.bluetooth.IBluetoothCsipSetCoordinator;
-import android.bluetooth.IBluetoothCsipSetCoordinatorCallback;
 import android.bluetooth.IBluetoothLeAudio;
-import android.content.AttributionSource;
 import android.bluetooth.IBluetoothVolumeControl;
+import android.content.AttributionSource;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -40,6 +36,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.media.AudioManager;
+import android.media.BtProfileConnectionInfo;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.ParcelUuid;
@@ -51,7 +48,6 @@
 import com.android.bluetooth.btservice.ProfileService;
 import com.android.bluetooth.btservice.ServiceFactory;
 import com.android.bluetooth.btservice.storage.DatabaseManager;
-import com.android.bluetooth.csip.CsipSetCoordinatorService;
 import com.android.bluetooth.mcp.McpService;
 import com.android.bluetooth.vc.VolumeControlService;
 import com.android.internal.annotations.VisibleForTesting;
@@ -93,8 +89,8 @@
     private AdapterService mAdapterService;
     private DatabaseManager mDatabaseManager;
     private HandlerThread mStateMachinesThread;
-    private BluetoothDevice mPreviousAudioOutDevice;
-    private BluetoothDevice mPreviousAudioInDevice;
+    private BluetoothDevice mActiveAudioOutDevice;
+    private BluetoothDevice mActiveAudioInDevice;
     ServiceFactory mServiceFactory = new ServiceFactory();
 
     LeAudioNativeInterface mLeAudioNativeInterface;
@@ -116,7 +112,6 @@
     private final Map<BluetoothDevice, LeAudioStateMachine> mStateMachines = new HashMap<>();
 
     private final Map<BluetoothDevice, Integer> mDeviceGroupIdMap = new ConcurrentHashMap<>();
-    private final Map<BluetoothDevice, Integer> mSetMemberAvailable = new ConcurrentHashMap<>();
     private int mActiveDeviceGroupId = LE_AUDIO_GROUP_ID_INVALID;
     private final int mContextSupportingInputAudio =
             BluetoothLeAudio.CONTEXT_TYPE_COMMUNICATION |
@@ -137,50 +132,6 @@
     private BroadcastReceiver mBondStateChangedReceiver;
     private BroadcastReceiver mConnectionStateChangedReceiver;
 
-    class MyCsipSetCoordinatorCallbacks extends IBluetoothCsipSetCoordinatorCallback.Stub {
-        @Override
-        public void onCsisSetMemberAvailable(BluetoothDevice device, int groupId) {
-            synchronized (LeAudioService.this) {
-                LeAudioService.this.setMemberAvailable(device, groupId);
-            }
-        }
-    };
-
-    private volatile MyCsipSetCoordinatorCallbacks mCsipSetCoordinatorCallback =
-                                                            new MyCsipSetCoordinatorCallbacks();
-    private volatile IBluetoothCsipSetCoordinator mCsipSetCoordinatorProxy;
-    private final ServiceConnection mCsipSetCoordinatorProxyConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            if (DBG) {
-                Log.d(TAG, "CsisClientProxy connected");
-            }
-            synchronized (LeAudioService.this) {
-                mCsipSetCoordinatorProxy = IBluetoothCsipSetCoordinator.Stub.asInterface(service);
-                CsipSetCoordinatorService mCsipSetCoordinatorService =
-                    CsipSetCoordinatorService.getCsipSetCoordinatorService();
-                if (mCsipSetCoordinatorService == null) {
-                    Log.e(TAG, "CsisClientService is null on LeAudioService starts");
-                    return;
-                }
-                mCsipSetCoordinatorService.registerCsisMemberObserver(
-                                                    LeAudioService.this.getMainExecutor(),
-                                                    BluetoothUuid.CAP,
-                                                    mCsipSetCoordinatorCallback);
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName className) {
-            if (DBG) {
-                Log.d(TAG, "CsisClientProxy disconnected");
-            }
-            synchronized (LeAudioService.this) {
-                mCsipSetCoordinatorProxy = null;
-            }
-        }
-    };
-
     private volatile IBluetoothVolumeControl mVolumeControlProxy;
     VolumeControlService mVolumeControlService = null;
     private final ServiceConnection mVolumeControlProxyConnection = new ServiceConnection() {
@@ -245,7 +196,6 @@
         mStateMachinesThread.start();
 
         mDeviceGroupIdMap.clear();
-        mSetMemberAvailable.clear();
         mGroupDescriptors.clear();
 
         // Setup broadcast receivers
@@ -258,8 +208,6 @@
         mConnectionStateChangedReceiver = new ConnectionStateChangedReceiver();
         registerReceiver(mConnectionStateChangedReceiver, filter);
 
-        /* Bind Csis Service */
-        bindCsisClientService();
 
         /* Bind Volume control service */
         bindVolumeControlService();
@@ -317,7 +265,6 @@
         }
 
         mDeviceGroupIdMap.clear();
-        mSetMemberAvailable.clear();
         mGroupDescriptors.clear();
 
         if (mStateMachinesThread != null) {
@@ -329,7 +276,6 @@
         mAdapterService = null;
         mAudioManager = null;
 
-        unbindCsisClientService();
         unbindVolumeControlService();
         return true;
     }
@@ -382,30 +328,6 @@
         }
     }
 
-    private void bindCsisClientService() {
-        synchronized (mCsipSetCoordinatorProxyConnection) {
-            Intent intent = new Intent(IBluetoothCsipSetCoordinator.class.getName());
-            ComponentName comp = intent.resolveSystemService(getPackageManager(), 0);
-            intent.setComponent(comp);
-            if (comp == null || !bindService(intent, mCsipSetCoordinatorProxyConnection, 0)) {
-                Log.wtf(TAG, "Could not bind to IBluetoothCsisClient Service with " +
-                        intent);
-            }
-        }
-    }
-    private void unbindCsisClientService() {
-        synchronized (mCsipSetCoordinatorProxyConnection) {
-            if (mCsipSetCoordinatorProxy != null) {
-                if (DBG) {
-                    Log.d(TAG, "Unbinding CsisClientProxyConnection");
-                }
-                mCsipSetCoordinatorProxy = null;
-                // Synchronization should make sure unbind can be successful
-                unbindService(mCsipSetCoordinatorProxyConnection);
-            }
-        }
-    }
-
     public boolean connect(BluetoothDevice device) {
         if (DBG) {
             Log.d(TAG, "connect(): " + device);
@@ -421,12 +343,6 @@
             return false;
         }
 
-        int groupId = getGroupId(device);
-
-        if (DBG) {
-            Log.d(TAG, "connect(): " + device + " group id: " + groupId);
-        }
-
         synchronized (mStateMachines) {
             LeAudioStateMachine sm = getOrCreateStateMachine(device);
             if (sm == null) {
@@ -437,25 +353,7 @@
         }
 
         // Connect other devices from this group
-        if (groupId != LE_AUDIO_GROUP_ID_INVALID) {
-            for (BluetoothDevice storedDevice : mDeviceGroupIdMap.keySet()) {
-                if (device.equals(storedDevice)) {
-                    continue;
-                }
-                if (getGroupId(storedDevice) != groupId) {
-                    continue;
-                }
-                synchronized (mStateMachines) {
-                     LeAudioStateMachine sm = getOrCreateStateMachine(storedDevice);
-                     if (sm == null) {
-                         Log.e(TAG, "Ignored connect request for " + storedDevice
-                                 + " : no state machine");
-                         continue;
-                     }
-                     sm.sendMessage(LeAudioStateMachine.CONNECT);
-                 }
-             }
-         }
+        connectSet(device);
 
         return true;
     }
@@ -507,7 +405,7 @@
         return true;
     }
 
-    List<BluetoothDevice> getConnectedDevices() {
+    public List<BluetoothDevice> getConnectedDevices() {
         synchronized (mStateMachines) {
             List<BluetoothDevice> devices = new ArrayList<>();
             for (LeAudioStateMachine sm : mStateMachines.values()) {
@@ -675,9 +573,9 @@
         return null;
     }
 
-    private void updateActiveInDevice(BluetoothDevice device, Integer groupId, Integer oldActiveContexts,
-    Integer newActiveContexts) {
-
+    private boolean updateActiveInDevice(BluetoothDevice device, Integer groupId,
+                                            Integer oldActiveContexts,
+                                            Integer newActiveContexts) {
         Integer oldSupportedAudioDirections =
                 getAudioDirectionsFromActiveContextsMap(oldActiveContexts);
         Integer newSupportedAudioDirections =
@@ -688,51 +586,47 @@
         boolean newSupportedByDeviceInput = (newSupportedAudioDirections
                 & AUDIO_DIRECTION_INPUT_BIT) != 0;
 
-        if (device != null && mPreviousAudioInDevice != null) {
-            int previousGroupId = getGroupId(mPreviousAudioInDevice);
+        if (device != null && mActiveAudioInDevice != null) {
+            int previousGroupId = getGroupId(mActiveAudioInDevice);
             if (previousGroupId == groupId) {
                 /* This is thes same group as aleady notified to the system.
                 * Therefore do not change the device we have connected to the group,
                 * unless, previous one is disconnected now
                 */
-                if (mPreviousAudioInDevice.isConnected())
-                    device = mPreviousAudioInDevice;
+                if (mActiveAudioInDevice.isConnected()) {
+                    device = mActiveAudioInDevice;
+                }
             }
         }
 
-        /* Disconnect input:
-         * - If active input device changed (to none or any)
-         * - If device stops supporting input
+        BluetoothDevice previousInDevice = mActiveAudioInDevice;
+
+        /*
+         * Do not update input if neither previous nor current device support input
          */
-        boolean inActiveDeviceReplace = (device != mPreviousAudioInDevice);
-        if (mPreviousAudioInDevice != null) {
-            mAudioManager.setBluetoothLeAudioInDeviceConnectionState(
-                    mPreviousAudioInDevice, BluetoothProfile.STATE_DISCONNECTED);
+        if (!oldSupportedByDeviceInput && !newSupportedByDeviceInput) {
+            Log.d(TAG, "updateActiveInDevice: Device does not support input.");
+            return false;
         }
 
-        mPreviousAudioInDevice = device;
-
-        if (device == null) {
-            Log.d(TAG,  " device is null.");
-            return;
-        }
-
-        if (inActiveDeviceReplace == false ||
-             (oldSupportedByDeviceInput == newSupportedByDeviceInput)) {
-            Log.d(TAG,  " Nothing to do.");
-            return;
-        }
-
-        /* Connect input:
-         * - If active input device changed
-         * - If device starts support input
+        /*
+         * Update input if:
+         * - Device changed
+         *     OR
+         * - Device stops / starts supporting input
          */
-        mAudioManager.setBluetoothLeAudioInDeviceConnectionState(
-                   device, BluetoothProfile.STATE_CONNECTED);
-
+        if (!Objects.equals(device, previousInDevice)
+                || (oldSupportedByDeviceInput != newSupportedByDeviceInput)) {
+            mActiveAudioInDevice = newSupportedByDeviceInput ? device : null;
+            mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioInDevice, previousInDevice,
+                    BtProfileConnectionInfo.leAudio(false, false));
+            return true;
+        }
+        Log.d(TAG, "updateActiveInDevice: Nothing to do.");
+        return false;
     }
 
-    private void updateActiveOutDevice(BluetoothDevice device, Integer groupId,
+    private boolean updateActiveOutDevice(BluetoothDevice device, Integer groupId,
                                        Integer oldActiveContexts,
                                        Integer newActiveContexts) {
         Integer oldSupportedAudioDirections =
@@ -745,52 +639,46 @@
         boolean newSupportedByDeviceOutput = (newSupportedAudioDirections
                 & AUDIO_DIRECTION_OUTPUT_BIT) != 0;
 
-
-        if (device != null && mPreviousAudioOutDevice != null) {
-            int previousGroupId = getGroupId(mPreviousAudioOutDevice);
+        if (device != null && mActiveAudioOutDevice != null) {
+            int previousGroupId = getGroupId(mActiveAudioOutDevice);
             if (previousGroupId == groupId) {
-                /* This is thes same group as aleady notified to the system.
+                /* This is the same group as already notified to the system.
                 * Therefore do not change the device we have connected to the group,
                 * unless, previous one is disconnected now
                 */
-             if (mPreviousAudioOutDevice.isConnected())
-                device = mPreviousAudioOutDevice;
+                if (mActiveAudioOutDevice.isConnected()) {
+                    device = mActiveAudioOutDevice;
+                }
             }
         }
 
-         /* Disconnect output:
-         * - If active output device changed (to none or any)
-         * - If device stops supporting output
+        BluetoothDevice previousOutDevice = mActiveAudioOutDevice;
+
+        /*
+         * Do not update output if neither previous nor current device support output
          */
-        boolean outActiveDeviceReplace = (device != mPreviousAudioOutDevice);
-        if (mPreviousAudioOutDevice != null) {
-            boolean suppressNoisyIntent =
-                    (getConnectionState(mPreviousAudioOutDevice) ==
-                    BluetoothProfile.STATE_CONNECTED);
-            mAudioManager.setBluetoothLeAudioOutDeviceConnectionState(
-                    mPreviousAudioOutDevice, BluetoothProfile.STATE_DISCONNECTED,
-                    suppressNoisyIntent);
+        if (!oldSupportedByDeviceOutput && !newSupportedByDeviceOutput) {
+            Log.d(TAG, "updateActiveOutDevice: Device does not support output.");
+            return false;
         }
 
-        mPreviousAudioOutDevice = device;
-
-        if (device == null) {
-            Log.d(TAG,  " device is null.");
-            return;
-        }
-
-        if (outActiveDeviceReplace == false ||
-            (oldSupportedByDeviceOutput == newSupportedByDeviceOutput)) {
-            Log.d(TAG,  " Nothing to do.");
-            return;
-        }
-
-        /* Connect output:
-         * - If active output device changed
-         * - If device starts support output
+        /*
+         * Update output if:
+         * - Device changed
+         *     OR
+         * - Device stops / starts supporting output
          */
-         mAudioManager.setBluetoothLeAudioOutDeviceConnectionState(
-                    device, BluetoothProfile.STATE_CONNECTED, true);
+        if (!Objects.equals(device, previousOutDevice)
+                || (oldSupportedByDeviceOutput != newSupportedByDeviceOutput)) {
+            mActiveAudioOutDevice = newSupportedByDeviceOutput ? device : null;
+            final boolean suppressNoisyIntent = (mActiveAudioOutDevice != null)
+                    || (getConnectionState(previousOutDevice) == BluetoothProfile.STATE_CONNECTED);
+            mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioOutDevice,
+                    previousOutDevice, BtProfileConnectionInfo.leAudio(suppressNoisyIntent, true));
+            return true;
+        }
+        Log.d(TAG, "updateActiveOutDevice: Nothing to do.");
+        return false;
     }
 
     /**
@@ -806,14 +694,18 @@
         if (isActive)
             device = getFirstDeviceFromGroup(groupId);
 
-        updateActiveOutDevice(device, groupId, oldActiveContexts, newActiveContexts);
-        updateActiveInDevice(device, groupId, oldActiveContexts, newActiveContexts);
+        boolean outReplaced =
+            updateActiveOutDevice(device, groupId, oldActiveContexts, newActiveContexts);
+        boolean inReplaced =
+            updateActiveInDevice(device, groupId, oldActiveContexts, newActiveContexts);
 
-        Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
-        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mPreviousAudioOutDevice);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
-                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-        sendBroadcast(intent, BLUETOOTH_CONNECT);
+        if (outReplaced || inReplaced) {
+            Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
+            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mActiveAudioOutDevice);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+            sendBroadcast(intent, BLUETOOTH_CONNECT);
+        }
     }
 
     /**
@@ -889,6 +781,42 @@
         return activeDevices;
     }
 
+    void connectSet(BluetoothDevice device) {
+        int groupId = getGroupId(device);
+        if (groupId == LE_AUDIO_GROUP_ID_INVALID) {
+            return;
+        }
+
+        if (DBG) {
+            Log.d(TAG, "connect() others from group id: " + groupId);
+        }
+
+        for (BluetoothDevice storedDevice : mDeviceGroupIdMap.keySet()) {
+            if (device.equals(storedDevice)) {
+                continue;
+            }
+
+            if (getGroupId(storedDevice) != groupId) {
+                continue;
+            }
+
+            if (DBG) {
+                Log.d(TAG, "connect(): " + device);
+            }
+
+            synchronized (mStateMachines) {
+                 LeAudioStateMachine sm = getOrCreateStateMachine(storedDevice);
+                 if (sm == null) {
+                     Log.e(TAG, "Ignored connect request for " + storedDevice
+                             + " : no state machine");
+                     continue;
+                 }
+                 sm.sendMessage(LeAudioStateMachine.CONNECT);
+             }
+         }
+
+    }
+
     // Suppressed since this is part of a local process
     @SuppressLint("AndroidFrameworkRequiresPermission")
     void messageFromNative(LeAudioStackEvent stackEvent) {
@@ -905,6 +833,8 @@
                         case LeAudioStackEvent.CONNECTION_STATE_CONNECTED:
                         case LeAudioStackEvent.CONNECTION_STATE_CONNECTING:
                             sm = getOrCreateStateMachine(device);
+                            /* Incoming connection try to connect other devices from the group */
+                            connectSet(device);
                             break;
                         default:
                             break;
@@ -976,6 +906,7 @@
         } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED) {
             int group_id = stackEvent.valueInt1;
             int group_status = stackEvent.valueInt2;
+            boolean send_intent = false;
 
             switch (group_status) {
                 case LeAudioStackEvent.GROUP_STATUS_ACTIVE: {
@@ -985,6 +916,7 @@
                             descriptor.mIsActive = true;
                             updateActiveDevices(group_id, ACTIVE_CONTEXTS_NONE,
                                                 descriptor.mActiveContexts, descriptor.mIsActive);
+                            send_intent = true;
                         }
                     } else {
                         Log.e(TAG, "no descriptors for group: " + group_id);
@@ -998,6 +930,7 @@
                             descriptor.mIsActive = false;
                             updateActiveDevices(group_id, descriptor.mActiveContexts,
                                     ACTIVE_CONTEXTS_NONE, descriptor.mIsActive);
+                            send_intent = true;
                         }
                     } else {
                         Log.e(TAG, "no descriptors for group: " + group_id);
@@ -1008,10 +941,11 @@
                     break;
             }
 
-            intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_GROUP_STATUS_CHANGED);
-            intent.putExtra(BluetoothLeAudio.EXTRA_LE_AUDIO_GROUP_ID, group_id);
-            intent.putExtra(BluetoothLeAudio.EXTRA_LE_AUDIO_GROUP_STATUS, group_status);
-
+            if (send_intent) {
+                intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_GROUP_STATUS_CHANGED);
+                intent.putExtra(BluetoothLeAudio.EXTRA_LE_AUDIO_GROUP_ID, group_id);
+                intent.putExtra(BluetoothLeAudio.EXTRA_LE_AUDIO_GROUP_STATUS, group_status);
+            }
         }
 
         if (intent != null) {
@@ -1079,11 +1013,6 @@
             return;
         }
 
-        /* Remove bonded set member from outstanding list */
-        if (mSetMemberAvailable.containsKey(device)) {
-            mSetMemberAvailable.remove(device);
-        }
-
         int groupId = getGroupId(device);
         if (groupId != LE_AUDIO_GROUP_ID_INVALID) {
             /* In case device is still in the group, let's remove it */
@@ -1221,22 +1150,6 @@
         }
     }
 
-    synchronized void setMemberAvailable(BluetoothDevice device, int groupId) {
-        if (device == null) {
-            Log.e(TAG, "unexpected invocation. device=" + device);
-            return;
-        }
-
-        if (mSetMemberAvailable.containsKey(device)) {
-            if (DBG) {
-                Log.d(TAG, "Device " + device + " is already notified- drop it");
-            }
-            return;
-        }
-
-        mSetMemberAvailable.put(device, groupId);
-    }
-
    /**
      * Check whether can connect to a peer device.
      * The check considers a number of factors during the evaluation.
diff --git a/src/com/android/bluetooth/mapclient/OWNERS b/src/com/android/bluetooth/mapclient/OWNERS
index 06dc3f8..fd47bd7 100644
--- a/src/com/android/bluetooth/mapclient/OWNERS
+++ b/src/com/android/bluetooth/mapclient/OWNERS
@@ -1 +1 @@
-include platform/system/bt:/OWNERS_automotive
+include platform/packages/modules/Bluetooth:/OWNERS_automotive
diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapUtils.java b/src/com/android/bluetooth/pbap/BluetoothPbapUtils.java
index 7691c3f..df78600 100644
--- a/src/com/android/bluetooth/pbap/BluetoothPbapUtils.java
+++ b/src/com/android/bluetooth/pbap/BluetoothPbapUtils.java
@@ -49,7 +49,18 @@
     private static final String TAG = "BluetoothPbapUtils";
     private static final boolean V = BluetoothPbapService.VERBOSE;
 
+    // Filter constants from Bluetooth PBAP specification
     private static final int FILTER_PHOTO = 3;
+    private static final int FILTER_BDAY = 4;
+    private static final int FILTER_ADDRESS = 5;
+    private static final int FILTER_LABEL = 6;
+    private static final int FILTER_EMAIL = 8;
+    private static final int FILTER_MAILER = 9;
+    private static final int FILTER_ORG = 16;
+    private static final int FILTER_NOTE = 17;
+    private static final int FILTER_SOUND = 19;
+    private static final int FILTER_URL = 20;
+    private static final int FILTER_NICKNAME = 23;
 
     private static final long QUERY_CONTACT_RETRY_INTERVAL = 4000;
 
@@ -122,6 +133,40 @@
             }
             vType |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT;
         }
+        if (hasFilter(filter)) {
+            if (!isFilterBitSet(filter, FILTER_ADDRESS) && !isFilterBitSet(filter, FILTER_LABEL)) {
+                Log.i(TAG, "Excluding addresses from VCardComposer...");
+                vType |= VCardConfig.FLAG_REFRAIN_ADDRESS_EXPORT;
+            }
+            if (!isFilterBitSet(filter, FILTER_EMAIL) && !isFilterBitSet(filter, FILTER_MAILER)) {
+                Log.i(TAG, "Excluding email addresses from VCardComposer...");
+                vType |= VCardConfig.FLAG_REFRAIN_EMAIL_EXPORT;
+            }
+            if (!isFilterBitSet(filter, FILTER_ORG)) {
+                Log.i(TAG, "Excluding organization from VCardComposer...");
+                vType |= VCardConfig.FLAG_REFRAIN_ORGANIZATION_EXPORT;
+            }
+            if (!isFilterBitSet(filter, FILTER_URL)) {
+                Log.i(TAG, "Excluding URLS from VCardComposer...");
+                vType |= VCardConfig.FLAG_REFRAIN_WEBSITES_EXPORT;
+            }
+            if (!isFilterBitSet(filter, FILTER_NOTE)) {
+                Log.i(TAG, "Excluding notes from VCardComposer...");
+                vType |= VCardConfig.FLAG_REFRAIN_NOTES_EXPORT;
+            }
+            if (!isFilterBitSet(filter, FILTER_NICKNAME)) {
+                Log.i(TAG, "Excluding nickname from VCardComposer...");
+                vType |= VCardConfig.FLAG_REFRAIN_NICKNAME_EXPORT;
+            }
+            if (!isFilterBitSet(filter, FILTER_SOUND)) {
+                Log.i(TAG, "Excluding phonetic name from VCardComposer...");
+                vType |= VCardConfig.FLAG_REFRAIN_PHONETIC_NAME_EXPORT;
+            }
+            if (!isFilterBitSet(filter, FILTER_BDAY)) {
+                Log.i(TAG, "Excluding birthday from VCardComposer...");
+                vType |= VCardConfig.FLAG_REFRAIN_EVENTS_EXPORT;
+            }
+        }
         return new VCardComposer(ctx, vType, true);
     }
 
diff --git a/src/com/android/bluetooth/pbapclient/OWNERS b/src/com/android/bluetooth/pbapclient/OWNERS
index 06dc3f8..fd47bd7 100644
--- a/src/com/android/bluetooth/pbapclient/OWNERS
+++ b/src/com/android/bluetooth/pbapclient/OWNERS
@@ -1 +1 @@
-include platform/system/bt:/OWNERS_automotive
+include platform/packages/modules/Bluetooth:/OWNERS_automotive
diff --git a/src/com/android/bluetooth/vc/VolumeControlService.java b/src/com/android/bluetooth/vc/VolumeControlService.java
index cb22e4d..b47a0ff 100644
--- a/src/com/android/bluetooth/vc/VolumeControlService.java
+++ b/src/com/android/bluetooth/vc/VolumeControlService.java
@@ -260,7 +260,7 @@
     }
 
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
-    List<BluetoothDevice> getConnectedDevices() {
+    public List<BluetoothDevice> getConnectedDevices() {
         enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
                 "Need BLUETOOTH_PRIVILEGED permission");
         synchronized (mStateMachines) {
diff --git a/tests/OWNERS b/tests/OWNERS
index 06dc3f8..fd47bd7 100644
--- a/tests/OWNERS
+++ b/tests/OWNERS
@@ -1 +1 @@
-include platform/system/bt:/OWNERS_automotive
+include platform/packages/modules/Bluetooth:/OWNERS_automotive
diff --git a/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java b/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
index 71843c5..ef26da1 100644
--- a/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
@@ -97,6 +97,7 @@
     private @Mock Binder mBinder;
     private @Mock AudioManager mAudioManager;
     private @Mock android.app.Application mApplication;
+    private @Mock MetricsLogger mMockMetricsLogger;
 
     // BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
     // underlying binder calls.
@@ -215,6 +216,10 @@
         when(mMockService.getName()).thenReturn("Service1");
         when(mMockService2.getName()).thenReturn("Service2");
 
+        when(mMockMetricsLogger.init(any())).thenReturn(true);
+        when(mMockMetricsLogger.close()).thenReturn(true);
+        mAdapterService.setMetricsLogger(mMockMetricsLogger);
+
         // Attach a context to the service for permission checks.
         mAdapterService.attach(mMockContext, null, null, null, mApplication, null);
         mAdapterService.onCreate();
diff --git a/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java b/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java
index cc4e8b7..235a25c 100644
--- a/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java
+++ b/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java
@@ -15,9 +15,13 @@
  */
 package com.android.bluetooth.btservice;
 
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.bluetooth.btservice.AdapterService;
 import com.android.bluetooth.BluetoothMetricsProto.BluetoothLog;
 import com.android.bluetooth.BluetoothMetricsProto.ProfileConnectionStats;
 import com.android.bluetooth.BluetoothMetricsProto.ProfileId;
@@ -27,6 +31,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.HashMap;
 import java.util.List;
@@ -37,17 +43,42 @@
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class MetricsLoggerTest {
+    private TestableMetricsLogger mTestableMetricsLogger;
+    @Mock
+    private AdapterService mMockAdapterService;
+
+    public class TestableMetricsLogger extends MetricsLogger {
+        public HashMap<Integer, Long> mTestableCounters = new HashMap<>();
+
+        @Override
+        protected void writeCounter(int key, long count) {
+            mTestableCounters.put(key, count);
+        }
+
+        @Override
+        protected void scheduleDrains() {
+        }
+
+        @Override
+        protected void cancelPendingDrain() {
+        }
+    }
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         // Dump metrics to clean up internal states
         MetricsLogger.dumpProto(BluetoothLog.newBuilder());
+        mTestableMetricsLogger = new TestableMetricsLogger();
+        doReturn(null)
+                .when(mMockAdapterService).registerReceiver(any(), any());
     }
 
     @After
     public void tearDown() {
         // Dump metrics to clean up internal states
         MetricsLogger.dumpProto(BluetoothLog.newBuilder());
+        mTestableMetricsLogger.close();
     }
 
     /**
@@ -104,4 +135,75 @@
         return profileUsageStatsMap;
     }
 
-}
+    /**
+     * Test add counters and send them to westworld
+     */
+    @Test
+    public void testAddAndSendCountersNormalCases() {
+        mTestableMetricsLogger.init(mMockAdapterService);
+        mTestableMetricsLogger.count(1, 10);
+        mTestableMetricsLogger.count(1, 10);
+        mTestableMetricsLogger.count(2, 5);
+        mTestableMetricsLogger.drainBufferedCounters();
+
+        Assert.assertEquals(20L, mTestableMetricsLogger.mTestableCounters.get(1).longValue());
+        Assert.assertEquals(5L, mTestableMetricsLogger.mTestableCounters.get(2).longValue());
+
+        mTestableMetricsLogger.count(1, 3);
+        mTestableMetricsLogger.count(2, 5);
+        mTestableMetricsLogger.count(2, 5);
+        mTestableMetricsLogger.count(3, 1);
+        mTestableMetricsLogger.drainBufferedCounters();
+        Assert.assertEquals(
+                3L, mTestableMetricsLogger.mTestableCounters.get(1).longValue());
+        Assert.assertEquals(
+                10L, mTestableMetricsLogger.mTestableCounters.get(2).longValue());
+        Assert.assertEquals(
+                1L, mTestableMetricsLogger.mTestableCounters.get(3).longValue());
+    }
+
+    @Test
+    public void testAddAndSendCountersCornerCases() {
+        mTestableMetricsLogger.init(mMockAdapterService);
+        Assert.assertTrue(mTestableMetricsLogger.isInitialized());
+        mTestableMetricsLogger.count(1, -1);
+        mTestableMetricsLogger.count(3, 0);
+        mTestableMetricsLogger.count(2, 10);
+        mTestableMetricsLogger.count(2, Long.MAX_VALUE - 8L);
+        mTestableMetricsLogger.drainBufferedCounters();
+
+        Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(1));
+        Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(3));
+        Assert.assertEquals(
+                Long.MAX_VALUE, mTestableMetricsLogger.mTestableCounters.get(2).longValue());
+    }
+
+    @Test
+    public void testMetricsLoggerClose() {
+        mTestableMetricsLogger.init(mMockAdapterService);
+        mTestableMetricsLogger.count(1, 1);
+        mTestableMetricsLogger.count(2, 10);
+        mTestableMetricsLogger.count(2, Long.MAX_VALUE);
+        mTestableMetricsLogger.close();
+
+        Assert.assertEquals(
+                1, mTestableMetricsLogger.mTestableCounters.get(1).longValue());
+        Assert.assertEquals(
+                Long.MAX_VALUE, mTestableMetricsLogger.mTestableCounters.get(2).longValue());
+    }
+
+    @Test
+    public void testMetricsLoggerNotInit() {
+        Assert.assertFalse(mTestableMetricsLogger.count(1, 1));
+        mTestableMetricsLogger.drainBufferedCounters();
+        Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(1));
+        Assert.assertFalse(mTestableMetricsLogger.close());
+    }
+
+    @Test
+    public void testAddAndSendCountersDoubleInit() {
+        Assert.assertTrue(mTestableMetricsLogger.init(mMockAdapterService));
+        Assert.assertTrue(mTestableMetricsLogger.isInitialized());
+        Assert.assertFalse(mTestableMetricsLogger.init(mMockAdapterService));
+    }
+}
\ No newline at end of file
diff --git a/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java b/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java
index 0b3d2bb..557a720 100644
--- a/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java
+++ b/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java
@@ -233,7 +233,7 @@
         verify(mDatabaseManager, never()).setConnection(eq(connectionOrder.get(2)), anyBoolean());
         verify(mDatabaseManager, never()).setConnection(eq(connectionOrder.get(3)), anyBoolean());
 
-        // Disconnect a2dp for the device
+        // Disconnect a2dp for the device from previous STATE_CONNECTED
         when(mHeadsetService.getConnectionState(connectionOrder.get(1))).thenReturn(
                 BluetoothProfile.STATE_DISCONNECTED);
         intent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
@@ -244,6 +244,18 @@
         mPhonePolicy.getBroadcastReceiver().onReceive(null /* context */, intent);
         waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
 
+        // Verify that we do not call setConnection, nor setDisconnection on disconnect
+        // from previous STATE_CONNECTED
+        verify(mDatabaseManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1)).setConnection(
+                connectionOrder.get(1), true);
+        verify(mDatabaseManager, never()).setDisconnection(connectionOrder.get(1));
+
+        // Disconnect a2dp for the device from previous STATE_DISCONNECTING
+        intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE,
+                BluetoothProfile.STATE_DISCONNECTING);
+        mPhonePolicy.getBroadcastReceiver().onReceive(null /* context */, intent);
+        waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+
         // Verify that we do not call setConnection, but instead setDisconnection on disconnect
         verify(mDatabaseManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1)).setConnection(
                 connectionOrder.get(1), true);
diff --git a/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java b/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java
index dab3099..b2996f9 100644
--- a/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java
@@ -28,6 +28,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.media.AudioManager;
+import android.media.BtProfileConnectionInfo;
 import android.os.Looper;
 import android.os.ParcelUuid;
 
@@ -521,9 +522,8 @@
         Assert.assertTrue(mService.getConnectedDevices().contains(mRightDevice));
 
         // Verify the audio is routed to Hearing Aid Profile
-        verify(mAudioManager).setBluetoothHearingAidDeviceConnectionState(
-                any(BluetoothDevice.class), eq(BluetoothProfile.STATE_CONNECTED),
-                eq(true), eq(0));
+        verify(mAudioManager).handleBluetoothActiveDeviceChanged(
+                any(BluetoothDevice.class), eq(null), any(BtProfileConnectionInfo.class));
 
         // Send a disconnect request
         Assert.assertTrue("Disconnect failed", mService.disconnect(mLeftDevice));
@@ -570,9 +570,8 @@
         Assert.assertFalse(mService.getConnectedDevices().contains(mRightDevice));
 
         // Verify the audio is not routed to Hearing Aid Profile
-        verify(mAudioManager).setBluetoothHearingAidDeviceConnectionState(
-                any(BluetoothDevice.class), eq(BluetoothProfile.STATE_DISCONNECTED),
-                eq(false), eq(0));
+        verify(mAudioManager).handleBluetoothActiveDeviceChanged(
+                eq(null), any(BluetoothDevice.class), any(BtProfileConnectionInfo.class));
     }
 
     /**
diff --git a/tests/unit/src/com/android/bluetooth/hfp/HeadsetPhoneStateTest.java b/tests/unit/src/com/android/bluetooth/hfp/HeadsetPhoneStateTest.java
index 99a9f34..130f457 100644
--- a/tests/unit/src/com/android/bluetooth/hfp/HeadsetPhoneStateTest.java
+++ b/tests/unit/src/com/android/bluetooth/hfp/HeadsetPhoneStateTest.java
@@ -137,9 +137,9 @@
     public void testListenForPhoneState_ServiceAndSignalStrength() {
         BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, 1);
         mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
         verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS));
     }
 
     /**
@@ -150,9 +150,9 @@
     public void testListenForPhoneState_ServiceAndSignalStrengthUpdateTurnOffSignalStrengh() {
         BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, 1);
         mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
         verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS));
         mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE);
         verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
         verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE));
@@ -165,9 +165,9 @@
     public void testListenForPhoneState_ServiceAndSignalStrengthUpdateTurnOffAll() {
         BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, 1);
         mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
         verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS));
         mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_NONE);
         verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
     }
@@ -183,12 +183,12 @@
         BluetoothDevice device2 = TestUtils.getTestDevice(mAdapter, 2);
         // Enabling updates from first device should trigger subscription
         mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
         verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS));
         // Enabling updates from second device should not trigger the same subscription
         mHeadsetPhoneState.listenForPhoneState(device2, PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
         // Disabling updates from first device should not cancel subscription
         mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_NONE);
         // Disabling updates from second device should cancel subscription
@@ -211,15 +211,15 @@
         verifyNoMoreInteractions(mTelephonyManager);
         // Partially enabling updates from second device should trigger partial subscription
         mHeadsetPhoneState.listenForPhoneState(device2,
-                PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
+                PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
         verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
         verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS));
         // Partially disabling updates from first device should not cancel all subscription
         mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_NONE);
         verify(mTelephonyManager, times(2)).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
         verify(mTelephonyManager).listen(
-                any(), eq(PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
+                any(), eq(PhoneStateListener.LISTEN_SIGNAL_STRENGTHS));
         // Partially disabling updates from second device should cancel subscription
         mHeadsetPhoneState.listenForPhoneState(device2, PhoneStateListener.LISTEN_NONE);
         verify(mTelephonyManager, times(3)).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
diff --git a/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java b/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
index 7ff5f1c..3ebcc05 100644
--- a/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
+++ b/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
@@ -954,8 +954,7 @@
         mHeadsetService.startVoiceRecognition(deviceA);
         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).atResponseCode(deviceA,
                 HeadsetHalConstants.AT_RESPONSE_OK, 0);
-        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS))
-                .setParameters("A2dpSuspended=true");
+        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setA2dpSuspended(true);
         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connectAudio(deviceA);
         verifyNoMoreInteractions(mNativeInterface);
     }
@@ -1008,8 +1007,7 @@
         // We still continue on the initiating HF
         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).atResponseCode(deviceA,
                 HeadsetHalConstants.AT_RESPONSE_OK, 0);
-        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS))
-                .setParameters("A2dpSuspended=true");
+        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setA2dpSuspended(true);
         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connectAudio(deviceA);
         verifyNoMoreInteractions(mNativeInterface);
     }
@@ -1084,8 +1082,7 @@
         verify(mNativeInterface).setActiveDevice(deviceA);
         Assert.assertEquals(deviceA, mHeadsetService.getActiveDevice());
         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).startVoiceRecognition(deviceA);
-        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS))
-                .setParameters("A2dpSuspended=true");
+        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setA2dpSuspended(true);
         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connectAudio(deviceA);
         waitAndVerifyAudioStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, deviceA,
                 BluetoothHeadset.STATE_AUDIO_CONNECTING, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
@@ -1133,8 +1130,7 @@
         Assert.assertTrue(mHeadsetService.startVoiceRecognition(device));
         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).atResponseCode(device,
                 HeadsetHalConstants.AT_RESPONSE_OK, 0);
-        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS))
-                .setParameters("A2dpSuspended=true");
+        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setA2dpSuspended(true);
         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connectAudio(device);
         waitAndVerifyAudioStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device,
                 BluetoothHeadset.STATE_AUDIO_CONNECTING, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
@@ -1151,8 +1147,7 @@
         Assert.assertNotNull(device);
         Assert.assertTrue(mHeadsetService.startVoiceRecognition(device));
         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).startVoiceRecognition(device);
-        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS))
-                .setParameters("A2dpSuspended=true");
+        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setA2dpSuspended(true);
         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connectAudio(device);
         waitAndVerifyAudioStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device,
                 BluetoothHeadset.STATE_AUDIO_CONNECTING, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
diff --git a/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java b/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
index 1a4e877..d1888bb 100644
--- a/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
@@ -706,7 +706,7 @@
                 headsetCallState.mType, headsetCallState.mName, mAdapter.getAttributionSource());
         TestUtils.waitForLooperToFinishScheduledTask(
                 mHeadsetService.getStateMachinesThreadLooper());
-        verify(mAudioManager, never()).setParameters("A2dpSuspended=true");
+        verify(mAudioManager, never()).setA2dpSuspended(true);
         HeadsetTestUtils.verifyPhoneStateChangeSetters(mPhoneState, headsetCallState,
                 ASYNC_CALL_TIMEOUT_MILLIS);
     }
@@ -765,7 +765,7 @@
                 mHeadsetService.getStateMachinesThreadLooper());
 
         // Should not ask Audio HAL to suspend A2DP without active device
-        verify(mAudioManager, never()).setParameters("A2dpSuspended=true");
+        verify(mAudioManager, never()).setA2dpSuspended(true);
         // Make sure we notify device about this change
         verify(mStateMachines.get(mCurrentDevice)).sendMessage(
                 HeadsetStateMachine.CALL_STATE_CHANGED, headsetCallState);
@@ -783,7 +783,7 @@
         TestUtils.waitForLooperToFinishScheduledTask(
                 mHeadsetService.getStateMachinesThreadLooper());
         // Ask Audio HAL to suspend A2DP
-        verify(mAudioManager).setParameters("A2dpSuspended=true");
+        verify(mAudioManager).setA2dpSuspended(true);
         // Make sure state is updated
         verify(mStateMachines.get(mCurrentDevice)).sendMessage(
                 HeadsetStateMachine.CALL_STATE_CHANGED, headsetCallState);
@@ -847,8 +847,7 @@
                 headsetCallState.mNumHeld, headsetCallState.mCallState, headsetCallState.mNumber,
                 headsetCallState.mType, headsetCallState.mName, mAdapter.getAttributionSource());
         // Ask Audio HAL to suspend A2DP
-        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS))
-                .setParameters("A2dpSuspended=true");
+        verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setA2dpSuspended(true);
         // Make sure we notify devices about this change
         for (BluetoothDevice device : connectedDevices) {
             verify(mStateMachines.get(device)).sendMessage(HeadsetStateMachine.CALL_STATE_CHANGED,
diff --git a/tests/unit/src/com/android/bluetooth/hfp/HeadsetStateMachineTest.java b/tests/unit/src/com/android/bluetooth/hfp/HeadsetStateMachineTest.java
index fde7dd6..f927a61 100644
--- a/tests/unit/src/com/android/bluetooth/hfp/HeadsetStateMachineTest.java
+++ b/tests/unit/src/com/android/bluetooth/hfp/HeadsetStateMachineTest.java
@@ -896,7 +896,7 @@
     public void testAtBiaEvent_initialSubscriptionWithUpdates() {
         setUpConnectedState();
         verify(mPhoneState).listenForPhoneState(mTestDevice, PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_BIA,
                         new HeadsetAgIndicatorEnableState(true, true, false, false), mTestDevice));
@@ -906,7 +906,7 @@
                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_BIA,
                         new HeadsetAgIndicatorEnableState(false, true, true, false), mTestDevice));
         verify(mPhoneState, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).listenForPhoneState(mTestDevice,
-                PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
+                PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_BIA,
                         new HeadsetAgIndicatorEnableState(false, true, false, false), mTestDevice));
diff --git a/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java b/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
index 43ddfcc..db66f00 100644
--- a/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
@@ -47,11 +47,13 @@
 import androidx.test.rule.ServiceTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.bluetooth.R;
 import com.android.bluetooth.TestUtils;
 import com.android.bluetooth.btservice.AdapterService;
 import com.android.bluetooth.btservice.storage.DatabaseManager;
 
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -98,6 +100,9 @@
     @Before
     public void setUp() throws Exception {
         mTargetContext = InstrumentationRegistry.getTargetContext();
+        Assume.assumeTrue("Ignore test when LeAudioService is not enabled",
+        mTargetContext.getResources().getBoolean(R.bool.profile_supported_le_audio));
+
         // Set up mocks and test assets
         MockitoAnnotations.initMocks(this);
 
@@ -149,6 +154,10 @@
 
     @After
     public void tearDown() throws Exception {
+        if (!mTargetContext.getResources().getBoolean(R.bool.profile_supported_le_audio)) {
+            return;
+        }
+
         mBondedDevices.clear();
         mGroupIntentQueue.clear();
         stopService();