From c4f36c03b300e80492f1fd4c41f2e2c49b5b57c4 Mon Sep 17 00:00:00 2001 From: thks Date: Sat, 1 Mar 2025 15:14:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AD=90=E7=AA=97&dialog?= =?UTF-8?q?=E8=B7=9F=E9=9A=8F=E4=B8=BB=E7=AA=97=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: thks --- interfaces/innerkits/wm/window.h | 8 ++ .../window_runtime/window_napi/js_window.cpp | 53 +++++++++ .../window_runtime/window_napi/js_window.h | 2 + previewer/include/window.h | 8 ++ .../js_scene_session.cpp | 47 +++++++- .../scene_session_manager/js_scene_session.h | 3 + .../session/host/include/main_session.h | 4 + .../host/include/move_drag_controller.h | 3 + .../session/host/include/scene_session.h | 20 +++- window_scene/session/host/include/session.h | 3 + .../host/include/zidl/session_interface.h | 1 + .../include/zidl/session_ipc_interface_code.h | 1 + .../session/host/include/zidl/session_proxy.h | 5 + .../session/host/include/zidl/session_stub.h | 2 + .../session/host/src/main_session.cpp | 11 ++ .../session/host/src/move_drag_controller.cpp | 22 ++++ .../session/host/src/scene_session.cpp | 105 ++++++++++++++++++ .../session/host/src/zidl/session_proxy.cpp | 32 ++++++ .../session/host/src/zidl/session_stub.cpp | 18 +++ .../src/scene_session_manager.cpp | 5 + wm/include/window_scene_session_impl.h | 1 + wm/src/window_scene_session_impl.cpp | 19 ++++ 22 files changed, 371 insertions(+), 2 deletions(-) diff --git a/interfaces/innerkits/wm/window.h b/interfaces/innerkits/wm/window.h index eeea50d2cc..01b8dcf485 100644 --- a/interfaces/innerkits/wm/window.h +++ b/interfaces/innerkits/wm/window.h @@ -3264,6 +3264,14 @@ public: * @return Api version */ virtual uint32_t GetApiVersion() const { return 0; } + + /** + * @brief Set the feature of subwindow follow the layout of the parent window. + * + * @param isFollow true - follow, false - not follow. + * @return WM_OK means set success. + */ + virtual WMError SetFollowParentWindowLayoutEnabled(bool isFollow) { return WMError::WM_ERROR_DEVICE_NOT_SUPPORT; } }; } } diff --git a/interfaces/kits/napi/window_runtime/window_napi/js_window.cpp b/interfaces/kits/napi/window_runtime/window_napi/js_window.cpp index 72d396f588..a4a86d0e90 100644 --- a/interfaces/kits/napi/window_runtime/window_napi/js_window.cpp +++ b/interfaces/kits/napi/window_runtime/window_napi/js_window.cpp @@ -1109,6 +1109,13 @@ napi_value JsWindow::IsWindowHighlighted(napi_env env, napi_callback_info info) return (me != nullptr) ? me->OnIsWindowHighlighted(env, info) : nullptr; } +napi_value JsWindow::SetFollowParentWindowLayoutEnabled(napi_env env, napi_callback_info info) +{ + TLOGD(WmsLogTag::WMS_SUB, "[NAPI]"); + JsWindow* me = CheckParamsAndGetThis(env, info); + return (me != nullptr) ? me->OnSetFollowParentWindowLayoutEnabled(env, info) : nullptr; +} + WMError UpdateStatusBarProperty(const sptr& window, const uint32_t contentColor) { if (window == nullptr) { @@ -7749,6 +7756,50 @@ napi_value JsWindow::OnIsWindowHighlighted(napi_env env, napi_callback_info info return CreateJsValue(env, isHighlighted); } +napi_value JsWindow::OnSetFollowParentWindowLayoutEnabled(napi_env env, napi_callback_info info) +{ + size_t argc = FOUR_PARAMS_SIZE; + napi_value argv[FOUR_PARAMS_SIZE] = { nullptr }; + napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); + if (argc != INDEX_ONE) { + TLOGE(WmsLogTag::WMS_SUB, "argc is invalid: %{public}zu", argc); + return NapiThrowError(env, WmErrorCode::WM_ERROR_INVALID_PARAM); + } + bool isFollow = false; + if (!ConvertFromJsValue(env, argv[INDEX_ZERO], isFollow)) { + TLOGE(WmsLogTag::WMS_SUB, "Failed to convert parameter to enable"); + return NapiThrowError(env, WmErrorCode::WM_ERROR_INVALID_PARAM); + } + std::shared_ptr errCodePtr = std::make_shared(WmErrorCode::WM_OK); + const char* const where = __func__; + auto execute = [weakToken = wptr(windowToken_), errCodePtr, isFollow, where] { + auto window = weakToken.promote(); + if (window == nullptr) { + TLOGNE(WmsLogTag::WMS_SUB, "%{public}s window is nullptr", where); + *errCodePtr = WmErrorCode::WM_ERROR_STATE_ABNORMALLY; + return; + } + if (!WindowHelper::IsSubWindow(window->GetType()) && !WindowHelper::IsDialogWindow(window->GetType())) { + TLOGNE(WmsLogTag::WMS_SUB, "%{public}s only sub window and dialog is valid", where); + *errCodePtr = WmErrorCode::WM_ERROR_INVALID_CALLING; + return; + } + *errCodePtr = WM_JS_TO_ERROR_CODE_MAP.at(window->SetFollowParentWindowLayoutEnabled(isFollow)); + }; + auto complete = [errCodePtr, where](napi_env env, NapiAsyncTask& task, int32_t status) { + if (*errCodePtr == WmErrorCode::WM_OK) { + task.Resolve(env, NapiGetUndefined(env)); + } else { + TLOGNE(WmsLogTag::WMS_SUB, "%{public}s failed, ret %{public}d", where, *errCodePtr); + task.Reject(env, JsErrUtils::CreateJsError(env, *errCodePtr, "set follow parent layout failed.")); + } + }; + napi_value result = nullptr; + NapiAsyncTask::Schedule("JsWindow::OnSetFollowParentWindowLayoutEnabled", + env, CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result)); + return result; +} + void BindFunctions(napi_env env, napi_value object, const char* moduleName) { BindNativeFunction(env, object, "startMoving", moduleName, JsWindow::StartMoving); @@ -7898,6 +7949,8 @@ void BindFunctions(napi_env env, napi_value object, const char* moduleName) BindNativeFunction(env, object, "isSystemAvoidAreaEnabled", moduleName, JsWindow::IsSystemAvoidAreaEnabled); BindNativeFunction(env, object, "setExclusivelyHighlighted", moduleName, JsWindow::SetExclusivelyHighlighted); BindNativeFunction(env, object, "isWindowHighlighted", moduleName, JsWindow::IsWindowHighlighted); + BindNativeFunction(env, object, "setFollowParentWindowLayoutEnabled", moduleName, + JsWindow::SetFollowParentWindowLayoutEnabled); } } // namespace Rosen } // namespace OHOS diff --git a/interfaces/kits/napi/window_runtime/window_napi/js_window.h b/interfaces/kits/napi/window_runtime/window_napi/js_window.h index c0e7e3e08d..c345c17b00 100644 --- a/interfaces/kits/napi/window_runtime/window_napi/js_window.h +++ b/interfaces/kits/napi/window_runtime/window_napi/js_window.h @@ -217,6 +217,7 @@ public: static napi_value IsSystemAvoidAreaEnabled(napi_env env, napi_callback_info info); static napi_value SetImmersiveModeEnabledState(napi_env env, napi_callback_info info); static napi_value GetImmersiveModeEnabledState(napi_env env, napi_callback_info info); + static napi_value SetFollowParentWindowLayoutEnabled(napi_env env, napi_callback_info info); private: std::string GetWindowName(); @@ -407,6 +408,7 @@ private: napi_value OnGetImmersiveModeEnabledState(napi_env env, napi_callback_info info); napi_value OnSetSystemAvoidAreaEnabled(napi_env env, napi_callback_info info); napi_value OnIsSystemAvoidAreaEnabled(napi_env env, napi_callback_info info); + napi_value OnSetFollowParentWindowLayoutEnabled(napi_env env, napi_callback_info info); }; } // namespace Rosen } // namespace OHOS diff --git a/previewer/include/window.h b/previewer/include/window.h index 09e7ad26bb..a4b03339a6 100644 --- a/previewer/include/window.h +++ b/previewer/include/window.h @@ -516,6 +516,14 @@ public: * @return Api version */ virtual uint32_t GetApiVersion() const { return 0; } + + /** + * @brief Set the feature of subwindow follow the layout of the parent window. + * + * @param isFollow true - follow, false - not follow. + * @return WM_OK means set success. + */ + virtual WMError SetFollowParentWindowLayoutEnabled(bool isFollow) { return WMError::WM_ERROR_SYSTEM_ABNORMALLY; } }; } } diff --git a/window_scene/interfaces/kits/napi/scene_session_manager/js_scene_session.cpp b/window_scene/interfaces/kits/napi/scene_session_manager/js_scene_session.cpp index 430c3815a5..7db889aceb 100644 --- a/window_scene/interfaces/kits/napi/scene_session_manager/js_scene_session.cpp +++ b/window_scene/interfaces/kits/napi/scene_session_manager/js_scene_session.cpp @@ -37,6 +37,7 @@ const std::string WINDOW_MOVING_CB = "windowMoving"; const std::string SESSION_PIP_CONTROL_STATUS_CHANGE_CB = "sessionPiPControlStatusChange"; const std::string SESSION_AUTO_START_PIP_CB = "autoStartPiP"; const std::string CREATE_SUB_SESSION_CB = "createSpecificSession"; +const std::string FOLLOW_PARENT_RECT_CB = "followParentRect"; const std::string BIND_DIALOG_TARGET_CB = "bindDialogTarget"; const std::string RAISE_TO_TOP_CB = "raiseToTop"; const std::string RAISE_TO_TOP_POINT_DOWN_CB = "raiseToTopForPointDown"; @@ -164,9 +165,10 @@ const std::map ListenerFuncMap { {SESSION_LOCK_STATE_CHANGE_CB, ListenerFuncType::SESSION_LOCK_STATE_CHANGE_CB}, {UPDATE_SESSION_LABEL_AND_ICON_CB, ListenerFuncType::UPDATE_SESSION_LABEL_AND_ICON_CB}, {KEYBOARD_STATE_CHANGE_CB, ListenerFuncType::KEYBOARD_STATE_CHANGE_CB}, - {KEYBOARD_VIEW_MODE_CHANGE_CB, ListenerFuncType::KEYBOARD_VIEW_MODE_CHANGE_CB}, + {KEYBOARD_VIEW_MODE_CHANGE_CB, ListenerFuncType::KEYBOARD_VIEW_MODE_CHANGE_CB}, {SET_WINDOW_CORNER_RADIUS_CB, ListenerFuncType::SET_WINDOW_CORNER_RADIUS_CB}, {HIGHLIGHT_CHANGE_CB, ListenerFuncType::HIGHLIGHT_CHANGE_CB}, + {FOLLOW_PARENT_RECT_CB, ListenerFuncType::FOLLOW_PARENT_RECT_CB}, }; const std::vector g_syncGlobalPositionPermission { @@ -2634,6 +2636,9 @@ void JsSceneSession::ProcessRegisterCallback(ListenerFuncType listenerFuncType) case static_cast(ListenerFuncType::SET_WINDOW_CORNER_RADIUS_CB): ProcessSetWindowCornerRadiusRegister(); break; + case static_cast(ListenerFuncType::FOLLOW_PARENT_RECT_CB): + ProcessFollowParentRectRegister(); + break; default: break; } @@ -6373,6 +6378,46 @@ void JsSceneSession::NotifyHighlightChange(bool isHighlight) taskScheduler_->PostMainThreadTask(task, "NotifyHighlightChange"); } +void JsSceneSession::ProcessFollowParentRectRegister() +{ + NotifyFollowParentRectFunc func = [weakThis = wptr(this), where = __func__](bool isFollow) { + auto jsSceneSession = weakThis.promote(); + if (!jsSceneSession) { + TLOGNE(WmsLogTag::WMS_SUB, "%{public}s: jsSceneSession is null", where); + return; + } + jsSceneSession->NotifyFollowParentRect(isFollow); + }; + auto session = weakSession_.promote(); + if (session == nullptr) { + TLOGE(WmsLogTag::WMS_SUB, "session is nullptr"); + return; + } + session->SetFollowParentRectFunc(std::move(func)); +} + +void JsSceneSession::NotifyFollowParentRect(bool isFollow) +{ + TLOGI(WmsLogTag::WMS_SUB, "isFollow: %{public}d, id: %{public}d", isFollow, persistentId_); + auto task = [weakThis = wptr(this), isFollow, env = env_, persistentId = persistentId_, where = __func__] { + auto jsSceneSession = weakThis.promote(); + if (!jsSceneSession || jsSceneSessionMap_.find(persistentId) == jsSceneSessionMap_.end()) { + TLOGNE(WmsLogTag::WMS_SUB, "%{public}s: jsSceneSession id: %{public}d has been destroyed", + where, persistentId); + return; + } + auto jsCallBack = jsSceneSession->GetJSCallback(FOLLOW_PARENT_RECT_CB); + if (!jsCallBack) { + TLOGNE(WmsLogTag::WMS_SUB, "%{public}s: jsCallBack is nullptr", where); + return; + } + napi_value jsIsFollow = CreateJsValue(env, isFollow); + napi_value argv[] = { jsIsFollow }; + napi_call_function(env, NapiGetUndefined(env), jsCallBack->GetNapiValue(), ArraySize(argv), argv, nullptr); + }; + taskScheduler_->PostMainThreadTask(task, "NotifyFollowParentRect"); +} + napi_value JsSceneSession::OnSetColorSpace(napi_env env, napi_callback_info info) { size_t argc = ARGC_FOUR; diff --git a/window_scene/interfaces/kits/napi/scene_session_manager/js_scene_session.h b/window_scene/interfaces/kits/napi/scene_session_manager/js_scene_session.h index fcb456f917..a378bd3537 100644 --- a/window_scene/interfaces/kits/napi/scene_session_manager/js_scene_session.h +++ b/window_scene/interfaces/kits/napi/scene_session_manager/js_scene_session.h @@ -91,6 +91,7 @@ enum class ListenerFuncType : uint32_t { KEYBOARD_VIEW_MODE_CHANGE_CB, SET_WINDOW_CORNER_RADIUS_CB, HIGHLIGHT_CHANGE_CB, + FOLLOW_PARENT_RECT_CB, }; class SceneSession; @@ -343,6 +344,7 @@ private: void ProcessKeyboardStateChangeRegister(); void ProcessKeyboardViewModeChangeRegister(); void ProcessSetHighlightChangeRegister(); + void ProcessFollowParentRectRegister(); /* * Window Property @@ -409,6 +411,7 @@ private: void OnKeyboardStateChange(SessionState state, KeyboardViewMode mode); void OnKeyboardViewModeChange(KeyboardViewMode mode); void NotifyHighlightChange(bool isHighlight); + void NotifyFollowParentRect(bool isFollow); /* * Window Property diff --git a/window_scene/session/host/include/main_session.h b/window_scene/session/host/include/main_session.h index e4913e41a7..bc71377aef 100644 --- a/window_scene/session/host/include/main_session.h +++ b/window_scene/session/host/include/main_session.h @@ -85,6 +85,10 @@ private: NotifySessionLockStateChangeCallback onSessionLockStateChangeCallback_; bool isLockedState_ = false; + /* + * Window Layout + */ + void NotifySubAndDialogFollowRectChange(const WSRect& rect, bool isGlobal, bool needFlush) override; }; } // namespace OHOS::Rosen #endif // OHOS_ROSEN_WINDOW_SCENE_MAIN_SESSION_H diff --git a/window_scene/session/host/include/move_drag_controller.h b/window_scene/session/host/include/move_drag_controller.h index ac14886401..7e86ab82e5 100644 --- a/window_scene/session/host/include/move_drag_controller.h +++ b/window_scene/session/host/include/move_drag_controller.h @@ -92,7 +92,10 @@ public: void SetWindowDragHotAreaFunc(const NotifyWindowDragHotAreaFunc& func); void UpdateGravityWhenDrag(const std::shared_ptr& pointerEvent, const std::shared_ptr& surfaceNode); + void UpdateSubWindowGravityWhenFollow(const sptr& followedController, + const std::shared_ptr& surfaceNode); void OnLostFocus(); + AreaType GetAreaType() const { return type_; }; /* * Cross Display Move Drag diff --git a/window_scene/session/host/include/scene_session.h b/window_scene/session/host/include/scene_session.h index 76f83c687d..1039bc11df 100644 --- a/window_scene/session/host/include/scene_session.h +++ b/window_scene/session/host/include/scene_session.h @@ -115,6 +115,8 @@ using NotifySetSupportedWindowModesFunc = std::function&& supportedWindowModes)>; using GetStatusBarAvoidHeightFunc = std::function; using NotifySetWindowCornerRadiusFunc = std::function; +using NotifyFollowParentRectFunc = std::function; +using GetSceneSessionByIdCallback = std::function(int32_t sessionId)>; struct UIExtensionTokenInfo { bool canShowOnLockScreen { false }; @@ -148,6 +150,7 @@ public: PiPStateChangeCallback onPiPStateChange_; UpdateGestureBackEnabledCallback onUpdateGestureBackEnabled_; NotifyAvoidAreaChangeCallback onNotifyAvoidAreaChange_; + GetSceneSessionByIdCallback onGetSceneSessionByIdCallback_; }; // func for change window scene pattern property @@ -187,6 +190,7 @@ public: uint32_t& screenWidth, uint32_t& screenHeight); void NotifyTargetScreenWidthAndHeight(bool isScreenAngleMismatch, uint32_t screenWidth, uint32_t screenHeight); + sptr GetSceneSessionById(int32_t sessionId) const; WSError UpdateActiveStatus(bool isActive) override; WSError OnSessionEvent(SessionEvent event) override; @@ -220,6 +224,8 @@ public: WSError NotifyClientToUpdateRect(const std::string& updateReason, std::shared_ptr rsTransaction) override; void SetWinRectWhenUpdateRect(const WSRect& rect); + void RegisterNotifySurfaceBoundsChangeFunc(int32_t sessionId, NotifySurfaceBoundsChangeFunc&& func) override; + void UnregisterNotifySurfaceBoundsChangeFunc(int32_t sessionId) override; virtual void OpenKeyboardSyncTransaction() {} virtual void CloseKeyboardSyncTransaction(const WSRect& keyboardPanelRect, @@ -616,6 +622,9 @@ public: void SetBehindWindowFilterEnabled(bool enabled); // Only accessed on main thread WSError GetCrossAxisState(CrossAxisState& state) override; virtual void UpdateCrossAxis(); + bool GetIsFollowParentLayout() const { return isFollowParentLayout_; } + sptr GetMoveDragController() const { return moveDragController_; } + void NotifyUpdateGravity(); /* * Gesture Back @@ -649,7 +658,9 @@ public: */ bool IsSameMainSession(const sptr& prevSession); void SetHighlightChangeNotifyFunc(const NotifyHighlightChangeFunc& func); - + void SetFollowParentRectFunc(NotifyFollowParentRectFunc&& func); + WSError SetFollowParentWindowLayoutEnabled(bool isFollow) override; + /* * Window Property */ @@ -742,6 +753,12 @@ protected: */ NotifyDefaultDensityEnabledFunc onDefaultDensityEnabledFunc_; sptr moveDragController_ = nullptr; + std::mutex followParentRectFuncMutex_; + NotifyFollowParentRectFunc followParentRectFunc_ = nullptr; + std::mutex registerNotifySurfaceBoundsChangeMutex_; + std::unordered_map notifySurfaceBoundsChangeFuncMap_; + bool isFollowParentLayout_ = false; + virtual void NotifySessionRectChange(const WSRect& rect, SizeChangeReason reason = SizeChangeReason::UNDEFINED, DisplayId displayId = DISPLAY_ID_INVALID, const RectAnimationConfig& rectAnimationConfig = {}); @@ -1053,6 +1070,7 @@ private: void SetSurfaceBounds(const WSRect& rect, bool isGlobal, bool needFlush = true); virtual void UpdateCrossAxisOfLayout(const WSRect& rect); NotifyLayoutFullScreenChangeFunc onLayoutFullScreenChangeFunc_; + virtual void NotifySubAndDialogFollowRectChange(const WSRect& rect, bool isGlobal, bool needFlush) {}; std::atomic shouldFollowParentWhenShow_ = true; std::shared_ptr behindWindowFilterEnabledModifier_; // Only accessed on main thread diff --git a/window_scene/session/host/include/session.h b/window_scene/session/host/include/session.h index caf751ef9b..5ac3b49f28 100644 --- a/window_scene/session/host/include/session.h +++ b/window_scene/session/host/include/session.h @@ -97,6 +97,7 @@ using NofitySessionLabelAndIconUpdatedFunc = std::function& icon)>; using NotifyKeyboardStateChangeFunc = std::function; using NotifyHighlightChangeFunc = std::function; +using NotifySurfaceBoundsChangeFunc = std::function; class ILifecycleListener { public: @@ -609,6 +610,8 @@ public: void SetClientDisplayId(DisplayId displayId); DisplayId GetClientDisplayId() const; void UpdateDisplayIdByParentSession(DisplayId& updatedDisplayId); + virtual void RegisterNotifySurfaceBoundsChangeFunc(int32_t sessionId, NotifySurfaceBoundsChangeFunc&& func) {}; + virtual void UnregisterNotifySurfaceBoundsChangeFunc(int32_t sessionId) {}; /* * Screen Lock diff --git a/window_scene/session/host/include/zidl/session_interface.h b/window_scene/session/host/include/zidl/session_interface.h index 4aa350eb98..a89473dfb4 100644 --- a/window_scene/session/host/include/zidl/session_interface.h +++ b/window_scene/session/host/include/zidl/session_interface.h @@ -386,6 +386,7 @@ public: * @param registered true means register success. */ virtual void NotifyWindowAttachStateListenerRegistered(bool registered) { } + virtual WSError SetFollowParentWindowLayoutEnabled(bool isFollow) { return WSError::WS_OK; }; }; } // namespace OHOS::Rosen diff --git a/window_scene/session/host/include/zidl/session_ipc_interface_code.h b/window_scene/session/host/include/zidl/session_ipc_interface_code.h index 79bfb112c2..7bec1eb0e2 100644 --- a/window_scene/session/host/include/zidl/session_ipc_interface_code.h +++ b/window_scene/session/host/include/zidl/session_ipc_interface_code.h @@ -82,6 +82,7 @@ enum class SessionInterfaceCode { TRANS_ID_START_MOVING_WITH_COORDINATE, TRANS_ID_GET_CROSS_AXIS_STATE, TRANS_ID_CONTAINER_MODAL_EVENT, + TRANS_ID_SET_FOLLOW_PARENT_LAYOUT_ENABLED, // keyboard TRANS_ID_CHANGE_KEYBOARD_VIEW_MODE, diff --git a/window_scene/session/host/include/zidl/session_proxy.h b/window_scene/session/host/include/zidl/session_proxy.h index 7424f0175d..55e71c479c 100644 --- a/window_scene/session/host/include/zidl/session_proxy.h +++ b/window_scene/session/host/include/zidl/session_proxy.h @@ -150,6 +150,11 @@ public: */ void NotifyWindowAttachStateListenerRegistered(bool registered) override; + /** + * Window layout + */ + WSError SetFollowParentWindowLayoutEnabled(bool isFollow) override; + private: static inline BrokerDelegator delegator_; }; diff --git a/window_scene/session/host/include/zidl/session_stub.h b/window_scene/session/host/include/zidl/session_stub.h index 1ee034031b..1f5004d009 100644 --- a/window_scene/session/host/include/zidl/session_stub.h +++ b/window_scene/session/host/include/zidl/session_stub.h @@ -127,6 +127,8 @@ private: int HandleGetCrossAxisState(MessageParcel& data, MessageParcel& reply); int ProcessRemoteRequest(uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option); + + int HandleSetFollowParentWindowLayoutEnabled(MessageParcel& data, MessageParcel& reply); }; } // namespace OHOS::Rosen diff --git a/window_scene/session/host/src/main_session.cpp b/window_scene/session/host/src/main_session.cpp index 4149e7617b..6047aab854 100644 --- a/window_scene/session/host/src/main_session.cpp +++ b/window_scene/session/host/src/main_session.cpp @@ -357,6 +357,17 @@ void MainSession::RegisterSessionLockStateChangeCallback(NotifySessionLockStateC }, __func__); } +void MainSession::NotifySubAndDialogFollowRectChange(const WSRect& rect, bool isGlobal, bool needFlush) +{ + std::lock_guard lock(registerNotifySurfaceBoundsChangeMutex_); + for (const auto& [sessionId, func] : notifySurfaceBoundsChangeFuncMap_) { + auto subSession = GetSceneSessionById(sessionId); + if (subSession && subSession->GetIsFollowParentLayout() && func) { + func(rect, isGlobal, needFlush); + } + } +} + void MainSession::NotifySessionLockStateChange(bool isLockedState) { PostTask([weakThis = wptr(this), isLockedState] { diff --git a/window_scene/session/host/src/move_drag_controller.cpp b/window_scene/session/host/src/move_drag_controller.cpp index c8cec316d8..9ce73cc33c 100644 --- a/window_scene/session/host/src/move_drag_controller.cpp +++ b/window_scene/session/host/src/move_drag_controller.cpp @@ -194,6 +194,28 @@ WSRect MoveDragController::GetTargetRectByDisplayId(DisplayId displayId) const moveDragProperty_.targetRect_.height_}; } +void MoveDragController::UpdateSubWindowGravityWhenFollow(const sptr& followedController, + const std::shared_ptr& surfaceNode) +{ + if (surfaceNode == nullptr || followedController == nullptr) { + TLOGE(WmsLogTag::WMS_LAYOUT, "surfaceNode or followedController is null"); + return; + } + auto type = followedController->GetAreaType(); + if (type == AreaType::UNDEFINED) { + TLOGI(WmsLogTag::WMS_LAYOUT, "type undefined"); + return; + } + Gravity dragGravity = GRAVITY_MAP.at(type); + if (dragGravity >= Gravity::TOP && dragGravity <= Gravity::BOTTOM_RIGHT) { + TLOGI(WmsLogTag::WMS_LAYOUT, "begin SetFrameGravity when follow, gravity:%{public}d, type:%{public}d", + dragGravity, type); + surfaceNode->SetFrameGravity(dragGravity); + RSTransaction::FlushImplicitTransaction(); + } +} + + /** @note @window.drag */ void MoveDragController::InitMoveDragProperty() { diff --git a/window_scene/session/host/src/scene_session.cpp b/window_scene/session/host/src/scene_session.cpp index 0dccca35af..ebdae1d44f 100644 --- a/window_scene/session/host/src/scene_session.cpp +++ b/window_scene/session/host/src/scene_session.cpp @@ -2662,6 +2662,7 @@ WSError SceneSession::TransferPointerEventInner(const std::shared_ptrConsumeDragEvent(pointerEvent, winRect_, property, systemConfig_)) { auto surfaceNode = GetSurfaceNode(); moveDragController_->UpdateGravityWhenDrag(pointerEvent, surfaceNode); + NotifyUpdateGravity(); PresentFoucusIfNeed(pointerEvent->GetPointerAction()); pointerEvent->MarkProcessed(); return WSError::WS_OK; @@ -2700,6 +2701,22 @@ WSError SceneSession::TransferPointerEventInner(const std::shared_ptrGetIsFollowParentLayout()) { + return; + } + auto surfaceNode = subSession->GetSurfaceNode(); + auto subController = subSession->GetMoveDragController(); + if (subController && surfaceNode) { + subController->UpdateSubWindowGravityWhenFollow(moveDragController_, surfaceNode); + } + } +} + void SceneSession::ProcessWindowMoving(const std::shared_ptr& pointerEvent) { if (pointerEvent->GetPointerAction() != MMI::PointerEvent::POINTER_ACTION_MOVE) { @@ -3326,8 +3343,10 @@ void SceneSession::OnMoveDragCallback(SizeChangeReason reason) HandleMoveDragSurfaceBounds(relativeRect, globalRect, reason); if (reason == SizeChangeReason::DRAG_END) { HandleMoveDragEnd(relativeRect, reason); + SetUIFirstSwitch(RSUIFirstSwitch::NONE); } else if (reason == SizeChangeReason::DRAG_START) { OnSessionEvent(SessionEvent::EVENT_DRAG_START); + SetUIFirstSwitch(RSUIFirstSwitch::FORCE_DISABLE); } } @@ -3472,6 +3491,7 @@ void SceneSession::SetSurfaceBounds(const WSRect& rect, bool isGlobal, bool need } auto surfaceNode = GetSurfaceNode(); auto leashWinSurfaceNode = GetLeashWinSurfaceNode(); + NotifySubAndDialogFollowRectChange(rect, isGlobal, needFlush); if (surfaceNode && leashWinSurfaceNode) { leashWinSurfaceNode->SetGlobalPositionEnabled(isGlobal); leashWinSurfaceNode->SetBounds(rect.posX_, rect.posY_, rect.width_, rect.height_); @@ -6170,6 +6190,91 @@ void SceneSession::SetHighlightChangeNotifyFunc(const NotifyHighlightChangeFunc& highlightChangeFunc_ = func; } +void SceneSession::RegisterNotifySurfaceBoundsChangeFunc(int32_t sessionId, NotifySurfaceBoundsChangeFunc&& func) +{ + std::lock_guard lock(registerNotifySurfaceBoundsChangeMutex_); + if (!func) { + TLOGE(WmsLogTag::WMS_SUB, "func is null"); + return; + } + notifySurfaceBoundsChangeFuncMap_[sessionId] = func; +} + +void SceneSession::UnregisterNotifySurfaceBoundsChangeFunc(int32_t sessionId) +{ + std::lock_guard lock(registerNotifySurfaceBoundsChangeMutex_); + notifySurfaceBoundsChangeFuncMap_.erase(sessionId); +} + +sptr SceneSession::GetSceneSessionById(int32_t sessionId) const +{ + if (specificCallback_ == nullptr || specificCallback_->onGetSceneSessionByIdCallback_ == nullptr) { + TLOGE(WmsLogTag::WMS_LAYOUT, "specificCallback or onGetSceneSessionByIdCallback is null"); + return nullptr; + } + return specificCallback_->onGetSceneSessionByIdCallback_(sessionId); +} + +void SceneSession::SetFollowParentRectFunc(NotifyFollowParentRectFunc&& func) +{ + if (!func) { + TLOGW(WmsLogTag::WMS_SUB, "func is null"); + return; + } + func(isFollowParentLayout_); + std::lock_guard lock(followParentRectFuncMutex_); + followParentRectFunc_ = func; +} + +WSError SceneSession::SetFollowParentWindowLayoutEnabled(bool isFollow) +{ + auto property = GetSessionProperty(); + if (!property) { + TLOGE(WmsLogTag::WMS_SUB, "property is null"); + return WSError::WS_ERROR_INVALID_OPERATION; + } + // only support sub window and dialog + if (!WindowHelper::IsSubWindow(property->GetWindowType()) && + !WindowHelper::IsDialogWindow(property->GetWindowType())) { + TLOGE(WmsLogTag::WMS_SUB, "only sub window and dialog is valid"); + return WSError::WS_ERROR_INVALID_OPERATION; + } + // only support first level window + if (property->GetSubWindowLevel() > 1) { + TLOGW(WmsLogTag::WMS_SUB, "not surppot more than 1 level window"); + return WSError::WS_ERROR_INVALID_OPERATION; + } + isFollowParentLayout_ = isFollow; + { + std::lock_guard lock(followParentRectFuncMutex_); + if (!followParentRectFunc_) { + TLOGW(WmsLogTag::WMS_SUB, "func is null"); + return WSError::WS_ERROR_INVALID_OPERATION; + } + followParentRectFunc_(isFollow); + } + + // if parent is null, don't need follow move drag + if (!parentSession_) { + TLOGW(WmsLogTag::WMS_SUB, "parent is null"); + return WSError::WS_OK; + } + if (!isFollow) { + parentSession_->UnregisterNotifySurfaceBoundsChangeFunc(GetPersistentId()); + return WSError::WS_OK; + } + auto task = [weak = wptr(this)](const WSRect& rect, bool isGlobal, bool needFlush) { + auto session = weak.promote(); + if (!session) { + TLOGNE(WmsLogTag::WMS_SUB, "session has been destroy"); + return; + } + session->SetSurfaceBounds(rect, isGlobal, needFlush); + }; + parentSession_->RegisterNotifySurfaceBoundsChangeFunc(GetPersistentId(), std::move(task)); + return WSError::WS_OK; +} + int32_t SceneSession::GetStatusBarHeight() { int32_t height = 0; diff --git a/window_scene/session/host/src/zidl/session_proxy.cpp b/window_scene/session/host/src/zidl/session_proxy.cpp index fc203cd449..75616864ec 100644 --- a/window_scene/session/host/src/zidl/session_proxy.cpp +++ b/window_scene/session/host/src/zidl/session_proxy.cpp @@ -2412,6 +2412,38 @@ WSError SessionProxy::SetWindowCornerRadius(float cornerRadius) return WSError::WS_OK; } +WSError SessionProxy::SetFollowParentWindowLayoutEnabled(bool isFollow) +{ + TLOGD(WmsLogTag::WMS_SUB, "isFollow: %{public}d", isFollow); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_ASYNC); + if (!data.WriteInterfaceToken(GetDescriptor())) { + TLOGE(WmsLogTag::WMS_SUB, "WriteInterfaceToken failed"); + return WSError::WS_ERROR_IPC_FAILED; + } + if (!data.WriteBool(isFollow)) { + TLOGE(WmsLogTag::WMS_SUB, "Write enable failed"); + return WSError::WS_ERROR_IPC_FAILED; + } + sptr remote = Remote(); + if (remote == nullptr) { + TLOGE(WmsLogTag::WMS_SUB, "remote is null"); + return WSError::WS_ERROR_IPC_FAILED; + } + if (remote->SendRequest(static_cast(SessionInterfaceCode::TRANS_ID_SET_FOLLOW_PARENT_LAYOUT_ENABLED), + data, reply, option) != ERR_NONE) { + TLOGE(WmsLogTag::WMS_SUB, "SendRequest failed"); + return WSError::WS_ERROR_IPC_FAILED; + } + int32_t ret = 0; + if (!reply.ReadInt32(ret)) { + TLOGE(WmsLogTag::WMS_MAIN, "read ret failed"); + return WSError::WS_ERROR_IPC_FAILED; + } + return static_cast(ret); +} + WSError SessionProxy::StartMovingWithCoordinate(int32_t offsetX, int32_t offsetY, int32_t pointerPosX, int32_t pointerPosY) { diff --git a/window_scene/session/host/src/zidl/session_stub.cpp b/window_scene/session/host/src/zidl/session_stub.cpp index 77ca1968b1..97e86d9160 100644 --- a/window_scene/session/host/src/zidl/session_stub.cpp +++ b/window_scene/session/host/src/zidl/session_stub.cpp @@ -248,6 +248,8 @@ int SessionStub::ProcessRemoteRequest(uint32_t code, MessageParcel& data, Messag return HandleContainerModalEvent(data, reply); case static_cast(SessionInterfaceCode::TRANS_ID_NOTIFY_WINDOW_ATTACH_STATE_LISTENER_REGISTERED): return HandleNotifyWindowAttachStateListenerRegistered(data, reply); + case static_cast(SessionInterfaceCode::TRANS_ID_SET_FOLLOW_PARENT_LAYOUT_ENABLED): + return HandleSetFollowParentWindowLayoutEnabled(data, reply); default: WLOGFE("Failed to find function handler!"); return IPCObjectStub::OnRemoteRequest(code, data, reply, option); @@ -1489,6 +1491,22 @@ int SessionStub::HandleSetWindowCornerRadius(MessageParcel& data, MessageParcel& return ERR_NONE; } +int SessionStub::HandleSetFollowParentWindowLayoutEnabled(MessageParcel& data, MessageParcel& reply) +{ + bool isFollow = false; + if (!data.ReadBool(isFollow)) { + TLOGE(WmsLogTag::WMS_ATTRIBUTE, "Read cornerRadius failed."); + return ERR_INVALID_DATA; + } + TLOGD(WmsLogTag::WMS_SUB, "isFollow: %{public}d", isFollow); + WSError errCode = SetFollowParentWindowLayoutEnabled(isFollow); + if (!reply.WriteInt32(static_cast(errCode))) { + TLOGE(WmsLogTag::WMS_MAIN, "write errCode fail."); + return ERR_INVALID_DATA; + } + return ERR_NONE; +} + int SessionStub::HandleStartMovingWithCoordinate(MessageParcel& data, MessageParcel& reply) { int32_t offsetX; diff --git a/window_scene/session_manager/src/scene_session_manager.cpp b/window_scene/session_manager/src/scene_session_manager.cpp index e7339c99fa..8bdc8ab605 100644 --- a/window_scene/session_manager/src/scene_session_manager.cpp +++ b/window_scene/session_manager/src/scene_session_manager.cpp @@ -1578,6 +1578,9 @@ sptr SceneSessionManager::CreateSpecificS specificCb->onUpdateGestureBackEnabled_ = [this](int32_t persistentId) { this->UpdateGestureBackEnabled(persistentId); }; + specificCb->onGetSceneSessionByIdCallback_ = [this](int32_t persistentId) { + return this->GetSceneSession(persistentId); + }; return specificCb; } @@ -3881,6 +3884,7 @@ WSError SceneSessionManager::DestroyAndDisconnectSpecificSessionInner(const int3 TLOGE(WmsLogTag::WMS_DIALOG, "Dialog not bind parent"); } else { parentSession->RemoveDialogToParentSession(sceneSession); + parentSession->UnregisterNotifySurfaceBoundsChangeFunc(persistentId); } } else if (windowType == WindowType::WINDOW_TYPE_TOAST) { auto parentSession = GetSceneSession(sceneSession->GetParentPersistentId()); @@ -3901,6 +3905,7 @@ WSError SceneSessionManager::DestroyAndDisconnectSpecificSessionInner(const int3 if (parentSession != nullptr) { TLOGD(WmsLogTag::WMS_SUB, "Find parentSession, id: %{public}d", persistentId); parentSession->RemoveSubSession(sceneSession->GetPersistentId()); + parentSession->UnregisterNotifySurfaceBoundsChangeFunc(persistentId); } else { TLOGW(WmsLogTag::WMS_SUB, "ParentSession is nullptr, id: %{public}d", persistentId); } diff --git a/wm/include/window_scene_session_impl.h b/wm/include/window_scene_session_impl.h index d4e4b37b9a..82374a2c1f 100644 --- a/wm/include/window_scene_session_impl.h +++ b/wm/include/window_scene_session_impl.h @@ -53,6 +53,7 @@ public: const RectAnimationConfig& rectAnimationConfig = {}) override; WMError ResizeAsync(uint32_t width, uint32_t height, const RectAnimationConfig& rectAnimationConfig = {}) override; + WMError SetFollowParentWindowLayoutEnabled(bool isFollow) override; WMError RaiseToAppTop() override; WMError RaiseAboveTarget(int32_t subWindowId) override; diff --git a/wm/src/window_scene_session_impl.cpp b/wm/src/window_scene_session_impl.cpp index ede12aa3b0..144b8fcaae 100644 --- a/wm/src/window_scene_session_impl.cpp +++ b/wm/src/window_scene_session_impl.cpp @@ -5231,6 +5231,25 @@ float WindowSceneSessionImpl::GetCustomDensity() const return customDensity_; } +WMError WindowSceneSessionImpl::SetFollowParentWindowLayoutEnabled(bool isFollow) +{ + if (IsWindowSessionInvalid()) { + return WMError::WM_ERROR_INVALID_WINDOW; + } + const auto& property = GetProperty(); + if (!WindowHelper::IsSubWindow(property->GetWindowType()) && + !WindowHelper::IsDialogWindow(property->GetWindowType())) { + TLOGE(WmsLogTag::WMS_SUB, "only sub window and dialog is valid"); + return WMError::WM_ERROR_INVALID_OPERATION; + } + if (property->GetSubWindowLevel() > 1) { + TLOGI(WmsLogTag::WMS_SUB, "not support more than 1 level window"); + return WMError::WM_ERROR_INVALID_OPERATION; + } + WSError ret = GetHostSession()->SetFollowParentWindowLayoutEnabled(isFollow); + return ret != WSError::WS_OK ? WMError::WM_ERROR_SYSTEM_ABNORMALLY : WMError::WM_OK; +} + WMError WindowSceneSessionImpl::SetCustomDensity(float density) { TLOGI(WmsLogTag::WMS_ATTRIBUTE, "winId=%{public}u, density=%{public}f", GetWindowId(), density); -- Gitee