1 /*
2 * Copyright (c) 2025 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_ability_vertical_panel.h"
17
18 #include "hilog_tag_wrapper.h"
19 #include "ipc_skeleton.h"
20 #include "js_panel_start_callback.h"
21 #include "js_error_utils.h"
22 #include "js_runtime_utils.h"
23 #include "napi_base_context.h"
24 #include "napi_common_util.h"
25 #include "napi_common_want.h"
26 #include "native_engine/native_value.h"
27 #include "screen_config.h"
28 #include "start_vertical_panel.h"
29 #include "tokenid_kit.h"
30
31 namespace OHOS {
32 namespace AbilityRuntime {
33 constexpr int32_t INDEX_ZERO = 0;
34 constexpr int32_t INDEX_ONE = 1;
35 constexpr int32_t INDEX_TWO = 2;
36 constexpr int32_t INDEX_THREE = 3;
37 constexpr size_t ARGC_FOUR = 4;
38
SetNamedProperty(napi_env env,napi_value dstObj,const char * objName,const char * propName)39 static void SetNamedProperty(napi_env env, napi_value dstObj, const char *objName, const char *propName)
40 {
41 TAG_LOGD(AAFwkTag::VERTICAL_PANEL, "SetNamedProperty called");
42 napi_value prop = nullptr;
43 napi_create_string_utf8(env, objName, NAPI_AUTO_LENGTH, &prop);
44 napi_set_named_property(env, dstObj, propName, prop);
45 }
46
47 class JsAbilityVerticalPanel {
48 public:
49 JsAbilityVerticalPanel() = default;
50 ~JsAbilityVerticalPanel() = default;
51
Finalizer(napi_env env,void * data,void * hint)52 static void Finalizer(napi_env env, void *data, void *hint)
53 {
54 TAG_LOGI(AAFwkTag::VERTICAL_PANEL, "finalizer");
55 std::unique_ptr<JsAbilityVerticalPanel>(static_cast<JsAbilityVerticalPanel*>(data));
56 }
57
StartVerticalPanel(napi_env env,napi_callback_info info)58 static napi_value StartVerticalPanel(napi_env env, napi_callback_info info)
59 {
60 GET_NAPI_INFO_AND_CALL(env, info, JsAbilityVerticalPanel, OnStartVerticalPanel);
61 }
62
63 private:
GetContext(napi_env env,napi_value value,std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> & abilityContext)64 static bool GetContext(napi_env env, napi_value value,
65 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> &abilityContext)
66 {
67 bool stageMode = false;
68 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
69 if (status != napi_ok || !stageMode) {
70 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "Get context It is not a stage mode");
71 return false;
72 }
73
74 auto context = AbilityRuntime::GetStageModeContext(env, value);
75 if (context == nullptr) {
76 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "Get context GetStageModeContext failed");
77 return false;
78 }
79
80 abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
81 if (abilityContext == nullptr || abilityContext->GetApplicationInfo() == nullptr) {
82 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "Get context failed");
83 return false;
84 }
85
86 return true;
87 }
88
UnwrapScreenConfig(napi_env env,napi_value param,AAFwk::ScreenConfig & screenConfig)89 static bool UnwrapScreenConfig(napi_env env, napi_value param, AAFwk::ScreenConfig &screenConfig)
90 {
91 if (!AppExecFwk::IsTypeForNapiValue(env, param, napi_object)) {
92 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "UnwrapScreenConfig param IsTypeForNapiValue failed");
93 return false;
94 }
95
96 napi_value type = nullptr;
97 napi_get_named_property(env, param, "type", &type);
98 if (type == nullptr || !ConvertFromJsValue(env, type, screenConfig.type)) {
99 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "parse UnwrapScreenConfig failed: type");
100 return false;
101 }
102
103 napi_value sourceAppInfo = nullptr;
104 napi_get_named_property(env, param, "sourceAppInfo", &sourceAppInfo);
105 if (sourceAppInfo == nullptr || !AppExecFwk::IsTypeForNapiValue(env, sourceAppInfo, napi_object)) {
106 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "parse UnwrapScreenConfig failed: sourceAppInfo");
107 return false;
108 }
109
110 napi_valuetype jsValueType = napi_undefined;
111 napi_value jsProNameList = nullptr;
112 uint32_t jsProCount = 0;
113
114 NAPI_CALL_BASE(env, napi_get_property_names(env, sourceAppInfo, &jsProNameList), false);
115 NAPI_CALL_BASE(env, napi_get_array_length(env, jsProNameList, &jsProCount), false);
116
117 napi_value jsProName = nullptr;
118 napi_value jsProValue = nullptr;
119 for (uint32_t index = 0; index < jsProCount; index++) {
120 NAPI_CALL_BASE(env, napi_get_element(env, jsProNameList, index, &jsProName), false);
121
122 std::string strProName = AppExecFwk::UnwrapStringFromJS(env, jsProName);
123 TAG_LOGD(AAFwkTag::VERTICAL_PANEL, "property name=%{public}s", strProName.c_str());
124 NAPI_CALL_BASE(env, napi_get_named_property(env, sourceAppInfo, strProName.c_str(), &jsProValue), false);
125 NAPI_CALL_BASE(env, napi_typeof(env, jsProValue, &jsValueType), false);
126
127 std::string natValue = AppExecFwk::UnwrapStringFromJS(env, jsProValue);
128 screenConfig.sourceAppInfo[strProName] = natValue;
129 }
130 return true;
131 }
132
ExecuteStartVerticalPanel(napi_env env,std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext,const AAFwk::WantParams & wantParam,const AAFwk::ScreenConfig & screenConfig,std::shared_ptr<JsPanelStartCallback> callback)133 napi_value ExecuteStartVerticalPanel(napi_env env,
134 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext,
135 const AAFwk::WantParams &wantParam,
136 const AAFwk::ScreenConfig &screenConfig,
137 std::shared_ptr<JsPanelStartCallback> callback)
138 {
139 auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
140 NapiAsyncTask::ExecuteCallback execute =
141 [abilityContext, wantParamCopy = wantParam, screenConfig, callback, innerErrCode]() mutable {
142 #ifdef SUPPORT_SCREEN
143 *innerErrCode = OHOS::AbilityRuntime::StartVerticalPanel(
144 abilityContext, wantParamCopy, screenConfig, callback);
145 #endif
146 };
147 NapiAsyncTask::CompleteCallback complete =
148 [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
149 if (*innerErrCode == ERR_OK) {
150 task.ResolveWithNoError(env, CreateJsUndefined(env));
151 } else {
152 task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
153 }
154 };
155 napi_value result = nullptr;
156 NapiAsyncTask::ScheduleHighQos("JsAbilityVerticalPanel::OnStartVerticalPanel",
157 env, CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result));
158 return result;
159 }
160
OnStartVerticalPanel(napi_env env,NapiCallbackInfo & info)161 napi_value OnStartVerticalPanel(napi_env env, NapiCallbackInfo &info)
162 {
163 TAG_LOGD(AAFwkTag::VERTICAL_PANEL, "OnStartVerticalPanel call");
164
165 auto selfToken = IPCSkeleton::GetSelfTokenID();
166 if (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken)) {
167 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "This application is not system-app,"
168 "can not use system-api");
169 ThrowNotSystemAppError(env);
170 return CreateJsUndefined(env);
171 }
172
173 if (info.argc < ARGC_FOUR) {
174 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "OnStartVerticalPanel invalid params");
175 ThrowTooFewParametersError(env);
176 return CreateJsUndefined(env);
177 }
178
179 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext;
180 if (!GetContext(env, info.argv[INDEX_ZERO], abilityContext)) {
181 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "OnStartVerticalPanel parse context failed");
182 ThrowInvalidParamError(env, "Parse param context failed, context must be UIAbilityContext.");
183 return CreateJsUndefined(env);
184 }
185
186 AAFwk::WantParams wantParam;
187 if (!AppExecFwk::UnwrapWantParams(env, info.argv[INDEX_ONE], wantParam)) {
188 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "OnStartVerticalPanel parse wantParam failed");
189 ThrowInvalidParamError(env, "Parse param want failed, want must be Want.");
190 return CreateJsUndefined(env);
191 }
192
193 AAFwk::ScreenConfig screenConfig;
194 if (!UnwrapScreenConfig(env, info.argv[INDEX_TWO], screenConfig)) {
195 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "OnStartVerticalPanel parse screenConfig failed");
196 ThrowInvalidParamError(env, "Parse param screenConfig failed, screenConfig must be ScreenConfig.");
197 return CreateJsUndefined(env);
198 }
199
200 std::shared_ptr<JsPanelStartCallback> callback = std::make_shared<JsPanelStartCallback>(env);
201 callback->SetJsCallbackObject(info.argv[INDEX_THREE]);
202 return ExecuteStartVerticalPanel(env, abilityContext, wantParam, screenConfig, callback);
203 }
204 };
205
JsAbilityVerticalPanelInit(napi_env env,napi_value exportObj)206 napi_value JsAbilityVerticalPanelInit(napi_env env, napi_value exportObj)
207 {
208 if (env == nullptr || exportObj == nullptr) {
209 TAG_LOGE(AAFwkTag::VERTICAL_PANEL, "null env or exportObj");
210 return nullptr;
211 }
212
213 napi_value verticalType = nullptr;
214 napi_create_object(env, &verticalType);
215 SetNamedProperty(env, verticalType, "navigation", "NAVIGATION");
216
217 napi_value bundleName = nullptr;
218 napi_create_string_utf8(env, "bundleName", NAPI_AUTO_LENGTH, &bundleName);
219 napi_value moduleNameProp = nullptr;
220 napi_create_string_utf8(env, "moduleName", NAPI_AUTO_LENGTH, &moduleNameProp);
221 napi_value abilityName = nullptr;
222 napi_create_string_utf8(env, "abilityName", NAPI_AUTO_LENGTH, &abilityName);
223 napi_value windowId = nullptr;
224 napi_create_string_utf8(env, "windowId", NAPI_AUTO_LENGTH, &windowId);
225 napi_value screenMode = nullptr;
226 napi_create_string_utf8(env, "screenMode", NAPI_AUTO_LENGTH, &screenMode);
227
228 napi_property_descriptor exportFuncs[] = {
229 DECLARE_NAPI_PROPERTY("VerticalType", verticalType),
230 DECLARE_NAPI_PROPERTY("SOURCE_APP_BUNDLE_NAME", bundleName),
231 DECLARE_NAPI_PROPERTY("SOURCE_APP_MODULE_NAME", moduleNameProp),
232 DECLARE_NAPI_PROPERTY("SOURCE_APP_ABILITY_NAME", abilityName),
233 DECLARE_NAPI_PROPERTY("SOURCE_APP_WINDOW_ID", windowId),
234 DECLARE_NAPI_PROPERTY("SOURCE_APP_SCREEN_MODE", screenMode),
235 };
236 napi_define_properties(env, exportObj, sizeof(exportFuncs) / sizeof(*exportFuncs), exportFuncs);
237
238 auto jsAbilityVerticalPanel = std::make_unique<JsAbilityVerticalPanel>();
239 napi_wrap(env, exportObj, jsAbilityVerticalPanel.release(),
240 JsAbilityVerticalPanel::Finalizer, nullptr, nullptr);
241
242 const char *moduleName = "JsAbilityVerticalPanel";
243 BindNativeFunction(env, exportObj, "startVerticalPanel", moduleName, JsAbilityVerticalPanel::StartVerticalPanel);
244 TAG_LOGD(AAFwkTag::VERTICAL_PANEL, "end");
245 return CreateJsUndefined(env);
246 }
247 } // namespace AbilityRuntime
248 } // namespace OHOS