1 /*
2  * Copyright (c) 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 
17 #include "interfaces/napi/kits/utils/napi_utils.h"
18 
19 #include "frameworks/bridge/common/utils/engine_helper.h"
20 
21 namespace OHOS::Ace::Napi {
22 namespace {
23 constexpr size_t STR_BUFFER_SIZE = 1024;
24 constexpr size_t ARGC_ACTIVATE_PARAMTER = 2;
25 }
26 
JSClearFocus(napi_env env, napi_callback_info info)27 static napi_value JSClearFocus(napi_env env, napi_callback_info info)
28 {
29     auto delegate = EngineHelper::GetCurrentDelegateSafely();
30     if (!delegate) {
31         return nullptr;
32     }
33     delegate->ResetFocus();
34     return nullptr;
35 }
36 
JSRequestFocus(napi_env env, napi_callback_info info)37 static napi_value JSRequestFocus(napi_env env, napi_callback_info info)
38 {
39     size_t argc = 1;
40     napi_value argv = nullptr;
41     napi_value thisVar = nullptr;
42     void* data = nullptr;
43     napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
44     NAPI_ASSERT(env, argc == 1, "requires 1 parameter");
45     napi_valuetype type = napi_undefined;
46     napi_typeof(env, argv, &type);
47     NAPI_ASSERT(env, type == napi_string, "the type of arg is not string");
48     char outBuffer[STR_BUFFER_SIZE] = { 0 };
49     size_t outSize = 0;
50     napi_get_value_string_utf8(env, argv, outBuffer, STR_BUFFER_SIZE, &outSize);
51     std::string key = std::string(outBuffer);
52 
53     napi_value obj = nullptr;
54     auto delegate = EngineHelper::GetCurrentDelegateSafely();
55     if (!delegate) {
56         napi_get_boolean(env, false, &obj);
57         return obj;
58     }
59     auto focusCallback = [env](NG::RequestFocusResult result) {
60         switch (result) {
61             case NG::RequestFocusResult::NON_FOCUSABLE:
62                 NapiThrow(env, "This component is not focusable.", ERROR_CODE_NON_FOCUSABLE);
63                 break;
64             case NG::RequestFocusResult::NON_FOCUSABLE_ANCESTOR:
65                 NapiThrow(env, "This component has unfocusable ancestor.", ERROR_CODE_NON_FOCUSABLE_ANCESTOR);
66                 break;
67             case NG::RequestFocusResult::NON_EXIST:
68                 NapiThrow(env,
69                     "The component doesn't exist, is currently invisible, or has been disabled.",
70                     ERROR_CODE_NON_EXIST);
71                 break;
72             default:
73                 NapiThrow(env, "An internal error occurred.", ERROR_CODE_INTERNAL_ERROR);
74                 break;
75         }
76     };
77     delegate->SetRequestFocusCallback(focusCallback);
78     delegate->RequestFocus(key, true);
79     delegate->ResetRequestFocusCallback();
80     napi_get_null(env, &obj);
81     return obj;
82 }
83 
JSActivate(napi_env env, napi_callback_info info)84 static napi_value JSActivate(napi_env env, napi_callback_info info)
85 {
86     size_t argc = ARGC_ACTIVATE_PARAMTER;
87     napi_value argv[ARGC_ACTIVATE_PARAMTER] = { nullptr };
88     napi_value thisVar = nullptr;
89     void* data = nullptr;
90     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
91     NAPI_ASSERT(env, argc >= 1, "requires at least 1 parameter");
92     napi_valuetype type = napi_undefined;
93     napi_typeof(env, argv[0], &type);
94     NAPI_ASSERT(env, type == napi_boolean, "the type of argv[0] is not bool");
95     bool isActive = false;
96     napi_get_value_bool(env, argv[0], &isActive);
97 
98     bool autoInactive = true;
99     if (argc == ARGC_ACTIVATE_PARAMTER) {
100         napi_typeof(env, argv[1], &type);
101         NAPI_ASSERT(env, type == napi_boolean, "the type of argv[1] is not bool");
102         napi_get_value_bool(env, argv[1], &autoInactive);
103     }
104 
105     napi_value obj = nullptr;
106     auto delegate = EngineHelper::GetCurrentDelegateSafely();
107     if (!delegate) {
108         napi_get_boolean(env, false, &obj);
109         return obj;
110     }
111     delegate->Activate(isActive, autoInactive);
112     napi_get_null(env, &obj);
113     return obj;
114 }
115 
registerFunc(napi_env env, napi_value exports)116 static napi_value registerFunc(napi_env env, napi_value exports)
117 {
118     napi_property_descriptor animatorDesc[] = {
119         DECLARE_NAPI_FUNCTION("clearFocus", JSClearFocus),
120         DECLARE_NAPI_FUNCTION("requestFocus", JSRequestFocus),
121         DECLARE_NAPI_FUNCTION("activate", JSActivate),
122     };
123     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(animatorDesc) / sizeof(animatorDesc[0]), animatorDesc));
124     return exports;
125 }
126 
127 static napi_module focusControllerModule = {
128     .nm_version = 1,
129     .nm_flags = 0,
130     .nm_filename = nullptr,
131     .nm_register_func = registerFunc,
132     .nm_modname = "arkui.focusController",
133     .nm_priv = ((void*)0),
134     .reserved = { 0 },
135 };
136 
FocusControllerRegister()137 extern "C" __attribute__((constructor)) void FocusControllerRegister()
138 {
139     napi_module_register(&focusControllerModule);
140 }
141 } // namespace OHOS::Ace::Napi