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