diff --git a/interfaces/innerkits/wm/window.h b/interfaces/innerkits/wm/window.h index 478e0d23d648b1c7a119e4bf1f846d931369f5f1..7bd570f89dd8c647efbca494c95bb625fc46c038 100644 --- a/interfaces/innerkits/wm/window.h +++ b/interfaces/innerkits/wm/window.h @@ -2736,6 +2736,17 @@ public: */ virtual WMError SetAspectRatio(float ratio) { return WMError::WM_OK; } + /** + * @brief Set content aspect ratio of the window. + * + * @param ratio The aspect ratio of window content (width divided by height). + * @param isPersistent Whether to persist the aspect ratio setting. + * @param needUpdateRect Whether to update the window rect after setting aspect ratio. + * @return WMError::WM_OK on success, or appropriate error code on failure. + */ + virtual WMError SetContentAspectRatio( + float ratio, bool isPersistent, bool needUpdateRect) { return WMError::WM_ERROR_DEVICE_NOT_SUPPORT; } + /** * @brief Unset aspect ratio * @return WMError diff --git a/interfaces/innerkits/wm/wm_common.h b/interfaces/innerkits/wm/wm_common.h index 0e344de1817067dfe914b267d15fe7fd05528ac1..b30289913fc255606fbdd729b968ece2d325599d 100644 --- a/interfaces/innerkits/wm/wm_common.h +++ b/interfaces/innerkits/wm/wm_common.h @@ -458,7 +458,15 @@ enum class WindowUIType : uint8_t { * @brief Used to map from WMError to WmErrorCode. */ extern const std::map WM_JS_TO_ERROR_CODE_MAP; -WmErrorCode ConvertErrorToCode(WMError error); + +/** + * @brief Convert WMError to corresponding WmErrorCode. + * + * @param error WMError value to convert. + * @param defaultCode Value to return if mapping is not found. + * @return Corresponding WmErrorCode or defaultCode if unmapped. + */ +WmErrorCode ConvertErrorToCode(WMError error, WmErrorCode defaultCode = WmErrorCode::WM_ERROR_STATE_ABNORMALLY); /** * @brief Enumerates flag of window. @@ -1778,11 +1786,40 @@ struct WindowLimits { float minRatio, float vpRatio) : maxWidth_(maxWidth), maxHeight_(maxHeight), minWidth_(minWidth), minHeight_(minHeight), maxRatio_(maxRatio), minRatio_(minRatio), vpRatio_(vpRatio) {} + void Clip(uint32_t clipWidth, uint32_t clipHeight) + { + auto safeSub = [](uint32_t base, uint32_t dec) -> uint32_t { + return (dec >= base) ? 0 : base - dec; + }; + + minWidth_ = safeSub(minWidth_, clipWidth); + maxWidth_ = safeSub(maxWidth_, clipWidth); + minHeight_ = safeSub(minHeight_, clipHeight); + maxHeight_ = safeSub(maxHeight_, clipHeight); + } + + void Expand(uint32_t expandWidth, uint32_t expandHeight) + { + auto safeAdd = [](uint32_t base, uint32_t inc) -> uint32_t { + return (base > UINT32_MAX - inc) ? UINT32_MAX : base + inc; + }; + + minWidth_ = safeAdd(minWidth_, expandWidth); + maxWidth_ = safeAdd(maxWidth_, expandWidth); + minHeight_ = safeAdd(minHeight_, expandHeight); + maxHeight_ = safeAdd(maxHeight_, expandHeight); + } + bool IsEmpty() const { return (maxWidth_ == 0 || minWidth_ == 0 || maxHeight_ == 0 || minHeight_ == 0); } + bool IsValid() const + { + return minWidth_ <= maxWidth_ && minHeight_ <= maxHeight_; + } + std::string ToString() const { constexpr int precision = 6; diff --git a/interfaces/kits/ani/window_runtime/window_stage_ani/ets/@ohos.window.ets b/interfaces/kits/ani/window_runtime/window_stage_ani/ets/@ohos.window.ets index 96aa154a67dc8969dcabda642a3d96700550da38..f5ee1725c6faa4eb95f9b4a5a45042d775cce86f 100644 --- a/interfaces/kits/ani/window_runtime/window_stage_ani/ets/@ohos.window.ets +++ b/interfaces/kits/ani/window_runtime/window_stage_ani/ets/@ohos.window.ets @@ -1260,6 +1260,8 @@ export class WindowInternal implements Window { private native getUIContextSync(nativeObj: long): UIContext; private native getWindowAvoidAreaSync(nativeObj: long, type: int): AvoidArea; private native setWaterMarkFlagSync(nativeObj: long, enable: boolean): void; + private native setContentAspectRatio( + nativeObj: long, ratio: number, isPersistent: boolean, needUpdateRect: boolean): void; private native onSync(nativeObj: long, type: string, callback: object): void; private native offSync(nativeObj: long, type: string, callback?: object): void; @@ -1684,6 +1686,19 @@ export class WindowInternal implements Window { }); } + public setContentAspectRatio(ratio: number, isPersistent?: boolean, needUpdateRect?: boolean): Promise { + return new Promise( + (resolve: (value: undefined) => void, reject: (error: BusinessError) => void ): void => { + taskpool.execute((): void => { + this.setContentAspectRatio(this.nativeObj, ratio, isPersistent ?? true, needUpdateRect ?? true); + }).then((ret: NullishType) => { + resolve(undefined); + }).catch((err: NullishType) => { + reject(err as BusinessError); + }); + }); + } + public on(type: string, callback: Callback): void { this.onSync(this.nativeObj, type, callback); } @@ -1737,6 +1752,7 @@ export interface Window { getWindowAvoidArea(type: AvoidAreaType): AvoidArea; setWaterMarkFlag(enable: boolean): Promise; setWaterMarkFlag(enable: boolean, callback: AsyncCallback): void; + setContentAspectRatio(ratio: number, isPersistent?: boolean, needUpdateRect?: boolean): Promise; on(type: string, callback: Callback): void; off(type: string, callback?: Callback): void; } diff --git a/interfaces/kits/ani/window_runtime/window_stage_ani/include/ani_window.h b/interfaces/kits/ani/window_runtime/window_stage_ani/include/ani_window.h index 35d74384a2ce789189de1f3da9edce1955234d48..3ce56923322fd1756f82794e1193678545d2c34e 100644 --- a/interfaces/kits/ani/window_runtime/window_stage_ani/include/ani_window.h +++ b/interfaces/kits/ani/window_runtime/window_stage_ani/include/ani_window.h @@ -57,6 +57,8 @@ public: static void UnregisterWindowCallback(ani_env* env, ani_object obj, ani_long nativeObj, ani_string type, ani_ref callback); static void Finalizer(ani_env* env, ani_long nativeObj); + static void SetContentAspectRatio(ani_env* env, ani_object obj, ani_long nativeObj, + ani_double ratio, ani_boolean isPersistent, ani_boolean needUpdateRect); /* * Window Layout @@ -99,6 +101,12 @@ private: WMError SetSystemBarPropertiesByFlags(std::map& systemBarPropertyFlags, std::map& systemBarProperties, sptr windowToken); + /* + * Window Layout + */ + void OnSetContentAspectRatio( + ani_env* env, ani_double ratio, ani_boolean isPersistent, ani_boolean needUpdateRect); + sptr windowToken_ = nullptr; std::unique_ptr registerManager_ = nullptr; ani_ref aniRef_ = nullptr; diff --git a/interfaces/kits/ani/window_runtime/window_stage_ani/include/ani_window_utils.h b/interfaces/kits/ani/window_runtime/window_stage_ani/include/ani_window_utils.h index adccd25237afb764df6478f64523c4a50cce6e9d..d3d189539619b18efb13f9917c3002111a911540 100644 --- a/interfaces/kits/ani/window_runtime/window_stage_ani/include/ani_window_utils.h +++ b/interfaces/kits/ani/window_runtime/window_stage_ani/include/ani_window_utils.h @@ -317,7 +317,7 @@ public: std::map& systemBarProperties); /** - * @brief Convert a WMError to its corresponding WmErrorCode. + * @brief Convert WMError to corresponding WmErrorCode. * * If the WMError is not found in the mapping, returns the given default code. * diff --git a/interfaces/kits/ani/window_runtime/window_stage_ani/src/ani_window.cpp b/interfaces/kits/ani/window_runtime/window_stage_ani/src/ani_window.cpp index ea58e53f032f6bb93acdfa9508a2d2ad5a2df31f..32fefff3565d92371b7e064ba96e6ea05a1f2833 100644 --- a/interfaces/kits/ani/window_runtime/window_stage_ani/src/ani_window.cpp +++ b/interfaces/kits/ani/window_runtime/window_stage_ani/src/ani_window.cpp @@ -887,6 +887,37 @@ void AniWindow::Finalizer(ani_env* env, ani_long nativeObj) TLOGE(WmsLogTag::DEFAULT, "[ANI] aniWindow is nullptr"); } } + +void AniWindow::SetContentAspectRatio(ani_env* env, ani_object obj, ani_long nativeObj, + ani_double ratio, ani_boolean isPersistent, ani_boolean needUpdateRect) +{ + TLOGD(WmsLogTag::WMS_LAYOUT, "[ANI]"); + AniWindow* aniWindow = reinterpret_cast(nativeObj); + if (!aniWindow) { + TLOGE(WmsLogTag::WMS_LAYOUT, "[ANI] aniWindow is nullptr"); + AniWindowUtils::AniThrowError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY); + return; + } + aniWindow->OnSetContentAspectRatio(env, ratio, isPersistent, needUpdateRect); +} + +void AniWindow::OnSetContentAspectRatio( + ani_env* env, ani_double ratio, ani_boolean isPersistent, ani_boolean needUpdateRect) +{ + if (!windowToken_) { + TLOGE(WmsLogTag::WMS_LAYOUT, "[ANI] window is nullptr"); + AniWindowUtils::AniThrowError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY); + return; + } + WMError ret = windowToken_->SetContentAspectRatio( + static_cast(ratio), static_cast(isPersistent), static_cast(needUpdateRect)); + if (ret != WMError::WM_OK) { + TLOGE(WmsLogTag::WMS_LAYOUT, "[ANI] failed, windowId: %{public}u, ret: %{public}d", + windowToken_->GetWindowId(), static_cast(ret)); + AniWindowUtils::AniThrowError(env, AniWindowUtils::ToErrorCode(ret)); + return; + } +} } // namespace Rosen } // namespace OHOS @@ -1196,6 +1227,8 @@ ani_status OHOS::Rosen::ANI_Window_Constructor(ani_vm *vm, uint32_t *result) reinterpret_cast(AniWindow::GetWindowAvoidArea)}, ani_native_function {"setWaterMarkFlagSync", "JZ:V", reinterpret_cast(AniWindow::SetWaterMarkFlag)}, + ani_native_function {"setContentAspectRatio", "JDZZ:V", + reinterpret_cast(AniWindow::SetContentAspectRatio)}, ani_native_function {"onSync", nullptr, reinterpret_cast(AniWindow::RegisterWindowCallback)}, ani_native_function {"offSync", nullptr, 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 4f732392937be2eb9b51790d0ea39d564621f86d..3852147cc2197794b0a42a42c842605bf2cea61a 100644 --- a/interfaces/kits/napi/window_runtime/window_napi/js_window.cpp +++ b/interfaces/kits/napi/window_runtime/window_napi/js_window.cpp @@ -875,14 +875,21 @@ napi_value JsWindow::SetHandwritingFlag(napi_env env, napi_callback_info info) napi_value JsWindow::SetAspectRatio(napi_env env, napi_callback_info info) { - TLOGD(WmsLogTag::DEFAULT, "[NAPI]"); + TLOGD(WmsLogTag::WMS_LAYOUT, "[NAPI]"); JsWindow* me = CheckParamsAndGetThis(env, info); return (me != nullptr) ? me->OnSetAspectRatio(env, info) : nullptr; } +napi_value JsWindow::SetContentAspectRatio(napi_env env, napi_callback_info info) +{ + TLOGD(WmsLogTag::WMS_LAYOUT, "[NAPI]"); + JsWindow* me = CheckParamsAndGetThis(env, info); + return (me != nullptr) ? me->OnSetContentAspectRatio(env, info) : nullptr; +} + napi_value JsWindow::ResetAspectRatio(napi_env env, napi_callback_info info) { - TLOGD(WmsLogTag::DEFAULT, "[NAPI]"); + TLOGD(WmsLogTag::WMS_LAYOUT, "[NAPI]"); JsWindow* me = CheckParamsAndGetThis(env, info); return (me != nullptr) ? me->OnResetAspectRatio(env, info) : nullptr; } @@ -1287,6 +1294,16 @@ napi_valuetype GetType(napi_env env, napi_value value) return res; } +template +bool ConvertFromOptionalJsValue(napi_env env, napi_value jsValue, T& value, const T& defaultValue) +{ + if (GetType(env, jsValue) == napi_undefined) { + value = defaultValue; + return true; + } + return ConvertFromJsValue(env, jsValue, value); +} + napi_value JsWindow::OnShow(napi_env env, napi_callback_info info) { WMError errCode = WMError::WM_OK; @@ -6915,6 +6932,63 @@ napi_value JsWindow::OnResetAspectRatio(napi_env env, napi_callback_info info) return result; } +napi_value JsWindow::OnSetContentAspectRatio(napi_env env, napi_callback_info info) +{ + const std::string errMsgPrefix = "[window][setContentAspectRatio]msg: "; + auto logAndThrowError = [env, where = __func__, errMsgPrefix](WmErrorCode code, const std::string& msg) { + TLOGNE(WmsLogTag::WMS_LAYOUT, "%{public}s: %{public}s", where, msg.c_str()); + return NapiThrowError(env, code, errMsgPrefix + msg); + }; + + size_t argc = THREE_PARAMS_SIZE; + napi_value argv[THREE_PARAMS_SIZE] = {nullptr}; + napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); + if (argc < ONE_PARAMS_SIZE || argc > THREE_PARAMS_SIZE) { + return logAndThrowError(WmErrorCode::WM_ERROR_INVALID_PARAM, "Number of parameters is invalid"); + } + + double aspectRatio = 0.0; + if (!ConvertFromJsValue(env, argv[INDEX_ZERO], aspectRatio)) { + return logAndThrowError(WmErrorCode::WM_ERROR_INVALID_PARAM, "Failed to convert parameter to aspectRatio"); + } + + bool isPersistent = true; + if (argc >= TWO_PARAMS_SIZE && !ConvertFromOptionalJsValue(env, argv[INDEX_ONE], isPersistent, true)) { + return logAndThrowError(WmErrorCode::WM_ERROR_INVALID_PARAM, "Failed to convert parameter to isPersistent"); + } + + bool needUpdateRect = true; + if (argc == THREE_PARAMS_SIZE && !ConvertFromOptionalJsValue(env, argv[INDEX_TWO], needUpdateRect, true)) { + return logAndThrowError(WmErrorCode::WM_ERROR_INVALID_PARAM, "Failed to convert parameter to needUpdateRect"); + } + + napi_value result = nullptr; + std::shared_ptr napiAsyncTask = CreateEmptyAsyncTask(env, nullptr, &result); + auto asyncTask = [windowToken = wptr(windowToken_), aspectRatio, isPersistent, needUpdateRect, + env, napiAsyncTask, where = __func__, errMsgPrefix] { + auto window = windowToken.promote(); + if (!window) { + TLOGNE(WmsLogTag::WMS_LAYOUT, "%{public}s: Window is nullptr", where); + napiAsyncTask->Reject(env, JsErrUtils::CreateJsError( + env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY, errMsgPrefix + "Window is nullptr")); + return; + } + WMError ret = window->SetContentAspectRatio(aspectRatio, isPersistent, needUpdateRect); + auto it = WM_JS_TO_ERROR_CODE_MAP.find(ret); + WmErrorCode code = (it != WM_JS_TO_ERROR_CODE_MAP.end()) ? it->second : WmErrorCode::WM_ERROR_STATE_ABNORMALLY; + if (code == WmErrorCode::WM_OK) { + napiAsyncTask->Resolve(env, NapiGetUndefined(env)); + } else { + napiAsyncTask->Reject(env, JsErrUtils::CreateJsError(env, code, errMsgPrefix + "Failed")); + } + }; + if (napi_send_event(env, asyncTask, napi_eprio_high, __func__) != napi_status::napi_ok) { + napiAsyncTask->Reject(env, JsErrUtils::CreateJsError( + env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY, errMsgPrefix + "Failed to send event")); + } + return result; +} + napi_value JsWindow::OnMinimize(napi_env env, napi_callback_info info) { size_t argc = FOUR_PARAMS_SIZE; @@ -9241,6 +9315,7 @@ void BindFunctions(napi_env env, napi_value object, const char* moduleName) BindNativeFunction(env, object, "setBackdropBlur", moduleName, JsWindow::SetBackdropBlur); BindNativeFunction(env, object, "setBackdropBlurStyle", moduleName, JsWindow::SetBackdropBlurStyle); BindNativeFunction(env, object, "setAspectRatio", moduleName, JsWindow::SetAspectRatio); + BindNativeFunction(env, object, "setContentAspectRatio", moduleName, JsWindow::SetContentAspectRatio); BindNativeFunction(env, object, "resetAspectRatio", moduleName, JsWindow::ResetAspectRatio); BindNativeFunction(env, object, "setWaterMarkFlag", moduleName, JsWindow::SetWaterMarkFlag); BindNativeFunction(env, object, "setHandwritingFlag", moduleName, JsWindow::SetHandwritingFlag); 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 ca07a5636d34a0c29a1c83e1f1e1147d73695661..4a649e3f56b636ad4920cfcf1289b8e7c8f44b15 100644 --- a/interfaces/kits/napi/window_runtime/window_napi/js_window.h +++ b/interfaces/kits/napi/window_runtime/window_napi/js_window.h @@ -114,6 +114,7 @@ public: static napi_value SetSnapshotSkip(napi_env env, napi_callback_info info); static napi_value RaiseToAppTop(napi_env env, napi_callback_info info); static napi_value SetAspectRatio(napi_env env, napi_callback_info info); + static napi_value SetContentAspectRatio(napi_env env, napi_callback_info info); static napi_value ResetAspectRatio(napi_env env, napi_callback_info info); static napi_value Minimize(napi_env env, napi_callback_info info); static napi_value RaiseAboveTarget(napi_env env, napi_callback_info info); @@ -305,6 +306,7 @@ private: napi_value OnGetPreferredOrientation(napi_env env, napi_callback_info info); napi_value OnRaiseToAppTop(napi_env env, napi_callback_info info); napi_value OnSetAspectRatio(napi_env env, napi_callback_info info); + napi_value OnSetContentAspectRatio(napi_env env, napi_callback_info info); napi_value OnResetAspectRatio(napi_env env, napi_callback_info info); napi_value OnMinimize(napi_env env, napi_callback_info info); WmErrorCode CheckRaiseMainWindowParams(napi_env env, size_t argc, napi_value argv[], diff --git a/previewer/include/window.h b/previewer/include/window.h index 8d23c8ea8b53d6e1e2d6e9bcd9641a3ff7376238..04fc5a30f524be235ce6ea7e26895f53450142a5 100644 --- a/previewer/include/window.h +++ b/previewer/include/window.h @@ -419,6 +419,18 @@ public: virtual WMError NotifyMemoryLevel(int32_t level) = 0; virtual bool IsAllowHaveSystemSubWindow() = 0; virtual WMError SetAspectRatio(float ratio) = 0; + + /** + * @brief Set content aspect ratio of the window. + * + * @param ratio The aspect ratio of window content (width divided by height). + * @param isPersistent Whether to persist the aspect ratio setting. + * @param needUpdateRect Whether to update the window rect after setting aspect ratio. + * @return WMError::WM_OK on success, or appropriate error code on failure. + */ + virtual WMError SetContentAspectRatio( + float ratio, bool isPersistent, bool needUpdateRect) { return WMError::WM_ERROR_DEVICE_NOT_SUPPORT; } + virtual WMError ResetAspectRatio() = 0; virtual KeyboardAnimationConfig GetKeyboardAnimationConfig() = 0; virtual void SetNeedDefaultAnimation(bool needDefaultAnimation) = 0; diff --git a/previewer/include/wm_common.h b/previewer/include/wm_common.h index 24a96d4f749594f4f722d6610bf6542ed686200b..098e4f050188a0c7e4d9c71da112600a5245c5c6 100644 --- a/previewer/include/wm_common.h +++ b/previewer/include/wm_common.h @@ -1097,11 +1097,40 @@ struct WindowLimits { float minRatio, float vpRatio) : maxWidth_(maxWidth), maxHeight_(maxHeight), minWidth_(minWidth), minHeight_(minHeight), maxRatio_(maxRatio), minRatio_(minRatio), vpRatio_(vpRatio) {} + void Clip(uint32_t clipWidth, uint32_t clipHeight) + { + auto safeSub = [](uint32_t base, uint32_t dec) -> uint32_t { + return (dec >= base) ? 0 : base - dec; + }; + + minWidth_ = safeSub(minWidth_, clipWidth); + maxWidth_ = safeSub(maxWidth_, clipWidth); + minHeight_ = safeSub(minHeight_, clipHeight); + maxHeight_ = safeSub(maxHeight_, clipHeight); + } + + void Expand(uint32_t expandWidth, uint32_t expandHeight) + { + auto safeAdd = [](uint32_t base, uint32_t inc) -> uint32_t { + return (base > UINT32_MAX - inc) ? UINT32_MAX : base + inc; + }; + + minWidth_ = safeAdd(minWidth_, expandWidth); + maxWidth_ = safeAdd(maxWidth_, expandWidth); + minHeight_ = safeAdd(minHeight_, expandHeight); + maxHeight_ = safeAdd(maxHeight_, expandHeight); + } + bool IsEmpty() const { return (maxHeight_ == 0 || minHeight_ == 0 || maxWidth_ == 0 || minWidth_ == 0); } + bool IsValid() const + { + return minWidth_ <= maxWidth_ && minHeight_ <= maxHeight_; + } + std::string ToString() const { constexpr int precision = 6; diff --git a/utils/src/wm_common.cpp b/utils/src/wm_common.cpp index 0d469bd18385a1f2ffb7824cbf23cfda81bdaf3a..4e46252b4ccf8b823f1b0ddc0f3b6a34551d4140 100644 --- a/utils/src/wm_common.cpp +++ b/utils/src/wm_common.cpp @@ -62,13 +62,15 @@ const std::map WM_JS_TO_ERROR_CODE_MAP { {WMError::WM_ERROR_UI_EFFECT_ERROR, WmErrorCode::WM_ERROR_UI_EFFECT_ERROR }, }; -WmErrorCode ConvertErrorToCode(WMError error) +WmErrorCode ConvertErrorToCode(WMError error, WmErrorCode defaultCode) { auto iter = WM_JS_TO_ERROR_CODE_MAP.find(error); if (iter != WM_JS_TO_ERROR_CODE_MAP.end()) { return iter->second; } - TLOGE(WmsLogTag::DEFAULT, "not find error::%{public}d", static_cast(error)); - return WmErrorCode::WM_ERROR_SYSTEM_ABNORMALLY; + TLOGE(WmsLogTag::DEFAULT, + "No mapping found for WMError: %{public}d, fallback to default WmErrorCode: %{public}d", + static_cast(error), static_cast(defaultCode)); + return defaultCode; } } \ No newline at end of file diff --git a/utils/test/unittest/utils_all_test.cpp b/utils/test/unittest/utils_all_test.cpp index 06c62041ca19cdb10256ff133c6f509692ccd26c..df72f575397fa975599e13c41e81c3ff0078c56e 100644 --- a/utils/test/unittest/utils_all_test.cpp +++ b/utils/test/unittest/utils_all_test.cpp @@ -225,7 +225,7 @@ HWTEST_F(UtilsAllTest, ConvertErrorToCode, TestSize.Level1) EXPECT_EQ(ConvertErrorToCode(WMError::WM_ERROR_FB_RESTORE_MAIN_WINDOW_FAILED), WmErrorCode::WM_ERROR_FB_RESTORE_MAIN_WINDOW_FAILED); WMError error = static_cast(-1); - EXPECT_EQ(ConvertErrorToCode(error), WmErrorCode::WM_ERROR_SYSTEM_ABNORMALLY); + EXPECT_EQ(ConvertErrorToCode(error), WmErrorCode::WM_ERROR_STATE_ABNORMALLY); } /** diff --git a/window_scene/interfaces/include/ws_common.h b/window_scene/interfaces/include/ws_common.h index 6e5e9e6c7e2dd0aa363953cd53b9d2d76a0e8f17..8b0ac32ff9cef509e892d5e3cd7c74f72e9d90ef 100644 --- a/window_scene/interfaces/include/ws_common.h +++ b/window_scene/interfaces/include/ws_common.h @@ -794,6 +794,41 @@ struct WSScreenRelativeRect { } }; +/** + * @struct WindowDecoration + * + * @brief Represents the window decoration thickness (non-drawable area). + * In general, the top decoration includes the title bar. + */ +struct WindowDecoration { + uint32_t left = 0; + uint32_t top = 0; + uint32_t right = 0; + uint32_t bottom = 0; + + bool operator==(const WindowDecoration& other) const + { + return left == other.left && top == other.top && right == other.right && bottom == other.bottom; + } + + /** + * @brief Calculate the total horizontal decoration. + */ + uint32_t Horizontal() const { return left + right; } + + /** + * @brief Calculate the total vertical decoration. + */ + uint32_t Vertical() const { return top + bottom; } + + std::string ToString() const + { + std::ostringstream oss; + oss << "[" << left << ", " << top << ", " << right << ", " << bottom << "]"; + return oss.str(); + } +}; + struct WindowAnimationInfo { WSRect beginRect { 0, 0, 0, 0 }; WSRect endRect { 0, 0, 0, 0 }; diff --git a/window_scene/session/BUILD.gn b/window_scene/session/BUILD.gn index 7bd5813a447fde8c761685cff45c4800ed7dc698..e3a4855888c440a646b169e6572107ee377018fa 100644 --- a/window_scene/session/BUILD.gn +++ b/window_scene/session/BUILD.gn @@ -36,14 +36,13 @@ config("session_public_config") { defines = [] if (window_manager_feature_asbng_path_enable) { defines += [ "WINDOW_ATOMIC_SERVICE_ATTRIBUTION_ENABLE" ] - cflags += [ "-DACE_ENGINE_PLUGIN_PATH=\"${window_manager_feature_asbng_path}\"" ] + cflags += + [ "-DACE_ENGINE_PLUGIN_PATH=\"${window_manager_feature_asbng_path}\"" ] } } config("ui_effect_public_config") { - include_dirs = [ - "${window_base_path}/window_scene/session/host/include", - ] + include_dirs = [ "${window_base_path}/window_scene/session/host/include" ] } ohos_source_set("ui_effect_controller_client") { @@ -55,14 +54,12 @@ ohos_source_set("ui_effect_controller_client") { debug = false } sources = [ - "host/src/ui_effect_controller_proxy.cpp", - "host/src/ui_effect_controller_client_stub.cpp", "host/src/ui_effect_controller_client.cpp", + "host/src/ui_effect_controller_client_stub.cpp", + "host/src/ui_effect_controller_proxy.cpp", ] - public_configs = [":ui_effect_public_config"] - public_deps = [ - "${window_base_path}/utils:ui_effect_controller_common", - ] + public_configs = [ ":ui_effect_public_config" ] + public_deps = [ "${window_base_path}/utils:ui_effect_controller_common" ] part_name = "window_manager" subsystem_name = "window" } @@ -76,16 +73,14 @@ ohos_source_set("ui_effect_controller") { debug = false } sources = [ - "host/src/ui_effect_controller_stub.cpp", "host/src/ui_effect_controller.cpp", "host/src/ui_effect_controller_client_proxy.cpp", + "host/src/ui_effect_controller_stub.cpp", ] - public_configs = [":ui_effect_public_config"] - public_deps = ["${window_base_path}/utils:ui_effect_controller_common"] + public_configs = [ ":ui_effect_public_config" ] + public_deps = [ "${window_base_path}/utils:ui_effect_controller_common" ] - deps = [ - "${window_base_path}/window_scene/common:window_scene_common", - ] + deps = [ "${window_base_path}/window_scene/common:window_scene_common" ] part_name = "window_manager" subsystem_name = "window" } @@ -121,6 +116,7 @@ ohos_shared_library("scene_session") { "host/src/session.cpp", "host/src/session_change_recorder.cpp", "host/src/session_coordinate_helper.cpp", + "host/src/session_utils.cpp", "host/src/sub_session.cpp", "host/src/system_session.cpp", "host/src/ui_extension/host_data_handler.cpp", diff --git a/window_scene/session/host/include/layout_controller.h b/window_scene/session/host/include/layout_controller.h index 04f3ea5a1b1eb3f034250ba148674fb166827494..c0e03a2454d47529aa8579eebbc7f0627ad1e220 100644 --- a/window_scene/session/host/include/layout_controller.h +++ b/window_scene/session/host/include/layout_controller.h @@ -42,7 +42,7 @@ public: WSRect ConvertRelativeRectToGlobal(const WSRect& relativeRect, DisplayId currentDisplayId) const; WSRect ConvertGlobalRectToRelative(const WSRect& globalRect, DisplayId targetDisplayId) const; int32_t GetSessionPersistentId() const; - bool AdjustRectByAspectRatio(WSRect& rect, bool isDecorEnable); + WSRect AdjustRectByAspectRatio(const WSRect& rect, const WindowDecoration& decoration); float GetAspectRatio() const { return aspectRatio_; } void SetAspectRatio(float ratio) { aspectRatio_ = ratio; } float GetScaleX() const { return scaleX_; } @@ -73,8 +73,6 @@ private: float aspectRatio_ = 0.0f; sptr sessionProperty_; GetSystemConfigFunc getSystemConfigFunc_; - - void AdjustRectByLimits(WindowLimits limits, float ratio, bool isDecor, float vpr, WSRect& rect); }; } // namespace OHOS::Rosen #endif // OHOS_ROSEN_LAYOUT_CONTROLLER_H diff --git a/window_scene/session/host/include/move_drag_controller.h b/window_scene/session/host/include/move_drag_controller.h index 89e0baea862818fc3e7e1f626cb8d533e6869423..678dc1b20a82201dc4e1a3c533a84f3ca52995a5 100644 --- a/window_scene/session/host/include/move_drag_controller.h +++ b/window_scene/session/host/include/move_drag_controller.h @@ -152,6 +152,7 @@ public: void StopMoving(); void SetLastDragEndRect(const WSRect& rect) { lastDragEndRect_ = rect; } WSRect GetLastDragEndRect() const { return lastDragEndRect_; } + void SetWindowDecoration(const WindowDecoration& decoration) { decoration_ = decoration; } private: struct MoveDragProperty { @@ -301,6 +302,7 @@ private: AreaType dragAreaType_ = AreaType::UNDEFINED; AxisType mainMoveAxis_ = AxisType::UNDEFINED; WindowLimits limits_; + WindowDecoration decoration_; MoveDragProperty moveDragProperty_; MoveDragCallback moveDragCallback_; int32_t persistentId_; diff --git a/window_scene/session/host/include/scene_session.h b/window_scene/session/host/include/scene_session.h index fb60840d3b6ccfbdcd8e5def0dcdba940a0659f9..bfc1ca8d26325abfa071818e14ee5d2e2d27f98d 100644 --- a/window_scene/session/host/include/scene_session.h +++ b/window_scene/session/host/include/scene_session.h @@ -294,6 +294,7 @@ public: bool needNotifyClient = true, bool isExecuteDelayRaise = false); WSError RequestSessionBack(bool needMoveToBackground) override; WSError SetAspectRatio(float ratio) override; + WSError SetContentAspectRatio(float ratio, bool isPersistent, bool needUpdateRect) override; WSError SetGlobalMaximizeMode(MaximizeMode mode) override; WSError GetGlobalMaximizeMode(MaximizeMode& mode) override; WSError UpdateWindowSceneAfterCustomAnimation(bool isAdd) override; @@ -675,6 +676,9 @@ public: */ int32_t GetCustomDecorHeight() const; void SetCustomDecorHeight(int32_t height) override; + WSError SetDecorVisible(bool isVisible) override; + bool IsDecorVisible() const; + WindowDecoration GetWindowDecoration() const; WMError UpdateSessionPropertyByAction(const sptr& property, WSPropertyChangeAction action) override; @@ -1259,6 +1263,8 @@ private: */ mutable std::mutex customDecorHeightMutex_; int32_t customDecorHeight_ = 0; + bool isDecorVisible_ = true; + // guarded by customDecorHeightMutex_ ForceHideState forceHideState_ { ForceHideState::NOT_HIDDEN }; int32_t oriPosYBeforeRaisedByKeyboard_ = 0; diff --git a/window_scene/session/host/include/session_utils.h b/window_scene/session/host/include/session_utils.h index b31ce091a6621bc585e749332bcbce3a48a1070e..65ee59ea122dfa243954df8da672ebdb57b1ea3a 100644 --- a/window_scene/session/host/include/session_utils.h +++ b/window_scene/session/host/include/session_utils.h @@ -17,43 +17,22 @@ #define OHOS_ROSEN_WINDOW_SCENE_SESSION_UTILS_H #include "wm_common_inner.h" +#include "ws_common.h" namespace OHOS::Rosen { namespace SessionUtils { constexpr const char* SESSION_NAME_MARK_HEAD = "#"; constexpr const char* SESSION_NAME_SEPARATOR = ":"; -inline float ToLayoutWidth(const int32_t winWidth, float vpr) +inline void CalcFloatWindowRectLimits(uint32_t maxFloatingWindowSize, float vpr, WindowLimits& limits) { - return winWidth - 2 * WINDOW_FRAME_WIDTH * vpr; // 2: left and right edge -} - -inline float ToLayoutHeight(const int32_t winHeight, float vpr) -{ - return winHeight - (WINDOW_FRAME_WIDTH + WINDOW_TITLE_BAR_HEIGHT) * vpr; -} - -inline float ToWinWidth(const int32_t layoutWidth, float vpr) -{ - return layoutWidth + 2 * WINDOW_FRAME_WIDTH * vpr; // 2: left and right edge -} - -inline float ToWinHeight(const int32_t layoutHeight, float vpr) -{ - return layoutHeight + (WINDOW_FRAME_WIDTH + WINDOW_TITLE_BAR_HEIGHT) * vpr; -} + uint32_t maxWidth = (limits.maxWidth_ == 0 || limits.maxWidth_ >= INT32_MAX) ? INT32_MAX : limits.maxWidth_; + uint32_t maxHeight = (limits.maxHeight_ == 0 || limits.maxHeight_ >= INT32_MAX) ? INT32_MAX : limits.maxHeight_; -inline void CalcFloatWindowRectLimits(const WindowLimits& limits, uint32_t maxFloatingWindowSize, float vpr, - int32_t& minWidth, int32_t& maxWidth, int32_t& minHeight, int32_t& maxHeight) -{ - minWidth = limits.minWidth_; - maxWidth = (limits.maxWidth_ == 0 || limits.maxWidth_ >= INT32_MAX) ? INT32_MAX : limits.maxWidth_; - minHeight = limits.minHeight_; - maxHeight = (limits.maxHeight_ == 0 || limits.maxHeight_ >= INT32_MAX) ? INT32_MAX : limits.maxHeight_; - minWidth = std::max(minWidth, static_cast(MIN_FLOATING_WIDTH * vpr)); - maxWidth = std::min(maxWidth, static_cast(maxFloatingWindowSize * vpr)); - minHeight = std::max(minHeight, static_cast(MIN_FLOATING_HEIGHT * vpr)); - maxHeight = std::min(maxHeight, static_cast(maxFloatingWindowSize * vpr)); + limits.minWidth_ = std::max(limits.minWidth_, static_cast(MIN_FLOATING_WIDTH * vpr)); + limits.maxWidth_ = std::min(maxWidth, static_cast(maxFloatingWindowSize * vpr)); + limits.minHeight_ = std::max(limits.minHeight_, static_cast(MIN_FLOATING_HEIGHT * vpr)); + limits.maxHeight_ = std::min(maxHeight, static_cast(maxFloatingWindowSize * vpr)); } inline std::string ConvertSessionName(const std::string& bundleName, const std::string& name, @@ -85,6 +64,46 @@ inline std::string GetAppLockKey(const std::string& bundleName, const int32_t ap { return bundleName + "#" + std::to_string(appIndex); } + +/** + * @brief Check if the aspect ratio is valid within the given window limits and decoration. + * + * @param ratio The aspect ratio to check (width / height). + * @param limits The window size limits including decoration. + * @param decoration The window decoration sizes (horizontal + vertical). + * @return True if the aspect ratio is valid, false otherwise. + */ +bool IsAspectRatioValid(float ratio, const WindowLimits& limits, const WindowDecoration& decoration); + +/** + * @brief Adjust window size limits to satisfy the specified aspect ratio, + * taking window decoration into account. + * + * @param limits Original window size limits including decoration. + * @param decoration Window decoration sizes (horizontal + vertical). + * @param aspectRatio Desired content aspect ratio (width / height). + * @return A new WindowLimits structure with aspect ratio constraints applied. + */ +WindowLimits AdjustLimitsByAspectRatio(const WindowLimits& limits, + const WindowDecoration& decoration, + float aspectRatio); + +/** + * @brief Adjust a window rectangle to satisfy both the specified aspect ratio + * and the given size limits, considering decoration sizes. + * + * @param rect Original window rectangle including decoration. + * @param limits Window size limits including decoration. + * @param decoration Window decoration sizes (horizontal + vertical). + * @param aspectRatio Desired content aspect ratio (width / height). + * @param tolerancePx Pixel tolerance used to skip small adjustments. + * @return A new WSRect adjusted to satisfy aspect ratio and size constraints. + */ +WSRect AdjustRectByAspectRatio(const WSRect& rect, + const WindowLimits& limits, + const WindowDecoration& decoration, + float aspectRatio, + int tolerancePx = 2); } // namespace SessionUtils } // namespace OHOS::Rosen #endif // OHOS_ROSEN_WINDOW_SCENE_SESSION_UTILS_H diff --git a/window_scene/session/host/include/zidl/session_interface.h b/window_scene/session/host/include/zidl/session_interface.h index f21a2657979e21153a0749211f6cac365b7bedbf..3911a69b400b939418364798158a7589c83127e3 100644 --- a/window_scene/session/host/include/zidl/session_interface.h +++ b/window_scene/session/host/include/zidl/session_interface.h @@ -193,6 +193,18 @@ public: * @return Returns WSError::WS_OK if called success, otherwise failed. */ virtual WSError SetAspectRatio(float ratio) { return WSError::WS_OK; } + + /** + * @brief Set content aspect ratio of the window. + * + * @param ratio The aspect ratio of window content (width divided by height). + * @param isPersistent Whether to persist the aspect ratio setting. + * @param needUpdateRect Whether to update the window rect after setting aspect ratio. + * @return Returns WSError::WS_OK if called success, otherwise failed. + */ + virtual WSError SetContentAspectRatio( + float ratio, bool isPersistent, bool needUpdateRect) { return WSError::WS_DO_NOTHING; } + virtual WSError UpdateWindowAnimationFlag(bool needDefaultAnimationFlag) { return WSError::WS_OK; } virtual WSError UpdateWindowSceneAfterCustomAnimation(bool isAdd) { return WSError::WS_OK; } @@ -358,6 +370,15 @@ public: virtual void NotifyKeyboardDidShowRegistered(bool registered) {}; virtual void NotifyKeyboardDidHideRegistered(bool registered) {}; virtual void SetCustomDecorHeight(int32_t height) {}; + + /** + * @brief Set whether the window decoration is visible. + * + * @param isVisible True means the window decoration is visible, false means the opposite. + * @return Returns WSError::WS_OK if called success, otherwise failed. + */ + virtual WSError SetDecorVisible(bool isVisible) { return WSError::WS_DO_NOTHING; } + virtual WMError UpdateSessionPropertyByAction(const sptr& property, WSPropertyChangeAction action) { return WMError::WM_OK; } virtual WMError GetAppForceLandscapeConfig(AppForceLandscapeConfig& config) { return WMError::WM_OK; } 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 78c45862dff9cf2f2b17f912cf17eecee4751eca..36c106b009b4a385983b87297855e1dc154f975a 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 @@ -45,6 +45,7 @@ enum class SessionInterfaceCode { TRANS_ID_NEED_AVOID, TRANS_ID_GET_AVOID_AREA, TRANS_ID_SET_ASPECT_RATIO, + TRANS_ID_SET_CONTENT_ASPECT_RATIO, TRANS_ID_UPDATE_WINDOW_ANIMATION_FLAG, TRANS_ID_UPDATE_CUSTOM_ANIMATION, TRANS_ID_RAISE_ABOVE_TARGET, @@ -57,6 +58,7 @@ enum class SessionInterfaceCode { TRANS_ID_UPDATE_RECTCHANGE_LISTENER_REGISTERED, TRANS_ID_SET_CALLING_SESSION_ID, TRANS_ID_SET_CUSTOM_DECOR_HEIGHT, + TRANS_ID_SET_DECOR_VISIBLE, TRANS_ID_UPDATE_SESSION_PROPERTY, TRANS_ID_ADJUST_KEYBOARD_LAYOUT, TRANS_ID_LAYOUT_FULL_SCREEN_CHANGE, diff --git a/window_scene/session/host/include/zidl/session_proxy.h b/window_scene/session/host/include/zidl/session_proxy.h index 943b3fb921c13ad071f0896d1f6db5ed53316aa2..53ec600d82e7483e996c11d444527d0f7d2d8ac7 100644 --- a/window_scene/session/host/include/zidl/session_proxy.h +++ b/window_scene/session/host/include/zidl/session_proxy.h @@ -74,6 +74,7 @@ public: WSError SetGlobalMaximizeMode(MaximizeMode mode) override; WSError GetGlobalMaximizeMode(MaximizeMode& mode) override; WSError SetAspectRatio(float ratio) override; + WSError SetContentAspectRatio(float ratio, bool isPersistent, bool needUpdateRect) override; WSError UpdateWindowAnimationFlag(bool needDefaultAnimationFlag) override; WSError SetLandscapeMultiWindow(bool isLandscapeMultiWindow) override; WSError GetIsMidScene(bool& isMidScene) override; @@ -124,6 +125,7 @@ public: void NotifyKeyboardDidShowRegistered(bool registered) override; void NotifyKeyboardDidHideRegistered(bool registered) override; void SetCustomDecorHeight(int32_t height) override; + WSError SetDecorVisible(bool isVisible) override; WSError AdjustKeyboardLayout(const KeyboardLayoutParams& params) override; WSError ChangeKeyboardEffectOption(const KeyboardEffectOption& effectOption) override; WMError UpdateSessionPropertyByAction(const sptr& property, diff --git a/window_scene/session/host/include/zidl/session_stub.h b/window_scene/session/host/include/zidl/session_stub.h index 020dfcebba8dae2b5507990693f9bd112514cf36..770ae4d278769d1f0537606549f4f2d4f8c8a46c 100644 --- a/window_scene/session/host/include/zidl/session_stub.h +++ b/window_scene/session/host/include/zidl/session_stub.h @@ -57,6 +57,7 @@ private: int HandleGetAllAvoidAreas(MessageParcel& data, MessageParcel& reply); int HandleGetTargetOrientationConfigInfo(MessageParcel& data, MessageParcel& reply); int HandleSetAspectRatio(MessageParcel& data, MessageParcel& reply); + int HandleSetContentAspectRatio(MessageParcel& data, MessageParcel& reply); int HandleSetWindowAnimationFlag(MessageParcel& data, MessageParcel& reply); int HandleUpdateWindowSceneAfterCustomAnimation(MessageParcel& data, MessageParcel& reply); int HandleRaiseAboveTarget(MessageParcel& data, MessageParcel& reply); @@ -75,6 +76,7 @@ private: int HandleUpdateRectChangeListenerRegistered(MessageParcel& data, MessageParcel& reply); int HandleSetCallingSessionId(MessageParcel& data, MessageParcel& reply); int HandleSetCustomDecorHeight(MessageParcel& data, MessageParcel& reply); + int HandleSetDecorVisible(MessageParcel& data, MessageParcel& reply); int HandleAdjustKeyboardLayout(MessageParcel& data, MessageParcel& reply); int HandleUpdatePropertyByAction(MessageParcel& data, MessageParcel& reply); int HandleLayoutFullScreenChange(MessageParcel& data, MessageParcel& reply); diff --git a/window_scene/session/host/src/layout_controller.cpp b/window_scene/session/host/src/layout_controller.cpp index e6b44555c0fd59c60a24c4a25bae8c147135e74b..e4f3adfe427b9acf6bf78ca933cf2c930e013b85 100644 --- a/window_scene/session/host/src/layout_controller.cpp +++ b/window_scene/session/host/src/layout_controller.cpp @@ -138,83 +138,33 @@ int32_t LayoutController::GetSessionPersistentId() const return sessionProperty_->GetPersistentId(); } -void LayoutController::AdjustRectByLimits(WindowLimits limits, float ratio, bool isDecor, float vpr, WSRect& rect) +WSRect LayoutController::AdjustRectByAspectRatio(const WSRect& rect, const WindowDecoration& decoration) { - if (isDecor) { - rect.width_ = SessionUtils::ToLayoutWidth(rect.width_, vpr); - rect.height_ = SessionUtils::ToLayoutHeight(rect.height_, vpr); - limits.minWidth_ = SessionUtils::ToLayoutWidth(limits.minWidth_, vpr); - limits.maxWidth_ = SessionUtils::ToLayoutWidth(limits.maxWidth_, vpr); - limits.minHeight_ = SessionUtils::ToLayoutHeight(limits.minHeight_, vpr); - limits.maxHeight_ = SessionUtils::ToLayoutHeight(limits.maxHeight_, vpr); + if (sessionProperty_ == nullptr) { + TLOGE(WmsLogTag::WMS_LAYOUT, "sessionProperty is null"); + return rect; } - if (static_cast(rect.height_) > limits.maxHeight_) { - rect.height_ = static_cast(limits.maxHeight_); - rect.width_ = floor(rect.height_ * ratio); - } else if (static_cast(rect.width_) > limits.maxWidth_) { - rect.width_ = static_cast(limits.maxWidth_); - rect.height_ = floor(rect.width_ / ratio); - } else if (static_cast(rect.width_) < limits.minWidth_) { - rect.width_ = static_cast(limits.minWidth_); - rect.height_ = ceil(rect.width_ / ratio); - } else if (static_cast(rect.height_) < limits.minHeight_) { - rect.height_ = static_cast(limits.minHeight_); - rect.width_ = ceil(rect.height_ * ratio); + auto windowId = GetSessionPersistentId(); + auto mode = sessionProperty_->GetWindowMode(); + auto type = sessionProperty_->GetWindowType(); + if (mode != WindowMode::WINDOW_MODE_FLOATING || !WindowHelper::IsMainWindow(type)) { + TLOGW(WmsLogTag::WMS_LAYOUT, "Skip adjustment, windowId: %{public}d, mode: %{public}u, type: %{public}u", + windowId, static_cast(mode), static_cast(type)); + return rect; } - if (isDecor) { - rect.height_ = SessionUtils::ToWinHeight(rect.height_, vpr) ; - rect.width_ = SessionUtils::ToWinWidth(rect.width_, vpr); + auto displayId = sessionProperty_->GetDisplayId(); + auto display = DisplayManager::GetInstance().GetDisplayById(displayId); + if (!display) { + TLOGE(WmsLogTag::WMS_LAYOUT, "display is null, displayId: %{public}" PRIu64, displayId); + return rect; } -} - -bool LayoutController::AdjustRectByAspectRatio(WSRect& rect, bool isDecorEnable) -{ - const int tolerancePx = 2; // 2: tolerance delta pixel value, unit: px - WSRect originalRect = rect; - if (sessionProperty_->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING || - !WindowHelper::IsMainWindow(sessionProperty_->GetWindowType())) { - return false; - } - - if (MathHelper::NearZero(aspectRatio_)) { - return false; - } - float vpr = 1.5f; // 1.5f: default virtual pixel ratio - auto display = DisplayManager::GetInstance().GetDefaultDisplay(); - if (display) { - vpr = display->GetVirtualPixelRatio(); - } - int32_t minW; - int32_t maxW; - int32_t minH; - int32_t maxH; - SessionUtils::CalcFloatWindowRectLimits(sessionProperty_->GetWindowLimits(), - getSystemConfigFunc_().maxFloatingWindowSize_, vpr, minW, maxW, minH, maxH); - rect.width_ = std::max(minW, static_cast(rect.width_)); - rect.width_ = std::min(maxW, static_cast(rect.width_)); - rect.height_ = std::max(minH, static_cast(rect.height_)); - rect.height_ = std::min(maxH, static_cast(rect.height_)); - if (isDecorEnable) { - if (SessionUtils::ToLayoutWidth(rect.width_, vpr) > - SessionUtils::ToLayoutHeight(rect.height_, vpr) * aspectRatio_) { - rect.width_ = SessionUtils::ToWinWidth(SessionUtils::ToLayoutHeight(rect.height_, vpr)* aspectRatio_, vpr); - } else { - rect.height_ = SessionUtils::ToWinHeight(SessionUtils::ToLayoutWidth(rect.width_, vpr) / aspectRatio_, vpr); - } - } else { - if (rect.width_ > rect.height_ * aspectRatio_) { - rect.width_ = rect.height_ * aspectRatio_; - } else { - rect.height_ = rect.width_ / aspectRatio_; - } - } - AdjustRectByLimits(sessionProperty_->GetWindowLimits(), aspectRatio_, isDecorEnable, vpr, rect); - if (std::abs(static_cast(originalRect.width_) - static_cast(rect.width_)) <= tolerancePx && - std::abs(static_cast(originalRect.height_) - static_cast(rect.height_)) <= tolerancePx) { - rect = originalRect; - return false; - } - return true; + float vpr = display->GetVirtualPixelRatio(); + auto limits = sessionProperty_->GetWindowLimits(); + SessionUtils::CalcFloatWindowRectLimits(getSystemConfigFunc_().maxFloatingWindowSize_, vpr, limits); + const WSRect& adjustedRect = SessionUtils::AdjustRectByAspectRatio(rect, limits, decoration, aspectRatio_); + TLOGD(WmsLogTag::WMS_LAYOUT, "After adjustment, windowId: %{public}d, rect: %{public}s", + windowId, adjustedRect.ToString().c_str()); + return adjustedRect; } void LayoutController::SetScale(float scaleX, float scaleY, float pivotX, float pivotY) diff --git a/window_scene/session/host/src/move_drag_controller.cpp b/window_scene/session/host/src/move_drag_controller.cpp index c49e516defb9c041c5accec6eac028594e1a7102..a928b787d23a35a99f518d0a869ee53910632747 100644 --- a/window_scene/session/host/src/move_drag_controller.cpp +++ b/window_scene/session/host/src/move_drag_controller.cpp @@ -505,8 +505,11 @@ void MoveDragController::CalcDragTargetRect(const std::shared_ptr trans = CalcUnifiedTranslate(pointerEvent); @@ -1162,94 +1165,58 @@ void MoveDragController::CalcFreeformTranslateLimits(AreaType type) void MoveDragController::CalcFixedAspectRatioTranslateLimits(AreaType type) { - int32_t minW = static_cast(limits_.minWidth_); - int32_t maxW = static_cast(limits_.maxWidth_); - int32_t minH = static_cast(limits_.minHeight_); - int32_t maxH = static_cast(limits_.maxHeight_); - if (isDecorEnable_) { - if (SessionUtils::ToLayoutWidth(minW, vpr_) < SessionUtils::ToLayoutHeight(minH, vpr_) * aspectRatio_) { - minW = SessionUtils::ToWinWidth(SessionUtils::ToLayoutHeight(minH, vpr_) * aspectRatio_, vpr_); - minH = SessionUtils::ToLayoutHeight(minH, vpr_); - } else { - minH = SessionUtils::ToWinHeight(SessionUtils::ToLayoutWidth(minW, vpr_) / aspectRatio_, vpr_); - minW = SessionUtils::ToLayoutWidth(minW, vpr_); + if (MathHelper::NearZero(aspectRatio_)) { + TLOGE(WmsLogTag::WMS_LAYOUT, "aspectRatio is near 0, id:%{public}d", persistentId_); + return; + } + + const int32_t origW = moveDragProperty_.originalRect_.width_; + const int32_t origH = moveDragProperty_.originalRect_.height_; + + auto adjustedLimits = SessionUtils::AdjustLimitsByAspectRatio(limits_, decoration_, aspectRatio_); + const int32_t minW = static_cast(adjustedLimits.minWidth_); + const int32_t maxW = static_cast(adjustedLimits.maxWidth_); + const int32_t minH = static_cast(adjustedLimits.minHeight_); + const int32_t maxH = static_cast(adjustedLimits.maxHeight_); + + switch (type) { + case AreaType::LEFT: + case AreaType::LEFT_BOTTOM: { + minTranX_ = origW - maxW; + maxTranX_ = origW - minW; + minTranY_ = minH - origH; + maxTranY_ = maxH - origH; + break; } - if (SessionUtils::ToLayoutWidth(maxW, vpr_) < SessionUtils::ToLayoutHeight(maxH, vpr_) * aspectRatio_) { - maxH = SessionUtils::ToWinHeight(SessionUtils::ToLayoutWidth(maxW, vpr_) / aspectRatio_, vpr_); - maxW = SessionUtils::ToLayoutWidth(maxW, vpr_); - } else { - maxW = SessionUtils::ToWinWidth(SessionUtils::ToLayoutHeight(maxH, vpr_) * aspectRatio_, vpr_); - maxH = SessionUtils::ToLayoutHeight(maxH, vpr_); + case AreaType::LEFT_TOP: { + minTranX_ = origW - maxW; + maxTranX_ = origW - minW; + minTranY_ = origH - maxH; + maxTranY_ = origH - minH; + break; } - } else { - // width = height * aspectRatio - if (minW < minH * aspectRatio_) { - minW = minH * aspectRatio_; - } else { - minH = minW / aspectRatio_; + case AreaType::RIGHT: + case AreaType::RIGHT_BOTTOM: + case AreaType::BOTTOM: { + minTranX_ = minW - origW; + maxTranX_ = maxW - origW; + minTranY_ = minH - origH; + maxTranY_ = maxH - origH; + break; } - if (maxW < maxH * aspectRatio_) { - maxH = maxW / aspectRatio_; - } else { - maxW = maxH * aspectRatio_; + case AreaType::RIGHT_TOP: + case AreaType::TOP: { + minTranX_ = minW - origW; + maxTranX_ = maxW - origW; + minTranY_ = origH - maxH; + maxTranY_ = origH - minH; + break; + } + default: { + TLOGE(WmsLogTag::WMS_LAYOUT, "Invalid type: %{public}u", static_cast(type)); + break; } } - - const static std::map> calcMinMaxTranMap = { - { AreaType::LEFT, [this](int32_t maxW, int32_t minW, int32_t maxH, int32_t minH) { - minTranX_ = static_cast(moveDragProperty_.originalRect_.width_) - maxW; - maxTranX_ = static_cast(moveDragProperty_.originalRect_.width_) - minW; - minTranY_ = minH - static_cast(moveDragProperty_.originalRect_.height_); - maxTranY_ = maxH - static_cast(moveDragProperty_.originalRect_.height_); - }}, - { AreaType::LEFT_TOP, [this](int32_t maxW, int32_t minW, int32_t maxH, int32_t minH) { - minTranX_ = static_cast(moveDragProperty_.originalRect_.width_) - maxW; - maxTranX_ = static_cast(moveDragProperty_.originalRect_.width_) - minW; - minTranY_ = static_cast(moveDragProperty_.originalRect_.height_) - maxH; - maxTranY_ = static_cast(moveDragProperty_.originalRect_.height_) - minH; - }}, - { AreaType::LEFT_BOTTOM, [this](int32_t maxW, int32_t minW, int32_t maxH, int32_t minH) { - minTranX_ = static_cast(moveDragProperty_.originalRect_.width_) - maxW; - maxTranX_ = static_cast(moveDragProperty_.originalRect_.width_) - minW; - minTranY_ = minH - static_cast(moveDragProperty_.originalRect_.height_); - maxTranY_ = maxH - static_cast(moveDragProperty_.originalRect_.height_); - }}, - { AreaType::RIGHT, [this](int32_t maxW, int32_t minW, int32_t maxH, int32_t minH) { - minTranX_ = minW - static_cast(moveDragProperty_.originalRect_.width_); - maxTranX_ = maxW - static_cast(moveDragProperty_.originalRect_.width_); - minTranY_ = minH - static_cast(moveDragProperty_.originalRect_.height_); - maxTranY_ = maxH - static_cast(moveDragProperty_.originalRect_.height_); - }}, - { AreaType::RIGHT_TOP, [this](int32_t maxW, int32_t minW, int32_t maxH, int32_t minH) { - minTranX_ = minW - static_cast(moveDragProperty_.originalRect_.width_); - maxTranX_ = maxW - static_cast(moveDragProperty_.originalRect_.width_); - minTranY_ = static_cast(moveDragProperty_.originalRect_.height_) - maxH; - maxTranY_ = static_cast(moveDragProperty_.originalRect_.height_) - minH; - }}, - { AreaType::RIGHT_BOTTOM, [this](int32_t maxW, int32_t minW, int32_t maxH, int32_t minH) { - minTranX_ = minW - static_cast(moveDragProperty_.originalRect_.width_); - maxTranX_ = maxW - static_cast(moveDragProperty_.originalRect_.width_); - minTranY_ = minH - static_cast(moveDragProperty_.originalRect_.height_); - maxTranY_ = maxH - static_cast(moveDragProperty_.originalRect_.height_); - }}, - { AreaType::TOP, [this](int32_t maxW, int32_t minW, int32_t maxH, int32_t minH) { - minTranX_ = minW - static_cast(moveDragProperty_.originalRect_.width_); - maxTranX_ = maxW - static_cast(moveDragProperty_.originalRect_.width_); - minTranY_ = static_cast(moveDragProperty_.originalRect_.height_) - maxH; - maxTranY_ = static_cast(moveDragProperty_.originalRect_.height_) - minH; - }}, - { AreaType::BOTTOM, [this](int32_t maxW, int32_t minW, int32_t maxH, int32_t minH) { - minTranX_ = minW - static_cast(moveDragProperty_.originalRect_.width_); - maxTranX_ = maxW - static_cast(moveDragProperty_.originalRect_.width_); - minTranY_ = minH - static_cast(moveDragProperty_.originalRect_.height_); - maxTranY_ = maxH - static_cast(moveDragProperty_.originalRect_.height_); - }}, - }; - if (calcMinMaxTranMap.find(type) == calcMinMaxTranMap.end()) { - TLOGE(WmsLogTag::WMS_LAYOUT, "not find type:%{public}d", type); - return; - } - calcMinMaxTranMap.at(type)(maxW, minW, maxH, minH); } void MoveDragController::FixTranslateByLimits(int32_t& tranX, int32_t& tranY) diff --git a/window_scene/session/host/src/scene_session.cpp b/window_scene/session/host/src/scene_session.cpp index 6640111a91d79dbf9ecfb5fc4627c3aa2e602a6c..39ef9d0fc5321d302a8ab267db6bbb3ba5adae27 100644 --- a/window_scene/session/host/src/scene_session.cpp +++ b/window_scene/session/host/src/scene_session.cpp @@ -1396,76 +1396,51 @@ WSError SceneSession::GetGlobalMaximizeMode(MaximizeMode& mode) }, __func__); } -static WSError CheckAspectRatioValid(const sptr& session, float ratio, float vpr) +/** @note @window.layout */ +WSError SceneSession::SetAspectRatio(float ratio) { - if (MathHelper::NearZero(ratio)) { - return WSError::WS_OK; - } - if (!session) { - return WSError::WS_ERROR_INVALID_PARAM; - } - auto sessionProperty = session->GetSessionProperty(); - if (!sessionProperty) { - return WSError::WS_ERROR_INVALID_PARAM; - } - auto limits = sessionProperty->GetWindowLimits(); - if (session->IsDecorEnable()) { - if (limits.minWidth_ && limits.maxHeight_ && - MathHelper::LessNotEqual(ratio, SessionUtils::ToLayoutWidth(limits.minWidth_, vpr) / - SessionUtils::ToLayoutHeight(limits.maxHeight_, vpr))) { - WLOGE("Failed, because aspectRatio is smaller than minWidth/maxHeight"); - return WSError::WS_ERROR_INVALID_PARAM; - } else if (limits.minHeight_ && limits.maxWidth_ && - MathHelper::GreatNotEqual(ratio, SessionUtils::ToLayoutWidth(limits.maxWidth_, vpr) / - SessionUtils::ToLayoutHeight(limits.minHeight_, vpr))) { - WLOGE("Failed, because aspectRatio is bigger than maxWidth/minHeight"); - return WSError::WS_ERROR_INVALID_PARAM; - } - } else { - if (limits.minWidth_ && limits.maxHeight_ && MathHelper::LessNotEqual(ratio, - static_cast(limits.minWidth_) / limits.maxHeight_)) { - WLOGE("Failed, because aspectRatio is smaller than minWidth/maxHeight"); - return WSError::WS_ERROR_INVALID_PARAM; - } else if (limits.minHeight_ && limits.maxWidth_ && MathHelper::GreatNotEqual(ratio, - static_cast(limits.maxWidth_) / limits.minHeight_)) { - WLOGE("Failed, because aspectRatio is bigger than maxWidth/minHeight"); - return WSError::WS_ERROR_INVALID_PARAM; - } - } - return WSError::WS_OK; + return SetContentAspectRatio(ratio, true, true); } -/** @note @window.layout */ -WSError SceneSession::SetAspectRatio(float ratio) +WSError SceneSession::SetContentAspectRatio(float ratio, bool isPersistent, bool needUpdateRect) { - return PostSyncTask([weakThis = wptr(this), ratio, where = __func__] { + TLOGI(WmsLogTag::WMS_LAYOUT, + "windowId: %{public}d, ratio: %{public}f, isPersistent: %{public}d, needUpdateRect: %{public}d", + GetPersistentId(), ratio, isPersistent, needUpdateRect); + return PostSyncTask([weakThis = wptr(this), ratio, isPersistent, needUpdateRect, where = __func__] { auto session = weakThis.promote(); if (!session) { - TLOGNE(WmsLogTag::WMS_LAYOUT, "%{public}s session is null", where); - return WSError::WS_ERROR_DESTROYED_OBJECT; + TLOGNE(WmsLogTag::WMS_LAYOUT, "%{public}s: session is null", where); + return WSError::WS_ERROR_NULLPTR; } - float vpr = 1.5f; // 1.5f: default virtual pixel ratio - auto display = DisplayManager::GetInstance().GetDefaultDisplay(); - if (display) { - vpr = display->GetVirtualPixelRatio(); - TLOGND(WmsLogTag::WMS_LAYOUT, "%{public}s vpr=%{public}f", where, vpr); + auto property = session->GetSessionProperty(); + if (!property) { + TLOGNE(WmsLogTag::WMS_LAYOUT, "%{public}s: property is null", where); + return WSError::WS_ERROR_NULLPTR; } - WSError ret = CheckAspectRatioValid(session, ratio, vpr); - if (ret != WSError::WS_OK) { - return ret; + WindowLimits limits = property->GetWindowLimits(); + WindowDecoration decoration = session->GetWindowDecoration(); + if (!SessionUtils::IsAspectRatioValid(ratio, limits, decoration)) { + TLOGE(WmsLogTag::WMS_LAYOUT, "%{public}s: Invalid ratio: %{public}f", where, ratio); + return WSError::WS_ERROR_INVALID_PARAM; } session->Session::SetAspectRatio(ratio); if (session->moveDragController_) { session->moveDragController_->SetAspectRatio(ratio); } - session->SaveAspectRatio(session->GetAspectRatio()); - WSRect adjustedRect = session->GetSessionRect(); - TLOGNI(WmsLogTag::WMS_LAYOUT, "%{public}s Before adjusting, the id:%{public}d, the current rect:%{public}s, " - "ratio:%{public}f", where, session->GetPersistentId(), adjustedRect.ToString().c_str(), ratio); - if (session->layoutController_->AdjustRectByAspectRatio(adjustedRect, session->IsDecorEnable())) { - TLOGNI(WmsLogTag::WMS_LAYOUT, "%{public}s After adjusting, the id:%{public}d, the adjusted rect:%{public}s", - where, session->GetPersistentId(), adjustedRect.ToString().c_str()); - session->NotifySessionRectChange(adjustedRect, SizeChangeReason::RESIZE); + if (isPersistent) { + session->SaveAspectRatio(ratio); + } + if (needUpdateRect) { + WSRect originalRect = session->GetSessionRect(); + WSRect adjustedRect = session->layoutController_->AdjustRectByAspectRatio(originalRect, decoration); + if (adjustedRect != originalRect) { + session->NotifySessionRectChange(adjustedRect, SizeChangeReason::RESIZE); + TLOGNI(WmsLogTag::WMS_LAYOUT, + "%{public}s: windowId: %{public}d, originalRect: %{public}s, adjustedRect: %{public}s", + where, session->GetPersistentId(), + originalRect.ToString().c_str(), adjustedRect.ToString().c_str()); + } } return WSError::WS_OK; }, __func__); @@ -3229,6 +3204,9 @@ WSError SceneSession::TransferPointerEventInner(const std::shared_ptrSetWindowDecoration(GetWindowDecoration()); + } moveDragController_->SetScale(GetScaleX(), GetScaleY()); // need scale ratio to calculate translate SetParentRect(); if (IsDraggable() && @@ -8339,6 +8317,46 @@ void SceneSession::SetCustomDecorHeight(int32_t height) customDecorHeight_ = height; } +WSError SceneSession::SetDecorVisible(bool isVisible) +{ + std::lock_guard lock(customDecorHeightMutex_); + isDecorVisible_ = isVisible; + return WSError::WS_OK; +} + +bool SceneSession::IsDecorVisible() const +{ + std::lock_guard lock(customDecorHeightMutex_); + return isDecorVisible_; +} + +WindowDecoration SceneSession::GetWindowDecoration() const +{ + auto getTopDecorInPx = [&, where = __func__]() -> uint32_t { + if (!IsDecorVisible() || !IsDecorEnable()) { + TLOGW(WmsLogTag::WMS_DECOR, "%{public}s: decor not visible or not enable", where); + return 0; + } + auto displayId = GetDisplayId(); + auto display = DisplayManager::GetInstance().GetDisplayById(displayId); + if (!display) { + TLOGW(WmsLogTag::WMS_DECOR, "%{public}s: display is null, displayId: %{public}" PRIu64, where, displayId); + return 0; + } + float vpr = display->GetVirtualPixelRatio(); + constexpr int32_t defaultTopDecorHeightVp = 37; + std::lock_guard lock(customDecorHeightMutex_); + auto decorHeightVp = customDecorHeight_ != 0 ? customDecorHeight_ : defaultTopDecorHeightVp; + TLOGD(WmsLogTag::WMS_DECOR, "%{public}s: decorHeight: %{public}d, vpr: %{public}f", where, decorHeightVp, vpr); + return static_cast(decorHeightVp * vpr); + }; + // Only the top decoration (title bar) currently has height. Left, right, and bottom are set to 0 by default. + // If future specifications introduce additional decorations, this return value should be updated accordingly. + WindowDecoration decoration{0, getTopDecorInPx(), 0, 0}; + TLOGD(WmsLogTag::WMS_DECOR, "decoration: %{public}s", decoration.ToString().c_str()); + return decoration; +} + void SceneSession::UpdateGestureBackEnabled() { if (specificCallback_ != nullptr && diff --git a/window_scene/session/host/src/session_utils.cpp b/window_scene/session/host/src/session_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b9ec2cef5446527e53c96d77d65f70ce26b3c5b --- /dev/null +++ b/window_scene/session/host/src/session_utils.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "session_utils.h" + +#include "window_manager_hilog.h" + +namespace OHOS::Rosen { +namespace SessionUtils { +bool IsAspectRatioValid(float aspectRatio, const WindowLimits& limits, const WindowDecoration& decoration) +{ + if (MathHelper::NearZero(aspectRatio)) { + return true; + } + + WindowLimits contentLimits = limits; + contentLimits.Clip(decoration.Horizontal(), decoration.Vertical()); + if (!contentLimits.IsValid()) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Invalid contentLimits: %{public}s", contentLimits.ToString().c_str()); + return false; + } + + float minRatio = contentLimits.maxHeight_ > 0 ? + static_cast(contentLimits.minWidth_) / static_cast(contentLimits.maxHeight_) : 0.0f; + float maxRatio = contentLimits.minHeight_ > 0 ? + static_cast(contentLimits.maxWidth_) / static_cast(contentLimits.minHeight_) : FLT_MAX; + + if (MathHelper::LessNotEqual(aspectRatio, minRatio) || MathHelper::GreatNotEqual(aspectRatio, maxRatio)) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Invalid aspectRatio: %{public}f, valid range: [%{public}f, %{public}f]", + aspectRatio, minRatio, maxRatio); + return false; + } + return true; +} + +WindowLimits AdjustLimitsByAspectRatio(const WindowLimits& limits, + const WindowDecoration& decoration, + float aspectRatio) +{ + if (MathHelper::NearZero(aspectRatio)) { + return limits; + } + + const uint32_t decorW = decoration.Horizontal(); + const uint32_t decorH = decoration.Vertical(); + + // Clip limits by decoration + WindowLimits adjustedLimits = limits; + adjustedLimits.Clip(decorW, decorH); + if (!adjustedLimits.IsValid()) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Invalid adjustedLimits: %{public}s", adjustedLimits.ToString().c_str()); + return limits; + } + + // Pre-calc aspect ratio constraints + const uint32_t minWByH = static_cast(std::ceil(adjustedLimits.minHeight_ * aspectRatio)); + const uint32_t minHByW = static_cast(std::ceil(adjustedLimits.minWidth_ / aspectRatio)); + const uint32_t maxHByW = static_cast(std::floor(adjustedLimits.maxWidth_ / aspectRatio)); + const uint32_t maxWByH = static_cast(std::floor(adjustedLimits.maxHeight_ * aspectRatio)); + + // Adjust constraints to satisfy aspect ratio. + if (adjustedLimits.minWidth_ < minWByH) { + adjustedLimits.minWidth_ = minWByH; + } else { + adjustedLimits.minHeight_ = minHByW; + } + + if (adjustedLimits.maxWidth_ > maxWByH) { + adjustedLimits.maxWidth_ = maxWByH; + } else { + adjustedLimits.maxHeight_ = maxHByW; + } + + // Add back decorations + adjustedLimits.Expand(decorW, decorH); + return adjustedLimits.IsValid() ? adjustedLimits : limits; +} + +WSRect AdjustRectByAspectRatio(const WSRect& rect, + const WindowLimits& limits, + const WindowDecoration& decoration, + float aspectRatio, + int tolerancePx) +{ + if (MathHelper::NearZero(aspectRatio)) { + return rect; + } + + const uint32_t decorW = decoration.Horizontal(); + const uint32_t decorH = decoration.Vertical(); + + // Clip limits by decoration + WindowLimits adjustedLimits = limits; + adjustedLimits.Clip(decorW, decorH); + if (!adjustedLimits.IsValid()) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Invalid adjustedLimits: %{public}s", adjustedLimits.ToString().c_str()); + return rect; + } + + // Width-prioritized aspect ratio adjustment + uint32_t minWByH = static_cast(std::ceil(adjustedLimits.minHeight_ * aspectRatio)); + uint32_t maxWByH = static_cast(std::floor(adjustedLimits.maxHeight_ * aspectRatio)); + uint32_t minW = std::max(adjustedLimits.minWidth_, minWByH); + uint32_t maxW = std::min(adjustedLimits.maxWidth_, maxWByH); + if (minW > maxW) { + TLOGE(WmsLogTag::WMS_LAYOUT, + "Aspect ratio conflicts with limits, aspectRatio: %{public}f, adjustedLimits: %{public}s", + aspectRatio, adjustedLimits.ToString().c_str()); + return rect; + } + + // Available rect (excluding decoration) + uint32_t availW = static_cast(rect.width_) - decorW; + uint32_t targetW = std::clamp(availW, minW, maxW); + uint32_t targetH = static_cast(std::round(static_cast(targetW) / aspectRatio)); + targetH = std::clamp(targetH, adjustedLimits.minHeight_, adjustedLimits.maxHeight_); + + WSRect adjustedRect = rect; + // Add back decorations + adjustedRect.width_ = static_cast(targetW + decorW); + adjustedRect.height_ = static_cast(targetH + decorH); + + // Tolerance: <= tolerancePx pixels is considered no adjustment + if (std::abs(rect.width_ - adjustedRect.width_) <= tolerancePx && + std::abs(rect.height_ - adjustedRect.height_) <= tolerancePx) { + TLOGD(WmsLogTag::WMS_LAYOUT, "Adjustment within tolerance: %{public}dpx, no adjustment", tolerancePx); + return rect; + } + return adjustedRect; +} +} // namespace SessionUtils +} // namespace OHOS::Rosen diff --git a/window_scene/session/host/src/zidl/session_proxy.cpp b/window_scene/session/host/src/zidl/session_proxy.cpp index cd448ea33d31281abdb0494e6bde2f331a7762aa..8319e04bfb608ed4cc02f7445d893b8eec83c23a 100644 --- a/window_scene/session/host/src/zidl/session_proxy.cpp +++ b/window_scene/session/host/src/zidl/session_proxy.cpp @@ -1650,6 +1650,43 @@ WSError SessionProxy::SetAspectRatio(float ratio) return static_cast(ret); } +/** @note @window.layout */ +WSError SessionProxy::SetContentAspectRatio(float ratio, bool isPersistent, bool needUpdateRect) +{ + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Failed to write interface token"); + return WSError::WS_ERROR_IPC_FAILED; + } + if (!data.WriteFloat(ratio)) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Failed to write ratio"); + return WSError::WS_ERROR_IPC_FAILED; + } + if (!data.WriteBool(isPersistent)) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Failed to write isPersistent"); + return WSError::WS_ERROR_IPC_FAILED; + } + if (!data.WriteBool(needUpdateRect)) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Failed to write needUpdateRect"); + return WSError::WS_ERROR_IPC_FAILED; + } + sptr remote = Remote(); + if (remote == nullptr) { + TLOGE(WmsLogTag::WMS_LAYOUT, "remote is null"); + return WSError::WS_ERROR_IPC_FAILED; + } + MessageParcel reply; + MessageOption option; + int sendRet = remote->SendRequest( + static_cast(SessionInterfaceCode::TRANS_ID_SET_CONTENT_ASPECT_RATIO), data, reply, option); + if (sendRet != ERR_NONE) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Failed to send request, error = %{public}d", sendRet); + return WSError::WS_ERROR_IPC_FAILED; + } + int32_t ret = reply.ReadInt32(); + return static_cast(ret); +} + WSError SessionProxy::UpdateWindowSceneAfterCustomAnimation(bool isAdd) { MessageParcel data; @@ -2403,6 +2440,34 @@ void SessionProxy::SetCustomDecorHeight(int32_t height) } } +WSError SessionProxy::SetDecorVisible(bool isVisible) +{ + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + TLOGE(WmsLogTag::WMS_DECOR, "Failed to write interface token"); + return WSError::WS_ERROR_IPC_FAILED; + } + if (!data.WriteBool(isVisible)) { + TLOGE(WmsLogTag::WMS_DECOR, "Failed to write isVisible"); + return WSError::WS_ERROR_IPC_FAILED; + } + sptr remote = Remote(); + if (remote == nullptr) { + TLOGE(WmsLogTag::DEFAULT, "remote is null"); + return WSError::WS_ERROR_IPC_FAILED; + } + MessageParcel reply; + MessageOption option; + int sendRet = remote->SendRequest( + static_cast(SessionInterfaceCode::TRANS_ID_SET_DECOR_VISIBLE), data, reply, option); + if (sendRet != ERR_NONE) { + TLOGE(WmsLogTag::WMS_DECOR, "Failed to send request, error = %{public}d", sendRet); + return WSError::WS_ERROR_IPC_FAILED; + } + int32_t ret = reply.ReadInt32(); + return static_cast(ret); +} + WSError SessionProxy::AdjustKeyboardLayout(const KeyboardLayoutParams& params) { MessageParcel data; diff --git a/window_scene/session/host/src/zidl/session_stub.cpp b/window_scene/session/host/src/zidl/session_stub.cpp index 65cc7f7fedc3ed189a4b7217e76f62619db406ac..5d5b44a87b5781730305c0158f8f7a0e2eb30a4a 100644 --- a/window_scene/session/host/src/zidl/session_stub.cpp +++ b/window_scene/session/host/src/zidl/session_stub.cpp @@ -143,6 +143,8 @@ int SessionStub::ProcessRemoteRequest(uint32_t code, MessageParcel& data, Messag return HandleGetTargetOrientationConfigInfo(data, reply); case static_cast(SessionInterfaceCode::TRANS_ID_SET_ASPECT_RATIO): return HandleSetAspectRatio(data, reply); + case static_cast(SessionInterfaceCode::TRANS_ID_SET_CONTENT_ASPECT_RATIO): + return HandleSetContentAspectRatio(data, reply); case static_cast(SessionInterfaceCode::TRANS_ID_UPDATE_WINDOW_ANIMATION_FLAG): return HandleSetWindowAnimationFlag(data, reply); case static_cast(SessionInterfaceCode::TRANS_ID_UPDATE_CUSTOM_ANIMATION): @@ -183,6 +185,8 @@ int SessionStub::ProcessRemoteRequest(uint32_t code, MessageParcel& data, Messag return HandleSetCallingSessionId(data, reply); case static_cast(SessionInterfaceCode::TRANS_ID_SET_CUSTOM_DECOR_HEIGHT): return HandleSetCustomDecorHeight(data, reply); + case static_cast(SessionInterfaceCode::TRANS_ID_SET_DECOR_VISIBLE): + return HandleSetDecorVisible(data, reply); case static_cast(SessionInterfaceCode::TRANS_ID_UPDATE_SESSION_PROPERTY): return HandleUpdatePropertyByAction(data, reply); case static_cast(SessionInterfaceCode::TRANS_ID_ADJUST_KEYBOARD_LAYOUT): @@ -1246,6 +1250,29 @@ int SessionStub::HandleSetAspectRatio(MessageParcel& data, MessageParcel& reply) return ERR_NONE; } +/** @note @window.layout */ +int SessionStub::HandleSetContentAspectRatio(MessageParcel& data, MessageParcel& reply) +{ + float ratio = 0.0f; + if (!data.ReadFloat(ratio)) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Failed to read ratio"); + return ERR_INVALID_DATA; + } + bool isPersistent = true; + if (!data.ReadBool(isPersistent)) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Failed to read isPersistent"); + return ERR_INVALID_DATA; + } + bool needUpdateRect = true; + if (!data.ReadBool(needUpdateRect)) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Failed to read needUpdateRect"); + return ERR_INVALID_DATA; + } + WSError ret = SetContentAspectRatio(ratio, isPersistent, needUpdateRect); + reply.WriteInt32(static_cast(ret)); + return ERR_NONE; +} + int SessionStub::HandleUpdateWindowSceneAfterCustomAnimation(MessageParcel& data, MessageParcel& reply) { WLOGD("HandleUpdateWindowSceneAfterCustomAnimation!"); @@ -1628,6 +1655,18 @@ int SessionStub::HandleSetCustomDecorHeight(MessageParcel& data, MessageParcel& return ERR_NONE; } +int SessionStub::HandleSetDecorVisible(MessageParcel& data, MessageParcel& reply) +{ + bool isVisible = false; + if (!data.ReadBool(isVisible)) { + TLOGE(WmsLogTag::WMS_DECOR, "Failed to read isVisible"); + return ERR_INVALID_DATA; + } + WSError ret = SetDecorVisible(isVisible); + reply.WriteInt32(static_cast(ret)); + return ERR_NONE; +} + int SessionStub::HandleAdjustKeyboardLayout(MessageParcel& data, MessageParcel& reply) { TLOGD(WmsLogTag::WMS_KEYBOARD, "run HandleAdjustKeyboardLayout!"); diff --git a/window_scene/test/mock/mock_session.h b/window_scene/test/mock/mock_session.h index defee81b715fb05e15e3aacbb53b4e99a7e3cb33..c35aec51c05e3ceaeb50aba8d28e503f8a064071 100644 --- a/window_scene/test/mock/mock_session.h +++ b/window_scene/test/mock/mock_session.h @@ -71,6 +71,7 @@ public: MOCK_METHOD(WSError, ProcessPointDownSession, (int32_t x, int32_t y), (override)); MOCK_CONST_METHOD2(ConvertGlobalRectToRelative, WSRect(const WSRect& globalRect, DisplayId targetDisplayId)); MOCK_METHOD1(SetIsShowDecorInFreeMultiWindow, WSError(bool isShow)); + MOCK_METHOD(WSError, SetContentAspectRatio, (float ratio, bool isPersistent, bool needUpdateRect), (override)); }; } // namespace Rosen } // namespace OHOS diff --git a/window_scene/test/mock/mock_session_stub.h b/window_scene/test/mock/mock_session_stub.h index 5db375bd981c47cf99dc00c0f7b3b12d0d0c8751..cbc0f6e02cf95c5a7b02f11fb75cd9a52bb123a4 100644 --- a/window_scene/test/mock/mock_session_stub.h +++ b/window_scene/test/mock/mock_session_stub.h @@ -88,6 +88,8 @@ public: MOCK_METHOD1(SendFbActionEvent, WSError(const std::string& action)); MOCK_METHOD1(RestoreFbMainWindow, WMError(const std::shared_ptr& want)); MOCK_METHOD1(UpdateIsShowDecorInFreeMultiWindow, WSError(bool& isShow)); + MOCK_METHOD(WSError, SetContentAspectRatio, (float ratio, bool isPersistent, bool needUpdateRect), (override)); + MOCK_METHOD(WSError, SetDecorVisible, (bool isVisible), (override)); }; } // namespace Rosen } // namespace OHOS diff --git a/window_scene/test/unittest/BUILD.gn b/window_scene/test/unittest/BUILD.gn index 61db84a37b6799e2feeb9b4d9dd9be23674b8330..08faedc63eb11e4932e1c4f16f42965b7f755a02 100644 --- a/window_scene/test/unittest/BUILD.gn +++ b/window_scene/test/unittest/BUILD.gn @@ -58,6 +58,7 @@ group("unittest") { ":ws_session_stage_stub_test", ":ws_session_stub_mock_test", ":ws_session_stub_property_test", + ":ws_session_utils_test", ":ws_ssmgr_specific_window_test", ":ws_sub_session_lifecycle_test", ":ws_system_session_lifecycle_test", @@ -72,10 +73,10 @@ group("unittest") { ":ws_window_scene_config_test", "animation:ws_scene_session_animation_test", "animation:ws_session_proxy_animation_test", - "animation:ws_window_session_property_animation_test", - "animation:ws_ui_effect_controller_test", "animation:ws_ui_effect_controller_proxy_test", "animation:ws_ui_effect_controller_stub_test", + "animation:ws_ui_effect_controller_test", + "animation:ws_window_session_property_animation_test", "event_distribution:ws_intention_event_manager_test", "event_distribution:ws_scene_input_manager_test", "event_distribution:ws_scene_session_dirty_manager_test2", @@ -94,8 +95,8 @@ group("unittest") { deps += [ ":ws_hidumper_controller_test", ":ws_keyboard_session_test", - ":ws_mock_session_manager_service_test", ":ws_main_session_test", + ":ws_mock_session_manager_service_test", ":ws_pc_fold_screen_controller_test", ":ws_scene_session_lifecycle_test", ":ws_scene_session_manager_kiosk_test", @@ -199,7 +200,7 @@ ohos_unittest("ws_system_session_test") { sources = [ "${window_base_path}/window_scene/test/mock/mock_accesstoken_kit.cpp", - "system_session_test.cpp" + "system_session_test.cpp", ] deps = [ ":ws_unittest_common" ] @@ -396,7 +397,8 @@ ohos_unittest("ws_session_test") { defines = [] if (window_manager_feature_asbng_path_enable) { defines += [ "WINDOW_ATOMIC_SERVICE_ATTRIBUTION_ENABLE" ] - cflags += [ "-DACE_ENGINE_PLUGIN_PATH=\"${window_manager_feature_asbng_path}\"" ] + cflags += + [ "-DACE_ENGINE_PLUGIN_PATH=\"${window_manager_feature_asbng_path}\"" ] } } @@ -719,7 +721,8 @@ ohos_unittest("ws_ssmgr_specific_window_test") { ohos_unittest("ws_scene_session_manager_proxy_test") { module_out_path = module_out_path - configs = [ "${window_base_path}/window_scene/session:ui_effect_public_config" ] + configs = + [ "${window_base_path}/window_scene/session:ui_effect_public_config" ] sources = [ "../mock/mock_message_parcel.cpp", @@ -849,7 +852,8 @@ ohos_unittest("ws_scene_session_manager_stub_test") { ohos_unittest("ws_scene_session_manager_stub_test2") { module_out_path = module_out_path - configs = [ "${window_base_path}/window_scene/session:ui_effect_public_config" ] + configs = + [ "${window_base_path}/window_scene/session:ui_effect_public_config" ] sources = [ "${window_base_path}/window_scene/test/mock/mock_message_parcel.cpp", @@ -940,14 +944,15 @@ ohos_unittest("ws_scene_session_lifecycle_test") { external_deps = test_external_deps external_deps += [ "ability_base:session_info", - "ability_runtime:process_options" + "ability_runtime:process_options", ] cflags = [] defines = [] if (window_manager_feature_asbng_path_enable) { defines += [ "WINDOW_ATOMIC_SERVICE_ATTRIBUTION_ENABLE" ] - cflags += [ "-DACE_ENGINE_PLUGIN_PATH=\"${window_manager_feature_asbng_path}\"" ] + cflags += + [ "-DACE_ENGINE_PLUGIN_PATH=\"${window_manager_feature_asbng_path}\"" ] } } @@ -1362,9 +1367,9 @@ ohos_unittest("ws_mock_session_manager_service_test") { include_dirs = [ "../mock" ] - sources = [ + sources = [ "${window_base_path}/window_scene/test/mock/mock_accesstoken_kit.cpp", - "mock_session_manager_service_test.cpp" + "mock_session_manager_service_test.cpp", ] deps = [ @@ -1577,4 +1582,22 @@ ohos_unittest("ws_session_coordinate_helper_test") { external_deps = test_external_deps } + +ohos_unittest("ws_session_utils_test") { + module_out_path = module_out_path + + include_dirs = [ + "${window_base_path}/test/common/utils/include/", + "${window_base_path}/window_scene/session/host/include/", + "${window_base_path}/window_scene/test/mock/", + ] + + sources = [ "session_utils_test.cpp" ] + + cflags_cc = [ "-Wno-thread-safety" ] + + deps = [ ":ws_unittest_common" ] + + external_deps = test_external_deps +} ## Build ws_unittest_common.a }}} diff --git a/window_scene/test/unittest/layout/layout_controller_test.cpp b/window_scene/test/unittest/layout/layout_controller_test.cpp index 440b0be776dbc0786e73765beb65b54099efb5fa..e53d58b14acefa8de683730bfea92d67a5940adf 100644 --- a/window_scene/test/unittest/layout/layout_controller_test.cpp +++ b/window_scene/test/unittest/layout/layout_controller_test.cpp @@ -158,60 +158,6 @@ HWTEST_F(LayoutControllerTest, ConvertGlobalRectToRelative, TestSize.Level1) EXPECT_EQ(retRect, globalRect); } -/** - * @tc.name: AdjustRectByAspectRatio - * @tc.desc: AdjustRectByAspectRatio function01 - * @tc.type: FUNC - */ -HWTEST_F(LayoutControllerTest, AdjustRectByAspectRatio, TestSize.Level1) -{ - SessionInfo info; - info.abilityName_ = "AdjustRectByAspectRatio"; - info.bundleName_ = "AdjustRectByAspectRatio"; - info.isSystem_ = false; - sptr session = sptr::MakeSptr(info, nullptr); - session->GetLayoutController()->SetSystemConfigFunc([session] { - return session->GetSystemConfig(); - }); - WSRect rect; - EXPECT_EQ(false, session->GetLayoutController()->AdjustRectByAspectRatio(rect, false)); - session->property_->SetWindowMode(WindowMode::WINDOW_MODE_UNDEFINED); - EXPECT_EQ(false, session->GetLayoutController()->AdjustRectByAspectRatio(rect, false)); - session->property_->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING); - session->property_->SetWindowType(WindowType::APP_MAIN_WINDOW_END); - EXPECT_EQ(false, session->GetLayoutController()->AdjustRectByAspectRatio(rect, false)); - session->property_->SetWindowType(WindowType::APP_MAIN_WINDOW_BASE); - EXPECT_EQ(false, session->GetLayoutController()->AdjustRectByAspectRatio(rect, false)); -} - -/** - * @tc.name: AdjustRectByAspectRatio01 - * @tc.desc: AdjustRectByAspectRatio function01 - * @tc.type: FUNC - */ -HWTEST_F(LayoutControllerTest, AdjustRectByAspectRatio01, TestSize.Level1) -{ - SessionInfo info; - info.abilityName_ = "AdjustRectByAspectRatio01"; - info.bundleName_ = "AdjustRectByAspectRatio01"; - info.isSystem_ = false; - sptr session = sptr::MakeSptr(info, nullptr); - WSRect rect; - session->property_->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING); - info.windowType_ = static_cast(WindowType::APP_MAIN_WINDOW_BASE); - session->Session::SetAspectRatio(0.5f); - EXPECT_NE(nullptr, DisplayManager::GetInstance().GetDefaultDisplay()); - - SystemSessionConfig systemConfig; - systemConfig.isSystemDecorEnable_ = true; - systemConfig.decorWindowModeSupportType_ = 2; - session->SetSystemConfig(systemConfig); - EXPECT_EQ(true, session->GetLayoutController()->AdjustRectByAspectRatio(rect, true)); - - systemConfig.isSystemDecorEnable_ = false; - EXPECT_EQ(true, session->GetLayoutController()->AdjustRectByAspectRatio(rect, false)); -} - /** * @tc.name: SetSystemConfigFunc * @tc.desc: SetSystemConfigFunc @@ -230,6 +176,49 @@ HWTEST_F(LayoutControllerTest, SetSystemConfigFunc, TestSize.Level1) layoutController_->getSystemConfigFunc_(); EXPECT_EQ(layoutController_->GetSessionRect(), rect); } + +/** + * @tc.name: TestAdjustRectByAspectRatioAbnormalCases + * @tc.desc: Verify AdjustRectByAspectRatio handles abnormal cases correctly + * @tc.type: FUNC + */ +HWTEST_F(LayoutControllerTest, TestAdjustRectByAspectRatioAbnormalCases, TestSize.Level1) +{ + WSRect rect{10, 20, 200, 200}; + WindowDecoration decor{0, 0, 0, 0}; + + // Case 1: sessionProperty is null + layoutController_->sessionProperty_ = nullptr; + EXPECT_EQ(layoutController_->AdjustRectByAspectRatio(rect, decor), rect); + + auto prop = sptr::MakeSptr(); + layoutController_->sessionProperty_ = prop; + + // Case 2: mode != FLOATING + prop->SetWindowMode(WindowMode::WINDOW_MODE_UNDEFINED); + EXPECT_EQ(layoutController_->AdjustRectByAspectRatio(rect, decor), rect); + + // Case 3: Not main window + prop->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING); + prop->SetWindowType(WindowType::APP_SUB_WINDOW_BASE); + EXPECT_EQ(layoutController_->AdjustRectByAspectRatio(rect, decor), rect); + + prop->SetWindowType(WindowType::WINDOW_TYPE_APP_MAIN_WINDOW); + + // Case 4: display is null + prop->SetDisplayId(DISPLAY_ID_INVALID); + EXPECT_EQ(layoutController_->AdjustRectByAspectRatio(rect, decor), rect); + + // Case 5: Success + DisplayManager::GetInstance().GetDisplayByScreen(0); + layoutController_->aspectRatio_ = 2.0f; + prop->SetDisplayId(0); + layoutController_->SetSystemConfigFunc([] { + SystemSessionConfig systemConfig; + return systemConfig; + }); + EXPECT_NE(layoutController_->AdjustRectByAspectRatio(rect, decor), rect); +} } // namespace } // namespace Rosen } // namespace OHOS diff --git a/window_scene/test/unittest/layout/scene_session_layout_test.cpp b/window_scene/test/unittest/layout/scene_session_layout_test.cpp index 94167894c704ee95447d9b84384e86b0890afbae..374cb9fe593bea63a18b1ef13b6dc2259cb4d46d 100644 --- a/window_scene/test/unittest/layout/scene_session_layout_test.cpp +++ b/window_scene/test/unittest/layout/scene_session_layout_test.cpp @@ -252,97 +252,6 @@ HWTEST_F(SceneSessionLayoutTest, NotifyClientToUpdateRect, TestSize.Level1) EXPECT_EQ(WSError::WS_OK, session->NotifyClientToUpdateRect("SceneSessionLayoutTest", nullptr)); } -/** - * @tc.name: CheckAspectRatioValid - * @tc.desc: CheckAspectRatioValid function01 - * @tc.type: FUNC - */ -HWTEST_F(SceneSessionLayoutTest, CheckAspectRatioValid, TestSize.Level0) -{ - SessionInfo info; - info.abilityName_ = "CheckAspectRatioValid"; - info.bundleName_ = "CheckAspectRatioValid"; - info.isSystem_ = false; - sptr session = sptr::MakeSptr(info, nullptr); - WindowLimits windowLimits; - ASSERT_NE(session->GetSessionProperty(), nullptr); - session->GetSessionProperty()->SetWindowLimits(windowLimits); - - SystemSessionConfig systemConfig; - systemConfig.isSystemDecorEnable_ = false; - session->SetSystemConfig(systemConfig); - EXPECT_EQ(false, session->IsDecorEnable()); - - windowLimits.minWidth_ = 0; - windowLimits.minHeight_ = 0; - EXPECT_EQ(WSError::WS_OK, session->SetAspectRatio(0.0f)); - - windowLimits.minWidth_ = 1; - windowLimits.maxHeight_ = 0; - windowLimits.minHeight_ = 1; - windowLimits.maxWidth_ = 0; - EXPECT_EQ(WSError::WS_OK, session->SetAspectRatio(0.0f)); - - windowLimits.maxHeight_ = 1; - windowLimits.maxWidth_ = 1; - EXPECT_EQ(WSError::WS_OK, session->SetAspectRatio(1.0f)); - - windowLimits.maxHeight_ = 10000; - windowLimits.minHeight_ = -10000; - EXPECT_EQ(WSError::WS_OK, session->SetAspectRatio(0.0f)); - - windowLimits.maxHeight_ = 10000; - windowLimits.minHeight_ = -10000; - EXPECT_EQ(WSError::WS_OK, session->SetAspectRatio(0.0f)); - - sptr property = sptr::MakeSptr(); - WindowLimits limits = { 8, 1, 6, 1, 1, 1.0f, 1.0f }; - property->SetWindowLimits(limits); - session->SetSessionProperty(property); - EXPECT_EQ(WSError::WS_ERROR_INVALID_PARAM, session->SetAspectRatio(0.1f)); - EXPECT_EQ(WSError::WS_ERROR_INVALID_PARAM, session->SetAspectRatio(10.0f)); -} - -/** - * @tc.name: CheckAspectRatioValid02 - * @tc.desc: CheckAspectRatioValid - * @tc.type: FUNC - */ -HWTEST_F(SceneSessionLayoutTest, CheckAspectRatioValid02, TestSize.Level0) -{ - SessionInfo info; - info.abilityName_ = "CheckAspectRatioValid02"; - info.bundleName_ = "CheckAspectRatioValid02"; - info.isSystem_ = false; - sptr sceneSession = sptr::MakeSptr(info, nullptr); - sptr property = sptr::MakeSptr(); - sceneSession->SetSessionProperty(property); - - WindowLimits windowLimits; - sceneSession->GetSessionProperty()->SetWindowLimits(windowLimits); - - SystemSessionConfig systemConfig; - systemConfig.isSystemDecorEnable_ = false; - sceneSession->SetSystemConfig(systemConfig); - EXPECT_EQ(false, sceneSession->IsDecorEnable()); - - windowLimits.minWidth_ = 0; - windowLimits.minHeight_ = 0; - EXPECT_EQ(WSError::WS_OK, sceneSession->SetAspectRatio(0.0f)); - - windowLimits.minWidth_ = 1; - windowLimits.minHeight_ = 2; - EXPECT_EQ(WSError::WS_OK, sceneSession->SetAspectRatio(0.0f)); - - windowLimits.minWidth_ = 2; - windowLimits.minHeight_ = 1; - EXPECT_EQ(WSError::WS_OK, sceneSession->SetAspectRatio(0.0f)); - - windowLimits.minWidth_ = 1; - windowLimits.minHeight_ = 2; - EXPECT_EQ(WSError::WS_OK, sceneSession->SetAspectRatio(1.0f)); -} - /** * @tc.name: NotifyClientToUpdateRectTask * @tc.desc: NotifyClientToUpdateRectTask function @@ -581,56 +490,6 @@ HWTEST_F(SceneSessionLayoutTest, SetAspectRatio7, TestSize.Level0) ASSERT_EQ(result, WSError::WS_ERROR_INVALID_PARAM); } -/** - * @tc.name: SetAspectRatio8 - * @tc.desc: normal function - * @tc.type: FUNC - */ -HWTEST_F(SceneSessionLayoutTest, SetAspectRatio8, TestSize.Level1) -{ - SessionInfo info; - info.abilityName_ = "SetAspectRatio8"; - info.bundleName_ = "SetAspectRatio8"; - sptr sceneSession = sptr::MakeSptr(info, nullptr); - sceneSession->isActive_ = true; - - float ratio = 0.1; - sptr property = sptr::MakeSptr(); - property->SetWindowType(WindowType::APP_MAIN_WINDOW_BASE); - WindowLimits limits; - limits.maxHeight_ = 10; - limits.minWidth_ = 0; - property->SetWindowLimits(limits); - sceneSession->SetSessionProperty(property); - auto result = sceneSession->SetAspectRatio(ratio); - ASSERT_EQ(result, WSError::WS_ERROR_INVALID_PARAM); -} - -/** - * @tc.name: SetAspectRatio9 - * @tc.desc: normal function - * @tc.type: FUNC - */ -HWTEST_F(SceneSessionLayoutTest, SetAspectRatio9, TestSize.Level1) -{ - SessionInfo info; - info.abilityName_ = "SetAspectRatio9"; - info.bundleName_ = "SetAspectRatio9"; - sptr sceneSession = sptr::MakeSptr(info, nullptr); - sceneSession->isActive_ = true; - - float ratio = 0.1; - sptr property = sptr::MakeSptr(); - property->SetWindowType(WindowType::APP_MAIN_WINDOW_BASE); - WindowLimits limits; - limits.maxHeight_ = 10; - limits.minWidth_ = 10; - property->SetWindowLimits(limits); - sceneSession->SetSessionProperty(property); - auto result = sceneSession->SetAspectRatio(ratio); - ASSERT_EQ(result, WSError::WS_ERROR_INVALID_PARAM); -} - /** * @tc.name: SaveAspectRatio * @tc.desc: SaveAspectRatio diff --git a/window_scene/test/unittest/move_drag_controller_test.cpp b/window_scene/test/unittest/move_drag_controller_test.cpp index 2b42064bf77ba627ccd937738158d4b543ef4f7f..89f669faa380ad1c8d3c3b034b5a2e06732207fb 100644 --- a/window_scene/test/unittest/move_drag_controller_test.cpp +++ b/window_scene/test/unittest/move_drag_controller_test.cpp @@ -604,28 +604,104 @@ HWTEST_F(MoveDragControllerTest, CalcFreeformTranslateLimits01, TestSize.Level0) } /** - * @tc.name: CalcFixedAspectRatioTranslateLimits01 - * @tc.desc: test function : CalcFixedAspectRatioTranslateLimits01 - * @tc.type: FUNC - */ -HWTEST_F(MoveDragControllerTest, CalcFixedAspectRatioTranslateLimits01, TestSize.Level1) -{ - moveDragController->limits_ = { 30, 60, 30, 60, 2.0, 2.0 }; - moveDragController->aspectRatio_ = 1.0f; - AreaType type = AreaType::RIGHT; - ASSERT_TRUE((moveDragController != nullptr)); - moveDragController->isDecorEnable_ = true; - moveDragController->CalcFixedAspectRatioTranslateLimits(type); - moveDragController->isDecorEnable_ = false; - moveDragController->CalcFixedAspectRatioTranslateLimits(type); - moveDragController->limits_ = { 60, 60, 60, 60, 2.0, 2.0 }; - moveDragController->CalcFixedAspectRatioTranslateLimits(type); - type = AreaType::LEFT; - moveDragController->CalcFixedAspectRatioTranslateLimits(type); - type = AreaType::BOTTOM; - moveDragController->CalcFixedAspectRatioTranslateLimits(type); - type = AreaType::TOP; - moveDragController->CalcFixedAspectRatioTranslateLimits(type); + * @tc.name: CalcFixedAspectRatioTranslateLimitsAbnormalBranches + * @tc.desc: Verify early-return and default branch (invalid AreaType) behaviors + * @tc.type: FUNC + */ +HWTEST_F(MoveDragControllerTest, CalcFixedAspectRatioTranslateLimitsAbnormalBranches, TestSize.Level1) +{ + moveDragController->limits_ = WindowLimits(300, 150, 100, 50, FLT_MAX, 0.0f); + moveDragController->decoration_ = {0, 0, 0, 0}; // no decoration + moveDragController->moveDragProperty_.originalRect_ = {0, 0, 200, 120}; + moveDragController->minTranX_ = INT32_MIN; + moveDragController->minTranY_ = INT32_MIN; + moveDragController->maxTranX_ = INT32_MAX; + moveDragController->maxTranY_ = INT32_MAX; + + // Case 1: aspectRatio_ is near zero -> early return, no modification + moveDragController->aspectRatio_ = 0.0f; + moveDragController->CalcFixedAspectRatioTranslateLimits(AreaType::LEFT); + EXPECT_EQ(moveDragController->minTranX_, INT32_MIN); + EXPECT_EQ(moveDragController->minTranY_, INT32_MIN); + EXPECT_EQ(moveDragController->maxTranX_, INT32_MAX); + EXPECT_EQ(moveDragController->maxTranY_, INT32_MAX); + + // Case 2: invalid AreaType -> no modification + moveDragController->aspectRatio_ = 2.0f; + moveDragController->CalcFixedAspectRatioTranslateLimits(AreaType::UNDEFINED); + EXPECT_EQ(moveDragController->minTranX_, INT32_MIN); + EXPECT_EQ(moveDragController->minTranY_, INT32_MIN); + EXPECT_EQ(moveDragController->maxTranX_, INT32_MAX); + EXPECT_EQ(moveDragController->maxTranY_, INT32_MAX); +} + +/** + * @tc.name: CalcFixedAspectRatioTranslateLimitsNormalBranches + * @tc.desc: Verify correct translate limits for all handled AreaType when aspectRatio is valid + * @tc.type: FUNC + */ +HWTEST_F(MoveDragControllerTest, CalcFixedAspectRatioTranslateLimitsNormalBranches, TestSize.Level1) +{ + moveDragController->limits_ = WindowLimits(300, 150, 100, 50, FLT_MAX, 0.0f); // compatible with aspectRatio = 2.0 + moveDragController->decoration_ = {0, 0, 0, 0}; // no decoration + moveDragController->moveDragProperty_.originalRect_ = {0, 0, 200, 120}; + moveDragController->aspectRatio_ = 2.0f; + + // Case 1: LEFT + moveDragController->CalcFixedAspectRatioTranslateLimits(AreaType::LEFT); + EXPECT_EQ(moveDragController->minTranX_, -100); + EXPECT_EQ(moveDragController->maxTranX_, 100); + EXPECT_EQ(moveDragController->minTranY_, -70); + EXPECT_EQ(moveDragController->maxTranY_, 30); + + // Case 2: LEFT_BOTTOM + moveDragController->CalcFixedAspectRatioTranslateLimits(AreaType::LEFT_BOTTOM); + EXPECT_EQ(moveDragController->minTranX_, -100); + EXPECT_EQ(moveDragController->maxTranX_, 100); + EXPECT_EQ(moveDragController->minTranY_, -70); + EXPECT_EQ(moveDragController->maxTranY_, 30); + + // Case 3: LEFT_TOP + moveDragController->CalcFixedAspectRatioTranslateLimits(AreaType::LEFT_TOP); + EXPECT_EQ(moveDragController->minTranX_, -100); + EXPECT_EQ(moveDragController->maxTranX_, 100); + EXPECT_EQ(moveDragController->minTranY_, -30); + EXPECT_EQ(moveDragController->maxTranY_, 70); + + // Case 4: RIGHT + moveDragController->CalcFixedAspectRatioTranslateLimits(AreaType::RIGHT); + EXPECT_EQ(moveDragController->minTranX_, -100); + EXPECT_EQ(moveDragController->maxTranX_, 100); + EXPECT_EQ(moveDragController->minTranY_, -70); + EXPECT_EQ(moveDragController->maxTranY_, 30); + + // Case 5: RIGHT_BOTTOM + moveDragController->CalcFixedAspectRatioTranslateLimits(AreaType::RIGHT_BOTTOM); + EXPECT_EQ(moveDragController->minTranX_, -100); + EXPECT_EQ(moveDragController->maxTranX_, 100); + EXPECT_EQ(moveDragController->minTranY_, -70); + EXPECT_EQ(moveDragController->maxTranY_, 30); + + // Case 6: BOTTOM + moveDragController->CalcFixedAspectRatioTranslateLimits(AreaType::BOTTOM); + EXPECT_EQ(moveDragController->minTranX_, -100); + EXPECT_EQ(moveDragController->maxTranX_, 100); + EXPECT_EQ(moveDragController->minTranY_, -70); + EXPECT_EQ(moveDragController->maxTranY_, 30); + + // Case 7: RIGHT_TOP + moveDragController->CalcFixedAspectRatioTranslateLimits(AreaType::RIGHT_TOP); + EXPECT_EQ(moveDragController->minTranX_, -100); + EXPECT_EQ(moveDragController->maxTranX_, 100); + EXPECT_EQ(moveDragController->minTranY_, -30); + EXPECT_EQ(moveDragController->maxTranY_, 70); + + // Case 8: TOP + moveDragController->CalcFixedAspectRatioTranslateLimits(AreaType::TOP); + EXPECT_EQ(moveDragController->minTranX_, -100); + EXPECT_EQ(moveDragController->maxTranX_, 100); + EXPECT_EQ(moveDragController->minTranY_, -30); + EXPECT_EQ(moveDragController->maxTranY_, 70); } /** @@ -1795,6 +1871,53 @@ HWTEST_F(MoveDragControllerTest, UpdateSubWindowGravityWhenFollow01, TestSize.Le modifier = surfaceNode->GetModifierByType(ModifierNG::RSModifierType::CLIP_TO_FRAME); EXPECT_NE(modifier, nullptr); } + +/** + * @tc.name: TestCalcDragTargetRect + * @tc.desc: Verify normal flows of CalcDragTargetRect + * @tc.type: FUNC + */ +HWTEST_F(MoveDragControllerTest, TestCalcDragTargetRect, TestSize.Level1) +{ + WSRect originalRect = {0, 0, 200, 100}; + moveDragController->moveDragProperty_.originalRect_ = originalRect; + moveDragController->limits_ = WindowLimits(400, 400, 200, 50, FLT_MAX, 0.0f); + moveDragController->decoration_ = {0, 0, 0, 0}; + moveDragController->type_ = AreaType::RIGHT; + + std::shared_ptr pointerEvent = MMI::PointerEvent::Create(); + pointerEvent->SetTargetDisplayId(0); + + // Case 1: DRAG_START → Adjust originalRect_ and set targetRect_ = originalRect_ + moveDragController->moveDragProperty_.targetRect_ = WSRect::EMPTY_RECT; + SizeChangeReason reason = SizeChangeReason::DRAG_START; + moveDragController->CalcDragTargetRect(pointerEvent, reason); + EXPECT_EQ(moveDragController->moveDragProperty_.targetRect_, originalRect); + + reason = SizeChangeReason::DRAG; + + // Case 2: Cross-display disabled & displayId mismatch → no update + moveDragController->moveDragProperty_.targetRect_ = WSRect::EMPTY_RECT; + moveDragController->winType_ = WindowType::SYSTEM_WINDOW_BASE; + moveDragController->moveDragStartDisplayId_ = 1; + moveDragController->CalcDragTargetRect(pointerEvent, reason); + EXPECT_EQ(moveDragController->moveDragProperty_.targetRect_, WSRect::EMPTY_RECT); + + // Case 3: Cross-display enabled but aspect ratio is 0 + moveDragController->moveDragProperty_.targetRect_ = WSRect::EMPTY_RECT; + moveDragController->winType_ = WindowType::WINDOW_TYPE_FLOAT; + moveDragController->aspectRatio_ = 0.0f; + moveDragController->CalcDragTargetRect(pointerEvent, reason); + EXPECT_NE(moveDragController->moveDragProperty_.targetRect_, WSRect::EMPTY_RECT); + + // Case 4: PointerEvent‘s displayId equals moveDragStartDisplayId and aspect ratio is not 0 + moveDragController->moveDragProperty_.targetRect_ = WSRect::EMPTY_RECT; + pointerEvent->SetTargetDisplayId(0); + moveDragController->moveDragStartDisplayId_ = 0; + moveDragController->aspectRatio_ = 1.0f; + moveDragController->CalcDragTargetRect(pointerEvent, reason); + EXPECT_NE(moveDragController->moveDragProperty_.targetRect_, WSRect::EMPTY_RECT); +} } // namespace } // namespace Rosen } // namespace OHOS \ No newline at end of file diff --git a/window_scene/test/unittest/scene_session_test2.cpp b/window_scene/test/unittest/scene_session_test2.cpp index 4044cac88daf85a4b4e29dde253c65e76bdbd5d3..f3f0f21989f14977b3f632de15b5e8c490d7576c 100644 --- a/window_scene/test/unittest/scene_session_test2.cpp +++ b/window_scene/test/unittest/scene_session_test2.cpp @@ -1343,7 +1343,6 @@ HWTEST_F(SceneSessionTest2, TransferPointerEvent03, TestSize.Level1) float ratio = 0.0; bool isDecor = true; float vpr = 0.0; - sceneSession->GetLayoutController()->AdjustRectByLimits(limits, ratio, isDecor, vpr, rect); sceneSession->SetPipActionEvent("pointerEvent", 0); auto property = sptr::MakeSptr(); @@ -1356,7 +1355,6 @@ HWTEST_F(SceneSessionTest2, TransferPointerEvent03, TestSize.Level1) property->SetWindowType(WindowType::WINDOW_TYPE_PIP); property->SetWindowMode(WindowMode::WINDOW_MODE_PIP); sceneSession->SetSessionProperty(property); - sceneSession->GetLayoutController()->AdjustRectByLimits(limits, ratio, false, vpr, rect); ASSERT_EQ(WSError::WS_OK, sceneSession->SetPipActionEvent("pointerEvent", 0)); } diff --git a/window_scene/test/unittest/scene_session_test6.cpp b/window_scene/test/unittest/scene_session_test6.cpp index 0737acaa2235c4753b51d29c6546719bf8e9b982..4a02ea0a12ff1e1f6f4cf546a9bc1bd53fe45e7e 100644 --- a/window_scene/test/unittest/scene_session_test6.cpp +++ b/window_scene/test/unittest/scene_session_test6.cpp @@ -1273,6 +1273,75 @@ HWTEST_F(SceneSessionTest6, SetSupportEnterWaterfallMode, Function | SmallTest | session->SetSupportEnterWaterfallMode(true); EXPECT_TRUE(session->sessionStage_ != nullptr); } + +/** + * @tc.name: TestSetContentAspectRatio + * @tc.desc: Verify SetContentAspectRatio covers all branches + * @tc.type: FUNC + */ +HWTEST_F(SceneSessionTest6, TestSetContentAspectRatio, TestSize.Level1) +{ + SessionInfo info; + auto session = sptr::MakeSptr(info, nullptr); + + // Case 1: sessionProperty is null + session->property_ = nullptr; + auto result = session->SetContentAspectRatio(1.5f, true, true); + EXPECT_EQ(result, WSError::WS_ERROR_NULLPTR); + + // Case 2: aspect ratio is invalid + session->property_ = sptr::MakeSptr(); + WindowLimits limits(400, 200, 200, 100, FLT_MAX, 0.0f); + session->property_->SetWindowLimits(limits); + result = session->SetContentAspectRatio(0.5f, true, true); + EXPECT_EQ(result, WSError::WS_ERROR_INVALID_PARAM); + + // Case 3: aspect ratio is valid, moveDragController is null + session->moveDragController_ = nullptr; + result = session->SetContentAspectRatio(2.0f, false, false); + EXPECT_EQ(result, WSError::WS_OK); + + // Case 4: aspect ratio is valid, moveDragController is not null + session->moveDragController_ = + sptr::MakeSptr(session->GetPersistentId(), session->GetWindowType()); + result = session->SetContentAspectRatio(2.0f, true, true); + EXPECT_EQ(result, WSError::WS_OK); +} + +/** + * @tc.name: TestGetWindowDecoration + * @tc.desc: Verify GetWindowDecoration covers all branches + * @tc.type: FUNC + */ +HWTEST_F(SceneSessionTest6, TestGetWindowDecoration, TestSize.Level1) +{ + SessionInfo info; + auto session = sptr::MakeSptr(info, nullptr); + auto prop = session->GetSessionProperty(); + + WindowDecoration emptyDecor{0, 0, 0, 0}; + + // Case 1: Not visible + session->SetDecorVisible(false); + auto decor = session->GetWindowDecoration(); + EXPECT_EQ(decor, emptyDecor); + + // Case 2: Not enabled + session->SetDecorVisible(true); + session->systemConfig_.isSystemDecorEnable_ = false; + decor = session->GetWindowDecoration(); + EXPECT_EQ(decor, emptyDecor); + + prop->SetWindowType(WindowType::WINDOW_TYPE_APP_MAIN_WINDOW); + prop->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING); + session->systemConfig_.decorWindowModeSupportType_ = WindowModeSupport::WINDOW_MODE_SUPPORT_ALL; + session->systemConfig_.isSystemDecorEnable_ = true; + + // Case 3: display is null + prop->SetDisplayId(DISPLAY_ID_INVALID); + decor = session->GetWindowDecoration(); + EXPECT_EQ(decor, emptyDecor); +} } // namespace } // namespace Rosen } // namespace OHOS \ No newline at end of file diff --git a/window_scene/test/unittest/session_proxy_test.cpp b/window_scene/test/unittest/session_proxy_test.cpp index 393eef5244241af078601b15b9da81fa517dd3e0..6579c03c4dee72492bfd251c4b544314e460f8be 100755 --- a/window_scene/test/unittest/session_proxy_test.cpp +++ b/window_scene/test/unittest/session_proxy_test.cpp @@ -2063,6 +2063,85 @@ HWTEST_F(SessionProxyTest, GetAppHookWindowInfoFromServer, TestSize.Level1) MockMessageParcel::ClearAllErrorFlag(); GTEST_LOG_(INFO) << "SessionProxyTest: GetAppHookWindowInfoFromServer end"; } + +/** + * @tc.name: TestSetContentAspectRatio + * @tc.desc: Test SetContentAspectRatio behavior in various IPC scenarios + * @tc.type: FUNC + */ +HWTEST_F(SessionProxyTest, TestSetContentAspectRatio, TestSize.Level1) +{ + auto mockRemote = sptr::MakeSptr(); + auto sessionProxy = sptr::MakeSptr(mockRemote); + float ratio = 1.5f; + bool isPersistent = true; + bool needUpdateRect = false; + + // Case 1: Failed to write interface token + MockMessageParcel::SetWriteInterfaceTokenErrorFlag(true); + EXPECT_EQ(WSError::WS_ERROR_IPC_FAILED, sessionProxy->SetContentAspectRatio(ratio, isPersistent, needUpdateRect)); + MockMessageParcel::SetWriteInterfaceTokenErrorFlag(false); + + // Case 2: Failed to write ratio + MockMessageParcel::SetWriteFloatErrorFlag(true); + EXPECT_EQ(WSError::WS_ERROR_IPC_FAILED, sessionProxy->SetContentAspectRatio(ratio, isPersistent, needUpdateRect)); + MockMessageParcel::SetWriteFloatErrorFlag(false); + + // Case 3: Failed to write isPersistent and needUpdateRect + MockMessageParcel::SetWriteBoolErrorFlag(true); + EXPECT_EQ(WSError::WS_ERROR_IPC_FAILED, sessionProxy->SetContentAspectRatio(ratio, isPersistent, needUpdateRect)); + MockMessageParcel::SetWriteBoolErrorFlag(false); + + // Case 4: remote is nullptr + sptr nullProxy = sptr::MakeSptr(nullptr); + EXPECT_EQ(WSError::WS_ERROR_IPC_FAILED, nullProxy->SetContentAspectRatio(ratio, isPersistent, needUpdateRect)); + + // Case 5: Failed to send request + mockRemote->sendRequestResult_ = ERR_TRANSACTION_FAILED; + sptr failProxy = sptr::MakeSptr(mockRemote); + EXPECT_EQ(WSError::WS_ERROR_IPC_FAILED, failProxy->SetContentAspectRatio(ratio, isPersistent, needUpdateRect)); + + // Case 6: Success + mockRemote->sendRequestResult_ = ERR_NONE; + sptr okProxy = sptr::MakeSptr(mockRemote); + EXPECT_EQ(WSError::WS_OK, okProxy->SetContentAspectRatio(ratio, isPersistent, needUpdateRect)); +} + +/** + * @tc.name: TestSetDecorVisible + * @tc.desc: Test SetDecorVisible behavior in various IPC scenarios + * @tc.type: FUNC + */ +HWTEST_F(SessionProxyTest, TestSetDecorVisible, TestSize.Level1) +{ + auto mockRemote = sptr::MakeSptr(); + auto sessionProxy = sptr::MakeSptr(mockRemote); + bool isVisible = true; + + // Case 1: Failed to write interface token + MockMessageParcel::SetWriteInterfaceTokenErrorFlag(true); + EXPECT_EQ(WSError::WS_ERROR_IPC_FAILED, sessionProxy->SetDecorVisible(isVisible)); + MockMessageParcel::SetWriteInterfaceTokenErrorFlag(false); + + // Case 2: Failed to write isVisible + MockMessageParcel::SetWriteBoolErrorFlag(true); + EXPECT_EQ(WSError::WS_ERROR_IPC_FAILED, sessionProxy->SetDecorVisible(isVisible)); + MockMessageParcel::SetWriteBoolErrorFlag(false); + + // Case 3: remote is nullptr + sptr nullProxy = sptr::MakeSptr(nullptr); + EXPECT_EQ(WSError::WS_ERROR_IPC_FAILED, nullProxy->SetDecorVisible(isVisible)); + + // Case 4: Failed to send request + mockRemote->sendRequestResult_ = ERR_TRANSACTION_FAILED; + sptr failProxy = sptr::MakeSptr(mockRemote); + EXPECT_EQ(WSError::WS_ERROR_IPC_FAILED, failProxy->SetDecorVisible(isVisible)); + + // Case 5: Success + mockRemote->sendRequestResult_ = ERR_NONE; + sptr okProxy = sptr::MakeSptr(mockRemote); + EXPECT_EQ(WSError::WS_OK, okProxy->SetDecorVisible(isVisible)); +} } // namespace } // namespace Rosen } // namespace OHOS \ No newline at end of file diff --git a/window_scene/test/unittest/session_stub_test.cpp b/window_scene/test/unittest/session_stub_test.cpp index cf565667cbc2fa3adaf11f7ba35dcec66d8f8ce0..74ca78405e9ae1598e364f57d69817e00e11f2dc 100644 --- a/window_scene/test/unittest/session_stub_test.cpp +++ b/window_scene/test/unittest/session_stub_test.cpp @@ -2022,6 +2022,85 @@ HWTEST_F(SessionStubTest, HandleConnect003, Function | SmallTest | Level2) result = session_->HandleConnect(data, reply); EXPECT_EQ(result, ERR_NONE); } + +/** + * @tc.name: HandleSetContentAspectRatioCases + * @tc.desc: Verify HandleSetContentAspectRatio with invalid and valid inputs + * @tc.type: FUNC + */ +HWTEST_F(SessionStubTest, HandleSetContentAspectRatioCases, TestSize.Level1) +{ + sptr session = sptr::MakeSptr(); + uint32_t code = static_cast(SessionInterfaceCode::TRANS_ID_SET_CONTENT_ASPECT_RATIO); + MessageOption option; + float ratio = 1.5f; + bool isPersistent = true; + bool needUpdateRect = false; + + // Case 1: Missing ratio + { + MessageParcel data; + MessageParcel reply; + EXPECT_EQ(session->ProcessRemoteRequest(code, data, reply, option), ERR_INVALID_DATA); + } + + // Case 2: Missing isPersistent and needUpdateRect + { + MessageParcel data; + MessageParcel reply; + data.WriteFloat(ratio); + EXPECT_EQ(session->ProcessRemoteRequest(code, data, reply, option), ERR_INVALID_DATA); + } + + // Case 3: Missing needUpdateRect + { + MessageParcel data; + MessageParcel reply; + data.WriteFloat(ratio); + data.WriteBool(isPersistent); + EXPECT_EQ(session->ProcessRemoteRequest(code, data, reply, option), ERR_INVALID_DATA); + } + + // Case 4: Success + { + MessageParcel data; + MessageParcel reply; + data.WriteFloat(ratio); + data.WriteBool(isPersistent); + data.WriteBool(needUpdateRect); + EXPECT_CALL(*session, SetContentAspectRatio(ratio, isPersistent, needUpdateRect)).Times(1); + EXPECT_EQ(session->ProcessRemoteRequest(code, data, reply, option), ERR_NONE); + } +} + +/** + * @tc.name: HandleSetDecorVisibleCases + * @tc.desc: Verify HandleSetDecorVisible with invalid and valid inputs + * @tc.type: FUNC + */ +HWTEST_F(SessionStubTest, HandleSetDecorVisibleCases, TestSize.Level1) +{ + sptr session = sptr::MakeSptr(); + uint32_t code = static_cast(SessionInterfaceCode::TRANS_ID_SET_DECOR_VISIBLE); + MessageOption option; + + // Case 1: Missing isVisible + { + MessageParcel data; + MessageParcel reply; + EXPECT_EQ(session->ProcessRemoteRequest(code, data, reply, option), ERR_INVALID_DATA); + } + + // Case 2: Success + { + MessageParcel data; + MessageParcel reply; + bool isVisible = true; + data.WriteBool(isVisible); + EXPECT_CALL(*session, SetDecorVisible(isVisible)).Times(1); + EXPECT_EQ(session->ProcessRemoteRequest(code, data, reply, option), ERR_NONE); + } +} } // namespace } // namespace Rosen } // namespace OHOS \ No newline at end of file diff --git a/window_scene/test/unittest/session_utils_test.cpp b/window_scene/test/unittest/session_utils_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed4ef38e2057bca6f670af5da0b3929a6adfad93 --- /dev/null +++ b/window_scene/test/unittest/session_utils_test.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "session_utils.h" + +#include + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Rosen { +namespace SessionUtils { +class SessionUtilsTest : public Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; + +void SessionUtilsTest::SetUpTestCase() {} +void SessionUtilsTest::TearDownTestCase() {} + +void SessionUtilsTest::SetUp() {} +void SessionUtilsTest::TearDown() {} + +/** + * @tc.name: TestIsAspectRatioValid + * @tc.desc: Verify IsAspectRatioValid behavior in different scenarios + * @tc.type: FUNC + */ +HWTEST_F(SessionUtilsTest, TestIsAspectRatioValid, TestSize.Level1) +{ + // Case 1: aspectRatio is near 0 + { + WindowLimits limits(400, 400, 100, 100, FLT_MAX, 0.0f); + WindowDecoration decor{0, 0, 0, 0}; + EXPECT_TRUE(IsAspectRatioValid(0.0f, limits, decor)); + } + + // Case 2: limits is invalid after trim + { + WindowLimits limits(100, 100, 200, 200, FLT_MAX, 0.0f); + WindowDecoration decor{50, 50, 50, 50}; + EXPECT_FALSE(IsAspectRatioValid(1.0f, limits, decor)); + } + + // Case 3: aspectRatio < minRatio + { + WindowLimits limits(400, 200, 200, 100, FLT_MAX, 0.0f); + WindowDecoration decor{0, 0, 0, 0}; + EXPECT_FALSE(IsAspectRatioValid(0.5f, limits, decor)); + } + + // Case 4: aspectRatio > maxRatio + { + WindowLimits limits(400, 200, 200, 100, FLT_MAX, 0.0f); + WindowDecoration decor{0, 0, 0, 0}; + EXPECT_FALSE(IsAspectRatioValid(5.0f, limits, decor)); + } + + // Case 5: aspectRatio is valid + { + WindowLimits limits(400, 200, 200, 100, FLT_MAX, 0.0f); + WindowDecoration decor{0, 0, 0, 0}; + EXPECT_TRUE(IsAspectRatioValid(2.0f, limits, decor)); + } +} + +/** + * @tc.name: TestAdjustLimitsByAspectRatio1 + * @tc.desc: Verify AdjustLimitsByAspectRatio behavior in different scenarios + * @tc.type: FUNC + */ +HWTEST_F(SessionUtilsTest, TestAdjustLimitsByAspectRatio1, TestSize.Level1) +{ + WindowLimits baseLimits(400, 400, 100, 100, FLT_MAX, 0.0f); + WindowDecoration noDecor {0, 0, 0, 0}; + + // Case 1: aspectRatio == 0 (NearZero) + { + float aspectRatio = 0.0f; + auto adjusted = AdjustLimitsByAspectRatio(baseLimits, noDecor, aspectRatio); + EXPECT_EQ(adjusted.minWidth_, baseLimits.minWidth_); + EXPECT_EQ(adjusted.minHeight_, baseLimits.minHeight_); + EXPECT_EQ(adjusted.maxWidth_, baseLimits.maxWidth_); + EXPECT_EQ(adjusted.maxHeight_, baseLimits.maxHeight_); + } + + // Case 2: Trim -> invalid (min > max) + { + float aspectRatio = 1.0f; + WindowLimits limits(50, 50, 100, 100, FLT_MAX, 0.0f); + WindowDecoration decor {60, 60, 0, 0}; + auto adjusted = AdjustLimitsByAspectRatio(limits, decor, aspectRatio); + EXPECT_EQ(adjusted.minWidth_, limits.minWidth_); + EXPECT_EQ(adjusted.minHeight_, limits.minHeight_); + EXPECT_EQ(adjusted.maxWidth_, limits.maxWidth_); + EXPECT_EQ(adjusted.maxHeight_, limits.maxHeight_); + } + + // Case 3: Adjust minWidth and maxHeight by aspect ratio + { + float aspectRatio = 2.0f; + WindowLimits limits(400, 400, 50, 100, FLT_MAX, 0.0f); + auto adjusted = AdjustLimitsByAspectRatio(limits, noDecor, aspectRatio); + EXPECT_GE(adjusted.minWidth_, adjusted.minHeight_ * aspectRatio); + EXPECT_LE(adjusted.maxHeight_, adjusted.maxWidth_ / aspectRatio); + } + + // Case 4: Adjust minHeight and maxWidth by aspect ratio + { + float aspectRatio = 0.5f; + WindowLimits limits(400, 400, 100, 50, FLT_MAX, 0.0f); + auto adjusted = AdjustLimitsByAspectRatio(limits, noDecor, aspectRatio); + EXPECT_GE(adjusted.minHeight_, adjusted.minWidth_ / aspectRatio); + EXPECT_LE(adjusted.maxWidth_, adjusted.maxHeight_ * aspectRatio); + } + + // Case 5: Adjusted is invalid (min > max) after aspect ratio adjustment + { + float aspectRatio = 4.0f; + WindowLimits limits(400, 400, 200, 110, FLT_MAX, 0.0f); + auto adjusted = AdjustLimitsByAspectRatio(limits, noDecor, aspectRatio); + EXPECT_EQ(adjusted.minWidth_, limits.minWidth_); + EXPECT_EQ(adjusted.minHeight_, limits.minHeight_); + EXPECT_EQ(adjusted.maxWidth_, limits.maxWidth_); + EXPECT_EQ(adjusted.maxHeight_, limits.maxHeight_); + } +} + +/** + * @tc.name: TestAdjustLimitsByAspectRatio2 + * @tc.desc: Verify AdjustLimitsByAspectRatio behavior in different scenarios + * @tc.type: FUNC + */ +HWTEST_F(SessionUtilsTest, TestAdjustLimitsByAspectRatio2, TestSize.Level1) +{ + // Case 5: With decoration (expand + trim check) + WindowLimits limits(500, 500, 100, 100, FLT_MAX, 0.0f); + WindowDecoration decor {10, 20, 10, 20}; + auto adjusted = AdjustLimitsByAspectRatio(limits, decor, 1.0f); + EXPECT_EQ(adjusted.minWidth_, 100); + EXPECT_EQ(adjusted.minHeight_, 120); + EXPECT_EQ(adjusted.maxWidth_, 480); + EXPECT_EQ(adjusted.maxHeight_, 500); +} + +/** + * @tc.name: TestAdjustRectByAspectRatio + * @tc.desc: Verify AdjustRectByAspectRatio behavior in different scenarios + * @tc.type: FUNC + */ +HWTEST_F(SessionUtilsTest, TestAdjustRectByAspectRatio, TestSize.Level1) +{ + WSRect rect {0, 0, 200, 100}; + WindowDecoration noDecor {0, 0, 0, 0}; + WindowLimits limits(400, 400, 50, 50, FLT_MAX, 0.0f); + + // Case 1: aspectRatio == 0 (NearZero) + { + auto adjusted = AdjustRectByAspectRatio(rect, limits, noDecor, 0.0f, 5); + EXPECT_EQ(adjusted, rect); + } + + // Case 2: Trim -> invalid (min > max) + { + WindowLimits smallLimits(50, 50, 100, 100, FLT_MAX, 0.0f); // invalid after trim + WindowDecoration decor {20, 20, 0, 0}; + auto adjusted = AdjustRectByAspectRatio(rect, smallLimits, decor, 2.0f, 5); + EXPECT_EQ(adjusted, rect); + } + + // Case 3: minW > maxW (aspect ratio conflicts with limits) + { + WindowLimits conflictLimits(100, 100, 90, 90, FLT_MAX, 0.0f); + auto adjusted = AdjustRectByAspectRatio(rect, conflictLimits, noDecor, 10.0f, 5); + EXPECT_EQ(adjusted, rect); + } + + // Case 4: Normal adjust, but difference <= tolerancePx + { + WSRect rectNear {0, 0, 200, 100}; + WindowLimits limitsOk(400, 400, 50, 50, FLT_MAX, 0.0f); + auto adjusted = AdjustRectByAspectRatio(rectNear, limitsOk, noDecor, 2.0f, 50); + EXPECT_EQ(adjusted, rectNear); + } + + // Case 5: Normal adjust, difference > tolerancePx + { + WSRect rectFar {0, 0, 300, 100}; + WindowLimits limitsOk(400, 400, 50, 50, FLT_MAX, 0.0f); + auto adjusted = AdjustRectByAspectRatio(rectFar, limitsOk, noDecor, 2.0f, 1); + EXPECT_EQ(adjusted.width_, 300); + EXPECT_EQ(adjusted.height_, 150); + } +} +} // namespace SessionUtils +} // namespace Rosen +} // namespace OHOS diff --git a/wm/include/window_scene_session_impl.h b/wm/include/window_scene_session_impl.h index ab6fe0d41e38b9704a5c976fc759995229d99098..d5e3733d7088566a28d4ffb19fdbe230b1f1a7c9 100644 --- a/wm/include/window_scene_session_impl.h +++ b/wm/include/window_scene_session_impl.h @@ -79,6 +79,7 @@ public: void PerformBack() override; WMError SetAspectRatio(float ratio) override; + WMError SetContentAspectRatio(float ratio, bool isPersistent, bool needUpdateRect) override; WMError ResetAspectRatio() override; WMError SetGlobalMaximizeMode(MaximizeMode mode) override; MaximizeMode GetGlobalMaximizeMode() const override; diff --git a/wm/src/window_scene_session_impl.cpp b/wm/src/window_scene_session_impl.cpp index 793fd300ec037a2cb3bb78619cda29b29497e3fb..7d4c5c4fb05a942dc479bd256084aafc9790ecbf 100644 --- a/wm/src/window_scene_session_impl.cpp +++ b/wm/src/window_scene_session_impl.cpp @@ -2604,6 +2604,32 @@ WMError WindowSceneSessionImpl::ResetAspectRatio() return static_cast(hostSession->SetAspectRatio(0.0f)); } +WMError WindowSceneSessionImpl::SetContentAspectRatio(float ratio, bool isPersistent, bool needUpdateRect) +{ + auto windowId = GetWindowId(); + if (!WindowHelper::IsMainWindow(GetType())) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Only allowed for the main window, windowId: %{public}u", windowId); + return WMError::WM_ERROR_INVALID_CALLING; + } + if (IsWindowSessionInvalid()) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Invalid session, windowId: %{public}u", windowId); + return WMError::WM_ERROR_INVALID_WINDOW; + } + auto hostSession = GetHostSession(); + CHECK_HOST_SESSION_RETURN_ERROR_IF_NULL(hostSession, WMError::WM_ERROR_NULLPTR); + if (ratio == MathHelper::INF || ratio == MathHelper::NAG_INF || std::isnan(ratio) || MathHelper::NearZero(ratio)) { + TLOGE(WmsLogTag::WMS_LAYOUT, "Invalid ratio: %{public}f, windowId: %{public}u", ratio, windowId); + return WMError::WM_ERROR_ILLEGAL_PARAM; + } + TLOGI(WmsLogTag::WMS_LAYOUT, + "windowId: %{public}u, ratio: %{public}f, isPersistent: %{public}d, needUpdateRect: %{public}d", + windowId, ratio, isPersistent, needUpdateRect); + if (hostSession->SetContentAspectRatio(ratio, isPersistent, needUpdateRect) != WSError::WS_OK) { + return WMError::WM_ERROR_ILLEGAL_PARAM; + } + return WMError::WM_OK; +} + /** @note @window.hierarchy */ WMError WindowSceneSessionImpl::RaiseToAppTop() { diff --git a/wm/src/window_session_impl.cpp b/wm/src/window_session_impl.cpp index 8a31c8bd251f827aa1831d1619388e78bd26f0dc..e744cb8d7f825854a840d85d3c843cdfddac67e6 100644 --- a/wm/src/window_session_impl.cpp +++ b/wm/src/window_session_impl.cpp @@ -3395,6 +3395,9 @@ WMError WindowSessionImpl::SetDecorVisible(bool isVisible) return WMError::WM_ERROR_NULLPTR; } uiContent->SetContainerModalTitleVisible(isVisible, true); + if (auto hostSession = GetHostSession()) { + hostSession->SetDecorVisible(isVisible); + } TLOGD(WmsLogTag::WMS_DECOR, "end"); return WMError::WM_OK; } diff --git a/wm/test/unittest/window_scene_session_impl_test5.cpp b/wm/test/unittest/window_scene_session_impl_test5.cpp index a9dbacb3f8cb0dddb5574632c3b23df2a9adca83..2fc1931d8537d8614ce501a81ab58698d6fc2925 100644 --- a/wm/test/unittest/window_scene_session_impl_test5.cpp +++ b/wm/test/unittest/window_scene_session_impl_test5.cpp @@ -2274,6 +2274,63 @@ HWTEST_F(WindowSceneSessionImplTest5, UpdateImmersiveBySwitchMode, TestSize.Leve window->UpdateImmersiveBySwitchMode(false); EXPECT_EQ(window->enableImmersiveMode_, true); } + +/** + * @tc.name: TestSetContentAspectRatio + * @tc.desc: Test SetContentAspectRatio under multiple conditions + * @tc.type: FUNC + */ +HWTEST_F(WindowSceneSessionImplTest5, TestSetContentAspectRatio, TestSize.Level1) +{ + sptr option = sptr::MakeSptr(); + sptr window = sptr::MakeSptr(option); + auto property = window->GetProperty(); + property->SetPersistentId(123); + SessionInfo sessionInfo; + sptr mockHostSession = sptr::MakeSptr(sessionInfo); + + // Case 1: Not main window + float ratio = 1.5f; + bool isPersistent = true; + bool needUpdateRect = true; + property->SetWindowType(WindowType::APP_SUB_WINDOW_BASE); + auto ret = window->SetContentAspectRatio(ratio, isPersistent, needUpdateRect); + EXPECT_EQ(ret, WMError::WM_ERROR_INVALID_CALLING); + property->SetWindowType(WindowType::APP_MAIN_WINDOW_BASE); + + // Case 2: Invalid session + window->hostSession_ = nullptr; + ret = window->SetContentAspectRatio(ratio, isPersistent, needUpdateRect); + EXPECT_EQ(ret, WMError::WM_ERROR_INVALID_WINDOW); + window->hostSession_ = mockHostSession; + + // Case 3: Invalid ratio => WM_ERROR_ILLEGAL_PARAM + ratio = MathHelper::INF; + ret = window->SetContentAspectRatio(ratio, isPersistent, needUpdateRect); + EXPECT_EQ(ret, WMError::WM_ERROR_ILLEGAL_PARAM); + ratio = MathHelper::NAG_INF; + ret = window->SetContentAspectRatio(ratio, isPersistent, needUpdateRect); + EXPECT_EQ(ret, WMError::WM_ERROR_ILLEGAL_PARAM); + ratio = std::numeric_limits::quiet_NaN(); + ret = window->SetContentAspectRatio(ratio, isPersistent, needUpdateRect); + EXPECT_EQ(ret, WMError::WM_ERROR_ILLEGAL_PARAM); + ratio = 0.0f; + ret = window->SetContentAspectRatio(ratio, isPersistent, needUpdateRect); + EXPECT_EQ(ret, WMError::WM_ERROR_ILLEGAL_PARAM); + + // Case 4: host returns failure => WM_ERROR_ILLEGAL_PARAM + ratio = 1.5f; + EXPECT_CALL(*mockHostSession, SetContentAspectRatio(_, _, _)) + .Times(1).WillOnce(Return(WSError::WS_ERROR_IPC_FAILED)); + ret = window->SetContentAspectRatio(ratio, isPersistent, needUpdateRect); + EXPECT_EQ(ret, WMError::WM_ERROR_ILLEGAL_PARAM); + + // Case 5: host returns success => WM_OK + EXPECT_CALL(*mockHostSession, SetContentAspectRatio(_, _, _)) + .Times(1).WillOnce(Return(WSError::WS_OK)); + ret = window->SetContentAspectRatio(ratio, isPersistent, needUpdateRect); + EXPECT_EQ(ret, WMError::WM_OK); +} } } // namespace Rosen } // namespace OHOS \ No newline at end of file