1 /*
2  * Copyright (C) 2022 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_pan"
17 #endif
18 
19 #include "bluetooth_log.h"
20 #include "bluetooth_pan.h"
21 #include "bluetooth_utils.h"
22 #include "napi_bluetooth_error.h"
23 #include "napi_bluetooth_pan.h"
24 #include "napi_bluetooth_pan_observer.h"
25 #include "napi_bluetooth_profile.h"
26 #include "napi_bluetooth_utils.h"
27 #include "hitrace_meter.h"
28 
29 namespace OHOS {
30 namespace Bluetooth {
31 using namespace std;
32 std::shared_ptr<NapiBluetoothPanObserver> NapiBluetoothPan::observer_ = std::make_shared<NapiBluetoothPanObserver>();
33 thread_local napi_ref NapiBluetoothPan::consRef_ = nullptr;
34 
CreatePanProfile(napi_env env,napi_callback_info info)35 napi_value NapiBluetoothPan::CreatePanProfile(napi_env env, napi_callback_info info)
36 {
37     HILOGI("enter");
38     napi_value napiProfile;
39     napi_value constructor = nullptr;
40     napi_get_reference_value(env, consRef_, &constructor);
41     napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
42     NapiProfile::SetProfile(env, ProfileId::PROFILE_PAN_NETWORK, napiProfile);
43     Pan *profile = Pan::GetProfile();
44     profile->RegisterObserver(NapiBluetoothPan::observer_);
45     HILOGI("finished");
46 
47     return napiProfile;
48 }
49 
DefinePanJSClass(napi_env env,napi_value exports)50 void NapiBluetoothPan::DefinePanJSClass(napi_env env, napi_value exports)
51 {
52     napi_value constructor;
53     napi_property_descriptor properties [] = {
54         DECLARE_NAPI_FUNCTION("on", NapiBluetoothPan::On),
55         DECLARE_NAPI_FUNCTION("off", NapiBluetoothPan::Off),
56         DECLARE_NAPI_FUNCTION("disconnect", NapiBluetoothPan::Disconnect),
57         DECLARE_NAPI_FUNCTION("setTethering", NapiBluetoothPan::SetTethering),
58         DECLARE_NAPI_FUNCTION("isTetheringOn", NapiBluetoothPan::IsTetheringOn),
59 #ifdef BLUETOOTH_API_SINCE_10
60         DECLARE_NAPI_FUNCTION("getConnectedDevices", NapiBluetoothPan::GetConnectedDevices),
61         DECLARE_NAPI_FUNCTION("getConnectionState", NapiBluetoothPan::GetConnectionState),
62         DECLARE_NAPI_FUNCTION("setConnectionStrategy", NapiBluetoothPan::SetConnectionStrategy),
63         DECLARE_NAPI_FUNCTION("getConnectionStrategy", NapiBluetoothPan::GetConnectionStrategy),
64 #else
65         DECLARE_NAPI_FUNCTION("getConnectionDevices", NapiBluetoothPan::GetConnectionDevices),
66         DECLARE_NAPI_FUNCTION("getDeviceState", NapiBluetoothPan::GetDeviceState),
67 #endif
68     };
69 
70     napi_define_class(env, "NapiBluetoothPan", NAPI_AUTO_LENGTH, NapiBluetoothPan::PanConstructor, nullptr,
71         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
72 
73 #ifdef BLUETOOTH_API_SINCE_10
74     DefineCreateProfile(env, exports);
75     napi_create_reference(env, constructor, 1, &consRef_);
76 #else
77     napi_define_class(env, "NapiBluetoothPan", NAPI_AUTO_LENGTH, PanConstructor, nullptr,
78         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
79     napi_value napiProfile;
80     napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
81     NapiProfile::SetProfile(env, ProfileId::PROFILE_PAN_NETWORK, napiProfile);
82     Pan *profile = Pan::GetProfile();
83     profile->RegisterObserver(NapiBluetoothPan::observer_);
84 #endif
85 }
86 
DefineCreateProfile(napi_env env,napi_value exports)87 napi_value NapiBluetoothPan::DefineCreateProfile(napi_env env, napi_value exports)
88 {
89     napi_property_descriptor properties [] = {
90         DECLARE_NAPI_FUNCTION("createPanProfile", NapiBluetoothPan::CreatePanProfile),
91     };
92     HITRACE_METER_NAME(HITRACE_TAG_OHOS, "pan:napi_define_properties");
93     napi_define_properties(env, exports, sizeof(properties) / sizeof(properties[0]), properties);
94     return exports;
95 }
96 
SetConnectionStrategy(napi_env env,napi_callback_info info)97 napi_value NapiBluetoothPan::SetConnectionStrategy(napi_env env, napi_callback_info info)
98 {
99     HILOGI("enter");
100     NAPI_BT_ASSERT_RETURN_UNDEF(env, false, BT_ERR_API_NOT_SUPPORT);
101     return NapiGetUndefinedRet(env);
102 }
103 
GetConnectionStrategy(napi_env env,napi_callback_info info)104 napi_value NapiBluetoothPan::GetConnectionStrategy(napi_env env, napi_callback_info info)
105 {
106     HILOGI("enter");
107     NAPI_BT_ASSERT_RETURN_UNDEF(env, false, BT_ERR_API_NOT_SUPPORT);
108     return NapiGetUndefinedRet(env);
109 }
110 
PanConstructor(napi_env env,napi_callback_info info)111 napi_value NapiBluetoothPan::PanConstructor(napi_env env, napi_callback_info info)
112 {
113     napi_value thisVar = nullptr;
114     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
115     return thisVar;
116 }
117 
On(napi_env env,napi_callback_info info)118 napi_value NapiBluetoothPan::On(napi_env env, napi_callback_info info)
119 {
120     if (observer_) {
121         auto status = observer_->eventSubscribe_.Register(env, info);
122         NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
123     }
124     return NapiGetUndefinedRet(env);
125 }
126 
Off(napi_env env,napi_callback_info info)127 napi_value NapiBluetoothPan::Off(napi_env env, napi_callback_info info)
128 {
129     if (observer_) {
130         auto status = observer_->eventSubscribe_.Deregister(env, info);
131         NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
132     }
133     return NapiGetUndefinedRet(env);
134 }
135 
GetConnectionDevices(napi_env env,napi_callback_info info)136 napi_value NapiBluetoothPan::GetConnectionDevices(napi_env env, napi_callback_info info)
137 {
138     HILOGI("enter");
139     napi_value ret = nullptr;
140     if (napi_create_array(env, &ret) != napi_ok) {
141         HILOGE("napi_create_array failed.");
142     }
143 
144     napi_status checkRet = CheckEmptyParam(env, info);
145     NAPI_BT_ASSERT_RETURN(env, checkRet == napi_ok, BT_ERR_INVALID_PARAM, ret);
146 
147     Pan *profile = Pan::GetProfile();
148     vector<int> states = { static_cast<int>(BTConnectState::CONNECTED) };
149     vector<BluetoothRemoteDevice> devices;
150     int errorCode = profile->GetDevicesByStates(states, devices);
151     HILOGI("errorCode:%{public}s, devices size:%{public}zu", GetErrorCode(errorCode).c_str(), devices.size());
152     NAPI_BT_ASSERT_RETURN(env, errorCode == BT_NO_ERROR, errorCode, ret);
153 
154     vector<string> deviceVector;
155     for (auto &device : devices) {
156         deviceVector.push_back(device.GetDeviceAddr());
157     }
158     ConvertStringVectorToJS(env, ret, deviceVector);
159     return ret;
160 }
161 
GetDeviceState(napi_env env,napi_callback_info info)162 napi_value NapiBluetoothPan::GetDeviceState(napi_env env, napi_callback_info info)
163 {
164     HILOGI("enter");
165     napi_value result = nullptr;
166     int32_t profileState = ProfileConnectionState::STATE_DISCONNECTED;
167     if (napi_create_int32(env, profileState, &result) != napi_ok) {
168         HILOGE("napi_create_int32 failed.");
169     }
170 
171     std::string remoteAddr {};
172     bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
173     NAPI_BT_ASSERT_RETURN(env, checkRet, BT_ERR_INVALID_PARAM, result);
174 
175     Pan *profile = Pan::GetProfile();
176     BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
177     int32_t state = static_cast<int32_t>(BTConnectState::DISCONNECTED);
178     int32_t errorCode = profile->GetDeviceState(device, state);
179     HILOGI("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
180     NAPI_BT_ASSERT_RETURN(env, errorCode == BT_NO_ERROR, errorCode, result);
181 
182     profileState = GetProfileConnectionState(state);
183     if (napi_create_int32(env, profileState, &result) != napi_ok) {
184         HILOGE("napi_create_int32 failed.");
185     }
186     HILOGI("profileState: %{public}d", profileState);
187     return result;
188 }
189 
GetConnectedDevices(napi_env env,napi_callback_info info)190 napi_value NapiBluetoothPan::GetConnectedDevices(napi_env env, napi_callback_info info)
191 {
192     HILOGI("enter");
193     napi_value ret = nullptr;
194     if (napi_create_array(env, &ret) != napi_ok) {
195         HILOGE("napi_create_array failed.");
196     }
197 
198     napi_status checkRet = CheckEmptyParam(env, info);
199     NAPI_BT_ASSERT_RETURN(env, checkRet == napi_ok, BT_ERR_INVALID_PARAM, ret);
200 
201     Pan *profile = Pan::GetProfile();
202     vector<int> states = { static_cast<int>(BTConnectState::CONNECTED) };
203     vector<BluetoothRemoteDevice> devices;
204     int errorCode = profile->GetDevicesByStates(states, devices);
205     HILOGI("errorCode:%{public}s, devices size:%{public}zu", GetErrorCode(errorCode).c_str(), devices.size());
206     NAPI_BT_ASSERT_RETURN(env, errorCode == BT_NO_ERROR, errorCode, ret);
207 
208     vector<string> deviceVector;
209     for (auto &device : devices) {
210         deviceVector.push_back(device.GetDeviceAddr());
211     }
212     ConvertStringVectorToJS(env, ret, deviceVector);
213     return ret;
214 }
215 
GetConnectionState(napi_env env,napi_callback_info info)216 napi_value NapiBluetoothPan::GetConnectionState(napi_env env, napi_callback_info info)
217 {
218     HILOGI("enter");
219     napi_value result = nullptr;
220     int32_t profileState = ProfileConnectionState::STATE_DISCONNECTED;
221     if (napi_create_int32(env, profileState, &result) != napi_ok) {
222         HILOGE("napi_create_int32 failed.");
223     }
224 
225     std::string remoteAddr {};
226     bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
227     NAPI_BT_ASSERT_RETURN(env, checkRet, BT_ERR_INVALID_PARAM, result);
228 
229     Pan *profile = Pan::GetProfile();
230     BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
231     int32_t state = static_cast<int32_t>(BTConnectState::DISCONNECTED);
232     int32_t errorCode = profile->GetDeviceState(device, state);
233     HILOGI("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
234     NAPI_BT_ASSERT_RETURN(env, errorCode == BT_NO_ERROR, errorCode, result);
235 
236     profileState = GetProfileConnectionState(state);
237     if (napi_create_int32(env, profileState, &result) != napi_ok) {
238         HILOGE("napi_create_int32 failed.");
239     }
240     HILOGI("profileState: %{public}d", profileState);
241     return result;
242 }
243 
Disconnect(napi_env env,napi_callback_info info)244 napi_value NapiBluetoothPan::Disconnect(napi_env env, napi_callback_info info)
245 {
246     HILOGI("enter");
247     std::string remoteAddr {};
248     bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
249     NAPI_BT_ASSERT_RETURN_FALSE(env, checkRet, BT_ERR_INVALID_PARAM);
250 
251     Pan *profile = Pan::GetProfile();
252     BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
253     int32_t errorCode = profile->Disconnect(device);
254     HILOGI("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
255     NAPI_BT_ASSERT_RETURN_FALSE(env, errorCode == BT_NO_ERROR, errorCode);
256 
257     return NapiGetBooleanTrue(env);
258 }
259 
CheckSetTetheringParam(napi_env env,napi_callback_info info,bool & out)260 static bool CheckSetTetheringParam(napi_env env, napi_callback_info info, bool &out)
261 {
262     size_t argc = ARGS_SIZE_ONE;
263     napi_value argv[ARGS_SIZE_ONE] = {nullptr};
264     NAPI_BT_RETURN_IF(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr) != napi_ok, "call failed.", false);
265     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_ONE, "Requires 1 argument.", false);
266     NAPI_BT_RETURN_IF(!ParseBool(env, out, argv[PARAM0]), "Bool expected.", false);
267     return true;
268 }
269 
SetTethering(napi_env env,napi_callback_info info)270 napi_value NapiBluetoothPan::SetTethering(napi_env env, napi_callback_info info)
271 {
272     HILOGI("enter");
273     bool value = false;
274     bool checkRet = CheckSetTetheringParam(env, info, value);
275     NAPI_BT_ASSERT_RETURN_UNDEF(env, checkRet, BT_ERR_INVALID_PARAM);
276 
277     Pan *profile = Pan::GetProfile();
278     int32_t errorCode = profile->SetTethering(value);
279     HILOGI("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
280     NAPI_BT_ASSERT_RETURN_UNDEF(env, errorCode == BT_NO_ERROR, errorCode);
281 
282     return NapiGetUndefinedRet(env);
283 }
284 
IsTetheringOn(napi_env env,napi_callback_info info)285 napi_value NapiBluetoothPan::IsTetheringOn(napi_env env, napi_callback_info info)
286 {
287     HILOGI("enter");
288     napi_status checkRet = CheckEmptyParam(env, info);
289     NAPI_BT_ASSERT_RETURN_FALSE(env, checkRet == napi_ok, BT_ERR_INVALID_PARAM);
290 
291     Pan *profile = Pan::GetProfile();
292     bool result = false;
293     int32_t errorCode = profile->IsTetheringOn(result);
294     HILOGI("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
295     NAPI_BT_ASSERT_RETURN_FALSE(env, errorCode == BT_NO_ERROR, errorCode);
296 
297     HILOGI("IsTetheringOn: %{public}d", result);
298     return NapiGetBooleanRet(env, result);
299 }
300 }  // namespace Bluetooth
301 }  // namespace OHOS