• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_ui_appearance.h"
17 
18 #include "ui_appearance_log.h"
19 
20 namespace OHOS {
21 namespace ArkUi::UiAppearance {
22 namespace {
23 static constexpr size_t ARGC_WITH_ONE = 1;
24 static constexpr size_t ARGC_WITH_TWO = 2;
25 const std::string PERMISSION_ERR_MSG =
26     "An attempt was made to update configuration forbidden by permission: ohos.permission.UPDATE_CONFIGURATION.";
27 const std::string INVALID_ARG_MSG = "The type of 'mode' must be DarkMode.";
28 
29 static const std::unordered_map<int32_t, std::string> ERROR_CODE_TO_MSG {
30     { UiAppearanceAbilityInterface::ErrCode::PERMISSION_ERR, "Permission denied. " },
31     { UiAppearanceAbilityInterface::ErrCode::INVALID_ARG, "Parameter error. " },
32     { UiAppearanceAbilityInterface::ErrCode::SYS_ERR, "Internal error. " },
33 };
34 
NapiThrow(napi_env env,const std::string & message,int32_t errCode)35 void NapiThrow(napi_env env, const std::string& message, int32_t errCode)
36 {
37     napi_value code = nullptr;
38     std::string strCode = std::to_string(errCode);
39     napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
40 
41     napi_value msg = nullptr;
42     auto iter = ERROR_CODE_TO_MSG.find(errCode);
43     std::string strMsg = (iter != ERROR_CODE_TO_MSG.end() ? iter->second : "") + message;
44     JS_HILOG_INFO("napi throw errCode %{public}d, strMsg %{public}s", errCode, strMsg.c_str());
45     napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
46 
47     napi_value error = nullptr;
48     napi_create_error(env, code, msg, &error);
49     napi_throw(env, error);
50 }
51 } // namespace
52 
OnExecute(napi_env env,void * data)53 void JsUiAppearance::OnExecute(napi_env env, void* data)
54 {
55     JS_HILOG_INFO("OnExecute begin.");
56     AsyncContext* asyncContext = static_cast<AsyncContext*>(data);
57     if (asyncContext == nullptr) {
58         NapiThrow(env, "asyncContext is null.", UiAppearanceAbilityInterface::ErrCode::SYS_ERR);
59         return;
60     }
61     auto resCode = UiAppearanceAbilityClient::GetInstance()->SetDarkMode(asyncContext->mode);
62     asyncContext->status = static_cast<UiAppearanceAbilityInterface::ErrCode>(resCode);
63     if (asyncContext->status == UiAppearanceAbilityInterface::ErrCode::PERMISSION_ERR) {
64         asyncContext->errMsg = PERMISSION_ERR_MSG;
65     } else if (asyncContext->status == UiAppearanceAbilityInterface::ErrCode::INVALID_ARG) {
66         asyncContext->errMsg = INVALID_ARG_MSG;
67     } else {
68         asyncContext->errMsg = "";
69     }
70 }
71 
OnComplete(napi_env env,napi_status status,void * data)72 void JsUiAppearance::OnComplete(napi_env env, napi_status status, void* data)
73 {
74     JS_HILOG_INFO("OnComplete begin.");
75     napi_handle_scope scope = nullptr;
76     napi_open_handle_scope(env, &scope);
77     if (scope == nullptr) {
78         NapiThrow(env, "open handle scope failed.", UiAppearanceAbilityInterface::ErrCode::SYS_ERR);
79         return;
80     }
81     AsyncContext* asyncContext = static_cast<AsyncContext*>(data);
82     if (asyncContext == nullptr) {
83         NapiThrow(env, "asyncContext is null.", UiAppearanceAbilityInterface::ErrCode::SYS_ERR);
84         return;
85     }
86 
87     if (asyncContext->status == UiAppearanceAbilityInterface::ErrCode::SUCCEEDED) {
88         napi_value result = nullptr;
89         napi_get_null(env, &result);
90         if (asyncContext->deferred) { // promise
91             napi_resolve_deferred(env, asyncContext->deferred, result);
92         } else { // AsyncCallback
93             napi_value callback = nullptr;
94             napi_get_reference_value(env, asyncContext->callbackRef, &callback);
95             napi_value ret;
96             napi_call_function(env, nullptr, callback, 1, &result, &ret);
97         }
98     } else {
99         napi_value code = nullptr;
100         std::string strCode = std::to_string(asyncContext->status);
101         napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
102 
103         napi_value msg = nullptr;
104         auto iter = ERROR_CODE_TO_MSG.find(asyncContext->status);
105         std::string strMsg = (iter != ERROR_CODE_TO_MSG.end() ? iter->second : "") + asyncContext->errMsg;
106         JS_HILOG_INFO("napi throw errCode %{public}d, strMsg %{public}s", asyncContext->status, strMsg.c_str());
107         napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
108 
109         napi_value error = nullptr;
110         napi_create_error(env, code, msg, &error);
111         if (asyncContext->deferred) { // promise
112             napi_reject_deferred(env, asyncContext->deferred, error);
113         } else { // AsyncCallback
114             napi_value callback = nullptr;
115             napi_get_reference_value(env, asyncContext->callbackRef, &callback);
116             napi_value ret;
117             napi_call_function(env, nullptr, callback, 1, &error, &ret);
118         }
119     }
120     napi_delete_async_work(env, asyncContext->work);
121     delete asyncContext;
122     napi_close_handle_scope(env, scope);
123 }
124 
CheckArgs(napi_env env,size_t argc,napi_value * argv)125 napi_status JsUiAppearance::CheckArgs(napi_env env, size_t argc, napi_value* argv)
126 {
127     if (argc != ARGC_WITH_ONE && argc != ARGC_WITH_TWO) {
128         NapiThrow(
129             env, "the number of parameters can only be 1 or 2.", UiAppearanceAbilityInterface::ErrCode::INVALID_ARG);
130         return napi_invalid_arg;
131     }
132 
133     napi_valuetype valueType = napi_undefined;
134     switch (argc) {
135         case ARGC_WITH_TWO:
136             napi_typeof(env, argv[1], &valueType);
137             if (valueType != napi_function) {
138                 NapiThrow(env, "the second parameter must be a function.",
139                     UiAppearanceAbilityInterface::ErrCode::INVALID_ARG);
140                 return napi_invalid_arg;
141             }
142             [[fallthrough]];
143         case ARGC_WITH_ONE:
144             napi_typeof(env, argv[0], &valueType);
145             if (valueType != napi_number) {
146                 NapiThrow(
147                     env, "the first parameter must be DarkMode.", UiAppearanceAbilityInterface::ErrCode::INVALID_ARG);
148                 return napi_invalid_arg;
149             }
150             break;
151         default:
152             return napi_invalid_arg;
153     }
154     return napi_ok;
155 }
156 
ConvertJsDarkMode2Enum(int32_t jsVal)157 UiAppearanceAbilityInterface::DarkMode JsUiAppearance::ConvertJsDarkMode2Enum(int32_t jsVal)
158 {
159     switch (jsVal) {
160         case 0:
161             return UiAppearanceAbilityInterface::DarkMode::ALWAYS_DARK;
162         case 1:
163             return UiAppearanceAbilityInterface::DarkMode::ALWAYS_LIGHT;
164         default:
165             return UiAppearanceAbilityInterface::DarkMode::UNKNOWN;
166     }
167 }
168 
JSSetDarkMode(napi_env env,napi_callback_info info)169 static napi_value JSSetDarkMode(napi_env env, napi_callback_info info)
170 {
171     JS_HILOG_INFO("JSSetDarkMode begin.");
172 
173     size_t argc = ARGC_WITH_TWO;
174     napi_value argv[ARGC_WITH_TWO] = { 0 };
175     napi_status napiStatus = napi_ok;
176     napi_value result = nullptr;
177     napi_get_undefined(env, &result);
178 
179     napiStatus = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
180     if (napiStatus != napi_ok) {
181         NapiThrow(env, "get callback info failed.", UiAppearanceAbilityInterface::ErrCode::INVALID_ARG);
182         return result;
183     }
184     napiStatus = JsUiAppearance::CheckArgs(env, argc, argv);
185     if (napiStatus != napi_ok) {
186         NapiThrow(env, "parameter parsing error.", UiAppearanceAbilityInterface::ErrCode::INVALID_ARG);
187         return result;
188     }
189 
190     auto asyncContext = new (std::nothrow) AsyncContext();
191     if (asyncContext == nullptr) {
192         NapiThrow(env, "create AsyncContext failed.", UiAppearanceAbilityInterface::ErrCode::SYS_ERR);
193         return result;
194     }
195 
196     napi_get_value_int32(env, argv[0], &asyncContext->jsSetArg);
197     asyncContext->mode = JsUiAppearance::ConvertJsDarkMode2Enum(asyncContext->jsSetArg);
198     if (argc == ARGC_WITH_TWO) {
199         napi_create_reference(env, argv[1], 1, &asyncContext->callbackRef);
200     }
201     if (asyncContext->callbackRef == nullptr) {
202         napi_create_promise(env, &asyncContext->deferred, &result);
203     }
204 
205     napi_value resource = nullptr;
206     napi_create_string_utf8(env, "JSSetDarkMode", NAPI_AUTO_LENGTH, &resource);
207     napi_create_async_work(env, nullptr, resource, JsUiAppearance::OnExecute, JsUiAppearance::OnComplete,
208         reinterpret_cast<void*>(asyncContext), &asyncContext->work);
209     napi_queue_async_work(env, asyncContext->work);
210 
211     return result;
212 }
213 
JSGetDarkMode(napi_env env,napi_callback_info info)214 static napi_value JSGetDarkMode(napi_env env, napi_callback_info info)
215 {
216     JS_HILOG_INFO("JSGetDarkMode begin.");
217 
218     napi_value result = nullptr;
219     napi_get_undefined(env, &result);
220     size_t argc = 0;
221     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr));
222     if (argc != 0) {
223         NapiThrow(env, "requires no parameter.", UiAppearanceAbilityInterface::ErrCode::INVALID_ARG);
224         return result;
225     }
226 
227     auto mode = UiAppearanceAbilityClient::GetInstance()->GetDarkMode();
228     if (mode == UiAppearanceAbilityInterface::ErrCode::SYS_ERR) {
229         NapiThrow(env, "get dark-mode failed.", UiAppearanceAbilityInterface::ErrCode::SYS_ERR);
230         return result;
231     }
232     if (mode == UiAppearanceAbilityInterface::ErrCode::PERMISSION_ERR) {
233         NapiThrow(env,
234             "An attempt was made to get configuration forbidden by permission: ohos.permission.UPDATE_CONFIGURATION.",
235             UiAppearanceAbilityInterface::ErrCode::PERMISSION_ERR);
236         return result;
237     }
238     NAPI_CALL(env, napi_create_int32(env, mode, &result));
239     return result;
240 }
241 
242 EXTERN_C_START
UiAppearanceExports(napi_env env,napi_value exports)243 static napi_value UiAppearanceExports(napi_env env, napi_value exports)
244 {
245     napi_value DarkMode = nullptr;
246     napi_value alwaysDark = nullptr;
247     napi_value alwaysLight = nullptr;
248     NAPI_CALL(env, napi_create_int32(env, 0, &alwaysDark));
249     NAPI_CALL(env, napi_create_int32(env, 1, &alwaysLight));
250     NAPI_CALL(env, napi_create_object(env, &DarkMode));
251     NAPI_CALL(env, napi_set_named_property(env, DarkMode, "ALWAYS_DARK", alwaysDark));
252     NAPI_CALL(env, napi_set_named_property(env, DarkMode, "ALWAYS_LIGHT", alwaysLight));
253     napi_property_descriptor properties[] = {
254         DECLARE_NAPI_FUNCTION("setDarkMode", JSSetDarkMode),
255         DECLARE_NAPI_FUNCTION("getDarkMode", JSGetDarkMode),
256         DECLARE_NAPI_STATIC_PROPERTY("DarkMode", DarkMode),
257     };
258     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(properties[0]), properties));
259     return exports;
260 }
261 EXTERN_C_END
262 
263 static napi_module ui_appearance_module = {
264     .nm_version = 1,
265     .nm_flags = 0,
266     .nm_filename = nullptr,
267     .nm_register_func = UiAppearanceExports,
268     .nm_modname = "uiAppearance", // relative to the module name while import.
269     .nm_priv = nullptr,
270     .reserved = { 0 },
271 };
272 
UiAppearanceRegister()273 extern "C" __attribute__((constructor)) void UiAppearanceRegister()
274 {
275     napi_module_register(&ui_appearance_module);
276 }
277 } // namespace ArkUi::UiAppearance
278 } // namespace OHOS
279