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