1 /*
2 * Copyright 2021 HIMSA II K/S - www.himsa.com.
3 * Represented by EHIMA - www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #define LOG_TAG "BluetoothHapClientJni"
19
20 #include <string.h>
21
22 #include <shared_mutex>
23
24 #include "com_android_bluetooth.h"
25 #include "hardware/bt_has.h"
26
27 using bluetooth::has::ConnectionState;
28 using bluetooth::has::ErrorCode;
29 using bluetooth::has::HasClientCallbacks;
30 using bluetooth::has::HasClientInterface;
31 using bluetooth::has::PresetInfo;
32 using bluetooth::has::PresetInfoReason;
33
34 namespace android {
35 static jmethodID method_onConnectionStateChanged;
36 static jmethodID method_onDeviceAvailable;
37 static jmethodID method_onFeaturesUpdate;
38 static jmethodID method_onActivePresetSelected;
39 static jmethodID method_onGroupActivePresetSelected;
40 static jmethodID method_onActivePresetSelectError;
41 static jmethodID method_onGroupActivePresetSelectError;
42 static jmethodID method_onPresetInfo;
43 static jmethodID method_onGroupPresetInfo;
44 static jmethodID method_onPresetInfoError;
45 static jmethodID method_onGroupPresetInfoError;
46 static jmethodID method_onPresetNameSetError;
47 static jmethodID method_onGroupPresetNameSetError;
48
49 static HasClientInterface* sHasClientInterface = nullptr;
50 static std::shared_timed_mutex interface_mutex;
51
52 static jobject mCallbacksObj = nullptr;
53 static std::shared_timed_mutex callbacks_mutex;
54
55 static struct {
56 jclass clazz;
57 jmethodID constructor;
58 jmethodID getCodecType;
59 jmethodID getCodecPriority;
60 jmethodID getSampleRate;
61 jmethodID getBitsPerSample;
62 jmethodID getChannelMode;
63 jmethodID getCodecSpecific1;
64 jmethodID getCodecSpecific2;
65 jmethodID getCodecSpecific3;
66 jmethodID getCodecSpecific4;
67 } android_bluetooth_BluetoothHapPresetInfo;
68
69 class HasClientCallbacksImpl : public HasClientCallbacks {
70 public:
71 ~HasClientCallbacksImpl() = default;
72
OnConnectionState(ConnectionState state,const RawAddress & bd_addr)73 void OnConnectionState(ConnectionState state,
74 const RawAddress& bd_addr) override {
75 log::info("");
76
77 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
78 CallbackEnv sCallbackEnv(__func__);
79 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
80
81 ScopedLocalRef<jbyteArray> addr(
82 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
83 if (!addr.get()) {
84 log::error("Failed to new bd addr jbyteArray for connection state");
85 return;
86 }
87
88 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
89 (jbyte*)&bd_addr);
90 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
91 (jint)state, addr.get());
92 }
93
OnDeviceAvailable(const RawAddress & bd_addr,uint8_t features)94 void OnDeviceAvailable(const RawAddress& bd_addr, uint8_t features) override {
95 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
96 CallbackEnv sCallbackEnv(__func__);
97 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
98
99 ScopedLocalRef<jbyteArray> addr(
100 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
101 if (!addr.get()) {
102 log::error("Failed to new bd addr jbyteArray for device available");
103 return;
104 }
105 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
106 (jbyte*)&bd_addr);
107
108 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDeviceAvailable,
109 addr.get(), (jint)features);
110 }
111
OnFeaturesUpdate(const RawAddress & bd_addr,uint8_t features)112 void OnFeaturesUpdate(const RawAddress& bd_addr, uint8_t features) override {
113 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
114 CallbackEnv sCallbackEnv(__func__);
115 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
116
117 ScopedLocalRef<jbyteArray> addr(
118 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
119 if (!addr.get()) {
120 log::error("Failed to new bd addr jbyteArray for device available");
121 return;
122 }
123 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
124 (jbyte*)&bd_addr);
125
126 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onFeaturesUpdate,
127 addr.get(), (jint)features);
128 }
129
OnActivePresetSelected(std::variant<RawAddress,int> addr_or_group_id,uint8_t preset_index)130 void OnActivePresetSelected(std::variant<RawAddress, int> addr_or_group_id,
131 uint8_t preset_index) override {
132 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
133 CallbackEnv sCallbackEnv(__func__);
134 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
135
136 if (std::holds_alternative<RawAddress>(addr_or_group_id)) {
137 ScopedLocalRef<jbyteArray> addr(
138 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
139 if (!addr.get()) {
140 log::error("Failed to new bd addr jbyteArray for preset selected");
141 return;
142 }
143 sCallbackEnv->SetByteArrayRegion(
144 addr.get(), 0, sizeof(RawAddress),
145 (jbyte*)&std::get<RawAddress>(addr_or_group_id));
146
147 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onActivePresetSelected,
148 addr.get(), (jint)preset_index);
149 } else {
150 sCallbackEnv->CallVoidMethod(
151 mCallbacksObj, method_onGroupActivePresetSelected,
152 std::get<int>(addr_or_group_id), (jint)preset_index);
153 }
154 }
155
OnActivePresetSelectError(std::variant<RawAddress,int> addr_or_group_id,ErrorCode error_code)156 void OnActivePresetSelectError(std::variant<RawAddress, int> addr_or_group_id,
157 ErrorCode error_code) override {
158 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
159 CallbackEnv sCallbackEnv(__func__);
160 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
161
162 if (std::holds_alternative<RawAddress>(addr_or_group_id)) {
163 ScopedLocalRef<jbyteArray> addr(
164 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
165 if (!addr.get()) {
166 log::error("Failed to new bd addr jbyteArray for preset select error");
167 return;
168 }
169 sCallbackEnv->SetByteArrayRegion(
170 addr.get(), 0, sizeof(RawAddress),
171 (jbyte*)&std::get<RawAddress>(addr_or_group_id));
172
173 sCallbackEnv->CallVoidMethod(mCallbacksObj,
174 method_onActivePresetSelectError, addr.get(),
175 (jint)error_code);
176 } else {
177 sCallbackEnv->CallVoidMethod(
178 mCallbacksObj, method_onGroupActivePresetSelectError,
179 std::get<int>(addr_or_group_id), (jint)error_code);
180 }
181 }
182
OnPresetInfo(std::variant<RawAddress,int> addr_or_group_id,PresetInfoReason info_reason,std::vector<PresetInfo> detail_records)183 void OnPresetInfo(std::variant<RawAddress, int> addr_or_group_id,
184 PresetInfoReason info_reason,
185 std::vector<PresetInfo> detail_records) override {
186 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
187 CallbackEnv sCallbackEnv(__func__);
188 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
189
190 jsize i = 0;
191 jobjectArray presets_array = sCallbackEnv->NewObjectArray(
192 (jsize)detail_records.size(),
193 android_bluetooth_BluetoothHapPresetInfo.clazz, nullptr);
194
195 const char null_str[] = "";
196 for (auto const& info : detail_records) {
197 const char* name = info.preset_name.c_str();
198 if (!sCallbackEnv.isValidUtf(name)) {
199 log::error("name is not a valid UTF string.");
200 name = null_str;
201 }
202
203 ScopedLocalRef<jstring> name_str(sCallbackEnv.get(),
204 sCallbackEnv->NewStringUTF(name));
205 if (!name_str.get()) {
206 log::error("Failed to new preset name String for preset name");
207 return;
208 }
209
210 jobject infoObj = sCallbackEnv->NewObject(
211 android_bluetooth_BluetoothHapPresetInfo.clazz,
212 android_bluetooth_BluetoothHapPresetInfo.constructor,
213 (jint)info.preset_index, name_str.get(), (jboolean)info.writable,
214 (jboolean)info.available);
215 sCallbackEnv->SetObjectArrayElement(presets_array, i++, infoObj);
216 sCallbackEnv->DeleteLocalRef(infoObj);
217 }
218
219 if (std::holds_alternative<RawAddress>(addr_or_group_id)) {
220 ScopedLocalRef<jbyteArray> addr(
221 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
222 if (!addr.get()) {
223 log::error("Failed to new bd addr jbyteArray for preset name");
224 return;
225 }
226 sCallbackEnv->SetByteArrayRegion(
227 addr.get(), 0, sizeof(RawAddress),
228 (jbyte*)&std::get<RawAddress>(addr_or_group_id));
229
230 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onPresetInfo,
231 addr.get(), (jint)info_reason,
232 presets_array);
233 } else {
234 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupPresetInfo,
235 std::get<int>(addr_or_group_id),
236 (jint)info_reason, presets_array);
237 }
238 }
239
OnPresetInfoError(std::variant<RawAddress,int> addr_or_group_id,uint8_t preset_index,ErrorCode error_code)240 virtual void OnPresetInfoError(std::variant<RawAddress, int> addr_or_group_id,
241 uint8_t preset_index,
242 ErrorCode error_code) override {
243 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
244 CallbackEnv sCallbackEnv(__func__);
245 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
246
247 if (std::holds_alternative<RawAddress>(addr_or_group_id)) {
248 ScopedLocalRef<jbyteArray> addr(
249 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
250 if (!addr.get()) {
251 log::error(
252 "Failed to new bd addr jbyteArray for preset name get error");
253 return;
254 }
255 sCallbackEnv->SetByteArrayRegion(
256 addr.get(), 0, sizeof(RawAddress),
257 (jbyte*)&std::get<RawAddress>(addr_or_group_id));
258
259 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onPresetInfoError,
260 addr.get(), (jint)preset_index,
261 (jint)error_code);
262 } else {
263 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupPresetInfoError,
264 std::get<int>(addr_or_group_id),
265 (jint)preset_index, (jint)error_code);
266 }
267 }
268
OnSetPresetNameError(std::variant<RawAddress,int> addr_or_group_id,uint8_t preset_index,ErrorCode error_code)269 void OnSetPresetNameError(std::variant<RawAddress, int> addr_or_group_id,
270 uint8_t preset_index,
271 ErrorCode error_code) override {
272 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
273 CallbackEnv sCallbackEnv(__func__);
274 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
275
276 if (std::holds_alternative<RawAddress>(addr_or_group_id)) {
277 ScopedLocalRef<jbyteArray> addr(
278 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
279 if (!addr.get()) {
280 log::error(
281 "Failed to new bd addr jbyteArray for preset name set error");
282 return;
283 }
284 sCallbackEnv->SetByteArrayRegion(
285 addr.get(), 0, sizeof(RawAddress),
286 (jbyte*)&std::get<RawAddress>(addr_or_group_id));
287
288 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onPresetNameSetError,
289 addr.get(), (jint)preset_index,
290 (jint)error_code);
291 } else {
292 sCallbackEnv->CallVoidMethod(mCallbacksObj,
293 method_onGroupPresetNameSetError,
294 std::get<int>(addr_or_group_id),
295 (jint)preset_index, (jint)error_code);
296 }
297 }
298 };
299
300 static HasClientCallbacksImpl sHasClientCallbacks;
301
initNative(JNIEnv * env,jobject object)302 static void initNative(JNIEnv* env, jobject object) {
303 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
304 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
305
306 const bt_interface_t* btInf = getBluetoothInterface();
307 if (btInf == nullptr) {
308 log::error("Bluetooth module is not loaded");
309 return;
310 }
311
312 if (sHasClientInterface != nullptr) {
313 log::info("Cleaning up HearingAid Interface before initializing...");
314 sHasClientInterface->Cleanup();
315 sHasClientInterface = nullptr;
316 }
317
318 if (mCallbacksObj != nullptr) {
319 log::info("Cleaning up HearingAid callback object");
320 env->DeleteGlobalRef(mCallbacksObj);
321 mCallbacksObj = nullptr;
322 }
323
324 if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
325 log::error("Failed to allocate Global Ref for Hearing Access Callbacks");
326 return;
327 }
328
329 android_bluetooth_BluetoothHapPresetInfo.clazz = (jclass)env->NewGlobalRef(
330 env->FindClass("android/bluetooth/BluetoothHapPresetInfo"));
331 if (android_bluetooth_BluetoothHapPresetInfo.clazz == nullptr) {
332 log::error(
333 "Failed to allocate Global Ref for BluetoothHapPresetInfo class");
334 return;
335 }
336
337 sHasClientInterface = (HasClientInterface*)btInf->get_profile_interface(
338 BT_PROFILE_HAP_CLIENT_ID);
339 if (sHasClientInterface == nullptr) {
340 log::error(
341 "Failed to get Bluetooth Hearing Access Service Client Interface");
342 return;
343 }
344
345 sHasClientInterface->Init(&sHasClientCallbacks);
346 }
347
cleanupNative(JNIEnv * env,jobject)348 static void cleanupNative(JNIEnv* env, jobject /* object */) {
349 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
350 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
351
352 const bt_interface_t* btInf = getBluetoothInterface();
353 if (btInf == nullptr) {
354 log::error("Bluetooth module is not loaded");
355 return;
356 }
357
358 if (sHasClientInterface != nullptr) {
359 sHasClientInterface->Cleanup();
360 sHasClientInterface = nullptr;
361 }
362
363 if (mCallbacksObj != nullptr) {
364 env->DeleteGlobalRef(mCallbacksObj);
365 mCallbacksObj = nullptr;
366 }
367 }
368
connectHapClientNative(JNIEnv * env,jobject,jbyteArray address)369 static jboolean connectHapClientNative(JNIEnv* env, jobject /* object */,
370 jbyteArray address) {
371 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
372 if (!sHasClientInterface) {
373 log::error("Failed to get the Bluetooth HAP Interface");
374 return JNI_FALSE;
375 }
376
377 jbyte* addr = env->GetByteArrayElements(address, nullptr);
378 if (!addr) {
379 jniThrowIOException(env, EINVAL);
380 return JNI_FALSE;
381 }
382
383 RawAddress* tmpraw = (RawAddress*)addr;
384 sHasClientInterface->Connect(*tmpraw);
385 env->ReleaseByteArrayElements(address, addr, 0);
386 return JNI_TRUE;
387 }
388
disconnectHapClientNative(JNIEnv * env,jobject,jbyteArray address)389 static jboolean disconnectHapClientNative(JNIEnv* env, jobject /* object */,
390 jbyteArray address) {
391 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
392 if (!sHasClientInterface) {
393 log::error("Failed to get the Bluetooth HAP Interface");
394 return JNI_FALSE;
395 }
396
397 jbyte* addr = env->GetByteArrayElements(address, nullptr);
398 if (!addr) {
399 jniThrowIOException(env, EINVAL);
400 return JNI_FALSE;
401 }
402
403 RawAddress* tmpraw = (RawAddress*)addr;
404 sHasClientInterface->Disconnect(*tmpraw);
405 env->ReleaseByteArrayElements(address, addr, 0);
406 return JNI_TRUE;
407 }
408
selectActivePresetNative(JNIEnv * env,jobject,jbyteArray address,jint preset_index)409 static void selectActivePresetNative(JNIEnv* env, jobject /* object */,
410 jbyteArray address, jint preset_index) {
411 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
412 if (!sHasClientInterface) {
413 log::error("Failed to get the Bluetooth HAP Interface");
414 return;
415 }
416
417 jbyte* addr = env->GetByteArrayElements(address, nullptr);
418 if (!addr) {
419 jniThrowIOException(env, EINVAL);
420 return;
421 }
422
423 RawAddress* tmpraw = (RawAddress*)addr;
424 sHasClientInterface->SelectActivePreset(*tmpraw, preset_index);
425 env->ReleaseByteArrayElements(address, addr, 0);
426 }
427
groupSelectActivePresetNative(JNIEnv *,jobject,jint group_id,jint preset_index)428 static void groupSelectActivePresetNative(JNIEnv* /* env */,
429 jobject /* object */, jint group_id,
430 jint preset_index) {
431 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
432 if (!sHasClientInterface) {
433 log::error("Failed to get the Bluetooth HAP Interface");
434 return;
435 }
436
437 sHasClientInterface->SelectActivePreset(group_id, preset_index);
438 }
439
nextActivePresetNative(JNIEnv * env,jobject,jbyteArray address)440 static void nextActivePresetNative(JNIEnv* env, jobject /* object */,
441 jbyteArray address) {
442 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
443 if (!sHasClientInterface) {
444 log::error("Failed to get the Bluetooth HAP Interface");
445 return;
446 }
447
448 jbyte* addr = env->GetByteArrayElements(address, nullptr);
449 if (!addr) {
450 jniThrowIOException(env, EINVAL);
451 return;
452 }
453
454 RawAddress* tmpraw = (RawAddress*)addr;
455 sHasClientInterface->NextActivePreset(*tmpraw);
456 env->ReleaseByteArrayElements(address, addr, 0);
457 }
458
groupNextActivePresetNative(JNIEnv *,jobject,jint group_id)459 static void groupNextActivePresetNative(JNIEnv* /* env */, jobject /* object */,
460 jint group_id) {
461 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
462 if (!sHasClientInterface) {
463 log::error("Failed to get the Bluetooth HAP Interface");
464 return;
465 }
466
467 sHasClientInterface->NextActivePreset(group_id);
468 }
469
previousActivePresetNative(JNIEnv * env,jobject,jbyteArray address)470 static void previousActivePresetNative(JNIEnv* env, jobject /* object */,
471 jbyteArray address) {
472 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
473 if (!sHasClientInterface) {
474 log::error("Failed to get the Bluetooth HAP Interface");
475 return;
476 }
477
478 jbyte* addr = env->GetByteArrayElements(address, nullptr);
479 if (!addr) {
480 jniThrowIOException(env, EINVAL);
481 return;
482 }
483
484 RawAddress* tmpraw = (RawAddress*)addr;
485 sHasClientInterface->PreviousActivePreset(*tmpraw);
486 env->ReleaseByteArrayElements(address, addr, 0);
487 }
488
groupPreviousActivePresetNative(JNIEnv *,jobject,jint group_id)489 static void groupPreviousActivePresetNative(JNIEnv* /* env */,
490 jobject /* object */,
491 jint group_id) {
492 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
493 if (!sHasClientInterface) {
494 log::error("Failed to get the Bluetooth HAP Interface");
495 return;
496 }
497
498 sHasClientInterface->PreviousActivePreset(group_id);
499 }
500
getPresetInfoNative(JNIEnv * env,jobject,jbyteArray address,jint preset_index)501 static void getPresetInfoNative(JNIEnv* env, jobject /* object */,
502 jbyteArray address, jint preset_index) {
503 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
504 if (!sHasClientInterface) {
505 log::error("Failed to get the Bluetooth HAP Interface");
506 return;
507 }
508
509 jbyte* addr = env->GetByteArrayElements(address, nullptr);
510 if (!addr) {
511 jniThrowIOException(env, EINVAL);
512 return;
513 }
514
515 RawAddress* tmpraw = (RawAddress*)addr;
516 sHasClientInterface->GetPresetInfo(*tmpraw, preset_index);
517 env->ReleaseByteArrayElements(address, addr, 0);
518 }
519
setPresetNameNative(JNIEnv * env,jobject,jbyteArray address,jint preset_index,jstring name)520 static void setPresetNameNative(JNIEnv* env, jobject /* object */,
521 jbyteArray address, jint preset_index,
522 jstring name) {
523 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
524 if (!sHasClientInterface) {
525 log::error("Failed to get the Bluetooth HAP Interface");
526 return;
527 }
528
529 jbyte* addr = env->GetByteArrayElements(address, nullptr);
530 if (!addr) {
531 jniThrowIOException(env, EINVAL);
532 return;
533 }
534
535 std::string name_str;
536 if (name != nullptr) {
537 const char* value = env->GetStringUTFChars(name, nullptr);
538 name_str = std::string(value);
539 env->ReleaseStringUTFChars(name, value);
540 }
541
542 RawAddress* tmpraw = (RawAddress*)addr;
543 sHasClientInterface->SetPresetName(*tmpraw, preset_index,
544 std::move(name_str));
545 env->ReleaseByteArrayElements(address, addr, 0);
546 }
547
groupSetPresetNameNative(JNIEnv * env,jobject,jint group_id,jint preset_index,jstring name)548 static void groupSetPresetNameNative(JNIEnv* env, jobject /* object */,
549 jint group_id, jint preset_index,
550 jstring name) {
551 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
552 if (!sHasClientInterface) {
553 log::error("Failed to get the Bluetooth HAP Interface");
554 return;
555 }
556
557 std::string name_str;
558 if (name != nullptr) {
559 const char* value = env->GetStringUTFChars(name, nullptr);
560 name_str = std::string(value);
561 env->ReleaseStringUTFChars(name, value);
562 }
563
564 sHasClientInterface->SetPresetName(group_id, preset_index,
565 std::move(name_str));
566 }
567
register_com_android_bluetooth_hap_client(JNIEnv * env)568 int register_com_android_bluetooth_hap_client(JNIEnv* env) {
569 const JNINativeMethod methods[] = {
570 {"initNative", "()V", (void*)initNative},
571 {"cleanupNative", "()V", (void*)cleanupNative},
572 {"connectHapClientNative", "([B)Z", (void*)connectHapClientNative},
573 {"disconnectHapClientNative", "([B)Z", (void*)disconnectHapClientNative},
574 {"selectActivePresetNative", "([BI)V", (void*)selectActivePresetNative},
575 {"groupSelectActivePresetNative", "(II)V",
576 (void*)groupSelectActivePresetNative},
577 {"nextActivePresetNative", "([B)V", (void*)nextActivePresetNative},
578 {"groupNextActivePresetNative", "(I)V",
579 (void*)groupNextActivePresetNative},
580 {"previousActivePresetNative", "([B)V",
581 (void*)previousActivePresetNative},
582 {"groupPreviousActivePresetNative", "(I)V",
583 (void*)groupPreviousActivePresetNative},
584 {"getPresetInfoNative", "([BI)V", (void*)getPresetInfoNative},
585 {"setPresetNameNative", "([BILjava/lang/String;)V",
586 (void*)setPresetNameNative},
587 {"groupSetPresetNameNative", "(IILjava/lang/String;)V",
588 (void*)groupSetPresetNameNative},
589 };
590 const int result = REGISTER_NATIVE_METHODS(
591 env, "com/android/bluetooth/hap/HapClientNativeInterface", methods);
592 if (result != 0) {
593 return result;
594 }
595
596 const JNIJavaMethod javaMethods[] = {
597 {"onConnectionStateChanged", "(I[B)V", &method_onConnectionStateChanged},
598 {"onDeviceAvailable", "([BI)V", &method_onDeviceAvailable},
599 {"onFeaturesUpdate", "([BI)V", &method_onFeaturesUpdate},
600 {"onActivePresetSelected", "([BI)V", &method_onActivePresetSelected},
601 {"onActivePresetGroupSelected", "(II)V",
602 &method_onGroupActivePresetSelected},
603 {"onActivePresetSelectError", "([BI)V",
604 &method_onActivePresetSelectError},
605 {"onActivePresetGroupSelectError", "(II)V",
606 &method_onGroupActivePresetSelectError},
607 {"onPresetInfo", "([BI[Landroid/bluetooth/BluetoothHapPresetInfo;)V",
608 &method_onPresetInfo},
609 {"onGroupPresetInfo", "(II[Landroid/bluetooth/BluetoothHapPresetInfo;)V",
610 &method_onGroupPresetInfo},
611 {"onPresetNameSetError", "([BII)V", &method_onPresetNameSetError},
612 {"onGroupPresetNameSetError", "(III)V",
613 &method_onGroupPresetNameSetError},
614 {"onPresetInfoError", "([BII)V", &method_onPresetInfoError},
615 {"onGroupPresetInfoError", "(III)V", &method_onGroupPresetInfoError},
616 };
617 GET_JAVA_METHODS(env, "com/android/bluetooth/hap/HapClientNativeInterface",
618 javaMethods);
619
620 const JNIJavaMethod javaHapPresetMethods[] = {
621 {"<init>", "(ILjava/lang/String;ZZ)V",
622 &android_bluetooth_BluetoothHapPresetInfo.constructor},
623 };
624 GET_JAVA_METHODS(env, "android/bluetooth/BluetoothHapPresetInfo",
625 javaHapPresetMethods);
626
627 return 0;
628 }
629 } // namespace android
630