1 /*
2 * Copyright (c) 2023-2024 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_fill_request_callback.h"
17
18 #include "ability_manager_client.h"
19 #include "accesstoken_kit.h"
20 #include "hilog_tag_wrapper.h"
21 #include "int_wrapper.h"
22 #include "ipc_skeleton.h"
23 #include "js_auto_fill_extension_util.h"
24 #include "js_error_utils.h"
25 #include "js_runtime_utils.h"
26 #include "napi_common_util.h"
27 #include "native_engine.h"
28 #include "native_value.h"
29 #include "tokenid_kit.h"
30 #include "ui_content.h"
31 #include "view_data.h"
32 #include "want.h"
33 #include "window.h"
34
35 namespace OHOS {
36 namespace AbilityRuntime {
37 namespace {
38 constexpr int32_t INDEX_ZERO = 0;
39 constexpr size_t ARGC_ONE = 1;
40 constexpr const char *WANT_PARAMS_VIEW_DATA = "ohos.ability.params.viewData";
41 constexpr const char *WANT_PARAMS_AUTO_FILL_CMD = "ohos.ability.params.autoFillCmd";
42 constexpr const char *WANT_PARAMS_AUTO_FILL_CMD_AUTOFILL = "autofill";
43 constexpr const char *WANT_PARAMS_UPDATE_POPUP_WIDTH = "ohos.ability.params.popupWidth";
44 constexpr const char *WANT_PARAMS_UPDATE_POPUP_HEIGHT = "ohos.ability.params.popupHeight";
45 constexpr const char *WANT_PARAMS_UPDATE_POPUP_PLACEMENT = "ohos.ability.params.popupPlacement";
46 constexpr const char *CONFIG_POPUP_SIZE = "popupSize";
47 constexpr const char *CONFIG_POPUP_PLACEMENT = "placement";
48 constexpr const char *WANT_PARAMS_FILL_CONTENT = "ohos.ability.params.fillContent";
49 constexpr const char *ERROR_MSG_INVALID_EMPTY = "JsonString is empty.";
50 constexpr const char *ERROR_MSG_VIEWDATA_INVALID = "The type of storeld, must be ViewData.";
51 constexpr const char *ERROR_MSG_AUTOFILLPOPUPCONFIG_INVALID =
52 "The type of storeld, must be AutoFillPopupConfig.";
53 constexpr const char *ERROR_MSG_PARAMETER_INVALID =
54 "The storeld can consist of only letters, digits, and underscores(_), and cannot exceed 128 characters.";
55 } // namespace
56
JsFillRequestCallback(const sptr<AAFwk::SessionInfo> & sessionInfo,const sptr<Rosen::Window> & uiWindow)57 JsFillRequestCallback::JsFillRequestCallback(
58 const sptr<AAFwk::SessionInfo> &sessionInfo, const sptr<Rosen::Window> &uiWindow)
59 : sessionInfo_(sessionInfo), uiWindow_(uiWindow)
60 {}
61
Finalizer(napi_env env,void * data,void * hint)62 void JsFillRequestCallback::Finalizer(napi_env env, void* data, void *hint)
63 {
64 TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
65 std::unique_ptr<JsFillRequestCallback>(static_cast<JsFillRequestCallback*>(data));
66 }
67
FillRequestSuccess(napi_env env,napi_callback_info info)68 napi_value JsFillRequestCallback::FillRequestSuccess(napi_env env, napi_callback_info info)
69 {
70 GET_NAPI_INFO_AND_CALL(env, info, JsFillRequestCallback, OnFillRequestSuccess);
71 }
72
FillRequestFailed(napi_env env,napi_callback_info info)73 napi_value JsFillRequestCallback::FillRequestFailed(napi_env env, napi_callback_info info)
74 {
75 GET_NAPI_INFO_AND_CALL(env, info, JsFillRequestCallback, OnFillRequestFailed);
76 }
77
FillRequestCanceled(napi_env env,napi_callback_info info)78 napi_value JsFillRequestCallback::FillRequestCanceled(napi_env env, napi_callback_info info)
79 {
80 GET_NAPI_INFO_AND_CALL(env, info, JsFillRequestCallback, OnFillRequestCanceled);
81 }
82
FillRequestAutoFillPopupConfig(napi_env env,napi_callback_info info)83 napi_value JsFillRequestCallback::FillRequestAutoFillPopupConfig(napi_env env, napi_callback_info info)
84 {
85 GET_NAPI_INFO_AND_CALL(env, info, JsFillRequestCallback, OnFillRequestAutoFillPopupConfig);
86 }
87
OnFillRequestSuccess(napi_env env,NapiCallbackInfo & info)88 napi_value JsFillRequestCallback::OnFillRequestSuccess(napi_env env, NapiCallbackInfo &info)
89 {
90 TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
91 if (info.argc < ARGC_ONE || !IsTypeForNapiValue(env, info.argv[INDEX_ZERO], napi_object)) {
92 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "parse viewData failed");
93 ThrowError(env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), ERROR_MSG_VIEWDATA_INVALID);
94 SendResultCodeAndViewData(
95 JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED_INVALID_PARAM, "");
96 return CreateJsUndefined(env);
97 }
98
99 FillResponse response;
100 JsAutoFillExtensionUtil::UnwrapFillResponse(env, info.argv[INDEX_ZERO], response);
101 std::string jsonString = response.viewData.ToJsonString();
102 if (jsonString.empty()) {
103 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "empty jsonString");
104 ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
105 SendResultCodeAndViewData(
106 JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED_INVALID_PARAM, "");
107 return CreateJsUndefined(env);
108 }
109
110 SendResultCodeAndViewData(JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_SUCESS, jsonString);
111 return CreateJsUndefined(env);
112 }
113
OnFillRequestFailed(napi_env env,NapiCallbackInfo & info)114 napi_value JsFillRequestCallback::OnFillRequestFailed(napi_env env, NapiCallbackInfo &info)
115 {
116 TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
117 SendResultCodeAndViewData(JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED, "");
118 return CreateJsUndefined(env);
119 }
120
OnFillRequestCanceled(napi_env env,NapiCallbackInfo & info)121 napi_value JsFillRequestCallback::OnFillRequestCanceled(napi_env env, NapiCallbackInfo &info)
122 {
123 TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
124 if (info.argc < ARGC_ONE) {
125 SendResultCodeAndViewData(JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_CANCEL, "");
126 return CreateJsUndefined(env);
127 }
128 if (!IsTypeForNapiValue(env, info.argv[INDEX_ZERO], napi_string)) {
129 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "parse fillContent failed");
130 ThrowError(env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), ERROR_MSG_PARAMETER_INVALID);
131 SendResultCodeAndViewData(
132 JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED_INVALID_PARAM, "");
133 return CreateJsUndefined(env);
134 }
135 std::string jsonString = UnwrapStringFromJS(env, info.argv[INDEX_ZERO], "");
136 if (jsonString.empty()) {
137 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "empty jsonString");
138 ThrowError(env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), ERROR_MSG_INVALID_EMPTY);
139 SendResultCodeAndViewData(
140 JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_FAILED_INVALID_PARAM, "");
141 return CreateJsUndefined(env);
142 }
143 SendResultCodeAndViewData(JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_CANCEL, jsonString);
144 return CreateJsUndefined(env);
145 }
146
OnFillRequestAutoFillPopupConfig(napi_env env,NapiCallbackInfo & info)147 napi_value JsFillRequestCallback::OnFillRequestAutoFillPopupConfig(napi_env env, NapiCallbackInfo &info)
148 {
149 TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
150 auto selfToken = IPCSkeleton::GetSelfTokenID();
151 if (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken)) {
152 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Non-system app forbidden to call");
153 ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
154 return CreateJsUndefined(env);
155 }
156 if (uiWindow_ == nullptr) {
157 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null uiWindow");
158 ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
159 return CreateJsUndefined(env);
160 }
161
162 if (info.argc < ARGC_ONE || !IsTypeForNapiValue(env, info.argv[INDEX_ZERO], napi_object)) {
163 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "parse resize failed");
164 ThrowError(env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM),
165 ERROR_MSG_AUTOFILLPOPUPCONFIG_INVALID);
166 return CreateJsUndefined(env);
167 }
168 AAFwk::WantParams wantParams;
169 wantParams.SetParam(WANT_PARAMS_AUTO_FILL_CMD, AAFwk::Integer::Box(AutoFillCommand::RESIZE));
170 auto isValueChanged = SetPopupConfigToWantParams(env, info, wantParams);
171 if (isValueChanged) {
172 auto ret = uiWindow_->TransferExtensionData(wantParams);
173 if (ret != Rosen::WMError::WM_OK) {
174 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Transfer ability result failed");
175 ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
176 }
177 }
178 return CreateJsUndefined(env);
179 }
180
SetPopupConfigToWantParams(napi_env env,NapiCallbackInfo & info,AAFwk::WantParams & wantParams)181 bool JsFillRequestCallback::SetPopupConfigToWantParams(
182 napi_env env, NapiCallbackInfo& info, AAFwk::WantParams& wantParams)
183 {
184 napi_value jsValue = nullptr;
185 bool isValueChanged = false;
186 jsValue = GetPropertyValueByPropertyName(env, info.argv[INDEX_ZERO], CONFIG_POPUP_SIZE, napi_object);
187 if (jsValue) {
188 PopupSize popupSize;
189 JsAutoFillExtensionUtil::UnwrapPopupSize(env, jsValue, popupSize);
190 wantParams.SetParam(WANT_PARAMS_UPDATE_POPUP_WIDTH, AAFwk::Integer::Box(popupSize.width));
191 wantParams.SetParam(WANT_PARAMS_UPDATE_POPUP_HEIGHT, AAFwk::Integer::Box(popupSize.height));
192 isValueChanged = true;
193 }
194
195 jsValue = nullptr;
196 jsValue = GetPropertyValueByPropertyName(env, info.argv[INDEX_ZERO], CONFIG_POPUP_PLACEMENT, napi_number);
197 if (jsValue) {
198 int popupPlacement = 0;
199 napi_get_value_int32(env, jsValue, &popupPlacement);
200 wantParams.SetParam(WANT_PARAMS_UPDATE_POPUP_PLACEMENT, AAFwk::Integer::Box(popupPlacement));
201 isValueChanged = true;
202 }
203 return isValueChanged;
204 }
205
SendResultCodeAndViewData(const JsAutoFillExtensionUtil::AutoFillResultCode & resultCode,const std::string & jsString)206 void JsFillRequestCallback::SendResultCodeAndViewData(
207 const JsAutoFillExtensionUtil::AutoFillResultCode &resultCode, const std::string &jsString)
208 {
209 TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
210 if (uiWindow_ == nullptr) {
211 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null uiWindow");
212 return;
213 }
214
215 AAFwk::Want want;
216 if (resultCode == JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_SUCESS) {
217 want.SetParam(WANT_PARAMS_VIEW_DATA, jsString);
218 want.SetParam(WANT_PARAMS_AUTO_FILL_CMD, WANT_PARAMS_AUTO_FILL_CMD_AUTOFILL);
219 }
220
221 if (resultCode == JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_CANCEL) {
222 want.SetParam(WANT_PARAMS_FILL_CONTENT, jsString);
223 }
224
225 auto ret = uiWindow_->TransferAbilityResult(resultCode, want);
226 if (ret != Rosen::WMError::WM_OK) {
227 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "TransferAbilityResult failed");
228 return;
229 }
230
231 auto errorCode = AAFwk::AbilityManagerClient::GetInstance()->TerminateUIExtensionAbility(sessionInfo_);
232 if (errorCode != ERR_OK) {
233 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "TerminateUIExtensionAbility error: %{public}d", errorCode);
234 }
235 }
236
CreateJsFillRequestCallback(napi_env env,const sptr<AAFwk::SessionInfo> & sessionInfo,const sptr<Rosen::Window> & uiWindow)237 napi_value JsFillRequestCallback::CreateJsFillRequestCallback(napi_env env,
238 const sptr<AAFwk::SessionInfo> &sessionInfo, const sptr<Rosen::Window> &uiWindow)
239 {
240 TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
241 napi_value object = nullptr;
242 napi_create_object(env, &object);
243 if (object == nullptr) {
244 TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null object");
245 return CreateJsUndefined(env);
246 }
247
248 std::unique_ptr<JsFillRequestCallback> jsSession =
249 std::make_unique<JsFillRequestCallback>(sessionInfo, uiWindow);
250 napi_wrap(env, object, jsSession.release(), Finalizer, nullptr, nullptr);
251
252 const char *moduleName = "JsFillRequestCallback";
253 BindNativeFunction(env, object, "onSuccess", moduleName, FillRequestSuccess);
254 BindNativeFunction(env, object, "onFailure", moduleName, FillRequestFailed);
255 BindNativeFunction(env, object, "onCancel", moduleName, FillRequestCanceled);
256 BindNativeFunction(env, object, "setAutoFillPopupConfig", moduleName, FillRequestAutoFillPopupConfig);
257 return object;
258 }
259 } // namespace AbilityRuntime
260 } // namespace OHOS