diff options
29 files changed, 80 insertions, 4570 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 3f5293e7f..cd409d32c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -456,15 +456,6 @@ <action android:name="android.bluetooth.IBluetoothLeAudio" /> </intent-filter> </service> - <!-- Hearing Aid Profile (HAP) client Profile Service --> - <service android:process="@string/process" - android:name="com.android.bluetooth.hap.HapClientService" - android:enabled="@bool/profile_supported_hap_client" - android:exported="true"> - <intent-filter> - <action android:name="android.bluetooth.IBluetoothHapClient"/> - </intent-filter> - </service> <service android:process="@string/process" android:name = "com.android.bluetooth.lebroadcast.BassClientService" diff --git a/jni/Android.bp b/jni/Android.bp index b598ec660..7414868e0 100644 --- a/jni/Android.bp +++ b/jni/Android.bp @@ -42,7 +42,6 @@ cc_library_shared { "com_android_bluetooth_hid_host.cpp", "com_android_bluetooth_hid_device.cpp", "com_android_bluetooth_hearing_aid.cpp", - "com_android_bluetooth_hap_client.cpp", "com_android_bluetooth_pan.cpp", "com_android_bluetooth_gatt.cpp", "com_android_bluetooth_sdp.cpp", diff --git a/jni/com_android_bluetooth.h b/jni/com_android_bluetooth.h index 572c3e6bd..40e0af4cc 100644 --- a/jni/com_android_bluetooth.h +++ b/jni/com_android_bluetooth.h @@ -169,8 +169,6 @@ int register_com_android_bluetooth_btservice_vendor_socket(JNIEnv* env); int register_com_android_bluetooth_hearing_aid(JNIEnv* env); -int register_com_android_bluetooth_hap_client(JNIEnv* env); - int register_com_android_bluetooth_avrcp_ext(JNIEnv* env); int register_com_android_bluetooth_ba(JNIEnv* env); diff --git a/jni/com_android_bluetooth_btservice_AdapterService.cpp b/jni/com_android_bluetooth_btservice_AdapterService.cpp index 2780a8bbc..bc9421025 100644 --- a/jni/com_android_bluetooth_btservice_AdapterService.cpp +++ b/jni/com_android_bluetooth_btservice_AdapterService.cpp @@ -1903,13 +1903,6 @@ jint JNI_OnLoad(JavaVM *jvm, void *reserved) { return JNI_ERR; } - status = android::register_com_android_bluetooth_hap_client(e); - if (status < 0) { - ALOGE("jni le audio hearing access client registration failure: %d", - status); - return JNI_ERR; - } - status = android::register_com_android_bluetooth_avrcp_ext(e); if (status < 0) { ALOGE("jni avrcp_ext registration failure: %d", status); diff --git a/jni/com_android_bluetooth_hap_client.cpp b/jni/com_android_bluetooth_hap_client.cpp deleted file mode 100644 index 1d77a27eb..000000000 --- a/jni/com_android_bluetooth_hap_client.cpp +++ /dev/null @@ -1,645 +0,0 @@ -/* - * Copyright 2021 HIMSA II K/S - www.himsa.com. - * Represented by EHIMA - www.ehima.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "BluetoothHapClientJni" - -#include <string.h> - -#include <shared_mutex> - -#include "base/logging.h" -#include "com_android_bluetooth.h" -#include "hardware/bt_has.h" - -using bluetooth::has::ConnectionState; -using bluetooth::has::ErrorCode; -using bluetooth::has::HasClientCallbacks; -using bluetooth::has::HasClientInterface; -using bluetooth::has::PresetInfo; -using bluetooth::has::PresetInfoReason; - -namespace android { -static jmethodID method_onConnectionStateChanged; -static jmethodID method_onDeviceAvailable; -static jmethodID method_onFeaturesUpdate; -static jmethodID method_onActivePresetSelected; -static jmethodID method_onGroupActivePresetSelected; -static jmethodID method_onActivePresetSelectError; -static jmethodID method_onGroupActivePresetSelectError; -static jmethodID method_onPresetInfo; -static jmethodID method_onGroupPresetInfo; -static jmethodID method_onPresetInfoError; -static jmethodID method_onGroupPresetInfoError; -static jmethodID method_onPresetNameSetError; -static jmethodID method_onGroupPresetNameSetError; - -static HasClientInterface* sHasClientInterface = nullptr; -static std::shared_timed_mutex interface_mutex; - -static jobject mCallbacksObj = nullptr; -static std::shared_timed_mutex callbacks_mutex; - -static struct { - jclass clazz; - jmethodID constructor; - jmethodID getCodecType; - jmethodID getCodecPriority; - jmethodID getSampleRate; - jmethodID getBitsPerSample; - jmethodID getChannelMode; - jmethodID getCodecSpecific1; - jmethodID getCodecSpecific2; - jmethodID getCodecSpecific3; - jmethodID getCodecSpecific4; -} android_bluetooth_BluetoothHapPresetInfo; - -class HasClientCallbacksImpl : public HasClientCallbacks { - public: - ~HasClientCallbacksImpl() = default; - - void OnConnectionState(ConnectionState state, - const RawAddress& bd_addr) override { - LOG(INFO) << __func__; - - std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - ScopedLocalRef<jbyteArray> addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - LOG(ERROR) << "Failed to new bd addr jbyteArray for connection state"; - return; - } - - sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), - (jbyte*)&bd_addr); - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, - (jint)state, addr.get()); - } - - void OnDeviceAvailable(const RawAddress& bd_addr, uint8_t features) override { - std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - ScopedLocalRef<jbyteArray> addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - LOG(ERROR) << "Failed to new bd addr jbyteArray for device available"; - return; - } - sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), - (jbyte*)&bd_addr); - - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDeviceAvailable, - addr.get(), (jint)features); - } - - void OnFeaturesUpdate(const RawAddress& bd_addr, uint8_t features) override { - std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - ScopedLocalRef<jbyteArray> addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - LOG(ERROR) << "Failed to new bd addr jbyteArray for device available"; - return; - } - sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), - (jbyte*)&bd_addr); - - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onFeaturesUpdate, - addr.get(), (jint)features); - } - - void OnActivePresetSelected(std::variant<RawAddress, int> addr_or_group_id, - uint8_t preset_index) override { - std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - if (std::holds_alternative<RawAddress>(addr_or_group_id)) { - ScopedLocalRef<jbyteArray> addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - LOG(ERROR) << "Failed to new bd addr jbyteArray for preset selected"; - return; - } - sCallbackEnv->SetByteArrayRegion( - addr.get(), 0, sizeof(RawAddress), - (jbyte*)&std::get<RawAddress>(addr_or_group_id)); - - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onActivePresetSelected, - addr.get(), (jint)preset_index); - } else { - sCallbackEnv->CallVoidMethod( - mCallbacksObj, method_onGroupActivePresetSelected, - std::get<int>(addr_or_group_id), (jint)preset_index); - } - } - - void OnActivePresetSelectError(std::variant<RawAddress, int> addr_or_group_id, - ErrorCode error_code) override { - std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - if (std::holds_alternative<RawAddress>(addr_or_group_id)) { - ScopedLocalRef<jbyteArray> addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - LOG(ERROR) - << "Failed to new bd addr jbyteArray for preset select error"; - return; - } - sCallbackEnv->SetByteArrayRegion( - addr.get(), 0, sizeof(RawAddress), - (jbyte*)&std::get<RawAddress>(addr_or_group_id)); - - sCallbackEnv->CallVoidMethod(mCallbacksObj, - method_onActivePresetSelectError, addr.get(), - (jint)error_code); - } else { - sCallbackEnv->CallVoidMethod( - mCallbacksObj, method_onGroupActivePresetSelectError, - std::get<int>(addr_or_group_id), (jint)error_code); - } - } - - void OnPresetInfo(std::variant<RawAddress, int> addr_or_group_id, - PresetInfoReason info_reason, - std::vector<PresetInfo> detail_records) override { - std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - jsize i = 0; - jobjectArray presets_array = sCallbackEnv->NewObjectArray( - (jsize)detail_records.size(), - android_bluetooth_BluetoothHapPresetInfo.clazz, nullptr); - - const char null_str[] = ""; - for (auto const& info : detail_records) { - const char* name = info.preset_name.c_str(); - if (!sCallbackEnv.isValidUtf(name)) { - ALOGE("%s: name is not a valid UTF string.", __func__); - name = null_str; - } - - ScopedLocalRef<jstring> name_str(sCallbackEnv.get(), - sCallbackEnv->NewStringUTF(name)); - if (!name_str.get()) { - LOG(ERROR) << "Failed to new preset name String for preset name"; - return; - } - - jobject infoObj = sCallbackEnv->NewObject( - android_bluetooth_BluetoothHapPresetInfo.clazz, - android_bluetooth_BluetoothHapPresetInfo.constructor, - (jint)info.preset_index, name_str.get(), (jboolean)info.writable, - (jboolean)info.available); - sCallbackEnv->SetObjectArrayElement(presets_array, i++, infoObj); - sCallbackEnv->DeleteLocalRef(infoObj); - } - - if (std::holds_alternative<RawAddress>(addr_or_group_id)) { - ScopedLocalRef<jbyteArray> addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - LOG(ERROR) << "Failed to new bd addr jbyteArray for preset name"; - return; - } - sCallbackEnv->SetByteArrayRegion( - addr.get(), 0, sizeof(RawAddress), - (jbyte*)&std::get<RawAddress>(addr_or_group_id)); - - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onPresetInfo, - addr.get(), (jint)info_reason, - presets_array); - } else { - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupPresetInfo, - std::get<int>(addr_or_group_id), - (jint)info_reason, presets_array); - } - } - - virtual void OnPresetInfoError(std::variant<RawAddress, int> addr_or_group_id, - uint8_t preset_index, - ErrorCode error_code) override { - std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - if (std::holds_alternative<RawAddress>(addr_or_group_id)) { - ScopedLocalRef<jbyteArray> addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - LOG(ERROR) - << "Failed to new bd addr jbyteArray for preset name get error"; - return; - } - sCallbackEnv->SetByteArrayRegion( - addr.get(), 0, sizeof(RawAddress), - (jbyte*)&std::get<RawAddress>(addr_or_group_id)); - - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onPresetInfoError, - addr.get(), (jint)preset_index, - (jint)error_code); - } else { - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupPresetInfoError, - std::get<int>(addr_or_group_id), - (jint)preset_index, (jint)error_code); - } - } - - void OnSetPresetNameError(std::variant<RawAddress, int> addr_or_group_id, - uint8_t preset_index, - ErrorCode error_code) override { - std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - if (std::holds_alternative<RawAddress>(addr_or_group_id)) { - ScopedLocalRef<jbyteArray> addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - LOG(ERROR) - << "Failed to new bd addr jbyteArray for preset name set error"; - return; - } - sCallbackEnv->SetByteArrayRegion( - addr.get(), 0, sizeof(RawAddress), - (jbyte*)&std::get<RawAddress>(addr_or_group_id)); - - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onPresetNameSetError, - addr.get(), (jint)preset_index, - (jint)error_code); - } else { - sCallbackEnv->CallVoidMethod(mCallbacksObj, - method_onGroupPresetNameSetError, - std::get<int>(addr_or_group_id), - (jint)preset_index, (jint)error_code); - } - } -}; - -static HasClientCallbacksImpl sHasClientCallbacks; - -static void classInitNative(JNIEnv* env, jclass clazz) { - jclass jniBluetoothBluetoothHapPresetInfoClass = - env->FindClass("android/bluetooth/BluetoothHapPresetInfo"); - CHECK(jniBluetoothBluetoothHapPresetInfoClass != NULL); - - android_bluetooth_BluetoothHapPresetInfo.constructor = - env->GetMethodID(jniBluetoothBluetoothHapPresetInfoClass, "<init>", - "(ILjava/lang/String;ZZ)V"); - - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); - - method_onDeviceAvailable = - env->GetMethodID(clazz, "onDeviceAvailable", "([BI)V"); - - method_onFeaturesUpdate = - env->GetMethodID(clazz, "onFeaturesUpdate", "([BI)V"); - - method_onActivePresetSelected = - env->GetMethodID(clazz, "onActivePresetSelected", "([BI)V"); - - method_onGroupActivePresetSelected = - env->GetMethodID(clazz, "onActivePresetGroupSelected", "(II)V"); - - method_onActivePresetSelectError = - env->GetMethodID(clazz, "onActivePresetSelectError", "([BI)V"); - - method_onGroupActivePresetSelectError = - env->GetMethodID(clazz, "onActivePresetGroupSelectError", "(II)V"); - - method_onPresetInfo = - env->GetMethodID(clazz, "onPresetInfo", - "([BI[Landroid/bluetooth/BluetoothHapPresetInfo;)V"); - - method_onGroupPresetInfo = - env->GetMethodID(clazz, "onGroupPresetInfo", - "(II[Landroid/bluetooth/BluetoothHapPresetInfo;)V"); - - method_onPresetNameSetError = - env->GetMethodID(clazz, "onPresetNameSetError", "([BII)V"); - - method_onGroupPresetNameSetError = - env->GetMethodID(clazz, "onGroupPresetNameSetError", "(III)V"); - - method_onPresetInfoError = - env->GetMethodID(clazz, "onPresetInfoError", "([BII)V"); - - method_onGroupPresetInfoError = - env->GetMethodID(clazz, "onGroupPresetInfoError", "(III)V"); - - LOG(INFO) << __func__ << ": succeeds"; -} - -static void initNative(JNIEnv* env, jobject object) { - std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex); - std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex); - - const bt_interface_t* btInf = getBluetoothInterface(); - if (btInf == nullptr) { - LOG(ERROR) << "Bluetooth module is not loaded"; - return; - } - - if (sHasClientInterface != nullptr) { - LOG(INFO) << "Cleaning up HearingAid Interface before initializing..."; - sHasClientInterface->Cleanup(); - sHasClientInterface = nullptr; - } - - if (mCallbacksObj != nullptr) { - LOG(INFO) << "Cleaning up HearingAid callback object"; - env->DeleteGlobalRef(mCallbacksObj); - mCallbacksObj = nullptr; - } - - if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) { - LOG(ERROR) << "Failed to allocate Global Ref for Hearing Access Callbacks"; - return; - } - - android_bluetooth_BluetoothHapPresetInfo.clazz = (jclass)env->NewGlobalRef( - env->FindClass("android/bluetooth/BluetoothHapPresetInfo")); - if (android_bluetooth_BluetoothHapPresetInfo.clazz == nullptr) { - ALOGE("%s: Failed to allocate Global Ref for BluetoothHapPresetInfo class", - __func__); - return; - } - - sHasClientInterface = (HasClientInterface*)btInf->get_profile_interface( - BT_PROFILE_HAP_CLIENT_ID); - if (sHasClientInterface == nullptr) { - LOG(ERROR) - << "Failed to get Bluetooth Hearing Access Service Client Interface"; - return; - } - - sHasClientInterface->Init(&sHasClientCallbacks); -} - -static void cleanupNative(JNIEnv* env, jobject object) { - std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex); - std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex); - - const bt_interface_t* btInf = getBluetoothInterface(); - if (btInf == nullptr) { - LOG(ERROR) << "Bluetooth module is not loaded"; - return; - } - - if (sHasClientInterface != nullptr) { - sHasClientInterface->Cleanup(); - sHasClientInterface = nullptr; - } - - if (mCallbacksObj != nullptr) { - env->DeleteGlobalRef(mCallbacksObj); - mCallbacksObj = nullptr; - } -} - -static jboolean connectHapClientNative(JNIEnv* env, jobject object, - jbyteArray address) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return JNI_FALSE; - } - - jbyte* addr = env->GetByteArrayElements(address, nullptr); - if (!addr) { - jniThrowIOException(env, EINVAL); - return JNI_FALSE; - } - - RawAddress* tmpraw = (RawAddress*)addr; - sHasClientInterface->Connect(*tmpraw); - env->ReleaseByteArrayElements(address, addr, 0); - return JNI_TRUE; -} - -static jboolean disconnectHapClientNative(JNIEnv* env, jobject object, - jbyteArray address) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return JNI_FALSE; - } - - jbyte* addr = env->GetByteArrayElements(address, nullptr); - if (!addr) { - jniThrowIOException(env, EINVAL); - return JNI_FALSE; - } - - RawAddress* tmpraw = (RawAddress*)addr; - sHasClientInterface->Disconnect(*tmpraw); - env->ReleaseByteArrayElements(address, addr, 0); - return JNI_TRUE; -} - -static void selectActivePresetNative(JNIEnv* env, jobject object, - jbyteArray address, jint preset_index) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return; - } - - jbyte* addr = env->GetByteArrayElements(address, nullptr); - if (!addr) { - jniThrowIOException(env, EINVAL); - return; - } - - RawAddress* tmpraw = (RawAddress*)addr; - sHasClientInterface->SelectActivePreset(*tmpraw, preset_index); - env->ReleaseByteArrayElements(address, addr, 0); -} - -static void groupSelectActivePresetNative(JNIEnv* env, jobject object, - jint group_id, jint preset_index) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return; - } - - sHasClientInterface->SelectActivePreset(group_id, preset_index); -} - -static void nextActivePresetNative(JNIEnv* env, jobject object, - jbyteArray address) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return; - } - - jbyte* addr = env->GetByteArrayElements(address, nullptr); - if (!addr) { - jniThrowIOException(env, EINVAL); - return; - } - - RawAddress* tmpraw = (RawAddress*)addr; - sHasClientInterface->NextActivePreset(*tmpraw); - env->ReleaseByteArrayElements(address, addr, 0); -} - -static void groupNextActivePresetNative(JNIEnv* env, jobject object, - jint group_id) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return; - } - - sHasClientInterface->NextActivePreset(group_id); -} - -static void previousActivePresetNative(JNIEnv* env, jobject object, - jbyteArray address) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return; - } - - jbyte* addr = env->GetByteArrayElements(address, nullptr); - if (!addr) { - jniThrowIOException(env, EINVAL); - return; - } - - RawAddress* tmpraw = (RawAddress*)addr; - sHasClientInterface->PreviousActivePreset(*tmpraw); - env->ReleaseByteArrayElements(address, addr, 0); -} - -static void groupPreviousActivePresetNative(JNIEnv* env, jobject object, - jint group_id) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return; - } - - sHasClientInterface->PreviousActivePreset(group_id); -} - -static void getPresetInfoNative(JNIEnv* env, jobject object, jbyteArray address, - jint preset_index) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return; - } - - jbyte* addr = env->GetByteArrayElements(address, nullptr); - if (!addr) { - jniThrowIOException(env, EINVAL); - return; - } - - RawAddress* tmpraw = (RawAddress*)addr; - sHasClientInterface->GetPresetInfo(*tmpraw, preset_index); - env->ReleaseByteArrayElements(address, addr, 0); -} - -static void setPresetNameNative(JNIEnv* env, jobject object, jbyteArray address, - jint preset_index, jstring name) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return; - } - - jbyte* addr = env->GetByteArrayElements(address, nullptr); - if (!addr) { - jniThrowIOException(env, EINVAL); - return; - } - - std::string name_str; - if (name != nullptr) { - const char* value = env->GetStringUTFChars(name, nullptr); - name_str = std::string(value); - env->ReleaseStringUTFChars(name, value); - } - - RawAddress* tmpraw = (RawAddress*)addr; - sHasClientInterface->SetPresetName(*tmpraw, preset_index, - std::move(name_str)); - env->ReleaseByteArrayElements(address, addr, 0); -} - -static void groupSetPresetNameNative(JNIEnv* env, jobject object, jint group_id, - jint preset_index, jstring name) { - std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); - if (!sHasClientInterface) { - LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; - return; - } - - std::string name_str; - if (name != nullptr) { - const char* value = env->GetStringUTFChars(name, nullptr); - name_str = std::string(value); - env->ReleaseStringUTFChars(name, value); - } - - sHasClientInterface->SetPresetName(group_id, preset_index, - std::move(name_str)); -} - -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectHapClientNative", "([B)Z", (void*)connectHapClientNative}, - {"disconnectHapClientNative", "([B)Z", (void*)disconnectHapClientNative}, - {"selectActivePresetNative", "([BI)V", (void*)selectActivePresetNative}, - {"groupSelectActivePresetNative", "(II)V", - (void*)groupSelectActivePresetNative}, - {"nextActivePresetNative", "([B)V", (void*)nextActivePresetNative}, - {"groupNextActivePresetNative", "(I)V", (void*)groupNextActivePresetNative}, - {"previousActivePresetNative", "([B)V", (void*)previousActivePresetNative}, - {"groupPreviousActivePresetNative", "(I)V", - (void*)groupPreviousActivePresetNative}, - {"getPresetInfoNative", "([BI)V", (void*)getPresetInfoNative}, - {"setPresetNameNative", "([BILjava/lang/String;)V", - (void*)setPresetNameNative}, - {"groupSetPresetNameNative", "(IILjava/lang/String;)V", - (void*)groupSetPresetNameNative}, -}; - -int register_com_android_bluetooth_hap_client(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/hap/HapClientNativeInterface", sMethods, - NELEM(sMethods)); -} -} // namespace android diff --git a/res/drawable/ic_bluetooth_share_icon.xml b/res/drawable/ic_bluetooth_share_icon.xml new file mode 100644 index 000000000..310323499 --- /dev/null +++ b/res/drawable/ic_bluetooth_share_icon.xml @@ -0,0 +1,28 @@ +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<!-- This drawable should only be used by the Bluetooth application for its share target icon. --> +<!-- The tint color is from https://www.bluetooth.com/develop-with-bluetooth/marketing-branding/ --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="#2285F8"> + + <path + android:fillColor="@android:color/white" + android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" /> +</vector> diff --git a/res/mipmap-anydpi/bt_share.xml b/res/mipmap-anydpi/bt_share.xml index c99e5609e..0a2dc9490 100644 --- a/res/mipmap-anydpi/bt_share.xml +++ b/res/mipmap-anydpi/bt_share.xml @@ -16,7 +16,7 @@ <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <foreground> <inset - android:drawable="@*android:drawable/ic_bluetooth_share_icon" + android:drawable="@drawable/ic_bluetooth_share_icon" android:insetTop="25%" android:insetRight="25%" android:insetBottom="25%" diff --git a/res/values/config.xml b/res/values/config.xml index bbf3e6ccb..868cb7e42 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -72,7 +72,6 @@ <bool name="profile_supported_broadcast">true</bool> <bool name="profile_supported_hid_device">true</bool> <bool name="profile_supported_le_audio">true</bool> - <bool name="profile_supported_hap_client">true</bool> <bool name="profile_supported_ba">false</bool> <bool name="profile_supported_group_client">true</bool> <bool name="profile_supported_csip_set_coordinator">true</bool> diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java index 4d16ba68e..be36bf2d7 100644 --- a/src/com/android/bluetooth/a2dp/A2dpService.java +++ b/src/com/android/bluetooth/a2dp/A2dpService.java @@ -12,10 +12,6 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * - * Changes from Qualcomm Innovation Center are provided under the following license: - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause-Clear */ package com.android.bluetooth.a2dp; @@ -79,7 +75,6 @@ import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.lang.reflect.Method; /** * Provides Bluetooth A2DP profile, as a service in the Bluetooth application. @@ -134,8 +129,6 @@ public class A2dpService extends ProfileService { private boolean mIsTwsPlusEnabled = false; private boolean mIsTwsPlusMonoSupported = false; private boolean mShoActive = false; - private boolean mGamingEnabled = false; - private boolean mAlsDisabled; private String mTwsPlusChannelMode = "dual-mono"; private BluetoothDevice mDummyDevice = null; private static final int max_tws_connection = 2; @@ -149,8 +142,6 @@ public class A2dpService extends ProfileService { private static final int SET_EBMONO_CFG = 1; private static final int SET_EBDUALMONO_CFG = 2; - private static final int ENABLE_GAMING_MODE = 3; - private static final int DISABLE_GAMING_MODE = 4; private static final int MonoCfg_Timeout = 3000; private static final int DualMonoCfg_Timeout = 3000; @@ -176,14 +167,6 @@ public class A2dpService extends ProfileService { } mTwsPlusChannelMode = "dual-mono"; break; - case ENABLE_GAMING_MODE: - Log.d(TAG, "Enable Gaming Mode in A2DP!!"); - enableGamingModeinA2DP(); - break; - case DISABLE_GAMING_MODE: - Log.d(TAG, "Disable Gaming Mode in A2DP!!"); - disableGamingModeinA2DP(); - break; default: break; } @@ -261,8 +244,6 @@ public class A2dpService extends ProfileService { if (!TwsPlusChannelMode.isEmpty() && "mono".equals(TwsPlusChannelMode)) { mTwsPlusChannelMode = "mono"; } - mAlsDisabled = SystemProperties.getBoolean - ("persist.vendor.service.bt.als_disabled", false); Log.d(TAG, "Default TwsPlus ChannelMode: " + mTwsPlusChannelMode); } @@ -1220,93 +1201,6 @@ public class A2dpService extends ProfileService { return true; } - public void setGamingMode(BluetoothDevice device, boolean status) { - if (status) { - Log.v(TAG,"setGamingMode"); - Message msg = mHandler.obtainMessage(ENABLE_GAMING_MODE); - mHandler.sendMessage(msg); - } - else { - Log.v(TAG,"setGamingMode"); - Message msg = mHandler.obtainMessage(DISABLE_GAMING_MODE); - mHandler.sendMessage(msg); - } - } - - private void enableGamingModeinA2DP() { - if (mGamingEnabled) { - Log.v(TAG,"enableGamingModeinA2DP: Already enabled Gaming Mode"); - return; - } - Log.v(TAG,"enableGamingModeinA2DP"); - BluetoothDevice device = getActiveDevice(); - BluetoothCodecStatus codecStatus = getCodecStatus(device); - if (codecStatus == null) { - Log.v(TAG,"enableGamingModeinA2DP: CodecStatus is empty"); - return; - } - BluetoothCodecConfig codecConfig = codecStatus.getCodecConfig(); - if (codecConfig == null) { - Log.v(TAG,"enableGamingModeinA2DP: CodecConfig is empty"); - return; - } - if (codecConfig.getCodecType() == BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE) { - Log.v(TAG,"APTX ADAPTIVE Codec Type"); - BluetoothCodecConfig a2dpGamingConfig = - new BluetoothCodecConfig.Builder() - .setCodecType(codecConfig.getCodecType()) - .setCodecPriority(codecConfig.getCodecPriority()) - .setSampleRate(codecConfig.getSampleRate()) - .setBitsPerSample(codecConfig.getBitsPerSample()) - .setChannelMode(codecConfig.getChannelMode()) - .setCodecSpecific1(codecConfig.getCodecSpecific1()) - .setCodecSpecific2(codecConfig.getCodecSpecific2()) - .setCodecSpecific3(codecConfig.getCodecSpecific3()) - .setCodecSpecific4(APTX_LL) - .build(); - mGamingEnabled = true; - mA2dpCodecConfig.setCodecConfigPreference(device, codecStatus, a2dpGamingConfig); - } else { - Log.d(TAG,"CodecType is not AptX AD"); - return; - } - } - - private void disableGamingModeinA2DP() { - if (!mGamingEnabled) { - Log.v(TAG,"disableGamingModeinA2DP: Already disabled Gaming Mode"); - return; - } - Log.v(TAG,"disableGamingModeinA2DP"); - BluetoothDevice device = getActiveDevice(); - BluetoothCodecStatus codecStatus = getCodecStatus(device); - if (codecStatus == null) { - Log.v(TAG,"disableGamingModeinA2DP: CodecStatus is empty, resetting gaming mode"); - mGamingEnabled = false; - return; - } - BluetoothCodecConfig codecConfig = codecStatus.getCodecConfig(); - if (codecConfig == null) { - Log.v(TAG,"disableGamingModeinA2DP: CodecConfig is empty, resetting gaming mode"); - mGamingEnabled = false; - return; - } - BluetoothCodecConfig a2dpGamingConfig = - new BluetoothCodecConfig.Builder() - .setCodecType(codecConfig.getCodecType()) - .setCodecPriority(codecConfig.getCodecPriority()) - .setSampleRate(codecConfig.getSampleRate()) - .setBitsPerSample(codecConfig.getBitsPerSample()) - .setChannelMode(codecConfig.getChannelMode()) - .setCodecSpecific1(codecConfig.getCodecSpecific1()) - .setCodecSpecific2(codecConfig.getCodecSpecific2()) - .setCodecSpecific3(codecConfig.getCodecSpecific3()) - .setCodecSpecific4(APTX_HQ) - .build(); - mGamingEnabled = false; - mA2dpCodecConfig.setCodecConfigPreference(device, codecStatus, a2dpGamingConfig); - } - private boolean setActiveDeviceA2dp(BluetoothDevice device) { BluetoothCodecStatus codecStatus = null; BluetoothDevice previousActiveDevice = mActiveDevice; @@ -1699,46 +1593,6 @@ public class A2dpService extends ProfileService { long cs4 = codecConfig.getCodecSpecific4(); GattService mGattService = GattService.getGattService(); - boolean isLowLatencyModeEnabled = false; - Object objStreamAudioService = null; - - if (mAlsDisabled) { - if (cs4 > 0 && codecConfig.getCodecType() == - BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE) { - Log.e(TAG, "setCodecConfigPreference: ALS trigger is ignored"); - return; - } - } - - try { - Class streamAudioService = Class.forName("com.android.bluetooth.apm.StreamAudioService"); - Method method = streamAudioService.getDeclaredMethod("getStreamAudioService"); - objStreamAudioService = method.invoke(null); - if (objStreamAudioService != null) { - Log.d(TAG, " setCodecConfigPreference, objStreamAudioService not null:"); - } else { - Log.d(TAG, " setCodecConfigPreference, objStreamAudioService is null:"); - } - } catch (Exception ex) { - Log.w(TAG, ex); - } - try { - Class streamAudioService = Class.forName("com.android.bluetooth.apm.StreamAudioService"); - Method method = streamAudioService.getDeclaredMethod("isLowLatencyModeEnabled"); - if (objStreamAudioService != null) { - Log.d(TAG, " setCodecConfigPreference, invoke isLowLatencyModeEnabled"); - isLowLatencyModeEnabled = (boolean) method.invoke(objStreamAudioService); - } - Log.d(TAG, " setCodecConfigPreference, isLowLatencyModeEnabled:" - + isLowLatencyModeEnabled); - } catch (Exception ex) { - Log.w(TAG, ex); - } - - if (cs4 > 0 && isLowLatencyModeEnabled) { - Log.e(TAG, "setCodecConfigPreference: LowLatencyModeEnabled, return"); - return; - } if(cs4 > 0 && mGattService != null) { switch((int)(cs4 & APTX_MODE_MASK)) { @@ -1758,28 +1612,6 @@ public class A2dpService extends ProfileService { } } - if (cs4 > 0 && Utils.isDualModeAudioEnabled()) { - MediaAudioIntf mMediaAudio = MediaAudioIntf.get(); - if(mMediaAudio == null) { - return; - } - - switch((int)(cs4 & APTX_MODE_MASK)) { - case APTX_HQ: - Log.d(TAG, "setCodecConfigPreference: disable Gaming from ALS"); - mMediaAudio.disableGamingMode(device, 0); - break; - - case APTX_LL: - Log.d(TAG, "setCodecConfigPreference: enable Gaming from ALS"); - mMediaAudio.enableGamingMode(device, 0); - break; - default: - break; - } - return; - } - if (codecConfig == null) { Log.e(TAG, "setCodecConfigPreference: Codec config can't be null"); return; @@ -1805,47 +1637,6 @@ public class A2dpService extends ProfileService { + Objects.toString(codecConfig)); } long cs4 = codecConfig.getCodecSpecific4(); - boolean isLowLatencyModeEnabled = false; - Object objStreamAudioService = null; - - if (mAlsDisabled) { - if (cs4 > 0 && codecConfig.getCodecType() == - BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE) { - Log.e(TAG, "setCodecConfigPreferenceA2dp: ALS trigger is ignored"); - return; - } - } - - try { - Class streamAudioService = Class.forName("com.android.bluetooth.apm.StreamAudioService"); - Method method = streamAudioService.getDeclaredMethod("getStreamAudioService"); - objStreamAudioService = method.invoke(null); - if (objStreamAudioService != null) { - Log.d(TAG, " setCodecConfigPreferenceA2dp, objStreamAudioService not null:"); - } else { - Log.d(TAG, " setCodecConfigPreferenceA2dp, objStreamAudioService is null:"); - } - } catch (Exception ex) { - Log.w(TAG, ex); - } - try { - Class streamAudioService = Class.forName("com.android.bluetooth.apm.StreamAudioService"); - Method method = streamAudioService.getDeclaredMethod("isLowLatencyModeEnabled"); - if (objStreamAudioService != null) { - Log.d(TAG, " setCodecConfigPreferenceA2dp, invoke isLowLatencyModeEnabled"); - isLowLatencyModeEnabled = (boolean) method.invoke(objStreamAudioService); - } - Log.d(TAG, "setCodecConfigPreferenceA2dp: isLowLatencyModeEnabled:" - + isLowLatencyModeEnabled); - } catch (Exception ex) { - Log.w(TAG, ex); - } - - if (cs4 > 0 && isLowLatencyModeEnabled) { - Log.e(TAG, "setCodecConfigPreferenceA2dp: LowLatencyModeEnabled, return"); - return; - } - GattService mGattService = GattService.getGattService(); if(cs4 > 0 && mGattService != null) { switch((int)(cs4 & APTX_MODE_MASK)) { @@ -3024,9 +2815,6 @@ public class A2dpService extends ProfileService { public void updateStreamState(BluetoothDevice device, int streamStatus) { MediaAudioIntf mMediaAudio = MediaAudioIntf.get(); mMediaAudio.onStreamStateChange(device, streamStatus); - if (streamStatus == BluetoothA2dp.STATE_NOT_PLAYING) { - disableGamingModeinA2DP(); - } } @Override diff --git a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java index 22dcf0189..c987ca94b 100644 --- a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +++ b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java @@ -12,10 +12,6 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * - * Changes from Qualcomm Innovation Center are provided under the following license: - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause-Clear */ /** @@ -77,7 +73,6 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.List; import java.util.Scanner; -import java.lang.reflect.Method; import android.os.SystemProperties; import com.android.bluetooth.btservice.AdapterService; @@ -636,7 +631,6 @@ final class A2dpStateMachine extends StateMachine { mA2dpService.setAvrcpAudioState(BluetoothA2dp.STATE_NOT_PLAYING, mDevice); broadcastAudioState(BluetoothA2dp.STATE_NOT_PLAYING, BluetoothA2dp.STATE_PLAYING); - mA2dpService.setGamingMode(mDevice, false); } } break; @@ -684,7 +678,6 @@ final class A2dpStateMachine extends StateMachine { // Split A2dp will be enabled by default boolean isSplitA2dpEnabled = true; AdapterService adapterService = AdapterService.getAdapterService(); - Object objStreamAudioService = null; if (adapterService != null){ isSplitA2dpEnabled = adapterService.isSplitA2dpEnabled(); @@ -760,34 +753,6 @@ final class A2dpStateMachine extends StateMachine { Log.d(TAG, " mCodecConfigUpdated is false, codecConfigUpdated is required"); update = true; } - - if ((newCodecConfig.getCodecType() - == BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE)) { - Log.d(TAG, "processCodecConfigEvent, APTX ADAPTIVE: reset Low Latency mode "); - try { - Class streamAudioService = Class.forName("com.android.bluetooth.apm.StreamAudioService"); - Method method = streamAudioService.getDeclaredMethod("getStreamAudioService"); - objStreamAudioService = method.invoke(null); - if (objStreamAudioService != null) { - Log.d(TAG, " processCodecConfigEvent, objStreamAudioService not null:"); - } else { - Log.d(TAG, " processCodecConfigEvent, objStreamAudioService is null:"); - } - } catch (Exception ex) { - Log.w(TAG, ex); - } - try { - Class streamAudioService = - Class.forName("com.android.bluetooth.apm.StreamAudioService"); - Method method = streamAudioService.getDeclaredMethod("resetLowLatencyMode"); - if (objStreamAudioService != null) { - Log.d(TAG, " processCodecConfigEvent, invoke resetLowLatencyMode "); - method.invoke(objStreamAudioService); - } - } catch (Exception ex) { - Log.w(TAG, ex); - } - } Log.d(TAG, " update: " + update); if (update) { mA2dpService.codecConfigUpdated(mDevice, mCodecStatus, false); @@ -851,9 +816,8 @@ final class A2dpStateMachine extends StateMachine { log("A2DP Playing state : device: " + mDevice + " State:" + audioStateToString(prevState) + "->" + audioStateToString(newState)); - mA2dpService.updateStreamState(mDevice, newState); - - if(mA2dpService.isQtiLeAudioEnabled()) { + if (mA2dpService.isQtiLeAudioEnabled()) { + mA2dpService.updateStreamState(mDevice, newState); return; } diff --git a/src/com/android/bluetooth/acm/AcmServIntf.java b/src/com/android/bluetooth/acm/AcmServIntf.java index 9fc13f9ba..afcfd85d8 100644 --- a/src/com/android/bluetooth/acm/AcmServIntf.java +++ b/src/com/android/bluetooth/acm/AcmServIntf.java @@ -349,27 +349,6 @@ public class AcmServIntf { return false; } - public boolean isAcmPlayingVoice(BluetoothDevice device) { - if(AcmService == null) - return false; - - Class[] arg = new Class[1]; - arg[0] = BluetoothDevice.class; - - try { - Method isAcmPlayingVoice = AcmService.getDeclaredMethod("isAcmPlayingVoice", arg); - boolean ret = (boolean)isAcmPlayingVoice.invoke(mAcmService, device); - return ret; - } catch(IllegalAccessException e) { - Log.i(TAG, "Exception" + e); - } catch(NoSuchMethodException e) { - Log.i(TAG, "Exception" + e); - } catch(InvocationTargetException e) { - Log.i(TAG, "Exception" + e); - } - return false; - } - /* public BluetoothCodecStatus getCodecStatus(BluetoothDevice device) { if(AcmService == null) diff --git a/src/com/android/bluetooth/apm/CallAudioIntf.java b/src/com/android/bluetooth/apm/CallAudioIntf.java index fd862b727..bf01ec040 100644 --- a/src/com/android/bluetooth/apm/CallAudioIntf.java +++ b/src/com/android/bluetooth/apm/CallAudioIntf.java @@ -25,11 +25,6 @@ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Changes from Qualcomm Innovation Center are provided under the following license: - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause-Clear - * **************************************************************************/ package com.android.bluetooth.apm; @@ -403,24 +398,6 @@ public class CallAudioIntf { return false; } - public boolean isVoipLeaWarEnabled() { - if(CallAudio == null) - return false; - - try { - Method isVoipLeaWarEnabled = CallAudio.getDeclaredMethod("isVoipLeaWarEnabled"); - Boolean ret = (Boolean)isVoipLeaWarEnabled.invoke(mCallAudio); - return ret; - } catch(IllegalAccessException e) { - Log.i(TAG, "Exception" + e); - } catch(NoSuchMethodException e) { - Log.i(TAG, "Exception" + e); - } catch(InvocationTargetException e) { - Log.i(TAG, "Exception" + e); - } - return false; - } - public List<BluetoothDevice> getConnectedDevices() { ArrayList<BluetoothDevice> devices = new ArrayList<>(); if(CallAudio == null) diff --git a/src/com/android/bluetooth/apm/MediaAudioIntf.java b/src/com/android/bluetooth/apm/MediaAudioIntf.java index 36063238c..aa6bc7648 100644 --- a/src/com/android/bluetooth/apm/MediaAudioIntf.java +++ b/src/com/android/bluetooth/apm/MediaAudioIntf.java @@ -381,46 +381,6 @@ public class MediaAudioIntf { } } - public void enableGamingMode(BluetoothDevice device, int context) { - if(MediaAudio == null) - return; - - Class[] arg = new Class[2]; - arg[0] = BluetoothDevice.class; - arg[1] = Integer.class; - - try { - Method enableGamingMode = MediaAudio.getDeclaredMethod("enableGamingMode", arg); - enableGamingMode.invoke(mMediaAudio, device, context); - } catch(IllegalAccessException e) { - Log.i(TAG, "Exception" + e); - } catch(NoSuchMethodException e) { - Log.i(TAG, "Exception" + e); - } catch(InvocationTargetException e) { - Log.i(TAG, "Exception" + e); - } - } - - public void disableGamingMode(BluetoothDevice device, int context) { - if(MediaAudio == null) - return; - - Class[] arg = new Class[2]; - arg[0] = BluetoothDevice.class; - arg[1] = Integer.class; - - try { - Method disableGamingMode = MediaAudio.getDeclaredMethod("disableGamingMode", arg); - disableGamingMode.invoke(mMediaAudio, device, context); - } catch(IllegalAccessException e) { - Log.i(TAG, "Exception" + e); - } catch(NoSuchMethodException e) { - Log.i(TAG, "Exception" + e); - } catch(InvocationTargetException e) { - Log.i(TAG, "Exception" + e); - } - } - public void setLeAudioCodecConfigPreference(int groupId, BluetoothLeAudioCodecConfig inputCodecConfig, BluetoothLeAudioCodecConfig outputCodecConfig) { diff --git a/src/com/android/bluetooth/btservice/ActiveDeviceManager.java b/src/com/android/bluetooth/btservice/ActiveDeviceManager.java index 821fb3399..edb4331db 100644 --- a/src/com/android/bluetooth/btservice/ActiveDeviceManager.java +++ b/src/com/android/bluetooth/btservice/ActiveDeviceManager.java @@ -42,12 +42,9 @@ import android.os.UserHandle; import android.util.Log; import com.android.bluetooth.a2dp.A2dpService; -import com.android.bluetooth.apm.ApmConst; import com.android.bluetooth.apm.ApmConstIntf; import com.android.bluetooth.apm.ActiveDeviceManagerServiceIntf; import com.android.bluetooth.apm.CallAudioIntf; -import com.android.bluetooth.cc.CCService; -import com.android.bluetooth.acm.AcmService; import com.android.bluetooth.hearingaid.HearingAidService; import com.android.bluetooth.hfp.HeadsetService; @@ -148,14 +145,12 @@ public class ActiveDeviceManager { private final List<BluetoothDevice> mA2dpConnectedDevices = new LinkedList<>(); private final List<BluetoothDevice> mHfpConnectedDevices = new LinkedList<>(); - private BluetoothDevice mSetRecentPendingA2dpActiveDevice = null; private BluetoothDevice mA2dpActiveDevice = null; private BluetoothDevice mHfpActiveDevice = null; private BluetoothDevice mHearingAidActiveDevice = null; private BluetoothDevice mLeAudioActiveDevice = null; private boolean mTwsPlusSwitch = false; private boolean mWiredDeviceConnected = false; - private boolean mIsRecentPendingA2dpActiveDevice = false; private static final int DELAY_A2DP_SLEEP_MILLIS = 50; @@ -434,43 +429,14 @@ public class ActiveDeviceManager { } mA2dpConnectedDevices.add(device); - - CallAudioIntf mCallAudio = CallAudioIntf.get(); - - int mCallActiveProfile = - getCurrentActiveProfile(ApmConstIntf.AudioFeatures.CALL_AUDIO); - - ActiveDeviceManagerServiceIntf activeDeviceManager = - ActiveDeviceManagerServiceIntf.get(); - BluetoothDevice mVoiceActiveDevice = null; - AcmService acmService = AcmService.getAcmService(); - if (activeDeviceManager != null) { - mVoiceActiveDevice = - activeDeviceManager.getActiveDevice(ApmConstIntf.AudioFeatures.CALL_AUDIO); - } - Log.d(TAG, "mCallActiveProfile: " + mCallActiveProfile + - ", mVoiceActiveDevice: " + mVoiceActiveDevice); - if (mHearingAidActiveDevice == null) { - if ((mCallActiveProfile == ApmConst.AudioProfiles.BAP_CALL) && - acmService != null && acmService.isAcmPlayingVoice(mVoiceActiveDevice)) { - Log.d(TAG, "BAP_Call streaming is on-going, cache a2dp active"); - setPendingA2dpActiveDevice(device); - } else { - // New connected device: select it as active - setA2dpActiveDevice(device); - } + // New connected device: select it as active + setA2dpActiveDevice(device); break; } else { if (!ApmConstIntf.getQtiLeAudioEnabled()) { - setHearingAidActiveDevice(null); - if ((mCallActiveProfile == ApmConst.AudioProfiles.BAP_CALL) && - acmService != null && acmService.isAcmPlayingVoice(mVoiceActiveDevice)) { - Log.d(TAG, "aosp lea, BAP_Call streaming is on-going, cache a2dp active"); - setPendingA2dpActiveDevice(device); - } else { - setA2dpActiveDevice(device); - } + setHearingAidActiveDevice(null); + setA2dpActiveDevice(device); } } break; @@ -904,7 +870,6 @@ public class ActiveDeviceManager { Log.d(TAG, "LEA device is source : " + bleDeviceInfo.isSource()); mWiredDeviceConnected = false; BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - boolean isDuMoEnabled = Utils.isDualModeAudioEnabled(); BluetoothDevice dev = adapter.getRemoteDevice(bleDeviceInfo.getAddress()); ActiveDeviceManagerServiceIntf activeDeviceManager = ActiveDeviceManagerServiceIntf.get(); @@ -915,16 +880,11 @@ public class ActiveDeviceManager { activeDeviceManager.getActiveDevice(ApmConstIntf.AudioFeatures.CALL_AUDIO); Log.d(TAG, "LEA active dev: " + dev + ", absolute device:" + AbsDevice); Log.d(TAG, "current active dev:" + activeDevice); - if ((Objects.equals(dev,activeDevice) && bleDeviceInfo.isSource()) || - (isDuMoEnabled && (Objects.equals(dev,AbsDevice) && bleDeviceInfo.isSource()))) { + if (Objects.equals(dev,activeDevice) && bleDeviceInfo.isSource()) { Log.d(TAG, "broadcast LEA device address: " + activeDevice); broadcastLeActiveDeviceChange(AbsDevice); onLeActiveDeviceChange(AbsDevice); mLeAudioActiveDevice = AbsDevice; - CCService ccService = CCService.getCCService(); - if (ccService != null) { - ccService.handleAnswerCall(AbsDevice); - } } } } @@ -1129,42 +1089,6 @@ public class ActiveDeviceManager { } } - private void setPendingA2dpActiveDevice(BluetoothDevice device) { - if (DBG) { - Log.d(TAG, "setPendingA2dpActiveDevice(" + device + ")"); - } - mIsRecentPendingA2dpActiveDevice = true; - mSetRecentPendingA2dpActiveDevice = device; - } - - public void resetPendingA2dpActiveDevice() { - if (DBG) { - Log.d(TAG, "resetPendingA2dpActiveDevice(): " + - "mIsRecentPendingA2dpActiveDevice: " + mIsRecentPendingA2dpActiveDevice + - " mSetRecentPendingA2dpActiveDevice: " + mSetRecentPendingA2dpActiveDevice); - } - if (mIsRecentPendingA2dpActiveDevice) { - mIsRecentPendingA2dpActiveDevice = false; - } - if (mSetRecentPendingA2dpActiveDevice != null) { - mSetRecentPendingA2dpActiveDevice = null; - } - } - - public void triggerPendingA2dpActiveDevice() { - if (DBG) { - Log.d(TAG, "triggerPendingA2dpActiveDevice(): " + - "mIsRecentPendingA2dpActiveDevice: " + mIsRecentPendingA2dpActiveDevice + - " mSetRecentPendingA2dpActiveDevice: " + mSetRecentPendingA2dpActiveDevice); - } - if (mIsRecentPendingA2dpActiveDevice && - mSetRecentPendingA2dpActiveDevice != null) { - setA2dpActiveDevice(mSetRecentPendingA2dpActiveDevice); - mIsRecentPendingA2dpActiveDevice = false; - mSetRecentPendingA2dpActiveDevice = null; - } - } - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) private boolean setLeAudioActiveDevice(BluetoothDevice device) { if (DBG) { @@ -1200,7 +1124,6 @@ public class ActiveDeviceManager { private void resetState() { mA2dpConnectedDevices.clear(); mA2dpActiveDevice = null; - resetPendingA2dpActiveDevice(); mHfpConnectedDevices.clear(); mHfpActiveDevice = null; diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java index 9cf114439..d239515cb 100644 --- a/src/com/android/bluetooth/btservice/AdapterService.java +++ b/src/com/android/bluetooth/btservice/AdapterService.java @@ -89,11 +89,6 @@ * Changes from Qualcomm Innovation Center are provided under the following license: * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * SPDX-License-Identifier: BSD-3-Clause-Clear - * - * Changes from Qualcomm Innovation Center are provided under the following license: - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause-Clear - * */ package com.android.bluetooth.btservice; @@ -192,7 +187,6 @@ import android.util.Log; import android.util.SparseArray; import com.android.bluetooth.le_audio.LeAudioService; -import com.android.bluetooth.hap.HapClientService; import com.android.bluetooth.BluetoothMetricsProto; import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.Utils; @@ -438,7 +432,6 @@ public class AdapterService extends Service { private SapService mSapService; private GattService mGattService; private LeAudioService mLeAudioService; - private HapClientService mHapClientService; private BassClientService mBassClientService; ///*_REF @@ -1475,10 +1468,6 @@ public class AdapterService extends Service { Log.e(TAG, "isSupported: profile: " + profile); return ArrayUtils.contains(remoteDeviceUuids, BluetoothUuid.LE_AUDIO); } - if (profile == BluetoothProfile.HAP_CLIENT) { - Log.e(TAG, "isSupported: profile: " + profile); - return ArrayUtils.contains(remoteDeviceUuids, BluetoothUuid.HAS); - } if (profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT) { return ArrayUtils.contains(remoteDeviceUuids, BluetoothUuid.BASS); } @@ -1553,12 +1542,6 @@ public class AdapterService extends Service { Log.i(TAG, "isAnyProfileEnabled: LE_AUDIO profile enabled"); return true; } - if (!isQtiLeAudioEnabled && - mHapClientService != null && mHapClientService.getConnectionPolicy(device) - > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { - Log.i(TAG, "isAnyProfileEnabled: HAP profile enabled"); - return true; - } if (mBassClientService != null && mBassClientService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { return true; @@ -1702,16 +1685,9 @@ public class AdapterService extends Service { BluetoothProfile.LE_AUDIO, device) && mLeAudioService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { - Log.i(TAG, "connectEnabledProfiles: Connecting LeAudio and HAP profile (BAP)"); + Log.i(TAG, "connectEnabledProfiles: Connecting LeAudio profile (BAP)"); mLeAudioService.connect(device); } - if (mHapClientService != null && isSupported(localDeviceUuids, remoteDeviceUuids, - BluetoothProfile.HAP_CLIENT, device) - && mHapClientService.getConnectionPolicy(device) - > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { - Log.i(TAG, "connectEnabledProfiles: Connecting HAP profile "); - mHapClientService.connect(device); - } if (mBassClientService != null && isSupported(localDeviceUuids, remoteDeviceUuids, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, device) && mBassClientService.getConnectionPolicy(device) @@ -1803,7 +1779,6 @@ public class AdapterService extends Service { mSapService = SapService.getSapService(); mGattService = GattService.getGattService(); mLeAudioService = LeAudioService.getLeAudioService(); - mHapClientService = HapClientService.getHapClientService(); mVolumeControlService = VolumeControlService.getVolumeControlService(); if (isAdvBCAAudioFeatEnabled()) { ///*_REF @@ -1948,13 +1923,6 @@ public class AdapterService extends Service { return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; } - public int isHapClientSupported() { - if (BluetoothProperties.isProfileHapClientEnabled().orElse(false)) { - return BluetoothStatusCodes.FEATURE_SUPPORTED; - } - return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; - } - public int isLeAudioBroadcastSourcePropertySet() { if (BluetoothProperties.isProfileBapBroadcastSourceEnabled().orElse(false)) { Log.e(TAG, "isLeAudioBroadcastSourceSupported: supported"); @@ -5440,30 +5408,6 @@ public class AdapterService extends Service { return info.callerPackageName; } - public boolean handleLeSetActiveDevice(BluetoothDevice device) { - boolean isAospLeaEnabled = ApmConstIntf.getAospLeaEnabled(); - boolean isLeActiveDevice = false; - Log.i(TAG, "handleLeSetActiveDevice: isAospLeaEnabled: " - + isAospLeaEnabled + ", device: " + device); - for (BluetoothDevice dev : getActiveDevices(BluetoothProfile.LE_AUDIO)) { - if (dev != null) { - Log.i(TAG, "handleLeSetActiveDevice: LE audio device is active"); - isLeActiveDevice = true; - break; - } - } - - if (isAospLeaEnabled && - mLeAudioService != null && (device == null && isLeActiveDevice - || mLeAudioService.getConnectionPolicy(device) - == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - Log.i(TAG, "handleLeSetActiveDevice: Setting active Le Audio device " + device); - mLeAudioService.setActiveDevice(device); - return true; - } - return false; - } - /** * Sets device as the active devices for the profiles passed into the function * @@ -5502,10 +5446,22 @@ public class AdapterService extends Service { return false; } - boolean isLeActiveDeviceHandled = false; - isLeActiveDeviceHandled = handleLeSetActiveDevice(device); - if (isLeActiveDeviceHandled) { - Log.i(TAG, "setActiveDevice: LE audio device made active"); + boolean isLeAudioDeviceActive = false; + for (BluetoothDevice dev : getActiveDevices(BluetoothProfile.LE_AUDIO)) { + if (dev != null) { + Log.i(TAG, "setActiveDevice: LE audio device is active"); + isLeAudioDeviceActive = true; + break; + } + } + + //Make only Le-A device setactive when qti LE-A not enabled. + if (!isQtiLeAudioEnabled && + mLeAudioService != null && (device == null && isLeAudioDeviceActive + || mLeAudioService.getConnectionPolicy(device) + == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + Log.i(TAG, "setActiveDevice: Setting active Le Audio device " + device); + mLeAudioService.setActiveDeviceBlocking(device); return true; } @@ -5528,17 +5484,13 @@ public class AdapterService extends Service { if (setHeadset && mHeadsetService != null) { if (isQtiLeAudioEnabled || isAospLeaEnabled) { activeDeviceManager.setActiveDevice(device, - ApmConstIntf.AudioFeatures.CALL_AUDIO, false); + ApmConstIntf.AudioFeatures.CALL_AUDIO, true); } else { Log.i(TAG, "setActiveDevice: Setting active Headset " + device); mHeadsetService.setActiveDevice(device); } } - if (device == null) { - handleLeSetActiveDevice(device); - } - return true; } @@ -5563,9 +5515,7 @@ public class AdapterService extends Service { Log.e(TAG, "getActiveDevices: HeadsetService is null"); } else { BluetoothDevice defaultValue = null; - CallAudioIntf mCallAudio = CallAudioIntf.get(); - if (ApmConstIntf.getQtiLeAudioEnabled() || - (ApmConstIntf.getAospLeaEnabled() && mCallAudio.isVoipLeaWarEnabled())) { + if (ApmConstIntf.getQtiLeAudioEnabled()) { Log.i(TAG, "getQtiLeAudioEnabled() is true, get HFP active dev from APM"); ActiveDeviceManagerServiceIntf activeDeviceManager = ActiveDeviceManagerServiceIntf.get(); @@ -5666,14 +5616,6 @@ public class AdapterService extends Service { numProfilesConnected++; } if (!isQtiLeAudioEnabled && - mHapClientService != null && isSupported(localDeviceUuids, remoteDeviceUuids, - BluetoothProfile.HAP_CLIENT, device)) { - Log.i(TAG, "connectAllEnabledProfiles: Connecting HAP"); - mHapClientService.setConnectionPolicy(device, - BluetoothProfile.CONNECTION_POLICY_ALLOWED); - numProfilesConnected++; - } - if (!isQtiLeAudioEnabled && mLeAudioService != null && isSupported(localDeviceUuids, remoteDeviceUuids, BluetoothProfile.LE_AUDIO, device)) { Log.i(TAG, "connectAllEnabledProfiles: Connecting Le Audio"); @@ -5859,12 +5801,6 @@ public class AdapterService extends Service { Log.i(TAG, "disconnectAllEnabledProfiles: Disconnecting Le Audio"); mLeAudioService.disconnect(device); } - if (!isQtiLeAudioEnabled && - mHapClientService != null && mHapClientService.getConnectionState(device) - == BluetoothProfile.STATE_CONNECTED) { - Log.i(TAG, "disconnectAllEnabledProfiles: Disconnecting HAP"); - mHapClientService.disconnect(device); - } if (mA2dpSinkService != null && mA2dpSinkService.getConnectionState(device) == BluetoothProfile.STATE_CONNECTED) { Log.i(TAG, "disconnectAllEnabledProfiles: Disconnecting A2dp Sink"); diff --git a/src/com/android/bluetooth/btservice/Config.java b/src/com/android/bluetooth/btservice/Config.java index 49f59ec5b..0e585bf6d 100644 --- a/src/com/android/bluetooth/btservice/Config.java +++ b/src/com/android/bluetooth/btservice/Config.java @@ -89,7 +89,6 @@ import com.android.bluetooth.sap.SapService; import com.android.bluetooth.apm.ApmConstIntf; import com.android.bluetooth.ba.BATService; import com.android.bluetooth.le_audio.LeAudioService; -import com.android.bluetooth.hap.HapClientService; import com.android.bluetooth.vc.VolumeControlService; import java.util.ArrayList; @@ -234,9 +233,6 @@ public class Config { R.bool.profile_supported_le_audio, (1L << BluetoothProfile.LE_AUDIO | 1L << BluetoothProfile.LE_AUDIO_BROADCAST)), - new ProfileConfig(HapClientService.class, - R.bool.profile_supported_hap_client, - (1L << BluetoothProfile.HAP_CLIENT)), new ProfileConfig(VolumeControlService.class, R.bool.profile_supported_volume_control, (1L << BluetoothProfile.VOLUME_CONTROL)) @@ -535,16 +531,6 @@ public class Config { } Log.d(TAG, "LeAudioService profile mask: " + mask); return mask; - } else if (profile == HapClientService.class) { - long mask = config.mMask; - HapClientService hapClientService = HapClientService.getHapClientService(); - if (hapClientService != null) { - if (hapClientService.isEnabled() == false) { - mask &= ~(1L << BluetoothProfile.HAP_CLIENT); - } - } - Log.d(TAG, "HapClientService profile mask: " + mask); - return mask; } return config.mMask; } @@ -596,8 +582,6 @@ public class Config { return addAospAudioProfiles(serviceName); } if (serviceName.equals("VolumeControlService")) { return VolumeControlService.isEnabled(); - } if (serviceName.equals("HapClientService")) { - return addAospAudioProfiles(serviceName); } if ((serviceName.equals("HeadsetClientService")) && (!mIsHfpClient)) return false; @@ -625,10 +609,6 @@ public class Config { BluetoothStatusCodes.FEATURE_NOT_SUPPORTED) { return false; } - if (serviceName.equals("HapClientService") && (adapterService.isHapClientSupported() == - BluetoothStatusCodes.FEATURE_NOT_SUPPORTED)) { - return false; - } return true; } diff --git a/src/com/android/bluetooth/btservice/PhonePolicy.java b/src/com/android/bluetooth/btservice/PhonePolicy.java index b2ce3f0c8..f75c98f6d 100644 --- a/src/com/android/bluetooth/btservice/PhonePolicy.java +++ b/src/com/android/bluetooth/btservice/PhonePolicy.java @@ -80,7 +80,6 @@ import android.os.SystemProperties; import android.util.Log; import com.android.bluetooth.le_audio.LeAudioService; -import com.android.bluetooth.hap.HapClientService; import com.android.bluetooth.a2dp.A2dpService; import com.android.bluetooth.a2dpsink.A2dpSinkService; import com.android.bluetooth.apm.ApmConstIntf; @@ -421,7 +420,7 @@ class PhonePolicy { ParcelUuid.fromString("00006AD0-0000-1000-8000-00805F9B34FB"); ParcelUuid ADV_AUDIO_HEARINGAID = - ParcelUuid.fromString("00001854-0000-1000-8000-00805F9B34FB"); + ParcelUuid.fromString("00006AD2-0000-1000-8000-00805F9B34FB"); ParcelUuid ADV_AUDIO_P_MEDIA = ParcelUuid.fromString("00006AD1-0000-1000-8000-00805F9B34FB"); @@ -449,7 +448,6 @@ class PhonePolicy { PanService panService = mFactory.getPanService(); HearingAidService hearingAidService = mFactory.getHearingAidService(); LeAudioService leAudioService = mFactory.getLeAudioService(); - HapClientService hapClientService = mFactory.getHapClientService(); CsipSetCoordinatorService csipSetCooridnatorService = mFactory.getCsipSetCoordinatorService(); VolumeControlService volumeControlService = mFactory.getVolumeControlService(); @@ -577,24 +575,6 @@ class PhonePolicy { } } } - - if ((hapClientService != null) && ArrayUtils.contains(uuids, - BluetoothUuid.HAS) && (hapClientService.getConnectionPolicy(device) - == BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) { - debugLog("setting hearing access profile priority for device " + device); - if ((hearingAidService != null) && ArrayUtils.contains(uuids, - BluetoothUuid.HEARING_AID) && (hearingAidService.getConnectionPolicy(device) - == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - debugLog("LE Audio preferred over ASHA for device " + device); - if (isLeAudioProfileAllowed) { - mAdapterService.getDatabase().setProfileConnectionPolicy(device, - BluetoothProfile.HEARING_AID, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); - } - } - mAdapterService.getDatabase().setProfileConnectionPolicy(device, - BluetoothProfile.HAP_CLIENT, BluetoothProfile.CONNECTION_POLICY_ALLOWED); - } - if ((bcService != null) && ArrayUtils.contains(uuids, BluetoothUuid.BASS) && (bcService.getConnectionPolicy(device) == BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) { diff --git a/src/com/android/bluetooth/btservice/ServiceFactory.java b/src/com/android/bluetooth/btservice/ServiceFactory.java index 34d8d5d32..96c83ac31 100644 --- a/src/com/android/bluetooth/btservice/ServiceFactory.java +++ b/src/com/android/bluetooth/btservice/ServiceFactory.java @@ -63,7 +63,6 @@ import com.android.bluetooth.hid.HidHostService; import com.android.bluetooth.lebroadcast.BassClientService; import com.android.bluetooth.pan.PanService; import com.android.bluetooth.le_audio.LeAudioService; -import com.android.bluetooth.hap.HapClientService; import com.android.bluetooth.vc.VolumeControlService; import android.util.Log; @@ -119,10 +118,6 @@ public class ServiceFactory { return LeAudioService.getLeAudioService(); } - public HapClientService getHapClientService() { - return HapClientService.getHapClientService(); - } - public BassClientService getBassClientService() { return BassClientService.getBassClientService(); } diff --git a/src/com/android/bluetooth/btservice/storage/Metadata.java b/src/com/android/bluetooth/btservice/storage/Metadata.java index 67650656e..c07747760 100644 --- a/src/com/android/bluetooth/btservice/storage/Metadata.java +++ b/src/com/android/bluetooth/btservice/storage/Metadata.java @@ -173,9 +173,6 @@ class Metadata { case BluetoothProfile.CSIP_SET_COORDINATOR: profileConnectionPolicies.csip_set_coordinator_connection_policy = connectionPolicy; break; - case BluetoothProfile.HAP_CLIENT: - profileConnectionPolicies.hap_client_connection_policy = connectionPolicy; - break; case BluetoothProfile.LE_AUDIO: profileConnectionPolicies.le_audio_connection_policy = connectionPolicy; break; @@ -222,8 +219,6 @@ class Metadata { return profileConnectionPolicies.csip_set_coordinator_connection_policy; case BluetoothProfile.LE_AUDIO: return profileConnectionPolicies.le_audio_connection_policy; - case BluetoothProfile.HAP_CLIENT: - return profileConnectionPolicies.hap_client_connection_policy; case BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT: return profileConnectionPolicies.bass_client_connection_policy; case BluetoothProfile.VOLUME_CONTROL: diff --git a/src/com/android/bluetooth/btservice/storage/ProfilePrioritiesEntity.java b/src/com/android/bluetooth/btservice/storage/ProfilePrioritiesEntity.java index 2cdbfa774..7167099ed 100644 --- a/src/com/android/bluetooth/btservice/storage/ProfilePrioritiesEntity.java +++ b/src/com/android/bluetooth/btservice/storage/ProfilePrioritiesEntity.java @@ -72,7 +72,6 @@ class ProfilePrioritiesEntity { public int map_client_connection_policy; public int bc_profile_priority; public int csip_set_coordinator_connection_policy; - public int hap_client_connection_policy; public int le_audio_connection_policy; public int bass_client_connection_policy; public int volume_control_connection_policy; @@ -92,7 +91,6 @@ class ProfilePrioritiesEntity { map_client_connection_policy = BluetoothProfile.CONNECTION_POLICY_UNKNOWN; bc_profile_priority = BluetoothProfile.CONNECTION_POLICY_UNKNOWN; csip_set_coordinator_connection_policy = BluetoothProfile.CONNECTION_POLICY_UNKNOWN; - hap_client_connection_policy = BluetoothProfile.CONNECTION_POLICY_UNKNOWN; le_audio_connection_policy = BluetoothProfile.CONNECTION_POLICY_UNKNOWN; bass_client_connection_policy = BluetoothProfile.CONNECTION_POLICY_UNKNOWN; volume_control_connection_policy = BluetoothProfile.CONNECTION_POLICY_UNKNOWN; @@ -114,7 +112,6 @@ class ProfilePrioritiesEntity { .append("|SAP=").append(sap_connection_policy) .append("|HEARING_AID=").append(hearing_aid_connection_policy) .append("|LE_AUDIO=").append(le_audio_connection_policy) - .append("|HAP=").append(hap_client_connection_policy) .append("|LE_BROADCAST_ASSISTANT=").append(bass_client_connection_policy) .append("|VOLUME_CONTROL=").append(volume_control_connection_policy); diff --git a/src/com/android/bluetooth/hap/HapClientNativeInterface.java b/src/com/android/bluetooth/hap/HapClientNativeInterface.java deleted file mode 100644 index 5fab43aef..000000000 --- a/src/com/android/bluetooth/hap/HapClientNativeInterface.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright 2021 HIMSA II K/S - www.himsa.com. - * Represented by EHIMA - www.ehima.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bluetooth.hap; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHapPresetInfo; -import android.util.Log; - -import com.android.bluetooth.Utils; -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Hearing Access Profile Client Native Interface to/from JNI. - */ -public class HapClientNativeInterface { - private static final String TAG = "HapClientNativeInterface"; - private static final boolean DBG = true; - private final BluetoothAdapter mAdapter; - - @GuardedBy("INSTANCE_LOCK") - private static HapClientNativeInterface sInstance; - private static final Object INSTANCE_LOCK = new Object(); - - static { - classInitNative(); - } - - private HapClientNativeInterface() { - mAdapter = BluetoothAdapter.getDefaultAdapter(); - if (mAdapter == null) { - Log.wtf(TAG, "No Bluetooth Adapter Available"); - } - } - - /** - * Get singleton instance. - */ - public static HapClientNativeInterface getInstance() { - synchronized (INSTANCE_LOCK) { - if (sInstance == null) { - sInstance = new HapClientNativeInterface(); - } - return sInstance; - } - } - - /** - * Initiates HapClientService connection to a remote device. - * - * @param device the remote device - * @return true on success, otherwise false. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public boolean connectHapClient(BluetoothDevice device) { - return connectHapClientNative(getByteAddress(device)); - } - - /** - * Disconnects HapClientService from a remote device. - * - * @param device the remote device - * @return true on success, otherwise false. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public boolean disconnectHapClient(BluetoothDevice device) { - return disconnectHapClientNative(getByteAddress(device)); - } - - /** - * Gets a HapClientService device - * - * @param address the remote device address - * @return Bluetooth Device. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public BluetoothDevice getDevice(byte[] address) { - return mAdapter.getRemoteDevice(address); - } - - private byte[] getByteAddress(BluetoothDevice device) { - if (device == null) { - return Utils.getBytesFromAddress("00:00:00:00:00:00"); - } - return Utils.getBytesFromAddress(device.getAddress()); - } - - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - void sendMessageToService(HapClientStackEvent event) { - HapClientService service = HapClientService.getHapClientService(); - if (service != null) { - service.messageFromNative(event); - } else { - Log.e(TAG, "Event ignored, service not available: " + event); - } - } - - /** - * Initializes the native interface. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void init() { - initNative(); - } - - /** - * Cleanup the native interface. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void cleanup() { - cleanupNative(); - } - - /** - * Selects the currently active preset for a HA device - * - * @param device is the device for which we want to set the active preset - * @param presetIndex is an index of one of the available presets - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void selectActivePreset(BluetoothDevice device, int presetIndex) { - selectActivePresetNative(getByteAddress(device), presetIndex); - } - - /** - * Selects the currently active preset for a HA device group. - * - * @param groupId is the device group identifier for which want to set the active preset - * @param presetIndex is an index of one of the available presets - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void groupSelectActivePreset(int groupId, int presetIndex) { - groupSelectActivePresetNative(groupId, presetIndex); - } - - /** - * Sets the next preset as a currently active preset for a HA device - * - * @param device is the device for which we want to set the active preset - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void nextActivePreset(BluetoothDevice device) { - nextActivePresetNative(getByteAddress(device)); - } - - /** - * Sets the next preset as a currently active preset for a HA device group - * - * @param groupId is the device group identifier for which want to set the active preset - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void groupNextActivePreset(int groupId) { - groupNextActivePresetNative(groupId); - } - - /** - * Sets the previous preset as a currently active preset for a HA device - * - * @param device is the device for which we want to set the active preset - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void previousActivePreset(BluetoothDevice device) { - previousActivePresetNative(getByteAddress(device)); - } - - /** - * Sets the previous preset as a currently active preset for a HA device group - * - * @param groupId is the device group identifier for which want to set the active preset - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void groupPreviousActivePreset(int groupId) { - groupPreviousActivePresetNative(groupId); - } - - /** - * Requests the preset name - * - * @param device is the device for which we want to get the preset name - * @param presetIndex is an index of one of the available presets - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void getPresetInfo(BluetoothDevice device, int presetIndex) { - getPresetInfoNative(getByteAddress(device), presetIndex); - } - - /** - * Sets the preset name - * - * @param device is the device for which we want to get the preset name - * @param presetIndex is an index of one of the available presets - * @param name is a new name for a preset - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void setPresetName(BluetoothDevice device, int presetIndex, String name) { - setPresetNameNative(getByteAddress(device), presetIndex, name); - } - - /** - * Sets the preset name - * - * @param groupId is the device group - * @param presetIndex is an index of one of the available presets - * @param name is a new name for a preset - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void groupSetPresetName(int groupId, int presetIndex, String name) { - groupSetPresetNameNative(groupId, presetIndex, name); - } - - // Callbacks from the native stack back into the Java framework. - // All callbacks are routed via the Service which will disambiguate which - // state machine the message should be routed to. - - @VisibleForTesting - void onConnectionStateChanged(int state, byte[] address) { - HapClientStackEvent event = - new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - event.device = getDevice(address); - event.valueInt1 = state; - - if (DBG) { - Log.d(TAG, "onConnectionStateChanged: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onDeviceAvailable(byte[] address, int features) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); - event.device = getDevice(address); - event.valueInt1 = features; - - if (DBG) { - Log.d(TAG, "onDeviceAvailable: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onFeaturesUpdate(byte[] address, int features) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_DEVICE_FEATURES); - event.device = getDevice(address); - event.valueInt1 = features; - - if (DBG) { - Log.d(TAG, "onFeaturesUpdate: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onActivePresetSelected(byte[] address, int presetIndex) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_ON_ACTIVE_PRESET_SELECTED); - event.device = getDevice(address); - event.valueInt1 = presetIndex; - - if (DBG) { - Log.d(TAG, "onActivePresetSelected: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onActivePresetGroupSelected(int groupId, int presetIndex) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_ON_ACTIVE_PRESET_SELECTED); - event.valueInt1 = presetIndex; - event.valueInt2 = groupId; - - if (DBG) { - Log.d(TAG, "onActivePresetGroupSelected: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onActivePresetSelectError(byte[] address, int resultCode) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_ON_ACTIVE_PRESET_SELECT_ERROR); - event.device = getDevice(address); - event.valueInt1 = resultCode; - - if (DBG) { - Log.d(TAG, "onActivePresetSelectError: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onActivePresetGroupSelectError(int groupId, int resultCode) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_ON_ACTIVE_PRESET_SELECT_ERROR); - event.valueInt1 = resultCode; - event.valueInt2 = groupId; - - if (DBG) { - Log.d(TAG, "onActivePresetGroupSelectError: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onPresetInfo(byte[] address, int infoReason, BluetoothHapPresetInfo[] presets) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_ON_PRESET_INFO); - event.device = getDevice(address); - event.valueInt2 = infoReason; - event.valueList = new ArrayList<>(Arrays.asList(presets)); - - if (DBG) { - Log.d(TAG, "onPresetInfo: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onGroupPresetInfo(int groupId, int infoReason, BluetoothHapPresetInfo[] presets) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_ON_PRESET_INFO); - event.valueInt2 = infoReason; - event.valueInt3 = groupId; - event.valueList = new ArrayList<>(Arrays.asList(presets)); - - if (DBG) { - Log.d(TAG, "onPresetInfo: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onPresetNameSetError(byte[] address, int presetIndex, int resultCode) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_ON_PRESET_NAME_SET_ERROR); - event.device = getDevice(address); - event.valueInt1 = resultCode; - event.valueInt2 = presetIndex; - - if (DBG) { - Log.d(TAG, "OnPresetNameSetError: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onGroupPresetNameSetError(int groupId, int presetIndex, int resultCode) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_ON_PRESET_NAME_SET_ERROR); - event.valueInt1 = resultCode; - event.valueInt2 = presetIndex; - event.valueInt3 = groupId; - - if (DBG) { - Log.d(TAG, "OnPresetNameSetError: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onPresetInfoError(byte[] address, int presetIndex, int resultCode) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_ON_PRESET_INFO_ERROR); - event.device = getDevice(address); - event.valueInt1 = resultCode; - event.valueInt2 = presetIndex; - - if (DBG) { - Log.d(TAG, "onPresetInfoError: " + event); - } - sendMessageToService(event); - } - - @VisibleForTesting - void onGroupPresetInfoError(int groupId, int presetIndex, int resultCode) { - HapClientStackEvent event = new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_ON_PRESET_INFO_ERROR); - event.valueInt1 = resultCode; - event.valueInt2 = presetIndex; - event.valueInt3 = groupId; - - if (DBG) { - Log.d(TAG, "onPresetInfoError: " + event); - } - sendMessageToService(event); - } - - // Native methods that call into the JNI interface - private static native void classInitNative(); - private native void initNative(); - private native void cleanupNative(); - private native boolean connectHapClientNative(byte[] address); - private native boolean disconnectHapClientNative(byte[] address); - private native void selectActivePresetNative(byte[] byteAddress, int presetIndex); - private native void groupSelectActivePresetNative(int groupId, int presetIndex); - private native void nextActivePresetNative(byte[] byteAddress); - private native void groupNextActivePresetNative(int groupId); - private native void previousActivePresetNative(byte[] byteAddress); - private native void groupPreviousActivePresetNative(int groupId); - private native void getPresetInfoNative(byte[] byteAddress, int presetIndex); - private native void setPresetNameNative(byte[] byteAddress, int presetIndex, String name); - private native void groupSetPresetNameNative(int groupId, int presetIndex, String name); -} diff --git a/src/com/android/bluetooth/hap/HapClientService.java b/src/com/android/bluetooth/hap/HapClientService.java deleted file mode 100644 index 5d39558b6..000000000 --- a/src/com/android/bluetooth/hap/HapClientService.java +++ /dev/null @@ -1,1674 +0,0 @@ -/* - * Copyright 2021 HIMSA II K/S - www.himsa.com. - * Represented by EHIMA - www.ehima.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bluetooth.hap; - -import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; - -import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission; - -import android.annotation.Nullable; -import android.bluetooth.BluetoothCsipSetCoordinator; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHapClient; -import android.bluetooth.BluetoothHapPresetInfo; -import android.bluetooth.BluetoothLeAudio; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothStatusCodes; -import android.bluetooth.BluetoothUuid; -import android.bluetooth.IBluetoothHapClient; -import android.bluetooth.IBluetoothHapClientCallback; -import android.content.AttributionSource; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.HandlerThread; -import android.os.ParcelUuid; -import android.os.RemoteCallbackList; -import android.os.RemoteException; -import android.sysprop.BluetoothProperties; -import android.util.Log; - -import com.android.bluetooth.Utils; -import com.android.bluetooth.btservice.AdapterService; -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.internal.annotations.VisibleForTesting; -import com.android.modules.utils.SynchronousResultReceiver; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Objects; - -/** - * Provides Bluetooth Hearing Access profile, as a service. - * @hide - */ -public class HapClientService extends ProfileService { - private static final boolean DBG = true; - private static final String TAG = "HapClientService"; - - // Upper limit of all HearingAccess devices: Bonded or Connected - private static final int MAX_HEARING_ACCESS_STATE_MACHINES = 10; - private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1000; - private static HapClientService sHapClient; - private final Map<BluetoothDevice, HapClientStateMachine> mStateMachines = - new HashMap<>(); - @VisibleForTesting - HapClientNativeInterface mHapClientNativeInterface; - private AdapterService mAdapterService; - private DatabaseManager mDatabaseManager; - private HandlerThread mStateMachinesThread; - private BroadcastReceiver mBondStateChangedReceiver; - private BroadcastReceiver mConnectionStateChangedReceiver; - - private final Map<BluetoothDevice, Integer> mDeviceCurrentPresetMap = new HashMap<>(); - private final Map<BluetoothDevice, Integer> mDeviceFeaturesMap = new HashMap<>(); - private final Map<BluetoothDevice, List<BluetoothHapPresetInfo>> mPresetsMap = - new HashMap<>(); - - @VisibleForTesting - RemoteCallbackList<IBluetoothHapClientCallback> mCallbacks; - - @VisibleForTesting - ServiceFactory mFactory = new ServiceFactory(); - - public static boolean isEnabled() { - return BluetoothProperties.isProfileHapClientEnabled().orElse(false); - } - - private static synchronized void setHapClient(HapClientService instance) { - if (DBG) { - Log.d(TAG, "setHapClient(): set to: " + instance); - } - sHapClient = instance; - } - - /** - * Get the HapClientService instance - * @return HapClientService instance - */ - public static synchronized HapClientService getHapClientService() { - if (sHapClient == null) { - Log.w(TAG, "getHapClientService(): service is NULL"); - return null; - } - - if (!sHapClient.isAvailable()) { - Log.w(TAG, "getHapClientService(): service is not available"); - return null; - } - return sHapClient; - } - - @Override - protected void create() { - if (DBG) { - Log.d(TAG, "create()"); - } - } - - @Override - protected void cleanup() { - if (DBG) { - Log.d(TAG, "cleanup()"); - } - } - - @Override - protected IProfileServiceBinder initBinder() { - return new BluetoothHapClientBinder(this); - } - - @Override - protected boolean start() { - if (DBG) { - Log.d(TAG, "start()"); - } - - if (sHapClient != null) { - throw new IllegalStateException("start() called twice"); - } - - // Get AdapterService, HapClientNativeInterface, DatabaseManager, AudioManager. - // None of them can be null. - mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(), - "AdapterService cannot be null when HapClientService starts"); - mDatabaseManager = Objects.requireNonNull(mAdapterService.getDatabase(), - "DatabaseManager cannot be null when HapClientService starts"); - mHapClientNativeInterface = Objects.requireNonNull( - HapClientNativeInterface.getInstance(), - "HapClientNativeInterface cannot be null when HapClientService starts"); - - // Start handler thread for state machines - mStateMachines.clear(); - mStateMachinesThread = new HandlerThread("HapClientService.StateMachines"); - mStateMachinesThread.start(); - - // Setup broadcast receivers - IntentFilter filter = new IntentFilter(); - filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); - mBondStateChangedReceiver = new BondStateChangedReceiver(); - registerReceiver(mBondStateChangedReceiver, filter); - filter = new IntentFilter(); - filter.addAction(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED); - mConnectionStateChangedReceiver = new ConnectionStateChangedReceiver(); - registerReceiver(mConnectionStateChangedReceiver, filter, Context.RECEIVER_NOT_EXPORTED); - - mCallbacks = new RemoteCallbackList<IBluetoothHapClientCallback>(); - - // Initialize native interface - mHapClientNativeInterface.init(); - - // Mark service as started - setHapClient(this); - - return true; - } - - @Override - protected boolean stop() { - if (DBG) { - Log.d(TAG, "stop()"); - } - if (sHapClient == null) { - Log.w(TAG, "stop() called before start()"); - return true; - } - - // Marks service as stopped - setHapClient(null); - - // Unregister broadcast receivers - unregisterReceiver(mBondStateChangedReceiver); - mBondStateChangedReceiver = null; - unregisterReceiver(mConnectionStateChangedReceiver); - mConnectionStateChangedReceiver = null; - - // Destroy state machines and stop handler thread - synchronized (mStateMachines) { - for (HapClientStateMachine sm : mStateMachines.values()) { - sm.doQuit(); - sm.cleanup(); - } - mStateMachines.clear(); - } - - if (mStateMachinesThread != null) { - try { - mStateMachinesThread.quitSafely(); - mStateMachinesThread.join(SM_THREAD_JOIN_TIMEOUT_MS); - mStateMachinesThread = null; - } catch (InterruptedException e) { - // Do not rethrow as we are shutting down anyway - } - } - - // Cleanup GATT interface - mHapClientNativeInterface.cleanup(); - mHapClientNativeInterface = null; - - // Cleanup the internals - mDeviceCurrentPresetMap.clear(); - mDeviceFeaturesMap.clear(); - mPresetsMap.clear(); - - if (mCallbacks != null) { - mCallbacks.kill(); - } - - // Clear AdapterService - mAdapterService = null; - - return true; - } - - @VisibleForTesting - void bondStateChanged(BluetoothDevice device, int bondState) { - if (DBG) { - Log.d(TAG, "Bond state changed for device: " + device + " state: " + bondState); - } - - // Remove state machine if the bonding for a device is removed - if (bondState != BluetoothDevice.BOND_NONE) { - return; - } - - mDeviceCurrentPresetMap.remove(device); - mDeviceFeaturesMap.remove(device); - mPresetsMap.remove(device); - - synchronized (mStateMachines) { - HapClientStateMachine sm = mStateMachines.get(device); - if (sm == null) { - return; - } - if (sm.getConnectionState() != BluetoothProfile.STATE_DISCONNECTED) { - Log.i(TAG, "Disconnecting device because it was unbonded."); - disconnect(device); - return; - } - removeStateMachine(device); - } - } - - private void removeStateMachine(BluetoothDevice device) { - synchronized (mStateMachines) { - HapClientStateMachine sm = mStateMachines.get(device); - if (sm == null) { - Log.w(TAG, "removeStateMachine: device " + device - + " does not have a state machine"); - return; - } - Log.i(TAG, "removeStateMachine: removing state machine for device: " + device); - sm.doQuit(); - sm.cleanup(); - mStateMachines.remove(device); - } - } - - List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { - enforceCallingOrSelfPermission(BLUETOOTH_CONNECT, "Need BLUETOOTH_CONNECT permission"); - ArrayList<BluetoothDevice> devices = new ArrayList<>(); - if (states == null) { - return devices; - } - final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices(); - if (bondedDevices == null) { - return devices; - } - synchronized (mStateMachines) { - for (BluetoothDevice device : bondedDevices) { - final ParcelUuid[] featureUuids = device.getUuids(); - if (!Utils.arrayContains(featureUuids, BluetoothUuid.HAS)) { - continue; - } - int connectionState = BluetoothProfile.STATE_DISCONNECTED; - HapClientStateMachine sm = mStateMachines.get(device); - if (sm != null) { - connectionState = sm.getConnectionState(); - } - for (int state : states) { - if (connectionState == state) { - devices.add(device); - break; - } - } - } - return devices; - } - } - - List<BluetoothDevice> getConnectedDevices() { - synchronized (mStateMachines) { - List<BluetoothDevice> devices = new ArrayList<>(); - for (HapClientStateMachine sm : mStateMachines.values()) { - if (sm.isConnected()) { - devices.add(sm.getDevice()); - } - } - return devices; - } - } - - /** - * Get the current connection state of the profile - * - * @param device is the remote bluetooth device - * @return {@link BluetoothProfile#STATE_DISCONNECTED} if this profile is disconnected, - * {@link BluetoothProfile#STATE_CONNECTING} if this profile is being connected, - * {@link BluetoothProfile#STATE_CONNECTED} if this profile is connected, or - * {@link BluetoothProfile#STATE_DISCONNECTING} if this profile is being disconnected - */ - public int getConnectionState(BluetoothDevice device) { - enforceCallingOrSelfPermission(BLUETOOTH_CONNECT, "Need BLUETOOTH_CONNECT permission"); - synchronized (mStateMachines) { - HapClientStateMachine sm = mStateMachines.get(device); - if (sm == null) { - return BluetoothProfile.STATE_DISCONNECTED; - } - return sm.getConnectionState(); - } - } - - /** - * Set connection policy of the profile and connects it if connectionPolicy is - * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED} or disconnects if connectionPolicy is - * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN} - * - * <p> The device should already be paired. - * Connection policy can be one of: - * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, - * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, - * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} - * - * @param device the remote device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true on success, otherwise false - */ - public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { - enforceBluetoothPrivilegedPermission(this); - if (DBG) { - Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy); - } - mDatabaseManager.setProfileConnectionPolicy(device, BluetoothProfile.HAP_CLIENT, - connectionPolicy); - if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - connect(device); - } else if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { - disconnect(device); - } - return true; - } - - /** - * Get the connection policy of the profile. - * - * <p> The connection policy can be any of: - * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, - * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, - * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - public int getConnectionPolicy(BluetoothDevice device) { - return mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.HAP_CLIENT); - } - - /** - * Check whether can connect to a peer device. - * The check considers a number of factors during the evaluation. - * - * @param device the peer device to connect to - * @return true if connection is allowed, otherwise false - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public boolean okToConnect(BluetoothDevice device) { - // Check if this is an incoming connection in Quiet mode. - if (mAdapterService.isQuietModeEnabled()) { - Log.e(TAG, "okToConnect: cannot connect to " + device + " : quiet mode enabled"); - return false; - } - // Check connection policy and accept or reject the connection. - int connectionPolicy = getConnectionPolicy(device); - int bondState = mAdapterService.getBondState(device); - // Allow this connection only if the device is bonded. Any attempt to connect while - // bonding would potentially lead to an unauthorized connection. - if (bondState != BluetoothDevice.BOND_BONDED) { - Log.w(TAG, "okToConnect: return false, bondState=" + bondState); - return false; - } else if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_UNKNOWN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - // Otherwise, reject the connection if connectionPolicy is not valid. - Log.w(TAG, "okToConnect: return false, connectionPolicy=" + connectionPolicy); - return false; - } - return true; - } - - @VisibleForTesting - synchronized void connectionStateChanged(BluetoothDevice device, int fromState, - int toState) { - if ((device == null) || (fromState == toState)) { - Log.e(TAG, "connectionStateChanged: unexpected invocation. device=" + device - + " fromState=" + fromState + " toState=" + toState); - return; - } - - // Check if the device is disconnected - if unbond, remove the state machine - if (toState == BluetoothProfile.STATE_DISCONNECTED) { - int bondState = mAdapterService.getBondState(device); - if (bondState == BluetoothDevice.BOND_NONE) { - if (DBG) { - Log.d(TAG, device + " is unbond. Remove state machine"); - } - removeStateMachine(device); - } - } - } - - /** - * Connects the hearing access service client to the passed in device - * - * @param device is the device with which we will connect the hearing access service client - * @return true if hearing access service client successfully connected, false otherwise - */ - public boolean connect(BluetoothDevice device) { - enforceBluetoothPrivilegedPermission(this); - if (DBG) { - Log.d(TAG, "connect(): " + device); - } - if (device == null) { - return false; - } - - if (getConnectionPolicy(device) == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { - return false; - } - ParcelUuid[] featureUuids = mAdapterService.getRemoteUuids(device); - if (!Utils.arrayContains(featureUuids, BluetoothUuid.HAS)) { - Log.e(TAG, "Cannot connect to " + device - + " : Remote does not have Hearing Access Service UUID"); - return false; - } - synchronized (mStateMachines) { - HapClientStateMachine smConnect = getOrCreateStateMachine(device); - if (smConnect == null) { - Log.e(TAG, "Cannot connect to " + device + " : no state machine"); - } - smConnect.sendMessage(HapClientStateMachine.CONNECT); - } - - return true; - } - - /** - * Disconnects hearing access service client for the passed in device - * - * @param device is the device with which we want to disconnect the hearing access service - * client - * @return true if hearing access service client successfully disconnected, false otherwise - */ - public boolean disconnect(BluetoothDevice device) { - enforceBluetoothPrivilegedPermission(this); - if (DBG) { - Log.d(TAG, "disconnect(): " + device); - } - if (device == null) { - return false; - } - synchronized (mStateMachines) { - HapClientStateMachine sm = mStateMachines.get(device); - if (sm != null) { - sm.sendMessage(HapClientStateMachine.DISCONNECT); - } - } - - return true; - } - - private HapClientStateMachine getOrCreateStateMachine(BluetoothDevice device) { - if (device == null) { - Log.e(TAG, "getOrCreateStateMachine failed: device cannot be null"); - return null; - } - synchronized (mStateMachines) { - HapClientStateMachine sm = mStateMachines.get(device); - if (sm != null) { - return sm; - } - // Limit the maximum number of state machines to avoid DoS attack - if (mStateMachines.size() >= MAX_HEARING_ACCESS_STATE_MACHINES) { - Log.e(TAG, "Maximum number of HearingAccess state machines reached: " - + MAX_HEARING_ACCESS_STATE_MACHINES); - return null; - } - if (DBG) { - Log.d(TAG, "Creating a new state machine for " + device); - } - sm = HapClientStateMachine.make(device, this, - mHapClientNativeInterface, mStateMachinesThread.getLooper()); - mStateMachines.put(device, sm); - return sm; - } - } - - /** - * Gets the hearing access device group of the passed device - * - * @param device is the device with which we want to get the group identifier for - * @return group ID if device is part of the coordinated group, 0 otherwise - */ - public int getHapGroup(BluetoothDevice device) { - CsipSetCoordinatorService csipClient = mFactory.getCsipSetCoordinatorService(); - - if (csipClient != null) { - Map<Integer, ParcelUuid> groups = csipClient.getGroupUuidMapByDevice(device); - for (Map.Entry<Integer, ParcelUuid> entry : groups.entrySet()) { - if (entry.getValue().equals(BluetoothUuid.CAP)) { - return entry.getKey(); - } - } - } - return BluetoothCsipSetCoordinator.GROUP_ID_INVALID; - } - - /** - * Gets the currently active preset index for a HA device - * - * @param device is the device for which we want to get the currently active preset - * @return active preset index - */ - public int getActivePresetIndex(BluetoothDevice device) { - return mDeviceCurrentPresetMap.getOrDefault(device, - BluetoothHapClient.PRESET_INDEX_UNAVAILABLE); - } - - /** - * Gets the currently active preset info for a HA device - * - * @param device is the device for which we want to get the currently active preset info - * @return active preset info or null if not available - */ - public @Nullable BluetoothHapPresetInfo getActivePresetInfo(BluetoothDevice device) { - int index = getActivePresetIndex(device); - if (index == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) return null; - - List<BluetoothHapPresetInfo> current_presets = mPresetsMap.get(device); - if (current_presets != null) { - for (BluetoothHapPresetInfo preset : current_presets) { - if (preset.getIndex() == index) { - return preset; - } - } - } - - return null; - } - - /** - * Selects the currently active preset for a HA device - * - * @param device is the device for which we want to set the active preset - * @param presetIndex is an index of one of the available presets - */ - public void selectPreset(BluetoothDevice device, int presetIndex) { - if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) { - if (mCallbacks != null) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onPresetSelectionFailed(device, - BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX); - } catch (RemoteException e) { - continue; - } - } - mCallbacks.finishBroadcast(); - } - return; - } - - mHapClientNativeInterface.selectActivePreset(device, presetIndex); - } - - /** - * Selects the currently active preset for a HA device group. - * - * @param groupId is the device group identifier for which want to set the active preset - * @param presetIndex is an index of one of the available presets - */ - public void selectPresetForGroup(int groupId, int presetIndex) { - int status = BluetoothStatusCodes.SUCCESS; - - if (!isGroupIdValid(groupId)) { - status = BluetoothStatusCodes.ERROR_CSIP_INVALID_GROUP_ID; - } else if (!isPresetIndexValid(groupId, presetIndex)) { - status = BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX; - } - - if (status != BluetoothStatusCodes.SUCCESS) { - if (mCallbacks != null) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i) - .onPresetSelectionForGroupFailed(groupId, status); - } catch (RemoteException e) { - continue; - } - } - mCallbacks.finishBroadcast(); - } - return; - } - - mHapClientNativeInterface.groupSelectActivePreset(groupId, presetIndex); - } - - /** - * Sets the next preset as a currently active preset for a HA device - * - * @param device is the device for which we want to set the active preset - */ - public void switchToNextPreset(BluetoothDevice device) { - mHapClientNativeInterface.nextActivePreset(device); - } - - /** - * Sets the next preset as a currently active preset for a HA device group - * - * @param groupId is the device group identifier for which want to set the active preset - */ - public void switchToNextPresetForGroup(int groupId) { - mHapClientNativeInterface.groupNextActivePreset(groupId); - } - - /** - * Sets the previous preset as a currently active preset for a HA device - * - * @param device is the device for which we want to set the active preset - */ - public void switchToPreviousPreset(BluetoothDevice device) { - mHapClientNativeInterface.previousActivePreset(device); - } - - /** - * Sets the previous preset as a currently active preset for a HA device group - * - * @param groupId is the device group identifier for which want to set the active preset - */ - public void switchToPreviousPresetForGroup(int groupId) { - mHapClientNativeInterface.groupPreviousActivePreset(groupId); - } - - /** - * Requests the preset name - * - * @param device is the device for which we want to get the preset name - * @param presetIndex is an index of one of the available presets - * @return a preset Info corresponding to the requested preset index or null if not available - */ - public @Nullable BluetoothHapPresetInfo getPresetInfo(BluetoothDevice device, int presetIndex) { - BluetoothHapPresetInfo defaultValue = null; - if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) return defaultValue; - - if (Utils.isPtsTestMode()) { - /* We want native to be called for PTS testing even we have all - * the data in the cache here - */ - mHapClientNativeInterface.getPresetInfo(device, presetIndex); - } - List<BluetoothHapPresetInfo> current_presets = mPresetsMap.get(device); - if (current_presets != null) { - for (BluetoothHapPresetInfo preset : current_presets) { - if (preset.getIndex() == presetIndex) { - return preset; - } - } - } - - return defaultValue; - } - - /** - * Requests all presets info - * - * @param device is the device for which we want to get all presets info - * @return a list of all presets Info - */ - public List<BluetoothHapPresetInfo> getAllPresetInfo(BluetoothDevice device) { - if (mPresetsMap.containsKey(device)) { - return mPresetsMap.get(device); - } - return Collections.emptyList(); - } - - /** - * Requests features - * - * @param device is the device for which we want to get features - * @return integer with feature bits set - */ - public int getFeatures(BluetoothDevice device) { - if (mDeviceFeaturesMap.containsKey(device)) { - return mDeviceFeaturesMap.get(device); - } - return 0x00; - } - - private int stackEventPresetInfoReasonToProfileStatus(int statusCode) { - switch (statusCode) { - case HapClientStackEvent.PRESET_INFO_REASON_ALL_PRESET_INFO: - return BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST; - case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_UPDATE: - return BluetoothStatusCodes.REASON_REMOTE_REQUEST; - case HapClientStackEvent.PRESET_INFO_REASON_PRESET_DELETED: - return BluetoothStatusCodes.REASON_REMOTE_REQUEST; - case HapClientStackEvent.PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED: - return BluetoothStatusCodes.REASON_REMOTE_REQUEST; - case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE: - return BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST; - default: - return BluetoothStatusCodes.ERROR_UNKNOWN; - } - } - - private void notifyPresetInfoChanged(BluetoothDevice device, int infoReason) { - List current_presets = mPresetsMap.get(device); - if (current_presets == null) return; - - if (mCallbacks != null) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onPresetInfoChanged(device, current_presets, - stackEventPresetInfoReasonToProfileStatus(infoReason)); - } catch (RemoteException e) { - continue; - } - } - mCallbacks.finishBroadcast(); - } - } - - private void notifyPresetInfoForGroupChanged(int groupId, int infoReason) { - List<BluetoothDevice> all_group_devices = getGroupDevices(groupId); - for (BluetoothDevice dev : all_group_devices) { - notifyPresetInfoChanged(dev, infoReason); - } - } - - private void notifyFeaturesAvailable(BluetoothDevice device, int features) { - Log.d(TAG, "HAP device: " + device + ", features: " + String.format("0x%04X", features)); - } - - private void notifyActivePresetChanged(BluetoothDevice device, int presetIndex, - int reasonCode) { - if (mCallbacks != null) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onPresetSelected(device, presetIndex, - reasonCode); - } catch (RemoteException e) { - continue; - } - } - mCallbacks.finishBroadcast(); - } - } - - private void notifyActivePresetChangedForGroup(int groupId, int presetIndex, int reasonCode) { - List<BluetoothDevice> all_group_devices = getGroupDevices(groupId); - for (BluetoothDevice dev : all_group_devices) { - notifyActivePresetChanged(dev, presetIndex, reasonCode); - } - } - - private int stackEventStatusToProfileStatus(int statusCode) { - switch (statusCode) { - case HapClientStackEvent.STATUS_SET_NAME_NOT_ALLOWED: - return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED; - case HapClientStackEvent.STATUS_OPERATION_NOT_SUPPORTED: - return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED; - case HapClientStackEvent.STATUS_OPERATION_NOT_POSSIBLE: - return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED; - case HapClientStackEvent.STATUS_INVALID_PRESET_NAME_LENGTH: - return BluetoothStatusCodes.ERROR_HAP_PRESET_NAME_TOO_LONG; - case HapClientStackEvent.STATUS_INVALID_PRESET_INDEX: - return BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX; - case HapClientStackEvent.STATUS_GROUP_OPERATION_NOT_SUPPORTED: - return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED; - case HapClientStackEvent.STATUS_PROCEDURE_ALREADY_IN_PROGRESS: - return BluetoothStatusCodes.ERROR_UNKNOWN; - default: - return BluetoothStatusCodes.ERROR_UNKNOWN; - } - } - - private void notifySelectActivePresetFailed(BluetoothDevice device, int statusCode) { - if (mCallbacks != null) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onPresetSelectionFailed(device, - stackEventStatusToProfileStatus(statusCode)); - } catch (RemoteException e) { - continue; - } - } - mCallbacks.finishBroadcast(); - } - } - - private void notifySelectActivePresetForGroupFailed(int groupId, int statusCode) { - if (mCallbacks != null) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onPresetSelectionForGroupFailed(groupId, - stackEventStatusToProfileStatus(statusCode)); - } catch (RemoteException e) { - continue; - } - } - mCallbacks.finishBroadcast(); - } - } - - private void notifySetPresetNameFailed(BluetoothDevice device, int statusCode) { - if (mCallbacks != null) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onSetPresetNameFailed(device, - stackEventStatusToProfileStatus(statusCode)); - } catch (RemoteException e) { - continue; - } - } - mCallbacks.finishBroadcast(); - } - } - - private void notifySetPresetNameForGroupFailed(int groupId, int statusCode) { - if (mCallbacks != null) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onSetPresetNameForGroupFailed(groupId, - stackEventStatusToProfileStatus(statusCode)); - } catch (RemoteException e) { - continue; - } - } - mCallbacks.finishBroadcast(); - } - } - - private boolean isPresetIndexValid(BluetoothDevice device, int presetIndex) { - if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) return false; - - List<BluetoothHapPresetInfo> device_presets = mPresetsMap.get(device); - if (device_presets != null) { - for (BluetoothHapPresetInfo preset : device_presets) { - if (preset.getIndex() == presetIndex) { - return true; - } - } - } - return false; - } - - private boolean isPresetIndexValid(int groupId, int presetIndex) { - List<BluetoothDevice> all_group_devices = getGroupDevices(groupId); - if (all_group_devices.isEmpty()) return false; - - for (BluetoothDevice device : all_group_devices) { - if (!isPresetIndexValid(device, presetIndex)) return false; - } - return true; - } - - - private boolean isGroupIdValid(int groupId) { - if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) return false; - - CsipSetCoordinatorService csipClient = mFactory.getCsipSetCoordinatorService(); - if (csipClient != null) { - List<Integer> groups = csipClient.getAllGroupIds(BluetoothUuid.CAP); - return groups.contains(groupId); - } - return false; - } - - /** - * Sets the preset name - * - * @param device is the device for which we want to get the preset name - * @param presetIndex is an index of one of the available presets - * @param name is a new name for a preset - */ - public void setPresetName(BluetoothDevice device, int presetIndex, String name) { - if (!isPresetIndexValid(device, presetIndex)) { - if (mCallbacks != null) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onSetPresetNameFailed(device, - BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX); - } catch (RemoteException e) { - continue; - } - } - mCallbacks.finishBroadcast(); - } - return; - } - // WARNING: We should check cache if preset exists and is writable, but then we would still - // need a way to trigger this action with an invalid index or on a non-writable - // preset for tests purpose. - mHapClientNativeInterface.setPresetName(device, presetIndex, name); - } - - /** - * Sets the preset name - * - * @param groupId is the device group identifier - * @param presetIndex is an index of one of the available presets - * @param name is a new name for a preset - */ - public void setPresetNameForGroup(int groupId, int presetIndex, String name) { - int status = BluetoothStatusCodes.SUCCESS; - - if (!isGroupIdValid(groupId)) { - status = BluetoothStatusCodes.ERROR_CSIP_INVALID_GROUP_ID; - } else if (!isPresetIndexValid(groupId, presetIndex)) { - status = BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX; - } - if (status != BluetoothStatusCodes.SUCCESS) { - if (mCallbacks != null) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onSetPresetNameForGroupFailed(groupId, - status); - } catch (RemoteException e) { - continue; - } - } - mCallbacks.finishBroadcast(); - } - return; - } - - mHapClientNativeInterface.groupSetPresetName(groupId, presetIndex, name); - } - - @Override - public void dump(StringBuilder sb) { - super.dump(sb); - for (HapClientStateMachine sm : mStateMachines.values()) { - sm.dump(sb); - } - } - - private boolean isPresetCoordinationSupported(BluetoothDevice device) { - Integer features = mDeviceFeaturesMap.getOrDefault(device, 0x00); - return BigInteger.valueOf(features).testBit( - HapClientStackEvent.FEATURE_BIT_NUM_SYNCHRONIZATED_PRESETS); - } - - void updateDevicePresetsCache(BluetoothDevice device, int infoReason, - List<BluetoothHapPresetInfo> presets) { - switch (infoReason) { - case HapClientStackEvent.PRESET_INFO_REASON_ALL_PRESET_INFO: - mPresetsMap.put(device, presets); - break; - case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_UPDATE: - case HapClientStackEvent.PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED: - case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE: { - List current_presets = mPresetsMap.get(device); - if (current_presets != null) { - ListIterator<BluetoothHapPresetInfo> iter = current_presets.listIterator(); - for (BluetoothHapPresetInfo new_preset : presets) { - while (iter.hasNext()) { - if (iter.next().getIndex() == new_preset.getIndex()) { - iter.remove(); - } - } - } - current_presets.addAll(presets); - mPresetsMap.put(device, current_presets); - } else { - mPresetsMap.put(device, presets); - } - } - break; - - case HapClientStackEvent.PRESET_INFO_REASON_PRESET_DELETED: { - List current_presets = mPresetsMap.get(device); - if (current_presets != null) { - ListIterator<BluetoothHapPresetInfo> iter = current_presets.listIterator(); - for (BluetoothHapPresetInfo new_preset : presets) { - while (iter.hasNext()) { - if (iter.next().getIndex() == new_preset.getIndex()) { - iter.remove(); - } - } - } - mPresetsMap.put(device, current_presets); - } - } - break; - - default: - break; - } - } - - private List<BluetoothDevice> getGroupDevices(int groupId) { - List<BluetoothDevice> devices = new ArrayList<>(); - - CsipSetCoordinatorService csipClient = mFactory.getCsipSetCoordinatorService(); - if (csipClient != null) { - if (groupId != BluetoothLeAudio.GROUP_ID_INVALID) { - //Phanee TODO: - //devices = csipClient.getGroupUuidMapByDevice(groupId); - } - } - return devices; - } - - /** - * Handle messages from native (JNI) to Java - * - * @param stackEvent the event that need to be handled - */ - public void messageFromNative(HapClientStackEvent stackEvent) { - // Decide which event should be sent to the state machine - if (stackEvent.type == HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) { - resendToStateMachine(stackEvent); - return; - } - - Intent intent = null; - BluetoothDevice device = stackEvent.device; - - switch (stackEvent.type) { - case (HapClientStackEvent.EVENT_TYPE_DEVICE_AVAILABLE): { - int features = stackEvent.valueInt1; - - if (device != null) { - mDeviceFeaturesMap.put(device, features); - - intent = new Intent(BluetoothHapClient.ACTION_HAP_DEVICE_AVAILABLE); - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); - intent.putExtra(BluetoothHapClient.EXTRA_HAP_FEATURES, features); - } - } break; - - case (HapClientStackEvent.EVENT_TYPE_DEVICE_FEATURES): { - int features = stackEvent.valueInt1; - - if (device != null) { - mDeviceFeaturesMap.put(device, features); - notifyFeaturesAvailable(device, features); - } - } return; - - case (HapClientStackEvent.EVENT_TYPE_ON_ACTIVE_PRESET_SELECTED): { - int currentPresetIndex = stackEvent.valueInt1; - int groupId = stackEvent.valueInt2; - - if (device != null) { - mDeviceCurrentPresetMap.put(device, currentPresetIndex); - // FIXME: Add app request queueing to support other reasons - int reasonCode = BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST; - notifyActivePresetChanged(device, currentPresetIndex, reasonCode); - - } else if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { - List<BluetoothDevice> all_group_devices = getGroupDevices(groupId); - for (BluetoothDevice dev : all_group_devices) { - mDeviceCurrentPresetMap.put(dev, currentPresetIndex); - } - // FIXME: Add app request queueing to support other reasons - int reasonCode = BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST; - notifyActivePresetChangedForGroup(groupId, currentPresetIndex, reasonCode); - } - } return; - - case (HapClientStackEvent.EVENT_TYPE_ON_ACTIVE_PRESET_SELECT_ERROR): { - int groupId = stackEvent.valueInt2; - int statusCode = stackEvent.valueInt1; - - if (device != null) { - notifySelectActivePresetFailed(device, statusCode); - } else if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { - notifySelectActivePresetForGroupFailed(groupId, statusCode); - } - } break; - - case (HapClientStackEvent.EVENT_TYPE_ON_PRESET_INFO): { - int presetIndex = stackEvent.valueInt1; - int infoReason = stackEvent.valueInt2; - int groupId = stackEvent.valueInt3; - ArrayList presets = stackEvent.valueList; - - if (device != null) { - updateDevicePresetsCache(device, infoReason, presets); - notifyPresetInfoChanged(device, infoReason); - - } else if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { - List<BluetoothDevice> all_group_devices = getGroupDevices(groupId); - for (BluetoothDevice dev : all_group_devices) { - updateDevicePresetsCache(dev, infoReason, presets); - } - notifyPresetInfoForGroupChanged(groupId, infoReason); - } - - } return; - - case (HapClientStackEvent.EVENT_TYPE_ON_PRESET_NAME_SET_ERROR): { - int statusCode = stackEvent.valueInt1; - int presetIndex = stackEvent.valueInt2; - int groupId = stackEvent.valueInt3; - - if (device != null) { - notifySetPresetNameFailed(device, statusCode); - } else if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { - notifySetPresetNameForGroupFailed(groupId, statusCode); - } - } break; - - case (HapClientStackEvent.EVENT_TYPE_ON_PRESET_INFO_ERROR): { - // Used only to report back on hidden API calls used for testing. - Log.d(TAG, stackEvent.toString()); - } break; - - default: - return; - } - - if (intent != null) { - sendBroadcast(intent, BLUETOOTH_PRIVILEGED); - } - } - - private void resendToStateMachine(HapClientStackEvent stackEvent) { - synchronized (mStateMachines) { - BluetoothDevice device = stackEvent.device; - HapClientStateMachine sm = mStateMachines.get(device); - - if (sm == null) { - if (stackEvent.type == HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) { - switch (stackEvent.valueInt1) { - case HapClientStackEvent.CONNECTION_STATE_CONNECTED: - case HapClientStackEvent.CONNECTION_STATE_CONNECTING: - sm = getOrCreateStateMachine(device); - break; - default: - break; - } - } - } - if (sm == null) { - Log.e(TAG, "Cannot process stack event: no state machine: " + stackEvent); - return; - } - sm.sendMessage(HapClientStateMachine.STACK_EVENT, stackEvent); - } - } - - /** - * Binder object: must be a static class or memory leak may occur - */ - @VisibleForTesting - static class BluetoothHapClientBinder extends IBluetoothHapClient.Stub - implements IProfileServiceBinder { - @VisibleForTesting - boolean mIsTesting = false; - private HapClientService mService; - - BluetoothHapClientBinder(HapClientService svc) { - mService = svc; - } - - private HapClientService getService(AttributionSource source) { - if (mIsTesting) { - return mService; - } - if (!Utils.checkServiceAvailable(mService, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(mService, TAG) - || !Utils.checkConnectPermissionForDataDelivery(mService, source, TAG)) { - Log.w(TAG, "Hearing Access call not allowed for non-active user"); - return null; - } - - if (mService != null && mService.isAvailable()) { - return mService; - } - return null; - } - - @Override - public void cleanup() { - mService = null; - } - - @Override - public void getConnectedDevices(AttributionSource source, - SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - List<BluetoothDevice> defaultValue = new ArrayList<>(); - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.getConnectedDevices(); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void getDevicesMatchingConnectionStates(int[] states, - AttributionSource source, SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - List<BluetoothDevice> defaultValue = new ArrayList<>(); - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.getDevicesMatchingConnectionStates(states); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void getConnectionState(BluetoothDevice device, AttributionSource source, - SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(device, "device cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.getConnectionState(device); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void setConnectionPolicy(BluetoothDevice device, int connectionPolicy, - AttributionSource source, SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(device, "device cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - boolean defaultValue = false; - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.setConnectionPolicy(device, connectionPolicy); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void getConnectionPolicy(BluetoothDevice device, AttributionSource source, - SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(device, "device cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - int defaultValue = BluetoothProfile.CONNECTION_POLICY_UNKNOWN; - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.getConnectionPolicy(device); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void getActivePresetIndex(BluetoothDevice device, AttributionSource source, - SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(device, "device cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - int defaultValue = BluetoothHapClient.PRESET_INDEX_UNAVAILABLE; - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.getActivePresetIndex(device); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void getActivePresetInfo(BluetoothDevice device, - AttributionSource source, SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(device, "device cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - BluetoothHapPresetInfo defaultValue = null; - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.getActivePresetInfo(device); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void getHapGroup(BluetoothDevice device, AttributionSource source, - SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(device, "device cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - int defaultValue = BluetoothCsipSetCoordinator.GROUP_ID_INVALID; - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.getHapGroup(device); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void selectPreset(BluetoothDevice device, int presetIndex, - AttributionSource source) { - if (source == null) { - Log.w(TAG, "source cannot be null"); - return; - } - - HapClientService service = getService(source); - if (service == null) { - Log.w(TAG, "service is null"); - return; - } - enforceBluetoothPrivilegedPermission(service); - service.selectPreset(device, presetIndex); - } - - @Override - public void selectPresetForGroup(int groupId, int presetIndex, AttributionSource source) { - if (source == null) { - Log.w(TAG, "source cannot be null"); - return; - } - - HapClientService service = getService(source); - if (service == null) { - Log.w(TAG, "service is null"); - return; - } - enforceBluetoothPrivilegedPermission(service); - service.selectPresetForGroup(groupId, presetIndex); - } - - @Override - public void switchToNextPreset(BluetoothDevice device, AttributionSource source) { - if (source == null) { - Log.w(TAG, "source cannot be null"); - return; - } - - HapClientService service = getService(source); - if (service == null) { - Log.w(TAG, "service is null"); - return; - } - enforceBluetoothPrivilegedPermission(service); - service.switchToNextPreset(device); - } - - @Override - public void switchToNextPresetForGroup(int groupId, AttributionSource source) { - if (source == null) { - Log.w(TAG, "source cannot be null"); - return; - } - - HapClientService service = getService(source); - if (service == null) { - Log.w(TAG, "service is null"); - return; - } - enforceBluetoothPrivilegedPermission(service); - service.switchToNextPresetForGroup(groupId); - } - - @Override - public void switchToPreviousPreset(BluetoothDevice device, AttributionSource source) { - if (source == null) { - Log.w(TAG, "source cannot be null"); - return; - } - - HapClientService service = getService(source); - if (service == null) { - Log.w(TAG, "service is null"); - return; - } - enforceBluetoothPrivilegedPermission(service); - service.switchToPreviousPreset(device); - } - - @Override - public void switchToPreviousPresetForGroup(int groupId, AttributionSource source) { - if (source == null) { - Log.w(TAG, "source cannot be null"); - return; - } - - HapClientService service = getService(source); - if (service == null) { - Log.w(TAG, "service is null"); - return; - } - enforceBluetoothPrivilegedPermission(service); - service.switchToPreviousPresetForGroup(groupId); - } - - @Override - public void getPresetInfo(BluetoothDevice device, int presetIndex, - AttributionSource source, SynchronousResultReceiver receiver) { - - try { - Objects.requireNonNull(device, "device cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - BluetoothHapPresetInfo defaultValue = null; - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.getPresetInfo(device, presetIndex); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void getAllPresetInfo(BluetoothDevice device, AttributionSource source, - SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(device, "device cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - List<BluetoothHapPresetInfo> defaultValue = new ArrayList<>(); - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.getAllPresetInfo(device); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void getFeatures(BluetoothDevice device, AttributionSource source, - SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(device, "device cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - int defaultValue = 0x00; - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("service is null"); - } - enforceBluetoothPrivilegedPermission(service); - defaultValue = service.getFeatures(device); - receiver.send(defaultValue); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void setPresetName(BluetoothDevice device, int presetIndex, String name, - AttributionSource source) { - if (device == null) { - Log.w(TAG, "device cannot be null"); - return; - } - if (name == null) { - Log.w(TAG, "name cannot be null"); - return; - } - if (source == null) { - Log.w(TAG, "source cannot be null"); - return; - } - - HapClientService service = getService(source); - if (service == null) { - Log.w(TAG, "service is null"); - return; - } - enforceBluetoothPrivilegedPermission(service); - service.setPresetName(device, presetIndex, name); - } - - @Override - public void setPresetNameForGroup(int groupId, int presetIndex, String name, - AttributionSource source) { - if (name == null) { - Log.w(TAG, "name cannot be null"); - return; - } - if (source == null) { - Log.w(TAG, "source cannot be null"); - return; - } - HapClientService service = getService(source); - if (service == null) { - Log.w(TAG, "service is null"); - return; - } - enforceBluetoothPrivilegedPermission(service); - service.setPresetNameForGroup(groupId, presetIndex, name); - } - - @Override - public void registerCallback(IBluetoothHapClientCallback callback, - AttributionSource source, SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(callback, "callback cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("Service is unavailable"); - } - enforceBluetoothPrivilegedPermission(service); - service.mCallbacks.register(callback); - receiver.send(null); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - - @Override - public void unregisterCallback(IBluetoothHapClientCallback callback, - AttributionSource source, SynchronousResultReceiver receiver) { - try { - Objects.requireNonNull(callback, "callback cannot be null"); - Objects.requireNonNull(source, "source cannot be null"); - Objects.requireNonNull(receiver, "receiver cannot be null"); - - HapClientService service = getService(source); - if (service == null) { - throw new IllegalStateException("Service is unavailable"); - } - enforceBluetoothPrivilegedPermission(service); - service.mCallbacks.unregister(callback); - receiver.send(null); - } catch (RuntimeException e) { - receiver.propagateException(e); - } - } - } - - // Remove state machine if the bonding for a device is removed - private class BondStateChangedReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (!BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) { - return; - } - int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, - BluetoothDevice.ERROR); - BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - Objects.requireNonNull(device, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE"); - bondStateChanged(device, state); - } - } - - private class ConnectionStateChangedReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (!BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED.equals( - intent.getAction())) { - return; - } - BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - int toState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); - int fromState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); - connectionStateChanged(device, fromState, toState); - } - } -} diff --git a/src/com/android/bluetooth/hap/HapClientStackEvent.java b/src/com/android/bluetooth/hap/HapClientStackEvent.java deleted file mode 100644 index 5911c293e..000000000 --- a/src/com/android/bluetooth/hap/HapClientStackEvent.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright 2021 HIMSA II K/S - www.himsa.com. - * Represented by EHIMA - www.ehima.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bluetooth.hap; - -import android.bluetooth.BluetoothDevice; -import android.bluetooth.IBluetoothHapClient; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - -/** - * Stack event sent via a callback from GATT Service client to main service module, or generated - * internally by the Hearing Access Profile State Machine. - */ -public class HapClientStackEvent { - // Event types for STACK_EVENT message (coming from native HAS client) - private static final int EVENT_TYPE_NONE = 0; - public static final int EVENT_TYPE_CONNECTION_STATE_CHANGED = 1; - public static final int EVENT_TYPE_DEVICE_AVAILABLE = 2; - public static final int EVENT_TYPE_DEVICE_FEATURES = 3; - public static final int EVENT_TYPE_ON_ACTIVE_PRESET_SELECTED = 4; - public static final int EVENT_TYPE_ON_ACTIVE_PRESET_SELECT_ERROR = 5; - public static final int EVENT_TYPE_ON_PRESET_INFO = 6; - public static final int EVENT_TYPE_ON_PRESET_NAME_SET_ERROR = 7; - public static final int EVENT_TYPE_ON_PRESET_INFO_ERROR = 8; - - // Connection state values as defined in bt_has.h - static final int CONNECTION_STATE_DISCONNECTED = 0; - static final int CONNECTION_STATE_CONNECTING = 1; - static final int CONNECTION_STATE_CONNECTED = 2; - static final int CONNECTION_STATE_DISCONNECTING = 3; - - // Possible operation results - /* WARNING: Matches status codes defined in bta_has.h */ - static final int STATUS_NO_ERROR = 0; - static final int STATUS_SET_NAME_NOT_ALLOWED = 1; - static final int STATUS_OPERATION_NOT_SUPPORTED = 2; - static final int STATUS_OPERATION_NOT_POSSIBLE = 3; - static final int STATUS_INVALID_PRESET_NAME_LENGTH = 4; - static final int STATUS_INVALID_PRESET_INDEX = 5; - static final int STATUS_GROUP_OPERATION_NOT_SUPPORTED = 6; - static final int STATUS_PROCEDURE_ALREADY_IN_PROGRESS = 7; - - // Supported features - public static final int FEATURE_BIT_NUM_TYPE_MONAURAL = - IBluetoothHapClient.FEATURE_BIT_NUM_TYPE_MONAURAL; - public static final int FEATURE_BIT_NUM_TYPE_BANDED = - IBluetoothHapClient.FEATURE_BIT_NUM_TYPE_BANDED; - public static final int FEATURE_BIT_NUM_SYNCHRONIZATED_PRESETS = - IBluetoothHapClient.FEATURE_BIT_NUM_SYNCHRONIZATED_PRESETS; - public static final int FEATURE_BIT_NUM_INDEPENDENT_PRESETS = - IBluetoothHapClient.FEATURE_BIT_NUM_INDEPENDENT_PRESETS; - public static final int FEATURE_BIT_NUM_DYNAMIC_PRESETS = - IBluetoothHapClient.FEATURE_BIT_NUM_DYNAMIC_PRESETS; - public static final int FEATURE_BIT_NUM_WRITABLE_PRESETS = - IBluetoothHapClient.FEATURE_BIT_NUM_WRITABLE_PRESETS; - - // Preset Info notification reason - /* WARNING: Matches status codes defined in bta_has.h */ - public static final int PRESET_INFO_REASON_ALL_PRESET_INFO = 0; - public static final int PRESET_INFO_REASON_PRESET_INFO_UPDATE = 1; - public static final int PRESET_INFO_REASON_PRESET_DELETED = 2; - public static final int PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED = 3; - public static final int PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE = 4; - - public int type; - public BluetoothDevice device; - public int valueInt1; - public int valueInt2; - public int valueInt3; - public ArrayList valueList; - - public HapClientStackEvent(int type) { - this.type = type; - } - - @Override - public String toString() { - // event dump - StringBuilder result = new StringBuilder(); - result.append("HearingAccessStackEvent {type:" + eventTypeToString(type)); - result.append(", device: " + device); - result.append(", value1: " + eventTypeValueInt1ToString(type, valueInt1)); - result.append(", value2: " + eventTypeValueInt2ToString(type, valueInt2)); - result.append(", value3: " + eventTypeValueInt3ToString(type, valueInt3)); - result.append(", list: " + eventTypeValueListToString(type, valueList)); - - result.append("}"); - return result.toString(); - } - - private String eventTypeValueListToString(int type, List value) { - switch (type) { - case EVENT_TYPE_ON_PRESET_INFO: - return "{presets count: " + (value == null ? 0 : value.size()) + "}"; - default: - return "{list: empty}"; - } - } - - private String eventTypeValueInt1ToString(int type, int value) { - switch (type) { - case EVENT_TYPE_CONNECTION_STATE_CHANGED: - return "{state: " + connectionStateValueToString(value) + "}"; - case EVENT_TYPE_DEVICE_AVAILABLE: - return "{features: " + featuresToString(value) + "}"; - case EVENT_TYPE_DEVICE_FEATURES: - return "{features: " + featuresToString(value) + "}"; - case EVENT_TYPE_ON_PRESET_NAME_SET_ERROR: - return "{statusCode: " + statusCodeValueToString(value) + "}"; - case EVENT_TYPE_ON_PRESET_INFO_ERROR: - return "{statusCode: " + statusCodeValueToString(value) + "}"; - case EVENT_TYPE_ON_ACTIVE_PRESET_SELECTED: - return "{presetIndex: " + value + "}"; - case EVENT_TYPE_ON_ACTIVE_PRESET_SELECT_ERROR: - return "{statusCode: " + statusCodeValueToString(value) + "}"; - case EVENT_TYPE_ON_PRESET_INFO: - default: - return "{unused: " + value + "}"; - } - } - - private String infoReasonToString(int value) { - switch (value) { - case PRESET_INFO_REASON_ALL_PRESET_INFO: - return "PRESET_INFO_REASON_ALL_PRESET_INFO"; - case PRESET_INFO_REASON_PRESET_INFO_UPDATE: - return "PRESET_INFO_REASON_PRESET_INFO_UPDATE"; - case PRESET_INFO_REASON_PRESET_DELETED: - return "PRESET_INFO_REASON_PRESET_DELETED"; - case PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED: - return "PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED"; - case PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE: - return "PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE"; - default: - return "UNKNOWN"; - } - } - - private String eventTypeValueInt2ToString(int type, int value) { - switch (type) { - case EVENT_TYPE_ON_PRESET_NAME_SET_ERROR: - return "{presetIndex: " + value + "}"; - case EVENT_TYPE_ON_PRESET_INFO: - return "{info_reason: " + infoReasonToString(value) + "}"; - case EVENT_TYPE_ON_PRESET_INFO_ERROR: - return "{presetIndex: " + value + "}"; - case EVENT_TYPE_ON_ACTIVE_PRESET_SELECTED: - return "{groupId: " + value + "}"; - case EVENT_TYPE_ON_ACTIVE_PRESET_SELECT_ERROR: - return "{groupId: " + value + "}"; - default: - return "{unused: " + value + "}"; - } - } - - private String eventTypeValueInt3ToString(int type, int value) { - switch (type) { - case EVENT_TYPE_ON_PRESET_INFO: - case EVENT_TYPE_ON_PRESET_INFO_ERROR: - case EVENT_TYPE_ON_PRESET_NAME_SET_ERROR: - return "{groupId: " + value + "}"; - default: - return "{unused: " + value + "}"; - } - } - - private String connectionStateValueToString(int value) { - switch (value) { - case CONNECTION_STATE_DISCONNECTED: - return "CONNECTION_STATE_DISCONNECTED"; - case CONNECTION_STATE_CONNECTING: - return "CONNECTION_STATE_CONNECTING"; - case CONNECTION_STATE_CONNECTED: - return "CONNECTION_STATE_CONNECTED"; - case CONNECTION_STATE_DISCONNECTING: - return "CONNECTION_STATE_DISCONNECTING"; - default: - return "CONNECTION_STATE_UNKNOWN!"; - } - } - - private String statusCodeValueToString(int value) { - switch (value) { - case STATUS_NO_ERROR: - return "STATUS_NO_ERROR"; - case STATUS_SET_NAME_NOT_ALLOWED: - return "STATUS_SET_NAME_NOT_ALLOWED"; - case STATUS_OPERATION_NOT_SUPPORTED: - return "STATUS_OPERATION_NOT_SUPPORTED"; - case STATUS_OPERATION_NOT_POSSIBLE: - return "STATUS_OPERATION_NOT_POSSIBLE"; - case STATUS_INVALID_PRESET_NAME_LENGTH: - return "STATUS_INVALID_PRESET_NAME_LENGTH"; - case STATUS_INVALID_PRESET_INDEX: - return "STATUS_INVALID_PRESET_INDEX"; - case STATUS_GROUP_OPERATION_NOT_SUPPORTED: - return "STATUS_GROUP_OPERATION_NOT_SUPPORTED"; - case STATUS_PROCEDURE_ALREADY_IN_PROGRESS: - return "STATUS_PROCEDURE_ALREADY_IN_PROGRESS"; - default: - return "ERROR_UNKNOWN"; - } - } - - private String featuresToString(int value) { - String features_str = ""; - if (BigInteger.valueOf(value).testBit(FEATURE_BIT_NUM_TYPE_MONAURAL)) { - features_str += "TYPE_MONAURAL"; - } else if (BigInteger.valueOf(value).testBit(FEATURE_BIT_NUM_TYPE_BANDED)) { - features_str += "TYPE_BANDED"; - } else { - features_str += "TYPE_BINAURAL"; - } - - if (BigInteger.valueOf(value).testBit(FEATURE_BIT_NUM_SYNCHRONIZATED_PRESETS)) { - features_str += ", SYNCHRONIZATED_PRESETS"; - } - if (BigInteger.valueOf(value).testBit(FEATURE_BIT_NUM_INDEPENDENT_PRESETS)) { - features_str += ", INDEPENDENT_PRESETS"; - } - if (BigInteger.valueOf(value).testBit(FEATURE_BIT_NUM_DYNAMIC_PRESETS)) { - features_str += ", DYNAMIC_PRESETS"; - } - if (BigInteger.valueOf(value).testBit(FEATURE_BIT_NUM_WRITABLE_PRESETS)) { - features_str += ", WRITABLE_PRESETS"; - } - - return features_str; - } - - private static String eventTypeToString(int type) { - switch (type) { - case EVENT_TYPE_NONE: - return "EVENT_TYPE_NONE"; - case EVENT_TYPE_CONNECTION_STATE_CHANGED: - return "EVENT_TYPE_CONNECTION_STATE_CHANGED"; - case EVENT_TYPE_DEVICE_AVAILABLE: - return "EVENT_TYPE_DEVICE_AVAILABLE"; - case EVENT_TYPE_DEVICE_FEATURES: - return "EVENT_TYPE_DEVICE_FEATURES"; - case EVENT_TYPE_ON_ACTIVE_PRESET_SELECTED: - return "EVENT_TYPE_ON_ACTIVE_PRESET_SELECTED"; - case EVENT_TYPE_ON_ACTIVE_PRESET_SELECT_ERROR: - return "EVENT_TYPE_ON_ACTIVE_PRESET_SELECT_ERROR"; - case EVENT_TYPE_ON_PRESET_INFO: - return "EVENT_TYPE_ON_PRESET_INFO"; - case EVENT_TYPE_ON_PRESET_NAME_SET_ERROR: - return "EVENT_TYPE_ON_PRESET_NAME_SET_ERROR"; - case EVENT_TYPE_ON_PRESET_INFO_ERROR: - return "EVENT_TYPE_ON_PRESET_INFO_ERROR"; - default: - return "EVENT_TYPE_UNKNOWN:" + type; - } - } -} diff --git a/src/com/android/bluetooth/hap/HapClientStateMachine.java b/src/com/android/bluetooth/hap/HapClientStateMachine.java deleted file mode 100644 index dc85f0aea..000000000 --- a/src/com/android/bluetooth/hap/HapClientStateMachine.java +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright 2021 HIMSA II K/S - www.himsa.com. - * Represented by EHIMA - www.ehima.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Bluetooth Hap Client StateMachine. There is one instance per remote device. - * - "Disconnected" and "Connected" are steady states. - * - "Connecting" and "Disconnecting" are transient states until the - * connection / disconnection is completed. - * - * - * (Disconnected) - * | ^ - * CONNECT | | DISCONNECTED - * V | - * (Connecting)<--->(Disconnecting) - * | ^ - * CONNECTED | | DISCONNECT - * V | - * (Connected) - * NOTES: - * - If state machine is in "Connecting" state and the remote device sends - * DISCONNECT request, the state machine transitions to "Disconnecting" state. - * - Similarly, if the state machine is in "Disconnecting" state and the remote device - * sends CONNECT request, the state machine transitions to "Connecting" state. - * - * DISCONNECT - * (Connecting) ---------------> (Disconnecting) - * <--------------- - * CONNECT - * - */ - -package com.android.bluetooth.hap; - -import static android.Manifest.permission.BLUETOOTH_CONNECT; - -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHapClient; -import android.bluetooth.BluetoothProfile; -import android.content.Intent; -import android.os.Looper; -import android.os.Message; -import android.util.Log; - -import com.android.bluetooth.btservice.ProfileService; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Scanner; - -final class HapClientStateMachine extends StateMachine { - static final int CONNECT = 1; - static final int DISCONNECT = 2; - @VisibleForTesting - static final int STACK_EVENT = 101; - private static final boolean DBG = true; - private static final String TAG = "HapClientStateMachine"; - @VisibleForTesting - static final int CONNECT_TIMEOUT = 201; - - // NOTE: the value is not "final" - it is modified in the unit tests - @VisibleForTesting - static int sConnectTimeoutMs = 30000; // 30s - - private final Disconnected mDisconnected; - private final Connecting mConnecting; - private final Disconnecting mDisconnecting; - private final Connected mConnected; - private int mConnectionState = BluetoothProfile.STATE_DISCONNECTED; - private int mLastConnectionState = -1; - - private final HapClientService mService; - private final HapClientNativeInterface mNativeInterface; - - private final BluetoothDevice mDevice; - - HapClientStateMachine(BluetoothDevice device, HapClientService svc, - HapClientNativeInterface gattInterface, Looper looper) { - super(TAG, looper); - mDevice = device; - mService = svc; - mNativeInterface = gattInterface; - - mDisconnected = new Disconnected(); - mConnecting = new Connecting(); - mDisconnecting = new Disconnecting(); - mConnected = new Connected(); - - addState(mDisconnected); - addState(mConnecting); - addState(mDisconnecting); - addState(mConnected); - - setInitialState(mDisconnected); - } - - static HapClientStateMachine make(BluetoothDevice device, HapClientService svc, - HapClientNativeInterface gattInterface, Looper looper) { - Log.i(TAG, "make for device " + device); - HapClientStateMachine hearingAccessSm = new HapClientStateMachine(device, svc, - gattInterface, looper); - hearingAccessSm.start(); - return hearingAccessSm; - } - - private static String messageWhatToString(int what) { - switch (what) { - case CONNECT: - return "CONNECT"; - case DISCONNECT: - return "DISCONNECT"; - case STACK_EVENT: - return "STACK_EVENT"; - case CONNECT_TIMEOUT: - return "CONNECT_TIMEOUT"; - default: - break; - } - return Integer.toString(what); - } - - private static String profileStateToString(int state) { - switch (state) { - case BluetoothProfile.STATE_DISCONNECTED: - return "DISCONNECTED"; - case BluetoothProfile.STATE_CONNECTING: - return "CONNECTING"; - case BluetoothProfile.STATE_CONNECTED: - return "CONNECTED"; - case BluetoothProfile.STATE_DISCONNECTING: - return "DISCONNECTING"; - default: - break; - } - return Integer.toString(state); - } - - public void doQuit() { - log("doQuit for device " + mDevice); - quitNow(); - } - - public void cleanup() { - log("cleanup for device " + mDevice); - } - - int getConnectionState() { - return mConnectionState; - } - - BluetoothDevice getDevice() { - return mDevice; - } - - synchronized boolean isConnected() { - return (getConnectionState() == BluetoothProfile.STATE_CONNECTED); - } - - // This method does not check for error condition (newState == prevState) - private void broadcastConnectionState(int newState, int prevState) { - log("Connection state " + mDevice + ": " + profileStateToString(prevState) - + "->" + profileStateToString(newState)); - - Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED); - intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); - intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT - | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - mService.sendBroadcast(intent, BLUETOOTH_CONNECT); - } - - public void dump(StringBuilder sb) { - ProfileService.println(sb, "mDevice: " + mDevice); - ProfileService.println(sb, " StateMachine: " + this); - // Dump the state machine logs - StringWriter stringWriter = new StringWriter(); - PrintWriter printWriter = new PrintWriter(stringWriter); - super.dump(new FileDescriptor(), printWriter, new String[]{}); - printWriter.flush(); - stringWriter.flush(); - ProfileService.println(sb, " StateMachineLog:"); - Scanner scanner = new Scanner(stringWriter.toString()); - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - ProfileService.println(sb, " " + line); - } - scanner.close(); - } - - @Override - protected void log(String msg) { - if (DBG) { - super.log(msg); - } - } - - @VisibleForTesting - class Disconnected extends State { - @Override - public void enter() { - Log.i(TAG, "Enter Disconnected(" + mDevice + "): " + messageWhatToString( - getCurrentMessage().what)); - mConnectionState = BluetoothProfile.STATE_DISCONNECTED; - - removeDeferredMessages(DISCONNECT); - - if (mLastConnectionState != -1) { - // Don't broadcast during startup - broadcastConnectionState(BluetoothProfile.STATE_DISCONNECTED, - mLastConnectionState); - } - } - - @Override - public void exit() { - log("Exit Disconnected(" + mDevice + "): " + messageWhatToString( - getCurrentMessage().what)); - mLastConnectionState = BluetoothProfile.STATE_DISCONNECTED; - } - - @Override - public boolean processMessage(Message message) { - log("Disconnected: process message(" + mDevice + "): " + messageWhatToString( - message.what)); - - switch (message.what) { - case CONNECT: - log("Connecting to " + mDevice); - if (!mNativeInterface.connectHapClient(mDevice)) { - Log.e(TAG, "Disconnected: error connecting to " + mDevice); - break; - } - if (mService.okToConnect(mDevice)) { - transitionTo(mConnecting); - } else { - // Reject the request and stay in Disconnected state - Log.w(TAG, "Outgoing HearingAccess Connecting request rejected: " - + mDevice); - } - break; - case DISCONNECT: - Log.d(TAG, "Disconnected: DISCONNECT: call native disconnect for " + mDevice); - mNativeInterface.disconnectHapClient(mDevice); - break; - case STACK_EVENT: - HapClientStackEvent event = (HapClientStackEvent) message.obj; - if (DBG) { - Log.d(TAG, "Disconnected: stack event: " + event); - } - if (!mDevice.equals(event.device)) { - Log.wtf(TAG, "Device(" + mDevice + "): event mismatch: " + event); - } - switch (event.type) { - case HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: - processConnectionEvent(event.valueInt1); - break; - default: - Log.e(TAG, "Disconnected: ignoring stack event: " + event); - break; - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - // in Disconnected state - private void processConnectionEvent(int state) { - switch (state) { - case HapClientStackEvent.CONNECTION_STATE_DISCONNECTED: - Log.w(TAG, "Ignore HearingAccess DISCONNECTED event: " + mDevice); - break; - case HapClientStackEvent.CONNECTION_STATE_CONNECTING: - if (mService.okToConnect(mDevice)) { - Log.i(TAG, "Incoming HearingAccess Connecting request accepted: " - + mDevice); - transitionTo(mConnecting); - } else { - // Reject the connection and stay in Disconnected state itself - Log.w(TAG, "Incoming HearingAccess Connecting request rejected: " - + mDevice); - mNativeInterface.disconnectHapClient(mDevice); - } - break; - case HapClientStackEvent.CONNECTION_STATE_CONNECTED: - Log.w(TAG, "HearingAccess Connected from Disconnected state: " + mDevice); - if (mService.okToConnect(mDevice)) { - Log.i(TAG, "Incoming HearingAccess Connected request accepted: " + mDevice); - transitionTo(mConnected); - } else { - // Reject the connection and stay in Disconnected state itself - Log.w(TAG, "Incoming HearingAccess Connected request rejected: " + mDevice); - mNativeInterface.disconnectHapClient(mDevice); - } - break; - case HapClientStackEvent.CONNECTION_STATE_DISCONNECTING: - Log.w(TAG, "Ignore HearingAccess DISCONNECTING event: " + mDevice); - break; - default: - Log.e(TAG, "Incorrect state: " + state + " device: " + mDevice); - break; - } - } - } - - @VisibleForTesting - class Connecting extends State { - @Override - public void enter() { - Log.i(TAG, "Enter Connecting(" + mDevice + "): " - + messageWhatToString(getCurrentMessage().what)); - sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs); - mConnectionState = BluetoothProfile.STATE_CONNECTING; - broadcastConnectionState(BluetoothProfile.STATE_CONNECTING, mLastConnectionState); - } - - @Override - public void exit() { - log("Exit Connecting(" + mDevice + "): " - + messageWhatToString(getCurrentMessage().what)); - mLastConnectionState = BluetoothProfile.STATE_CONNECTING; - removeMessages(CONNECT_TIMEOUT); - } - - @Override - public boolean processMessage(Message message) { - log("Connecting: process message(" + mDevice + "): " - + messageWhatToString(message.what)); - - switch (message.what) { - case CONNECT: - deferMessage(message); - break; - case CONNECT_TIMEOUT: - Log.w(TAG, "Connecting connection timeout: " + mDevice); - mNativeInterface.disconnectHapClient(mDevice); - HapClientStackEvent disconnectEvent = - new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - disconnectEvent.device = mDevice; - disconnectEvent.valueInt1 = HapClientStackEvent.CONNECTION_STATE_DISCONNECTED; - sendMessage(STACK_EVENT, disconnectEvent); - break; - case DISCONNECT: - log("Connecting: connection canceled to " + mDevice); - mNativeInterface.disconnectHapClient(mDevice); - transitionTo(mDisconnected); - break; - case STACK_EVENT: - HapClientStackEvent event = (HapClientStackEvent) message.obj; - log("Connecting: stack event: " + event); - if (!mDevice.equals(event.device)) { - Log.wtf(TAG, "Device(" + mDevice + "): event mismatch: " + event); - } - switch (event.type) { - case HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: - processConnectionEvent(event.valueInt1); - break; - default: - Log.e(TAG, "Connecting: ignoring stack event: " + event); - break; - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - // in Connecting state - private void processConnectionEvent(int state) { - switch (state) { - case HapClientStackEvent.CONNECTION_STATE_DISCONNECTED: - Log.w(TAG, "Connecting device disconnected: " + mDevice); - transitionTo(mDisconnected); - break; - case HapClientStackEvent.CONNECTION_STATE_CONNECTED: - transitionTo(mConnected); - break; - case HapClientStackEvent.CONNECTION_STATE_CONNECTING: - break; - case HapClientStackEvent.CONNECTION_STATE_DISCONNECTING: - Log.w(TAG, "Connecting interrupted: device is disconnecting: " + mDevice); - transitionTo(mDisconnecting); - break; - default: - Log.e(TAG, "Incorrect state: " + state); - break; - } - } - } - - @VisibleForTesting - class Disconnecting extends State { - @Override - public void enter() { - Log.i(TAG, "Enter Disconnecting(" + mDevice + "): " - + messageWhatToString(getCurrentMessage().what)); - sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs); - mConnectionState = BluetoothProfile.STATE_DISCONNECTING; - broadcastConnectionState(BluetoothProfile.STATE_DISCONNECTING, mLastConnectionState); - } - - @Override - public void exit() { - log("Exit Disconnecting(" + mDevice + "): " - + messageWhatToString(getCurrentMessage().what)); - mLastConnectionState = BluetoothProfile.STATE_DISCONNECTING; - removeMessages(CONNECT_TIMEOUT); - } - - @Override - public boolean processMessage(Message message) { - log("Disconnecting: process message(" + mDevice + "): " - + messageWhatToString(message.what)); - - switch (message.what) { - case CONNECT: - deferMessage(message); - break; - case CONNECT_TIMEOUT: { - Log.w(TAG, "Disconnecting connection timeout: " + mDevice); - mNativeInterface.disconnectHapClient(mDevice); - - HapClientStackEvent disconnectEvent = - new HapClientStackEvent( - HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - disconnectEvent.device = mDevice; - disconnectEvent.valueInt1 = HapClientStackEvent.CONNECTION_STATE_DISCONNECTED; - sendMessage(STACK_EVENT, disconnectEvent); - break; - } - case DISCONNECT: - deferMessage(message); - break; - case STACK_EVENT: - HapClientStackEvent event = (HapClientStackEvent) message.obj; - log("Disconnecting: stack event: " + event); - if (!mDevice.equals(event.device)) { - Log.wtf(TAG, "Device(" + mDevice + "): event mismatch: " + event); - } - switch (event.type) { - case HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: - processConnectionEvent(event.valueInt1); - break; - default: - Log.e(TAG, "Disconnecting: ignoring stack event: " + event); - break; - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - // in Disconnecting state - private void processConnectionEvent(int state) { - switch (state) { - case HapClientStackEvent.CONNECTION_STATE_DISCONNECTED: - Log.i(TAG, "Disconnected: " + mDevice); - transitionTo(mDisconnected); - break; - case HapClientStackEvent.CONNECTION_STATE_CONNECTED: - if (mService.okToConnect(mDevice)) { - Log.w(TAG, "Disconnecting interrupted: device is connected: " + mDevice); - transitionTo(mConnected); - } else { - // Reject the connection and stay in Disconnecting state - Log.w(TAG, "Incoming HearingAccess Connected request rejected: " + mDevice); - mNativeInterface.disconnectHapClient(mDevice); - } - break; - case HapClientStackEvent.CONNECTION_STATE_CONNECTING: - if (mService.okToConnect(mDevice)) { - Log.i(TAG, "Disconnecting interrupted: try to reconnect: " + mDevice); - transitionTo(mConnecting); - } else { - // Reject the connection and stay in Disconnecting state - Log.w(TAG, "Incoming HearingAccess Connecting request rejected: " - + mDevice); - mNativeInterface.disconnectHapClient(mDevice); - } - break; - case HapClientStackEvent.CONNECTION_STATE_DISCONNECTING: - break; - default: - Log.e(TAG, "Incorrect state: " + state); - break; - } - } - } - - @VisibleForTesting - class Connected extends State { - @Override - public void enter() { - Log.i(TAG, "Enter Connected(" + mDevice + "): " - + messageWhatToString(getCurrentMessage().what)); - mConnectionState = BluetoothProfile.STATE_CONNECTED; - removeDeferredMessages(CONNECT); - broadcastConnectionState(BluetoothProfile.STATE_CONNECTED, mLastConnectionState); - } - - @Override - public void exit() { - log("Exit Connected(" + mDevice + "): " - + messageWhatToString(getCurrentMessage().what)); - mLastConnectionState = BluetoothProfile.STATE_CONNECTED; - } - - @Override - public boolean processMessage(Message message) { - log("Connected: process message(" + mDevice + "): " - + messageWhatToString(message.what)); - - switch (message.what) { - case CONNECT: - Log.w(TAG, "Connected: CONNECT ignored: " + mDevice); - break; - case DISCONNECT: - log("Disconnecting from " + mDevice); - if (!mNativeInterface.disconnectHapClient(mDevice)) { - // If error in the native stack, transition directly to Disconnected state. - Log.e(TAG, "Connected: error disconnecting from " + mDevice); - transitionTo(mDisconnected); - break; - } - transitionTo(mDisconnecting); - break; - case STACK_EVENT: - HapClientStackEvent event = (HapClientStackEvent) message.obj; - log("Connected: stack event: " + event); - if (!mDevice.equals(event.device)) { - Log.wtf(TAG, "Device(" + mDevice + "): event mismatch: " + event); - } - switch (event.type) { - case HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: - processConnectionEvent(event.valueInt1); - break; - default: - Log.e(TAG, "Connected: ignoring stack event: " + event); - break; - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - // in Connected state - private void processConnectionEvent(int state) { - switch (state) { - case HapClientStackEvent.CONNECTION_STATE_DISCONNECTED: - Log.i(TAG, "Disconnected from " + mDevice + " but still in Allowlist"); - transitionTo(mDisconnected); - break; - case HapClientStackEvent.CONNECTION_STATE_DISCONNECTING: - Log.i(TAG, "Disconnecting from " + mDevice); - transitionTo(mDisconnecting); - break; - default: - Log.e(TAG, "Connection State Device: " + mDevice + " bad state: " + state); - break; - } - } - } -} diff --git a/src/com/android/bluetooth/hfp/HeadsetA2dpSync.java b/src/com/android/bluetooth/hfp/HeadsetA2dpSync.java index 6a6a2ab13..b68a1854f 100644 --- a/src/com/android/bluetooth/hfp/HeadsetA2dpSync.java +++ b/src/com/android/bluetooth/hfp/HeadsetA2dpSync.java @@ -47,7 +47,6 @@ import java.lang.reflect.*; import com.android.bluetooth.apm.ApmConstIntf; import com.android.bluetooth.apm.ActiveDeviceManagerServiceIntf; import com.android.bluetooth.apm.CallAudioIntf; -import com.android.bluetooth.acm.AcmService; /** * Defines methods used for synchronization between HFP and A2DP @@ -161,42 +160,6 @@ public class HeadsetA2dpSync { } } - public void hfpCallBapMediaSync(boolean isBapMediaSuspend) { - Log.d(TAG,"hfpCallBapMediaSync(): isBapMediaSuspend: " + isBapMediaSuspend); - if (ApmConstIntf.getAospLeaEnabled()) { - ActiveDeviceManagerServiceIntf mActiveDeviceManager = - ActiveDeviceManagerServiceIntf.get(); - int MediaProfile = - mActiveDeviceManager.getActiveProfile(ApmConstIntf.AudioFeatures.MEDIA_AUDIO); - int VoiceProfile = - mActiveDeviceManager.getActiveProfile(ApmConstIntf.AudioFeatures.CALL_AUDIO); - BluetoothDevice mMediaDevice = - mActiveDeviceManager.getActiveDevice(ApmConstIntf.AudioFeatures.MEDIA_AUDIO); - BluetoothDevice mVoiceDevice = - mActiveDeviceManager.getActiveDevice(ApmConstIntf.AudioFeatures.CALL_AUDIO); - Log.d(TAG,"hfpCallBapMediaSync(): MediaProfile: " + MediaProfile + - ", current active media device: " + mMediaDevice); - Log.d(TAG,"hfpCallBapMediaSync: VoiceProfile: " + VoiceProfile + - ", current active voice device: " + mVoiceDevice); - - if (MediaProfile != ApmConstIntf.AudioProfiles.NONE && - MediaProfile != ApmConstIntf.AudioProfiles.A2DP && - VoiceProfile != ApmConstIntf.AudioProfiles.NONE && - VoiceProfile == ApmConstIntf.AudioProfiles.HFP) { - AcmService mAcmService = AcmService.getAcmService(); - if (mAcmService != null) { - if (isBapMediaSuspend) { - Log.d(TAG,"hfpCallBapMediaSync(): hfp call active, suspend bap Music "); - mAcmService.hfpCallBapMediaSync(true); - } else { - Log.d(TAG,"hfpCallBapMediaSync(): hfp call ended, resume bap Music "); - mAcmService.hfpCallBapMediaSync(false); - } - } - } - } - } - public boolean suspendA2DP(int reason, BluetoothDevice device) { int a2dpState = isA2dpPlaying(); String a2dpSuspendStatus; @@ -317,7 +280,6 @@ public class HeadsetA2dpSync { } } Log.d(TAG," A2DP Playing ,wait for suspend "); - //hfpCallBapMediaSync(true); return true; } return false; @@ -377,7 +339,6 @@ public class HeadsetA2dpSync { } else { mSystemInterface.getAudioManager().setA2dpSuspended(false); releaseLeAudio(); - //hfpCallBapMediaSync(false); } return true; } diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java index 47b9b60c2..7b3e9d1c1 100644 --- a/src/com/android/bluetooth/hfp/HeadsetService.java +++ b/src/com/android/bluetooth/hfp/HeadsetService.java @@ -46,11 +46,6 @@ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE - * - * Changes from Qualcomm Innovation Center are provided under the following license: - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause-Clear - * */ package com.android.bluetooth.hfp; @@ -99,17 +94,11 @@ import com.android.bluetooth.btservice.storage.DatabaseManager; import com.android.internal.annotations.VisibleForTesting; import com.android.bluetooth.apm.DeviceProfileMapIntf; import com.android.bluetooth.apm.ApmConstIntf; -import com.android.bluetooth.apm.ApmConst; import com.android.bluetooth.apm.CallAudioIntf; import com.android.bluetooth.apm.CallControlIntf; import com.android.bluetooth.apm.ActiveDeviceManagerServiceIntf; import com.android.bluetooth.le_audio.LeAudioService; import com.android.modules.utils.SynchronousResultReceiver; -import com.android.bluetooth.cc.CCService; -import com.android.bluetooth.acm.AcmService; -import com.android.bluetooth.apm.StreamAudioService; -import com.android.bluetooth.btservice.ActiveDeviceManager; -import com.android.bluetooth.le_audio.LeAudioService; import java.util.ArrayList; import java.util.Arrays; @@ -166,7 +155,6 @@ public class HeadsetService extends ProfileService { private int mSetMaxConfig; private BluetoothDevice mActiveDevice; private BluetoothDevice mTempActiveDevice; - private BluetoothDevice mTempDualModeActiveDevice; private boolean mSHOStatus = false; private AdapterService mAdapterService; private DatabaseManager mDatabaseManager; @@ -196,7 +184,6 @@ public class HeadsetService extends ProfileService { private boolean mIsTwsPlusShoEnabled = false; private vendorhfservice mVendorHf; private Context mContext = null; - private static final int BAP_CALL = 0x10; private AudioServerStateCallback mServerStateCallback = new AudioServerStateCallback(); private static final int AUDIO_CONNECTION_DELAY_DEFAULT = 100; private static final String ACTION_BATTERY_STATE_CHANGED = "android.bluetooth.action.BATTERY_STATE_CHANGED"; @@ -660,11 +647,6 @@ public class HeadsetService extends ProfileService { mCallAudio.onAudioStateChange(device, mAudioState); } - public boolean isVoipLeaWarEnabled() { - CallAudioIntf mCallAudio = CallAudioIntf.get(); - return mCallAudio.isVoipLeaWarEnabled(); - } - public void setIntentScoVolume(Intent intent) { Log.w(TAG, "setIntentScoVolume"); synchronized (mStateMachines) { @@ -707,24 +689,6 @@ public class HeadsetService extends ProfileService { return mService; } - private boolean isAospLeaVoipWarEnabled() { - boolean ret = false; - if (ApmConstIntf.getAospLeaEnabled()) { - CallAudioIntf mCallAudio = CallAudioIntf.get(); - ActiveDeviceManagerServiceIntf mActiveDeviceManager = - ActiveDeviceManagerServiceIntf.get(); - if (mCallAudio.isVoipLeaWarEnabled() && - (mActiveDeviceManager.getActiveProfile(ApmConst.AudioFeatures.CALL_AUDIO) - == ApmConst.AudioProfiles.BAP_CALL || - mActiveDeviceManager.getActiveProfile(ApmConst.AudioFeatures.CALL_AUDIO) - == ApmConst.AudioProfiles.TMAP_CALL)) { - ret = true; - } - } - Log.i(TAG, "isAospLeaVoipWarEnabled: " + ret); - return ret; - } - @Override public void connect(BluetoothDevice device, AttributionSource source, SynchronousResultReceiver receiver) { @@ -780,7 +744,7 @@ public class HeadsetService extends ProfileService { SynchronousResultReceiver receiver) { try { List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(0); - if (ApmConstIntf.getQtiLeAudioEnabled() || isAospLeaVoipWarEnabled()) { + if (ApmConstIntf.getQtiLeAudioEnabled()) { Log.d(TAG, "getConnectedDevicesWithAttribution(): Adv Audio enabled"); CallAudioIntf mCallAudio = CallAudioIntf.get(); if (mCallAudio != null) { @@ -805,7 +769,7 @@ public class HeadsetService extends ProfileService { AttributionSource source, SynchronousResultReceiver receiver) { try { List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(0); - if (ApmConstIntf.getQtiLeAudioEnabled() || isAospLeaVoipWarEnabled()) { + if (ApmConstIntf.getQtiLeAudioEnabled()) { Log.d(TAG, "getDevicesMatchingConnectionStates(): Adv Audio enabled"); CallAudioIntf mCallAudio = CallAudioIntf.get(); defaultValue = mCallAudio.getDevicesMatchingConnectionStates(states); @@ -979,7 +943,7 @@ public class HeadsetService extends ProfileService { public void isAudioOn(AttributionSource source, SynchronousResultReceiver receiver) { try { boolean defaultValue = false; - if(ApmConstIntf.getQtiLeAudioEnabled() || isAospLeaVoipWarEnabled()) { + if(ApmConstIntf.getQtiLeAudioEnabled()) { Log.d(TAG, "isAudioOn(): Adv Audio enabled"); CallAudioIntf mCallAudio = CallAudioIntf.get(); defaultValue = mCallAudio.isAudioOn(); @@ -1016,8 +980,7 @@ public class HeadsetService extends ProfileService { SynchronousResultReceiver receiver) { try { int defaultValue = BluetoothHeadset.STATE_AUDIO_DISCONNECTED; - // Not fake getAudioState API for Aosp LeAudio VOIP WAR - if (ApmConstIntf.getQtiLeAudioEnabled()) { + if(ApmConstIntf.getQtiLeAudioEnabled()) { Log.d(TAG, "getAudioState(): Adv Audio enabled"); CallAudioIntf mCallAudio = CallAudioIntf.get(); defaultValue = mCallAudio.getAudioState(device); @@ -1137,7 +1100,7 @@ public class HeadsetService extends ProfileService { SynchronousResultReceiver receiver) { try { boolean defaultValue = false; - if(ApmConstIntf.getQtiLeAudioEnabled() || isAospLeaVoipWarEnabled()) { + if(ApmConstIntf.getQtiLeAudioEnabled()) { Log.d(TAG, "startScoUsingVirtualVoiceCall(): Adv Audio enabled"); CallAudioIntf mCallAudio = CallAudioIntf.get(); defaultValue = mCallAudio.startScoUsingVirtualVoiceCall(); @@ -1159,7 +1122,7 @@ public class HeadsetService extends ProfileService { SynchronousResultReceiver receiver) { try { boolean defaultValue = false; - if(ApmConstIntf.getQtiLeAudioEnabled() || isAospLeaVoipWarEnabled()) { + if(ApmConstIntf.getQtiLeAudioEnabled()) { Log.d(TAG, "stopScoUsingVirtualVoiceCall(): Adv Audio enabled"); CallAudioIntf mCallAudio = CallAudioIntf.get(); defaultValue = mCallAudio.stopScoUsingVirtualVoiceCall(); @@ -1247,7 +1210,7 @@ public class HeadsetService extends ProfileService { public void getActiveDevice(AttributionSource source, SynchronousResultReceiver receiver) { try { BluetoothDevice defaultValue = null; - if(ApmConstIntf.getQtiLeAudioEnabled() || isAospLeaVoipWarEnabled()) { + if(ApmConstIntf.getQtiLeAudioEnabled()) { ActiveDeviceManagerServiceIntf activeDeviceManager = ActiveDeviceManagerServiceIntf.get(); defaultValue = activeDeviceManager.getActiveAbsoluteDevice(ApmConstIntf.AudioFeatures.CALL_AUDIO); receiver.send(defaultValue); @@ -2394,39 +2357,7 @@ public class HeadsetService extends ProfileService { } if (mActiveDevice == null) { Log.w(TAG, "startScoUsingVirtualVoiceCall: no active device"); - if (Utils.isDualModeAudioEnabled()) { - Log.i(TAG, "Dual mode is enabled"); - ActiveDeviceManagerServiceIntf mActiveDeviceManager = - ActiveDeviceManagerServiceIntf.get(); - StreamAudioService mStreamAudioService = - StreamAudioService.getStreamAudioService(); - if (mActiveDeviceManager != null) { - mTempDualModeActiveDevice = - mActiveDeviceManager.getActiveAbsoluteDevice(ApmConstIntf.AudioFeatures.CALL_AUDIO); - } - if (mStreamAudioService != null) { - Log.i(TAG, "Setting ACM null device"); - int ret = - mStreamAudioService.setActiveDevice(null, - BAP_CALL, - false); - mHfpA2dpSyncInterface.suspendLeAudio(HeadsetA2dpSync. - A2DP_SUSPENDED_BY_CS_CALL); - } - if (mTempDualModeActiveDevice != null) { - int ret = setActiveDeviceHF(mTempDualModeActiveDevice); - if (ret == ActiveDeviceManagerServiceIntf.SHO_SUCCESS) { - //Active device is set. Initiate SCO. - Log.i(TAG, "active device is set. Initiate SCO"); - } else { - return false; - } - } else { - return false; - } - } else { - return false; - } + return false; } mVirtualCallStarted = true; mSystemInterface.getHeadsetPhoneState().setIsCsCall(false); @@ -2452,21 +2383,6 @@ public class HeadsetService extends ProfileService { // 2. Send virtual phone state changed to close SCO phoneStateChanged(0, 0, HeadsetHalConstants.CALL_STATE_IDLE, "", 0, "", true); } - if (Utils.isDualModeAudioEnabled()) { - StreamAudioService mStreamAudioService = - StreamAudioService.getStreamAudioService(); - if (mTempDualModeActiveDevice != null) { - if (mStreamAudioService != null) { - Log.i(TAG, "Setting ACM device after voip"); - int ret = - mStreamAudioService.setActiveDevice(mTempDualModeActiveDevice, - BAP_CALL, - false); - } - setActiveDeviceHF(null); - mTempDualModeActiveDevice = null; - } - } return true; } @@ -2763,15 +2679,6 @@ public class HeadsetService extends ProfileService { Log.w(TAG, "mStateMachinesThread is null, returning"); return; } - - if (isScoOrCallActive() && - (((numActive + numHeld) == 0) && - (callState == HeadsetHalConstants.CALL_STATE_IDLE))) { - ActiveDeviceManager mDeviceManager = - AdapterService.getAdapterService().getActiveDeviceManager(); - mDeviceManager.triggerPendingA2dpActiveDevice(); - } - // Should stop all other audio mode in this case if ((numActive + numHeld) > 0 || callState != HeadsetHalConstants.CALL_STATE_IDLE) { if (!isVirtualCall && mVirtualCallStarted) { @@ -2938,32 +2845,9 @@ public class HeadsetService extends ProfileService { int toState) { synchronized (mStateMachines) { List<BluetoothDevice> audioConnectableDevices = - getConnectedDevices(); - CCService ccService = CCService.getCCService(); - AcmService acmService = AcmService.getAcmService(); - LeAudioService leAudioService = LeAudioService.getLeAudioService(); - List<BluetoothDevice> leaudioConnectedDevices = new ArrayList<>(0); - List<BluetoothDevice> leAudioGroupLeadDevices = new ArrayList<>(0); - if (acmService != null) { - leaudioConnectedDevices = acmService.getConnectedDevices(); - Log.v(TAG, "onConnectionStateChanged: leAudioConnectedDevices = " - + leaudioConnectedDevices.size()); - } - - if (leAudioService != null) { - leAudioGroupLeadDevices = leAudioService.getConnectedGroupLeadDevices(); - Log.v(TAG, "onConnectionStateChanged: leAudioGroupLeadDevices = " - + leAudioGroupLeadDevices.size()); - } - + getConnectedDevices(); if (fromState != BluetoothProfile.STATE_CONNECTED && toState == BluetoothProfile.STATE_CONNECTED) { - if (ccService != null) { - if ((leAudioGroupLeadDevices.size() >= 1) && ccService.isInbandRingingEnabled()) { - Log.i(TAG,"Disable Inband Ringtone for CC if hf device also connected"); - ccService.updateStatusFlags(0); - } - } boolean isInbandRingingSupported = getResources().getBoolean( com.android.bluetooth.R.bool.config_bluetooth_hfp_inband_ringing_support); if (audioConnectableDevices.size() > 1 && isInbandRingingSupported && @@ -2979,12 +2863,6 @@ public class HeadsetService extends ProfileService { && toState == BluetoothProfile.STATE_DISCONNECTED) { if (audioConnectableDevices.size() <= 1 ) { mInbandRingingRuntimeDisable = false; - if (ccService != null) { - if (leAudioGroupLeadDevices.size() <= 1 && ccService.isInbandRingingEnabled()) { - Log.i(TAG,"enable Inband Ringtone for CC if hf device is disconnected"); - ccService.updateStatusFlags(1); - } - } } if (device.equals(mActiveDevice)) { AdapterService adapterService = AdapterService.getAdapterService(); diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java index 59d264685..36a8e4971 100644 --- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java +++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java @@ -46,11 +46,6 @@ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE - * - * Changes from Qualcomm Innovation Center are provided under the following license: - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause-Clear - * */ package com.android.bluetooth.hfp; @@ -515,8 +510,7 @@ public class HeadsetStateMachine extends StateMachine { mHeadsetService.updateConnState(device, toState); } mHeadsetService.onConnectionStateChangedFromStateMachine(device, fromState, toState); - if(!ApmConstIntf.getQtiLeAudioEnabled() && - !(ApmConstIntf.getAospLeaEnabled() && mHeadsetService.isVoipLeaWarEnabled())) { + if(!ApmConstIntf.getQtiLeAudioEnabled()) { Intent intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, fromState); intent.putExtra(BluetoothProfile.EXTRA_STATE, toState); diff --git a/src/com/android/bluetooth/le_audio/LeAudioService.java b/src/com/android/bluetooth/le_audio/LeAudioService.java index 886bc2ff2..da12310db 100644 --- a/src/com/android/bluetooth/le_audio/LeAudioService.java +++ b/src/com/android/bluetooth/le_audio/LeAudioService.java @@ -13,11 +13,6 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * - * Changes from Qualcomm Innovation Center are provided under the following license: - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause-Clear - * */ package com.android.bluetooth.le_audio; @@ -69,7 +64,6 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.ServiceFactory; -import com.android.bluetooth.hap.HapClientService; import com.android.bluetooth.hfp.HeadsetService; import com.android.bluetooth.btservice.storage.DatabaseManager; import com.android.bluetooth.csip.CsipSetCoordinatorService; @@ -82,13 +76,11 @@ import com.android.modules.utils.SynchronousResultReceiver; import com.android.bluetooth.apm.ActiveDeviceManagerServiceIntf; import com.android.bluetooth.apm.ApmConstIntf; -import com.android.bluetooth.apm.ApmConst; import com.android.bluetooth.apm.MediaAudioIntf; import com.android.bluetooth.apm.CallAudioIntf; import com.android.bluetooth.apm.VolumeManagerIntf; import com.android.bluetooth.acm.AcmServIntf; import com.android.internal.util.ArrayUtils; -import com.android.bluetooth.apm.DeviceProfileMap; import java.util.Arrays; import java.math.BigInteger; @@ -161,7 +153,6 @@ public class LeAudioService extends ProfileService { private HandlerThread mStateMachinesThread; private BluetoothDevice mActiveAudioOutDevice; private BluetoothDevice mActiveAudioInDevice; - private static BluetoothDevice mPreviousActiveDevice; private int mLeActiveGroupID; private LeAudioCodecConfig mLeAudioCodecConfig; ServiceFactory mServiceFactory = new ServiceFactory(); @@ -377,7 +368,6 @@ public class LeAudioService extends ProfileService { mStateMachines.clear(); }*/ - mPreviousActiveDevice = null; mDeviceGroupIdMap.clear(); mDeviceAudioLocationMap.clear(); mGroupDescriptors.clear(); @@ -494,13 +484,9 @@ public class LeAudioService extends ProfileService { } } - if (!mPtsTmapConfBandC && - mPtsMediaAndVoice == 2) { + if (!mPtsTmapConfBandC && mPtsMediaAndVoice == 2) { if (mCallAudio != null) { - Log.d(TAG, "connect(): Connecting call AUdio"); mCallAudio.connect(device); - } else { - Log.d(TAG, "call AUdio is null"); } } @@ -1178,139 +1164,23 @@ public class LeAudioService extends ProfileService { setActiveDeviceGroup(device); return true; }*/ - Log.d(TAG, "setActiveDevice() for device: " + device + - ", mPreviousActiveDevice: " + mPreviousActiveDevice); - DeviceProfileMap dpm = DeviceProfileMap.getDeviceProfileMapInstance(); - if (dpm == null) { - Log.w(TAG, "setActiveDevice: dpm is null, return."); - return false; - } - BluetoothDevice fetchCurrentActiveDevice = null; - - if (device == null) { - fetchCurrentActiveDevice = mPreviousActiveDevice; - mPreviousActiveDevice = null; - } else { - fetchCurrentActiveDevice = device; - } - - int MediaProfID = dpm.getSupportedProfile(fetchCurrentActiveDevice, - ApmConst.AudioFeatures.MEDIA_AUDIO); - int VoiceProfID = dpm.getSupportedProfile(fetchCurrentActiveDevice, - ApmConst.AudioFeatures.CALL_AUDIO); - Log.d(TAG, "setActiveDevice: "+ " MediaProfID:" + MediaProfID + - ", VoiceProfID:" + VoiceProfID); - - mPreviousActiveDevice = device; - CallAudioIntf mCallAudio = CallAudioIntf.get(); - boolean isInCall = - mCallAudio != null && mCallAudio.isVoiceOrCallActive(); - int adapterState = (mAdapterService != null) ? mAdapterService.getState() - : BluetoothAdapter.STATE_OFF; - Log.d(TAG, "setActiveDevice: "+ " adapterState: " + adapterState); - - boolean isDuMoEnabled = Utils.isDualModeAudioEnabled(); ActiveDeviceManagerServiceIntf activeDeviceManager = ActiveDeviceManagerServiceIntf.get(); - if (device == null || ((ApmConst.AudioProfiles.HAP_LE & VoiceProfID) == - ApmConst.AudioProfiles.HAP_LE) || - ((ApmConst.AudioProfiles.BAP_CALL & VoiceProfID) == - ApmConst.AudioProfiles.BAP_CALL)) { - if (isInCall && adapterState == BluetoothAdapter.STATE_ON) { - if (isDuMoEnabled) { - Log.d(TAG, "Telephony request for Active device, DualMode"); - activeDeviceManager.setActiveDevice(device, - ApmConstIntf.AudioFeatures.CALL_AUDIO, true); - } else { - activeDeviceManager.setActiveDeviceBlocking(device, - ApmConstIntf.AudioFeatures.CALL_AUDIO); - } - } else { - activeDeviceManager.setActiveDevice(device, - ApmConstIntf.AudioFeatures.CALL_AUDIO); - } - } - - if (device == null || ((ApmConst.AudioProfiles.HAP_LE & MediaProfID) == - ApmConst.AudioProfiles.HAP_LE) || - ((ApmConst.AudioProfiles.BAP_MEDIA & MediaProfID) == - ApmConst.AudioProfiles.BAP_MEDIA)) { - if (isInCall && adapterState == BluetoothAdapter.STATE_ON) { - if (isDuMoEnabled) { - activeDeviceManager.setActiveDevice(device, - ApmConstIntf.AudioFeatures.MEDIA_AUDIO, true); - } else { - activeDeviceManager.setActiveDeviceBlocking(device, - ApmConstIntf.AudioFeatures.MEDIA_AUDIO); - } - } else { - Log.d(TAG, "Telephony request for Active device, DualMode"); - activeDeviceManager.setActiveDevice(device, - ApmConstIntf.AudioFeatures.MEDIA_AUDIO); - } - } + activeDeviceManager.setActiveDevice(device, + ApmConstIntf.AudioFeatures.CALL_AUDIO); + activeDeviceManager.setActiveDevice(device, + ApmConstIntf.AudioFeatures.MEDIA_AUDIO); return true; } public boolean setActiveDeviceBlocking(BluetoothDevice device) { - Log.d(TAG, "setActiveDeviceBlocking() for device: " + device + - ", mPreviousActiveDevice: " + mPreviousActiveDevice); - DeviceProfileMap dpm = DeviceProfileMap.getDeviceProfileMapInstance(); - if (dpm == null) { - Log.w(TAG, "setActiveDeviceBlocking: dpm is null, return."); - return false; - } - BluetoothDevice fetchCurrentActiveDevice = null; - boolean isDuMoEnabled = Utils.isDualModeAudioEnabled(); - - if (device == null) { - fetchCurrentActiveDevice = mPreviousActiveDevice; - mPreviousActiveDevice = null; - } else { - fetchCurrentActiveDevice = device; - } - - Log.d(TAG, "setActiveDeviceBlocking(): fetchCurrentActiveDevice: " + - fetchCurrentActiveDevice); - - int MediaProfID = dpm.getSupportedProfile(fetchCurrentActiveDevice, - ApmConst.AudioFeatures.MEDIA_AUDIO); - int VoiceProfID = dpm.getSupportedProfile(fetchCurrentActiveDevice, - ApmConst.AudioFeatures.CALL_AUDIO); - Log.d(TAG, "setActiveDeviceBlocking: "+ " MediaProfID:" + MediaProfID + - ", VoiceProfID:" + VoiceProfID); - mPreviousActiveDevice = device; - + Log.d(TAG, "setActiveDeviceBlocking() for device: " + device); ActiveDeviceManagerServiceIntf activeDeviceManager = ActiveDeviceManagerServiceIntf.get(); - - if (device == null || ((ApmConst.AudioProfiles.HAP_LE & VoiceProfID) == - ApmConst.AudioProfiles.HAP_LE) || - ((ApmConst.AudioProfiles.BAP_CALL & VoiceProfID) == - ApmConst.AudioProfiles.BAP_CALL)) { - if (isDuMoEnabled) { - Log.d(TAG, " Avoiding Blocking call for DUMO"); - activeDeviceManager.setActiveDevice(device, - ApmConstIntf.AudioFeatures.CALL_AUDIO); - } else { - activeDeviceManager.setActiveDeviceBlocking(device, + activeDeviceManager.setActiveDeviceBlocking(device, ApmConstIntf.AudioFeatures.CALL_AUDIO); - } - } - - if (device == null || ((ApmConst.AudioProfiles.HAP_LE & MediaProfID) == - ApmConst.AudioProfiles.HAP_LE) || - ((ApmConst.AudioProfiles.BAP_MEDIA & MediaProfID) == - ApmConst.AudioProfiles.BAP_MEDIA)) { - if (isDuMoEnabled) { - Log.d(TAG, " Avoiding Blocking call for DUMO"); - activeDeviceManager.setActiveDevice(device, - ApmConstIntf.AudioFeatures.MEDIA_AUDIO); - } else { - activeDeviceManager.setActiveDeviceBlocking(device, + activeDeviceManager.setActiveDeviceBlocking(device, ApmConstIntf.AudioFeatures.MEDIA_AUDIO); - } - } return true; } @@ -1340,13 +1210,6 @@ public class LeAudioService extends ProfileService { activeDevices.add(1, mActiveAudioInDevice); }*/ - activeDevices.add(0, null); - activeDevices.add(1, null); - if (ApmConstIntf.getQtiLeAudioEnabled()) { - Log.d(TAG, "QTI LeAudio is enabled, return empty list"); - return activeDevices; - } - ActiveDeviceManagerServiceIntf activeDeviceManager = ActiveDeviceManagerServiceIntf.get(); BluetoothDevice outDevice = activeDeviceManager.getActiveAbsoluteDevice(ApmConstIntf.AudioFeatures.MEDIA_AUDIO); @@ -1364,21 +1227,13 @@ public class LeAudioService extends ProfileService { mActiveAudioInDevice = activeDeviceManager.getActiveAbsoluteDevice(ApmConstIntf.AudioFeatures.CALL_AUDIO); */ - int ActiveAudioMediaProfile = - activeDeviceManager.getActiveProfile(ApmConstIntf.AudioFeatures.MEDIA_AUDIO); - int ActiveAudioCallProfile = - activeDeviceManager.getActiveProfile(ApmConstIntf.AudioFeatures.CALL_AUDIO); - /*if (ActiveAudioMediaProfile == ApmConst.AudioProfiles.TMAP_MEDIA || ActiveAudioMediaProfile == ApmConst.AudioProfiles.BAP_MEDIA || ActiveAudioMediaProfile == ApmConst.AudioProfiles.BAP_GCP || ActiveAudioMediaProfile == ApmConst.AudioProfiles.BAP_GCP_VBC || ActiveAudioCallProfile == ApmConst.AudioProfiles.TMAP_CALL || - ActiveAudioCallProfile == ApmConst.AudioProfiles.BAP_CALL) { - if (ActiveAudioCallProfile != ApmConst.AudioProfiles.HFP) { - activeDevices.add(0, mActiveAudioOutDevice); - } - } + ActiveAudioCallProfile == ApmConst.AudioProfiles.BAP_CALL) + activeDevices.add(0, mActiveAudioOutDevice); if (ActiveAudioMediaProfile == ApmConst.AudioProfiles.BAP_RECORDING || ActiveAudioMediaProfile == ApmConst.AudioProfiles.BAP_GCP_VBC || @@ -1393,12 +1248,6 @@ public class LeAudioService extends ProfileService { activeDevices.add(1, mActiveAudioInDevice); } }*/ - - if ((ActiveAudioMediaProfile == ApmConst.AudioProfiles.BROADCAST_LE) && - (ActiveAudioCallProfile == ApmConst.AudioProfiles.TMAP_CALL || - ActiveAudioCallProfile == ApmConst.AudioProfiles.BAP_CALL)) { - mActiveAudioOutDevice = mActiveAudioInDevice; - } activeDevices.add(0, mActiveAudioOutDevice); int activeGid = getGroupId(mActiveAudioOutDevice); if (activeGid < INVALID_SET_ID) { @@ -2076,17 +1925,6 @@ public class LeAudioService extends ProfileService { Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy); } - ParcelUuid[] featureUuids = mAdapterService.getRemoteUuids(device); - if (ArrayUtils.contains(featureUuids, BluetoothUuid.HAS)) { - Log.e(TAG, ": Remote has Hearing Aid UUID"); - //Calling HapClient Setconnection policy - HapClientService hapClientService = HapClientService.getHapClientService(); - if (hapClientService != null) { - hapClientService.setConnectionPolicy(device, connectionPolicy); - Log.d(TAG, "Hap connectionPolicy "); - } - } - if (!mDatabaseManager.setProfileConnectionPolicy(device, BluetoothProfile.LE_AUDIO, connectionPolicy)) { return false; @@ -2680,50 +2518,12 @@ public class LeAudioService extends ProfileService { boolean defaultValueVoice = false; boolean defaultValueMedia = false; if (service != null) { - Log.d(TAG, "Binder setActiveDevice() for device: " + device + - ", mPreviousActiveDevice: " + mPreviousActiveDevice); ActiveDeviceManagerServiceIntf activeDeviceManager = ActiveDeviceManagerServiceIntf.get(); - DeviceProfileMap dpm = DeviceProfileMap.getDeviceProfileMapInstance(); - if (dpm == null) { - Log.w(TAG, "Binder setActiveDevice: dpm is null, return."); - return; - } - - BluetoothDevice fetchCurrentActiveDevice = null; - - if (device == null) { - fetchCurrentActiveDevice = mPreviousActiveDevice; - mPreviousActiveDevice = null; - } else { - fetchCurrentActiveDevice = device; - } - - int MediaProfID = dpm.getSupportedProfile(fetchCurrentActiveDevice, - ApmConst.AudioFeatures.MEDIA_AUDIO); - int VoiceProfID = dpm.getSupportedProfile(fetchCurrentActiveDevice, - ApmConst.AudioFeatures.CALL_AUDIO); - Log.d(TAG, "Binder setActiveDevice: "+ " MediaProfID:" + MediaProfID + - ", VoiceProfID:" + VoiceProfID); - - mPreviousActiveDevice = device; - - if (((ApmConst.AudioProfiles.HAP_LE & VoiceProfID) == - ApmConst.AudioProfiles.HAP_LE) || - ((ApmConst.AudioProfiles.BAP_CALL & VoiceProfID) == - ApmConst.AudioProfiles.BAP_CALL)) { - defaultValueVoice = activeDeviceManager.setActiveDevice(device, - ApmConstIntf.AudioFeatures.CALL_AUDIO, true); - } - - if (((ApmConst.AudioProfiles.HAP_LE & MediaProfID) == - ApmConst.AudioProfiles.HAP_LE) || - ((ApmConst.AudioProfiles.BAP_MEDIA & MediaProfID) == - ApmConst.AudioProfiles.BAP_MEDIA)) { - defaultValueMedia = activeDeviceManager.setActiveDevice(device, - ApmConstIntf.AudioFeatures.MEDIA_AUDIO, true); - } - + defaultValueVoice = activeDeviceManager.setActiveDevice(device, + ApmConstIntf.AudioFeatures.CALL_AUDIO, true); + defaultValueMedia = activeDeviceManager.setActiveDevice(device, + ApmConstIntf.AudioFeatures.MEDIA_AUDIO, true); defaultValue = (defaultValueVoice & defaultValueMedia); } receiver.send(defaultValue); diff --git a/114.json b/tests/unit/src/com/android/bluetooth/btservice/storage/schemas/com.android.bluetooth.btservice.storage.MetadataDatabase/114.json index 64f8ab3fd..64f8ab3fd 100644 --- a/114.json +++ b/tests/unit/src/com/android/bluetooth/btservice/storage/schemas/com.android.bluetooth.btservice.storage.MetadataDatabase/114.json |