• 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 "perform_reporter.h"
17 #include "session/host/include/keyboard_session.h"
18 
19 #include <hitrace_meter.h>
20 #include "rs_adapter.h"
21 #include "screen_session_manager_client/include/screen_session_manager_client.h"
22 #include "session_helper.h"
23 #include <ui/rs_surface_node.h>
24 #include "window_helper.h"
25 #include "window_manager_hilog.h"
26 
27 #define RETURN_IF_PARAM_IS_NULL(param, ...)                                   \
28     do {                                                                      \
29         if (!param) {                                                         \
30             TLOGE(WmsLogTag::WMS_KEYBOARD, "The %{public}s is null", #param); \
31             return __VA_ARGS__;                                               \
32         }                                                                     \
33     } while (false)                                                           \
34 
35 namespace OHOS::Rosen {
36 namespace {
37     constexpr float MOVE_DRAG_POSITION_Z = 100.5f;
38     constexpr int32_t INSERT_TO_THE_END = -1;
39 }
KeyboardSession(const SessionInfo & info,const sptr<SpecificSessionCallback> & specificCallback,const sptr<KeyboardSessionCallback> & keyboardCallback)40 KeyboardSession::KeyboardSession(const SessionInfo& info, const sptr<SpecificSessionCallback>& specificCallback,
41     const sptr<KeyboardSessionCallback>& keyboardCallback)
42     : SystemSession(info, specificCallback)
43 {
44     keyboardCallback_ = keyboardCallback;
45     scenePersistence_ = sptr<ScenePersistence>::MakeSptr(info.bundleName_, GetPersistentId());
46     if (info.persistentId_ != 0 && info.persistentId_ != GetPersistentId()) {
47         // persistentId changed due to id conflicts. Need to rename the old snapshot if exists
48         scenePersistence_->RenameSnapshotFromOldPersistentId(info.persistentId_);
49         TLOGI(WmsLogTag::WMS_KEYBOARD, "RenameSnapshotFromOldPersistentId %{public}d", info.persistentId_);
50     }
51     TLOGI(WmsLogTag::WMS_KEYBOARD, "Create KeyboardSession");
52 }
53 
~KeyboardSession()54 KeyboardSession::~KeyboardSession()
55 {
56     TLOGI(WmsLogTag::WMS_KEYBOARD, "Destroy KeyboardSession");
57 }
58 
BindKeyboardPanelSession(sptr<SceneSession> panelSession)59 void KeyboardSession::BindKeyboardPanelSession(sptr<SceneSession> panelSession)
60 {
61     if (panelSession == nullptr) {
62         TLOGE(WmsLogTag::WMS_KEYBOARD, "PanelSession is null");
63         return;
64     }
65     keyboardPanelSession_ = panelSession;
66     TLOGI(WmsLogTag::WMS_KEYBOARD, "Success, panelId: %{public}d", panelSession->GetPersistentId());
67 }
68 
GetKeyboardPanelSession() const69 sptr<SceneSession> KeyboardSession::GetKeyboardPanelSession() const
70 {
71     return keyboardPanelSession_;
72 }
73 
GetKeyboardGravity() const74 SessionGravity KeyboardSession::GetKeyboardGravity() const
75 {
76     SessionGravity gravity = static_cast<SessionGravity>(GetSessionProperty()->GetKeyboardLayoutParams().gravity_);
77     TLOGD(WmsLogTag::WMS_KEYBOARD, "Gravity: %{public}d", gravity);
78     return gravity;
79 }
80 
Show(sptr<WindowSessionProperty> property)81 WSError KeyboardSession::Show(sptr<WindowSessionProperty> property)
82 {
83     if (property == nullptr) {
84         TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is null");
85         return WSError::WS_ERROR_NULLPTR;
86     }
87     if (!CheckPermissionWithPropertyAnimation(property)) {
88         return WSError::WS_ERROR_NOT_SYSTEM_APP;
89     }
90     PostTask([weakThis = wptr(this), property]() {
91         auto session = weakThis.promote();
92         if (!session) {
93             TLOGE(WmsLogTag::WMS_KEYBOARD, "Session is null, show keyboard failed");
94             return WSError::WS_ERROR_DESTROYED_OBJECT;
95         }
96         if (session->systemConfig_.IsPcWindow()) {
97             if (auto surfaceNode = session->GetSurfaceNode()) {
98                 surfaceNode->SetUIFirstSwitch(RSUIFirstSwitch::FORCE_DISABLE);
99             }
100         }
101         if (session->GetKeyboardGravity() == SessionGravity::SESSION_GRAVITY_BOTTOM) {
102             session->NotifySystemKeyboardAvoidChange(SystemKeyboardAvoidChangeReason::KEYBOARD_SHOW);
103         }
104         session->GetSessionProperty()->SetKeyboardEffectOption(property->GetKeyboardEffectOption());
105         session->UseFocusIdIfCallingSessionIdInvalid();
106         TLOGNI(WmsLogTag::WMS_KEYBOARD,
107             "Show keyboard session, id: %{public}d, calling id: %{public}d, effectOption: %{public}s",
108             session->GetPersistentId(), session->GetCallingSessionId(),
109             property->GetKeyboardEffectOption().ToString().c_str());
110         return session->SceneSession::Foreground(property);
111     }, "Show");
112     return WSError::WS_OK;
113 }
114 
Hide()115 WSError KeyboardSession::Hide()
116 {
117     if (!CheckPermissionWithPropertyAnimation(GetSessionProperty())) {
118         return WSError::WS_ERROR_NOT_SYSTEM_APP;
119     }
120     PostTask([weakThis = wptr(this)]() {
121         auto session = weakThis.promote();
122         if (!session) {
123             TLOGE(WmsLogTag::WMS_KEYBOARD, "Session is null, hide keyboard failed");
124             return WSError::WS_ERROR_DESTROYED_OBJECT;
125         }
126 
127         TLOGNI(WmsLogTag::WMS_KEYBOARD, "Hide keyboard session, set callingSessionId to 0, id: %{public}d",
128             session->GetPersistentId());
129         auto ret = session->SetActive(false);
130         if (ret != WSError::WS_OK) {
131             TLOGE(WmsLogTag::WMS_KEYBOARD, "Set session active state failed, ret: %{public}d", ret);
132             return ret;
133         }
134         ret = session->SceneSession::Background();
135         WSRect rect = {0, 0, 0, 0};
136         session->NotifyKeyboardPanelInfoChange(rect, false);
137         if (session->systemConfig_.IsPcWindow() || session->GetSessionScreenName() == "HiCar" ||
138             session->GetSessionScreenName() == "SuperLauncher" ||
139             session->GetSessionScreenName() == "PadWithCar") {
140             TLOGD(WmsLogTag::WMS_KEYBOARD, "PC or virtual screen, restore calling session");
141             !session->IsSystemKeyboard() ? session->RestoreCallingSession(session->GetCallingSessionId(), nullptr) :
142                 session->NotifySystemKeyboardAvoidChange(SystemKeyboardAvoidChangeReason::KEYBOARD_HIDE);
143             auto sessionProperty = session->GetSessionProperty();
144             if (sessionProperty) {
145                 sessionProperty->SetCallingSessionId(INVALID_WINDOW_ID);
146             }
147         }
148         return ret;
149     }, "Hide");
150     return WSError::WS_OK;
151 }
152 
Disconnect(bool isFromClient,const std::string & identityToken)153 WSError KeyboardSession::Disconnect(bool isFromClient, const std::string& identityToken)
154 {
155     PostTask([weakThis = wptr(this), isFromClient]() {
156         auto session = weakThis.promote();
157         if (!session) {
158             TLOGE(WmsLogTag::WMS_KEYBOARD, "Session is null, disconnect keyboard session failed");
159             return WSError::WS_ERROR_DESTROYED_OBJECT;
160         }
161         TLOGI(WmsLogTag::WMS_KEYBOARD, "Disconnect keyboard session, id: %{public}d, isFromClient: %{public}d",
162             session->GetPersistentId(), isFromClient);
163         session->SceneSession::Disconnect(isFromClient);
164         WSRect rect = {0, 0, 0, 0};
165         session->NotifyKeyboardPanelInfoChange(rect, false);
166         !session->IsSystemKeyboard() ? session->RestoreCallingSession(session->GetCallingSessionId(), nullptr) :
167             session->NotifySystemKeyboardAvoidChange(SystemKeyboardAvoidChangeReason::KEYBOARD_DISCONNECT);
168         auto sessionProperty = session->GetSessionProperty();
169         if (sessionProperty) {
170             sessionProperty->SetCallingSessionId(INVALID_WINDOW_ID);
171         }
172         return WSError::WS_OK;
173     }, "Disconnect");
174     return WSError::WS_OK;
175 }
176 
NotifyClientToUpdateRect(const std::string & updateReason,std::shared_ptr<RSTransaction> rsTransaction)177 WSError KeyboardSession::NotifyClientToUpdateRect(const std::string& updateReason,
178     std::shared_ptr<RSTransaction> rsTransaction)
179 {
180     PostTask([weakThis = wptr(this), rsTransaction, updateReason]() {
181         auto session = weakThis.promote();
182         if (!session) {
183             TLOGE(WmsLogTag::WMS_KEYBOARD, "Session is null");
184             return WSError::WS_ERROR_DESTROYED_OBJECT;
185         }
186 
187         WSError ret = session->NotifyClientToUpdateRectTask(updateReason, rsTransaction);
188         return ret;
189     }, "NotifyClientToUpdateRect");
190     return WSError::WS_OK;
191 }
192 
SetCallingSessionId(uint32_t callingSessionId)193 void KeyboardSession::SetCallingSessionId(uint32_t callingSessionId)
194 {
195     PostTask([weakThis = wptr(this), callingSessionId]() mutable {
196         auto session = weakThis.promote();
197         if (!session) {
198             TLOGE(WmsLogTag::WMS_KEYBOARD, "Session is null");
199             return;
200         }
201         if (session->GetSceneSession(callingSessionId) == nullptr) {
202             uint32_t focusedSessionId = static_cast<uint32_t>(session->GetFocusedSessionId());
203             if (session->GetSceneSession(focusedSessionId) == nullptr) {
204                 TLOGE(WmsLogTag::WMS_KEYBOARD, "Focused session is null, set id: %{public}d failed", focusedSessionId);
205                 return;
206             } else {
207                 TLOGI(WmsLogTag::WMS_KEYBOARD, "Using focusedSession id: %{public}d", focusedSessionId);
208                 callingSessionId = focusedSessionId;
209             }
210         }
211         uint32_t curCallingId = session->GetCallingSessionId();
212         TLOGI(WmsLogTag::WMS_KEYBOARD, "CurId: %{public}d, newId: %{public}d", curCallingId, callingSessionId);
213         // When the keyboard is shown, if the callingId changes, restore the cur calling session.
214         if (curCallingId != INVALID_WINDOW_ID && callingSessionId != curCallingId && session->IsSessionForeground()) {
215             session->RestoreCallingSession(curCallingId, nullptr);
216             sptr<SceneSession> callingSession = session->GetSceneSession(curCallingId);
217             WSRect panelRect = session->GetPanelRect();
218             if (callingSession != nullptr && session->GetKeyboardGravity() == SessionGravity::SESSION_GRAVITY_BOTTOM) {
219                 session->RecalculatePanelRectForAvoidArea(panelRect);
220                 WSRect endRect = {panelRect.posX_, panelRect.posY_ + panelRect.height_, panelRect.width_,
221                     panelRect.height_};
222                 // panelRect as beginRect
223                 callingSession->NotifyKeyboardAnimationCompleted(false, panelRect, endRect);
224             }
225         }
226         session->GetSessionProperty()->SetCallingSessionId(callingSessionId);
227 
228         if (session->keyboardCallback_ == nullptr ||
229             session->keyboardCallback_->onCallingSessionIdChange == nullptr) {
230             TLOGE(WmsLogTag::WMS_KEYBOARD, "KeyboardCallback_, callingSessionId: %{public}d", callingSessionId);
231             return;
232         }
233         session->keyboardCallback_->onCallingSessionIdChange(callingSessionId);
234     }, "SetCallingSessionId");
235     return;
236 }
237 
GetCallingSessionId()238 uint32_t KeyboardSession::GetCallingSessionId()
239 {
240     auto sessionProperty = GetSessionProperty();
241     if (sessionProperty == nullptr) {
242         TLOGE(WmsLogTag::WMS_KEYBOARD, "Session property is null");
243         return INVALID_SESSION_ID;
244     }
245     return sessionProperty->GetCallingSessionId();
246 }
247 
AdjustKeyboardLayout(const KeyboardLayoutParams & params)248 WSError KeyboardSession::AdjustKeyboardLayout(const KeyboardLayoutParams& params)
249 {
250     PostTask([weakThis = wptr(this), params]() -> WSError {
251         auto session = weakThis.promote();
252         if (!session) {
253             TLOGE(WmsLogTag::WMS_KEYBOARD, "Keyboard session is null");
254             return WSError::WS_ERROR_DESTROYED_OBJECT;
255         }
256         // set keyboard layout params
257         auto sessionProperty = session->GetSessionProperty();
258         const KeyboardLayoutParams lastParams = sessionProperty->GetKeyboardLayoutParams();
259         sessionProperty->SetKeyboardLayoutParams(params);
260         // handle keyboard gravity change
261         if (params.gravity_ == WindowGravity::WINDOW_GRAVITY_FLOAT) {
262             session->NotifySystemKeyboardAvoidChange(SystemKeyboardAvoidChangeReason::KEYBOARD_GRAVITY_FLOAT);
263             session->SetWindowAnimationFlag(false);
264         } else {
265             if (session->IsSessionForeground()) {
266                 session->NotifySystemKeyboardAvoidChange(SystemKeyboardAvoidChangeReason::KEYBOARD_GRAVITY_BOTTOM);
267             }
268             session->SetWindowAnimationFlag(true);
269         }
270         // avoidHeight is set, notify avoidArea in case ui params don't flush
271         if (lastParams != params && session->IsSessionForeground() && params.landscapeAvoidHeight_ >= 0 &&
272             params.portraitAvoidHeight_ >= 0 && lastParams.landscapeAvoidHeight_ >= 0 &&
273             lastParams.portraitAvoidHeight_ >= 0) {
274             TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard avoidHeight is set, id: %{public}d",
275                 session->GetCallingSessionId());
276             session->ProcessKeyboardOccupiedAreaInfo(session->GetCallingSessionId(), true, false);
277         }
278         // notify keyboard layout param
279         if (session->adjustKeyboardLayoutFunc_) {
280             session->adjustKeyboardLayoutFunc_(params);
281         }
282         TLOGNI(WmsLogTag::WMS_KEYBOARD, "Adjust keyboard layout, keyboardId: %{public}d, gravity: %{public}u, "
283             "landscapeAvoidHeight: %{public}d, portraitAvoidHeight: %{public}d, "
284             "Landscape: %{public}s, Portrait: %{public}s, LandscapePanel: %{public}s, "
285             "PortraitPanel: %{public}s, request: %{public}s", session->GetPersistentId(),
286             static_cast<uint32_t>(params.gravity_), params.landscapeAvoidHeight_, params.portraitAvoidHeight_,
287             params.LandscapeKeyboardRect_.ToString().c_str(), params.PortraitKeyboardRect_.ToString().c_str(),
288             params.LandscapePanelRect_.ToString().c_str(), params.PortraitPanelRect_.ToString().c_str(),
289             session->GetSessionRequestRect().ToString().c_str());
290         return WSError::WS_OK;
291     }, "AdjustKeyboardLayout");
292     return WSError::WS_OK;
293 }
294 
GetSceneSession(uint32_t persistentId)295 sptr<SceneSession> KeyboardSession::GetSceneSession(uint32_t persistentId)
296 {
297     if (keyboardCallback_ == nullptr || keyboardCallback_->onGetSceneSession == nullptr) {
298         TLOGE(WmsLogTag::WMS_KEYBOARD, "Get scene session failed, persistentId: %{public}d", persistentId);
299         return nullptr;
300     }
301     return keyboardCallback_->onGetSceneSession(persistentId);
302 }
303 
GetFocusedSessionId()304 int32_t KeyboardSession::GetFocusedSessionId()
305 {
306     if (keyboardCallback_ == nullptr || keyboardCallback_->onGetFocusedSessionId == nullptr) {
307         TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboardCallback is null, get focusedSessionId failed");
308         return INVALID_WINDOW_ID;
309     }
310     return keyboardCallback_->onGetFocusedSessionId();
311 }
312 
CalculateSafeRectForMidScene(const WSRect & windowRect,const WSRect & keyboardRect,float scaleX,float scaleY)313 static WSRect CalculateSafeRectForMidScene(const WSRect& windowRect, const WSRect& keyboardRect, float scaleX,
314     float scaleY)
315 {
316     if (MathHelper::NearZero(scaleX) || MathHelper::NearZero(scaleY)) {
317         return { 0, 0, 0, 0 };
318     }
319     const WSRect scaledWindowRect = {
320         windowRect.posX_,
321         windowRect.posY_,
322         static_cast<int32_t>(windowRect.width_ * scaleX),
323         static_cast<int32_t>(windowRect.height_ * scaleY)
324     };
325 
326     const WSRect overlap = SessionHelper::GetOverlap(scaledWindowRect, keyboardRect, 0, 0);
327     if (SessionHelper::IsEmptyRect(overlap)) {
328         return { 0, 0, 0, 0 };
329     }
330 
331     const WSRect result = {
332         static_cast<int32_t>((overlap.posX_ - scaledWindowRect.posX_) / scaleX),
333         static_cast<int32_t>((overlap.posY_ - scaledWindowRect.posY_) / scaleY),
334         static_cast<int32_t>(overlap.width_ / scaleX),
335         static_cast<int32_t>(overlap.height_ / scaleY)
336     };
337     return result;
338 }
339 
NotifyOccupiedAreaChanged(const sptr<SceneSession> & callingSession,sptr<OccupiedAreaChangeInfo> & occupiedAreaInfo,bool needRecalculateAvoidAreas,std::shared_ptr<RSTransaction> rsTransaction)340 void KeyboardSession::NotifyOccupiedAreaChanged(const sptr<SceneSession>& callingSession,
341     sptr<OccupiedAreaChangeInfo>& occupiedAreaInfo,
342     bool needRecalculateAvoidAreas, std::shared_ptr<RSTransaction> rsTransaction)
343 {
344     if (occupiedAreaInfo == nullptr) {
345         TLOGE(WmsLogTag::WMS_KEYBOARD, "occupiedAreaInfo is null");
346         return;
347     }
348     if (callingSession->IsSystemSession()) {
349         NotifyRootSceneOccupiedAreaChange(occupiedAreaInfo);
350         TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling id: %{public}d, safeRect: %{public}s"
351             ", textFieldPositionY_: %{public}f, textFieldHeight_: %{public}f",
352             callingSession->GetPersistentId(), occupiedAreaInfo->rect_.ToString().c_str(),
353             occupiedAreaInfo->textFieldPositionY_, occupiedAreaInfo->textFieldHeight_);
354     } else {
355         std::map<AvoidAreaType, AvoidArea> avoidAreas = {};
356         if (needRecalculateAvoidAreas) {
357             callingSession->GetAllAvoidAreas(avoidAreas);
358         }
359         const WSRect& callingSessionRect = callingSession->GetSessionRect();
360         callingSession->NotifyOccupiedAreaChangeInfo(occupiedAreaInfo, rsTransaction,
361             SessionHelper::TransferToRect(callingSessionRect), avoidAreas);
362     }
363 }
364 
CalculateOccupiedArea(const sptr<SceneSession> & callingSession,const WSRect & callingSessionRect,const WSRect & panelRect,sptr<OccupiedAreaChangeInfo> & occupiedAreaInfo)365 bool KeyboardSession::CalculateOccupiedArea(const sptr<SceneSession>& callingSession, const WSRect& callingSessionRect,
366     const WSRect& panelRect, sptr<OccupiedAreaChangeInfo>& occupiedAreaInfo)
367 {
368     if (callingSession == nullptr) {
369         TLOGE(WmsLogTag::WMS_KEYBOARD, "callingSession is null");
370         return false;
371     }
372     // if keyboard will occupy calling, notify calling window the occupied area and safe height
373     const WSRect& safeRect = !callingSession->GetIsMidScene() ?
374         SessionHelper::GetOverlap(panelRect, CalculateScaledRect(callingSessionRect, callingSession->GetScaleX(),
375             callingSession->GetScaleY()), 0, 0) :
376         CalculateSafeRectForMidScene(callingSessionRect, panelRect,
377             callingSession->GetScaleX(), callingSession->GetScaleY());
378     const WSRect& lastSafeRect = callingSession->GetLastSafeRect();
379     if (lastSafeRect == safeRect) {
380         TLOGI(WmsLogTag::WMS_KEYBOARD, "Same safeRect: %{public}s", safeRect.ToString().c_str());
381         return false;
382     }
383     callingSession->SetLastSafeRect(safeRect);
384     double textFieldPositionY = 0.0;
385     double textFieldHeight = 0.0;
386     auto sessionProperty = GetSessionProperty();
387     if (sessionProperty != nullptr) {
388         textFieldPositionY = sessionProperty->GetTextFieldPositionY();
389         textFieldHeight = sessionProperty->GetTextFieldHeight();
390     }
391     occupiedAreaInfo = sptr<OccupiedAreaChangeInfo>::MakeSptr(OccupiedAreaType::TYPE_INPUT,
392         SessionHelper::TransferToRect(safeRect), safeRect.height_, textFieldPositionY, textFieldHeight);
393     return true;
394 }
395 
ProcessKeyboardOccupiedAreaInfo(uint32_t callingId,bool needRecalculateAvoidAreas,bool needCheckRSTransaction)396 void KeyboardSession::ProcessKeyboardOccupiedAreaInfo(uint32_t callingId, bool needRecalculateAvoidAreas,
397     bool needCheckRSTransaction)
398 {
399     sptr<SceneSession> callingSession = GetSceneSession(callingId);
400     if (callingSession == nullptr) {
401         TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is null");
402         if (needCheckRSTransaction) {
403             CloseRSTransaction();
404         }
405         return;
406     }
407     sptr<OccupiedAreaChangeInfo> occupiedAreaInfo = nullptr;
408     std::shared_ptr<RSTransaction> rsTransaction = needCheckRSTransaction ? GetRSTransaction() : nullptr;
409     bool occupiedAreaChanged = RaiseCallingSession(callingSession, occupiedAreaInfo);
410     if (occupiedAreaChanged) {
411         NotifyOccupiedAreaChanged(callingSession, occupiedAreaInfo, needRecalculateAvoidAreas, rsTransaction);
412     }
413     TLOGD(WmsLogTag::WMS_KEYBOARD, "id: %{public}d, needRecalculateAvoidAreas: %{public}d"
414         ", occupiedAreaChanged: %{public}d", callingId, needRecalculateAvoidAreas, occupiedAreaChanged);
415     if (needCheckRSTransaction) {
416         CloseRSTransaction();
417     }
418 }
419 
NotifyKeyboardPanelInfoChange(WSRect rect,bool isKeyboardPanelShow)420 void KeyboardSession::NotifyKeyboardPanelInfoChange(WSRect rect, bool isKeyboardPanelShow)
421 {
422     if (!sessionStage_) {
423         TLOGE(WmsLogTag::WMS_KEYBOARD, "SessionStage is null, notify keyboard panel rect change failed");
424         return;
425     }
426     KeyboardPanelInfo keyboardPanelInfo;
427     keyboardPanelInfo.rect_ = SessionHelper::TransferToRect(rect);
428     keyboardPanelInfo.gravity_ = static_cast<WindowGravity>(GetKeyboardGravity());
429     keyboardPanelInfo.isShowing_ = isKeyboardPanelShow;
430 
431     sessionStage_->NotifyKeyboardPanelInfoChange(keyboardPanelInfo);
432 }
433 
CheckIfNeedRaiseCallingSession(sptr<SceneSession> callingSession,bool isCallingSessionFloating)434 bool KeyboardSession::CheckIfNeedRaiseCallingSession(sptr<SceneSession> callingSession, bool isCallingSessionFloating)
435 {
436     if (callingSession == nullptr) {
437         TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is null");
438         return false;
439     }
440 
441     SessionGravity gravity = GetKeyboardGravity();
442     if (gravity == SessionGravity::SESSION_GRAVITY_FLOAT) {
443         TLOGI(WmsLogTag::WMS_KEYBOARD, "No need to raise calling session, gravity: %{public}d", gravity);
444         return false;
445     }
446 
447     /**
448      * When an app calls move or resize, if the layout pipeline hasn't yet refreshed the window size, the calling
449      * window dimensions obtained for keyboard avoidance will be incorrect. To prevent the app's intended dimensions
450      * from being overridden, avoidance is deliberately skipped.
451      */
452     if (callingSession->isSubWindowResizingOrMoving_ && WindowHelper::IsSubWindow(callingSession->GetWindowType())) {
453         TLOGI(WmsLogTag::WMS_KEYBOARD, "subWindow is resizing or moving");
454         return false;
455     }
456 
457     bool isMainOrParentFloating = WindowHelper::IsMainWindow(callingSession->GetWindowType()) ||
458         (SessionHelper::IsNonSecureToUIExtension(callingSession->GetWindowType()) &&
459          callingSession->GetParentSession() != nullptr &&
460          callingSession->GetParentSession()->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING);
461     bool isFreeMultiWindowMode = callingSession->IsFreeMultiWindowMode();
462     bool isMidScene = callingSession->GetIsMidScene();
463     bool isPhoneNotFreeMultiWindow = systemConfig_.IsPhoneWindow() && !isFreeMultiWindowMode;
464     bool isPadNotFreeMultiWindow = systemConfig_.IsPadWindow() && !isFreeMultiWindowMode;
465     if (isCallingSessionFloating && isMainOrParentFloating && !isMidScene &&
466         (isPhoneNotFreeMultiWindow || isPadNotFreeMultiWindow)) {
467         TLOGI(WmsLogTag::WMS_KEYBOARD, "No need to raise calling session in float window, "
468             "isPhoneNotFreeMultiWindow: %{public}d, isPadNotFreeMultiWindow: %{public}d",
469             isPhoneNotFreeMultiWindow, isPadNotFreeMultiWindow);
470         return false;
471     }
472 
473     return true;
474 }
475 
RaiseCallingSession(const sptr<SceneSession> & callingSession,sptr<OccupiedAreaChangeInfo> & occupiedAreaInfo)476 bool KeyboardSession::RaiseCallingSession(const sptr<SceneSession>& callingSession,
477     sptr<OccupiedAreaChangeInfo>& occupiedAreaInfo)
478 {
479     bool occupiedAreaChanged = false;
480     WSRect panelAvoidRect = GetPanelRect();
481     if (!keyboardAvoidAreaActive_) {
482         TLOGI(WmsLogTag::WMS_KEYBOARD, "Id: %{public}d, isSystemKeyboard: %{public}d, state: %{public}d, "
483             "gravity: %{public}d", callingSession->GetPersistentId(), IsSystemKeyboard(), GetSessionState(),
484             GetKeyboardGravity());
485         return false;
486     }
487     if (!IsSessionForeground()) {
488         TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard is not foreground, sessionState: %{public}d", GetSessionState());
489         return false;
490     }
491     NotifyKeyboardPanelInfoChange(panelAvoidRect, true);
492 
493     bool isCallingSessionFloating = (callingSession->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING) &&
494         !callingSession->GetIsMidScene();
495     if (!CheckIfNeedRaiseCallingSession(callingSession, isCallingSessionFloating)) {
496         return false;
497     }
498 
499     WSRect callingSessionRect = callingSession->GetSessionRect();
500     float callingSessionScaleY = callingSession->GetScaleY();
501     int32_t oriPosYBeforeRaisedByKeyboard = callingSession->GetOriPosYBeforeRaisedByKeyboard();
502     if (oriPosYBeforeRaisedByKeyboard != 0 && isCallingSessionFloating) {
503         callingSessionRect.posY_ = oriPosYBeforeRaisedByKeyboard;
504     }
505     // update panel rect for avoid area caculate
506     RecalculatePanelRectForAvoidArea(panelAvoidRect);
507     if (SessionHelper::IsEmptyRect(SessionHelper::GetOverlap(panelAvoidRect, CalculateScaledRect(
508         callingSessionRect, callingSession->GetScaleX(), callingSessionScaleY), 0, 0)) &&
509         oriPosYBeforeRaisedByKeyboard == 0) {
510         TLOGI(WmsLogTag::WMS_KEYBOARD, "No overlap area, keyboardRect: %{public}s, callingRect: %{public}s",
511             panelAvoidRect.ToString().c_str(), callingSessionRect.ToString().c_str());
512         return CalculateOccupiedArea(callingSession, callingSessionRect, panelAvoidRect, occupiedAreaInfo);
513     }
514 
515     WSRect newRect = callingSessionRect;
516     int32_t statusHeight = callingSession->GetStatusBarHeight();
517     int32_t scaledPosY = MathHelper::GreatNotEqual(callingSessionScaleY, 1) ?
518         newRect.posY_ - static_cast<int32_t>(std::round((callingSessionScaleY - 1) * newRect.height_ / 2)) :
519         newRect.posY_;
520     if (IsNeedRaiseSubWindow(callingSession, newRect) && isCallingSessionFloating && scaledPosY > statusHeight) {
521         if (oriPosYBeforeRaisedByKeyboard == 0) {
522             oriPosYBeforeRaisedByKeyboard = callingSessionRect.posY_;
523             callingSession->SetOriPosYBeforeRaisedByKeyboard(callingSessionRect.posY_);
524         }
525         // calculate new rect of calling session
526         newRect.posY_ = std::max(panelAvoidRect.posY_ - newRect.height_, statusHeight);
527         newRect.posY_ = std::min(oriPosYBeforeRaisedByKeyboard, newRect.posY_);
528         if (MathHelper::GreatNotEqual(callingSessionScaleY, 1)) {
529             scaledPosY = newRect.posY_ - static_cast<int32_t>(std::round(
530                 (callingSessionScaleY - 1) * newRect.height_ / 2));
531             if (scaledPosY < statusHeight) {
532                 newRect.posY_ = newRect.posY_ + (statusHeight - scaledPosY);
533             }
534         }
535         occupiedAreaChanged = CalculateOccupiedArea(callingSession, newRect, panelAvoidRect, occupiedAreaInfo);
536         if (!IsSystemKeyboard()) {
537             callingSession->UpdateSessionRect(newRect, SizeChangeReason::UNDEFINED);
538         }
539     } else {
540         occupiedAreaChanged = CalculateOccupiedArea(callingSession, newRect, panelAvoidRect, occupiedAreaInfo);
541     }
542 
543     TLOGI(WmsLogTag::WMS_KEYBOARD, "KeyboardRect: %{public}s, callSession OriRect: %{public}s, newRect: %{public}s"
544         ", isFloating: %{public}d, oriPosY: %{public}d",
545         panelAvoidRect.ToString().c_str(), callingSessionRect.ToString().c_str(), newRect.ToString().c_str(),
546         isCallingSessionFloating, oriPosYBeforeRaisedByKeyboard);
547     return occupiedAreaChanged;
548 }
549 
CalculateScaledRect(WSRect sessionRect,float scaleX,float scaleY)550 WSRect KeyboardSession::CalculateScaledRect(WSRect sessionRect, float scaleX, float scaleY)
551 {
552     if (!(MathHelper::GreatNotEqual(scaleY, 1) || MathHelper::GreatNotEqual(scaleX, 1))) {
553         return sessionRect;
554     }
555     int32_t centerX = static_cast<int32_t>(sessionRect.posX_ + std::round(static_cast<float>(sessionRect.width_) / 2));
556     int32_t centerY = static_cast<int32_t>(sessionRect.posY_ + std::round(static_cast<float>(sessionRect.height_) / 2));
557     sessionRect.width_ = static_cast<int32_t>(std::round(sessionRect.width_ * scaleX));
558     sessionRect.height_ = static_cast<int32_t>(std::round(sessionRect.height_ * scaleY));
559     sessionRect.posX_ = centerX - static_cast<int32_t>(std::round(static_cast<float>(sessionRect.width_) / 2));
560     sessionRect.posY_ = centerY - static_cast<int32_t>(std::round(static_cast<float>(sessionRect.height_) / 2));
561 
562     TLOGI(WmsLogTag::WMS_KEYBOARD, "scaledRect: %{public}s, scaleX: %{public}f, scaleY: %{public}f, centerX: %{public}d"
563         ", centerY: %{public}d", sessionRect.ToString().c_str(), scaleX, scaleY, centerX, centerY);
564     return sessionRect;
565 }
566 
RestoreCallingSession(uint32_t callingId,const std::shared_ptr<RSTransaction> & rsTransaction)567 void KeyboardSession::RestoreCallingSession(uint32_t callingId, const std::shared_ptr<RSTransaction>& rsTransaction)
568 {
569     if (!keyboardAvoidAreaActive_) {
570         TLOGI(WmsLogTag::WMS_KEYBOARD, "Id: %{public}d, isSystemKeyboard: %{public}d, state: %{public}d, "
571             "gravity: %{public}d", GetPersistentId(), IsSystemKeyboard(), GetSessionState(), GetKeyboardGravity());
572         return;
573     }
574     sptr<SceneSession> callingSession = GetSceneSession(callingId);
575     if (callingSession == nullptr) {
576         TLOGI(WmsLogTag::WMS_KEYBOARD, "Calling session is null");
577         return;
578     }
579     const WSRect& emptyRect = { 0, 0, 0, 0 };
580     int32_t oriPosYBeforeRaisedByKeyboard = callingSession->GetOriPosYBeforeRaisedByKeyboard();
581     sptr<OccupiedAreaChangeInfo> occupiedAreaInfo = nullptr;
582     bool occupiedAreaChanged = CalculateOccupiedArea(callingSession, emptyRect, emptyRect, occupiedAreaInfo);
583     if (occupiedAreaChanged) {
584         NotifyOccupiedAreaChanged(callingSession, occupiedAreaInfo, true, rsTransaction);
585     }
586     if (oriPosYBeforeRaisedByKeyboard != 0 &&
587         callingSession->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING) {
588         WSRect callingSessionRestoringRect = callingSession->GetSessionRect();
589         if (oriPosYBeforeRaisedByKeyboard != 0) {
590             callingSessionRestoringRect.posY_ = oriPosYBeforeRaisedByKeyboard;
591         }
592         TLOGI(WmsLogTag::WMS_KEYBOARD, "OriPosYBeforeRaisedByKeyboard: %{public}d, sessionMode: %{public}d",
593             oriPosYBeforeRaisedByKeyboard, callingSession->GetWindowMode());
594         if (!IsSystemKeyboard()) {
595             callingSession->UpdateSessionRect(callingSessionRestoringRect, SizeChangeReason::UNDEFINED);
596         }
597     }
598     callingSession->SetOriPosYBeforeRaisedByKeyboard(0); // 0: default value
599 }
600 
NotifySessionRectChange(const WSRect & rect,SizeChangeReason reason,DisplayId displayId,const RectAnimationConfig & rectAnimationConfig)601 void KeyboardSession::NotifySessionRectChange(const WSRect& rect,
602     SizeChangeReason reason, DisplayId displayId, const RectAnimationConfig& rectAnimationConfig)
603 {
604     PostTask([weakThis = wptr(this), rect, reason, displayId, rectAnimationConfig, where = __func__] {
605         auto session = weakThis.promote();
606         if (session == nullptr) {
607             TLOGNE(WmsLogTag::WMS_KEYBOARD, "%{public}s session is null", where);
608             return;
609         }
610         uint32_t screenWidth = 0;
611         uint32_t screenHeight = 0;
612         auto sessionProperty = session->GetSessionProperty();
613         bool ret = session->GetScreenWidthAndHeightFromClient(sessionProperty, screenWidth, screenHeight);
614         if (!ret) {
615             TLOGNE(WmsLogTag::WMS_KEYBOARD, "%{public}s get screen size failed", where);
616             return;
617         }
618         bool isLand = screenWidth > screenHeight;
619         KeyboardLayoutParams params = sessionProperty->GetKeyboardLayoutParams();
620         if (displayId != DISPLAY_ID_INVALID) {
621             params.displayId_ = displayId;
622         }
623         if (isLand) {
624             params.LandscapeKeyboardRect_.posX_ = rect.posX_;
625             params.LandscapeKeyboardRect_.posY_ = rect.posY_;
626             params.LandscapePanelRect_.posX_ = rect.posX_;
627             params.LandscapePanelRect_.posY_ = rect.posY_;
628         } else {
629             params.PortraitKeyboardRect_.posX_ = rect.posX_;
630             params.PortraitKeyboardRect_.posY_ = rect.posY_;
631             params.PortraitPanelRect_.posX_ = rect.posX_;
632             params.PortraitPanelRect_.posY_ = rect.posY_;
633         }
634         sessionProperty->SetKeyboardLayoutParams(params);
635         if (session->adjustKeyboardLayoutFunc_) {
636             session->adjustKeyboardLayoutFunc_(params);
637         }
638         TLOGI(WmsLogTag::WMS_KEYBOARD,
639             "isLand:%{public}d, landRect:%{public}s, portraitRect:%{public}s, displayId:%{public}" PRIu64,
640             isLand, params.LandscapeKeyboardRect_.ToString().c_str(),
641             params.PortraitKeyboardRect_.ToString().c_str(), displayId);
642     }, __func__ + GetRectInfo(rect));
643 }
644 
645 // Use focused session id when calling session id is invalid.
UseFocusIdIfCallingSessionIdInvalid()646 void KeyboardSession::UseFocusIdIfCallingSessionIdInvalid()
647 {
648     if (GetSceneSession(GetCallingSessionId()) != nullptr) {
649         return;
650     }
651     uint32_t focusedSessionId = static_cast<uint32_t>(GetFocusedSessionId());
652     if (GetSceneSession(focusedSessionId) == nullptr) {
653         TLOGE(WmsLogTag::WMS_KEYBOARD, "Focused session is null, id: %{public}d", focusedSessionId);
654     } else {
655         TLOGI(WmsLogTag::WMS_KEYBOARD, "Using focusedSession id: %{public}d", focusedSessionId);
656         GetSessionProperty()->SetCallingSessionId(focusedSessionId);
657         if (keyboardCallback_ != nullptr && keyboardCallback_->onCallingSessionIdChange != nullptr) {
658             keyboardCallback_->onCallingSessionIdChange(focusedSessionId);
659         }
660     }
661 }
662 
EnableCallingSessionAvoidArea()663 void KeyboardSession::EnableCallingSessionAvoidArea()
664 {
665     ProcessKeyboardOccupiedAreaInfo(GetCallingSessionId(), true, false);
666 }
667 
NotifySystemKeyboardAvoidChange(SystemKeyboardAvoidChangeReason reason)668 void KeyboardSession::NotifySystemKeyboardAvoidChange(SystemKeyboardAvoidChangeReason reason)
669 {
670     if (!systemConfig_.IsPcWindow()) {
671         TLOGI(WmsLogTag::WMS_KEYBOARD, "This device is not pc");
672         return;
673     }
674     if (!IsSystemKeyboard()) {
675         TLOGI(WmsLogTag::WMS_KEYBOARD, "This is not system keyboard, id: %{public}d", GetPersistentId());
676         return;
677     }
678     if (keyboardCallback_ == nullptr || keyboardCallback_->onSystemKeyboardAvoidChange == nullptr) {
679         TLOGI(WmsLogTag::WMS_KEYBOARD, "SystemKeyboardAvoidChange callback is null, id: %{public}d",
680             GetPersistentId());
681         return;
682     }
683     keyboardCallback_->onSystemKeyboardAvoidChange(GetScreenId(), reason);
684 }
685 
OpenKeyboardSyncTransaction()686 void KeyboardSession::OpenKeyboardSyncTransaction()
687 {
688     auto task = [weakThis = wptr(this)]() {
689         auto session = weakThis.promote();
690         if (!session) {
691             TLOGNE(WmsLogTag::WMS_KEYBOARD, "Keyboard session is null");
692             return WSError::WS_ERROR_DESTROYED_OBJECT;
693         }
694         if (session->isKeyboardSyncTransactionOpen_) {
695             TLOGNI(WmsLogTag::WMS_KEYBOARD, "Keyboard sync transaction is already open");
696             return WSError::WS_OK;
697         }
698         TLOGNI(WmsLogTag::WMS_KEYBOARD, "Open keyboard sync");
699         session->isKeyboardSyncTransactionOpen_ = true;
700         RSSyncTransactionAdapter::OpenSyncTransaction(session->GetRSUIContext(), session->GetEventHandler());
701         session->PostKeyboardAnimationSyncTimeoutTask();
702         return WSError::WS_OK;
703     };
704     PostSyncTask(task);
705 }
706 
CloseKeyboardSyncTransaction(const WSRect & keyboardPanelRect,bool isKeyboardShow,const WindowAnimationInfo & animationInfo)707 void KeyboardSession::CloseKeyboardSyncTransaction(const WSRect& keyboardPanelRect,
708     bool isKeyboardShow, const WindowAnimationInfo& animationInfo)
709 {
710     PostTask([weakThis = wptr(this), keyboardPanelRect, isKeyboardShow, animationInfo]() {
711         auto session = weakThis.promote();
712         if (!session) {
713             TLOGE(WmsLogTag::WMS_KEYBOARD, "Keyboard session is null");
714             return WSError::WS_ERROR_DESTROYED_OBJECT;
715         }
716         auto callingId = animationInfo.callingId;
717         TLOGNI(WmsLogTag::WMS_KEYBOARD, "Close keyboard sync, callingId: %{public}d, isShow: %{public}d,"
718             " isGravityChanged: %{public}d", callingId, isKeyboardShow, animationInfo.isGravityChanged);
719         std::shared_ptr<RSTransaction> rsTransaction = nullptr;
720         if (session->isKeyboardSyncTransactionOpen_) {
721             rsTransaction = session->GetRSTransaction();
722         }
723         // The callingId may change in WindowManager.
724         // Use scb's callingId to properly handle callingWindow raise/restore.
725         sptr<SceneSession> callingSession = session->GetSceneSession(callingId);
726         if (callingSession != nullptr) {
727             callingSession->NotifyKeyboardAnimationWillBegin(isKeyboardShow, animationInfo.beginRect,
728                 animationInfo.endRect, animationInfo.animated, rsTransaction);
729         }
730         bool isLayoutFinished = true;
731         if (isKeyboardShow) {
732             // When the keyboard shows/hides rapidly in succession,
733             // the attributes aren't refreshed but occupied area info recalculation needs to be triggered.
734             if (!animationInfo.isGravityChanged) {
735                 session->stateChanged_ = true;
736             }
737             // If the vsync period terminates, immediately notify all registered listeners.
738             if (session->keyboardCallback_ != nullptr &&
739                 session->keyboardCallback_->isLastFrameLayoutFinished != nullptr) {
740                 isLayoutFinished = session->keyboardCallback_->isLastFrameLayoutFinished();
741             }
742             if (isLayoutFinished) {
743                 TLOGI(WmsLogTag::WMS_KEYBOARD, "vsync period completed, id: %{public}d", callingId);
744                 session->ProcessKeyboardOccupiedAreaInfo(callingId, true, true);
745                 session->stateChanged_ = false;
746             }
747             if (session->IsSessionForeground() && session->GetCallingSessionId() == INVALID_WINDOW_ID &&
748                 !animationInfo.isGravityChanged) {
749                 session->GetSessionProperty()->SetCallingSessionId(callingId);
750             }
751         } else {
752             session->RestoreCallingSession(callingId, rsTransaction);
753             if (!animationInfo.isGravityChanged) {
754                 session->GetSessionProperty()->SetCallingSessionId(INVALID_WINDOW_ID);
755             }
756         }
757         if (isLayoutFinished) {
758             session->CloseRSTransaction();
759         }
760         return WSError::WS_OK;
761     }, "CloseKeyboardSyncTransaction");
762 }
763 
CloseRSTransaction()764 void KeyboardSession::CloseRSTransaction()
765 {
766     if (!isKeyboardSyncTransactionOpen_) {
767         TLOGI(WmsLogTag::WMS_KEYBOARD, "Keyboard sync transaction is closed");
768         return;
769     }
770     isKeyboardSyncTransactionOpen_ = false;
771     auto handler = GetEventHandler();
772     if (handler) {
773         TLOGI(WmsLogTag::WMS_KEYBOARD, "cancelled");
774         handler->RemoveTask(KEYBOARD_ANIM_SYNC_EVENT_NAME);
775     }
776     RSSyncTransactionAdapter::CloseSyncTransaction(GetRSUIContext(), handler);
777 }
778 
GetRSTransaction()779 std::shared_ptr<RSTransaction> KeyboardSession::GetRSTransaction()
780 {
781     std::shared_ptr<RSTransaction> rsTransaction = nullptr;
782     if (isKeyboardSyncTransactionOpen_) {
783         rsTransaction = RSSyncTransactionAdapter::GetRSTransaction(GetRSUIContext());
784     }
785     return rsTransaction;
786 }
787 
GetSessionScreenName()788 std::string KeyboardSession::GetSessionScreenName()
789 {
790     auto sessionProperty = GetSessionProperty();
791     if (sessionProperty != nullptr) {
792         auto displayId = sessionProperty->GetDisplayId();
793         auto screenSession = ScreenSessionManagerClient::GetInstance().GetScreenSession(displayId);
794         if (screenSession != nullptr) {
795             return screenSession->GetName();
796         }
797     }
798     return "";
799 }
800 
IsVisibleForeground() const801 bool KeyboardSession::IsVisibleForeground() const
802 {
803     return isVisible_;
804 }
805 
IsVisibleNotBackground() const806 bool KeyboardSession::IsVisibleNotBackground() const
807 {
808     return isVisible_;
809 }
810 
RecalculatePanelRectForAvoidArea(WSRect & panelRect)811 void KeyboardSession::RecalculatePanelRectForAvoidArea(WSRect& panelRect)
812 {
813     auto sessionProperty = GetSessionProperty();
814     KeyboardLayoutParams params = sessionProperty->GetKeyboardLayoutParams();
815     if (params.landscapeAvoidHeight_ < 0 || params.portraitAvoidHeight_ < 0) {
816         return;
817     }
818     // need to get screen property if the landscape width is same to the portrait
819     if (params.LandscapePanelRect_.width_ != params.PortraitPanelRect_.width_) {
820         if (static_cast<uint32_t>(panelRect.width_) == params.LandscapePanelRect_.width_) {
821             panelRect.posY_ += panelRect.height_ - params.landscapeAvoidHeight_;
822             panelRect.height_ = params.landscapeAvoidHeight_;
823             TLOGI(WmsLogTag::WMS_KEYBOARD, "LandscapeAvoidHeight %{public}d", panelRect.height_);
824             return;
825         }
826         if (static_cast<uint32_t>(panelRect.width_) == params.PortraitPanelRect_.width_) {
827             panelRect.posY_ += panelRect.height_ - params.portraitAvoidHeight_;
828             panelRect.height_ = params.portraitAvoidHeight_;
829             TLOGI(WmsLogTag::WMS_KEYBOARD, "PortraitAvoidHeight %{public}d", panelRect.height_);
830             return;
831         }
832     }
833     uint32_t screenWidth = 0;
834     uint32_t screenHeight = 0;
835     bool result = GetScreenWidthAndHeightFromClient(sessionProperty, screenWidth, screenHeight);
836     if (!result) {
837         TLOGE(WmsLogTag::WMS_KEYBOARD, "Get screen width and height failed");
838         return;
839     }
840     bool isLandscape = screenHeight < screenWidth;
841     int32_t height_ = isLandscape ? params.landscapeAvoidHeight_ : params.portraitAvoidHeight_;
842     panelRect.posY_ += panelRect.height_ - height_;
843     panelRect.height_ = height_;
844     TLOGI(WmsLogTag::WMS_KEYBOARD, "IsLandscape %{public}d, avoidHeight %{public}d", isLandscape, panelRect.height_);
845 }
846 
ChangeKeyboardEffectOption(const KeyboardEffectOption & effectOption)847 WSError KeyboardSession::ChangeKeyboardEffectOption(const KeyboardEffectOption& effectOption)
848 {
849     PostTask([weakThis = wptr(this), effectOption]() {
850         auto session = weakThis.promote();
851         if (!session) {
852             TLOGNE(WmsLogTag::WMS_KEYBOARD, "Session is null, change keyboard effect option failed");
853             return WSError::WS_ERROR_DESTROYED_OBJECT;
854         }
855         session->GetSessionProperty()->SetKeyboardEffectOption(effectOption);
856         if (session->changeKeyboardEffectOptionFunc_) {
857             session->changeKeyboardEffectOptionFunc_(effectOption);
858             return WSError::WS_OK;
859         }
860         TLOGNE(WmsLogTag::WMS_KEYBOARD, "Can not found changeKeyboardEffectOptionFunc_");
861         return WSError::WS_OK;
862     }, __func__);
863     return WSError::WS_OK;
864 }
865 
NotifyRootSceneOccupiedAreaChange(const sptr<OccupiedAreaChangeInfo> & info)866 void KeyboardSession::NotifyRootSceneOccupiedAreaChange(const sptr<OccupiedAreaChangeInfo>& info)
867 {
868     ScreenId defaultScreenId = ScreenSessionManagerClient::GetInstance().GetDefaultScreenId();
869     auto displayId = GetSessionProperty()->GetDisplayId();
870     if (displayId != defaultScreenId) {
871         TLOGI(WmsLogTag::WMS_KEYBOARD, "DisplayId: %{public}" PRIu64", defaultScreenId: %{public}" PRIu64"",
872             displayId, defaultScreenId);
873         return;
874     }
875     if (keyboardCallback_ == nullptr || keyboardCallback_->onNotifyOccupiedAreaChange == nullptr) {
876         TLOGE(WmsLogTag::WMS_KEYBOARD, "Callback is null");
877         return;
878     }
879     keyboardCallback_->onNotifyOccupiedAreaChange(info);
880 }
881 
IsNeedRaiseSubWindow(const sptr<SceneSession> & callingSession,const WSRect & callingSessionRect)882 bool KeyboardSession::IsNeedRaiseSubWindow(const sptr<SceneSession>& callingSession, const WSRect& callingSessionRect)
883 {
884     if (!SessionHelper::IsSubWindow(callingSession->GetWindowType())) {
885         TLOGD(WmsLogTag::WMS_KEYBOARD, "Not sub window");
886         return true;
887     }
888 
889     auto mainSession = callingSession->GetMainSession();
890     if (mainSession != nullptr && WindowHelper::IsSplitWindowMode(mainSession->GetWindowMode()) &&
891         callingSessionRect == mainSession->GetSessionRect()) {
892         TLOGI(WmsLogTag::WMS_KEYBOARD, "No need to raise, parentId: %{public}d, rect: %{public}s",
893             mainSession->GetPersistentId(), callingSessionRect.ToString().c_str());
894         return false;
895     }
896 
897     return true;
898 }
899 
HandleCrossScreenChild(bool isMoveOrDrag)900 void KeyboardSession::HandleCrossScreenChild(bool isMoveOrDrag)
901 {
902     RETURN_IF_PARAM_IS_NULL(moveDragController_);
903     auto displayIds = isMoveOrDrag ?
904         moveDragController_->GetNewAddedDisplayIdsDuringMoveDrag() :
905         moveDragController_->GetDisplayIdsDuringMoveDrag();
906     for (const auto displayId : displayIds) {
907         if (displayId == moveDragController_->GetMoveDragStartDisplayId()) {
908             continue;
909         }
910         auto screenSession = ScreenSessionManagerClient::GetInstance().GetScreenSessionById(displayId);
911         if (screenSession == nullptr) {
912             TLOGE(WmsLogTag::WMS_KEYBOARD, "ScreenSession is null");
913             continue;
914         }
915         if (screenSession->GetScreenProperty().GetScreenType() == ScreenType::VIRTUAL) {
916             TLOGI(WmsLogTag::WMS_KEYBOARD, "virtual screen, no need to add cross parent child");
917             continue;
918         }
919         RETURN_IF_PARAM_IS_NULL(keyboardPanelSession_);
920         auto keyboardPanelSurfaceNode = keyboardPanelSession_->GetSurfaceNode();
921         RETURN_IF_PARAM_IS_NULL(keyboardPanelSurfaceNode);
922         auto displayNode = screenSession->GetDisplayNode();
923         RETURN_IF_PARAM_IS_NULL(displayNode);
924         if (isMoveOrDrag) {
925             {
926                 AutoRSTransaction trans(keyboardPanelSurfaceNode->GetRSUIContext());
927                 keyboardPanelSurfaceNode->SetPositionZ(MOVE_DRAG_POSITION_Z);
928                 keyboardPanelSurfaceNode->SetIsCrossNode(true);
929             }
930             {
931                 AutoRSTransaction trans(displayNode->GetRSUIContext());
932                 displayNode->AddCrossScreenChild(keyboardPanelSurfaceNode, INSERT_TO_THE_END, true);
933             }
934             TLOGI(WmsLogTag::WMS_KEYBOARD, "Add window: %{public}d to display: %{public}" PRIu64,
935                 keyboardPanelSession_->GetPersistentId(), displayId);
936         } else {
937             keyboardPanelSurfaceNode->SetPositionZ(moveDragController_->GetOriginalPositionZ());
938             displayNode->RemoveCrossScreenChild(keyboardPanelSurfaceNode);
939             keyboardPanelSurfaceNode->SetIsCrossNode(false);
940             TLOGI(WmsLogTag::WMS_KEYBOARD, "Remove window: %{public}d from display: %{public}" PRIu64,
941                 keyboardPanelSession_->GetPersistentId(), displayId);
942         }
943     }
944 }
945 
HandleMoveDragSurfaceNode(SizeChangeReason reason)946 void KeyboardSession::HandleMoveDragSurfaceNode(SizeChangeReason reason)
947 {
948     if (reason == SizeChangeReason::DRAG || reason == SizeChangeReason::DRAG_MOVE) {
949         HandleCrossScreenChild(true);
950     } else if (reason == SizeChangeReason::DRAG_END) {
951         HandleCrossScreenChild(false);
952     }
953 }
954 
SetSurfaceBounds(const WSRect & rect,bool isGlobal,bool needFlush)955 void KeyboardSession::SetSurfaceBounds(const WSRect& rect, bool isGlobal, bool needFlush)
956 {
957     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER,
958         "KeyboardSession::SetSurfaceBounds id:%d [%d, %d, %d, %d] reason:%u",
959         GetPersistentId(), rect.posX_, rect.posY_, rect.width_, rect.height_, GetSizeChangeReason());
960     TLOGD(WmsLogTag::WMS_KEYBOARD, "id: %{public}d, rect: %{public}s isGlobal: %{public}d needFlush: %{public}d",
961         GetPersistentId(), rect.ToString().c_str(), isGlobal, needFlush);
962     {
963         AutoRSTransaction trans(GetRSUIContext(), needFlush);
964         if (keyboardPanelSession_ == nullptr) {
965             TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboard panel session is null");
966             return;
967         }
968         auto surfaceNode = keyboardPanelSession_->GetSurfaceNode();
969         if (surfaceNode == nullptr) {
970             TLOGE(WmsLogTag::WMS_KEYBOARD, "keyboard panel surfacenode is null");
971             return;
972         }
973         surfaceNode->SetGlobalPositionEnabled(isGlobal);
974         surfaceNode->SetBounds(rect.posX_, rect.posY_, rect.width_, rect.height_);
975         surfaceNode->SetFrame(rect.posX_, rect.posY_, rect.width_, rect.height_);
976     }
977 }
978 
SetKeyboardEffectOptionChangeListener(const NotifyKeyboarEffectOptionChangeFunc & func)979 void KeyboardSession::SetKeyboardEffectOptionChangeListener(const NotifyKeyboarEffectOptionChangeFunc& func)
980 {
981     PostTask([weakThis = wptr(this), func, where = __func__] {
982         auto session = weakThis.promote();
983         if (!session || !func) {
984             TLOGNE(WmsLogTag::WMS_KEYBOARD, "%{public}s session or NotifyKeyboarEffectOptionChangeFunc is null",
985                 where);
986             return WSError::WS_ERROR_DESTROYED_OBJECT;
987         }
988         session->changeKeyboardEffectOptionFunc_ = func;
989         TLOGND(WmsLogTag::WMS_KEYBOARD, "%{public}s Register changeKeyboardEffectOptionFunc_ success", where);
990         return WSError::WS_OK;
991     }, __func__);
992 }
993 
GetPanelRect() const994 WSRect KeyboardSession::GetPanelRect() const
995 {
996     WSRect panelRect = { 0, 0, 0, 0 };
997     if (keyboardPanelSession_ != nullptr) {
998         panelRect = keyboardPanelSession_->GetSessionRect();
999     } else {
1000         TLOGE(WmsLogTag::WMS_KEYBOARD, "Panel session is null, get panel rect failed");
1001     }
1002     return panelRect;
1003 }
1004 
SetSkipSelfWhenShowOnVirtualScreen(bool isSkip)1005 void KeyboardSession::SetSkipSelfWhenShowOnVirtualScreen(bool isSkip)
1006 {
1007     TLOGI(WmsLogTag::WMS_KEYBOARD, "Set Skip keyboard, isSkip: %{public}d", isSkip);
1008     PostTask([weakThis = wptr(this), isSkip, where = __func__]() {
1009         auto session = weakThis.promote();
1010         if (!session) {
1011             TLOGNE(WmsLogTag::WMS_KEYBOARD, "%{public}s: Session is null", where);
1012             return;
1013         }
1014         std::shared_ptr<RSSurfaceNode> surfaceNode = session->GetSurfaceNode();
1015         if (!surfaceNode) {
1016             TLOGNE(WmsLogTag::WMS_KEYBOARD, "%{public}s: SurfaceNode is null", where);
1017             return;
1018         }
1019         if (session->specificCallback_ != nullptr
1020             && session->specificCallback_->onSetSkipSelfWhenShowOnVirtualScreen_ != nullptr) {
1021             session->specificCallback_->onSetSkipSelfWhenShowOnVirtualScreen_(surfaceNode->GetId(), isSkip);
1022         }
1023     }, __func__);
1024 }
1025 
PostKeyboardAnimationSyncTimeoutTask()1026 void KeyboardSession::PostKeyboardAnimationSyncTimeoutTask()
1027 {
1028     // anim_sync_exception
1029     int32_t const THRESHOLD = 1000;
1030     auto task = [weakThis = wptr(this)]() {
1031         auto session = weakThis.promote();
1032         if (!session) {
1033             TLOGNE(WmsLogTag::WMS_KEYBOARD, "keyboard session is null");
1034             return;
1035         }
1036         if (!session->GetIsKeyboardSyncTransactionOpen()) {
1037             TLOGND(WmsLogTag::WMS_KEYBOARD, "closed anim_sync in time");
1038             return;
1039         }
1040         std::string msg("close anim_sync timeout");
1041         WindowInfoReporter::GetInstance().ReportKeyboardLifeCycleException(
1042             session->GetPersistentId(),
1043             KeyboardLifeCycleException::ANIM_SYNC_EXCEPTION,
1044             msg);
1045     };
1046     auto handler = GetEventHandler();
1047     if (!handler) {
1048         TLOGE(WmsLogTag::WMS_KEYBOARD, "handler is null");
1049         return;
1050     }
1051     handler->PostTask(task, KEYBOARD_ANIM_SYNC_EVENT_NAME, THRESHOLD);
1052 }
1053 
SetSkipEventOnCastPlus(bool isSkip)1054 void KeyboardSession::SetSkipEventOnCastPlus(bool isSkip)
1055 {
1056     PostTask([weakThis = wptr(this), isSkip, where = __func__]() {
1057         auto session = weakThis.promote();
1058         if (!session) {
1059             TLOGNE(WmsLogTag::WMS_SCB, "%{public}s session is null", where);
1060             return;
1061         }
1062         TLOGNI(WmsLogTag::WMS_SCB, "%{public}s wid: %{public}d, isSkip: %{public}d", where,
1063             session->GetPersistentId(), isSkip);
1064         if (session->specificCallback_ != nullptr &&
1065             session->specificCallback_->onSetSkipEventOnCastPlus_ != nullptr) {
1066             session->specificCallback_->onSetSkipEventOnCastPlus_(session->GetPersistentId(), isSkip);
1067         }
1068     }, __func__);
1069 }
1070 
UpdateSizeChangeReason(SizeChangeReason reason)1071 WSError KeyboardSession::UpdateSizeChangeReason(SizeChangeReason reason)
1072 {
1073     PostTask([weakThis = wptr(this), reason, where = __func__]() {
1074         auto keyboardSession = weakThis.promote();
1075         if (keyboardSession == nullptr) {
1076             TLOGE(WmsLogTag::WMS_KEYBOARD, "%{public}s session is null", where);
1077             return WSError::WS_ERROR_DESTROYED_OBJECT;
1078         }
1079         if (reason == SizeChangeReason::DRAG_START || reason == SizeChangeReason::DRAG_MOVE ||
1080             reason == SizeChangeReason::DRAG_END || reason == SizeChangeReason::UNDEFINED) {
1081             auto panelSession = keyboardSession->GetKeyboardPanelSession();
1082             if (panelSession != nullptr) {
1083                 panelSession->UpdateSizeChangeReason(reason);
1084             }
1085         }
1086         TLOGD(WmsLogTag::WMS_KEYBOARD, "%{public}s Id: %{public}d, reason: %{public}d",
1087             where, keyboardSession->GetPersistentId(), static_cast<int32_t>(reason));
1088         keyboardSession->SceneSession::UpdateSizeChangeReason(reason);
1089         return WSError::WS_OK;
1090     }, __func__);
1091     return WSError::WS_OK;
1092 }
1093 
CalculateOccupiedAreaAfterUIRefresh()1094 void KeyboardSession::CalculateOccupiedAreaAfterUIRefresh()
1095 {
1096     bool needRecalculateOccupiedArea = false;
1097     const uint32_t keyboardDirtyFlags = GetDirtyFlags();
1098     if ((keyboardDirtyFlags & static_cast<uint32_t>(SessionUIDirtyFlag::VISIBLE)) !=
1099         static_cast<uint32_t>(SessionUIDirtyFlag::NONE) ||
1100         (keyboardDirtyFlags & static_cast<uint32_t>(SessionUIDirtyFlag::RECT)) !=
1101         static_cast<uint32_t>(SessionUIDirtyFlag::NONE) || stateChanged_) {
1102         TLOGD(WmsLogTag::WMS_KEYBOARD, "Keyboard panel rect has changed");
1103         needRecalculateOccupiedArea = true;
1104     }
1105     // Recalculate the occupied area info when calling session rect changes && keyboard is visible.
1106     uint32_t callingId = GetCallingSessionId();
1107     sptr<SceneSession> callingSession = GetSceneSession(callingId);
1108     if (callingSession && (callingSession->GetDirtyFlags() & static_cast<uint32_t>(SessionUIDirtyFlag::RECT)) !=
1109         static_cast<uint32_t>(SessionUIDirtyFlag::NONE) && IsVisibleForeground()) {
1110         SizeChangeReason reason = callingSession->GetSizeChangeReason();
1111         // Skip recalculation during drag operations and reset oriPosYBeforeRaisedByKeyboard_.
1112         if ((reason >= SizeChangeReason::DRAG && reason <= SizeChangeReason::DRAG_END) ||
1113             reason == SizeChangeReason::DRAG_MOVE) {
1114             if (callingSession->GetOriPosYBeforeRaisedByKeyboard() != 0) {
1115                 TLOGI(WmsLogTag::WMS_KEYBOARD, "Skip recalculation and reset oriPosYBeforeRaisedByKeyboard_,"
1116                     " id: %{public}d", callingId);
1117                 callingSession->SetOriPosYBeforeRaisedByKeyboard(0);
1118             }
1119         } else {
1120             TLOGD(WmsLogTag::WMS_KEYBOARD, "Calling session rect has changed");
1121             needRecalculateOccupiedArea = true;
1122         }
1123     }
1124     if (needRecalculateOccupiedArea) {
1125         ProcessKeyboardOccupiedAreaInfo(callingId, false, stateChanged_);
1126         stateChanged_ = false;
1127     }
1128 }
1129 } // namespace OHOS::Rosen