1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "session/host/include/keyboard_session.h"
17 #include "session/host/include/session.h"
18 #include "common/include/session_permission.h"
19 #include "display_manager.h"
20 #include "screen_session_manager/include/screen_session_manager_client.h"
21 #include "session_helper.h"
22 #include <parameters.h>
23 #include "window_helper.h"
24 #include "window_manager_hilog.h"
25
26 namespace OHOS::Rosen {
27
KeyboardSession(const SessionInfo & info,const sptr<SpecificSessionCallback> & specificCallback,const sptr<KeyboardSessionCallback> & keyboardCallback)28 KeyboardSession::KeyboardSession(const SessionInfo& info, const sptr<SpecificSessionCallback>& specificCallback,
29 const sptr<KeyboardSessionCallback>& keyboardCallback)
30 : SystemSession(info, specificCallback)
31 {
32 keyboardCallback_ = keyboardCallback;
33 TLOGI(WmsLogTag::WMS_KEYBOARD, "Create KeyboardSession");
34 }
35
~KeyboardSession()36 KeyboardSession::~KeyboardSession()
37 {
38 TLOGI(WmsLogTag::WMS_KEYBOARD, "~KeyboardSession");
39 }
40
BindKeyboardPanelSession(sptr<SceneSession> panelSession)41 void KeyboardSession::BindKeyboardPanelSession(sptr<SceneSession> panelSession)
42 {
43 if (panelSession == nullptr) {
44 TLOGE(WmsLogTag::WMS_KEYBOARD, "panelSession is nullptr");
45 return;
46 }
47 keyboardPanelSession_ = panelSession;
48 TLOGI(WmsLogTag::WMS_KEYBOARD, "Success, panelId: %{public}d", panelSession->GetPersistentId());
49 }
50
GetKeyboardPanelSession() const51 sptr<SceneSession> KeyboardSession::GetKeyboardPanelSession() const
52 {
53 return keyboardPanelSession_;
54 }
55
GetKeyboardGravity() const56 SessionGravity KeyboardSession::GetKeyboardGravity() const
57 {
58 SessionGravity gravity = SessionGravity::SESSION_GRAVITY_DEFAULT;
59 auto sessionProperty = GetSessionProperty();
60 if (sessionProperty) {
61 gravity = static_cast<SessionGravity>(sessionProperty->GetKeyboardLayoutParams().gravity_);
62 }
63 TLOGI(WmsLogTag::WMS_KEYBOARD, "gravity: %{public}d", gravity);
64 return gravity;
65 }
66
Show(sptr<WindowSessionProperty> property)67 WSError KeyboardSession::Show(sptr<WindowSessionProperty> property)
68 {
69 if (property == nullptr) {
70 TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is null");
71 return WSError::WS_ERROR_NULLPTR;
72 }
73 if (!CheckPermissionWithPropertyAnimation(property)) {
74 return WSError::WS_ERROR_NOT_SYSTEM_APP;
75 }
76 auto task = [weakThis = wptr(this), property]() {
77 auto session = weakThis.promote();
78 if (!session) {
79 TLOGE(WmsLogTag::WMS_KEYBOARD, "Session is null, show keyboard failed");
80 return WSError::WS_ERROR_DESTROYED_OBJECT;
81 }
82 session->GetSessionProperty()->SetKeyboardViewMode(property->GetKeyboardViewMode());
83 session->UseFocusIdIfCallingSessionIdInvalid();
84 TLOGNI(WmsLogTag::WMS_KEYBOARD,
85 "Show keyboard session, id: %{public}d, calling id: %{public}d, viewMode: %{public}u",
86 session->GetPersistentId(), session->GetCallingSessionId(),
87 static_cast<uint32_t>(property->GetKeyboardViewMode()));
88 session->MoveAndResizeKeyboard(property->GetKeyboardLayoutParams(), property, true);
89 session->NotifySessionRectChange(session->GetSessionRequestRect(), SizeChangeReason::UNDEFINED);
90 return session->SceneSession::Foreground(property);
91 };
92 PostTask(task, "Show");
93 return WSError::WS_OK;
94 }
95
Hide()96 WSError KeyboardSession::Hide()
97 {
98 if (!CheckPermissionWithPropertyAnimation(GetSessionProperty())) {
99 return WSError::WS_ERROR_NOT_SYSTEM_APP;
100 }
101 auto task = [weakThis = wptr(this)]() {
102 auto session = weakThis.promote();
103 if (!session) {
104 TLOGE(WmsLogTag::WMS_KEYBOARD, "Session is null, hide keyboard failed!");
105 return WSError::WS_ERROR_DESTROYED_OBJECT;
106 }
107
108 TLOGI(WmsLogTag::WMS_KEYBOARD, "Hide keyboard session, set callingSessionId to 0, id: %{public}d",
109 session->GetPersistentId());
110 auto ret = session->SetActive(false);
111 if (ret != WSError::WS_OK) {
112 TLOGE(WmsLogTag::WMS_KEYBOARD, "Set session active state failed, ret: %{public}d", ret);
113 return ret;
114 }
115 ret = session->SceneSession::Background();
116 WSRect rect = {0, 0, 0, 0};
117 session->NotifyKeyboardPanelInfoChange(rect, false);
118 if (session->systemConfig_.uiType_ == UI_TYPE_PC || session->GetSessionScreenName() == "HiCar"
119 || session->GetSessionScreenName() == "SuperLauncher") {
120 TLOGD(WmsLogTag::WMS_KEYBOARD, "pc or virtual screen, restore calling session");
121 session->RestoreCallingSession();
122 auto sessionProperty = session->GetSessionProperty();
123 if (sessionProperty) {
124 sessionProperty->SetCallingSessionId(INVALID_WINDOW_ID);
125 }
126 }
127 return ret;
128 };
129 PostTask(task, "Hide");
130 return WSError::WS_OK;
131 }
132
Disconnect(bool isFromClient,const std::string & identityToken)133 WSError KeyboardSession::Disconnect(bool isFromClient, const std::string& identityToken)
134 {
135 auto task = [weakThis = wptr(this), isFromClient]() {
136 auto session = weakThis.promote();
137 if (!session) {
138 TLOGE(WmsLogTag::WMS_KEYBOARD, "Session is null, disconnect keyboard session failed!");
139 return WSError::WS_ERROR_DESTROYED_OBJECT;
140 }
141 TLOGI(WmsLogTag::WMS_KEYBOARD, "Disconnect keyboard session, id: %{public}d, isFromClient: %{public}d",
142 session->GetPersistentId(), isFromClient);
143 session->SceneSession::Disconnect(isFromClient);
144 WSRect rect = {0, 0, 0, 0};
145 session->NotifyKeyboardPanelInfoChange(rect, false);
146 session->RestoreCallingSession();
147 auto sessionProperty = session->GetSessionProperty();
148 if (sessionProperty) {
149 sessionProperty->SetCallingSessionId(INVALID_WINDOW_ID);
150 }
151 return WSError::WS_OK;
152 };
153 PostTask(task, "Disconnect");
154 return WSError::WS_OK;
155 }
156
NotifyClientToUpdateRect(const std::string & updateReason,std::shared_ptr<RSTransaction> rsTransaction)157 WSError KeyboardSession::NotifyClientToUpdateRect(const std::string& updateReason,
158 std::shared_ptr<RSTransaction> rsTransaction)
159 {
160 auto task = [weakThis = wptr(this), rsTransaction, updateReason]() {
161 auto session = weakThis.promote();
162 if (!session) {
163 TLOGE(WmsLogTag::WMS_KEYBOARD, "session is null");
164 return WSError::WS_ERROR_DESTROYED_OBJECT;
165 }
166
167 WSError ret = session->NotifyClientToUpdateRectTask(updateReason, rsTransaction);
168 return ret;
169 };
170 PostTask(task, "NotifyClientToUpdateRect");
171 return WSError::WS_OK;
172 }
173
UpdateKeyboardAvoidArea()174 void KeyboardSession::UpdateKeyboardAvoidArea()
175 {
176 if (!IsSessionForeground() || (Session::IsScbCoreEnabled() && !IsVisibleForeground())) {
177 TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard is not foreground, no need update avoid Area");
178 return;
179 }
180 if (specificCallback_ != nullptr && specificCallback_->onUpdateAvoidArea_ != nullptr) {
181 if (Session::IsScbCoreEnabled()) {
182 dirtyFlags_ |= static_cast<uint32_t>(SessionUIDirtyFlag::AVOID_AREA);
183 } else {
184 specificCallback_->onUpdateAvoidArea_(GetPersistentId());
185 }
186 }
187 }
188
OnKeyboardPanelUpdated()189 void KeyboardSession::OnKeyboardPanelUpdated()
190 {
191 TLOGI(WmsLogTag::WMS_KEYBOARD, "id: %{public}d", GetPersistentId());
192 WSRect panelRect = { 0, 0, 0, 0 };
193 panelRect = (keyboardPanelSession_ == nullptr) ? panelRect : keyboardPanelSession_->GetSessionRect();
194 RaiseCallingSession(panelRect, true);
195 UpdateKeyboardAvoidArea();
196 }
197
OnCallingSessionUpdated()198 void KeyboardSession::OnCallingSessionUpdated()
199 {
200 TLOGI(WmsLogTag::WMS_KEYBOARD, "id: %{public}d", GetPersistentId());
201 if (!IsSessionForeground() || (Session::IsScbCoreEnabled() && !IsVisibleForeground())) {
202 TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard is not foreground.");
203 return;
204 }
205 WSRect panelRect = { 0, 0, 0, 0 };
206 panelRect = (keyboardPanelSession_ == nullptr) ? panelRect : keyboardPanelSession_->GetSessionRect();
207 RecalculatePanelRectForAvoidArea(panelRect);
208 sptr<SceneSession> callingSession = GetSceneSession(GetCallingSessionId());
209 if (callingSession == nullptr) {
210 TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is nullptr");
211 return;
212 }
213 bool isCallingSessionFloating = (callingSession->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING);
214 if (!CheckIfNeedRaiseCallingSession(callingSession, isCallingSessionFloating)) {
215 return;
216 }
217 WSRect callingSessionRect = callingSession->GetSessionRect();
218 NotifyOccupiedAreaChangeInfo(callingSession, callingSessionRect, panelRect);
219
220 TLOGI(WmsLogTag::WMS_KEYBOARD, "callSession Rect: %{public}s", callingSessionRect.ToString().c_str());
221 }
222
SetKeyboardSessionGravity(SessionGravity gravity)223 WSError KeyboardSession::SetKeyboardSessionGravity(SessionGravity gravity)
224 {
225 TLOGI(WmsLogTag::WMS_KEYBOARD, "keyboardId: %{public}d, gravity: %{public}d", GetPersistentId(), gravity);
226 if (keyboardGravityChangeFunc_) {
227 keyboardGravityChangeFunc_(gravity);
228 }
229 RelayoutKeyBoard();
230 if (gravity == SessionGravity::SESSION_GRAVITY_FLOAT) {
231 SetWindowAnimationFlag(false);
232 if (IsSessionForeground()) {
233 RestoreCallingSession();
234 }
235 } else {
236 SetWindowAnimationFlag(true);
237 }
238 return WSError::WS_OK;
239 }
240
SetCallingSessionId(uint32_t callingSessionId)241 void KeyboardSession::SetCallingSessionId(uint32_t callingSessionId)
242 {
243 auto task = [weakThis = wptr(this), callingSessionId]() mutable {
244 auto session = weakThis.promote();
245 if (!session) {
246 TLOGE(WmsLogTag::WMS_KEYBOARD, "session is null");
247 return;
248 }
249 if (session->GetSceneSession(callingSessionId) == nullptr) {
250 uint32_t focusedSessionId = static_cast<uint32_t>(session->GetFocusedSessionId());
251 if (session->GetSceneSession(focusedSessionId) == nullptr) {
252 TLOGE(WmsLogTag::WMS_KEYBOARD, "Focused session is null, set id: %{public}d failed", focusedSessionId);
253 return;
254 } else {
255 TLOGI(WmsLogTag::WMS_KEYBOARD, "Using focusedSession id: %{public}d", focusedSessionId);
256 callingSessionId = focusedSessionId;
257 }
258 }
259 uint32_t curCallingSessionId = session->GetCallingSessionId();
260 TLOGI(WmsLogTag::WMS_KEYBOARD, "curId: %{public}d, newId: %{public}d", curCallingSessionId, callingSessionId);
261 auto sessionProperty = session->GetSessionProperty();
262 if (sessionProperty != nullptr) {
263 if (curCallingSessionId != INVALID_WINDOW_ID && callingSessionId != curCallingSessionId &&
264 session->IsSessionForeground()) {
265 session->MoveAndResizeKeyboard(sessionProperty->GetKeyboardLayoutParams(), sessionProperty, true);
266 session->NotifySessionRectChange(session->GetSessionRequestRect(), SizeChangeReason::UNDEFINED);
267
268 session->UpdateCallingSessionIdAndPosition(callingSessionId);
269 } else {
270 sessionProperty->SetCallingSessionId(callingSessionId);
271 }
272 }
273 if (session->keyboardCallback_ == nullptr ||
274 session->keyboardCallback_->onCallingSessionIdChange_ == nullptr) {
275 TLOGE(WmsLogTag::WMS_KEYBOARD, "KeyboardCallback_, callingSessionId: %{public}d", callingSessionId);
276 return;
277 }
278 session->keyboardCallback_->onCallingSessionIdChange_(callingSessionId);
279 };
280 PostTask(task, "SetCallingSessionId");
281 return;
282 }
283
GetCallingSessionId()284 uint32_t KeyboardSession::GetCallingSessionId()
285 {
286 auto sessionProperty = GetSessionProperty();
287 if (sessionProperty == nullptr) {
288 TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is null");
289 return INVALID_SESSION_ID;
290 }
291 return sessionProperty->GetCallingSessionId();
292 }
293
AdjustKeyboardLayout(const KeyboardLayoutParams & params)294 WSError KeyboardSession::AdjustKeyboardLayout(const KeyboardLayoutParams& params)
295 {
296 auto task = [weakThis = wptr(this), params]() -> WSError {
297 auto session = weakThis.promote();
298 if (!session) {
299 TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboard session is null");
300 return WSError::WS_ERROR_DESTROYED_OBJECT;
301 }
302 auto sessionProperty = session->GetSessionProperty();
303 if (sessionProperty == nullptr) {
304 TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is null");
305 return WSError::WS_ERROR_NULLPTR;
306 }
307 sessionProperty->SetKeyboardLayoutParams(params);
308 session->MoveAndResizeKeyboard(params, sessionProperty, false);
309 session->SetKeyboardSessionGravity(static_cast<SessionGravity>(params.gravity_));
310 // avoidHeight is set, notify avoidArea in case ui params don't flush
311 if (params.landscapeAvoidHeight_ >= 0 && params.portraitAvoidHeight_ >= 0) {
312 session->NotifyClientToUpdateAvoidArea();
313 }
314 if (session->adjustKeyboardLayoutFunc_) {
315 session->adjustKeyboardLayoutFunc_(params);
316 }
317 session->NotifySessionRectChange(session->GetSessionRequestRect(), SizeChangeReason::UNDEFINED);
318 TLOGI(WmsLogTag::WMS_KEYBOARD, "adjust keyboard layout, keyboardId: %{public}d, gravity: %{public}u, "
319 "landscapeAvoidHeight: %{public}d, portraitAvoidHeight: %{public}d, "
320 "LandscapeKeyboardRect: %{public}s, PortraitKeyboardRect: %{public}s, LandscapePanelRect: %{public}s, "
321 "PortraitPanelRect: %{public}s, requestRect: %{public}s", session->GetPersistentId(),
322 static_cast<uint32_t>(params.gravity_), params.landscapeAvoidHeight_, params.portraitAvoidHeight_,
323 params.LandscapeKeyboardRect_.ToString().c_str(), params.PortraitKeyboardRect_.ToString().c_str(),
324 params.LandscapePanelRect_.ToString().c_str(), params.PortraitPanelRect_.ToString().c_str(),
325 session->GetSessionRequestRect().ToString().c_str());
326 return WSError::WS_OK;
327 };
328 PostTask(task, "AdjustKeyboardLayout");
329 return WSError::WS_OK;
330 }
331
GetSceneSession(uint32_t persistentId)332 sptr<SceneSession> KeyboardSession::GetSceneSession(uint32_t persistentId)
333 {
334 if (keyboardCallback_ == nullptr || keyboardCallback_->onGetSceneSession_ == nullptr) {
335 TLOGE(WmsLogTag::WMS_KEYBOARD, "Get scene session failed, persistentId: %{public}d", persistentId);
336 return nullptr;
337 }
338 return keyboardCallback_->onGetSceneSession_(persistentId);
339 }
340
GetFocusedSessionId()341 int32_t KeyboardSession::GetFocusedSessionId()
342 {
343 if (keyboardCallback_ == nullptr || keyboardCallback_->onGetFocusedSessionId_ == nullptr) {
344 TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboardCallback_ is nullptr, get focusedSessionId failed!");
345 return INVALID_WINDOW_ID;
346 }
347 return keyboardCallback_->onGetFocusedSessionId_();
348 }
349
GetStatusBarHeight()350 int32_t KeyboardSession::GetStatusBarHeight()
351 {
352 int32_t statusBarHeight = 0;
353 auto sessionProperty = GetSessionProperty();
354 if (specificCallback_ == nullptr || specificCallback_->onGetSceneSessionVectorByTypeAndDisplayId_ == nullptr ||
355 sessionProperty == nullptr) {
356 TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboardCallback_ or session property is null, get statusBarHeight failed!");
357 return statusBarHeight;
358 }
359
360 std::vector<sptr<SceneSession>> statusBarVector = specificCallback_->onGetSceneSessionVectorByTypeAndDisplayId_(
361 WindowType::WINDOW_TYPE_STATUS_BAR, GetSessionProperty()->GetDisplayId());
362 for (const auto& statusBar : statusBarVector) {
363 if (statusBar != nullptr && statusBar->GetSessionRect().height_ > statusBarHeight) {
364 statusBarHeight = statusBar->GetSessionRect().height_;
365 }
366 }
367 TLOGI(WmsLogTag::WMS_KEYBOARD, "Status Bar height: %{public}d", statusBarHeight);
368 return statusBarHeight;
369 }
370
NotifyOccupiedAreaChangeInfo(const sptr<SceneSession> & callingSession,const WSRect & rect,const WSRect & occupiedArea,const std::shared_ptr<RSTransaction> & rsTransaction)371 void KeyboardSession::NotifyOccupiedAreaChangeInfo(const sptr<SceneSession>& callingSession, const WSRect& rect,
372 const WSRect& occupiedArea, const std::shared_ptr<RSTransaction>& rsTransaction)
373 {
374 // if keyboard will occupy calling, notify calling window the occupied area and safe height
375 const WSRect& safeRect = SessionHelper::GetOverlap(occupiedArea, rect, 0, 0);
376 const WSRect& lastSafeRect = callingSession->GetLastSafeRect();
377 if (lastSafeRect == safeRect) {
378 TLOGI(WmsLogTag::WMS_KEYBOARD, "SafeRect is same to lastSafeRect: %{public}s", safeRect.ToString().c_str());
379 return;
380 }
381 callingSession->SetLastSafeRect(safeRect);
382 double textFieldPositionY = 0.0;
383 double textFieldHeight = 0.0;
384 auto sessionProperty = GetSessionProperty();
385 if (sessionProperty != nullptr) {
386 textFieldPositionY = sessionProperty->GetTextFieldPositionY();
387 textFieldHeight = sessionProperty->GetTextFieldHeight();
388 }
389 sptr<OccupiedAreaChangeInfo> info = sptr<OccupiedAreaChangeInfo>::MakeSptr(OccupiedAreaType::TYPE_INPUT,
390 SessionHelper::TransferToRect(safeRect), safeRect.height_, textFieldPositionY, textFieldHeight);
391 TLOGI(WmsLogTag::WMS_KEYBOARD, "lastSafeRect: %{public}s, safeRect: %{public}s, keyboardRect: %{public}s, "
392 "textFieldPositionY_: %{public}f, textFieldHeight_: %{public}f", lastSafeRect.ToString().c_str(),
393 safeRect.ToString().c_str(), occupiedArea.ToString().c_str(), textFieldPositionY, textFieldHeight);
394 callingSession->NotifyOccupiedAreaChangeInfo(info, rsTransaction);
395 }
396
NotifyKeyboardPanelInfoChange(WSRect rect,bool isKeyboardPanelShow)397 void KeyboardSession::NotifyKeyboardPanelInfoChange(WSRect rect, bool isKeyboardPanelShow)
398 {
399 if (!sessionStage_) {
400 TLOGE(WmsLogTag::WMS_KEYBOARD, "sessionStage_ is nullptr, notify keyboard panel rect change failed");
401 return;
402 }
403 KeyboardPanelInfo keyboardPanelInfo;
404 keyboardPanelInfo.rect_ = SessionHelper::TransferToRect(rect);
405 keyboardPanelInfo.gravity_ = static_cast<WindowGravity>(GetKeyboardGravity());
406 keyboardPanelInfo.isShowing_ = isKeyboardPanelShow;
407
408 sessionStage_->NotifyKeyboardPanelInfoChange(keyboardPanelInfo);
409 }
410
CheckIfNeedRaiseCallingSession(sptr<SceneSession> callingSession,bool isCallingSessionFloating)411 bool KeyboardSession::CheckIfNeedRaiseCallingSession(sptr<SceneSession> callingSession, bool isCallingSessionFloating)
412 {
413 if (callingSession == nullptr) {
414 TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is nullptr");
415 return false;
416 }
417
418 SessionGravity gravity = GetKeyboardGravity();
419 if (gravity == SessionGravity::SESSION_GRAVITY_FLOAT) {
420 TLOGI(WmsLogTag::WMS_KEYBOARD, "No need to raise calling session, gravity: %{public}d", gravity);
421 return false;
422 }
423 bool isMainOrParentFloating = WindowHelper::IsMainWindow(callingSession->GetWindowType()) ||
424 (WindowHelper::IsSubWindow(callingSession->GetWindowType()) && callingSession->GetParentSession() != nullptr &&
425 callingSession->GetParentSession()->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING);
426 bool isFreeMultiWindowMode = callingSession->IsFreeMultiWindowMode();
427 bool isMidScene = callingSession->GetIsMidScene();
428 if (isCallingSessionFloating && isMainOrParentFloating && !isMidScene &&
429 (systemConfig_.uiType_ == UI_TYPE_PHONE || (systemConfig_.uiType_ == UI_TYPE_PAD && !isFreeMultiWindowMode))) {
430 TLOGI(WmsLogTag::WMS_KEYBOARD, "No need to raise calling session in float window.");
431 return false;
432 }
433
434 return true;
435 }
436
RaiseCallingSession(const WSRect & keyboardPanelRect,bool needCheckVisible,const std::shared_ptr<RSTransaction> & rsTransaction)437 void KeyboardSession::RaiseCallingSession(const WSRect& keyboardPanelRect, bool needCheckVisible,
438 const std::shared_ptr<RSTransaction>& rsTransaction)
439 {
440 if (!IsSessionForeground() || (Session::IsScbCoreEnabled() && needCheckVisible && !IsVisibleForeground())) {
441 TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard is not foreground.");
442 return;
443 }
444 sptr<SceneSession> callingSession = GetSceneSession(GetCallingSessionId());
445 if (callingSession == nullptr) {
446 TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is nullptr");
447 return;
448 }
449 NotifyKeyboardPanelInfoChange(keyboardPanelRect, true);
450
451 bool isCallingSessionFloating = (callingSession->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING);
452 if (!CheckIfNeedRaiseCallingSession(callingSession, isCallingSessionFloating)) {
453 return;
454 }
455
456 WSRect callingSessionRect = callingSession->GetSessionRect();
457 int32_t oriPosYBeforeRaisedByKeyboard = callingSession->GetOriPosYBeforeRaisedByKeyboard();
458 if (oriPosYBeforeRaisedByKeyboard != 0 && isCallingSessionFloating) {
459 callingSessionRect.posY_ = oriPosYBeforeRaisedByKeyboard;
460 }
461 // update panel rect for avoid area caculate
462 WSRect panelAvoidRect = keyboardPanelRect;
463 RecalculatePanelRectForAvoidArea(panelAvoidRect);
464 if (SessionHelper::IsEmptyRect(SessionHelper::GetOverlap(panelAvoidRect, callingSessionRect, 0, 0)) &&
465 oriPosYBeforeRaisedByKeyboard == 0) {
466 TLOGI(WmsLogTag::WMS_KEYBOARD, "No overlap area, keyboardRect: %{public}s, callingRect: %{public}s",
467 keyboardPanelRect.ToString().c_str(), callingSessionRect.ToString().c_str());
468 NotifyOccupiedAreaChangeInfo(callingSession, callingSessionRect, panelAvoidRect, rsTransaction);
469 return;
470 }
471
472 WSRect newRect = callingSessionRect;
473 int32_t statusHeight = GetStatusBarHeight();
474 if (isCallingSessionFloating && callingSessionRect.posY_ > statusHeight) {
475 if (oriPosYBeforeRaisedByKeyboard == 0) {
476 oriPosYBeforeRaisedByKeyboard = callingSessionRect.posY_;
477 callingSession->SetOriPosYBeforeRaisedByKeyboard(callingSessionRect.posY_);
478 }
479 // calculate new rect of calling session
480 newRect.posY_ = std::max(panelAvoidRect.posY_ - newRect.height_, statusHeight);
481 newRect.posY_ = std::min(oriPosYBeforeRaisedByKeyboard, newRect.posY_);
482 NotifyOccupiedAreaChangeInfo(callingSession, newRect, panelAvoidRect, rsTransaction);
483 callingSession->UpdateSessionRect(newRect, SizeChangeReason::UNDEFINED);
484 } else {
485 NotifyOccupiedAreaChangeInfo(callingSession, newRect, panelAvoidRect, rsTransaction);
486 }
487
488 TLOGI(WmsLogTag::WMS_KEYBOARD, "keyboardRect: %{public}s, CallSession OriRect: %{public}s, NewRect: %{public}s"
489 ", oriPosYBeforeRaisedByKeyboard: %{public}d, isCallingSessionFloating: %{public}d",
490 keyboardPanelRect.ToString().c_str(), callingSessionRect.ToString().c_str(), newRect.ToString().c_str(),
491 oriPosYBeforeRaisedByKeyboard, isCallingSessionFloating);
492 }
493
RestoreCallingSession(const std::shared_ptr<RSTransaction> & rsTransaction)494 void KeyboardSession::RestoreCallingSession(const std::shared_ptr<RSTransaction>& rsTransaction)
495 {
496 sptr<SceneSession> callingSession = GetSceneSession(GetCallingSessionId());
497 if (callingSession == nullptr) {
498 TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is nullptr");
499 return;
500 }
501 const WSRect& emptyRect = { 0, 0, 0, 0 };
502 int32_t oriPosYBeforeRaisedByKeyboard = callingSession->GetOriPosYBeforeRaisedByKeyboard();
503 NotifyOccupiedAreaChangeInfo(callingSession, emptyRect, emptyRect, rsTransaction);
504 if (oriPosYBeforeRaisedByKeyboard != 0 &&
505 callingSession->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING) {
506 WSRect callingSessionRestoringRect = callingSession->GetSessionRect();
507 if (oriPosYBeforeRaisedByKeyboard != 0) {
508 callingSessionRestoringRect.posY_ = oriPosYBeforeRaisedByKeyboard;
509 }
510 TLOGI(WmsLogTag::WMS_KEYBOARD, "oriPosYBeforeRaisedByKeyboard: %{public}d, sessionMode: %{public}d",
511 oriPosYBeforeRaisedByKeyboard, callingSession->GetWindowMode());
512 callingSession->UpdateSessionRect(callingSessionRestoringRect, SizeChangeReason::UNDEFINED);
513 }
514 callingSession->SetOriPosYBeforeRaisedByKeyboard(0); // 0: default value
515 }
516
517 // Use focused session id when calling session id is invalid.
UseFocusIdIfCallingSessionIdInvalid()518 void KeyboardSession::UseFocusIdIfCallingSessionIdInvalid()
519 {
520 if (GetSceneSession(GetCallingSessionId()) != nullptr) {
521 return;
522 }
523 uint32_t focusedSessionId = static_cast<uint32_t>(GetFocusedSessionId());
524 if (GetSceneSession(focusedSessionId) == nullptr) {
525 TLOGE(WmsLogTag::WMS_KEYBOARD, "Focused session is null, id: %{public}d", focusedSessionId);
526 } else {
527 TLOGI(WmsLogTag::WMS_KEYBOARD, "Using focusedSession id: %{public}d", focusedSessionId);
528 GetSessionProperty()->SetCallingSessionId(focusedSessionId);
529 }
530 }
531
UpdateCallingSessionIdAndPosition(uint32_t newCallingSessionId)532 void KeyboardSession::UpdateCallingSessionIdAndPosition(uint32_t newCallingSessionId)
533 {
534 auto sessionProperty = GetSessionProperty();
535 if (sessionProperty == nullptr) {
536 TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is nullptr");
537 return;
538 }
539 RestoreCallingSession();
540
541 sessionProperty->SetCallingSessionId(newCallingSessionId);
542 WSRect panelRect = { 0, 0, 0, 0 };
543 panelRect = (keyboardPanelSession_ == nullptr) ? panelRect : keyboardPanelSession_->GetSessionRect();
544 RaiseCallingSession(panelRect, true);
545 }
546
RelayoutKeyBoard()547 void KeyboardSession::RelayoutKeyBoard()
548 {
549 auto sessionProperty = GetSessionProperty();
550 if (sessionProperty == nullptr) {
551 TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is nullptr, relayout keyboard failed");
552 return;
553 }
554 uint32_t screenWidth = 0;
555 uint32_t screenHeight = 0;
556 SessionGravity gravity = GetKeyboardGravity();
557 if (gravity == SessionGravity::SESSION_GRAVITY_FLOAT) {
558 return;
559 }
560 if (!GetScreenWidthAndHeightFromClient(sessionProperty, screenWidth, screenHeight)) {
561 return;
562 }
563
564 auto requestRect = sessionProperty->GetRequestRect();
565 if (gravity == SessionGravity::SESSION_GRAVITY_BOTTOM) {
566 requestRect.width_ = screenWidth;
567 requestRect.posX_ = 0;
568 }
569 requestRect.posY_ = static_cast<int32_t>(screenHeight - requestRect.height_);
570 sessionProperty->SetRequestRect(requestRect);
571 TLOGI(WmsLogTag::WMS_KEYBOARD, "Id: %{public}d, rect: %{public}s", GetPersistentId(),
572 SessionHelper::TransferToWSRect(requestRect).ToString().c_str());
573 }
574
OpenKeyboardSyncTransaction()575 void KeyboardSession::OpenKeyboardSyncTransaction()
576 {
577 auto task = [weakThis = wptr(this)]() {
578 auto session = weakThis.promote();
579 if (!session) {
580 TLOGNE(WmsLogTag::WMS_KEYBOARD, "keyboard session is null");
581 return WSError::WS_ERROR_DESTROYED_OBJECT;
582 }
583 if (session->isKeyboardSyncTransactionOpen_) {
584 TLOGNI(WmsLogTag::WMS_KEYBOARD, "Keyboard sync transaction is already open");
585 return WSError::WS_OK;
586 }
587 TLOGNI(WmsLogTag::WMS_KEYBOARD, "Open keyboard sync");
588 session->isKeyboardSyncTransactionOpen_ = true;
589 auto transactionController = RSSyncTransactionController::GetInstance();
590 if (transactionController) {
591 transactionController->OpenSyncTransaction(session->GetEventHandler());
592 }
593 return WSError::WS_OK;
594 };
595 PostSyncTask(task);
596 }
597
CloseKeyboardSyncTransaction(const WSRect & keyboardPanelRect,bool isKeyboardShow,bool isRotating)598 void KeyboardSession::CloseKeyboardSyncTransaction(const WSRect& keyboardPanelRect,
599 bool isKeyboardShow, bool isRotating)
600 {
601 auto task = [weakThis = wptr(this), keyboardPanelRect, isKeyboardShow, isRotating]() {
602 auto session = weakThis.promote();
603 if (!session) {
604 TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboard session is null");
605 return WSError::WS_ERROR_DESTROYED_OBJECT;
606 }
607 TLOGNI(WmsLogTag::WMS_KEYBOARD, "Close keyboard sync, isKeyboardShow: %{public}d, isRotating: %{public}d",
608 isKeyboardShow, isRotating);
609 std::shared_ptr<RSTransaction> rsTransaction = nullptr;
610 if (!isRotating && session->isKeyboardSyncTransactionOpen_) {
611 rsTransaction = session->GetRSTransaction();
612 }
613 if (isKeyboardShow) {
614 // notify calling session when keyboard is not visible
615 if (session->GetCallingSessionId() == INVALID_WINDOW_ID) {
616 uint32_t focusedSessionId = static_cast<uint32_t>(session->GetFocusedSessionId());
617 TLOGI(WmsLogTag::WMS_KEYBOARD, "Using focusedSession id: %{public}d", focusedSessionId);
618 session->GetSessionProperty()->SetCallingSessionId(focusedSessionId);
619 }
620 session->RaiseCallingSession(keyboardPanelRect, false, rsTransaction);
621 session->UpdateKeyboardAvoidArea();
622 } else {
623 session->RestoreCallingSession(rsTransaction);
624 session->GetSessionProperty()->SetCallingSessionId(INVALID_WINDOW_ID);
625 }
626
627 if (!session->isKeyboardSyncTransactionOpen_) {
628 TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard sync transaction is closed");
629 return WSError::WS_OK;
630 }
631 session->isKeyboardSyncTransactionOpen_ = false;
632 auto transactionController = RSSyncTransactionController::GetInstance();
633 if (transactionController) {
634 transactionController->CloseSyncTransaction(session->GetEventHandler());
635 }
636 return WSError::WS_OK;
637 };
638 PostTask(task, "CloseKeyboardSyncTransaction");
639 }
640
GetRSTransaction()641 std::shared_ptr<RSTransaction> KeyboardSession::GetRSTransaction()
642 {
643 auto transactionController = RSSyncTransactionController::GetInstance();
644 std::shared_ptr<RSTransaction> rsTransaction = nullptr;
645 if (transactionController) {
646 rsTransaction = transactionController->GetRSTransaction();
647 }
648 return rsTransaction;
649 }
650
GetSessionScreenName()651 std::string KeyboardSession::GetSessionScreenName()
652 {
653 auto sessionProperty = GetSessionProperty();
654 if (sessionProperty != nullptr) {
655 auto displayId = sessionProperty->GetDisplayId();
656 auto screenSession = ScreenSessionManagerClient::GetInstance().GetScreenSession(displayId);
657 if (screenSession != nullptr) {
658 return screenSession->GetName();
659 }
660 }
661 return "";
662 }
663
MoveAndResizeKeyboard(const KeyboardLayoutParams & params,const sptr<WindowSessionProperty> & sessionProperty,bool isShow)664 void KeyboardSession::MoveAndResizeKeyboard(const KeyboardLayoutParams& params,
665 const sptr<WindowSessionProperty>& sessionProperty, bool isShow)
666 {
667 uint32_t screenWidth = 0;
668 uint32_t screenHeight = 0;
669 WSRect newWinRect = winRect_;
670 WSRect newRequestRect = GetSessionRequestRect();
671 bool ret = (isShow) ? GetScreenWidthAndHeightFromServer(sessionProperty, screenWidth, screenHeight) :
672 GetScreenWidthAndHeightFromClient(sessionProperty, screenWidth, screenHeight);
673 if (!ret) {
674 TLOGE(WmsLogTag::WMS_KEYBOARD, "getScreenWidthAndHeight failed, isShow: %{public}d", isShow);
675 return;
676 }
677 bool isLandscape = screenWidth > screenHeight ? true : false;
678 WSRect rect = isLandscape ? SessionHelper::TransferToWSRect(params.LandscapeKeyboardRect_) :
679 SessionHelper::TransferToWSRect(params.PortraitKeyboardRect_);
680 SessionGravity gravity = static_cast<SessionGravity>(params.gravity_);
681 if (gravity == SessionGravity::SESSION_GRAVITY_BOTTOM || gravity == SessionGravity::SESSION_GRAVITY_DEFAULT) {
682 newWinRect.width_ = (gravity == SessionGravity::SESSION_GRAVITY_BOTTOM) ?
683 static_cast<int32_t>(screenWidth) : rect.width_;
684 newWinRect.height_ = rect.height_;
685 newWinRect.posX_ = (gravity == SessionGravity::SESSION_GRAVITY_BOTTOM) ? 0 : rect.posX_;
686 newWinRect.posY_ = static_cast<int32_t>(screenHeight) - rect.height_;
687 newRequestRect= newWinRect;
688 } else if (rect.width_ > 0 && rect.height_ > 0) {
689 newWinRect = rect;
690 newRequestRect = newWinRect;
691 }
692 SetSessionRequestRect(newRequestRect);
693 TLOGI(WmsLogTag::WMS_KEYBOARD, "Id: %{public}d, gravity: %{public}d, rect: %{public}s, newRequestRect: %{public}s"
694 ", isLandscape: %{public}d, screenWidth: %{public}d, screenHeight: %{public}d", GetPersistentId(), gravity,
695 rect.ToString().c_str(), newRequestRect.ToString().c_str(), isLandscape, screenWidth, screenHeight);
696 }
697
IsVisibleForeground() const698 bool KeyboardSession::IsVisibleForeground() const
699 {
700 return isVisible_;
701 }
702
RecalculatePanelRectForAvoidArea(WSRect & panelRect)703 void KeyboardSession::RecalculatePanelRectForAvoidArea(WSRect& panelRect)
704 {
705 auto sessionProperty = GetSessionProperty();
706 KeyboardLayoutParams params = sessionProperty->GetKeyboardLayoutParams();
707 if (params.landscapeAvoidHeight_ < 0 || params.portraitAvoidHeight_ < 0) {
708 return;
709 }
710 if (params.LandscapePanelRect_.width_ != params.PortraitPanelRect_.width_) {
711 if (static_cast<uint32_t>(panelRect.width_ == params.LandscapePanelRect_.width_)) {
712 panelRect.posY_ += panelRect.height_ - params.landscapeAvoidHeight_;
713 panelRect.height_ = params.landscapeAvoidHeight_;
714 TLOGI(WmsLogTag::WMS_KEYBOARD, "landscapeAvoidHeight %{public}d", panelRect.height_);
715 return;
716 }
717 if (static_cast<uint32_t>(panelRect.width_ == params.PortraitPanelRect_.width_)) {
718 panelRect.posY_ += panelRect.height_ - params.portraitAvoidHeight_;
719 panelRect.height_ = params.portraitAvoidHeight_;
720 TLOGI(WmsLogTag::WMS_KEYBOARD, "portraitAvoidHeight %{public}d", panelRect.height_);
721 return;
722 }
723 }
724 uint32_t screenWidth = 0;
725 uint32_t screenHeight = 0;
726 bool result = GetScreenWidthAndHeightFromClient(sessionProperty, screenWidth, screenHeight);
727 if (!result) {
728 TLOGE(WmsLogTag::WMS_KEYBOARD, "getScreenWidthAndHeight failed");
729 return;
730 }
731 bool isLandscape = screenHeight < screenWidth;
732 int32_t height_ = isLandscape ? params.landscapeAvoidHeight_ : params.portraitAvoidHeight_;
733 panelRect.posY_ += panelRect.height_ - height_;
734 panelRect.height_ = height_;
735 TLOGI(WmsLogTag::WMS_KEYBOARD, "isLandscape %{public}d, avoidHeight %{public}d", isLandscape, panelRect.height_);
736 }
737
ChangeKeyboardViewMode(KeyboardViewMode mode)738 WSError KeyboardSession::ChangeKeyboardViewMode(KeyboardViewMode mode)
739 {
740 PostTask([weakThis = wptr(this), mode]() {
741 auto session = weakThis.promote();
742 if (!session) {
743 TLOGNE(WmsLogTag::WMS_KEYBOARD, "Session is null, change keyboard view mode failed");
744 return WSError::WS_ERROR_DESTROYED_OBJECT;
745 }
746 session->GetSessionProperty()->SetKeyboardViewMode(mode);
747 if (session->changeKeyboardViewModeFunc_) {
748 session->changeKeyboardViewModeFunc_(mode);
749 }
750 return WSError::WS_OK;
751 }, __func__);
752 return WSError::WS_OK;
753 }
754
SetKeyboardViewModeChangeListener(const NotifyKeyboarViewModeChangeFunc & func)755 void KeyboardSession::SetKeyboardViewModeChangeListener(const NotifyKeyboarViewModeChangeFunc& func)
756 {
757 PostTask([weakThis = wptr(this), func, where = __func__] {
758 auto session = weakThis.promote();
759 if (!session || !func) {
760 TLOGNE(WmsLogTag::WMS_KEYBOARD, "%{public}s session or keyboardViewModeChangeFunc is null", where);
761 return WSError::WS_ERROR_DESTROYED_OBJECT;
762 }
763 session->changeKeyboardViewModeFunc_ = func;
764 return WSError::WS_OK;
765 }, __func__);
766 }
767 } // namespace OHOS::Rosen
768