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