• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "display_manager.h"
19 #include "global.h"
20 #include "input_method_ability_utils.h"
21 #include "ui/rs_surface_node.h"
22 
23 namespace OHOS {
24 namespace MiscServices {
25 using WMError = OHOS::Rosen::WMError;
26 using WindowGravity = OHOS::Rosen::WindowGravity;
27 using WindowState = OHOS::Rosen::WindowState;
28 constexpr float SCREEN_RATIO = 0.6;
29 std::atomic<uint32_t> InputMethodPanel::sequenceId_{ 0 };
30 InputMethodPanel::~InputMethodPanel() = default;
31 
CreatePanel(const std::shared_ptr<AbilityRuntime::Context> & context,const PanelInfo & panelInfo)32 int32_t InputMethodPanel::CreatePanel(
33     const std::shared_ptr<AbilityRuntime::Context> &context, const PanelInfo &panelInfo)
34 {
35     IMSA_HILOGD("InputMethodPanel start to create panel.");
36     panelType_ = panelInfo.panelType;
37     panelFlag_ = panelInfo.panelFlag;
38     winOption_ = new (std::nothrow) OHOS::Rosen::WindowOption();
39     if (winOption_ == nullptr) {
40         return ErrorCode::ERROR_NULL_POINTER;
41     }
42     if (panelInfo.panelType == PanelType::STATUS_BAR) {
43         winOption_->SetWindowType(OHOS::Rosen::WindowType::WINDOW_TYPE_INPUT_METHOD_STATUS_BAR);
44     } else {
45         winOption_->SetWindowType(OHOS::Rosen::WindowType::WINDOW_TYPE_INPUT_METHOD_FLOAT);
46     }
47     WMError wmError = WMError::WM_OK;
48     window_ = OHOS::Rosen::Window::Create(GeneratePanelName(), winOption_, context, wmError);
49     if (wmError == WMError::WM_ERROR_INVALID_PERMISSION || wmError == WMError::WM_ERROR_NOT_SYSTEM_APP) {
50         IMSA_HILOGE("Create window failed, permission denied, %{public}d", wmError);
51         return ErrorCode::ERROR_NOT_IME;
52     }
53     if (window_ == nullptr || wmError != WMError::WM_OK) {
54         return ErrorCode::ERROR_OPERATE_PANEL;
55     }
56     windowId_ = window_->GetWindowId();
57     IMSA_HILOGD("GetWindowId, windowId = %{public}u", windowId_);
58     if (SetPanelProperties() != ErrorCode::NO_ERROR) {
59         wmError = window_->Destroy();
60         IMSA_HILOGI("Destroy window end, wmError is %{public}d.", wmError);
61         return ErrorCode::ERROR_OPERATE_PANEL;
62     }
63     return ErrorCode::NO_ERROR;
64 }
65 
GeneratePanelName()66 std::string InputMethodPanel::GeneratePanelName()
67 {
68     uint32_t sequenceId = GenerateSequenceId();
69     std::string windowName = panelType_ == SOFT_KEYBOARD ? "softKeyboard" + std::to_string(sequenceId)
70                                                          : "statusBar" + std::to_string(sequenceId);
71     IMSA_HILOGD("InputMethodPanel,  windowName = %{public}s", windowName.c_str());
72     return windowName;
73 }
74 
SetPanelProperties()75 int32_t InputMethodPanel::SetPanelProperties()
76 {
77     if (window_ == nullptr) {
78         IMSA_HILOGE("window is not exist.");
79         return ErrorCode::ERROR_OPERATE_PANEL;
80     }
81     WindowGravity gravity = WindowGravity::WINDOW_GRAVITY_FLOAT;
82     if (panelType_ == SOFT_KEYBOARD && panelFlag_ == FLG_FIXED) {
83         gravity = WindowGravity::WINDOW_GRAVITY_BOTTOM;
84     } else if (panelType_ == SOFT_KEYBOARD && panelFlag_ == FLG_FLOATING) {
85         window_->GetSurfaceNode()->SetFrameGravity(Rosen::Gravity::TOP_LEFT);
86         Rosen::RSTransactionProxy::GetInstance()->FlushImplicitTransaction();
87     } else if (panelType_ == STATUS_BAR) {
88         window_->GetSurfaceNode()->SetFrameGravity(Rosen::Gravity::TOP_LEFT);
89         Rosen::RSTransactionProxy::GetInstance()->FlushImplicitTransaction();
90         return ErrorCode::NO_ERROR;
91     }
92     WMError wmError = window_->SetWindowGravity(gravity, invalidGravityPercent);
93     if (wmError != WMError::WM_OK) {
94         IMSA_HILOGE("SetWindowGravity failed, wmError is %{public}d, start destroy window.", wmError);
95         return ErrorCode::ERROR_OPERATE_PANEL;
96     }
97     return ErrorCode::NO_ERROR;
98 }
99 
DestroyPanel()100 int32_t InputMethodPanel::DestroyPanel()
101 {
102     auto ret = HidePanel();
103     if (ret != ErrorCode::NO_ERROR) {
104         IMSA_HILOGE("InputMethodPanel, hide panel failed, ret = %{public}d.", ret);
105         return ret;
106     }
107     auto result = window_->Destroy();
108     IMSA_HILOGI("InputMethodPanel, Destroy end, ret = %{public}d", result);
109     return result == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
110 }
111 
Resize(uint32_t width,uint32_t height)112 int32_t InputMethodPanel::Resize(uint32_t width, uint32_t height)
113 {
114     if (window_ == nullptr) {
115         return ErrorCode::ERROR_NULL_POINTER;
116     }
117     auto defaultDisplay = Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
118     if (defaultDisplay == nullptr) {
119         IMSA_HILOGE("GetDefaultDisplay failed.");
120         return ErrorCode::ERROR_NULL_POINTER;
121     }
122     if (width > INT32_MAX || height > INT32_MAX) {
123         IMSA_HILOGE("width or height over maximum");
124         return ErrorCode::ERROR_BAD_PARAMETERS;
125     }
126     if (static_cast<int32_t>(width) > defaultDisplay->GetWidth() ||
127         static_cast<float>(height) > defaultDisplay->GetHeight() * SCREEN_RATIO) {
128         IMSA_HILOGE("GetDefaultDisplay, defaultDisplay->width = %{public}d, defaultDisplay->height = %{public}d, "
129                     "width = %{public}u, height = %{public}u",
130             defaultDisplay->GetWidth(), defaultDisplay->GetHeight(), width, height);
131         return ErrorCode::ERROR_BAD_PARAMETERS;
132     }
133     auto ret = window_->Resize(width, height);
134     IMSA_HILOGI("InputMethodPanel, Resize ret = %{public}d", ret);
135     return ret == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
136 }
137 
MoveTo(int32_t x,int32_t y)138 int32_t InputMethodPanel::MoveTo(int32_t x, int32_t y)
139 {
140     if (window_ == nullptr) {
141         IMSA_HILOGE("window_ is nullptr.");
142         return ErrorCode::ERROR_NULL_POINTER;
143     }
144     if (panelType_ == SOFT_KEYBOARD && panelFlag_ == FLG_FIXED) {
145         IMSA_HILOGE("FLG_FIXED panel can not moveTo.");
146         return ErrorCode::NO_ERROR;
147     }
148     auto ret = window_->MoveTo(x, y);
149     IMSA_HILOGI("InputMethodPanel, MoveTo ret = %{public}d", ret);
150     return ret == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
151 }
152 
ChangePanelFlag(PanelFlag panelFlag)153 int32_t InputMethodPanel::ChangePanelFlag(PanelFlag panelFlag)
154 {
155     if (window_ == nullptr) {
156         IMSA_HILOGE("window_ is nullptr.");
157         return ErrorCode::ERROR_NULL_POINTER;
158     }
159     if (panelFlag_ == panelFlag) {
160         return ErrorCode::NO_ERROR;
161     }
162     if (panelType_ == STATUS_BAR) {
163         IMSA_HILOGE("STATUS_BAR cannot ChangePanelFlag.");
164         return ErrorCode::ERROR_BAD_PARAMETERS;
165     }
166     panelFlag_ = panelFlag;
167     WindowGravity gravity = WindowGravity::WINDOW_GRAVITY_FLOAT;
168     if (panelFlag == FLG_FIXED) {
169         gravity = WindowGravity::WINDOW_GRAVITY_BOTTOM;
170     } else {
171         window_->GetSurfaceNode()->SetFrameGravity(Rosen::Gravity::TOP_LEFT);
172         Rosen::RSTransactionProxy::GetInstance()->FlushImplicitTransaction();
173     }
174     auto ret = window_->SetWindowGravity(gravity, invalidGravityPercent);
175     IMSA_HILOGI("InputMethodPanel, ChangePanelFlag end, ret = %{public}d", ret);
176     return ret == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
177 }
178 
GetPanelType()179 PanelType InputMethodPanel::GetPanelType()
180 {
181     return panelType_;
182 }
183 
GetPanelFlag()184 PanelFlag InputMethodPanel::GetPanelFlag()
185 {
186     return panelFlag_;
187 }
188 
ShowPanel()189 int32_t InputMethodPanel::ShowPanel()
190 {
191     if (window_ == nullptr) {
192         IMSA_HILOGE("window_ is nullptr.");
193         return ErrorCode::ERROR_NULL_POINTER;
194     }
195     if (IsShowing()) {
196         IMSA_HILOGE("Panel already shown.");
197         return ErrorCode::NO_ERROR;
198     }
199     auto ret = window_->Show();
200     if (ret != WMError::WM_OK) {
201         IMSA_HILOGE("ShowPanel error, err = %{public}d", ret);
202         return ErrorCode::ERROR_OPERATE_PANEL;
203     }
204     IMSA_HILOGI("InputMethodPanel, ShowPanel success.");
205     PanelStatusChange(InputWindowStatus::SHOW);
206     return ErrorCode::NO_ERROR;
207 }
208 
HidePanel()209 int32_t InputMethodPanel::HidePanel()
210 {
211     if (window_ == nullptr) {
212         IMSA_HILOGE("window_ is nullptr.");
213         return ErrorCode::ERROR_NULL_POINTER;
214     }
215     if (IsHidden()) {
216         IMSA_HILOGE("Panel already hidden.");
217         return ErrorCode::NO_ERROR;
218     }
219     auto ret = window_->Hide();
220     if (ret != WMError::WM_OK) {
221         IMSA_HILOGE("HidePanel error, err = %{public}d", ret);
222         return ErrorCode::ERROR_OPERATE_PANEL;
223     }
224     IMSA_HILOGI("InputMethodPanel, HidePanel success.");
225     PanelStatusChange(InputWindowStatus::HIDE);
226     return ErrorCode::NO_ERROR;
227 }
228 
SetCallingWindow(uint32_t windowId)229 int32_t InputMethodPanel::SetCallingWindow(uint32_t windowId)
230 {
231     if (window_ == nullptr) {
232         IMSA_HILOGE("window_ is nullptr.");
233         return ErrorCode::ERROR_NULL_POINTER;
234     }
235     auto ret = window_->SetCallingWindow(windowId);
236     IMSA_HILOGI("InputMethodPanel, SetCallingWindow ret = %{public}d, windowId = %{public}u", ret, windowId);
237     return ret == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
238 }
239 
PanelStatusChange(const InputWindowStatus & status)240 void InputMethodPanel::PanelStatusChange(const InputWindowStatus &status)
241 {
242     if (status == InputWindowStatus::SHOW && showRegistered_ && panelStatusListener_ != nullptr) {
243         IMSA_HILOGE("InputMethodPanel::ShowPanel panelStatusListener_ is not nullptr");
244         panelStatusListener_->OnPanelStatus(windowId_, true);
245     }
246     if (status == InputWindowStatus::HIDE && hideRegistered_ && panelStatusListener_ != nullptr) {
247         IMSA_HILOGE("InputMethodPanel::HidePanel panelStatusListener_ is not nullptr");
248         panelStatusListener_->OnPanelStatus(windowId_, false);
249     }
250     auto imsa = ImaUtils::GetImsaProxy();
251     if (imsa == nullptr) {
252         IMSA_HILOGE("imsa is nullptr");
253         return;
254     }
255     if (panelType_ == SOFT_KEYBOARD && panelFlag_ == FLG_FIXED) {
256         auto rect = window_->GetRect();
257         IMSA_HILOGD("InputMethodPanel::x:%{public}d, y:%{public}d, w:%{public}u, h:%{public}u", rect.posX_, rect.posY_,
258             rect.width_, rect.height_);
259         std::string name = window_->GetWindowName() + "/" + std::to_string(window_->GetWindowId());
260         imsa->PanelStatusChange(status, { std::move(name), rect.posX_, rect.posY_, rect.width_, rect.height_ });
261     }
262 }
263 
IsShowing()264 bool InputMethodPanel::IsShowing()
265 {
266     WindowState windowState = window_->GetWindowState();
267     if (windowState == WindowState::STATE_SHOWN) {
268         return true;
269     }
270     IMSA_HILOGD("InputMethodPanel windowState = %{public}d", static_cast<int>(windowState));
271     return false;
272 }
273 
IsHidden()274 bool InputMethodPanel::IsHidden()
275 {
276     WindowState windowState = window_->GetWindowState();
277     if (windowState == WindowState::STATE_HIDDEN) {
278         return true;
279     }
280     IMSA_HILOGD("InputMethodPanel windowState = %{public}d", static_cast<int>(windowState));
281     return false;
282 }
283 
SetUiContent(const std::string & contentInfo,NativeEngine & engine,std::shared_ptr<NativeReference> storage)284 int32_t InputMethodPanel::SetUiContent(
285     const std::string &contentInfo, NativeEngine &engine, std::shared_ptr<NativeReference> storage)
286 {
287     if (window_ == nullptr) {
288         IMSA_HILOGE("window_ is nullptr, can not SetUiContent.");
289         return ErrorCode::ERROR_NULL_POINTER;
290     }
291     WMError ret = WMError::WM_OK;
292     if (storage == nullptr) {
293         ret = window_->SetUIContent(contentInfo, &engine, nullptr);
294     } else {
295         ret = window_->SetUIContent(contentInfo, &engine, storage->Get());
296     }
297     WMError wmError = window_->SetTransparent(true);
298     IMSA_HILOGI("SetTransparent end, wmError = %{public}u", wmError);
299     IMSA_HILOGI("InputMethodPanel, SetUiContent ret = %{public}d", ret);
300     return ret == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
301 }
302 
SetPanelStatusListener(std::shared_ptr<PanelStatusListener> statusListener,const std::string & type)303 void InputMethodPanel::SetPanelStatusListener(
304     std::shared_ptr<PanelStatusListener> statusListener, const std::string &type)
305 {
306     IMSA_HILOGD("SetPanelStatusListener start.");
307     if (!MarkListener(type, true)) {
308         return;
309     }
310     if (panelStatusListener_ != nullptr) {
311         IMSA_HILOGE("PanelStatusListener already set.");
312         return;
313     }
314     panelStatusListener_ = std::move(statusListener);
315     if (window_ != nullptr && IsShowing()) {
316         panelStatusListener_->OnPanelStatus(windowId_, true);
317     }
318 }
319 
ClearPanelListener(const std::string & type)320 void InputMethodPanel::ClearPanelListener(const std::string &type)
321 {
322     if (!MarkListener(type, false)) {
323         return;
324     }
325     if (panelStatusListener_ == nullptr) {
326         IMSA_HILOGE("PanelStatusListener not set, don't need to remove.");
327         return;
328     }
329     if (showRegistered_ || hideRegistered_) {
330         return;
331     }
332     panelStatusListener_ = nullptr;
333 }
334 
MarkListener(const std::string & type,bool isRegister)335 bool InputMethodPanel::MarkListener(const std::string &type, bool isRegister)
336 {
337     if (type == "show") {
338         showRegistered_ = isRegister;
339     } else if (type == "hide") {
340         hideRegistered_ = isRegister;
341     } else {
342         IMSA_HILOGE("type error.");
343         return false;
344     }
345     return true;
346 }
347 
GenerateSequenceId()348 uint32_t InputMethodPanel::GenerateSequenceId()
349 {
350     uint32_t seqId = ++sequenceId_;
351     if (seqId == std::numeric_limits<uint32_t>::max()) {
352         return ++sequenceId_;
353     }
354     return seqId;
355 }
356 } // namespace MiscServices
357 } // namespace OHOS
358