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 "accessibility_element_operator_callback_proxy.h"
17 #include "accessibility_element_info_parcel.h"
18 #include "hilog_wrapper.h"
19 
20 namespace OHOS {
21 namespace Accessibility {
22 
23 constexpr int32_t IPC_MEMORY_SIZE = 500 * 1024; // default size is 200 * 1024B, batch query need more memory
24 constexpr int32_t SINGLE_TRANSMIT = -2;
25 constexpr int32_t MULTI_TRANSMIT_FINISH = -1;
26 constexpr int32_t DATA_NUMBER_ONE_TIME = 400;
27 
AccessibilityElementOperatorCallbackProxy(const sptr<IRemoteObject> & impl)28 AccessibilityElementOperatorCallbackProxy::AccessibilityElementOperatorCallbackProxy(
29     const sptr<IRemoteObject> &impl) : IRemoteProxy<IAccessibilityElementOperatorCallback>(impl)
30 {}
31 
~AccessibilityElementOperatorCallbackProxy()32 AccessibilityElementOperatorCallbackProxy::~AccessibilityElementOperatorCallbackProxy()
33 {}
34 
WriteInterfaceToken(MessageParcel & data)35 bool AccessibilityElementOperatorCallbackProxy::WriteInterfaceToken(MessageParcel &data)
36 {
37     HILOG_DEBUG();
38     if (!data.WriteInterfaceToken(AccessibilityElementOperatorCallbackProxy::GetDescriptor())) {
39         HILOG_ERROR("write interface token failed");
40         return false;
41     }
42     return true;
43 }
44 
SendTransactCmd(AccessibilityInterfaceCode code,MessageParcel & data,MessageParcel & reply,MessageOption & option)45 bool AccessibilityElementOperatorCallbackProxy::SendTransactCmd(AccessibilityInterfaceCode code,
46     MessageParcel &data, MessageParcel &reply,  MessageOption &option)
47 {
48     HILOG_DEBUG();
49 
50     sptr<IRemoteObject> remoteObj = Remote();
51     if (remoteObj == nullptr) {
52         HILOG_ERROR("fail to send transact cmd %{public}d due to remote object", code);
53         return false;
54     }
55     int32_t ret = remoteObj->SendRequest(static_cast<uint32_t>(code), data, reply, option);
56     if (ret != NO_ERROR) {
57         HILOG_ERROR("receive error transact code %{public}d in transact cmd %{public}d", ret, code);
58         return false;
59     }
60     return true;
61 }
62 
GetTransmitFlag(int32_t time,int32_t leftSize)63 int32_t AccessibilityElementOperatorCallbackProxy::GetTransmitFlag(int32_t time, int32_t leftSize)
64 {
65     int32_t flag = time;
66     if (time == 0 && leftSize <= DATA_NUMBER_ONE_TIME) {
67         flag = SINGLE_TRANSMIT;
68     } else if (leftSize <= DATA_NUMBER_ONE_TIME) {
69         flag = MULTI_TRANSMIT_FINISH;
70     }
71 
72     return flag;
73 }
74 
SetSearchElementInfoByAccessibilityIdResult(const std::vector<AccessibilityElementInfo> & infos,const int32_t requestId)75 void AccessibilityElementOperatorCallbackProxy::SetSearchElementInfoByAccessibilityIdResult(
76     const std::vector<AccessibilityElementInfo> &infos, const int32_t requestId)
77 {
78     HILOG_DEBUG("infos size %{public}zu, resquestId %{public}d", infos.size(), requestId);
79     int32_t leftSize = static_cast<int32_t>(infos.size());
80     int32_t time = 0;
81     int32_t index = 0;
82     while (leftSize >= 0) {
83         MessageParcel data;
84         MessageParcel reply;
85         MessageOption type = MessageOption::TF_SYNC;
86         if (leftSize <= DATA_NUMBER_ONE_TIME) {
87             type = MessageOption::TF_ASYNC;
88         }
89         MessageOption option(type);
90         data.SetMaxCapacity(IPC_MEMORY_SIZE);
91 
92         // when infos size is a multi of 800, do not send the last empty reply
93         if (leftSize == 0 && time > 0) {
94             return;
95         }
96         if (!WriteInterfaceToken(data)) {
97             return;
98         }
99 
100         int32_t flag = GetTransmitFlag(time, leftSize);
101         if (!data.WriteInt32(flag)) {
102             return;
103         }
104 
105         int32_t writeSize = (leftSize <= DATA_NUMBER_ONE_TIME) ? leftSize : DATA_NUMBER_ONE_TIME;
106         if (!data.WriteInt32(writeSize)) {
107             return;
108         }
109 
110         for (int32_t i = 0; i < writeSize; ++i) {
111             AccessibilityElementInfoParcel infoParcel(infos[index]);
112             index++;
113             if (!data.WriteParcelable(&infoParcel)) {
114                 HILOG_ERROR("accessibility element info failed index %{public}d", index);
115                 return;
116             }
117         }
118 
119         if (!data.WriteInt32(requestId)) {
120             return;
121         }
122 
123         if (!SendTransactCmd(AccessibilityInterfaceCode::SET_RESULT_BY_ACCESSIBILITY_ID, data, reply, option)) {
124             HILOG_ERROR("set search element info by accessibility id result failed");
125             return;
126         }
127 
128         leftSize -= DATA_NUMBER_ONE_TIME;
129         time++;
130         if (static_cast<RetError>(reply.ReadInt32()) != RET_OK) {
131             return;
132         }
133     }
134 }
135 
SetSearchElementInfoByTextResult(const std::vector<AccessibilityElementInfo> & infos,const int32_t requestId)136 void AccessibilityElementOperatorCallbackProxy::SetSearchElementInfoByTextResult(
137     const std::vector<AccessibilityElementInfo> &infos, const int32_t requestId)
138 {
139     HILOG_DEBUG();
140     MessageParcel data;
141     MessageParcel reply;
142     MessageOption option(MessageOption::TF_ASYNC);
143 
144     if (!WriteInterfaceToken(data)) {
145         HILOG_ERROR("connection write token failed");
146         return;
147     }
148 
149     if (!data.WriteInt32(infos.size())) {
150         HILOG_ERROR("write infos's size failed");
151         return;
152     }
153 
154     for (auto &info : infos) {
155         AccessibilityElementInfoParcel infoParcel(info);
156         if (!data.WriteParcelable(&infoParcel)) {
157             HILOG_ERROR("write accessibility element info failed");
158             return;
159         }
160     }
161 
162     if (!data.WriteInt32(requestId)) {
163         HILOG_ERROR("connection write request id failed");
164         return;
165     }
166 
167     if (!SendTransactCmd(AccessibilityInterfaceCode::SET_RESULT_BY_TEXT,
168         data, reply, option)) {
169         HILOG_ERROR("set search element info by text result failed");
170         return;
171     }
172 }
173 
SetFindFocusedElementInfoResult(const AccessibilityElementInfo & info,const int32_t requestId)174 void AccessibilityElementOperatorCallbackProxy::SetFindFocusedElementInfoResult(
175     const AccessibilityElementInfo &info, const int32_t requestId)
176 {
177     HILOG_DEBUG();
178     MessageParcel data;
179     MessageParcel reply;
180     MessageOption option(MessageOption::TF_ASYNC);
181     AccessibilityElementInfoParcel infoParcel(info);
182 
183     if (!WriteInterfaceToken(data)) {
184         HILOG_ERROR("connection write token failed");
185         return;
186     }
187 
188     if (!data.WriteParcelable(&infoParcel)) {
189         HILOG_ERROR("connection write info failed");
190         return;
191     }
192     if (!data.WriteInt32(requestId)) {
193         HILOG_ERROR("connection write request id failed");
194         return;
195     }
196 
197     if (!SendTransactCmd(AccessibilityInterfaceCode::SET_RESULT_FOCUSED_INFO,
198         data, reply, option)) {
199         HILOG_ERROR("set find focused element info result failed");
200         return;
201     }
202 }
203 
SetFocusMoveSearchResult(const AccessibilityElementInfo & info,const int32_t requestId)204 void AccessibilityElementOperatorCallbackProxy::SetFocusMoveSearchResult(const AccessibilityElementInfo &info,
205     const int32_t requestId)
206 {
207     HILOG_DEBUG();
208     MessageParcel data;
209     MessageParcel reply;
210     MessageOption option(MessageOption::TF_ASYNC);
211     AccessibilityElementInfoParcel infoParcel(info);
212 
213     if (!WriteInterfaceToken(data)) {
214         HILOG_ERROR("connection write token failed");
215         return;
216     }
217 
218     if (!data.WriteParcelable(&infoParcel)) {
219         HILOG_ERROR("connection write info failed");
220         return;
221     }
222 
223     if (!data.WriteInt32(requestId)) {
224         HILOG_ERROR("connection write requestId failed");
225         return;
226     }
227 
228     if (!SendTransactCmd(AccessibilityInterfaceCode::SET_RESULT_FOCUS_MOVE,
229         data, reply, option)) {
230         HILOG_ERROR("set focus move search result failed");
231         return;
232     }
233 }
234 
SetExecuteActionResult(const bool succeeded,const int32_t requestId)235 void AccessibilityElementOperatorCallbackProxy::SetExecuteActionResult(const bool succeeded, const int32_t requestId)
236 {
237     HILOG_DEBUG();
238     MessageParcel data;
239     MessageParcel reply;
240     MessageOption option(MessageOption::TF_ASYNC);
241 
242     if (!WriteInterfaceToken(data)) {
243         HILOG_ERROR("connection write token failed");
244         return;
245     }
246 
247     if (!data.WriteBool(succeeded)) {
248         HILOG_ERROR("connection write failed");
249         return;
250     }
251 
252     if (!data.WriteInt32(requestId)) {
253         HILOG_ERROR("connection write request id failed");
254         return;
255     }
256 
257     if (!SendTransactCmd(AccessibilityInterfaceCode::SET_RESULT_PERFORM_ACTION,
258         data, reply, option)) {
259         HILOG_ERROR("set execute action result failed");
260         return;
261     }
262 }
263 
SetCursorPositionResult(const int32_t cursorPosition,const int32_t requestId)264 void AccessibilityElementOperatorCallbackProxy::SetCursorPositionResult(const int32_t cursorPosition,
265     const int32_t requestId)
266 {
267     HILOG_DEBUG();
268     MessageParcel data;
269     MessageParcel reply;
270     MessageOption option(MessageOption::TF_ASYNC);
271 
272     if (!WriteInterfaceToken(data)) {
273         HILOG_ERROR("connection write token failed");
274         return;
275     }
276     HILOG_INFO(" [cursorPosition:%{public}d]", cursorPosition);
277     if (!data.WriteInt32(cursorPosition)) {
278         HILOG_ERROR("connection write failed");
279         return;
280     }
281 
282     if (!data.WriteInt32(requestId)) {
283         HILOG_ERROR("connection write request id failed");
284         return;
285     }
286 
287     if (!SendTransactCmd(AccessibilityInterfaceCode::SET_RESULT_CURSOR_RESULT,
288         data, reply, option)) {
289         HILOG_ERROR("set cursor position result failed");
290         return;
291     }
292 }
293 
294 } // namespace Accessibility
295 } // namespace OHOS
296