1 /*
2 * Copyright (c) 2022-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
16 #include "js_device_selection_listener.h"
17
18 #include "base/continuationmgr_log.h"
19 #include "js_runtime_utils.h"
20 #include "napi_common_util.h"
21
22 namespace OHOS {
23 namespace DistributedSchedule {
24 using namespace OHOS::AbilityRuntime;
25 namespace {
26 const std::string TAG = "JsDeviceSelectionListener";
27 }
28
OnDeviceConnect(const std::vector<ContinuationResult> & continuationResults)29 void JsDeviceSelectionListener::OnDeviceConnect(const std::vector<ContinuationResult>& continuationResults)
30 {
31 HILOGD("called.");
32 CallJsMethod(EVENT_CONNECT, continuationResults);
33 }
34
OnDeviceDisconnect(const std::vector<ContinuationResult> & continuationResults)35 void JsDeviceSelectionListener::OnDeviceDisconnect(const std::vector<ContinuationResult>& continuationResults)
36 {
37 HILOGD("called.");
38 CallJsMethod(EVENT_DISCONNECT, continuationResults);
39 }
40
AddCallback(const std::string & cbType,NativeValue * jsListenerObj)41 void JsDeviceSelectionListener::AddCallback(const std::string& cbType, NativeValue* jsListenerObj)
42 {
43 HILOGD("called.");
44 std::unique_ptr<NativeReference> callbackRef;
45 if (engine_ == nullptr) {
46 HILOGE("engine_ is nullptr");
47 return;
48 }
49 callbackRef.reset(engine_->CreateReference(jsListenerObj, 1));
50
51 std::lock_guard<std::mutex> jsCallBackMapLock(jsCallBackMapMutex_);
52 jsCallBackMap_[cbType] = std::move(callbackRef);
53 HILOGD("jsCallBackMap_ cbType: %{public}s, size: %{public}u!",
54 cbType.c_str(), static_cast<uint32_t>(jsCallBackMap_.size()));
55 }
56
RemoveCallback(const std::string & cbType)57 void JsDeviceSelectionListener::RemoveCallback(const std::string& cbType)
58 {
59 HILOGD("called.");
60 std::lock_guard<std::mutex> jsCallBackMapLock(jsCallBackMapMutex_);
61 jsCallBackMap_.erase(cbType);
62 HILOGD("jsCallBackMap_ cbType: %{public}s, size: %{public}u!",
63 cbType.c_str(), static_cast<uint32_t>(jsCallBackMap_.size()));
64 }
65
CallJsMethod(const std::string & methodName,const std::vector<ContinuationResult> & continuationResults)66 void JsDeviceSelectionListener::CallJsMethod(const std::string& methodName,
67 const std::vector<ContinuationResult>& continuationResults)
68 {
69 HILOGD("methodName = %{public}s", methodName.c_str());
70 if (engine_ == nullptr) {
71 HILOGE("engine_ is nullptr");
72 return;
73 }
74 // js callback should run in js thread
75 std::unique_ptr<AsyncTask::CompleteCallback> complete = std::make_unique<AsyncTask::CompleteCallback>
76 ([this, methodName, continuationResults]
77 (NativeEngine &engine, AsyncTask &task, int32_t status) {
78 napi_handle_scope scope = nullptr;
79 napi_open_handle_scope(reinterpret_cast<napi_env>(&engine), &scope);
80 if (scope == nullptr) {
81 return;
82 }
83
84 CallJsMethodInner(methodName, continuationResults);
85
86 napi_close_handle_scope(reinterpret_cast<napi_env>(&engine), scope);
87 });
88 NativeReference* callback = nullptr;
89 std::unique_ptr<AsyncTask::ExecuteCallback> execute = nullptr;
90 AsyncTask::Schedule("JsDeviceSelectionListener::OnDeviceConnect",
91 *engine_, std::make_unique<AsyncTask>(callback, std::move(execute), std::move(complete)));
92 }
93
CallJsMethodInner(const std::string & methodName,const std::vector<ContinuationResult> & continuationResults)94 void JsDeviceSelectionListener::CallJsMethodInner(const std::string& methodName,
95 const std::vector<ContinuationResult>& continuationResults)
96 {
97 std::lock_guard<std::mutex> jsCallBackMapLock(jsCallBackMapMutex_);
98 NativeValue* method = jsCallBackMap_[methodName]->Get();
99 if (method == nullptr) {
100 HILOGE("Failed to get %{public}s from object", methodName.c_str());
101 return;
102 }
103 NativeValue* argv[] = { WrapContinuationResultArray(*engine_, continuationResults) };
104 engine_->CallFunction(engine_->CreateUndefined(), method, argv, ArraySize(argv));
105 }
106
CallJsMethod(const std::string & methodName,const std::vector<std::string> & deviceIds)107 void JsDeviceSelectionListener::CallJsMethod(const std::string& methodName, const std::vector<std::string>& deviceIds)
108 {
109 HILOGD("methodName = %{public}s", methodName.c_str());
110 if (engine_ == nullptr) {
111 HILOGE("engine_ is nullptr");
112 return;
113 }
114 // js callback should run in js thread
115 std::unique_ptr<AsyncTask::CompleteCallback> complete = std::make_unique<AsyncTask::CompleteCallback>
116 ([this, methodName, deviceIds]
117 (NativeEngine &engine, AsyncTask &task, int32_t status) {
118 napi_handle_scope scope = nullptr;
119 napi_open_handle_scope(reinterpret_cast<napi_env>(&engine), &scope);
120 if (scope == nullptr) {
121 return;
122 }
123
124 CallJsMethodInner(methodName, deviceIds);
125
126 napi_close_handle_scope(reinterpret_cast<napi_env>(&engine), scope);
127 });
128 NativeReference* callback = nullptr;
129 std::unique_ptr<AsyncTask::ExecuteCallback> execute = nullptr;
130 AsyncTask::Schedule("JsDeviceSelectionListener::OnDeviceDisconnect",
131 *engine_, std::make_unique<AsyncTask>(callback, std::move(execute), std::move(complete)));
132 }
133
CallJsMethodInner(const std::string & methodName,const std::vector<std::string> & deviceIds)134 void JsDeviceSelectionListener::CallJsMethodInner(const std::string& methodName,
135 const std::vector<std::string>& deviceIds)
136 {
137 std::lock_guard<std::mutex> jsCallBackMapLock(jsCallBackMapMutex_);
138 NativeValue* method = jsCallBackMap_[methodName]->Get();
139 if (method == nullptr) {
140 HILOGE("Failed to get %{public}s from object", methodName.c_str());
141 return;
142 }
143 NativeValue* argv[] = { WrapDeviceIdArray(*engine_, deviceIds) };
144 engine_->CallFunction(engine_->CreateUndefined(), method, argv, ArraySize(argv));
145 }
146
WrapContinuationResult(NativeEngine & engine,const ContinuationResult & continuationResult)147 NativeValue* JsDeviceSelectionListener::WrapContinuationResult(NativeEngine& engine,
148 const ContinuationResult& continuationResult)
149 {
150 NativeValue* objValue = engine.CreateObject();
151 NativeObject* object = ConvertNativeValueTo<NativeObject>(objValue);
152 object->SetProperty("id", CreateJsValue(engine, continuationResult.GetDeviceId()));
153 object->SetProperty("type", CreateJsValue(engine, continuationResult.GetDeviceType()));
154 object->SetProperty("name", CreateJsValue(engine, continuationResult.GetDeviceName()));
155 return objValue;
156 }
157
WrapContinuationResultArray(NativeEngine & engine,const std::vector<ContinuationResult> & continuationResults)158 NativeValue* JsDeviceSelectionListener::WrapContinuationResultArray(NativeEngine& engine,
159 const std::vector<ContinuationResult>& continuationResults)
160 {
161 NativeValue* arrayValue = engine.CreateArray(continuationResults.size());
162 NativeArray* array = ConvertNativeValueTo<NativeArray>(arrayValue);
163 uint32_t index = 0;
164 for (const auto& continuationResult : continuationResults) {
165 array->SetElement(index++, WrapContinuationResult(engine, continuationResult));
166 }
167 return arrayValue;
168 }
169
WrapDeviceIdArray(NativeEngine & engine,const std::vector<std::string> & deviceIds)170 NativeValue* JsDeviceSelectionListener::WrapDeviceIdArray(NativeEngine& engine,
171 const std::vector<std::string>& deviceIds)
172 {
173 NativeValue* arrayValue = engine.CreateArray(deviceIds.size());
174 NativeArray* array = ConvertNativeValueTo<NativeArray>(arrayValue);
175 uint32_t index = 0;
176 for (const auto& deviceId : deviceIds) {
177 array->SetElement(index++, CreateJsValue(engine, deviceId));
178 }
179 return arrayValue;
180 }
181 } // namespace DistributedSchedule
182 } // namespace OHOS