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
16 #include "bridge/declarative_frontend/jsview/js_ui_extension.h"
17
18 #include <functional>
19 #include <string>
20
21 #include "base/log/ace_scoring_log.h"
22 #include "base/want/want_wrap.h"
23 #include "bridge/common/utils/engine_helper.h"
24 #include "bridge/declarative_frontend/engine/js_converter.h"
25 #include "bridge/declarative_frontend/jsview/js_utils.h"
26 #include "core/common/container_scope.h"
27 #include "core/components_ng/pattern/ui_extension/ui_extension_model.h"
28 #include "core/components_ng/pattern/ui_extension/ui_extension_model_ng.h"
29
30 namespace OHOS::Ace {
31 std::unique_ptr<UIExtensionModel> UIExtensionModel::instance_ = nullptr;
32 std::mutex UIExtensionModel::mutex_;
33
GetInstance()34 UIExtensionModel* UIExtensionModel::GetInstance()
35 {
36 if (!instance_) {
37 std::lock_guard<std::mutex> lock(mutex_);
38 if (!instance_) {
39 #ifdef NG_BUILD
40 instance_.reset(new NG::UIExtensionModelNG());
41 #else
42 if (Container::IsCurrentUseNewPipeline()) {
43 instance_.reset(new NG::UIExtensionModelNG());
44 } else {
45 return nullptr;
46 }
47 #endif
48 }
49 }
50 return instance_.get();
51 }
52 } // namespace OHOS::Ace
53
54 namespace OHOS::Ace::Framework {
JSBind(BindingTarget globalObj)55 void JSUIExtensionProxy::JSBind(BindingTarget globalObj)
56 {
57 JSClass<JSUIExtensionProxy>::Declare("UIExtensionProxy ");
58 JSClass<JSUIExtensionProxy>::CustomMethod("send", &JSUIExtensionProxy::Send);
59 JSClass<JSUIExtensionProxy>::Bind(globalObj, &JSUIExtensionProxy::Constructor, &JSUIExtensionProxy::Destructor);
60 }
61
Constructor(const JSCallbackInfo & info)62 void JSUIExtensionProxy::Constructor(const JSCallbackInfo& info)
63 {
64 auto uiExtensionProxy = Referenced::MakeRefPtr<JSUIExtensionProxy>();
65 uiExtensionProxy->IncRefCount();
66 info.SetReturnValue(Referenced::RawPtr(uiExtensionProxy));
67 }
68
Destructor(JSUIExtensionProxy * uiExtensionProxy)69 void JSUIExtensionProxy::Destructor(JSUIExtensionProxy* uiExtensionProxy)
70 {
71 if (uiExtensionProxy != nullptr) {
72 uiExtensionProxy->DecRefCount();
73 }
74 }
75
Send(const JSCallbackInfo & info)76 void JSUIExtensionProxy::Send(const JSCallbackInfo& info)
77 {
78 if (!info[0]->IsObject()) {
79 return;
80 }
81 ContainerScope scope(instanceId_);
82 auto engine = EngineHelper::GetCurrentEngine();
83 CHECK_NULL_VOID(engine);
84 NativeEngine* nativeEngine = engine->GetNativeEngine();
85 panda::Local<JsiValue> value = info[0].Get().GetLocalHandle();
86 JSValueWrapper valueWrapper = value;
87 ScopeRAII scopeRAII(nativeEngine->GetScopeManager());
88 NativeValue* nativeValue = nativeEngine->ValueToNativeValue(valueWrapper);
89 auto wantParams = WantParamsWrap::CreateWantWrap(nativeEngine, nativeValue);
90 if (proxy_) {
91 proxy_->SendData(wantParams);
92 }
93 }
94
SetInstanceId(int32_t instanceId)95 void JSUIExtensionProxy::SetInstanceId(int32_t instanceId)
96 {
97 instanceId_ = instanceId;
98 }
99
SetProxy(const RefPtr<NG::UIExtensionProxy> & proxy)100 void JSUIExtensionProxy::SetProxy(const RefPtr<NG::UIExtensionProxy>& proxy)
101 {
102 proxy_ = proxy;
103 }
104
JSBind(BindingTarget globalObj)105 void JSUIExtension::JSBind(BindingTarget globalObj)
106 {
107 JSClass<JSUIExtension>::Declare("UIExtensionComponent");
108 MethodOptions opt = MethodOptions::NONE;
109 JSClass<JSUIExtension>::StaticMethod("create", &JSUIExtension::Create, opt);
110 JSClass<JSUIExtension>::StaticMethod("onRemoteReady", &JSUIExtension::OnRemoteReady);
111 JSClass<JSUIExtension>::StaticMethod("onReceive", &JSUIExtension::OnReceive);
112 JSClass<JSUIExtension>::StaticMethod("onRelease", &JSUIExtension::OnRelease);
113 JSClass<JSUIExtension>::StaticMethod("onResult", &JSUIExtension::OnResult);
114 JSClass<JSUIExtension>::StaticMethod("onError", &JSUIExtension::OnError);
115 JSClass<JSUIExtension>::InheritAndBind<JSViewAbstract>(globalObj);
116 }
117
Create(const JSCallbackInfo & info)118 void JSUIExtension::Create(const JSCallbackInfo& info)
119 {
120 if (!info[0]->IsObject()) {
121 return;
122 }
123 auto wantObj = JSRef<JSObject>::Cast(info[0]);
124 RefPtr<OHOS::Ace::WantWrap> want = CreateWantWrapFromNapiValue(wantObj);
125 UIExtensionModel::GetInstance()->Create(want);
126 }
127
OnRemoteReady(const JSCallbackInfo & info)128 void JSUIExtension::OnRemoteReady(const JSCallbackInfo& info)
129 {
130 if (!info[0]->IsFunction()) {
131 return;
132 }
133 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
134 auto instanceId = ContainerScope::CurrentId();
135 auto onRemoteReady = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), instanceId]
136 (const RefPtr<NG::UIExtensionProxy>& session) {
137 ContainerScope scope(instanceId);
138 JSRef<JSObject> contextObj = JSClass<JSUIExtensionProxy>::NewInstance();
139 RefPtr<JSUIExtensionProxy> proxy = Referenced::Claim(contextObj->Unwrap<JSUIExtensionProxy>());
140 proxy->SetInstanceId(instanceId);
141 proxy->SetProxy(session);
142 auto returnValue = JSRef<JSVal>::Cast(contextObj);
143 func->ExecuteJS(1, &returnValue);
144 };
145 UIExtensionModel::GetInstance()->SetOnRemoteReady(std::move(onRemoteReady));
146 }
147
OnReceive(const JSCallbackInfo & info)148 void JSUIExtension::OnReceive(const JSCallbackInfo& info)
149 {
150 if (!info[0]->IsFunction()) {
151 return;
152 }
153 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
154 auto instanceId = ContainerScope::CurrentId();
155 auto onReceive = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), instanceId]
156 (const AAFwk::WantParams& wantParams) {
157 ContainerScope scope(instanceId);
158 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
159 ACE_SCORING_EVENT("UIExtensionComponent.UIExtensionDataSession.onReceive");
160 auto engine = EngineHelper::GetCurrentEngine();
161 CHECK_NULL_VOID(engine);
162 NativeEngine* nativeEngine = engine->GetNativeEngine();
163 CHECK_NULL_VOID(nativeEngine);
164 auto nativeWantParams = WantWrap::ConvertParamsToNativeValue(wantParams, nativeEngine);
165 auto wantParamsJSVal = JsConverter::ConvertNativeValueToJsVal(nativeWantParams);
166 func->ExecuteJS(1, &wantParamsJSVal);
167 };
168 UIExtensionModel::GetInstance()->SetOnReceive(std::move(onReceive));
169 }
170
OnRelease(const JSCallbackInfo & info)171 void JSUIExtension::OnRelease(const JSCallbackInfo& info)
172 {
173 if (!info[0]->IsFunction()) {
174 return;
175 }
176 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
177 auto instanceId = ContainerScope::CurrentId();
178 auto onRelease = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), instanceId](int32_t releaseCode) {
179 ContainerScope scope(instanceId);
180 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
181 ACE_SCORING_EVENT("UIExtensionComponent.onRelease");
182 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(releaseCode));
183 func->ExecuteJS(1, &newJSVal);
184 };
185 UIExtensionModel::GetInstance()->SetOnRelease(std::move(onRelease));
186 }
187
OnResult(const JSCallbackInfo & info)188 void JSUIExtension::OnResult(const JSCallbackInfo& info)
189 {
190 if (!info[0]->IsFunction()) {
191 return;
192 }
193 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
194 auto instanceId = ContainerScope::CurrentId();
195 auto onResult = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), instanceId]
196 (int32_t code, const AAFwk::Want& want) {
197 ContainerScope scope(instanceId);
198 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
199 ACE_SCORING_EVENT("UIExtensionComponent.onResult");
200 auto engine = EngineHelper::GetCurrentEngine();
201 CHECK_NULL_VOID(engine);
202 NativeEngine* nativeEngine = engine->GetNativeEngine();
203 CHECK_NULL_VOID(nativeEngine);
204 auto nativeWant = WantWrap::ConvertToNativeValue(want, nativeEngine);
205 auto wantJSVal = JsConverter::ConvertNativeValueToJsVal(nativeWant);
206 JSRef<JSObject> obj = JSRef<JSObject>::New();
207 obj->SetProperty<int32_t>("code", code);
208 obj->SetPropertyObject("want", wantJSVal);
209 auto returnValue = JSRef<JSVal>::Cast(obj);
210 func->ExecuteJS(1, &returnValue);
211 };
212 UIExtensionModel::GetInstance()->SetOnResult(std::move(onResult));
213 }
214
OnError(const JSCallbackInfo & info)215 void JSUIExtension::OnError(const JSCallbackInfo& info)
216 {
217 if (!info[0]->IsFunction()) {
218 return;
219 }
220 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
221 auto instanceId = ContainerScope::CurrentId();
222 auto onError = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), instanceId]
223 (int32_t code, const std::string& name, const std::string& message) {
224 ContainerScope scope(instanceId);
225 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
226 ACE_SCORING_EVENT("UIExtensionComponent.onError");
227 JSRef<JSObject> obj = JSRef<JSObject>::New();
228 obj->SetProperty<int32_t>("code", code);
229 obj->SetProperty<std::string>("name", name);
230 obj->SetProperty<std::string>("message", message);
231 auto returnValue = JSRef<JSVal>::Cast(obj);
232 func->ExecuteJS(1, &returnValue);
233 };
234 UIExtensionModel::GetInstance()->SetOnError(std::move(onError));
235 }
236 } // namespace OHOS::Ace::Framework
237