1 /*
2  * Copyright (c) 2023 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/system_session.h"
17 
18 #include "common/include/session_permission.h"
19 #include "key_event.h"
20 #include "session/host/include/session.h"
21 #include "window_helper.h"
22 #include "window_manager_hilog.h"
23 #include "parameters.h"
24 #include "pointer_event.h"
25 namespace OHOS::Rosen {
26 namespace {
27 constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, HILOG_DOMAIN_WINDOW, "SystemSession" };
28 } // namespace
29 
30 constexpr uint32_t MIN_SYSTEM_WINDOW_WIDTH = 5;
31 constexpr uint32_t MIN_SYSTEM_WINDOW_HEIGHT = 5;
32 
SystemSession(const SessionInfo& info, const sptr<SpecificSessionCallback>& specificCallback)33 SystemSession::SystemSession(const SessionInfo& info, const sptr<SpecificSessionCallback>& specificCallback)
34     : SceneSession(info, specificCallback)
35 {
36     TLOGD(WmsLogTag::WMS_LIFE, "Create SystemSession");
37     moveDragController_ = sptr<MoveDragController>::MakeSptr(GetPersistentId(), true);
38     if (specificCallback != nullptr &&
39         specificCallback->onWindowInputPidChangeCallback_ != nullptr) {
40         moveDragController_->SetNotifyWindowPidChangeCallback(specificCallback_->onWindowInputPidChangeCallback_);
41     }
42     SetMoveDragCallback();
43 }
44 
~SystemSession()45 SystemSession::~SystemSession()
46 {
47     TLOGD(WmsLogTag::WMS_LIFE, "~SystemSession, id: %{public}d", GetPersistentId());
48 }
49 
UpdateCameraWindowStatus(bool isShowing)50 void SystemSession::UpdateCameraWindowStatus(bool isShowing)
51 {
52     if (specificCallback_ == nullptr) {
53         return;
54     }
55     if (GetWindowType() == WindowType::WINDOW_TYPE_FLOAT_CAMERA) {
56         if (!specificCallback_->onCameraFloatSessionChange_) {
57             return;
58         }
59         TLOGI(WmsLogTag::WMS_SYSTEM, "CameraFloat status: %{public}d, id: %{public}d", isShowing, GetPersistentId());
60         specificCallback_->onCameraFloatSessionChange_(GetSessionProperty()->GetAccessTokenId(), isShowing);
61     } else if (GetWindowType() == WindowType::WINDOW_TYPE_PIP && GetWindowMode() == WindowMode::WINDOW_MODE_PIP) {
62         if (!specificCallback_->onCameraSessionChange_) {
63             return;
64         }
65         auto pipType = GetPiPTemplateInfo().pipTemplateType;
66         if (pipType == static_cast<uint32_t>(PiPTemplateType::VIDEO_CALL) ||
67             pipType == static_cast<uint32_t>(PiPTemplateType::VIDEO_MEETING)) {
68             TLOGI(WmsLogTag::WMS_SYSTEM, "PiPWindow status: %{public}d, id: %{public}d", isShowing, GetPersistentId());
69             specificCallback_->onCameraSessionChange_(GetSessionProperty()->GetAccessTokenId(), isShowing);
70         }
71     } else {
72         TLOGI(WmsLogTag::WMS_SYSTEM, "Skip window type, isShowing: %{public}d", isShowing);
73     }
74 }
75 
Show(sptr<WindowSessionProperty> property)76 WSError SystemSession::Show(sptr<WindowSessionProperty> property)
77 {
78     if (!CheckPermissionWithPropertyAnimation(property)) {
79         return WSError::WS_ERROR_NOT_SYSTEM_APP;
80     }
81     auto type = GetWindowType();
82     if (((type == WindowType::WINDOW_TYPE_TOAST) || (type == WindowType::WINDOW_TYPE_FLOAT)) &&
83         !SessionPermission::IsSystemCalling()) {
84         auto parentSession = GetParentSession();
85         if (parentSession == nullptr) {
86             WLOGFW("parent session is null");
87             return WSError::WS_ERROR_INVALID_PARENT;
88         }
89         if (!parentSession->IsSessionForeground()) {
90             WLOGFW("parent session is not in foreground");
91             return WSError::WS_ERROR_INVALID_OPERATION;
92         }
93     }
94     auto task = [weakThis = wptr(this), property]() {
95         auto session = weakThis.promote();
96         if (!session) {
97             WLOGFE("session is null");
98             return WSError::WS_ERROR_DESTROYED_OBJECT;
99         }
100         TLOGI(WmsLogTag::WMS_LIFE, "Show session, id: %{public}d", session->GetPersistentId());
101         // use property from client
102         if (property && property->GetAnimationFlag() == static_cast<uint32_t>(WindowAnimation::CUSTOM)) {
103             session->GetSessionProperty()->SetAnimationFlag(static_cast<uint32_t>(WindowAnimation::CUSTOM));
104             session->NotifyIsCustomAnimationPlaying(true);
105         }
106         session->UpdateCameraWindowStatus(true);
107         session->UpdatePiPWindowStateChanged(true);
108         auto ret = session->SceneSession::Foreground(property);
109         return ret;
110     };
111     PostTask(task, "Show");
112     return WSError::WS_OK;
113 }
114 
Hide()115 WSError SystemSession::Hide()
116 {
117     if (!CheckPermissionWithPropertyAnimation(GetSessionProperty())) {
118         return WSError::WS_ERROR_NOT_SYSTEM_APP;
119     }
120     auto type = GetWindowType();
121     if (NeedSystemPermission(type)) {
122         // Do not need to verify the permission to hide the input method status bar.
123         if (!SessionPermission::IsSystemCalling() && type != WindowType::WINDOW_TYPE_INPUT_METHOD_STATUS_BAR) {
124             TLOGE(WmsLogTag::WMS_LIFE, "Hide permission denied id: %{public}d type:%{public}u",
125                 GetPersistentId(), type);
126             return WSError::WS_ERROR_INVALID_PERMISSION;
127         }
128     }
129     auto task = [weakThis = wptr(this)]() {
130         auto session = weakThis.promote();
131         if (!session) {
132             TLOGE(WmsLogTag::WMS_LIFE, "session is null");
133             return WSError::WS_ERROR_DESTROYED_OBJECT;
134         }
135         TLOGI(WmsLogTag::WMS_LIFE, "Hide session, id: %{public}d", session->GetPersistentId());
136         auto ret = session->SetActive(false);
137         if (ret != WSError::WS_OK) {
138             return ret;
139         }
140         // background will remove surfaceNode, custom not execute
141         // not animation playing when already background; inactive may be animation playing
142         auto sessionProperty = session->GetSessionProperty();
143         if (sessionProperty &&
144             sessionProperty->GetAnimationFlag() == static_cast<uint32_t>(WindowAnimation::CUSTOM)) {
145             session->NotifyIsCustomAnimationPlaying(true);
146             return WSError::WS_OK;
147         }
148         session->UpdateCameraWindowStatus(false);
149         session->UpdatePiPWindowStateChanged(false);
150         ret = session->SceneSession::Background();
151         return ret;
152     };
153     PostTask(task, "Hide");
154     return WSError::WS_OK;
155 }
156 
Disconnect(bool isFromClient, const std::string& identityToken)157 WSError SystemSession::Disconnect(bool isFromClient, const std::string& identityToken)
158 {
159     auto task = [weakThis = wptr(this), isFromClient]() {
160         auto session = weakThis.promote();
161         if (!session) {
162             TLOGE(WmsLogTag::WMS_LIFE, "session is null");
163             return WSError::WS_ERROR_DESTROYED_OBJECT;
164         }
165         TLOGI(WmsLogTag::WMS_LIFE, "Disconnect session, id: %{public}d", session->GetPersistentId());
166         session->SceneSession::Disconnect(isFromClient);
167         session->UpdateCameraWindowStatus(false);
168         session->UpdatePiPWindowStateChanged(false);
169         return WSError::WS_OK;
170     };
171     PostTask(task, "Disconnect");
172     return WSError::WS_OK;
173 }
174 
ProcessPointDownSession(int32_t posX, int32_t posY)175 WSError SystemSession::ProcessPointDownSession(int32_t posX, int32_t posY)
176 {
177     const auto& id = GetPersistentId();
178     const auto& type = GetWindowType();
179     auto parentSession = GetParentSession();
180     if (parentSession && parentSession->CheckDialogOnForeground()) {
181         WLOGFI("Parent has dialog foreground, id: %{public}d, type: %{public}d", id, type);
182         parentSession->HandlePointDownDialog();
183         if (!IsTopDialog()) {
184             return WSError::WS_OK;
185         }
186     }
187     if (type == WindowType::WINDOW_TYPE_DIALOG) {
188         Session::ProcessClickModalSpecificWindowOutside(posX, posY);
189         auto sessionProperty = GetSessionProperty();
190         if (sessionProperty && sessionProperty->GetRaiseEnabled()) {
191             RaiseToAppTopForPointDown();
192         }
193     }
194     TLOGI(WmsLogTag::WMS_LIFE, "id: %{public}d, type: %{public}d", id, type);
195     PresentFocusIfPointDown();
196     return SceneSession::ProcessPointDownSession(posX, posY);
197 }
198 
GetMissionId() const199 int32_t SystemSession::GetMissionId() const
200 {
201     auto parentSession = GetParentSession();
202     return parentSession != nullptr ? parentSession->GetPersistentId() : SceneSession::GetMissionId();
203 }
204 
TransferKeyEvent(const std::shared_ptr<MMI::KeyEvent>& keyEvent)205 WSError SystemSession::TransferKeyEvent(const std::shared_ptr<MMI::KeyEvent>& keyEvent)
206 {
207     if (!IsSessionValid()) {
208         return WSError::WS_ERROR_INVALID_SESSION;
209     }
210     if (keyEvent == nullptr) {
211         WLOGFE("KeyEvent is nullptr");
212         return WSError::WS_ERROR_NULLPTR;
213     }
214     if (GetWindowType() == WindowType::WINDOW_TYPE_DIALOG) {
215         if (keyEvent->GetKeyCode() == MMI::KeyEvent::KEYCODE_BACK) {
216             return WSError::WS_ERROR_INVALID_PERMISSION;
217         }
218         auto parentSession = GetParentSession();
219         if (parentSession && parentSession->CheckDialogOnForeground() &&
220             !IsTopDialog()) {
221             return WSError::WS_ERROR_INVALID_PERMISSION;
222         }
223         if (!CheckKeyEventDispatch(keyEvent)) {
224             WLOGFW("Do not dispatch the key event.");
225             return WSError::WS_DO_NOTHING;
226         }
227     }
228 
229     WSError ret = Session::TransferKeyEvent(keyEvent);
230     return ret;
231 }
232 
ProcessBackEvent()233 WSError SystemSession::ProcessBackEvent()
234 {
235     if (!IsSessionValid()) {
236         TLOGD(WmsLogTag::WMS_EVENT, "Session is invalid, id: %{public}d state: %{public}u",
237             GetPersistentId(), GetSessionState());
238         return WSError::WS_ERROR_INVALID_SESSION;
239     }
240     if (GetWindowType() == WindowType::WINDOW_TYPE_DIALOG && !dialogSessionBackGestureEnabled_) {
241         TLOGI(WmsLogTag::WMS_DIALOG, "this is dialog, id: %{public}d", GetPersistentId());
242         return WSError::WS_OK;
243     }
244     if (sessionStage_ == nullptr) {
245         TLOGE(WmsLogTag::WMS_EVENT, "sessionStage_ is nullptr, id = %{public}d.",
246             GetPersistentId());
247         return WSError::WS_ERROR_NULLPTR;
248     }
249     return sessionStage_->HandleBackEvent();
250 }
251 
NotifyClientToUpdateRect(const std::string& updateReason, std::shared_ptr<RSTransaction> rsTransaction)252 WSError SystemSession::NotifyClientToUpdateRect(const std::string& updateReason,
253     std::shared_ptr<RSTransaction> rsTransaction)
254 {
255     auto task = [weakThis = wptr(this), rsTransaction, updateReason]() {
256         auto session = weakThis.promote();
257         if (!session) {
258             WLOGFE("session is null");
259             return WSError::WS_ERROR_DESTROYED_OBJECT;
260         }
261         WSError ret = session->NotifyClientToUpdateRectTask(updateReason, rsTransaction);
262         if (ret != WSError::WS_OK) {
263             return ret;
264         }
265         if (session->specificCallback_ != nullptr && session->specificCallback_->onUpdateAvoidArea_ != nullptr) {
266             if (Session::IsScbCoreEnabled()) {
267                 session->dirtyFlags_ |= static_cast<uint32_t>(SessionUIDirtyFlag::AVOID_AREA);
268             } else {
269                 session->specificCallback_->onUpdateAvoidArea_(session->GetPersistentId());
270             }
271         }
272         if (session->reason_ != SizeChangeReason::DRAG) {
273             session->reason_ = SizeChangeReason::UNDEFINED;
274             session->dirtyFlags_ &= ~static_cast<uint32_t>(SessionUIDirtyFlag::RECT);
275         }
276         return ret;
277     };
278     PostTask(task, "NotifyClientToUpdateRect");
279     return WSError::WS_OK;
280 }
281 
CheckKeyEventDispatch(const std::shared_ptr<MMI::KeyEvent>& keyEvent) const282 bool SystemSession::CheckKeyEventDispatch(const std::shared_ptr<MMI::KeyEvent>& keyEvent) const
283 {
284     auto currentRect = winRect_;
285     if (!GetRSVisible() || currentRect.width_ == 0 || currentRect.height_ == 0) {
286         WLOGE("Error size: [width: %{public}d, height: %{public}d], isRSVisible_: %{public}d,"
287             " persistentId: %{public}d",
288             currentRect.width_, currentRect.height_, GetRSVisible(), GetPersistentId());
289         return false;
290     }
291 
292     auto parentSession = GetParentSession();
293     if (parentSession == nullptr) {
294         WLOGFW("Dialog parent is null");
295         return false;
296     }
297     auto parentSessionState = parentSession->GetSessionState();
298     if ((parentSessionState != SessionState::STATE_FOREGROUND &&
299         parentSessionState != SessionState::STATE_ACTIVE) ||
300         (state_ != SessionState::STATE_FOREGROUND &&
301         state_ != SessionState::STATE_ACTIVE)) {
302         TLOGE(WmsLogTag::WMS_DIALOG, "Dialog's parent info : [persistentId: %{publicd}d, state:%{public}d];"
303             "Dialog info:[persistentId: %{publicd}d, state:%{public}d]",
304             parentSession->GetPersistentId(), parentSessionState, GetPersistentId(), GetSessionState());
305         return false;
306     }
307     return true;
308 }
309 
NeedSystemPermission(WindowType type)310 bool SystemSession::NeedSystemPermission(WindowType type)
311 {
312     return !(type == WindowType::WINDOW_TYPE_SCENE_BOARD || type == WindowType::WINDOW_TYPE_SYSTEM_FLOAT ||
313         type == WindowType::WINDOW_TYPE_SYSTEM_SUB_WINDOW || type == WindowType::WINDOW_TYPE_TOAST ||
314         type == WindowType::WINDOW_TYPE_DRAGGING_EFFECT || type == WindowType::WINDOW_TYPE_APP_LAUNCHING ||
315         type == WindowType::WINDOW_TYPE_PIP);
316 }
317 
CheckPointerEventDispatch(const std::shared_ptr<MMI::PointerEvent>& pointerEvent) const318 bool SystemSession::CheckPointerEventDispatch(const std::shared_ptr<MMI::PointerEvent>& pointerEvent) const
319 {
320     auto sessionState = GetSessionState();
321     int32_t action = pointerEvent->GetPointerAction();
322     auto isPC = systemConfig_.IsPcWindow();
323     bool isDialog = WindowHelper::IsDialogWindow(GetWindowType());
324     if (isPC && isDialog && sessionState != SessionState::STATE_FOREGROUND &&
325         sessionState != SessionState::STATE_ACTIVE &&
326         action != MMI::PointerEvent::POINTER_ACTION_LEAVE_WINDOW) {
327         WLOGFW("CheckPointerEventDispatch false, Current Session Info: [persistentId: %{public}d, "
328             "state: %{public}d, action:%{public}d]", GetPersistentId(), GetSessionState(), action);
329         return false;
330     }
331     return true;
332 }
333 
UpdatePointerArea(const WSRect& rect)334 void SystemSession::UpdatePointerArea(const WSRect& rect)
335 {
336     auto property = GetSessionProperty();
337     if (!(property->IsDecorEnable() && GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING)) {
338         return;
339     }
340     Session::UpdatePointerArea(rect);
341 }
342 
RectCheck(uint32_t curWidth, uint32_t curHeight)343 void SystemSession::RectCheck(uint32_t curWidth, uint32_t curHeight)
344 {
345     uint32_t minWidth = MIN_SYSTEM_WINDOW_WIDTH;
346     uint32_t minHeight = MIN_SYSTEM_WINDOW_HEIGHT;
347     uint32_t maxFloatingWindowSize = GetSystemConfig().maxFloatingWindowSize_;
348     RectSizeCheckProcess(curWidth, curHeight, minWidth, minHeight, maxFloatingWindowSize);
349 }
350 
IsVisibleForeground() const351 bool SystemSession::IsVisibleForeground() const
352 {
353     if (GetWindowType() == WindowType::WINDOW_TYPE_DIALOG &&
354         parentSession_ && WindowHelper::IsMainWindow(parentSession_->GetWindowType())) {
355         return parentSession_->IsVisibleForeground() && Session::IsVisibleForeground();
356     }
357     return Session::IsVisibleForeground();
358 }
359 
SetDialogSessionBackGestureEnabled(bool isEnabled)360 WSError SystemSession::SetDialogSessionBackGestureEnabled(bool isEnabled)
361 {
362     return PostSyncTask([weakThis = wptr(this), isEnabled]() {
363         auto session = weakThis.promote();
364         if (!session) {
365             WLOGFE("session is null");
366             return WSError::WS_ERROR_DESTROYED_OBJECT;
367         }
368         WindowType windowType = session->GetWindowType();
369         if (windowType != WindowType::WINDOW_TYPE_DIALOG) {
370             TLOGE(WmsLogTag::WMS_DIALOG, "windowType not support. WinId:%{public}u, WindowType:%{public}u",
371                 session->GetWindowId(), static_cast<uint32_t>(windowType));
372             return WSError::WS_ERROR_INVALID_CALLING;
373         }
374         session->dialogSessionBackGestureEnabled_ = isEnabled;
375         return WSError::WS_OK;
376     });
377 }
378 
UpdatePiPWindowStateChanged(bool isForeground)379 void SystemSession::UpdatePiPWindowStateChanged(bool isForeground)
380 {
381     if (specificCallback_ == nullptr || !specificCallback_->onPiPStateChange_) {
382         return;
383     }
384     if (GetWindowType() == WindowType::WINDOW_TYPE_PIP) {
385         TLOGI(WmsLogTag::WMS_PIP, "pip state changed, bundleName:%{public}s, state:%{public}d",
386             GetSessionInfo().bundleName_.c_str(), isForeground);
387         specificCallback_->onPiPStateChange_(GetSessionInfo().bundleName_, isForeground);
388     } else {
389         TLOGD(WmsLogTag::WMS_PIP, "skip type");
390     }
391 }
392 } // namespace OHOS::Rosen
393