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->UseFocusIdIfCallingSessionIdInvalid();
83         TLOGI(WmsLogTag::WMS_KEYBOARD, "Show keyboard session, id: %{public}d, calling session id: %{public}d",
84             session->GetPersistentId(), session->GetCallingSessionId());
85         session->MoveAndResizeKeyboard(property->GetKeyboardLayoutParams(), property, true);
86         session->NotifySessionRectChange(session->GetSessionRequestRect(), SizeChangeReason::UNDEFINED);
87         return session->SceneSession::Foreground(property);
88     };
89     PostTask(task, "Show");
90     return WSError::WS_OK;
91 }
92 
Hide()93 WSError KeyboardSession::Hide()
94 {
95     if (!CheckPermissionWithPropertyAnimation(GetSessionProperty())) {
96         return WSError::WS_ERROR_NOT_SYSTEM_APP;
97     }
98     auto task = [weakThis = wptr(this)]() {
99         auto session = weakThis.promote();
100         if (!session) {
101             TLOGE(WmsLogTag::WMS_KEYBOARD, "Session is null, hide keyboard failed!");
102             return WSError::WS_ERROR_DESTROYED_OBJECT;
103         }
104 
105         TLOGI(WmsLogTag::WMS_KEYBOARD, "Hide keyboard session, set callingSessionId to 0, id: %{public}d",
106             session->GetPersistentId());
107         auto ret = session->SetActive(false);
108         if (ret != WSError::WS_OK) {
109             TLOGE(WmsLogTag::WMS_KEYBOARD, "Set session active state failed, ret: %{public}d", ret);
110             return ret;
111         }
112         ret = session->SceneSession::Background();
113         WSRect rect = {0, 0, 0, 0};
114         session->NotifyKeyboardPanelInfoChange(rect, false);
115         if (session->systemConfig_.uiType_ == UI_TYPE_PC || session->GetSessionScreenName() == "HiCar"
116             || session->GetSessionScreenName() == "SuperLauncher") {
117             TLOGD(WmsLogTag::WMS_KEYBOARD, "pc or virtual screen, restore calling session");
118             session->RestoreCallingSession();
119             auto sessionProperty = session->GetSessionProperty();
120             if (sessionProperty) {
121                 sessionProperty->SetCallingSessionId(INVALID_WINDOW_ID);
122             }
123         }
124         return ret;
125     };
126     PostTask(task, "Hide");
127     return WSError::WS_OK;
128 }
129 
Disconnect(bool isFromClient,const std::string & identityToken)130 WSError KeyboardSession::Disconnect(bool isFromClient, const std::string& identityToken)
131 {
132     auto task = [weakThis = wptr(this), isFromClient]() {
133         auto session = weakThis.promote();
134         if (!session) {
135             TLOGE(WmsLogTag::WMS_KEYBOARD, "Session is null, disconnect keyboard session failed!");
136             return WSError::WS_ERROR_DESTROYED_OBJECT;
137         }
138         TLOGI(WmsLogTag::WMS_KEYBOARD, "Disconnect keyboard session, id: %{public}d, isFromClient: %{public}d",
139             session->GetPersistentId(), isFromClient);
140         session->SceneSession::Disconnect(isFromClient);
141         WSRect rect = {0, 0, 0, 0};
142         session->NotifyKeyboardPanelInfoChange(rect, false);
143         session->RestoreCallingSession();
144         auto sessionProperty = session->GetSessionProperty();
145         if (sessionProperty) {
146             sessionProperty->SetCallingSessionId(INVALID_WINDOW_ID);
147         }
148         return WSError::WS_OK;
149     };
150     PostTask(task, "Disconnect");
151     return WSError::WS_OK;
152 }
153 
NotifyClientToUpdateRect(const std::string & updateReason,std::shared_ptr<RSTransaction> rsTransaction)154 WSError KeyboardSession::NotifyClientToUpdateRect(const std::string& updateReason,
155     std::shared_ptr<RSTransaction> rsTransaction)
156 {
157     auto task = [weakThis = wptr(this), rsTransaction, updateReason]() {
158         auto session = weakThis.promote();
159         if (!session) {
160             TLOGE(WmsLogTag::WMS_KEYBOARD, "session is null");
161             return WSError::WS_ERROR_DESTROYED_OBJECT;
162         }
163 
164         WSError ret = session->NotifyClientToUpdateRectTask(updateReason, rsTransaction);
165         return ret;
166     };
167     PostTask(task, "NotifyClientToUpdateRect");
168     return WSError::WS_OK;
169 }
170 
UpdateKeyboardAvoidArea()171 void KeyboardSession::UpdateKeyboardAvoidArea()
172 {
173     if (!IsSessionForeground() || (Session::IsScbCoreEnabled() && !IsVisibleForeground())) {
174         TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard is not foreground, no need update avoid Area");
175         return;
176     }
177     if (specificCallback_ != nullptr && specificCallback_->onUpdateAvoidArea_ != nullptr) {
178         if (Session::IsScbCoreEnabled()) {
179             dirtyFlags_ |= static_cast<uint32_t>(SessionUIDirtyFlag::AVOID_AREA);
180         } else {
181             specificCallback_->onUpdateAvoidArea_(GetPersistentId());
182         }
183     }
184 }
185 
OnKeyboardPanelUpdated()186 void KeyboardSession::OnKeyboardPanelUpdated()
187 {
188     TLOGI(WmsLogTag::WMS_KEYBOARD, "id: %{public}d", GetPersistentId());
189     WSRect panelRect = { 0, 0, 0, 0 };
190     panelRect = (keyboardPanelSession_ == nullptr) ? panelRect : keyboardPanelSession_->GetSessionRect();
191     RaiseCallingSession(panelRect, true);
192     UpdateKeyboardAvoidArea();
193 }
194 
OnCallingSessionUpdated()195 void KeyboardSession::OnCallingSessionUpdated()
196 {
197     TLOGI(WmsLogTag::WMS_KEYBOARD, "id: %{public}d", GetPersistentId());
198     if (!IsSessionForeground() || (Session::IsScbCoreEnabled() && !IsVisibleForeground())) {
199         TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard is not foreground.");
200         return;
201     }
202     WSRect panelRect = { 0, 0, 0, 0 };
203     panelRect = (keyboardPanelSession_ == nullptr) ? panelRect : keyboardPanelSession_->GetSessionRect();
204     sptr<SceneSession> callingSession = GetSceneSession(GetCallingSessionId());
205     if (callingSession == nullptr) {
206         TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is nullptr");
207         return;
208     }
209     bool isCallingSessionFloating = (callingSession->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING);
210     if (!CheckIfNeedRaiseCallingSession(callingSession, isCallingSessionFloating)) {
211         return;
212     }
213     WSRect callingSessionRect = callingSession->GetSessionRect();
214     NotifyOccupiedAreaChangeInfo(callingSession, callingSessionRect, panelRect);
215 
216     TLOGI(WmsLogTag::WMS_KEYBOARD, "callSession Rect: %{public}s", callingSessionRect.ToString().c_str());
217 }
218 
SetKeyboardSessionGravity(SessionGravity gravity)219 WSError KeyboardSession::SetKeyboardSessionGravity(SessionGravity gravity)
220 {
221     TLOGI(WmsLogTag::WMS_KEYBOARD, "keyboardId: %{public}d, gravity: %{public}d", GetPersistentId(), gravity);
222     if (keyboardGravityChangeFunc_) {
223         keyboardGravityChangeFunc_(gravity);
224     }
225     RelayoutKeyBoard();
226     if (gravity == SessionGravity::SESSION_GRAVITY_FLOAT) {
227         SetWindowAnimationFlag(false);
228         if (IsSessionForeground()) {
229             RestoreCallingSession();
230         }
231     } else {
232         SetWindowAnimationFlag(true);
233     }
234     return WSError::WS_OK;
235 }
236 
SetCallingSessionId(uint32_t callingSessionId)237 void KeyboardSession::SetCallingSessionId(uint32_t callingSessionId)
238 {
239     auto task = [weakThis = wptr(this), callingSessionId]() mutable {
240         auto session = weakThis.promote();
241         if (!session) {
242             TLOGE(WmsLogTag::WMS_KEYBOARD, "session is null");
243             return;
244         }
245         if (session->GetSceneSession(callingSessionId) == nullptr) {
246             uint32_t focusedSessionId = static_cast<uint32_t>(session->GetFocusedSessionId());
247             if (session->GetSceneSession(focusedSessionId) == nullptr) {
248                 TLOGE(WmsLogTag::WMS_KEYBOARD, "Focused session is null, set id: %{public}d failed", focusedSessionId);
249                 return;
250             } else {
251                 TLOGI(WmsLogTag::WMS_KEYBOARD, "Using focusedSession id: %{public}d", focusedSessionId);
252                 callingSessionId = focusedSessionId;
253             }
254         }
255         uint32_t curCallingSessionId = session->GetCallingSessionId();
256         TLOGI(WmsLogTag::WMS_KEYBOARD, "curId: %{public}d, newId: %{public}d", curCallingSessionId, callingSessionId);
257         auto sessionProperty = session->GetSessionProperty();
258         if (sessionProperty != nullptr) {
259             if (curCallingSessionId != INVALID_WINDOW_ID && callingSessionId != curCallingSessionId &&
260                 session->IsSessionForeground()) {
261                 session->MoveAndResizeKeyboard(sessionProperty->GetKeyboardLayoutParams(), sessionProperty, true);
262                 session->NotifySessionRectChange(session->GetSessionRequestRect(), SizeChangeReason::UNDEFINED);
263 
264                 session->UpdateCallingSessionIdAndPosition(callingSessionId);
265             } else {
266                 sessionProperty->SetCallingSessionId(callingSessionId);
267             }
268         }
269         if (session->keyboardCallback_ == nullptr ||
270             session->keyboardCallback_->onCallingSessionIdChange_ == nullptr) {
271             TLOGE(WmsLogTag::WMS_KEYBOARD, "KeyboardCallback_, callingSessionId: %{public}d", callingSessionId);
272             return;
273         }
274         session->keyboardCallback_->onCallingSessionIdChange_(callingSessionId);
275     };
276     PostTask(task, "SetCallingSessionId");
277     return;
278 }
279 
GetCallingSessionId()280 uint32_t KeyboardSession::GetCallingSessionId()
281 {
282     auto sessionProperty = GetSessionProperty();
283     if (sessionProperty == nullptr) {
284         TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is null");
285         return INVALID_SESSION_ID;
286     }
287     return sessionProperty->GetCallingSessionId();
288 }
289 
AdjustKeyboardLayout(const KeyboardLayoutParams & params)290 WSError KeyboardSession::AdjustKeyboardLayout(const KeyboardLayoutParams& params)
291 {
292     auto task = [weakThis = wptr(this), params]() -> WSError {
293         auto session = weakThis.promote();
294         if (!session) {
295             TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboard session is null");
296             return WSError::WS_ERROR_DESTROYED_OBJECT;
297         }
298         auto sessionProperty = session->GetSessionProperty();
299         if (sessionProperty == nullptr) {
300             TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is null");
301             return WSError::WS_ERROR_NULLPTR;
302         }
303         sessionProperty->SetKeyboardLayoutParams(params);
304         session->MoveAndResizeKeyboard(params, sessionProperty, false);
305         session->SetKeyboardSessionGravity(static_cast<SessionGravity>(params.gravity_));
306         if (session->adjustKeyboardLayoutFunc_) {
307             session->adjustKeyboardLayoutFunc_(params);
308         }
309         session->NotifySessionRectChange(session->GetSessionRequestRect(), SizeChangeReason::UNDEFINED);
310         TLOGI(WmsLogTag::WMS_KEYBOARD, "adjust keyboard layout, keyboardId: %{public}d, gravity: %{public}u, "
311             "LandscapeKeyboardRect: %{public}s, PortraitKeyboardRect: %{public}s, LandscapePanelRect: %{public}s, "
312             "PortraitPanelRect: %{public}s, requestRect: %{public}s", session->GetPersistentId(),
313             static_cast<uint32_t>(params.gravity_), params.LandscapeKeyboardRect_.ToString().c_str(),
314             params.PortraitKeyboardRect_.ToString().c_str(), params.LandscapePanelRect_.ToString().c_str(),
315             params.PortraitPanelRect_.ToString().c_str(), session->GetSessionRequestRect().ToString().c_str());
316         return WSError::WS_OK;
317     };
318     PostTask(task, "AdjustKeyboardLayout");
319     return WSError::WS_OK;
320 }
321 
GetSceneSession(uint32_t persistentId)322 sptr<SceneSession> KeyboardSession::GetSceneSession(uint32_t persistentId)
323 {
324     if (keyboardCallback_ == nullptr || keyboardCallback_->onGetSceneSession_ == nullptr) {
325         TLOGE(WmsLogTag::WMS_KEYBOARD, "Get scene session failed, persistentId: %{public}d", persistentId);
326         return nullptr;
327     }
328     return keyboardCallback_->onGetSceneSession_(persistentId);
329 }
330 
GetFocusedSessionId()331 int32_t KeyboardSession::GetFocusedSessionId()
332 {
333     if (keyboardCallback_ == nullptr || keyboardCallback_->onGetFocusedSessionId_ == nullptr) {
334         TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboardCallback_ is nullptr, get focusedSessionId failed!");
335         return INVALID_WINDOW_ID;
336     }
337     return keyboardCallback_->onGetFocusedSessionId_();
338 }
339 
GetStatusBarHeight()340 int32_t KeyboardSession::GetStatusBarHeight()
341 {
342     int32_t statusBarHeight = 0;
343     auto sessionProperty = GetSessionProperty();
344     if (specificCallback_ == nullptr || specificCallback_->onGetSceneSessionVectorByType_ == nullptr ||
345         sessionProperty == nullptr) {
346         TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboardCallback_ or session property is null, get statusBarHeight failed!");
347         return statusBarHeight;
348     }
349 
350     std::vector<sptr<SceneSession>> statusBarVector = specificCallback_->onGetSceneSessionVectorByType_(
351         WindowType::WINDOW_TYPE_STATUS_BAR, GetSessionProperty()->GetDisplayId());
352     for (const auto& statusBar : statusBarVector) {
353         if (statusBar != nullptr && statusBar->GetSessionRect().height_ > statusBarHeight) {
354             statusBarHeight = statusBar->GetSessionRect().height_;
355         }
356     }
357     TLOGI(WmsLogTag::WMS_KEYBOARD, "Status Bar height: %{public}d", statusBarHeight);
358     return statusBarHeight;
359 }
360 
NotifyOccupiedAreaChangeInfo(const sptr<SceneSession> & callingSession,const WSRect & rect,const WSRect & occupiedArea,const std::shared_ptr<RSTransaction> & rsTransaction)361 void KeyboardSession::NotifyOccupiedAreaChangeInfo(const sptr<SceneSession>& callingSession, const WSRect& rect,
362     const WSRect& occupiedArea, const std::shared_ptr<RSTransaction>& rsTransaction)
363 {
364     // if keyboard will occupy calling, notify calling window the occupied area and safe height
365     const WSRect& safeRect = SessionHelper::GetOverlap(occupiedArea, rect, 0, 0);
366     const WSRect& lastSafeRect = callingSession->GetLastSafeRect();
367     if (lastSafeRect == safeRect) {
368         TLOGI(WmsLogTag::WMS_KEYBOARD, "SafeRect is same to lastSafeRect: %{public}s", safeRect.ToString().c_str());
369         return;
370     }
371     callingSession->SetLastSafeRect(safeRect);
372     double textFieldPositionY = 0.0;
373     double textFieldHeight = 0.0;
374     auto sessionProperty = GetSessionProperty();
375     if (sessionProperty != nullptr) {
376         textFieldPositionY = sessionProperty->GetTextFieldPositionY();
377         textFieldHeight = sessionProperty->GetTextFieldHeight();
378     }
379     sptr<OccupiedAreaChangeInfo> info = sptr<OccupiedAreaChangeInfo>::MakeSptr(OccupiedAreaType::TYPE_INPUT,
380         SessionHelper::TransferToRect(safeRect), safeRect.height_, textFieldPositionY, textFieldHeight);
381     TLOGI(WmsLogTag::WMS_KEYBOARD, "lastSafeRect: %{public}s, safeRect: %{public}s, keyboardRect: %{public}s, "
382         "textFieldPositionY_: %{public}f, textFieldHeight_: %{public}f", lastSafeRect.ToString().c_str(),
383         safeRect.ToString().c_str(), occupiedArea.ToString().c_str(), textFieldPositionY, textFieldHeight);
384     callingSession->NotifyOccupiedAreaChangeInfo(info, rsTransaction);
385 }
386 
NotifyKeyboardPanelInfoChange(WSRect rect,bool isKeyboardPanelShow)387 void KeyboardSession::NotifyKeyboardPanelInfoChange(WSRect rect, bool isKeyboardPanelShow)
388 {
389     if (!sessionStage_) {
390         TLOGE(WmsLogTag::WMS_KEYBOARD, "sessionStage_ is nullptr, notify keyboard panel rect change failed");
391         return;
392     }
393     KeyboardPanelInfo keyboardPanelInfo;
394     keyboardPanelInfo.rect_ = SessionHelper::TransferToRect(rect);
395     keyboardPanelInfo.gravity_ = static_cast<WindowGravity>(GetKeyboardGravity());
396     keyboardPanelInfo.isShowing_ = isKeyboardPanelShow;
397 
398     sessionStage_->NotifyKeyboardPanelInfoChange(keyboardPanelInfo);
399 }
400 
CheckIfNeedRaiseCallingSession(sptr<SceneSession> callingSession,bool isCallingSessionFloating)401 bool KeyboardSession::CheckIfNeedRaiseCallingSession(sptr<SceneSession> callingSession, bool isCallingSessionFloating)
402 {
403     if (callingSession == nullptr) {
404         TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is nullptr");
405         return false;
406     }
407 
408     SessionGravity gravity = GetKeyboardGravity();
409     if (gravity == SessionGravity::SESSION_GRAVITY_FLOAT) {
410         TLOGI(WmsLogTag::WMS_KEYBOARD, "No need to raise calling session, gravity: %{public}d", gravity);
411         return false;
412     }
413     bool isMainOrParentFloating = WindowHelper::IsMainWindow(callingSession->GetWindowType()) ||
414         (WindowHelper::IsSubWindow(callingSession->GetWindowType()) && callingSession->GetParentSession() != nullptr &&
415          callingSession->GetParentSession()->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING);
416     bool isFreeMultiWindowMode = callingSession->IsFreeMultiWindowMode();
417     bool isMidScene = callingSession->GetIsMidScene();
418     if (isCallingSessionFloating && isMainOrParentFloating && !isMidScene &&
419         (systemConfig_.uiType_ == UI_TYPE_PHONE || (systemConfig_.uiType_ == UI_TYPE_PAD && !isFreeMultiWindowMode))) {
420         TLOGI(WmsLogTag::WMS_KEYBOARD, "No need to raise calling session in float window.");
421         return false;
422     }
423 
424     return true;
425 }
426 
RaiseCallingSession(const WSRect & keyboardPanelRect,bool needCheckVisible,const std::shared_ptr<RSTransaction> & rsTransaction)427 void KeyboardSession::RaiseCallingSession(const WSRect& keyboardPanelRect, bool needCheckVisible,
428     const std::shared_ptr<RSTransaction>& rsTransaction)
429 {
430     if (!IsSessionForeground() || (Session::IsScbCoreEnabled() && needCheckVisible && !IsVisibleForeground())) {
431         TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard is not foreground.");
432         return;
433     }
434     sptr<SceneSession> callingSession = GetSceneSession(GetCallingSessionId());
435     if (callingSession == nullptr) {
436         TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is nullptr");
437         return;
438     }
439     NotifyKeyboardPanelInfoChange(keyboardPanelRect, true);
440 
441     bool isCallingSessionFloating = (callingSession->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING);
442     if (!CheckIfNeedRaiseCallingSession(callingSession, isCallingSessionFloating)) {
443         return;
444     }
445 
446     WSRect callingSessionRect = callingSession->GetSessionRect();
447     int32_t oriPosYBeforeRaisedByKeyboard = callingSession->GetOriPosYBeforeRaisedByKeyboard();
448     if (oriPosYBeforeRaisedByKeyboard != 0 && isCallingSessionFloating) {
449         callingSessionRect.posY_ = oriPosYBeforeRaisedByKeyboard;
450     }
451     if (SessionHelper::IsEmptyRect(SessionHelper::GetOverlap(keyboardPanelRect, callingSessionRect, 0, 0)) &&
452         oriPosYBeforeRaisedByKeyboard == 0) {
453         TLOGI(WmsLogTag::WMS_KEYBOARD, "No overlap area, keyboardRect: %{public}s, callingRect: %{public}s",
454             keyboardPanelRect.ToString().c_str(), callingSessionRect.ToString().c_str());
455         NotifyOccupiedAreaChangeInfo(callingSession, callingSessionRect, keyboardPanelRect, rsTransaction);
456         return;
457     }
458 
459     WSRect newRect = callingSessionRect;
460     int32_t statusHeight = GetStatusBarHeight();
461     if (isCallingSessionFloating && callingSessionRect.posY_ > statusHeight) {
462         if (oriPosYBeforeRaisedByKeyboard == 0) {
463             oriPosYBeforeRaisedByKeyboard = callingSessionRect.posY_;
464             callingSession->SetOriPosYBeforeRaisedByKeyboard(callingSessionRect.posY_);
465         }
466         // calculate new rect of calling session
467         newRect.posY_ = std::max(keyboardPanelRect.posY_ - newRect.height_, statusHeight);
468         newRect.posY_ = std::min(oriPosYBeforeRaisedByKeyboard, newRect.posY_);
469         NotifyOccupiedAreaChangeInfo(callingSession, newRect, keyboardPanelRect, rsTransaction);
470         callingSession->UpdateSessionRect(newRect, SizeChangeReason::UNDEFINED);
471     } else {
472         NotifyOccupiedAreaChangeInfo(callingSession, newRect, keyboardPanelRect, rsTransaction);
473     }
474 
475     TLOGI(WmsLogTag::WMS_KEYBOARD, "keyboardRect: %{public}s, CallSession OriRect: %{public}s, NewRect: %{public}s"
476         ", oriPosYBeforeRaisedByKeyboard: %{public}d, isCallingSessionFloating: %{public}d",
477         keyboardPanelRect.ToString().c_str(), callingSessionRect.ToString().c_str(), newRect.ToString().c_str(),
478         oriPosYBeforeRaisedByKeyboard, isCallingSessionFloating);
479 }
480 
RestoreCallingSession(const std::shared_ptr<RSTransaction> & rsTransaction)481 void KeyboardSession::RestoreCallingSession(const std::shared_ptr<RSTransaction>& rsTransaction)
482 {
483     sptr<SceneSession> callingSession = GetSceneSession(GetCallingSessionId());
484     if (callingSession == nullptr) {
485         TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is nullptr");
486         return;
487     }
488     const WSRect& emptyRect = { 0, 0, 0, 0 };
489     int32_t oriPosYBeforeRaisedByKeyboard = callingSession->GetOriPosYBeforeRaisedByKeyboard();
490     NotifyOccupiedAreaChangeInfo(callingSession, emptyRect, emptyRect, rsTransaction);
491     if (oriPosYBeforeRaisedByKeyboard != 0 &&
492         callingSession->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING) {
493         WSRect callingSessionRestoringRect = callingSession->GetSessionRect();
494         if (oriPosYBeforeRaisedByKeyboard != 0) {
495             callingSessionRestoringRect.posY_ = oriPosYBeforeRaisedByKeyboard;
496         }
497         TLOGI(WmsLogTag::WMS_KEYBOARD, "oriPosYBeforeRaisedByKeyboard: %{public}d, sessionMode: %{public}d",
498             oriPosYBeforeRaisedByKeyboard, callingSession->GetWindowMode());
499         callingSession->UpdateSessionRect(callingSessionRestoringRect, SizeChangeReason::UNDEFINED);
500     }
501     callingSession->SetOriPosYBeforeRaisedByKeyboard(0); // 0: default value
502 }
503 
504 // Use focused session id when calling session id is invalid.
UseFocusIdIfCallingSessionIdInvalid()505 void KeyboardSession::UseFocusIdIfCallingSessionIdInvalid()
506 {
507     if (GetSceneSession(GetCallingSessionId()) != nullptr) {
508         return;
509     }
510     uint32_t focusedSessionId = static_cast<uint32_t>(GetFocusedSessionId());
511     if (GetSceneSession(focusedSessionId) == nullptr) {
512         TLOGE(WmsLogTag::WMS_KEYBOARD, "Focused session is null, id: %{public}d", focusedSessionId);
513     } else {
514         TLOGI(WmsLogTag::WMS_KEYBOARD, "Using focusedSession id: %{public}d", focusedSessionId);
515             GetSessionProperty()->SetCallingSessionId(focusedSessionId);
516     }
517 }
518 
UpdateCallingSessionIdAndPosition(uint32_t newCallingSessionId)519 void KeyboardSession::UpdateCallingSessionIdAndPosition(uint32_t newCallingSessionId)
520 {
521     auto sessionProperty = GetSessionProperty();
522     if (sessionProperty == nullptr) {
523         TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is nullptr");
524         return;
525     }
526     RestoreCallingSession();
527 
528     sessionProperty->SetCallingSessionId(newCallingSessionId);
529     WSRect panelRect = { 0, 0, 0, 0 };
530     panelRect = (keyboardPanelSession_ == nullptr) ? panelRect : keyboardPanelSession_->GetSessionRect();
531     RaiseCallingSession(panelRect, true);
532 }
533 
RelayoutKeyBoard()534 void KeyboardSession::RelayoutKeyBoard()
535 {
536     auto sessionProperty = GetSessionProperty();
537     if (sessionProperty == nullptr) {
538         TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is nullptr, relayout keyboard failed");
539         return;
540     }
541     uint32_t screenWidth = 0;
542     uint32_t screenHeight = 0;
543     SessionGravity gravity = GetKeyboardGravity();
544     if (gravity == SessionGravity::SESSION_GRAVITY_FLOAT) {
545         return;
546     }
547     if (!GetScreenWidthAndHeightFromClient(sessionProperty, screenWidth, screenHeight)) {
548         return;
549     }
550 
551     auto requestRect = sessionProperty->GetRequestRect();
552     if (gravity == SessionGravity::SESSION_GRAVITY_BOTTOM) {
553         requestRect.width_ = screenWidth;
554         requestRect.posX_ = 0;
555     }
556     requestRect.posY_ = static_cast<int32_t>(screenHeight - requestRect.height_);
557     sessionProperty->SetRequestRect(requestRect);
558     TLOGI(WmsLogTag::WMS_KEYBOARD, "Id: %{public}d, rect: %{public}s", GetPersistentId(),
559         SessionHelper::TransferToWSRect(requestRect).ToString().c_str());
560 }
561 
OpenKeyboardSyncTransaction()562 void KeyboardSession::OpenKeyboardSyncTransaction()
563 {
564     auto task = [weakThis = wptr(this)]() {
565         auto session = weakThis.promote();
566         if (!session) {
567             TLOGNE(WmsLogTag::WMS_KEYBOARD, "keyboard session is null");
568             return WSError::WS_ERROR_DESTROYED_OBJECT;
569         }
570         if (session->isKeyboardSyncTransactionOpen_) {
571             TLOGNI(WmsLogTag::WMS_KEYBOARD, "Keyboard sync transaction is already open");
572             return WSError::WS_OK;
573         }
574         TLOGNI(WmsLogTag::WMS_KEYBOARD, "Open keyboard sync");
575         session->isKeyboardSyncTransactionOpen_ = true;
576         auto transactionController = RSSyncTransactionController::GetInstance();
577         if (transactionController) {
578             transactionController->OpenSyncTransaction(session->GetEventHandler());
579         }
580         return WSError::WS_OK;
581     };
582     PostSyncTask(task);
583 }
584 
CloseKeyboardSyncTransaction(const WSRect & keyboardPanelRect,bool isKeyboardShow,bool isRotating)585 void KeyboardSession::CloseKeyboardSyncTransaction(const WSRect& keyboardPanelRect,
586     bool isKeyboardShow, bool isRotating)
587 {
588     auto task = [weakThis = wptr(this), keyboardPanelRect, isKeyboardShow, isRotating]() {
589         auto session = weakThis.promote();
590         if (!session) {
591             TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboard session is null");
592             return WSError::WS_ERROR_DESTROYED_OBJECT;
593         }
594         TLOGNI(WmsLogTag::WMS_KEYBOARD, "Close keyboard sync, isKeyboardShow: %{public}d, isRotating: %{public}d",
595             isKeyboardShow, isRotating);
596         std::shared_ptr<RSTransaction> rsTransaction = nullptr;
597         if (!isRotating && session->isKeyboardSyncTransactionOpen_) {
598             rsTransaction = session->GetRSTransaction();
599         }
600         if (isKeyboardShow) {
601             // notify calling session when keyboard is not visible
602             session->RaiseCallingSession(keyboardPanelRect, false, rsTransaction);
603             session->UpdateKeyboardAvoidArea();
604         } else {
605             session->RestoreCallingSession(rsTransaction);
606             auto sessionProperty = session->GetSessionProperty();
607             if (sessionProperty) {
608                 sessionProperty->SetCallingSessionId(INVALID_WINDOW_ID);
609             }
610         }
611 
612         if (!session->isKeyboardSyncTransactionOpen_) {
613             TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard sync transaction is closed");
614             return WSError::WS_OK;
615         }
616         session->isKeyboardSyncTransactionOpen_ = false;
617         auto transactionController = RSSyncTransactionController::GetInstance();
618         if (transactionController) {
619             transactionController->CloseSyncTransaction(session->GetEventHandler());
620         }
621         return WSError::WS_OK;
622     };
623     PostTask(task, "CloseKeyboardSyncTransaction");
624 }
625 
GetRSTransaction()626 std::shared_ptr<RSTransaction> KeyboardSession::GetRSTransaction()
627 {
628     auto transactionController = RSSyncTransactionController::GetInstance();
629     std::shared_ptr<RSTransaction> rsTransaction = nullptr;
630     if (transactionController) {
631         rsTransaction = transactionController->GetRSTransaction();
632     }
633     return rsTransaction;
634 }
635 
GetSessionScreenName()636 std::string KeyboardSession::GetSessionScreenName()
637 {
638     auto sessionProperty = GetSessionProperty();
639     if (sessionProperty != nullptr) {
640         auto displayId = sessionProperty->GetDisplayId();
641         auto screenSession = ScreenSessionManagerClient::GetInstance().GetScreenSession(displayId);
642         if (screenSession != nullptr) {
643             return screenSession->GetName();
644         }
645     }
646     return "";
647 }
648 
MoveAndResizeKeyboard(const KeyboardLayoutParams & params,const sptr<WindowSessionProperty> & sessionProperty,bool isShow)649 void KeyboardSession::MoveAndResizeKeyboard(const KeyboardLayoutParams& params,
650     const sptr<WindowSessionProperty>& sessionProperty, bool isShow)
651 {
652     uint32_t screenWidth = 0;
653     uint32_t screenHeight = 0;
654     WSRect newWinRect = winRect_;
655     WSRect newRequestRect = GetSessionRequestRect();
656     bool ret = (isShow) ? GetScreenWidthAndHeightFromServer(sessionProperty, screenWidth, screenHeight) :
657         GetScreenWidthAndHeightFromClient(sessionProperty, screenWidth, screenHeight);
658     if (!ret) {
659         TLOGE(WmsLogTag::WMS_KEYBOARD, "getScreenWidthAndHeight failed, isShow: %{public}d", isShow);
660         return;
661     }
662     bool isLandscape = screenWidth > screenHeight ? true : false;
663     WSRect rect = isLandscape ? SessionHelper::TransferToWSRect(params.LandscapeKeyboardRect_) :
664         SessionHelper::TransferToWSRect(params.PortraitKeyboardRect_);
665     SessionGravity gravity = static_cast<SessionGravity>(params.gravity_);
666     if (gravity == SessionGravity::SESSION_GRAVITY_BOTTOM || gravity == SessionGravity::SESSION_GRAVITY_DEFAULT) {
667         newWinRect.width_ = (gravity == SessionGravity::SESSION_GRAVITY_BOTTOM) ?
668             static_cast<int32_t>(screenWidth) : rect.width_;
669         newWinRect.height_ = rect.height_;
670         newWinRect.posX_ = (gravity == SessionGravity::SESSION_GRAVITY_BOTTOM) ? 0 : rect.posX_;
671         newWinRect.posY_ = static_cast<int32_t>(screenHeight) - rect.height_;
672         newRequestRect= newWinRect;
673     } else if (rect.width_ > 0 && rect.height_ > 0) {
674         newWinRect = rect;
675         newRequestRect = newWinRect;
676     }
677     SetSessionRequestRect(newRequestRect);
678     TLOGI(WmsLogTag::WMS_KEYBOARD, "Id: %{public}d, gravity: %{public}d, rect: %{public}s, newRequestRect: %{public}s"
679         ", isLandscape: %{public}d, screenWidth: %{public}d, screenHeight: %{public}d", GetPersistentId(), gravity,
680         rect.ToString().c_str(), newRequestRect.ToString().c_str(), isLandscape, screenWidth, screenHeight);
681 }
682 
IsVisibleForeground() const683 bool KeyboardSession::IsVisibleForeground() const
684 {
685     return isVisible_;
686 }
687 } // namespace OHOS::Rosen
688