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_hid_host"
17 #endif
18 
19 #include "bluetooth_hid_host.h"
20 
21 #include "bluetooth_log.h"
22 #include "bluetooth_utils.h"
23 #include "napi_async_work.h"
24 #include "napi_bluetooth_hid_host_observer.h"
25 #include "napi_bluetooth_error.h"
26 #include "napi_bluetooth_utils.h"
27 #include "napi_bluetooth_profile.h"
28 #include "napi_bluetooth_hid_host.h"
29 #include "hitrace_meter.h"
30 
31 namespace OHOS {
32 namespace Bluetooth {
33 using namespace std;
34 std::shared_ptr<NapiBluetoothHidHostObserver> NapiBluetoothHidHost::observer_ =
35     std::make_shared<NapiBluetoothHidHostObserver>();
36 thread_local napi_ref NapiBluetoothHidHost::consRef_ = nullptr;
37 
DefineHidHostJSClass(napi_env env,napi_value exports)38 void NapiBluetoothHidHost::DefineHidHostJSClass(napi_env env, napi_value exports)
39 {
40     napi_value constructor;
41     napi_property_descriptor properties[] = {
42         DECLARE_NAPI_FUNCTION("on", On),
43         DECLARE_NAPI_FUNCTION("off", Off),
44 #ifdef BLUETOOTH_API_SINCE_10
45         DECLARE_NAPI_FUNCTION("getConnectedDevices", GetConnectionDevices),
46         DECLARE_NAPI_FUNCTION("getConnectionState", GetDeviceState),
47 #else
48         DECLARE_NAPI_FUNCTION("getConnectionDevices", GetConnectionDevices),
49         DECLARE_NAPI_FUNCTION("getDeviceState", GetDeviceState),
50 #endif
51         DECLARE_NAPI_FUNCTION("connect", Connect),
52         DECLARE_NAPI_FUNCTION("disconnect", Disconnect),
53         DECLARE_NAPI_FUNCTION("setConnectionStrategy", SetConnectionStrategy),
54         DECLARE_NAPI_FUNCTION("getConnectionStrategy", GetConnectionStrategy),
55     };
56 
57     napi_define_class(env, "NapiBluetoothHidHost", NAPI_AUTO_LENGTH, HidHostConstructor, nullptr,
58         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
59 #ifdef BLUETOOTH_API_SINCE_10
60     DefineCreateProfile(env, exports);
61     napi_create_reference(env, constructor, 1, &consRef_);
62 #else
63     napi_value napiProfile;
64     napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
65     NapiProfile::SetProfile(env, ProfileId::PROFILE_HID_HOST, napiProfile);
66     HidHost *profile = HidHost::GetProfile();
67     profile->RegisterObserver(observer_);
68 #endif
69 }
70 
DefineCreateProfile(napi_env env,napi_value exports)71 napi_value NapiBluetoothHidHost::DefineCreateProfile(napi_env env, napi_value exports)
72 {
73     napi_property_descriptor properties[] = {
74         DECLARE_NAPI_FUNCTION("createHidHostProfile", CreateHidHostProfile),
75     };
76     HITRACE_METER_NAME(HITRACE_TAG_OHOS, "hid:napi_define_properties");
77     napi_define_properties(env, exports, sizeof(properties) / sizeof(properties[0]), properties);
78     return exports;
79 }
80 
CreateHidHostProfile(napi_env env,napi_callback_info info)81 napi_value NapiBluetoothHidHost::CreateHidHostProfile(napi_env env, napi_callback_info info)
82 {
83     HILOGI("enter");
84     napi_value napiProfile;
85     napi_value constructor = nullptr;
86     napi_get_reference_value(env, consRef_, &constructor);
87     napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
88     NapiProfile::SetProfile(env, ProfileId::PROFILE_HID_HOST, napiProfile);
89 
90     HidHost *profile = HidHost::GetProfile();
91     profile->RegisterObserver(observer_);
92 
93     return napiProfile;
94 }
95 
96 
HidHostConstructor(napi_env env,napi_callback_info info)97 napi_value NapiBluetoothHidHost::HidHostConstructor(napi_env env, napi_callback_info info)
98 {
99     napi_value thisVar = nullptr;
100     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
101     return thisVar;
102 }
103 
On(napi_env env,napi_callback_info info)104 napi_value NapiBluetoothHidHost::On(napi_env env, napi_callback_info info)
105 {
106     if (observer_) {
107         auto status = observer_->eventSubscribe_.Register(env, info);
108         NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
109     }
110     return NapiGetUndefinedRet(env);
111 }
112 
Off(napi_env env,napi_callback_info info)113 napi_value NapiBluetoothHidHost::Off(napi_env env, napi_callback_info info)
114 {
115     if (observer_) {
116         auto status = observer_->eventSubscribe_.Deregister(env, info);
117         NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
118     }
119     return NapiGetUndefinedRet(env);
120 }
121 
GetConnectionDevices(napi_env env,napi_callback_info info)122 napi_value NapiBluetoothHidHost::GetConnectionDevices(napi_env env, napi_callback_info info)
123 {
124     HILOGI("enter");
125 
126     napi_value ret = nullptr;
127     if (napi_create_array(env, &ret) != napi_ok) {
128         HILOGE("napi_create_array failed.");
129     }
130     napi_status checkRet = CheckEmptyParam(env, info);
131     NAPI_BT_ASSERT_RETURN(env, checkRet == napi_ok, BT_ERR_INVALID_PARAM, ret);
132 
133     HidHost *profile = HidHost::GetProfile();
134     vector<int> states = { static_cast<int>(BTConnectState::CONNECTED) };
135     vector<BluetoothRemoteDevice> devices;
136     int errorCode = profile->GetDevicesByStates(states, devices);
137     HILOGI("errorCode:%{public}s, devices size:%{public}zu", GetErrorCode(errorCode).c_str(), devices.size());
138     NAPI_BT_ASSERT_RETURN(env, errorCode == BT_NO_ERROR, errorCode, ret);
139 
140     vector<string> deviceVector;
141     for (auto &device: devices) {
142         deviceVector.push_back(device.GetDeviceAddr());
143     }
144     ConvertStringVectorToJS(env, ret, deviceVector);
145     return ret;
146 }
147 
GetDeviceState(napi_env env,napi_callback_info info)148 napi_value NapiBluetoothHidHost::GetDeviceState(napi_env env, napi_callback_info info)
149 {
150     napi_value result = nullptr;
151     int32_t profileState = ProfileConnectionState::STATE_DISCONNECTED;
152     if (napi_create_int32(env, profileState, &result) != napi_ok) {
153         HILOGE("napi_create_int32 failed.");
154     }
155 
156     std::string remoteAddr {};
157     bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
158     NAPI_BT_ASSERT_RETURN(env, checkRet, BT_ERR_INVALID_PARAM, result);
159 
160     HidHost *profile = HidHost::GetProfile();
161     BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
162     int32_t state = static_cast<int32_t>(BTConnectState::DISCONNECTED);
163     int32_t errorCode = profile->GetDeviceState(device, state);
164     NAPI_BT_ASSERT_RETURN(env, errorCode == BT_NO_ERROR, errorCode, result);
165 
166     profileState = GetProfileConnectionState(state);
167     if (napi_create_int32(env, profileState, &result) != napi_ok) {
168         HILOGE("napi_create_int32 failed.");
169     }
170     return result;
171 }
172 
Connect(napi_env env,napi_callback_info info)173 napi_value NapiBluetoothHidHost::Connect(napi_env env, napi_callback_info info)
174 {
175     HILOGI("enter");
176     std::string remoteAddr {};
177     bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
178     NAPI_BT_ASSERT_RETURN_FALSE(env, checkRet, BT_ERR_INVALID_PARAM);
179 
180     HidHost *profile = HidHost::GetProfile();
181     BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
182     int32_t errorCode = profile->Connect(device);
183     HILOGI("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
184     NAPI_BT_ASSERT_RETURN_FALSE(env, errorCode == BT_NO_ERROR, errorCode);
185     return NapiGetBooleanTrue(env);
186 }
187 
Disconnect(napi_env env,napi_callback_info info)188 napi_value NapiBluetoothHidHost::Disconnect(napi_env env, napi_callback_info info)
189 {
190     HILOGI("Disconnect called");
191     std::string remoteAddr {};
192     bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
193     NAPI_BT_ASSERT_RETURN_FALSE(env, checkRet, BT_ERR_INVALID_PARAM);
194 
195     HidHost *profile = HidHost::GetProfile();
196     BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
197     int32_t errorCode = profile->Disconnect(device);
198     HILOGI("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
199     NAPI_BT_ASSERT_RETURN_FALSE(env, errorCode == BT_NO_ERROR, errorCode);
200     return NapiGetBooleanTrue(env);
201 }
202 
SetConnectionStrategy(napi_env env,napi_callback_info info)203 napi_value NapiBluetoothHidHost::SetConnectionStrategy(napi_env env, napi_callback_info info)
204 {
205     HILOGD("start");
206     std::string remoteAddr {};
207     int32_t strategy = 0;
208     auto status = CheckSetConnectStrategyParam(env, info, remoteAddr, strategy);
209     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
210 
211     auto func = [remoteAddr, strategy]() {
212         BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR);
213         HidHost *profile = HidHost::GetProfile();
214         int32_t err = profile->SetConnectStrategy(remoteDevice, strategy);
215         HILOGI("err: %{public}d", err);
216         return NapiAsyncWorkRet(err);
217     };
218     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
219     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
220     asyncWork->Run();
221     return asyncWork->GetRet();
222 }
223 
GetConnectionStrategy(napi_env env,napi_callback_info info)224 napi_value NapiBluetoothHidHost::GetConnectionStrategy(napi_env env, napi_callback_info info)
225 {
226     HILOGD("start");
227     std::string remoteAddr {};
228     auto status = CheckDeviceAddressParam(env, info, remoteAddr);
229     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
230 
231     auto func = [remoteAddr]() {
232         int strategy = 0;
233         BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR);
234         HidHost *profile = HidHost::GetProfile();
235         int32_t err = profile->GetConnectStrategy(remoteDevice, strategy);
236         HILOGI("err: %{public}d, deviceName: %{public}d", err, strategy);
237         auto object = std::make_shared<NapiNativeInt>(strategy);
238         return NapiAsyncWorkRet(err, object);
239     };
240     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
241     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
242     asyncWork->Run();
243     return asyncWork->GetRet();
244 }
245 }  // namespace Bluetooth
246 }  // namespace OHOS