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 "pointer.h"
17 #include <iostream>
18
19 #include "define_multimodal.h"
20 #include "input_manager.h"
21 #include "mmi_log.h"
22
23 #include <cstdint>
24 #include <cmath>
25 #include <limits>
26
27 #undef MMI_LOG_TAG
28 #define MMI_LOG_TAG "AniPointer"
29
30 using namespace OHOS::MMI;
31
32 namespace {
33 constexpr int32_t ANI_SCOPE_SIZE = 16;
34 constexpr int32_t MILLISECOND_FACTOR = 1000;
35 constexpr size_t EVENT_NAME_LEN { 64 };
36 constexpr size_t PRE_KEYS_SIZE { 4 };
37 constexpr size_t INPUT_PARAMETER_MIDDLE { 2 };
38 constexpr size_t INPUT_PARAMETER_MAX { 3 };
39 constexpr int32_t OCCUPIED_BY_SYSTEM = -3;
40 constexpr int32_t OCCUPIED_BY_OTHER = -4;
41 const double INT32_MAX_D = static_cast<double>(std::numeric_limits<int32_t>::max());
42 } // namespace
43
44 enum AniErrorCode : int32_t {
45 COMMON_PARAMETER_ERROR = 401,
46 COMMON_USE_SYSAPI_ERROR = 202,
47 };
48
ThrowBusinessError(ani_env * env,int errCode,std::string && errMsg)49 static void ThrowBusinessError(ani_env *env, int errCode, std::string&& errMsg)
50 {
51 MMI_HILOGD("Begin ThrowBusinessError.");
52 static const char *errorClsName = "L@ohos/base/BusinessError;";
53 ani_class cls {};
54 if (ANI_OK != env->FindClass(errorClsName, &cls)) {
55 MMI_HILOGE("find class BusinessError %{public}s failed", errorClsName);
56 return;
57 }
58 ani_method ctor;
59 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", ":V", &ctor)) {
60 MMI_HILOGE("find method BusinessError.constructor failed");
61 return;
62 }
63 ani_object errorObject;
64 if (ANI_OK != env->Object_New(cls, ctor, &errorObject)) {
65 MMI_HILOGE("create BusinessError object failed");
66 return;
67 }
68 ani_double aniErrCode = static_cast<ani_double>(errCode);
69 ani_string errMsgStr;
70 if (ANI_OK != env->String_NewUTF8(errMsg.c_str(), errMsg.size(), &errMsgStr)) {
71 MMI_HILOGE("convert errMsg to ani_string failed");
72 return;
73 }
74 if (ANI_OK != env->Object_SetFieldByName_Double(errorObject, "code", aniErrCode)) {
75 MMI_HILOGE("set error code failed");
76 return;
77 }
78 if (ANI_OK != env->Object_SetPropertyByName_Ref(errorObject, "message", errMsgStr)) {
79 MMI_HILOGE("set error message failed");
80 return;
81 }
82 env->ThrowError(static_cast<ani_error>(errorObject));
83 return;
84 }
85
ToInt32ECMAScript(double value)86 static int32_t ToInt32ECMAScript(double value)
87 {
88 if (std::isnan(value) || std::isinf(value)) {
89 return 0;
90 }
91
92 double truncated = std::trunc(value);
93 double modValue = std::fmod(truncated, 4294967296.0);
94 uint32_t uint32Val = static_cast<uint32_t>(modValue);
95 return static_cast<int32_t>(uint32Val);
96 }
97
ParseEnumToInt(ani_env * env,ani_enum_item enumItem)98 static ani_int ParseEnumToInt(ani_env *env, ani_enum_item enumItem)
99 {
100 ani_int intValue = -1;
101 if (ANI_OK != env->EnumItem_GetValue_Int(enumItem, &intValue)) {
102 MMI_HILOGE("%{public}s: EnumItem_GetValue_Int FAILD.", __func__);
103 return -1;
104 }
105 MMI_HILOGD("%{public}s: Enum Value: %{public}d.", __func__, intValue);
106 return intValue;
107 }
108
SetPointerStyleInner(ani_env * env,ani_double windowid,ani_enum_item pointerStyle)109 static int SetPointerStyleInner(ani_env *env, ani_double windowid, ani_enum_item pointerStyle)
110 {
111 int32_t windowID = ToInt32ECMAScript(static_cast<double>(windowid));
112 if (windowID < 0 && windowID != GLOBAL_WINDOW_ID) {
113 MMI_HILOGE("Invalid windowid");
114 ThrowBusinessError(env, COMMON_PARAMETER_ERROR, "Windowid is invalid");
115 return 0;
116 }
117
118 int32_t pointerStyleID = ParseEnumToInt(env, pointerStyle);
119 if ((pointerStyleID < DEFAULT && pointerStyleID != DEVELOPER_DEFINED_ICON) || pointerStyleID > RUNNING) {
120 MMI_HILOGE("Undefined pointer style");
121 ThrowBusinessError(env, COMMON_PARAMETER_ERROR, "Pointer style does not exist");
122 return 0;
123 }
124
125 PointerStyle style;
126 style.id = pointerStyleID;
127 int32_t errorCode = InputManager::GetInstance()->SetPointerStyle(windowid, style);
128 if (errorCode == COMMON_USE_SYSAPI_ERROR) {
129 MMI_HILOGE("The windowId is negative number and no system applications use system API");
130 ThrowBusinessError(env, COMMON_USE_SYSAPI_ERROR,
131 "windowId is negative number and no system applications use system API");
132 return 0;
133 }
134 MMI_HILOGD(" SetPointerStyleInner end.");
135 return 0;
136 }
137
ANI_Constructor(ani_vm * vm,uint32_t * result)138 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
139 {
140 ani_env *env;
141 if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
142 MMI_HILOGE("%{public}s: Unsupported ANI_VERSION_1", __func__);
143 return ANI_ERROR;
144 }
145
146 static const char *name = "L@ohos/multimodalInput/pointer/pointer;";
147 ani_namespace ns;
148 if (ANI_OK != env->FindNamespace(name, &ns)) {
149 MMI_HILOGE("%{public}s: Not found %{public}s", __func__, name);
150 return ANI_NOT_FOUND;
151 }
152
153 std::array methods = {
154 ani_native_function {"setPointerStyleInner", nullptr, reinterpret_cast<void *>(SetPointerStyleInner)},
155 };
156
157 if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) {
158 MMI_HILOGE("%{public}s:Cannot bind native methods to '%{public}s'", __func__, name);
159 return ANI_ERROR;
160 };
161
162 *result = ANI_VERSION_1;
163 return ANI_OK;
164 }