1 /*
2 * Copyright (C) 2023-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 #include "input_method_panel.h"
17
18 #include <tuple>
19
20 #include "display_info.h"
21 #include "dm_common.h"
22 #include "global.h"
23 #include "input_method_ability.h"
24 #include "input_method_ability_utils.h"
25 #include "inputmethod_trace.h"
26 #include "scene_board_judgement.h"
27 #include "sys_cfg_parser.h"
28 #include "ui/rs_surface_node.h"
29
30 namespace OHOS {
31 namespace MiscServices {
32 using WMError = OHOS::Rosen::WMError;
33 using WindowGravity = OHOS::Rosen::WindowGravity;
34 using WindowState = OHOS::Rosen::WindowState;
35 using namespace Rosen;
36 constexpr float FIXED_SOFT_KEYBOARD_PANEL_RATIO = 0.7;
37 constexpr float NON_FIXED_SOFT_KEYBOARD_PANEL_RATIO = 1;
38 constexpr int32_t FIXED_PANEL_POS_X = 0;
39 constexpr int32_t ORIGIN_POS_X = 0;
40 constexpr int32_t ORIGIN_POS_Y = 0;
41 constexpr int32_t DEFAULT_AVOID_HEIGHT = -1;
42 std::atomic<uint32_t> InputMethodPanel::sequenceId_ { 0 };
43 constexpr int32_t MAXWAITTIME = 30;
44 constexpr int32_t WAITTIME = 10;
45 InputMethodPanel::~InputMethodPanel() = default;
46 constexpr float GRADIENT_HEIGHT_RATIO = 0.15;
47
CreatePanel(const std::shared_ptr<AbilityRuntime::Context> & context,const PanelInfo & panelInfo)48 int32_t InputMethodPanel::CreatePanel(
49 const std::shared_ptr<AbilityRuntime::Context> &context, const PanelInfo &panelInfo)
50 {
51 IMSA_HILOGD(
52 "start, type/flag: %{public}d/%{public}d.", static_cast<int32_t>(panelType_), static_cast<int32_t>(panelFlag_));
53 panelType_ = panelInfo.panelType;
54 panelFlag_ = panelInfo.panelFlag;
55 winOption_ = new (std::nothrow) OHOS::Rosen::WindowOption();
56 if (winOption_ == nullptr) {
57 return ErrorCode::ERROR_NULL_POINTER;
58 }
59 if (panelInfo.panelType == PanelType::STATUS_BAR) {
60 winOption_->SetWindowType(OHOS::Rosen::WindowType::WINDOW_TYPE_INPUT_METHOD_STATUS_BAR);
61 } else {
62 winOption_->SetWindowType(OHOS::Rosen::WindowType::WINDOW_TYPE_INPUT_METHOD_FLOAT);
63 }
64 WMError wmError = WMError::WM_OK;
65 window_ = OHOS::Rosen::Window::Create(GeneratePanelName(), winOption_, context, wmError);
66 if (wmError == WMError::WM_ERROR_INVALID_PERMISSION || wmError == WMError::WM_ERROR_NOT_SYSTEM_APP) {
67 IMSA_HILOGE("create window failed, permission denied, %{public}d!", wmError);
68 return ErrorCode::ERROR_NOT_IME;
69 }
70 if (window_ == nullptr || wmError != WMError::WM_OK) {
71 IMSA_HILOGE("create window failed: %{public}d!", wmError);
72 return ErrorCode::ERROR_OPERATE_PANEL;
73 }
74 if (SetPanelProperties() != ErrorCode::NO_ERROR) {
75 wmError = window_->Destroy();
76 IMSA_HILOGI("destroy window end, wmError is %{public}d.", wmError);
77 return ErrorCode::ERROR_OPERATE_PANEL;
78 }
79 windowId_ = window_->GetWindowId();
80 IMSA_HILOGI("success, type/flag/windowId: %{public}d/%{public}d/%{public}u.", static_cast<int32_t>(panelType_),
81 static_cast<int32_t>(panelFlag_), windowId_);
82 if (panelInfo.panelType == SOFT_KEYBOARD) {
83 isScbEnable_ = Rosen::SceneBoardJudgement::IsSceneBoardEnabled();
84 if (isScbEnable_) {
85 RegisterKeyboardPanelInfoChangeListener();
86 }
87 }
88 return ErrorCode::NO_ERROR;
89 }
90
GeneratePanelName()91 std::string InputMethodPanel::GeneratePanelName()
92 {
93 uint32_t sequenceId = GenerateSequenceId();
94 std::string windowName = panelType_ == SOFT_KEYBOARD ? "softKeyboard" + std::to_string(sequenceId) :
95 "statusBar" + std::to_string(sequenceId);
96 IMSA_HILOGD("InputMethodPanel, windowName: %{public}s.", windowName.c_str());
97 return windowName;
98 }
99
FullScreenPrepare(Rosen::KeyboardLayoutParams & param,const ImmersiveEffect & effect)100 int32_t InputMethodPanel::FullScreenPrepare(Rosen::KeyboardLayoutParams ¶m, const ImmersiveEffect &effect)
101 {
102 ChangeY changeY = { .portrait = 0, .landscape = 0 };
103 SetChangeY(changeY);
104 if (param.portraitAvoidHeight_ < 0 || param.landscapeAvoidHeight_ < 0 || param.PortraitPanelRect_.posY_ < 0 ||
105 param.LandscapePanelRect_.posY_ < 0) {
106 IMSA_HILOGE("invalid portraitAvoidHeight_:%{public}d, landscapeAvoidHeight_:%{public}d, portraitPosY_:\
107 %{public}d, landscapePosY_:%{public}d", param.portraitAvoidHeight_, param.landscapeAvoidHeight_,
108 param.PortraitPanelRect_.posY_, param.LandscapePanelRect_.posY_);
109 return ErrorCode::ERROR_INVALID_RANGE;
110 }
111
112 // calculate changeY
113 uint32_t avoidHeightTmp = static_cast<uint32_t>(param.portraitAvoidHeight_) + effect.gradientHeight;
114 if (param.PortraitPanelRect_.height_ < avoidHeightTmp) {
115 changeY.portrait = avoidHeightTmp - param.PortraitPanelRect_.height_;
116 param.PortraitPanelRect_.height_ = avoidHeightTmp;
117 param.PortraitPanelRect_.posY_ = static_cast<int32_t>(SafeSubtract(
118 static_cast<uint32_t>(param.PortraitPanelRect_.posY_), changeY.portrait));
119 }
120 avoidHeightTmp = static_cast<uint32_t>(param.landscapeAvoidHeight_) + effect.gradientHeight;
121 if (param.LandscapePanelRect_.height_ < avoidHeightTmp) {
122 changeY.landscape = avoidHeightTmp - param.LandscapePanelRect_.height_;
123 param.LandscapePanelRect_.height_ = avoidHeightTmp;
124 param.LandscapePanelRect_.posY_ = static_cast<int32_t>(SafeSubtract(
125 static_cast<uint32_t>(param.LandscapePanelRect_.posY_), changeY.landscape));
126 }
127 SetChangeY(changeY);
128
129 // calculate avoid height
130 auto gradientHeightTemp = static_cast<int32_t>(effect.gradientHeight);
131 if (param.landscapeAvoidHeight_ > INT32_MAX - gradientHeightTemp) {
132 IMSA_HILOGE("landscapeAvoidHeight_ overflow detected");
133 return ErrorCode::ERROR_INVALID_RANGE;
134 }
135 param.landscapeAvoidHeight_ += gradientHeightTemp;
136 if (param.portraitAvoidHeight_ > INT32_MAX - gradientHeightTemp) {
137 IMSA_HILOGE("portraitAvoidHeight_ overflow detected");
138 return ErrorCode::ERROR_INVALID_RANGE;
139 }
140 param.portraitAvoidHeight_ += gradientHeightTemp;
141 return ErrorCode::NO_ERROR;
142 }
143
NormalImePrepare(Rosen::KeyboardLayoutParams & param,const ImmersiveEffect & effect)144 int32_t InputMethodPanel::NormalImePrepare(Rosen::KeyboardLayoutParams ¶m, const ImmersiveEffect &effect)
145 {
146 if (param.PortraitPanelRect_.posY_ < 0 || param.LandscapePanelRect_.posY_ < 0) {
147 IMSA_HILOGE("invalid portraitPosY_:%{public}d, landscapePosY_:%{public}d", param.PortraitPanelRect_.posY_,
148 param.LandscapePanelRect_.posY_);
149 return ErrorCode::ERROR_INVALID_RANGE;
150 }
151 uint32_t portraitHeight = param.PortraitPanelRect_.height_ + effect.gradientHeight;
152 uint32_t landscapeHeight = param.LandscapePanelRect_.height_ + effect.gradientHeight;
153
154 param.PortraitPanelRect_.height_ = portraitHeight;
155 param.LandscapePanelRect_.height_ = landscapeHeight;
156 param.LandscapePanelRect_.posY_ = static_cast<int32_t>(SafeSubtract(
157 static_cast<uint32_t>(param.LandscapePanelRect_.posY_), effect.gradientHeight));
158 param.PortraitPanelRect_.posY_ = static_cast<int32_t>(SafeSubtract(
159 static_cast<uint32_t>(param.PortraitPanelRect_.posY_), effect.gradientHeight));
160
161 SetChangeY({ .portrait = effect.gradientHeight, .landscape = effect.gradientHeight });
162 return ErrorCode::NO_ERROR;
163 }
164
PrepareAdjustLayout(Rosen::KeyboardLayoutParams & param,const ImmersiveEffect & effect)165 int32_t InputMethodPanel::PrepareAdjustLayout(Rosen::KeyboardLayoutParams ¶m, const ImmersiveEffect &effect)
166 {
167 int32_t ret = ErrorCode::NO_ERROR;
168 // full screen keyboard
169 if (param.landscapeAvoidHeight_ != DEFAULT_AVOID_HEIGHT && param.portraitAvoidHeight_ != DEFAULT_AVOID_HEIGHT) {
170 ret = FullScreenPrepare(param, effect);
171 } else {
172 ret = NormalImePrepare(param, effect);
173 }
174 if (ret != ErrorCode::NO_ERROR) {
175 IMSA_HILOGE("prepare failed");
176 return ret;
177 }
178 return ErrorCode::NO_ERROR;
179 }
180
AdjustLayout(const Rosen::KeyboardLayoutParams & param)181 int32_t InputMethodPanel::AdjustLayout(const Rosen::KeyboardLayoutParams ¶m)
182 {
183 return AdjustLayout(param, LoadImmersiveEffect());
184 }
185
AdjustLayout(const Rosen::KeyboardLayoutParams & param,const ImmersiveEffect & effect)186 int32_t InputMethodPanel::AdjustLayout(const Rosen::KeyboardLayoutParams ¶m, const ImmersiveEffect &effect)
187 {
188 if (window_ == nullptr) {
189 IMSA_HILOGE("window is nullptr!");
190 return ErrorCode::ERROR_NULL_POINTER;
191 }
192
193 Rosen::KeyboardLayoutParams paramTmp = param;
194 if (effect.gradientHeight != 0) {
195 IMSA_HILOGI("gradientHeight:%{public}u is not zero, need adjust layout", effect.gradientHeight);
196 auto ret = PrepareAdjustLayout(paramTmp, effect);
197 if (ret != ErrorCode::NO_ERROR) {
198 return ret;
199 }
200 } else {
201 SetChangeY({ 0, 0 });
202 }
203 // The actual system panel height includes the gradient height, which may not be consistent with the cached value.
204 auto wmRet = window_->AdjustKeyboardLayout(paramTmp);
205 if (wmRet != WMError::WM_OK) {
206 IMSA_HILOGE("AdjustKeyboardLayout failed, wmError is %{public}d!", wmRet);
207 return ErrorCode::ERROR_WINDOW_MANAGER;
208 }
209 return ErrorCode::NO_ERROR;
210 }
211
SetPanelProperties()212 int32_t InputMethodPanel::SetPanelProperties()
213 {
214 if (window_ == nullptr) {
215 IMSA_HILOGE("window is nullptr!");
216 return ErrorCode::ERROR_OPERATE_PANEL;
217 }
218 WindowGravity gravity = WindowGravity::WINDOW_GRAVITY_FLOAT;
219 if (panelType_ == SOFT_KEYBOARD && panelFlag_ == FLG_FIXED) {
220 gravity = WindowGravity::WINDOW_GRAVITY_BOTTOM;
221 } else if (panelType_ == SOFT_KEYBOARD && panelFlag_ == FLG_FLOATING) {
222 auto surfaceNode = window_->GetSurfaceNode();
223 if (surfaceNode == nullptr) {
224 IMSA_HILOGE("surfaceNode is nullptr!");
225 return ErrorCode::ERROR_OPERATE_PANEL;
226 }
227 surfaceNode->SetFrameGravity(Rosen::Gravity::TOP_LEFT);
228 Rosen::RSTransactionProxy::GetInstance()->FlushImplicitTransaction();
229 } else if (panelType_ == STATUS_BAR) {
230 auto surfaceNo = window_->GetSurfaceNode();
231 if (surfaceNo == nullptr) {
232 IMSA_HILOGE("surfaceNo is nullptr!");
233 return ErrorCode::ERROR_OPERATE_PANEL;
234 }
235 surfaceNo->SetFrameGravity(Rosen::Gravity::TOP_LEFT);
236 Rosen::RSTransactionProxy::GetInstance()->FlushImplicitTransaction();
237 return ErrorCode::NO_ERROR;
238 }
239 if (!isScbEnable_) {
240 WMError wmError = window_->SetWindowGravity(gravity, invalidGravityPercent);
241 if (wmError != WMError::WM_OK) {
242 IMSA_HILOGE("failed to set window gravity, wmError is %{public}d, start destroy window!", wmError);
243 return ErrorCode::ERROR_OPERATE_PANEL;
244 }
245 return ErrorCode::NO_ERROR;
246 }
247 auto params = GetKeyboardLayoutParams();
248 params.gravity_ = gravity;
249 auto ret = AdjustLayout(params);
250 if (ret != ErrorCode::NO_ERROR) {
251 IMSA_HILOGE("SetWindowGravity failed, ret is %{public}d, start destroy window!", ret);
252 return ErrorCode::ERROR_OPERATE_PANEL;
253 }
254 SetKeyboardLayoutParams(params);
255 return ErrorCode::NO_ERROR;
256 }
257
DestroyPanel()258 int32_t InputMethodPanel::DestroyPanel()
259 {
260 auto ret = HidePanel();
261 if (ret != ErrorCode::NO_ERROR) {
262 IMSA_HILOGE("InputMethodPanel, hide panel failed, ret: %{public}d!", ret);
263 }
264 if (window_ == nullptr) {
265 IMSA_HILOGE("window_ is nullptr!");
266 return ErrorCode::ERROR_NULL_POINTER;
267 }
268 if (panelType_ == SOFT_KEYBOARD) {
269 UnregisterKeyboardPanelInfoChangeListener();
270 }
271 auto result = window_->Destroy();
272 IMSA_HILOGI("destroy ret: %{public}d", result);
273 return ErrorCode::NO_ERROR;
274 }
275
GetResizeParams(Rosen::Rect & portrait,Rosen::Rect & landscape,uint32_t width,uint32_t height)276 int32_t InputMethodPanel::GetResizeParams(
277 Rosen::Rect &portrait, Rosen::Rect &landscape, uint32_t width, uint32_t height)
278 {
279 LayoutParams currParams;
280 DisplaySize displaySize;
281 auto ret = GetDisplaySize(displaySize);
282 if (ret != ErrorCode::NO_ERROR) {
283 IMSA_HILOGE("failed to GetDisplaySize ret: %{public}d", ret);
284 return ret;
285 }
286
287 if (displaySize.portrait.height == displaySize.portrait.width) {
288 portrait.height_ = height;
289 portrait.width_ = width;
290 landscape.height_ = height;
291 landscape.width_ = width;
292 IMSA_HILOGI("isScreenEqual now, update screen equal size");
293 return ErrorCode::NO_ERROR;
294 }
295
296 if (IsDisplayUnfolded()) {
297 std::lock_guard<std::mutex> lock(unfoldResizeParamMutex_);
298 IMSA_HILOGI("foldable device without fold state");
299 if (!isInEnhancedAdjust_.load()) {
300 RectifyResizeParams(resizePanelUnfoldParams_, displaySize);
301 }
302 currParams = resizePanelUnfoldParams_;
303 } else {
304 std::lock_guard<std::mutex> lock(foldResizeParamMutex_);
305 IMSA_HILOGI("foldable device with fold state or non-foldable device");
306 if (!isInEnhancedAdjust_.load()) {
307 RectifyResizeParams(resizePanelFoldParams_, displaySize);
308 }
309 currParams = resizePanelFoldParams_;
310 }
311
312 UpdateRectParams(portrait, landscape, width, height, currParams);
313 return ErrorCode::NO_ERROR;
314 }
315
RectifyResizeParams(LayoutParams & params,const DisplaySize & displaySize)316 void InputMethodPanel::RectifyResizeParams(LayoutParams ¶ms, const DisplaySize &displaySize)
317 {
318 params.portraitRect.height_ =
319 std::min(static_cast<float>(displaySize.portrait.height) * FIXED_SOFT_KEYBOARD_PANEL_RATIO,
320 static_cast<float>(params.portraitRect.height_));
321 params.landscapeRect.height_ =
322 std::min(static_cast<float>(displaySize.landscape.height) * FIXED_SOFT_KEYBOARD_PANEL_RATIO,
323 static_cast<float>(params.landscapeRect.height_));
324 params.portraitRect.width_ =
325 std::min(displaySize.portrait.width, params.portraitRect.width_);
326 params.landscapeRect.width_ =
327 std::min(displaySize.landscape.width, params.landscapeRect.width_);
328 }
329
UpdateRectParams(Rosen::Rect & portrait,Rosen::Rect & landscape,uint32_t width,uint32_t height,const LayoutParams & currParams)330 void InputMethodPanel::UpdateRectParams(
331 Rosen::Rect &portrait, Rosen::Rect &landscape, uint32_t width, uint32_t height, const LayoutParams &currParams)
332 {
333 if (IsDisplayPortrait()) {
334 landscape.height_ = currParams.landscapeRect.height_;
335 landscape.width_ = currParams.landscapeRect.width_;
336 portrait.height_ = height;
337 portrait.width_ = width;
338 IMSA_HILOGI("isPortrait now, update portrait size");
339 } else {
340 portrait.height_ = currParams.portraitRect.height_;
341 portrait.width_ = currParams.portraitRect.width_;
342 landscape.height_ = height;
343 landscape.width_ = width;
344 IMSA_HILOGI("isLandscapeRect now, update landscape size");
345 }
346 }
347
UpdateResizeParams()348 void InputMethodPanel::UpdateResizeParams()
349 {
350 auto layoutParams = GetKeyboardLayoutParams();
351 if (IsDisplayUnfolded()) {
352 std::lock_guard<std::mutex> lock(unfoldResizeParamMutex_);
353 IMSA_HILOGI("foldable device without fold state");
354 resizePanelUnfoldParams_ = { layoutParams.LandscapeKeyboardRect_, layoutParams.PortraitKeyboardRect_ };
355 } else {
356 std::lock_guard<std::mutex> lock(foldResizeParamMutex_);
357 IMSA_HILOGI("foldable device in fold state or non-foldable device");
358 resizePanelFoldParams_ = { layoutParams.LandscapeKeyboardRect_, layoutParams.PortraitKeyboardRect_ };
359 }
360 }
361
ResizeEnhancedPanel(uint32_t width,uint32_t height)362 int32_t InputMethodPanel::ResizeEnhancedPanel(uint32_t width, uint32_t height)
363 {
364 auto layoutParam = GetEnhancedLayoutParams();
365 auto ret = GetResizeParams(layoutParam.portrait.rect, layoutParam.landscape.rect, width, height);
366 if (ret != ErrorCode::NO_ERROR) {
367 IMSA_HILOGE("failed to GetResizeParams, ret: %{public}d", ret);
368 return ret;
369 }
370 auto hotAreas = GetHotAreas();
371 ret = AdjustPanelRect(panelFlag_, layoutParam, hotAreas);
372 if (ret != ErrorCode::NO_ERROR) {
373 IMSA_HILOGE("failed to AdjustPanelRect, ret: %{public}d", ret);
374 return ErrorCode::ERROR_OPERATE_PANEL;
375 }
376 std::lock_guard<std::mutex> lock(keyboardSizeLock_);
377 keyboardSize_ = { width, height };
378 IMSA_HILOGI("success, width/height: %{public}u/%{public}u.", width, height);
379 return ErrorCode::NO_ERROR;
380 }
381
ResizeWithoutAdjust(uint32_t width,uint32_t height)382 int32_t InputMethodPanel::ResizeWithoutAdjust(uint32_t width, uint32_t height)
383 {
384 if (!IsSizeValid(width, height)) {
385 IMSA_HILOGE("size is invalid!");
386 return ErrorCode::ERROR_BAD_PARAMETERS;
387 }
388 auto ret = window_->Resize(width, height);
389 if (ret != WMError::WM_OK) {
390 IMSA_HILOGE("failed to resize, ret: %{public}d", ret);
391 return ErrorCode::ERROR_OPERATE_PANEL;
392 }
393 std::lock_guard<std::mutex> lock(keyboardSizeLock_);
394 keyboardSize_ = { width, height };
395 IMSA_HILOGI("success, width/height: %{public}u/%{public}u.", width, height);
396 return ErrorCode::NO_ERROR;
397 }
398
ResizePanel(uint32_t width,uint32_t height)399 int32_t InputMethodPanel::ResizePanel(uint32_t width, uint32_t height)
400 {
401 if (!IsSizeValid(width, height)) {
402 IMSA_HILOGE("size is invalid!");
403 return ErrorCode::ERROR_BAD_PARAMETERS;
404 }
405 auto currentParams = GetEnhancedLayoutParams();
406 LayoutParams targetParams = { .landscapeRect = currentParams.landscape.rect,
407 .portraitRect = currentParams.portrait.rect };
408 auto ret = GetResizeParams(targetParams.portraitRect, targetParams.landscapeRect, width, height);
409 if (ret != ErrorCode::NO_ERROR) {
410 IMSA_HILOGE("failed to GetResizeParams, ret: %{public}d", ret);
411 return ret;
412 }
413 ret = AdjustPanelRect(panelFlag_, targetParams);
414 if (ret != ErrorCode::NO_ERROR) {
415 IMSA_HILOGE("failed to resize, ret: %{public}d", ret);
416 return ErrorCode::ERROR_OPERATE_PANEL;
417 }
418 std::lock_guard<std::mutex> lock(keyboardSizeLock_);
419 keyboardSize_ = { width, height };
420 IMSA_HILOGI("success, width/height: %{public}u/%{public}u.", width, height);
421 return ErrorCode::NO_ERROR;
422 }
423
Resize(uint32_t width,uint32_t height)424 int32_t InputMethodPanel::Resize(uint32_t width, uint32_t height)
425 {
426 if (window_ == nullptr) {
427 IMSA_HILOGE("window is nullptr!");
428 return ErrorCode::ERROR_NULL_POINTER;
429 }
430 if (!isScbEnable_ || window_->GetType() != WindowType::WINDOW_TYPE_INPUT_METHOD_FLOAT) {
431 return ResizeWithoutAdjust(width, height);
432 }
433 if (isInEnhancedAdjust_.load()) {
434 return ResizeEnhancedPanel(width, height);
435 }
436 return ResizePanel(width, height);
437 }
438
MovePanelRect(int32_t x,int32_t y)439 int32_t InputMethodPanel::MovePanelRect(int32_t x, int32_t y)
440 {
441 auto currentParams = GetEnhancedLayoutParams();
442 LayoutParams params = { currentParams.landscape.rect, currentParams.portrait.rect };
443 if (IsDisplayPortrait()) {
444 params.portraitRect.posX_ = x;
445 params.portraitRect.posY_ = y;
446 IMSA_HILOGI("isPortrait now, updata portrait size");
447 } else {
448 params.landscapeRect.posX_ = x;
449 params.landscapeRect.posY_ = y;
450 IMSA_HILOGI("isLandscapeRect now, updata landscape size");
451 }
452 auto ret = AdjustPanelRect(panelFlag_, params, false);
453 IMSA_HILOGI("x/y: %{public}d/%{public}d, ret = %{public}d", x, y, ret);
454 return ret == ErrorCode::NO_ERROR ? ErrorCode::NO_ERROR : ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
455 }
456
MoveEnhancedPanelRect(int32_t x,int32_t y)457 int32_t InputMethodPanel::MoveEnhancedPanelRect(int32_t x, int32_t y)
458 {
459 auto params = GetEnhancedLayoutParams();
460 if (IsDisplayPortrait()) {
461 params.portrait.rect.posX_ = x;
462 params.portrait.rect.posY_ = y;
463 } else {
464 params.landscape.rect.posX_ = x;
465 params.landscape.rect.posY_ = y;
466 }
467 auto hotAreas = GetHotAreas();
468 auto ret = AdjustPanelRect(panelFlag_, params, hotAreas);
469 IMSA_HILOGI("x/y: %{public}d/%{public}d, ret = %{public}d", x, y, ret);
470 return ret == ErrorCode::NO_ERROR ? ErrorCode::NO_ERROR : ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
471 }
472
MoveTo(int32_t x,int32_t y)473 int32_t InputMethodPanel::MoveTo(int32_t x, int32_t y)
474 {
475 if (window_ == nullptr) {
476 IMSA_HILOGE("window_ is nullptr!");
477 return ErrorCode::ERROR_NULL_POINTER;
478 }
479 if (panelType_ == SOFT_KEYBOARD && panelFlag_ == FLG_FIXED) {
480 IMSA_HILOGE("FLG_FIXED panel can not moveTo!");
481 return ErrorCode::NO_ERROR;
482 }
483 if (!isScbEnable_ || window_->GetType() != WindowType::WINDOW_TYPE_INPUT_METHOD_FLOAT) {
484 auto ret = window_->MoveTo(x, y);
485 IMSA_HILOGI("x/y: %{public}d/%{public}d, ret = %{public}d", x, y, ret);
486 return ret == WMError::WM_ERROR_INVALID_PARAM ? ErrorCode::ERROR_PARAMETER_CHECK_FAILED : ErrorCode::NO_ERROR;
487 } else if (isInEnhancedAdjust_.load()) {
488 return MoveEnhancedPanelRect(x, y);
489 } else {
490 return MovePanelRect(x, y);
491 }
492 }
493
StartMoving()494 int32_t InputMethodPanel::StartMoving()
495 {
496 if (window_ == nullptr) {
497 IMSA_HILOGE("window_ is nullptr!");
498 return ErrorCode::ERROR_IME;
499 }
500 if (panelType_ == PanelType::SOFT_KEYBOARD &&
501 !(panelFlag_ == FLG_FLOATING || panelFlag_ == FLG_CANDIDATE_COLUMN)) {
502 IMSA_HILOGE("invalid panel flag: %{public}d", panelFlag_);
503 return ErrorCode::ERROR_INVALID_PANEL_FLAG;
504 }
505 auto ret = window_->StartMoveWindow();
506 if (ret == WmErrorCode::WM_ERROR_DEVICE_NOT_SUPPORT) {
507 IMSA_HILOGE("window manager service not support error ret = %{public}d.", ret);
508 return ErrorCode::ERROR_DEVICE_UNSUPPORTED;
509 }
510 if (ret != WmErrorCode::WM_OK) {
511 IMSA_HILOGE("window manager service error ret = %{public}d.", ret);
512 return ErrorCode::ERROR_WINDOW_MANAGER;
513 }
514 IMSA_HILOGI("StartMoving success!");
515 return ErrorCode::NO_ERROR;
516 }
517
GetDisplayId(uint64_t & displayId)518 int32_t InputMethodPanel::GetDisplayId(uint64_t &displayId)
519 {
520 if (window_ == nullptr) {
521 IMSA_HILOGE("window_ is nullptr!");
522 return ErrorCode::ERROR_IME;
523 }
524 displayId = window_->GetDisplayId();
525 if (displayId == Rosen::DISPLAY_ID_INVALID) {
526 IMSA_HILOGE("display id invalid!");
527 return ErrorCode::ERROR_WINDOW_MANAGER;
528 }
529 IMSA_HILOGD("GetDisplayId success dispalyId = %{public}" PRIu64 "", displayId);
530 return ErrorCode::NO_ERROR;
531 }
532
AdjustKeyboard()533 int32_t InputMethodPanel::AdjustKeyboard()
534 {
535 isAdjustInfoInitialized_.store(false);
536 int32_t ret = 0;
537 auto params = GetEnhancedLayoutParams();
538 if (isInEnhancedAdjust_.load()) {
539 DisplaySize displaySize;
540 ret = GetDisplaySize(displaySize);
541 if (ret != ErrorCode::NO_ERROR) {
542 IMSA_HILOGE("failed to GetDisplaySize ret: %{public}d", ret);
543 return ret;
544 }
545 params.portrait.avoidY = static_cast<int32_t>(displaySize.portrait.height - params.portrait.avoidHeight);
546 params.landscape.avoidY = static_cast<int32_t>(displaySize.landscape.height - params.landscape.avoidHeight);
547 auto hotAreas = GetHotAreas();
548 ret = AdjustPanelRect(panelFlag_, params, hotAreas);
549 } else {
550 LayoutParams layoutParams = { params.landscape.rect, params.portrait.rect };
551 ret = AdjustPanelRect(panelFlag_, layoutParams);
552 }
553 if (ret != ErrorCode::NO_ERROR) {
554 IMSA_HILOGE("failed to adjust keyboard, ret: %{public}d", ret);
555 return ErrorCode::ERROR_OPERATE_PANEL;
556 }
557 IMSA_HILOGI("adjust keyboard success");
558 return ErrorCode::NO_ERROR;
559 }
560
AdjustPanelRect(const PanelFlag panelFlag,const LayoutParams & layoutParams,bool needUpdateRegion)561 int32_t InputMethodPanel::AdjustPanelRect(
562 const PanelFlag panelFlag, const LayoutParams &layoutParams, bool needUpdateRegion)
563 {
564 if (window_ == nullptr) {
565 IMSA_HILOGE("window_ is nullptr!");
566 return ErrorCode::ERROR_WINDOW_MANAGER;
567 }
568 KeyboardLayoutParams resultParams;
569 int32_t result = ParseParams(panelFlag, layoutParams, resultParams);
570 if (result != ErrorCode::NO_ERROR) {
571 IMSA_HILOGE("failed to parse panel rect, result: %{public}d!", result);
572 return result;
573 }
574 auto ret = AdjustLayout(resultParams);
575 if (ret != ErrorCode::NO_ERROR) {
576 IMSA_HILOGE("AdjustPanelRect error, err: %{public}d!", ret);
577 return ErrorCode::ERROR_WINDOW_MANAGER;
578 }
579 UpdateLayoutInfo(panelFlag, layoutParams, {}, resultParams, false);
580 UpdateResizeParams();
581 if (needUpdateRegion) {
582 UpdateHotAreas();
583 }
584 IMSA_HILOGI("success, type/flag: %{public}d/%{public}d.", static_cast<int32_t>(panelType_),
585 static_cast<int32_t>(panelFlag_));
586 return ErrorCode::NO_ERROR;
587 }
588
ConvertToWMSParam(PanelFlag panelFlag,const EnhancedLayoutParams & layoutParams)589 Rosen::KeyboardLayoutParams InputMethodPanel::ConvertToWMSParam(
590 PanelFlag panelFlag, const EnhancedLayoutParams &layoutParams)
591 {
592 Rosen::KeyboardLayoutParams wmsParams;
593 if (panelFlag == PanelFlag::FLG_FIXED) {
594 wmsParams.gravity_ = WindowGravity::WINDOW_GRAVITY_BOTTOM;
595 } else {
596 wmsParams.gravity_ = WindowGravity::WINDOW_GRAVITY_FLOAT;
597 }
598 wmsParams.LandscapeKeyboardRect_ = layoutParams.landscape.rect;
599 wmsParams.LandscapePanelRect_ = layoutParams.landscape.panelRect;
600 wmsParams.PortraitKeyboardRect_ = layoutParams.portrait.rect;
601 wmsParams.PortraitPanelRect_ = layoutParams.portrait.panelRect;
602 wmsParams.portraitAvoidHeight_ = layoutParams.portrait.avoidHeight;
603 wmsParams.landscapeAvoidHeight_ = layoutParams.landscape.avoidHeight;
604 return wmsParams;
605 }
606
ConvertToWMSHotArea(const HotAreas & hotAreas)607 Rosen::KeyboardTouchHotAreas InputMethodPanel::ConvertToWMSHotArea(const HotAreas &hotAreas)
608 {
609 return { .landscapeKeyboardHotAreas_ = hotAreas.landscape.keyboardHotArea,
610 .portraitKeyboardHotAreas_ = hotAreas.portrait.keyboardHotArea,
611 .landscapePanelHotAreas_ = hotAreas.landscape.panelHotArea,
612 .portraitPanelHotAreas_ = hotAreas.portrait.panelHotArea };
613 }
614
IsEnhancedParamValid(PanelFlag panelFlag,EnhancedLayoutParams & params)615 int32_t InputMethodPanel::IsEnhancedParamValid(PanelFlag panelFlag, EnhancedLayoutParams ¶ms)
616 {
617 if (window_ == nullptr) {
618 IMSA_HILOGE("window_ is nullptr!");
619 return ErrorCode::ERROR_WINDOW_MANAGER;
620 }
621 if (panelType_ != PanelType::SOFT_KEYBOARD) {
622 IMSA_HILOGE("not soft keyboard panel");
623 return ErrorCode::ERROR_INVALID_PANEL_TYPE;
624 }
625 FullPanelAdjustInfo adjustInfo;
626 auto ret = GetAdjustInfo(panelFlag, adjustInfo);
627 if (ret != ErrorCode::NO_ERROR) {
628 return ret;
629 }
630 ret = ParseEnhancedParams(panelFlag, adjustInfo, params);
631 if (ret != ErrorCode::NO_ERROR) {
632 return ret;
633 }
634 return ErrorCode::NO_ERROR;
635 }
636
AdjustPanelRect(PanelFlag panelFlag,EnhancedLayoutParams params,HotAreas hotAreas)637 int32_t InputMethodPanel::AdjustPanelRect(PanelFlag panelFlag, EnhancedLayoutParams params, HotAreas hotAreas)
638 {
639 if (window_ == nullptr) {
640 IMSA_HILOGE("window_ is nullptr!");
641 return ErrorCode::ERROR_WINDOW_MANAGER;
642 }
643 if (panelType_ != PanelType::SOFT_KEYBOARD) {
644 IMSA_HILOGE("not soft keyboard panel");
645 return ErrorCode::ERROR_INVALID_PANEL_TYPE;
646 }
647 FullPanelAdjustInfo adjustInfo;
648 if (IsNeedConfig()) {
649 auto ret = GetAdjustInfo(panelFlag, adjustInfo);
650 if (ret != ErrorCode::NO_ERROR) {
651 return ret;
652 }
653 }
654 auto ret = ParseEnhancedParams(panelFlag, adjustInfo, params);
655 if (ret != ErrorCode::NO_ERROR) {
656 return ret;
657 }
658 // adjust rect
659 auto lastWmsParam = GetKeyboardLayoutParams();
660 auto lastIsEnhanced = isInEnhancedAdjust_.load();
661 auto lastParams = GetEnhancedLayoutParams();
662 auto lastPanelFlag = panelFlag_;
663 auto wmsParams = ConvertToWMSParam(panelFlag, params);
664 ret = AdjustLayout(wmsParams);
665 if (ret != ErrorCode::NO_ERROR) {
666 IMSA_HILOGE("AdjustKeyboardLayout error, err: %{public}d!", ret);
667 return ErrorCode::ERROR_WINDOW_MANAGER;
668 }
669 UpdateLayoutInfo(panelFlag, {}, params, wmsParams, true);
670 // set hot area
671 CalculateHotAreas(params, wmsParams, adjustInfo, hotAreas);
672 auto wmsHotAreas = ConvertToWMSHotArea(hotAreas);
673 auto result = window_->SetKeyboardTouchHotAreas(wmsHotAreas);
674 if (result != WMError::WM_OK) {
675 IMSA_HILOGE("SetKeyboardTouchHotAreas error, err: %{public}d!", result);
676 ret = AdjustLayout(lastWmsParam);
677 UpdateLayoutInfo(lastPanelFlag, {}, lastParams, lastWmsParam, lastIsEnhanced);
678 IMSA_HILOGE("restore layout param, result: %{public}d", ret);
679 return ErrorCode::ERROR_WINDOW_MANAGER;
680 }
681 SetHotAreas(hotAreas);
682 UpdateResizeParams();
683 IMSA_HILOGI("success, type/flag: %{public}d/%{public}d.", static_cast<int32_t>(panelType_),
684 static_cast<int32_t>(panelFlag_));
685 return ErrorCode::NO_ERROR;
686 }
687
UpdateLayoutInfo(PanelFlag panelFlag,const LayoutParams & params,const EnhancedLayoutParams & enhancedParams,const KeyboardLayoutParams & wmsParams,bool isEnhanced)688 void InputMethodPanel::UpdateLayoutInfo(PanelFlag panelFlag, const LayoutParams ¶ms,
689 const EnhancedLayoutParams &enhancedParams, const KeyboardLayoutParams &wmsParams, bool isEnhanced)
690 {
691 SetKeyboardLayoutParams(wmsParams);
692 if (isEnhanced) {
693 SetEnhancedLayoutParams(enhancedParams);
694 } else {
695 EnhancedLayoutParams enhancedLayoutParams = { .isFullScreen = false,
696 .portrait = { .rect = params.portraitRect },
697 .landscape = { .rect = params.landscapeRect } };
698 SetEnhancedLayoutParams(enhancedLayoutParams);
699 }
700 if (panelFlag_ != panelFlag) {
701 InputMethodAbility::GetInstance().NotifyPanelStatus(true, panelFlag);
702 }
703 panelFlag_ = panelFlag;
704 isInEnhancedAdjust_.store(isEnhanced);
705 }
706
ParseEnhancedParams(PanelFlag panelFlag,const FullPanelAdjustInfo & adjustInfo,EnhancedLayoutParams & params)707 int32_t InputMethodPanel::ParseEnhancedParams(
708 PanelFlag panelFlag, const FullPanelAdjustInfo &adjustInfo, EnhancedLayoutParams ¶ms)
709 {
710 DisplaySize display;
711 auto ret = GetDisplaySize(display);
712 if (ret != ErrorCode::NO_ERROR) {
713 IMSA_HILOGE("failed to GetDisplaySize ret: %{public}d", ret);
714 return ret;
715 }
716 ret = RectifyRect(params.isFullScreen, params.portrait, display.portrait, panelFlag, adjustInfo.portrait);
717 if (ret != ErrorCode::NO_ERROR) {
718 IMSA_HILOGE("RectifyRect portrait failed, ret: %{public}d", ret);
719 return ret;
720 }
721 ret = RectifyRect(params.isFullScreen, params.landscape, display.landscape, panelFlag, adjustInfo.landscape);
722 if (ret != ErrorCode::NO_ERROR) {
723 IMSA_HILOGE("RectifyRect landscape failed, ret: %{public}d", ret);
724 return ret;
725 }
726 ret = CalculateAvoidHeight(params.portrait, display.portrait, panelFlag, adjustInfo.portrait);
727 if (ret != ErrorCode::NO_ERROR) {
728 IMSA_HILOGE("CalculateAvoidHeight portrait failed, ret: %{public}d", ret);
729 return ret;
730 }
731 ret = CalculateAvoidHeight(params.landscape, display.landscape, panelFlag, adjustInfo.landscape);
732 if (ret != ErrorCode::NO_ERROR) {
733 IMSA_HILOGE("CalculateAvoidHeight landscape failed, ret: %{public}d", ret);
734 return ret;
735 }
736 IMSA_HILOGD("success, portrait: %{public}s, landscape: %{public}s", params.portrait.ToString().c_str(),
737 params.landscape.ToString().c_str());
738 return ErrorCode::NO_ERROR;
739 }
740
IsRectValid(const Rosen::Rect & rect,const WindowSize & displaySize)741 bool InputMethodPanel::IsRectValid(const Rosen::Rect &rect, const WindowSize &displaySize)
742 {
743 if (rect.posX_ < 0 || rect.posY_ < 0) {
744 IMSA_HILOGE("posX_ and posY_ cannot be less than 0!");
745 return false;
746 }
747 if (rect.width_ > INT32_MAX || rect.height_ > INT32_MAX) {
748 IMSA_HILOGE("width or height over maximum!");
749 return false;
750 }
751 if (rect.width_ > displaySize.width || rect.height_ > displaySize.height) {
752 IMSA_HILOGE("invalid width or height, target: %{public}u/%{public}u, display: %{public}u/%{public}u",
753 rect.width_, rect.height_, displaySize.width, displaySize.height);
754 return false;
755 }
756 return true;
757 }
758
IsRectValid(PanelFlag panelFlag,const Rosen::Rect & rect,const WindowSize & displaySize)759 bool InputMethodPanel::IsRectValid(PanelFlag panelFlag, const Rosen::Rect &rect, const WindowSize &displaySize)
760 {
761 if (rect.posX_ < 0 || rect.posY_ < 0) {
762 IMSA_HILOGE("posX_ and posY_ cannot be less than 0!");
763 return false;
764 }
765 return IsSizeValid(panelFlag, rect.width_, rect.height_, displaySize.width, displaySize.height);
766 }
767
RectifyRect(bool isFullScreen,EnhancedLayoutParam & layoutParam,const WindowSize & displaySize,PanelFlag panelFlag,const PanelAdjustInfo & adjustInfo)768 int32_t InputMethodPanel::RectifyRect(bool isFullScreen, EnhancedLayoutParam &layoutParam,
769 const WindowSize &displaySize, PanelFlag panelFlag, const PanelAdjustInfo &adjustInfo)
770 {
771 if (isFullScreen) {
772 layoutParam.rect = { ORIGIN_POS_X, ORIGIN_POS_Y, displaySize.width, displaySize.height };
773 layoutParam.panelRect = layoutParam.rect;
774 return ErrorCode::NO_ERROR;
775 }
776 if (!IsRectValid(layoutParam.rect, displaySize)) {
777 return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
778 }
779 layoutParam.rect.height_ = std::max(layoutParam.rect.height_, static_cast<uint32_t>(adjustInfo.bottom));
780 if (panelFlag == PanelFlag::FLG_FIXED) {
781 layoutParam.rect = { FIXED_PANEL_POS_X, static_cast<int32_t>(displaySize.height - layoutParam.rect.height_),
782 displaySize.width, layoutParam.rect.height_ };
783 }
784 layoutParam.panelRect = layoutParam.rect;
785 return ErrorCode::NO_ERROR;
786 }
787
CalculateAvoidHeight(EnhancedLayoutParam & layoutParam,const WindowSize & displaySize,PanelFlag panelFlag,const PanelAdjustInfo & adjustInfo)788 int32_t InputMethodPanel::CalculateAvoidHeight(EnhancedLayoutParam &layoutParam, const WindowSize &displaySize,
789 PanelFlag panelFlag, const PanelAdjustInfo &adjustInfo)
790 {
791 if (layoutParam.avoidY < 0 || layoutParam.avoidY > INT32_MAX) {
792 IMSA_HILOGE("invalid avoidY");
793 return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
794 }
795 if (static_cast<uint32_t>(layoutParam.avoidY) > layoutParam.rect.height_) {
796 IMSA_HILOGE(
797 "invalid avoidY %{public}d, keyboard height %{public}u", layoutParam.avoidY, layoutParam.rect.height_);
798 return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
799 }
800 auto ratio = panelFlag == PanelFlag::FLG_FIXED ? FIXED_SOFT_KEYBOARD_PANEL_RATIO
801 : NON_FIXED_SOFT_KEYBOARD_PANEL_RATIO;
802 uint32_t avoidHeight = layoutParam.rect.height_ - static_cast<uint32_t>(layoutParam.avoidY);
803 if (static_cast<float>(avoidHeight) > displaySize.height * ratio) {
804 IMSA_HILOGE("invalid avoidY: %{public}d, avoidHeight: %{public}u, displayHeight: %{public}u",
805 layoutParam.avoidY, avoidHeight, displaySize.height);
806 return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
807 }
808 if (avoidHeight < static_cast<uint32_t>(adjustInfo.bottom)) {
809 avoidHeight = adjustInfo.bottom;
810 layoutParam.avoidY = static_cast<int32_t>(layoutParam.rect.height_) - static_cast<int32_t>(avoidHeight);
811 IMSA_HILOGI("rectify avoidY to %{public}d", layoutParam.avoidY);
812 }
813 layoutParam.avoidHeight = avoidHeight;
814 return ErrorCode::NO_ERROR;
815 }
816
UpdateHotAreas()817 void InputMethodPanel::UpdateHotAreas()
818 {
819 auto hotAreas = GetHotAreas();
820 if (!hotAreas.isSet) {
821 IMSA_HILOGD("hot area is not customized, no need to update");
822 return;
823 }
824 FullPanelAdjustInfo adjustInfo;
825 auto ret = GetAdjustInfo(panelFlag_, adjustInfo);
826 if (ret != ErrorCode::NO_ERROR) {
827 IMSA_HILOGE("GetAdjustInfo failed ret: %{public}d", ret);
828 return;
829 }
830 auto changeY = GetChangeY();
831 auto layoutParams = GetKeyboardLayoutParams();
832 CalculateDefaultHotArea(layoutParams.LandscapeKeyboardRect_, layoutParams.LandscapePanelRect_,
833 adjustInfo.landscape, hotAreas.landscape, changeY.landscape);
834 CalculateDefaultHotArea(layoutParams.PortraitKeyboardRect_, layoutParams.PortraitPanelRect_, adjustInfo.portrait,
835 hotAreas.portrait, changeY.portrait);
836 auto wmsHotAreas = ConvertToWMSHotArea(hotAreas);
837 WMError result = window_->SetKeyboardTouchHotAreas(wmsHotAreas);
838 if (result != WMError::WM_OK) {
839 IMSA_HILOGE("SetKeyboardTouchHotAreas error, err: %{public}d!", result);
840 return;
841 }
842 SetHotAreas(hotAreas);
843 IMSA_HILOGI("success, portrait: %{public}s, landscape: %{public}s",
844 HotArea::ToString(hotAreas.portrait.keyboardHotArea).c_str(),
845 HotArea::ToString(hotAreas.landscape.keyboardHotArea).c_str());
846 }
847
CalculateHotAreas(const EnhancedLayoutParams & enhancedParams,const Rosen::KeyboardLayoutParams & params,const FullPanelAdjustInfo & adjustInfo,HotAreas & hotAreas)848 void InputMethodPanel::CalculateHotAreas(const EnhancedLayoutParams &enhancedParams,
849 const Rosen::KeyboardLayoutParams ¶ms, const FullPanelAdjustInfo &adjustInfo, HotAreas &hotAreas)
850 {
851 auto changeY = GetChangeY();
852 if (isInEnhancedAdjust_.load()) {
853 CalculateEnhancedHotArea(enhancedParams.portrait, adjustInfo.portrait, hotAreas.portrait, changeY.portrait);
854 CalculateEnhancedHotArea(enhancedParams.landscape, adjustInfo.landscape, hotAreas.landscape, changeY.landscape);
855 } else {
856 CalculateHotArea(params.PortraitKeyboardRect_, params.PortraitPanelRect_, adjustInfo.portrait,
857 hotAreas.portrait, changeY.portrait);
858 CalculateHotArea(params.LandscapeKeyboardRect_, params.LandscapePanelRect_, adjustInfo.landscape,
859 hotAreas.landscape, changeY.landscape);
860 }
861 hotAreas.isSet = true;
862 IMSA_HILOGD("portrait keyboard: %{public}s, panel: %{public}s",
863 HotArea::ToString(hotAreas.portrait.keyboardHotArea).c_str(),
864 HotArea::ToString(hotAreas.portrait.panelHotArea).c_str());
865 IMSA_HILOGD("landscape keyboard: %{public}s, panel: %{public}s",
866 HotArea::ToString(hotAreas.landscape.keyboardHotArea).c_str(),
867 HotArea::ToString(hotAreas.landscape.panelHotArea).c_str());
868 }
869
CalculateHotArea(const Rosen::Rect & keyboard,const Rosen::Rect & panel,const PanelAdjustInfo & adjustInfo,HotArea & hotArea,uint32_t changeY)870 void InputMethodPanel::CalculateHotArea(const Rosen::Rect &keyboard, const Rosen::Rect &panel,
871 const PanelAdjustInfo &adjustInfo, HotArea &hotArea, uint32_t changeY)
872 {
873 IMSA_HILOGI("changeY: %{public}u", changeY);
874 // calculate keyboard hot area
875 if (hotArea.keyboardHotArea.empty()) {
876 hotArea.keyboardHotArea.push_back({ ORIGIN_POS_X, ORIGIN_POS_Y, keyboard.width_, keyboard.height_ });
877 }
878 std::vector<Rosen::Rect> availableAreas = { { { ORIGIN_POS_X, ORIGIN_POS_Y, keyboard.width_, keyboard.height_ } } };
879 RectifyAreas(availableAreas, hotArea.keyboardHotArea);
880 // calculate panel hot area
881 Rosen::Rect left = { ORIGIN_POS_X, ORIGIN_POS_Y + static_cast<int32_t>(changeY),
882 static_cast<uint32_t>(adjustInfo.left), panel.height_ };
883 Rosen::Rect right = { .posX_ = static_cast<int32_t>(panel.width_) - adjustInfo.right,
884 .posY_ = ORIGIN_POS_Y + static_cast<int32_t>(changeY),
885 .width_ = static_cast<uint32_t>(adjustInfo.right),
886 .height_ = panel.height_ };
887 Rosen::Rect bottom = { .posX_ = ORIGIN_POS_X,
888 .posY_ = static_cast<int32_t>(panel.height_ + changeY) - adjustInfo.bottom,
889 .width_ = panel.width_,
890 .height_ = static_cast<uint32_t>(adjustInfo.bottom) };
891 hotArea.panelHotArea = { left, right, bottom };
892 }
893
CalculateEnhancedHotArea(const EnhancedLayoutParam & layout,const PanelAdjustInfo & adjustInfo,HotArea & hotArea,uint32_t changeY)894 void InputMethodPanel::CalculateEnhancedHotArea(
895 const EnhancedLayoutParam &layout, const PanelAdjustInfo &adjustInfo, HotArea &hotArea, uint32_t changeY)
896 {
897 IMSA_HILOGI("changeY: %{public}u", changeY);
898 // calculate keyboard hot area
899 if (hotArea.keyboardHotArea.empty()) {
900 hotArea.keyboardHotArea.push_back({ ORIGIN_POS_X, ORIGIN_POS_Y, layout.rect.width_, layout.rect.height_ });
901 }
902 std::vector<Rosen::Rect> availableAreas;
903 availableAreas.push_back({ ORIGIN_POS_X, ORIGIN_POS_Y, layout.rect.width_, static_cast<uint32_t>(layout.avoidY) });
904 availableAreas.push_back({ .posX_ = adjustInfo.left,
905 .posY_ = layout.avoidY,
906 .width_ = SafeSubtract(layout.rect.width_, static_cast<uint32_t>(adjustInfo.left + adjustInfo.right)),
907 .height_ = SafeSubtract(layout.avoidHeight, static_cast<uint32_t>(adjustInfo.bottom)) });
908 RectifyAreas(availableAreas, hotArea.keyboardHotArea);
909 // calculate panel hot area
910 Rosen::Rect left = { ORIGIN_POS_X, layout.avoidY + static_cast<int32_t>(changeY),
911 static_cast<uint32_t>(adjustInfo.left), layout.avoidHeight };
912 Rosen::Rect right = { .posX_ = static_cast<int32_t>(layout.rect.width_) - adjustInfo.right,
913 .posY_ = layout.avoidY + static_cast<int32_t>(changeY),
914 .width_ = static_cast<uint32_t>(adjustInfo.right),
915 .height_ = layout.avoidHeight };
916 Rosen::Rect bottom = { .posX_ = ORIGIN_POS_X,
917 .posY_ = static_cast<int32_t>(layout.rect.height_ + changeY) - adjustInfo.bottom,
918 .width_ = layout.rect.width_,
919 .height_ = static_cast<uint32_t>(adjustInfo.bottom) };
920 hotArea.panelHotArea = { left, right, bottom };
921 }
922
CalculateDefaultHotArea(const Rosen::Rect & keyboard,const Rosen::Rect & panel,const PanelAdjustInfo & adjustInfo,HotArea & hotArea,uint32_t changeY)923 void InputMethodPanel::CalculateDefaultHotArea(const Rosen::Rect &keyboard, const Rosen::Rect &panel,
924 const PanelAdjustInfo &adjustInfo, HotArea &hotArea, uint32_t changeY)
925 {
926 IMSA_HILOGI("changeY: %{public}u", changeY);
927 // calculate keyboard hot area
928 hotArea.keyboardHotArea.clear();
929 hotArea.keyboardHotArea.push_back({ ORIGIN_POS_X, ORIGIN_POS_Y, keyboard.width_, keyboard.height_ });
930 // calculate panel hot area
931 Rosen::Rect left = { ORIGIN_POS_X, ORIGIN_POS_Y + static_cast<int32_t>(changeY),
932 static_cast<uint32_t>(adjustInfo.left), panel.height_ };
933 Rosen::Rect right = { .posX_ = static_cast<int32_t>(panel.width_) - adjustInfo.right,
934 .posY_ = ORIGIN_POS_Y + static_cast<int32_t>(changeY),
935 .width_ = static_cast<uint32_t>(adjustInfo.right),
936 .height_ = panel.height_ };
937 Rosen::Rect bottom = { .posX_ = ORIGIN_POS_X,
938 .posY_ = static_cast<int32_t>(panel.height_ + changeY) - adjustInfo.bottom,
939 .width_ = panel.width_,
940 .height_ = static_cast<uint32_t>(adjustInfo.bottom) };
941 hotArea.panelHotArea = { left, right, bottom };
942 }
943
RectifyAreas(const std::vector<Rosen::Rect> & availableAreas,std::vector<Rosen::Rect> & areas)944 void InputMethodPanel::RectifyAreas(const std::vector<Rosen::Rect> &availableAreas, std::vector<Rosen::Rect> &areas)
945 {
946 std::vector<Rosen::Rect> validAreas;
947 for (const auto &availableArea : availableAreas) {
948 std::vector<Rosen::Rect> modifiedAreas;
949 for (const auto &area : areas) {
950 auto inter = GetRectIntersection(area, availableArea);
951 if (inter.width_ != 0 && inter.height_ != 0) {
952 modifiedAreas.push_back(inter);
953 }
954 }
955 validAreas.insert(validAreas.end(), modifiedAreas.begin(), modifiedAreas.end());
956 }
957 areas = std::move(validAreas);
958 // If no valid area, set the region size to 0.
959 if (areas.empty()) {
960 areas.push_back({ 0, 0, 0, 0 });
961 }
962 }
963
GetRectIntersection(Rosen::Rect a,Rosen::Rect b)964 Rosen::Rect InputMethodPanel::GetRectIntersection(Rosen::Rect a, Rosen::Rect b)
965 {
966 int32_t left = std::max(a.posX_, b.posX_);
967 int32_t right = std::min(a.posX_ + static_cast<int32_t>(a.width_), b.posX_ + static_cast<int32_t>(b.width_));
968 int32_t top = std::max(a.posY_, b.posY_);
969 int32_t bottom = std::min(a.posY_ + static_cast<int32_t>(a.height_), b.posY_ + static_cast<int32_t>(b.height_));
970 if (left < right && top < bottom) {
971 return { left, top, static_cast<uint32_t>(right - left), static_cast<uint32_t>(bottom - top) };
972 } else {
973 return { 0, 0, 0, 0 };
974 }
975 }
976
SafeSubtract(uint32_t minuend,uint32_t subtrahend)977 uint32_t InputMethodPanel::SafeSubtract(uint32_t minuend, uint32_t subtrahend)
978 {
979 if (minuend < subtrahend) {
980 IMSA_HILOGE("subtrahend:%{public}u is larger than minuend:%{public}u", subtrahend, minuend);
981 return 0;
982 }
983 return minuend - subtrahend;
984 }
985
UpdateRegion(std::vector<Rosen::Rect> region)986 int32_t InputMethodPanel::UpdateRegion(std::vector<Rosen::Rect> region)
987 {
988 if (window_ == nullptr) {
989 IMSA_HILOGE("window_ is nullptr!");
990 return ErrorCode::ERROR_WINDOW_MANAGER;
991 }
992 if (panelType_ != PanelType::SOFT_KEYBOARD) {
993 IMSA_HILOGE("not soft keyboard panel: %{public}d", panelType_);
994 return ErrorCode::ERROR_INVALID_PANEL_TYPE;
995 }
996 if (panelFlag_ != PanelFlag::FLG_FIXED && panelFlag_ != PanelFlag::FLG_FLOATING) {
997 IMSA_HILOGE("flag not fixed or floating: %{public}d", panelFlag_);
998 return ErrorCode::ERROR_INVALID_PANEL_FLAG;
999 }
1000 FullPanelAdjustInfo adjustInfo;
1001 auto ret = GetAdjustInfo(panelFlag_, adjustInfo);
1002 if (ret != ErrorCode::NO_ERROR) {
1003 IMSA_HILOGE("GetAdjustInfo failed ret: %{public}d", ret);
1004 return ret;
1005 }
1006 IMSA_HILOGD("region: %{public}s", HotArea::ToString(region).c_str());
1007 auto hotAreas = GetHotAreas();
1008 bool isPortrait = IsDisplayPortrait();
1009 if (isPortrait) {
1010 hotAreas.portrait.keyboardHotArea = region;
1011 } else {
1012 hotAreas.landscape.keyboardHotArea = region;
1013 }
1014 CalculateHotAreas(GetEnhancedLayoutParams(), GetKeyboardLayoutParams(), adjustInfo, hotAreas);
1015 auto wmsHotAreas = ConvertToWMSHotArea(hotAreas);
1016 WMError result = window_->SetKeyboardTouchHotAreas(wmsHotAreas);
1017 if (result != WMError::WM_OK) {
1018 IMSA_HILOGE("SetKeyboardTouchHotAreas error, err: %{public}d!", result);
1019 return ErrorCode::ERROR_WINDOW_MANAGER;
1020 }
1021 SetHotAreas(hotAreas);
1022 if (isPortrait) {
1023 IMSA_HILOGI("success, portrait: %{public}s", HotArea::ToString(hotAreas.portrait.keyboardHotArea).c_str());
1024 } else {
1025 IMSA_HILOGI("success, landscape: %{public}s", HotArea::ToString(hotAreas.landscape.keyboardHotArea).c_str());
1026 }
1027 return ErrorCode::NO_ERROR;
1028 }
1029
InitAdjustInfo()1030 int32_t InputMethodPanel::InitAdjustInfo()
1031 {
1032 std::lock_guard<std::mutex> initLk(adjustInfoInitLock_);
1033 auto curDisplayId = GetCurDisplayId();
1034 if (isAdjustInfoInitialized_.load() && adjustInfoDisplayId_ == curDisplayId) {
1035 return ErrorCode::NO_ERROR;
1036 }
1037 std::vector<SysPanelAdjust> configs;
1038 auto isSuccess = SysCfgParser::ParsePanelAdjust(configs);
1039 if (!isSuccess) {
1040 adjustInfoDisplayId_ = curDisplayId;
1041 isAdjustInfoInitialized_.store(true);
1042 return ErrorCode::NO_ERROR;
1043 }
1044 float densityDpi = 0;
1045 if (GetDensityDpi(densityDpi) != ErrorCode::NO_ERROR) {
1046 IMSA_HILOGE("failed to get density dpi");
1047 return ErrorCode::ERROR_WINDOW_MANAGER;
1048 }
1049 std::lock_guard<std::mutex> lk(panelAdjustLock_);
1050 panelAdjust_.clear();
1051 for (const auto &config : configs) {
1052 PanelAdjustInfo info = {
1053 .top = static_cast<int32_t>(config.top * densityDpi),
1054 .left = static_cast<int32_t>(config.left * densityDpi),
1055 .right = static_cast<int32_t>(config.right * densityDpi),
1056 .bottom = static_cast<int32_t>(config.bottom * densityDpi) };
1057 panelAdjust_.insert({ config.style, info });
1058 }
1059 adjustInfoDisplayId_ = curDisplayId;
1060 isAdjustInfoInitialized_.store(true);
1061 return ErrorCode::NO_ERROR;
1062 }
1063
ParseParams(PanelFlag panelFlag,const LayoutParams & input,KeyboardLayoutParams & output)1064 int32_t InputMethodPanel::ParseParams(PanelFlag panelFlag, const LayoutParams &input, KeyboardLayoutParams &output)
1065 {
1066 // 1 - check parameters
1067 DisplaySize displaySize;
1068 int32_t ret = GetDisplaySize(displaySize);
1069 if (ret != ErrorCode::NO_ERROR) {
1070 IMSA_HILOGE("failed to GetDisplaySize ret: %{public}d", ret);
1071 return ErrorCode::ERROR_WINDOW_MANAGER;
1072 }
1073 if (!IsRectValid(panelFlag, input.portraitRect, displaySize.portrait)) {
1074 IMSA_HILOGE("invalid portrait rect!");
1075 return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
1076 }
1077 if (!IsRectValid(panelFlag, input.landscapeRect, displaySize.landscape)) {
1078 IMSA_HILOGE("invalid landscape rect!");
1079 return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
1080 }
1081
1082 // 2 - calculate parameters
1083 FullPanelAdjustInfo adjustInfo;
1084 if (IsNeedConfig()) {
1085 ret = GetAdjustInfo(panelFlag, adjustInfo);
1086 IMSA_HILOGD("get adjust info: %{public}d", ret);
1087 }
1088 EnhancedLayoutParams tempOutput;
1089 ParseParam(panelFlag, adjustInfo.portrait, displaySize.portrait, input.portraitRect, tempOutput.portrait);
1090 ParseParam(panelFlag, adjustInfo.landscape, displaySize.landscape, input.landscapeRect, tempOutput.landscape);
1091 output = ConvertToWMSParam(panelFlag, tempOutput);
1092 output.portraitAvoidHeight_ = DEFAULT_AVOID_HEIGHT;
1093 output.landscapeAvoidHeight_ = DEFAULT_AVOID_HEIGHT;
1094 IMSA_HILOGD("success, portrait: %{public}s, landscape: %{public}s", tempOutput.portrait.ToString().c_str(),
1095 tempOutput.landscape.ToString().c_str());
1096 return ErrorCode::NO_ERROR;
1097 }
1098
ParseParam(PanelFlag panelFlag,const PanelAdjustInfo & adjustInfo,const WindowSize & displaySize,const Rosen::Rect & inputRect,EnhancedLayoutParam & outputParam)1099 void InputMethodPanel::ParseParam(PanelFlag panelFlag, const PanelAdjustInfo &adjustInfo,
1100 const WindowSize &displaySize, const Rosen::Rect &inputRect, EnhancedLayoutParam &outputParam)
1101 {
1102 Rosen::Rect panelRect{};
1103 Rosen::Rect keyboardRect{};
1104 if (panelFlag == PanelFlag::FLG_FIXED) {
1105 // fixed panel rect
1106 panelRect.width_ = displaySize.width;
1107 panelRect.height_ = inputRect.height_ + static_cast<uint32_t>(adjustInfo.top + adjustInfo.bottom);
1108 panelRect.height_ = std::min(panelRect.height_,
1109 static_cast<uint32_t>(static_cast<float>(displaySize.height) * FIXED_SOFT_KEYBOARD_PANEL_RATIO));
1110 panelRect.posX_ = ORIGIN_POS_X;
1111 panelRect.posY_ = static_cast<int32_t>(SafeSubtract(displaySize.height, panelRect.height_));
1112 // fixed keyboard rect
1113 keyboardRect.width_ =
1114 SafeSubtract(panelRect.width_, static_cast<uint32_t>(adjustInfo.left + adjustInfo.right));
1115 keyboardRect.height_ =
1116 SafeSubtract(panelRect.height_, static_cast<uint32_t>(adjustInfo.top + adjustInfo.bottom));
1117 keyboardRect.posY_ = panelRect.posY_ + static_cast<int32_t>(adjustInfo.top);
1118 keyboardRect.posX_ = panelRect.posX_ + static_cast<int32_t>(adjustInfo.left);
1119 } else {
1120 // floating keyboard rect
1121 keyboardRect = inputRect;
1122 // floating panel rect
1123 panelRect.width_ = keyboardRect.width_ + static_cast<uint32_t>(adjustInfo.left + adjustInfo.right);
1124 panelRect.height_ = keyboardRect.height_ + static_cast<uint32_t>(adjustInfo.top + adjustInfo.bottom);
1125 panelRect.posY_ = keyboardRect.posY_ - adjustInfo.top;
1126 panelRect.posX_ = keyboardRect.posX_ - adjustInfo.left;
1127 }
1128 outputParam.rect = keyboardRect;
1129 outputParam.panelRect = panelRect;
1130 }
1131
GetScreenStatus(const PanelFlag panelFlag)1132 std::tuple<std::vector<std::string>, std::vector<std::string>> InputMethodPanel::GetScreenStatus(
1133 const PanelFlag panelFlag)
1134 {
1135 std::string flag = "invaildFlag";
1136 std::string foldStatus = "default";
1137 if (panelFlag == PanelFlag::FLG_FIXED) {
1138 flag = "fix";
1139 } else if (panelFlag == PanelFlag::FLG_FLOATING) {
1140 flag = "floating";
1141 }
1142 if (Rosen::DisplayManager::GetInstance().IsFoldable() &&
1143 Rosen::DisplayManager::GetInstance().GetFoldStatus() != Rosen::FoldStatus::FOLDED) {
1144 foldStatus = "foldable";
1145 }
1146 std::vector<std::string> lanPanel = { flag, foldStatus, "landscape" };
1147 std::vector<std::string> porPanel = { flag, foldStatus, "portrait" };
1148 return std::make_tuple(lanPanel, porPanel);
1149 }
1150
GetAdjustInfo(PanelFlag panelFlag,FullPanelAdjustInfo & fullPanelAdjustInfo)1151 int32_t InputMethodPanel::GetAdjustInfo(PanelFlag panelFlag, FullPanelAdjustInfo &fullPanelAdjustInfo)
1152 {
1153 int32_t ret = InitAdjustInfo();
1154 if (ret != ErrorCode::NO_ERROR) {
1155 IMSA_HILOGE("failed to init adjust info, ret: %{public}d", ret);
1156 return ret;
1157 }
1158 auto keys = GetScreenStatus(panelFlag);
1159 auto landscapeKey = std::get<0>(keys);
1160 auto portraitKey = std::get<1>(keys);
1161 std::lock_guard<std::mutex> lock(panelAdjustLock_);
1162 auto lanIter = panelAdjust_.find(landscapeKey);
1163 auto porIter = panelAdjust_.find(portraitKey);
1164 if (lanIter != panelAdjust_.end()) {
1165 fullPanelAdjustInfo.landscape = lanIter->second;
1166 }
1167 if (porIter != panelAdjust_.end()) {
1168 fullPanelAdjustInfo.portrait = porIter->second;
1169 }
1170 IMSA_HILOGD("GetAdjustInfo, portrait: %{public}s, landscape: %{public}s",
1171 fullPanelAdjustInfo.portrait.ToString().c_str(), fullPanelAdjustInfo.landscape.ToString().c_str());
1172 return ErrorCode::NO_ERROR;
1173 }
1174
ChangePanelFlag(PanelFlag panelFlag)1175 int32_t InputMethodPanel::ChangePanelFlag(PanelFlag panelFlag)
1176 {
1177 if (window_ == nullptr) {
1178 IMSA_HILOGE("window_ is nullptr!");
1179 return ErrorCode::ERROR_NULL_POINTER;
1180 }
1181 if (panelFlag_ == panelFlag) {
1182 return ErrorCode::NO_ERROR;
1183 }
1184 if (panelType_ == STATUS_BAR) {
1185 IMSA_HILOGE("STATUS_BAR cannot ChangePanelFlag!");
1186 return ErrorCode::ERROR_BAD_PARAMETERS;
1187 }
1188 if (panelType_ == SOFT_KEYBOARD && panelFlag == FLG_CANDIDATE_COLUMN) {
1189 PanelStatusChangeToImc(InputWindowStatus::HIDE, { 0, 0, 0, 0 });
1190 }
1191 WindowGravity gravity = WindowGravity::WINDOW_GRAVITY_FLOAT;
1192 if (panelFlag == FLG_FIXED) {
1193 gravity = WindowGravity::WINDOW_GRAVITY_BOTTOM;
1194 } else {
1195 auto surfaceNode = window_->GetSurfaceNode();
1196 if (surfaceNode == nullptr) {
1197 IMSA_HILOGE("surfaceNode is nullptr!");
1198 return ErrorCode::ERROR_NULL_POINTER;
1199 }
1200 surfaceNode->SetFrameGravity(Rosen::Gravity::TOP_LEFT);
1201 Rosen::RSTransactionProxy::GetInstance()->FlushImplicitTransaction();
1202 }
1203 if (!isScbEnable_) {
1204 auto ret = window_->SetWindowGravity(gravity, invalidGravityPercent);
1205 if (ret == WMError::WM_OK) {
1206 panelFlag_ = panelFlag;
1207 }
1208 IMSA_HILOGI("flag: %{public}d, ret: %{public}d.", panelFlag, ret);
1209 return ret == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
1210 }
1211 auto layoutParams = GetKeyboardLayoutParams();
1212 layoutParams.gravity_ = gravity;
1213 auto ret = AdjustLayout(layoutParams);
1214 if (ret == ErrorCode::NO_ERROR) {
1215 panelFlag_ = panelFlag;
1216 SetKeyboardLayoutParams(layoutParams);
1217 }
1218 InputMethodAbility::GetInstance().NotifyPanelStatus(true, panelFlag);
1219 IMSA_HILOGI("flag: %{public}d, ret: %{public}d.", panelFlag, ret);
1220 return ret == ErrorCode::NO_ERROR ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
1221 }
1222
GetPanelType()1223 PanelType InputMethodPanel::GetPanelType()
1224 {
1225 return panelType_;
1226 }
1227
GetPanelFlag()1228 PanelFlag InputMethodPanel::GetPanelFlag()
1229 {
1230 return panelFlag_;
1231 }
1232
ShowPanel()1233 int32_t InputMethodPanel::ShowPanel()
1234 {
1235 IMSA_HILOGD("InputMethodPanel start.");
1236 int32_t waitTime = 0;
1237 while (isWaitSetUiContent_ && waitTime < MAXWAITTIME) {
1238 std::this_thread::sleep_for(std::chrono::milliseconds(WAITTIME));
1239 waitTime += WAITTIME;
1240 IMSA_HILOGI("InputMethodPanel show pannel waitTime %{public}d.", waitTime);
1241 }
1242 if (window_ == nullptr) {
1243 IMSA_HILOGE("window_ is nullptr!");
1244 return ErrorCode::ERROR_IMA_NULLPTR;
1245 }
1246 if (IsShowing()) {
1247 IMSA_HILOGI("panel already shown.");
1248 return ErrorCode::NO_ERROR;
1249 }
1250 auto ret = WMError::WM_OK;
1251 {
1252 KeyboardEffectOption option = ConvertToWmEffect(GetImmersiveMode(), LoadImmersiveEffect());
1253 InputMethodSyncTrace tracer("InputMethodPanel_ShowPanel");
1254 ret = window_->ShowKeyboard(option);
1255 }
1256 if (ret != WMError::WM_OK) {
1257 IMSA_HILOGE("ShowPanel error, err = %{public}d", ret);
1258 return ErrorCode::ERROR_OPERATE_PANEL;
1259 }
1260 IMSA_HILOGI("success, type/flag: %{public}d/%{public}d.", static_cast<int32_t>(panelType_),
1261 static_cast<int32_t>(panelFlag_));
1262 PanelStatusChange(InputWindowStatus::SHOW);
1263 if (!isScbEnable_) {
1264 PanelStatusChangeToImc(InputWindowStatus::SHOW, window_->GetRect());
1265 }
1266 return ErrorCode::NO_ERROR;
1267 }
1268
SetTextFieldAvoidInfo(double positionY,double height)1269 int32_t InputMethodPanel::SetTextFieldAvoidInfo(double positionY, double height)
1270 {
1271 if (window_ == nullptr) {
1272 IMSA_HILOGE("window_ is nullptr!");
1273 return ErrorCode::ERROR_NULL_POINTER;
1274 }
1275 auto ret = window_->SetTextFieldAvoidInfo(positionY, height);
1276 if (ret != WMError::WM_OK) {
1277 IMSA_HILOGE("SetTextFieldAvoidInfo error, err: %{public}d!", ret);
1278 return ErrorCode::ERROR_OPERATE_PANEL;
1279 }
1280 return ErrorCode::NO_ERROR;
1281 }
1282
HidePanel()1283 int32_t InputMethodPanel::HidePanel()
1284 {
1285 IMSA_HILOGD("InputMethodPanel start");
1286 if (window_ == nullptr) {
1287 IMSA_HILOGE("window_ is nullptr!");
1288 return ErrorCode::ERROR_NULL_POINTER;
1289 }
1290 if (IsHidden()) {
1291 IMSA_HILOGI("panel already hidden.");
1292 return ErrorCode::NO_ERROR;
1293 }
1294 auto ret = WMError::WM_OK;
1295 {
1296 InputMethodSyncTrace tracer("InputMethodPanel_HidePanel");
1297 ret = window_->Hide();
1298 }
1299 if (ret != WMError::WM_OK) {
1300 IMSA_HILOGE("HidePanel error, err: %{public}d!", ret);
1301 return ErrorCode::ERROR_OPERATE_PANEL;
1302 }
1303 IMSA_HILOGI("success, type/flag: %{public}d/%{public}d.", static_cast<int32_t>(panelType_),
1304 static_cast<int32_t>(panelFlag_));
1305 PanelStatusChange(InputWindowStatus::HIDE);
1306 if (!isScbEnable_) {
1307 PanelStatusChangeToImc(InputWindowStatus::HIDE, { 0, 0, 0, 0 });
1308 }
1309 return ErrorCode::NO_ERROR;
1310 }
1311
SetCallingWindow(uint32_t windowId)1312 int32_t InputMethodPanel::SetCallingWindow(uint32_t windowId)
1313 {
1314 IMSA_HILOGD("InputMethodPanel start, windowId: %{public}d.", windowId);
1315 if (window_ == nullptr) {
1316 IMSA_HILOGE("window_ is nullptr!");
1317 return ErrorCode::ERROR_PANEL_NOT_FOUND;
1318 }
1319 auto ret = window_->SetCallingWindow(windowId);
1320 IMSA_HILOGI("ret: %{public}d, windowId: %{public}u", ret, windowId);
1321 return ret == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_WINDOW_MANAGER;
1322 }
1323
GetCallingWindowInfo(CallingWindowInfo & windowInfo)1324 int32_t InputMethodPanel::GetCallingWindowInfo(CallingWindowInfo &windowInfo)
1325 {
1326 IMSA_HILOGD("InputMethodPanel start.");
1327 if (window_ == nullptr) {
1328 IMSA_HILOGE("window_ is nullptr!");
1329 return ErrorCode::ERROR_PANEL_NOT_FOUND;
1330 }
1331 auto ret = window_->GetCallingWindowWindowStatus(windowInfo.status);
1332 if (ret != WMError::WM_OK) {
1333 IMSA_HILOGE("get status failed, ret: %{public}d!", ret);
1334 return ErrorCode::ERROR_WINDOW_MANAGER;
1335 }
1336 ret = window_->GetCallingWindowRect(windowInfo.rect);
1337 if (ret != WMError::WM_OK) {
1338 IMSA_HILOGE("get rect failed, ret: %{public}d!", ret);
1339 return ErrorCode::ERROR_WINDOW_MANAGER;
1340 }
1341 IMSA_HILOGI("status: %{public}u, rect[x/y/w/h]: [%{public}d/%{public}d/%{public}u/%{public}u].",
1342 static_cast<uint32_t>(windowInfo.status), windowInfo.rect.posX_, windowInfo.rect.posY_, windowInfo.rect.width_,
1343 windowInfo.rect.height_);
1344 return ErrorCode::NO_ERROR;
1345 }
1346
SetPrivacyMode(bool isPrivacyMode)1347 int32_t InputMethodPanel::SetPrivacyMode(bool isPrivacyMode)
1348 {
1349 IMSA_HILOGD("isPrivacyMode: %{public}d.", isPrivacyMode);
1350 if (window_ == nullptr) {
1351 IMSA_HILOGE("window_ is nullptr!");
1352 return ErrorCode::ERROR_NULL_POINTER;
1353 }
1354 auto ret = window_->SetPrivacyMode(isPrivacyMode);
1355 if (ret != WMError::WM_OK) {
1356 IMSA_HILOGE("SetWindowPrivacyMode error, ret: %{public}d", ret);
1357 return static_cast<int32_t>(ret);
1358 }
1359 IMSA_HILOGD("end, isPrivacyMode: %{public}d.", isPrivacyMode);
1360 return ErrorCode::NO_ERROR;
1361 }
1362
PanelStatusChange(const InputWindowStatus & status)1363 void InputMethodPanel::PanelStatusChange(const InputWindowStatus &status)
1364 {
1365 if (status == InputWindowStatus::SHOW && showRegistered_ && panelStatusListener_ != nullptr) {
1366 IMSA_HILOGD("ShowPanel panelStatusListener_ is not nullptr.");
1367 panelStatusListener_->OnPanelStatus(windowId_, true);
1368 }
1369 if (status == InputWindowStatus::HIDE && hideRegistered_ && panelStatusListener_ != nullptr) {
1370 IMSA_HILOGD("HidePanel panelStatusListener_ is not nullptr.");
1371 panelStatusListener_->OnPanelStatus(windowId_, false);
1372 }
1373 }
1374
PanelStatusChangeToImc(const InputWindowStatus & status,const Rosen::Rect & rect)1375 void InputMethodPanel::PanelStatusChangeToImc(const InputWindowStatus &status, const Rosen::Rect &rect)
1376 {
1377 ImeWindowInfo info;
1378 info.panelInfo.panelType = panelType_;
1379 info.panelInfo.panelFlag = panelFlag_;
1380 if (info.panelInfo.panelType != SOFT_KEYBOARD || info.panelInfo.panelFlag == FLG_CANDIDATE_COLUMN) {
1381 IMSA_HILOGD("no need to deal.");
1382 return;
1383 }
1384 auto proxy = ImaUtils::GetImsaProxy();
1385 if (proxy == nullptr) {
1386 IMSA_HILOGE("proxy is nullptr!");
1387 return;
1388 }
1389
1390 if (window_ == nullptr) {
1391 IMSA_HILOGE("window_ is nullptr!");
1392 return;
1393 }
1394
1395 std::string name = window_->GetWindowName() + "/" + std::to_string(window_->GetWindowId());
1396 info.windowInfo.name = std::move(name);
1397 info.windowInfo.left = rect.posX_;
1398 info.windowInfo.top = rect.posY_;
1399 info.windowInfo.width = rect.width_;
1400 info.windowInfo.height = rect.height_;
1401 IMSA_HILOGD("rect[%{public}d, %{public}d, %{public}u, %{public}u], status: %{public}d, "
1402 "panelFlag: %{public}d.",
1403 rect.posX_, rect.posY_, rect.width_, rect.height_, status, info.panelInfo.panelFlag);
1404 proxy->PanelStatusChange(static_cast<uint32_t>(status), info);
1405 }
1406
IsShowing()1407 bool InputMethodPanel::IsShowing()
1408 {
1409 if (window_ == nullptr) {
1410 IMSA_HILOGE("window_ is nullptr!");
1411 return false;
1412 }
1413 auto windowState = window_->GetWindowState();
1414 if (windowState == WindowState::STATE_SHOWN) {
1415 return true;
1416 }
1417 IMSA_HILOGD("windowState: %{public}d.", static_cast<int>(windowState));
1418 return false;
1419 }
1420
IsHidden()1421 bool InputMethodPanel::IsHidden()
1422 {
1423 auto windowState = window_->GetWindowState();
1424 if (windowState == WindowState::STATE_HIDDEN) {
1425 return true;
1426 }
1427 IMSA_HILOGD("windowState: %{public}d.", static_cast<int>(windowState));
1428 return false;
1429 }
1430
SetUiContent(const std::string & contentInfo,napi_env env,std::shared_ptr<NativeReference> storage)1431 int32_t InputMethodPanel::SetUiContent(
1432 const std::string &contentInfo, napi_env env, std::shared_ptr<NativeReference> storage)
1433 {
1434 if (window_ == nullptr) {
1435 IMSA_HILOGE("window_ is nullptr, can not SetUiContent!");
1436 return ErrorCode::ERROR_NULL_POINTER;
1437 }
1438 WMError ret = WMError::WM_OK;
1439 if (storage == nullptr) {
1440 ret = window_->NapiSetUIContent(contentInfo, env, nullptr);
1441 } else {
1442 ret = window_->NapiSetUIContent(contentInfo, env, storage->GetNapiValue());
1443 }
1444 WMError wmError = window_->SetTransparent(true);
1445 if (isWaitSetUiContent_) {
1446 isWaitSetUiContent_ = false;
1447 }
1448 IMSA_HILOGI("SetTransparent ret: %{public}u.", wmError);
1449 IMSA_HILOGI("NapiSetUIContent ret: %{public}d.", ret);
1450 return ret == WMError::WM_ERROR_INVALID_PARAM ? ErrorCode::ERROR_PARAMETER_CHECK_FAILED : ErrorCode::NO_ERROR;
1451 }
1452
SetPanelStatusListener(std::shared_ptr<PanelStatusListener> statusListener,const std::string & type)1453 bool InputMethodPanel::SetPanelStatusListener(
1454 std::shared_ptr<PanelStatusListener> statusListener, const std::string &type)
1455 {
1456 if (!MarkListener(type, true)) {
1457 return false;
1458 }
1459 IMSA_HILOGD("type: %{public}s.", type.c_str());
1460 if (type == "show" || type == "hide") {
1461 if (panelStatusListener_ == nullptr) {
1462 IMSA_HILOGD("panelStatusListener_ is nullptr, need to be set");
1463 panelStatusListener_ = std::move(statusListener);
1464 }
1465 if (window_ != nullptr) {
1466 if (type == "show" && IsShowing()) {
1467 panelStatusListener_->OnPanelStatus(windowId_, true);
1468 }
1469 if (type == "hide" && IsHidden()) {
1470 panelStatusListener_->OnPanelStatus(windowId_, false);
1471 }
1472 }
1473 }
1474 if (type == "sizeChange" || type == "sizeUpdate") {
1475 return SetPanelSizeChangeListener(statusListener);
1476 }
1477 return true;
1478 }
1479
SetPanelSizeChangeListener(std::shared_ptr<PanelStatusListener> statusListener)1480 bool InputMethodPanel::SetPanelSizeChangeListener(std::shared_ptr<PanelStatusListener> statusListener)
1481 {
1482 if (panelType_ != PanelType::SOFT_KEYBOARD ||
1483 (panelFlag_ != PanelFlag::FLG_FIXED && panelFlag_ != PanelFlag::FLG_FLOATING)) {
1484 return true;
1485 }
1486 if (panelStatusListener_ == nullptr && statusListener != nullptr) {
1487 panelStatusListener_ = std::move(statusListener);
1488 }
1489 std::lock_guard<std::mutex> lock(windowListenerLock_);
1490 if (windowChangedListener_ != nullptr) {
1491 IMSA_HILOGD("windowChangedListener already registered.");
1492 return true;
1493 }
1494 windowChangedListener_ = new (std::nothrow)
1495 WindowChangeListenerImpl([this](WindowSize windowSize) { SizeChange(windowSize); });
1496 if (windowChangedListener_ == nullptr || window_ == nullptr) {
1497 IMSA_HILOGE("observer or window_ is nullptr!");
1498 return false;
1499 }
1500 auto ret = window_->RegisterWindowChangeListener(windowChangedListener_);
1501 if (ret != WMError::WM_OK) {
1502 IMSA_HILOGE("RegisterWindowChangeListener error: %{public}d!", ret);
1503 return false;
1504 }
1505 return true;
1506 }
1507
ClearPanelListener(const std::string & type)1508 void InputMethodPanel::ClearPanelListener(const std::string &type)
1509 {
1510 if (!MarkListener(type, false)) {
1511 return;
1512 }
1513 IMSA_HILOGD("type: %{public}s.", type.c_str());
1514 if (!sizeChangeRegistered_ && !sizeUpdateRegistered_ && windowChangedListener_ != nullptr && window_ != nullptr) {
1515 auto ret = window_->UnregisterWindowChangeListener(windowChangedListener_);
1516 IMSA_HILOGI("UnregisterWindowChangeListener ret: %{public}d.", ret);
1517 windowChangedListener_ = nullptr;
1518 }
1519 if (panelStatusListener_ == nullptr) {
1520 IMSA_HILOGD("panelStatusListener_ not set, don't need to remove.");
1521 return;
1522 }
1523 if (showRegistered_ || hideRegistered_ || sizeChangeRegistered_ || sizeUpdateRegistered_) {
1524 return;
1525 }
1526 panelStatusListener_ = nullptr;
1527 }
1528
GetPanelListener()1529 std::shared_ptr<PanelStatusListener> InputMethodPanel::GetPanelListener()
1530 {
1531 return panelStatusListener_;
1532 }
1533
MarkListener(const std::string & type,bool isRegister)1534 bool InputMethodPanel::MarkListener(const std::string &type, bool isRegister)
1535 {
1536 if (type == "show") {
1537 showRegistered_ = isRegister;
1538 } else if (type == "hide") {
1539 hideRegistered_ = isRegister;
1540 } else if (type == "sizeChange") {
1541 sizeChangeRegistered_ = isRegister;
1542 } else if (type == "sizeUpdate") {
1543 sizeUpdateRegistered_ = isRegister;
1544 } else {
1545 IMSA_HILOGE("type error!");
1546 return false;
1547 }
1548 return true;
1549 }
1550
GenerateSequenceId()1551 uint32_t InputMethodPanel::GenerateSequenceId()
1552 {
1553 uint32_t seqId = ++sequenceId_;
1554 if (seqId == std::numeric_limits<uint32_t>::max()) {
1555 return ++sequenceId_;
1556 }
1557 return seqId;
1558 }
1559
IsSizeValid(uint32_t width,uint32_t height)1560 bool InputMethodPanel::IsSizeValid(uint32_t width, uint32_t height)
1561 {
1562 if (width > INT32_MAX || height > INT32_MAX) {
1563 IMSA_HILOGE("width or height over maximum!");
1564 return false;
1565 }
1566 auto defaultDisplay = GetCurDisplay();
1567 if (defaultDisplay == nullptr) {
1568 IMSA_HILOGE("GetDefaultDisplay failed!");
1569 return false;
1570 }
1571 float ratio = panelType_ == PanelType::SOFT_KEYBOARD && panelFlag_ == PanelFlag::FLG_FIXED ?
1572 FIXED_SOFT_KEYBOARD_PANEL_RATIO :
1573 NON_FIXED_SOFT_KEYBOARD_PANEL_RATIO;
1574 auto defaultDisplayHeight = defaultDisplay->GetHeight();
1575 auto defaultDisplayWidth = defaultDisplay->GetWidth();
1576 if (static_cast<float>(height) > defaultDisplayHeight * ratio ||
1577 static_cast<int32_t>(width) > defaultDisplayWidth) {
1578 IMSA_HILOGE("param is invalid, defaultDisplay height: %{public}d, defaultDisplay width %{public}d, target "
1579 "height: %{public}u, target width: %{public}u!",
1580 defaultDisplayHeight, defaultDisplayWidth, height, width);
1581 return false;
1582 }
1583 return true;
1584 }
1585
GetKeyboardSize()1586 WindowSize InputMethodPanel::GetKeyboardSize()
1587 {
1588 std::lock_guard<std::mutex> lock(keyboardSizeLock_);
1589 return keyboardSize_;
1590 }
1591
SizeChange(const WindowSize & size)1592 int32_t InputMethodPanel::SizeChange(const WindowSize &size)
1593 {
1594 IMSA_HILOGD("InputMethodPanel start.");
1595 IMSA_HILOGI("type/flag: %{public}d/%{public}d, width/height: %{public}d/%{public}d.",
1596 static_cast<int32_t>(panelType_), static_cast<int32_t>(panelFlag_), static_cast<int32_t>(size.width),
1597 static_cast<int32_t>(size.height));
1598 {
1599 std::lock_guard<std::mutex> lock(keyboardSizeLock_);
1600 keyboardSize_ = size;
1601 }
1602 auto listener = GetPanelListener();
1603 if (listener == nullptr) {
1604 IMSA_HILOGD("panelStatusListener_ is nullptr");
1605 return ErrorCode::ERROR_NULL_POINTER;
1606 }
1607 PanelAdjustInfo keyboardArea;
1608 if (isInEnhancedAdjust_.load() && GetKeyboardArea(panelFlag_, size, keyboardArea) != ErrorCode::NO_ERROR) {
1609 IMSA_HILOGE("failed to GetKeyboardArea");
1610 return ErrorCode::ERROR_BAD_PARAMETERS;
1611 }
1612 if (sizeChangeRegistered_) {
1613 listener->OnSizeChange(windowId_, keyboardSize_, keyboardArea, "sizeChange");
1614 }
1615 if (sizeUpdateRegistered_) {
1616 listener->OnSizeChange(windowId_, keyboardSize_, keyboardArea, "sizeUpdate");
1617 }
1618 return ErrorCode::NO_ERROR;
1619 }
1620
GetKeyboardArea(PanelFlag panelFlag,const WindowSize & size,PanelAdjustInfo & keyboardArea)1621 int32_t InputMethodPanel::GetKeyboardArea(PanelFlag panelFlag, const WindowSize &size, PanelAdjustInfo &keyboardArea)
1622 {
1623 bool isPortrait = false;
1624 if (GetWindowOrientation(panelFlag, size.width, isPortrait) != ErrorCode::NO_ERROR) {
1625 IMSA_HILOGE("failed to GetWindowOrientation");
1626 return ErrorCode::ERROR_WINDOW_MANAGER;
1627 }
1628 FullPanelAdjustInfo adjustInfo;
1629 if (GetAdjustInfo(panelFlag, adjustInfo) != ErrorCode::NO_ERROR) {
1630 IMSA_HILOGE("GetAdjustInfo failed");
1631 return ErrorCode::ERROR_BAD_PARAMETERS;
1632 }
1633 if (isPortrait) {
1634 keyboardArea = adjustInfo.portrait;
1635 keyboardArea.top = GetEnhancedLayoutParams().portrait.avoidY;
1636 } else {
1637 keyboardArea = adjustInfo.landscape;
1638 keyboardArea.top = GetEnhancedLayoutParams().landscape.avoidY;
1639 }
1640 return ErrorCode::NO_ERROR;
1641 }
1642
GetWindowOrientation(PanelFlag panelFlag,uint32_t windowWidth,bool & isPortrait)1643 int32_t InputMethodPanel::GetWindowOrientation(PanelFlag panelFlag, uint32_t windowWidth, bool &isPortrait)
1644 {
1645 if (panelFlag != PanelFlag::FLG_FIXED) {
1646 isPortrait = IsDisplayPortrait();
1647 return ErrorCode::NO_ERROR;
1648 }
1649 DisplaySize displaySize;
1650 if (GetDisplaySize(displaySize) != ErrorCode::NO_ERROR) {
1651 IMSA_HILOGE("failed to GetDisplaySize");
1652 return ErrorCode::ERROR_WINDOW_MANAGER;
1653 }
1654 if (displaySize.portrait.width == displaySize.portrait.height) {
1655 isPortrait = IsDisplayPortrait();
1656 return ErrorCode::NO_ERROR;
1657 }
1658 if (windowWidth == displaySize.portrait.width) {
1659 isPortrait = true;
1660 }
1661 if (windowWidth == displaySize.landscape.width) {
1662 isPortrait = false;
1663 }
1664 return ErrorCode::NO_ERROR;
1665 }
1666
RegisterKeyboardPanelInfoChangeListener()1667 void InputMethodPanel::RegisterKeyboardPanelInfoChangeListener()
1668 {
1669 kbPanelInfoListener_ =
1670 new (std::nothrow) KeyboardPanelInfoChangeListener([this](const KeyboardPanelInfo &keyboardPanelInfo) {
1671 OnPanelHeightChange(keyboardPanelInfo);
1672 HandleKbPanelInfoChange(keyboardPanelInfo);
1673 });
1674 if (kbPanelInfoListener_ == nullptr) {
1675 return;
1676 }
1677 if (window_ == nullptr) {
1678 return;
1679 }
1680 auto ret = window_->RegisterKeyboardPanelInfoChangeListener(kbPanelInfoListener_);
1681 IMSA_HILOGD("ret: %{public}d.", ret);
1682 }
1683
OnPanelHeightChange(const Rosen::KeyboardPanelInfo & keyboardPanelInfo)1684 void InputMethodPanel::OnPanelHeightChange(const Rosen::KeyboardPanelInfo &keyboardPanelInfo)
1685 {
1686 auto heightChangeHandler = GetPanelHeightCallback();
1687 if (heightChangeHandler == nullptr) {
1688 return;
1689 }
1690 if (!isInEnhancedAdjust_.load()) {
1691 heightChangeHandler(keyboardPanelInfo.rect_.height_, panelFlag_);
1692 return;
1693 }
1694 bool isPortrait = false;
1695 if (GetWindowOrientation(panelFlag_, keyboardPanelInfo.rect_.width_, isPortrait) != ErrorCode::NO_ERROR) {
1696 IMSA_HILOGE("failed to GetWindowOrientation");
1697 return;
1698 }
1699 if (isPortrait) {
1700 heightChangeHandler(GetEnhancedLayoutParams().portrait.avoidHeight, panelFlag_);
1701 } else {
1702 heightChangeHandler(GetEnhancedLayoutParams().landscape.avoidHeight, panelFlag_);
1703 }
1704 }
1705
UnregisterKeyboardPanelInfoChangeListener()1706 void InputMethodPanel::UnregisterKeyboardPanelInfoChangeListener()
1707 {
1708 if (window_ == nullptr) {
1709 return;
1710 }
1711 auto ret = window_->UnregisterKeyboardPanelInfoChangeListener(kbPanelInfoListener_);
1712 kbPanelInfoListener_ = nullptr;
1713 IMSA_HILOGD("ret: %{public}d.", ret);
1714 }
1715
HandleKbPanelInfoChange(const KeyboardPanelInfo & keyboardPanelInfo)1716 void InputMethodPanel::HandleKbPanelInfoChange(const KeyboardPanelInfo &keyboardPanelInfo)
1717 {
1718 IMSA_HILOGD("start.");
1719 InputWindowStatus status = InputWindowStatus::HIDE;
1720 if (keyboardPanelInfo.isShowing_) {
1721 status = InputWindowStatus::SHOW;
1722 }
1723 PanelStatusChangeToImc(status, keyboardPanelInfo.rect_);
1724 }
1725
IsDisplayPortrait()1726 bool InputMethodPanel::IsDisplayPortrait()
1727 {
1728 auto defaultDisplay = GetCurDisplay();
1729 if (defaultDisplay == nullptr) {
1730 IMSA_HILOGE("GetDefaultDisplay failed!");
1731 return false;
1732 }
1733 auto width = defaultDisplay->GetWidth();
1734 auto height = defaultDisplay->GetHeight();
1735 if (width != height) {
1736 return width < height;
1737 }
1738 auto displayInfo = defaultDisplay->GetDisplayInfo();
1739 if (displayInfo == nullptr) {
1740 IMSA_HILOGE("GetDisplayInfo failed");
1741 return false;
1742 }
1743 auto orientation = displayInfo->GetDisplayOrientation();
1744 IMSA_HILOGI("width equals to height, orientation: %{public}u", static_cast<uint32_t>(orientation));
1745 return orientation == DisplayOrientation::PORTRAIT || orientation == DisplayOrientation::PORTRAIT_INVERTED;
1746 }
1747
IsDisplayUnfolded()1748 bool InputMethodPanel::IsDisplayUnfolded()
1749 {
1750 return Rosen::DisplayManager::GetInstance().IsFoldable() &&
1751 Rosen::DisplayManager::GetInstance().GetFoldStatus() != Rosen::FoldStatus::FOLDED;
1752 }
1753
IsSizeValid(PanelFlag panelFlag,uint32_t width,uint32_t height,int32_t displayWidth,int32_t displayHeight)1754 bool InputMethodPanel::IsSizeValid(
1755 PanelFlag panelFlag, uint32_t width, uint32_t height, int32_t displayWidth, int32_t displayHeight)
1756 {
1757 if (width > INT32_MAX || height > INT32_MAX) {
1758 IMSA_HILOGE("width or height over maximum!");
1759 return false;
1760 }
1761 float ratio = panelType_ == PanelType::SOFT_KEYBOARD && panelFlag == PanelFlag::FLG_FIXED ?
1762 FIXED_SOFT_KEYBOARD_PANEL_RATIO :
1763 NON_FIXED_SOFT_KEYBOARD_PANEL_RATIO;
1764 if (static_cast<float>(height) > displayHeight * ratio || static_cast<int32_t>(width) > displayWidth) {
1765 IMSA_HILOGE("param is invalid, defaultDisplay height: %{public}d, defaultDisplay width %{public}d, target "
1766 "height: %{public}u, target width: %{public}u!",
1767 displayHeight, displayWidth, height, width);
1768 return false;
1769 }
1770 return true;
1771 }
1772
SetPanelHeightCallback(CallbackFunc heightCallback)1773 void InputMethodPanel::SetPanelHeightCallback(CallbackFunc heightCallback)
1774 {
1775 std::lock_guard<std::mutex> lock(heightCallbackMutex_);
1776 panelHeightCallback_ = std::move(heightCallback);
1777 }
1778
GetPanelHeightCallback()1779 InputMethodPanel::CallbackFunc InputMethodPanel::GetPanelHeightCallback()
1780 {
1781 std::lock_guard<std::mutex> lock(heightCallbackMutex_);
1782 return panelHeightCallback_;
1783 }
1784
GetDensityDpi(float & densityDpi)1785 int32_t InputMethodPanel::GetDensityDpi(float &densityDpi)
1786 {
1787 auto defaultDisplay = GetCurDisplay();
1788 if (defaultDisplay == nullptr) {
1789 IMSA_HILOGE("GetDefaultDisplay failed!");
1790 return ErrorCode::ERROR_WINDOW_MANAGER;
1791 }
1792 auto displayInfo = defaultDisplay->GetDisplayInfo();
1793 if (displayInfo == nullptr) {
1794 IMSA_HILOGE("GetDisplayInfo failed!");
1795 return ErrorCode::ERROR_WINDOW_MANAGER;
1796 }
1797 densityDpi = displayInfo->GetDensityInCurResolution();
1798 IMSA_HILOGI("densityDpi: %{public}f", densityDpi);
1799 if (densityDpi <= 0) {
1800 return ErrorCode::ERROR_WINDOW_MANAGER;
1801 }
1802 return ErrorCode::NO_ERROR;
1803 }
1804
GetDisplaySize(DisplaySize & size)1805 int32_t InputMethodPanel::GetDisplaySize(DisplaySize &size)
1806 {
1807 auto defaultDisplay = GetCurDisplay();
1808 if (defaultDisplay == nullptr) {
1809 IMSA_HILOGE("GetDefaultDisplay failed!");
1810 return ErrorCode::ERROR_WINDOW_MANAGER;
1811 }
1812 auto width = defaultDisplay->GetWidth();
1813 auto height = defaultDisplay->GetHeight();
1814 if (width < height) {
1815 size.portrait = { .width = width, .height = height };
1816 size.landscape = { .width = height, .height = width };
1817 } else {
1818 size.portrait = { .width = height, .height = width };
1819 size.landscape = { .width = width, .height = height };
1820 }
1821 return ErrorCode::NO_ERROR;
1822 }
1823
SetImmersiveEffectToNone()1824 void InputMethodPanel::SetImmersiveEffectToNone()
1825 {
1826 auto currentEffect = LoadImmersiveEffect();
1827 if (currentEffect.gradientHeight == 0) {
1828 currentEffect.gradientMode = GradientMode::NONE;
1829 currentEffect.fluidLightMode = FluidLightMode::NONE;
1830 StoreImmersiveEffect(currentEffect);
1831 return;
1832 }
1833
1834 // The SetImmersiveEffect API must be called after the AdjustPanelRect API is called.
1835 auto layoutParams = GetKeyboardLayoutParams();
1836 Rosen::KeyboardLayoutParams emptyParams;
1837 if (layoutParams == emptyParams) {
1838 IMSA_HILOGW("set gradientHeight to zero");
1839 return;
1840 }
1841
1842 currentEffect.gradientHeight = 0;
1843 currentEffect.gradientMode = GradientMode::NONE;
1844 currentEffect.fluidLightMode = FluidLightMode::NONE;
1845 auto ret = AdjustLayout(layoutParams, currentEffect);
1846 if (ret != ErrorCode::NO_ERROR) {
1847 IMSA_HILOGE("adjust failed, ret: %{public}d", ret);
1848 return;
1849 }
1850 StoreImmersiveEffect(currentEffect);
1851 UpdateImmersiveHotArea();
1852 IMSA_HILOGW("set gradientHeight to zero and adjust layout success");
1853 }
1854
SetImmersiveMode(ImmersiveMode mode)1855 int32_t InputMethodPanel::SetImmersiveMode(ImmersiveMode mode)
1856 {
1857 if ((mode != ImmersiveMode::NONE_IMMERSIVE && mode != ImmersiveMode::LIGHT_IMMERSIVE &&
1858 mode != ImmersiveMode::DARK_IMMERSIVE)) {
1859 IMSA_HILOGE("invalid mode: %{public}d", mode);
1860 return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
1861 }
1862
1863 auto currentMode = GetImmersiveMode();
1864 if (!IsShowing()) {
1865 if (mode != currentMode && mode == ImmersiveMode::NONE_IMMERSIVE) {
1866 SetImmersiveEffectToNone();
1867 }
1868 StoreImmersiveMode(mode);
1869 IMSA_HILOGD("window is not show, mode: %{public}d", mode);
1870 return ErrorCode::NO_ERROR;
1871 }
1872
1873 if (window_ == nullptr) {
1874 IMSA_HILOGE("window is null");
1875 return ErrorCode::ERROR_IME;
1876 }
1877
1878 if (mode != currentMode && mode == ImmersiveMode::NONE_IMMERSIVE) {
1879 SetImmersiveEffectToNone();
1880 }
1881 KeyboardEffectOption option = ConvertToWmEffect(mode, LoadImmersiveEffect());
1882 // call window manager to set immersive mode
1883 auto ret = window_->ChangeKeyboardEffectOption(option);
1884 if (ret == WMError::WM_DO_NOTHING) {
1885 IMSA_HILOGW("repeat set mode new:%{public}d, old:%{public}d", mode, currentMode);
1886 return ErrorCode::NO_ERROR;
1887 }
1888 if (ret != WMError::WM_OK) {
1889 IMSA_HILOGE("ChangeKeyboardEffectOption failed, ret: %{public}d", ret);
1890 return ErrorCode::ERROR_WINDOW_MANAGER;
1891 }
1892 StoreImmersiveMode(mode);
1893 IMSA_HILOGI("SetImmersiveMode success, mode: %{public}d", mode);
1894 return ErrorCode::NO_ERROR;
1895 }
1896
IsValidGradientHeight(uint32_t gradientHeight)1897 bool InputMethodPanel::IsValidGradientHeight(uint32_t gradientHeight)
1898 {
1899 if (gradientHeight > INT32_MAX) {
1900 IMSA_HILOGE("gradientHeight over maximum!");
1901 return false;
1902 }
1903 DisplaySize displaySize;
1904 auto ret = GetDisplaySize(displaySize);
1905 if (ret != ErrorCode::NO_ERROR) {
1906 IMSA_HILOGE("Get portrait display size failed, ret: %{public}d", ret);
1907 return false;
1908 }
1909
1910 if (static_cast<float>(gradientHeight) > displaySize.portrait.height * GRADIENT_HEIGHT_RATIO) {
1911 IMSA_HILOGE("invalid gradientHeight:%{public}u, portraitHeight:%{public}u", gradientHeight,
1912 displaySize.portrait.height);
1913 return false;
1914 }
1915
1916 if (static_cast<float>(gradientHeight) > displaySize.landscape.height * GRADIENT_HEIGHT_RATIO) {
1917 IMSA_HILOGE("invalid gradientHeight:%{public}u, landscapeHeight:%{public}u", gradientHeight,
1918 displaySize.landscape.height);
1919 return false;
1920 }
1921
1922 return true;
1923 }
1924
IsValidParam(const ImmersiveEffect & effect,const KeyboardLayoutParams & layoutParams)1925 int32_t InputMethodPanel::IsValidParam(const ImmersiveEffect &effect, const KeyboardLayoutParams &layoutParams)
1926 {
1927 if (effect.gradientMode < GradientMode::NONE || effect.gradientMode >= GradientMode::END ||
1928 effect.fluidLightMode < FluidLightMode::NONE || effect.fluidLightMode >= FluidLightMode::END) {
1929 IMSA_HILOGE("invalid effect, gradientMpde:%{public}d, fluidLightMode:%{public}d", effect.gradientMode,
1930 effect.fluidLightMode);
1931 return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
1932 }
1933
1934 // The gradient mode and the fluid light mode can only be used when the immersive mode is enabled.
1935 if (GetImmersiveMode() == ImmersiveMode::NONE_IMMERSIVE) {
1936 if (effect.gradientMode != GradientMode::NONE || effect.fluidLightMode != FluidLightMode::NONE ||
1937 effect.gradientHeight != 0) {
1938 IMSA_HILOGE("immersiveMode is NONE, but gradientMode=%{public}d, fluidLightMode=%{public}d",
1939 effect.gradientMode, effect.fluidLightMode);
1940 return ErrorCode::ERROR_IMA_INVALID_IMMERSIVE_EFFECT;
1941 }
1942 return ErrorCode::NO_ERROR;
1943 }
1944
1945 // The fluid light mode can only be used when the gradient mode is enabled.
1946 if (effect.gradientMode == GradientMode::NONE && effect.fluidLightMode != FluidLightMode::NONE) {
1947 IMSA_HILOGE("gradientMode is NONE, but fluidLightMode=%{public}d", effect.fluidLightMode);
1948 return ErrorCode::ERROR_IMA_INVALID_IMMERSIVE_EFFECT;
1949 }
1950
1951 if (effect.gradientMode == GradientMode::NONE && effect.gradientHeight != 0) {
1952 IMSA_HILOGE("gradientMode is NONE, but gradientHeight:%{public}u", effect.gradientHeight);
1953 return ErrorCode::ERROR_IMA_INVALID_IMMERSIVE_EFFECT;
1954 }
1955
1956 // Only system applications can set the fluid light mode.
1957 if (!InputMethodAbility::GetInstance().IsSystemApp() && effect.fluidLightMode != FluidLightMode::NONE) {
1958 IMSA_HILOGE("only system app can set fluidLightMode:%{public}d", effect.fluidLightMode);
1959 return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
1960 }
1961
1962 // The gradient height cannot be greater than the screen height * GRADIENT_HEIGHT_RATIO.
1963 if (!IsValidGradientHeight(effect.gradientHeight)) {
1964 return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
1965 }
1966
1967 // The SetImmersiveEffect API must be called after the AdjustPanelRect API is called.
1968 Rosen::KeyboardLayoutParams emptyParams;
1969 if (layoutParams == emptyParams) {
1970 IMSA_HILOGE("adjust is not call, %{public}s", effect.ToString().c_str());
1971 return ErrorCode::ERROR_IMA_PRECONDITION_REQUIRED;
1972 }
1973 return ErrorCode::NO_ERROR;
1974 }
1975
IsImmersiveEffectSupported()1976 bool InputMethodPanel::IsImmersiveEffectSupported()
1977 {
1978 static int32_t isSupport = 0;
1979 static std::mutex isSupportMutex;
1980 if (isSupport != 0) {
1981 return isSupport == 1 ? true : false;
1982 }
1983
1984 std::lock_guard<std::mutex> lock(isSupportMutex);
1985 bool isSupportTemp = false;
1986 int32_t ret = InputMethodAbility::GetInstance().IsCapacitySupport(
1987 static_cast<int32_t>(CapacityType::IMMERSIVE_EFFECT), isSupportTemp);
1988 if (ret != ErrorCode::NO_ERROR) {
1989 IMSA_HILOGE("IsCapacitySupport failed, ret:%{public}d", ret);
1990 return false;
1991 }
1992
1993 if (isSupportTemp) {
1994 isSupport = 1;
1995 } else {
1996 isSupport = -1;
1997 }
1998 IMSA_HILOGI("isSupportTemp:%{public}d", isSupportTemp);
1999 return isSupportTemp;
2000 }
2001
ConvertToWmEffect(ImmersiveMode mode,const ImmersiveEffect & effect)2002 KeyboardEffectOption InputMethodPanel::ConvertToWmEffect(ImmersiveMode mode, const ImmersiveEffect &effect)
2003 {
2004 KeyboardEffectOption option;
2005 option.blurHeight_ = effect.gradientHeight;
2006 option.viewMode_ = static_cast<KeyboardViewMode>(mode);
2007 option.gradientMode_ = static_cast<KeyboardGradientMode>(effect.gradientMode);
2008 option.flowLightMode_ = static_cast<KeyboardFlowLightMode>(effect.fluidLightMode);
2009 IMSA_HILOGI("effect: %{public}s", effect.ToString().c_str());
2010 return option;
2011 }
2012
UpdateImmersiveHotArea()2013 void InputMethodPanel::UpdateImmersiveHotArea()
2014 {
2015 auto hotAreas = GetHotAreas();
2016 if (!hotAreas.isSet) {
2017 return;
2018 }
2019 FullPanelAdjustInfo adjustInfo;
2020 auto ret = GetAdjustInfo(panelFlag_, adjustInfo);
2021 if (ret != ErrorCode::NO_ERROR) {
2022 IMSA_HILOGE("GetAdjustInfo failed ret: %{public}d", ret);
2023 return;
2024 }
2025
2026 CalculateHotAreas(GetEnhancedLayoutParams(), GetKeyboardLayoutParams(), adjustInfo, hotAreas);
2027 auto wmsHotAreas = ConvertToWMSHotArea(hotAreas);
2028 WMError result = window_->SetKeyboardTouchHotAreas(wmsHotAreas);
2029 if (result != WMError::WM_OK) {
2030 IMSA_HILOGE("SetKeyboardTouchHotAreas error, err: %{public}d!", result);
2031 return;
2032 }
2033 SetHotAreas(hotAreas);
2034 IMSA_HILOGI("success, portrait: %{public}s", HotArea::ToString(hotAreas.portrait.keyboardHotArea).c_str());
2035 IMSA_HILOGI("success, landscape: %{public}s", HotArea::ToString(hotAreas.landscape.keyboardHotArea).c_str());
2036 }
2037
SetImmersiveEffect(const ImmersiveEffect & effect)2038 int32_t InputMethodPanel::SetImmersiveEffect(const ImmersiveEffect &effect)
2039 {
2040 if (!IsImmersiveEffectSupported()) {
2041 IMSA_HILOGE("immersive effect is not supported");
2042 return ErrorCode::ERROR_DEVICE_UNSUPPORTED;
2043 }
2044 auto layoutParams = GetKeyboardLayoutParams();
2045 auto ret = IsValidParam(effect, layoutParams);
2046 if (ret != ErrorCode::NO_ERROR) {
2047 IMSA_HILOGE("invalid param, ret:%{public}d", ret);
2048 return ret;
2049 }
2050
2051 // adjust again
2052 auto currentEffect = LoadImmersiveEffect();
2053 ImmersiveEffect targetEffect = effect;
2054 if (currentEffect.gradientMode != effect.gradientMode && effect.gradientMode == GradientMode::NONE) {
2055 targetEffect =
2056 { .gradientHeight = 0, .gradientMode = GradientMode::NONE, .fluidLightMode = FluidLightMode::NONE };
2057 }
2058 ret = AdjustLayout(layoutParams, targetEffect);
2059 if (ret != ErrorCode::NO_ERROR) {
2060 IMSA_HILOGE("AdjustLayout failed, ret:%{public}d", ret);
2061 return ret;
2062 }
2063 UpdateImmersiveHotArea();
2064
2065 if (!IsShowing()) {
2066 StoreImmersiveEffect(targetEffect);
2067 IMSA_HILOGW("keyboard is not showing, do nothing");
2068 return ErrorCode::NO_ERROR;
2069 }
2070 if (window_ == nullptr) {
2071 IMSA_HILOGE("window_ is nullptr");
2072 return ErrorCode::ERROR_NULL_POINTER;
2073 }
2074 auto mode = GetImmersiveMode();
2075 KeyboardEffectOption option = ConvertToWmEffect(mode, targetEffect);
2076 // call window manager to set immersive mode
2077 auto wmRet = window_->ChangeKeyboardEffectOption(option);
2078 if (wmRet == WMError::WM_DO_NOTHING) {
2079 IMSA_HILOGW("repeat set mode new:, old:%{public}d", mode);
2080 StoreImmersiveEffect(targetEffect);
2081 return ErrorCode::NO_ERROR;
2082 }
2083 if (wmRet != WMError::WM_OK) {
2084 IMSA_HILOGE("ChangeKeyboardViewMode failed, wmRet: %{public}d", wmRet);
2085 return ErrorCode::ERROR_WINDOW_MANAGER;
2086 }
2087 StoreImmersiveEffect(targetEffect);
2088 IMSA_HILOGI("success, %{public}s", effect.ToString().c_str());
2089 return ErrorCode::NO_ERROR;
2090 }
2091
GetImmersiveMode()2092 ImmersiveMode InputMethodPanel::GetImmersiveMode()
2093 {
2094 std::lock_guard<std::mutex> lock(immersiveModeMutex_);
2095 IMSA_HILOGD("mode: %{public}d", immersiveMode_);
2096 return immersiveMode_;
2097 }
2098
StoreImmersiveMode(ImmersiveMode mode)2099 void InputMethodPanel::StoreImmersiveMode(ImmersiveMode mode)
2100 {
2101 std::lock_guard<std::mutex> lock(immersiveModeMutex_);
2102 immersiveMode_ = mode;
2103 }
2104
SetHotAreas(const HotAreas & hotAreas)2105 void InputMethodPanel::SetHotAreas(const HotAreas &hotAreas)
2106 {
2107 std::lock_guard<std::mutex> lock(hotAreasLock_);
2108 hotAreas_ = hotAreas;
2109 }
2110
GetHotAreas()2111 HotAreas InputMethodPanel::GetHotAreas()
2112 {
2113 std::lock_guard<std::mutex> lock(hotAreasLock_);
2114 return hotAreas_;
2115 }
2116
GetCurDisplay()2117 sptr<Rosen::Display> InputMethodPanel::GetCurDisplay()
2118 {
2119 IMSA_HILOGD("enter!!");
2120 uint64_t displayId = GetCurDisplayId();
2121 auto displayInfo = Rosen::DisplayManager::GetInstance().GetDisplayById(displayId);
2122 if (displayInfo == nullptr) {
2123 IMSA_HILOGE("get display info err:%{public}" PRIu64 "!", displayId);
2124 displayInfo = Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
2125 }
2126 return displayInfo;
2127 }
2128
GetCurDisplayId()2129 uint64_t InputMethodPanel::GetCurDisplayId()
2130 {
2131 return InputMethodAbility::GetInstance().GetInputAttribute().callingDisplayId;
2132 }
2133
IsInMainDisplay()2134 bool InputMethodPanel::IsInMainDisplay()
2135 {
2136 IMSA_HILOGD("enter!!");
2137 uint64_t displayId = GetCurDisplayId();
2138 auto primaryDisplay = Rosen::DisplayManager::GetInstance().GetPrimaryDisplaySync();
2139 if (primaryDisplay == nullptr) {
2140 IMSA_HILOGE("primaryDisplay failed!");
2141 return true;
2142 }
2143 return primaryDisplay->GetId() == displayId;
2144 }
2145
SetIgnoreAdjustInputTypes(const std::vector<int32_t> & inputTypes)2146 void InputMethodPanel::SetIgnoreAdjustInputTypes(const std::vector<int32_t> &inputTypes)
2147 {
2148 std::lock_guard<std::mutex> lock(ignoreAdjustInputTypeLock_);
2149 ignoreAdjustInputTypes_ = inputTypes;
2150 }
2151
GetIgnoreAdjustInputTypes()2152 std::vector<int32_t> InputMethodPanel::GetIgnoreAdjustInputTypes()
2153 {
2154 std::lock_guard<std::mutex> lock(ignoreAdjustInputTypeLock_);
2155 return ignoreAdjustInputTypes_;
2156 }
2157
IsNeedConfig()2158 bool InputMethodPanel::IsNeedConfig()
2159 {
2160 bool needConfig = true;
2161 bool isSpecialInputType = false;
2162 auto inputType = InputMethodAbility::GetInstance().GetInputType();
2163 if (!isIgnorePanelAdjustInitialized_.load()) {
2164 IgnoreSysPanelAdjust ignoreSysPanelAdjust;
2165 auto isSuccess = SysCfgParser::ParseIgnoreSysPanelAdjust(ignoreSysPanelAdjust);
2166 if (isSuccess) {
2167 SetIgnoreAdjustInputTypes(ignoreSysPanelAdjust.inputType);
2168 }
2169 isIgnorePanelAdjustInitialized_.store(true);
2170 }
2171 std::vector<int32_t> ignoreAdjustInputTypes = GetIgnoreAdjustInputTypes();
2172 auto it = std::find_if(
2173 ignoreAdjustInputTypes.begin(), ignoreAdjustInputTypes.end(), [inputType](const int32_t &mInputType) {
2174 return static_cast<int32_t>(inputType) == mInputType;
2175 });
2176 isSpecialInputType = (it != ignoreAdjustInputTypes.end());
2177 if (isSpecialInputType || !IsInMainDisplay()) {
2178 needConfig = false;
2179 }
2180 IMSA_HILOGD("isNeedConfig is %{public}d", needConfig);
2181 return needConfig;
2182 }
2183
SetKeepScreenOn(bool isKeepScreenOn)2184 int32_t InputMethodPanel::SetKeepScreenOn(bool isKeepScreenOn)
2185 {
2186 if (window_ == nullptr) {
2187 IMSA_HILOGE("window_ is nullptr!");
2188 return ErrorCode::ERROR_WINDOW_MANAGER;
2189 }
2190 auto ret = window_->SetKeepScreenOn(isKeepScreenOn);
2191 if (ret != WMError::WM_OK) {
2192 IMSA_HILOGE("SetKeepScreenOn error: %{public}d!", ret);
2193 return ErrorCode::ERROR_WINDOW_MANAGER;
2194 }
2195 IMSA_HILOGI("SetKeepScreenOn success");
2196 return ErrorCode::NO_ERROR;
2197 }
2198
GetKeyboardLayoutParams()2199 Rosen::KeyboardLayoutParams InputMethodPanel::GetKeyboardLayoutParams()
2200 {
2201 std::lock_guard<std::mutex> lock(keyboardLayoutParamsMutex_);
2202 return keyboardLayoutParams_;
2203 }
2204
SetKeyboardLayoutParams(Rosen::KeyboardLayoutParams params)2205 void InputMethodPanel::SetKeyboardLayoutParams(Rosen::KeyboardLayoutParams params)
2206 {
2207 std::lock_guard<std::mutex> lock(keyboardLayoutParamsMutex_);
2208 keyboardLayoutParams_ = std::move(params);
2209 }
2210
GetEnhancedLayoutParams()2211 EnhancedLayoutParams InputMethodPanel::GetEnhancedLayoutParams()
2212 {
2213 std::lock_guard<std::mutex> lock(enhancedLayoutParamMutex_);
2214 return enhancedLayoutParams_;
2215 }
2216
SetEnhancedLayoutParams(EnhancedLayoutParams params)2217 void InputMethodPanel::SetEnhancedLayoutParams(EnhancedLayoutParams params)
2218 {
2219 std::lock_guard<std::mutex> lock(enhancedLayoutParamMutex_);
2220 enhancedLayoutParams_ = params;
2221 }
2222
LoadImmersiveEffect()2223 ImmersiveEffect InputMethodPanel::LoadImmersiveEffect()
2224 {
2225 std::lock_guard<std::mutex> lock(immersiveEffectMutex_);
2226 return immersiveEffect_;
2227 }
2228
StoreImmersiveEffect(ImmersiveEffect effect)2229 void InputMethodPanel::StoreImmersiveEffect(ImmersiveEffect effect)
2230 {
2231 std::lock_guard<std::mutex> lock(immersiveEffectMutex_);
2232 immersiveEffect_ = effect;
2233 }
2234
GetChangeY()2235 ChangeY InputMethodPanel::GetChangeY()
2236 {
2237 std::lock_guard<std::mutex> lock(changeYMutex_);
2238 return changeY_;
2239 }
2240
SetChangeY(ChangeY changeY)2241 void InputMethodPanel::SetChangeY(ChangeY changeY)
2242 {
2243 std::lock_guard<std::mutex> lock(changeYMutex_);
2244 changeY_ = changeY;
2245 }
2246 } // namespace MiscServices
2247 } // namespace OHOS