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