1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef LOG_TAG
16 #define LOG_TAG "bt_napi_pbap_pse"
17 #endif
18 
19 #include "bluetooth_errorcode.h"
20 #include "bluetooth_pbap_pse.h"
21 #include "bluetooth_utils.h"
22 #include "napi_async_work.h"
23 #include "napi_bluetooth_event.h"
24 #include "napi_bluetooth_error.h"
25 #include "napi_bluetooth_pbap_pse.h"
26 #include "napi_bluetooth_profile.h"
27 #include "napi_bluetooth_utils.h"
28 #include "../parser/napi_parser_utils.h"
29 #include "hitrace_meter.h"
30 
31 namespace OHOS {
32 namespace Bluetooth {
33 using namespace std;
34 
35 enum ShareType {
36     SHARE_NAME_AND_PHONE_NUMBER = 0,
37     SHARE_ALL = 1,
38     SHARE_NOTHING = 2,
39 };
40 
41 std::shared_ptr<NapiPbapPseObserver> NapiPbapServer::observer_ = std::make_shared<NapiPbapPseObserver>();
42 thread_local napi_ref g_consRef_ = nullptr;
43 
DefinePbapServerJSClass(napi_env env,napi_value exports)44 void NapiPbapServer::DefinePbapServerJSClass(napi_env env, napi_value exports)
45 {
46     napi_value constructor;
47     PbapPropertyValueInit(env, exports);
48     napi_property_descriptor properties[] = {
49         DECLARE_NAPI_FUNCTION("on", On),
50         DECLARE_NAPI_FUNCTION("off", Off),
51         DECLARE_NAPI_FUNCTION("getConnectedDevices", GetConnectedDevices),
52         DECLARE_NAPI_FUNCTION("getConnectionState", GetConnectionState),
53         DECLARE_NAPI_FUNCTION("setConnectionStrategy", SetConnectionStrategy),
54         DECLARE_NAPI_FUNCTION("getConnectionStrategy", GetConnectionStrategy),
55         DECLARE_NAPI_FUNCTION("disconnect", Disconnect),
56         DECLARE_NAPI_FUNCTION("setShareType", SetShareType),
57         DECLARE_NAPI_FUNCTION("getShareType", GetShareType),
58         DECLARE_NAPI_FUNCTION("setPhoneBookAccessAuthorization", SetPhoneBookAccessAuthorization),
59         DECLARE_NAPI_FUNCTION("getPhoneBookAccessAuthorization", GetPhoneBookAccessAuthorization),
60     };
61 
62     napi_define_class(env, "PbapPse", NAPI_AUTO_LENGTH, PbapServerConstructor, nullptr,
63         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
64 
65     DefineCreateProfile(env, exports);
66     napi_create_reference(env, constructor, 1, &g_consRef_);
67 }
68 
DefineCreateProfile(napi_env env,napi_value exports)69 napi_value NapiPbapServer::DefineCreateProfile(napi_env env, napi_value exports)
70 {
71     napi_property_descriptor properties[] = {
72         DECLARE_NAPI_FUNCTION("createPbapServerProfile", CreatePbapServerProfile),
73     };
74     HITRACE_METER_NAME(HITRACE_TAG_OHOS, "pbappse:napi_define_properties");
75     napi_define_properties(env, exports, sizeof(properties) / sizeof(properties[0]), properties);
76     return exports;
77 }
78 
CreatePbapServerProfile(napi_env env,napi_callback_info info)79 napi_value NapiPbapServer::CreatePbapServerProfile(napi_env env, napi_callback_info info)
80 {
81     napi_value napiProfile;
82     napi_value constructor = nullptr;
83     napi_get_reference_value(env, g_consRef_, &constructor);
84     napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
85 
86     PbapPse *profile = PbapPse::GetProfile();
87     profile->RegisterObserver(observer_);
88     return napiProfile;
89 }
90 
PbapServerConstructor(napi_env env,napi_callback_info info)91 napi_value NapiPbapServer::PbapServerConstructor(napi_env env, napi_callback_info info)
92 {
93     napi_value thisVar = nullptr;
94     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
95     return thisVar;
96 }
97 
PbapPropertyValueInit(napi_env env,napi_value exports)98 napi_value NapiPbapServer::PbapPropertyValueInit(napi_env env, napi_value exports)
99 {
100     HILOGI("enter");
101     napi_value shareTypeObj = ShareTypeInit(env);
102     napi_property_descriptor exportFuncs[] = {
103         DECLARE_NAPI_PROPERTY("ShareType", shareTypeObj),
104     };
105     HITRACE_METER_NAME(HITRACE_TAG_OHOS, "pbappse:napi_define_properties");
106     napi_define_properties(env, exports, sizeof(exportFuncs) / sizeof(*exportFuncs), exportFuncs);
107     return exports;
108 }
109 
ShareTypeInit(napi_env env)110 napi_value NapiPbapServer::ShareTypeInit(napi_env env)
111 {
112     HILOGD("enter");
113     napi_value shareType = nullptr;
114     napi_create_object(env, &shareType);
115     SetNamedPropertyByInteger(env, shareType, ShareType::SHARE_NAME_AND_PHONE_NUMBER, "SHARE_NAME_AND_PHONE_NUMBER");
116     SetNamedPropertyByInteger(env, shareType, ShareType::SHARE_ALL, "SHARE_ALL");
117     SetNamedPropertyByInteger(env, shareType, ShareType::SHARE_NOTHING, "SHARE_NOTHING");
118     return shareType;
119 }
120 
On(napi_env env,napi_callback_info info)121 napi_value NapiPbapServer::On(napi_env env, napi_callback_info info)
122 {
123     if (observer_) {
124         auto status = observer_->eventSubscribe_.Register(env, info);
125         NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
126     }
127     return NapiGetUndefinedRet(env);
128 }
129 
Off(napi_env env,napi_callback_info info)130 napi_value NapiPbapServer::Off(napi_env env, napi_callback_info info)
131 {
132     if (observer_) {
133         auto status = observer_->eventSubscribe_.Deregister(env, info);
134         NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
135     }
136     return NapiGetUndefinedRet(env);
137 }
138 
GetConnectedDevices(napi_env env,napi_callback_info info)139 napi_value NapiPbapServer::GetConnectedDevices(napi_env env, napi_callback_info info)
140 {
141     HILOGI("enter");
142     napi_value ret = nullptr;
143     napi_create_array(env, &ret);
144     napi_status checkRet = CheckEmptyParam(env, info);
145     NAPI_BT_ASSERT_RETURN(env, checkRet == napi_ok, BT_ERR_INVALID_PARAM, ret);
146 
147     PbapPse *profile = PbapPse::GetProfile();
148     vector<int32_t> states = { static_cast<int32_t>(BTConnectState::CONNECTED) };
149     vector<BluetoothRemoteDevice> devices {};
150     int32_t errorCode = profile->GetDevicesByStates(states, devices);
151     NAPI_BT_ASSERT_RETURN(env, errorCode == BT_NO_ERROR, errorCode, ret);
152 
153     vector<string> deviceVector;
154     for (auto &device : devices) {
155         deviceVector.push_back(device.GetDeviceAddr());
156     }
157 
158     auto status = ConvertStringVectorToJS(env, ret, deviceVector);
159     NAPI_BT_ASSERT_RETURN(env, status == napi_ok, BT_ERR_INTERNAL_ERROR, ret);
160     return ret;
161 }
162 
GetConnectionState(napi_env env,napi_callback_info info)163 napi_value NapiPbapServer::GetConnectionState(napi_env env, napi_callback_info info)
164 {
165     HILOGI("enter");
166     std::string remoteAddr{};
167     bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
168     NAPI_BT_ASSERT_RETURN_UNDEF(env, checkRet, BT_ERR_INVALID_PARAM);
169 
170     PbapPse *profile = PbapPse::GetProfile();
171     BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
172     int32_t state = static_cast<int32_t>(BTConnectState::DISCONNECTED);
173     int32_t errorCode = profile->GetDeviceState(device, state);
174     HILOGD("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
175     NAPI_BT_ASSERT_RETURN_UNDEF(env, errorCode == BT_NO_ERROR, errorCode);
176 
177     napi_value result = nullptr;
178     int32_t profileState = GetProfileConnectionState(state);
179     napi_create_int32(env, profileState, &result);
180     return result;
181 }
182 
Disconnect(napi_env env,napi_callback_info info)183 napi_value NapiPbapServer::Disconnect(napi_env env, napi_callback_info info)
184 {
185     HILOGI("enter");
186     std::string remoteAddr{};
187     bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
188     NAPI_BT_ASSERT_RETURN_FALSE(env, checkRet, BT_ERR_INVALID_PARAM);
189 
190     PbapPse *profile = PbapPse::GetProfile();
191     BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
192     int32_t errorCode = profile->Disconnect(device);
193     HILOGD("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
194     NAPI_BT_ASSERT_RETURN_FALSE(env, errorCode == BT_NO_ERROR, errorCode);
195     return NapiGetBooleanTrue(env);
196 }
197 
SetConnectionStrategy(napi_env env,napi_callback_info info)198 napi_value NapiPbapServer::SetConnectionStrategy(napi_env env, napi_callback_info info)
199 {
200     HILOGI("enter");
201     std::string remoteAddr{};
202     int32_t strategy = 0;
203     auto status = CheckSetConnectStrategyParam(env, info, remoteAddr, strategy);
204     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
205 
206     auto func = [remoteAddr, strategy]() {
207         BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR);
208         PbapPse *profile = PbapPse::GetProfile();
209         int32_t errorCode = profile->SetConnectionStrategy(remoteDevice, strategy);
210         HILOGI("err: %{public}d", errorCode);
211         return NapiAsyncWorkRet(errorCode);
212     };
213     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
214     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
215     asyncWork->Run();
216     return asyncWork->GetRet();
217 }
218 
GetConnectionStrategy(napi_env env,napi_callback_info info)219 napi_value NapiPbapServer::GetConnectionStrategy(napi_env env, napi_callback_info info)
220 {
221     HILOGI("enter");
222     std::string remoteAddr{};
223     auto status = CheckDeviceAddressParam(env, info, remoteAddr);
224     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
225 
226     auto func = [remoteAddr]() {
227         int32_t strategy = 0;
228         BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR);
229         PbapPse *profile = PbapPse::GetProfile();
230         int32_t errorCode = profile->GetConnectionStrategy(remoteDevice, strategy);
231         HILOGI("errorCode: %{public}d, deviceName: %{public}d", errorCode, strategy);
232         auto object = std::make_shared<NapiNativeInt>(strategy);
233         return NapiAsyncWorkRet(errorCode, object);
234     };
235     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
236     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
237     asyncWork->Run();
238     return asyncWork->GetRet();
239 }
240 
IsShareTypeValid(int32_t shareType)241 bool IsShareTypeValid(int32_t shareType)
242 {
243     return shareType == static_cast<int32_t>(ShareType::SHARE_NAME_AND_PHONE_NUMBER) ||
244         shareType == static_cast<int32_t>(ShareType::SHARE_ALL) ||
245         shareType == static_cast<int32_t>(ShareType::SHARE_NOTHING);
246 }
247 
CheckShareTypeParam(napi_env env,napi_callback_info info,std::string & addr,int32_t & shareType)248 napi_status CheckShareTypeParam(napi_env env, napi_callback_info info, std::string &addr, int32_t &shareType)
249 {
250     size_t argc = ARGS_SIZE_THREE;
251     napi_value argv[ARGS_SIZE_THREE] = {nullptr};
252     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
253     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO && argc != ARGS_SIZE_THREE, "Requires 2 or 3 arguments.", napi_invalid_arg);
254     NAPI_BT_CALL_RETURN(NapiParseBdAddr(env, argv[PARAM0], addr));
255     NAPI_BT_RETURN_IF(!ParseInt32(env, shareType, argv[PARAM1]), "ParseInt failed", napi_invalid_arg);
256     NAPI_BT_RETURN_IF(!IsShareTypeValid(shareType), "Invalid shareType", napi_invalid_arg);
257     return napi_ok;
258 }
259 
SetShareType(napi_env env,napi_callback_info info)260 napi_value NapiPbapServer::SetShareType(napi_env env, napi_callback_info info)
261 {
262     HILOGI("enter");
263     std::string remoteAddr{};
264     int32_t shareType = 0;
265     auto status = CheckShareTypeParam(env, info, remoteAddr, shareType);
266     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
267 
268     auto func = [remoteAddr, shareType]() {
269         BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR);
270         PbapPse *profile = PbapPse::GetProfile();
271         int32_t errorCode = profile->SetShareType(remoteDevice, shareType);
272         HILOGI("errorCode: %{public}d", errorCode);
273         return NapiAsyncWorkRet(errorCode);
274     };
275     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
276     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
277     asyncWork->Run();
278     return asyncWork->GetRet();
279 }
280 
GetShareType(napi_env env,napi_callback_info info)281 napi_value NapiPbapServer::GetShareType(napi_env env, napi_callback_info info)
282 {
283     HILOGI("enter");
284     std::string remoteAddr{};
285     auto status = CheckDeviceAddressParam(env, info, remoteAddr);
286     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
287 
288     auto func = [remoteAddr]() {
289         int32_t shareType = 0;
290         BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR);
291         PbapPse *profile = PbapPse::GetProfile();
292         int32_t errorCode = profile->GetShareType(remoteDevice, shareType);
293         HILOGI("errorCode: %{public}d, shareType: %{public}d", errorCode, shareType);
294         auto object = std::make_shared<NapiNativeInt>(shareType);
295         return NapiAsyncWorkRet(errorCode, object);
296     };
297     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
298     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
299     asyncWork->Run();
300     return asyncWork->GetRet();
301 }
302 
SetPhoneBookAccessAuthorization(napi_env env,napi_callback_info info)303 napi_value NapiPbapServer::SetPhoneBookAccessAuthorization(napi_env env, napi_callback_info info)
304 {
305     HILOGI("enter");
306     std::string remoteAddr{};
307     int32_t accessAuthorization = 0;
308     auto status = CheckAccessAuthorizationParam(env, info, remoteAddr, accessAuthorization);
309     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
310 
311     auto func = [remoteAddr, accessAuthorization]() {
312         BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR);
313         PbapPse *profile = PbapPse::GetProfile();
314         int32_t errorCode = profile->SetPhoneBookAccessAuthorization(remoteDevice, accessAuthorization);
315         HILOGI("errorCode: %{public}d", errorCode);
316         return NapiAsyncWorkRet(errorCode);
317     };
318     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
319     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
320     asyncWork->Run();
321     return asyncWork->GetRet();
322 }
323 
GetPhoneBookAccessAuthorization(napi_env env,napi_callback_info info)324 napi_value NapiPbapServer::GetPhoneBookAccessAuthorization(napi_env env, napi_callback_info info)
325 {
326     HILOGI("enter");
327     std::string remoteAddr{};
328     auto status = CheckDeviceAddressParam(env, info, remoteAddr);
329     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
330 
331     auto func = [remoteAddr]() {
332         int32_t accessAuthorization = 0;
333         BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR);
334         PbapPse *profile = PbapPse::GetProfile();
335         int32_t errorCode = profile->GetPhoneBookAccessAuthorization(remoteDevice, accessAuthorization);
336         HILOGI("errorCode: %{public}d, accessAuthorization: %{public}d", errorCode, accessAuthorization);
337         auto object = std::make_shared<NapiNativeInt>(accessAuthorization);
338         return NapiAsyncWorkRet(errorCode, object);
339     };
340     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
341     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
342     asyncWork->Run();
343     return asyncWork->GetRet();
344 }
345 
346 }  // namespace Bluetooth
347 }  // namespace OHOS