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