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();