当前位置:   article > 正文

OpenHarmony系统解决方案 - 配置屏幕方向导致开机动画和Launcher显示异常_openharmony launcher

openharmony launcher

问题描述

问题环境

系统版本:OpenHarmony-3.2-Release

问题现象

1. 配置设备默认方向,例如修改为横屏显示,修改文件display_manager_config.xmlbuildInDefaultOrientation参数值2(Orientation::HORIZONTAL)。

源码中文件位于foundation/window/window_manager/resources/config/rk3568/display_manager_config.xml。

系统中文件位于/etc/window/resources/display_manager_config.xml。

2. 系统启动后开机动画横竖屏切换,Launcher显示异常(偶现,去掉锁屏应用和锁屏服务后大概率出现)。

异常效果:

正常效果:

问题原因

  • ScreenRotationController初始化会设置rotationLockedRotation_属性初始值,而ScreenRotationController初始化的触发点在开机动画窗口销毁时,此时间点在LauncherWindow加载之后。
  • Launcher加载Window时会设置SetScreenRotation(屏幕旋转角度),因为Launcher的方向加载配置为AUTO_ROTATION_RESTRICTED(方向随传感器旋转),所以SetScreenRotation会根据rotationLockedRotation_属性值设置旋转角度,而此时rotationLockedRotation_属性并未被设置初始值,所以SetScreenRotation设置的值取得是默认值0(如果配置为Orientation::HORIZONTAL,则应旋转90度,取值为1),导致问题的产生。

解决方案

调整ScreenRotationController初始化时序,使ScreenRotationControllerLauncher加载Window时触发。修改源码文件:foundation/window/window_manager/wmserver/src/window_node_container.cpp

1. WindowNodeContainer::RemoveWindowNode函数中,移除以下代码:

  1. if (node->GetWindowType() == WindowType::WINDOW_TYPE_BOOT_ANIMATION) {
  2. DisplayManagerServiceInner::GetInstance().SetGravitySensorSubscriptionEnabled();
  3. }

修改后WindowNodeContainer::RemoveWindowNode函数代码:

  1. // foundation/window/window_manager/wmserver/src/window_node_container.cpp
  2. WMError WindowNodeContainer::RemoveWindowNode(sptr<WindowNode>& node, bool fromAnimation)
  3. {
  4. ···
  5. NotifyIfAvoidAreaChanged(node, AvoidControlType::AVOID_NODE_REMOVE);
  6. DumpScreenWindowTree();
  7. UpdateCameraFloatWindowStatus(node, false);
  8. if (node->GetWindowType() == WindowType::WINDOW_TYPE_KEYGUARD) {
  9. isScreenLocked_ = false;
  10. SetBelowScreenlockVisible(node, true);
  11. }
  12. WLOGFD("RemoveWindowNode windowId: %{public}u end", node->GetWindowId());
  13. RSInterfaces::GetInstance().SetAppWindowNum(GetAppWindowNum());
  14. return WMError::WM_OK;
  15. }

2. WindowNodeContainer::AddWindowNode函数中,在WLOGFD("AddWindowNode windowId: %{public}u end", node->GetWindowId());行代码前添加以下代码:

  1. if (node->GetWindowType() == WindowType::WINDOW_TYPE_DESKTOP) {
  2. DisplayManagerServiceInner::GetInstance().SetGravitySensorSubscriptionEnabled();
  3. }

修改后WindowNodeContainer::AddWindowNode函数代码:

  1. WMError WindowNodeContainer::AddWindowNode(sptr<WindowNode>& node, sptr<WindowNode>& parentNode, bool afterAnimation)
  2. {
  3. ···
  4. if (node->GetWindowType() == WindowType::WINDOW_TYPE_WALLPAPER) {
  5. RemoteAnimation::NotifyAnimationUpdateWallpaper(node);
  6. }
  7. if (node->GetWindowType() == WindowType::WINDOW_TYPE_DESKTOP) {
  8. DisplayManagerServiceInner::GetInstance().SetGravitySensorSubscriptionEnabled();
  9. }
  10. WLOGFD("AddWindowNode windowId: %{public}u end", node->GetWindowId());
  11. RSInterfaces::GetInstance().SetAppWindowNum(GetAppWindowNum());
  12. return WMError::WM_OK;
  13. }

定位过程

1. 落盘异常开机日志,查找SetRotation相关日志,发现系统启动过程中横竖屏被设置两次。

  1. 08-05 18:39:55.002 622 811 I C04201/AbstractScreenController: <722>SetRotation: Enter SetRotation, screenId: 0, rotation: 1, isFromWindow: 1
  2. 08-05 18:39:58.487 622 811 I C04201/AbstractScreenController: <722>SetRotation: Enter SetRotation, screenId: 0, rotation: 0, isFromWindow: 1

2. 查找对应源码发现rotation代表含义。在系统启动时已成功设置旋转90度(水平),但又被设置为旋转0度(垂直),导致异常。

  1. // foundation/window/window_manager/interfaces/innerkits/dm/dm_common.h
  2. enum class Rotation : uint32_t {
  3. ROTATION_0, // 不旋转,垂直
  4. ROTATION_90, // 旋转90度,水平
  5. ROTATION_180,
  6. ROTATION_270,
  7. };
  8. // foundation/window/window_manager/dmserver/src/abstract_screen_controller.cpp
  9. bool AbstractScreenController::SetRotation(ScreenId screenId, Rotation rotationAfter, bool isFromWindow)
  10. {
  11. WLOGFI("Enter SetRotation, screenId: %{public}" PRIu64 ", rotation: %{public}u, isFromWindow: %{public}u",
  12. screenId, rotationAfter, isFromWindow);
  13. ···
  14. }

3. 追踪设置旋转0度(垂直)操作日志。发现set orientation时,orientation被设置为8,对应源码含义为AUTO_ROTATION_RESTRICTED

  1. 08-05 18:39:58.487 622 811 D C04201/AbstractScreenController: <627>set orientation. screen 0 orientation 8
  2. 08-05 18:39:58.487 622 811 D C04201/AbstractScreenController: <144>GetAbstractScreen: screenId: 0
  3. 08-05 18:39:58.487 622 811 D C04201/AbstractScreenController: <177>GetDefaultAbstractScreenId: GetDefaultAbstractScreenId, screen:0
  4. 08-05 18:39:58.487 622 811 D C04201/DisplayManagerService: <190>GetDefaultDisplayInfo: GetDefaultDisplayInfo 0
  5. 08-05 18:39:58.487 622 811 D C04201/AbstractScreenController: <177>GetDefaultAbstractScreenId: GetDefaultAbstractScreenId, screen:0
  6. 08-05 18:39:58.487 622 811 D C04201/DisplayManagerService: <190>GetDefaultDisplayInfo: GetDefaultDisplayInfo 0
  7. 08-05 18:39:58.487 622 811 I C04201/AbstractScreenController: <722>SetRotation: Enter SetRotation, screenId: 0, rotation: 0, isFromWindow: 1
  1. // foundation/window/window_manager/dmserver/src/abstract_screen_controller.cpp
  2. bool AbstractScreenController::SetOrientation(ScreenId screenId, Orientation newOrientation, bool isFromWindow)
  3. {
  4. WLOGD("set orientation. screen %{public}" PRIu64" orientation %{public}u", screenId, newOrientation);
  5. ···
  6. }
  7. // foundation/window/window_manager/interfaces/innerkits/dm/dm_common.h
  8. enum class Orientation : uint32_t {
  9. BEGIN = 0,
  10. UNSPECIFIED = BEGIN,
  11. VERTICAL = 1,
  12. HORIZONTAL = 2,
  13. REVERSE_VERTICAL = 3,
  14. REVERSE_HORIZONTAL = 4,
  15. SENSOR = 5,
  16. SENSOR_VERTICAL = 6,
  17. SENSOR_HORIZONTAL = 7,
  18. AUTO_ROTATION_RESTRICTED = 8,
  19. AUTO_ROTATION_PORTRAIT_RESTRICTED = 9,
  20. AUTO_ROTATION_LANDSCAPE_RESTRICTED = 10,
  21. LOCKED = 11,
  22. END = LOCKED,
  23. };

4. Launcher在创建window时会把PreferredOrientation设置为Window.Orientation.AUTO_ROTATION_RESTRICTED

  1. // common/src/main/ets/default/manager/WindowManager.ts
  2. createWindow(context: ServiceExtensionContext, name: string, windowType: number, loadContent: string,
  3. isShow: boolean, callback?: Function) {
  4. Window.create(context, name, windowType).then((win) => {
  5. void win.setPreferredOrientation(Window.Orientation.AUTO_ROTATION_RESTRICTED);
  6. ···
  7. }, (error) => {
  8. Log.showError(TAG, `createWindow, create error: ${JSON.stringify(error)}`);
  9. });
  10. }

5. 当Launcher显示窗口时执行SetOrientation,isFromWindow参数为true

  1. // foundation/window/window_manager/dmserver/src/abstract_screen_controller.cpp
  2. bool AbstractScreenController::SetOrientation(ScreenId screenId, Orientation newOrientation, bool isFromWindow)
  3. {
  4. WLOGD("set orientation. screen %{public}" PRIu64" orientation %{public}u", screenId, newOrientation);
  5. auto screen = GetAbstractScreen(screenId);
  6. ···
  7. if (isFromWindow) {
  8. ScreenRotationController::ProcessOrientationSwitch(newOrientation); // 执行方向选择
  9. } else {
  10. Rotation rotationAfter = screen->CalcRotation(newOrientation);
  11. SetRotation(screenId, rotationAfter, false);
  12. screen->rotation_ = rotationAfter;
  13. }
  14. if (!screen->SetOrientation(newOrientation)) {
  15. WLOGE("fail to set rotation, screen %{public}" PRIu64"", screenId);
  16. return false;
  17. }
  18. ···
  19. return true;
  20. }

6. 因orientationAUTO_ROTATION_RESTRICTED,会执行ProcessSwitchToSensorRelatedOrientation函数。

  1. // foundation/window/window_manager/dmserver/src/screen_rotation_controller.cpp
  2. void ScreenRotationController::ProcessOrientationSwitch(Orientation orientation)
  3. {
  4. if (!IsSensorRelatedOrientation(orientation)) {
  5. ProcessSwitchToSensorUnrelatedOrientation(orientation);
  6. } else {
  7. ProcessSwitchToSensorRelatedOrientation(orientation, lastSensorRotationConverted_);
  8. }
  9. }
  10. bool ScreenRotationController::IsSensorRelatedOrientation(Orientation orientation)
  11. {
  12. if ((orientation >= Orientation::UNSPECIFIED && orientation <= Orientation::REVERSE_HORIZONTAL) ||
  13. orientation == Orientation::LOCKED) {
  14. return false;
  15. }
  16. // AUTO_ROTATION_RESTRICTED 返回 true
  17. return true;
  18. }

7. 当rotationLockedRotation_GetCurrentDisplayRotation()不一致时会切换旋转角度。在此处增加日志打印rotationLockedRotation_GetCurrentDisplayRotation()的值,发现在开机触发Launcher设置屏幕旋转角度时GetCurrentDisplayRotation()函数获取的当前屏幕旋转角度为1(水平)是正确的。而rotationLockedRotation_0(垂直)。

  1. // foundation/window/window_manager/dmserver/src/screen_rotation_controller.cpp
  2. void ScreenRotationController::ProcessSwitchToSensorRelatedOrientation(
  3. Orientation orientation, DeviceRotation sensorRotationConverted){
  4. lastOrientationType_ = orientation;
  5. switch (orientation) {
  6. case Orientation::AUTO_ROTATION_RESTRICTED: {
  7. if (isScreenRotationLocked_) {
  8. SetScreenRotation(rotationLockedRotation_);
  9. return;
  10. }
  11. [[fallthrough]];
  12. }
  13. ···
  14. }
  15. }
  16. void ScreenRotationController::SetScreenRotation(Rotation targetRotation){
  17. if (targetRotation == GetCurrentDisplayRotation()) {
  18. return;
  19. }
  20. DisplayManagerServiceInner::GetInstance().GetDefaultDisplay()->SetRotation(targetRotation);
  21. DisplayManagerServiceInner::GetInstance().SetRotationFromWindow(defaultDisplayId_, targetRotation);
  22. WLOGFI("dms: Set screen rotation: %{public}u", targetRotation);
  23. }

8. 查看rotationLockedRotation_被设置的场景。分别增加日志,发现开机启动时SetScreenRotationLocked函数不会被触发,而Init函数则是在Launcher启动后被触发,此时Launcher已经把屏幕旋转角度设置为0(垂直),rotationLockedRotation_的初始化值则会变成Launcher设置后的参数0(垂直)。而在Launcher触发SetScreenRotation时,rotationLockedRotation_还未被设置,此时取默认值0(垂直),导致异常的产生。

  1. // foundation/window/window_manager/dmserver/src/screen_rotation_controller.cpp
  2. void ScreenRotationController::Init()
  3. {
  4. ProcessRotationMapping();
  5. currentDisplayRotation_ = GetCurrentDisplayRotation();
  6. lastSensorDecidedRotation_ = currentDisplayRotation_;
  7. rotationLockedRotation_ = currentDisplayRotation_;
  8. }
  9. void ScreenRotationController::SetScreenRotationLocked(bool isLocked)
  10. {
  11. if (isLocked) {
  12. rotationLockedRotation_ = GetCurrentDisplayRotation();
  13. }
  14. isScreenRotationLocked_ = isLocked;
  15. }

9. ScreenRotationController::Init()的触发时机是在系统检测到启动完成后,关闭开机动画窗口时触发。如果此操作在Launcher加载Window之后,则会导致问题。改变ScreenRotationController::Init()的初始化时序,在Launcherwindow加载时初始化可以修复此问题。

  1. // foundation/window/window_manager/wmserver/src/window_node_container.cpp
  2. WMError WindowNodeContainer::RemoveWindowNode(sptr<WindowNode>& node, bool fromAnimation)
  3. {
  4. ···
  5. if (node->GetWindowType() == WindowType::WINDOW_TYPE_BOOT_ANIMATION) {
  6. DisplayManagerServiceInner::GetInstance().SetGravitySensorSubscriptionEnabled();
  7. }
  8. ···
  9. return WMError::WM_OK;
  10. }
  11. // foundation/window/window_manager/dmserver/src/display_manager_service.cpp
  12. void DisplayManagerService::SetGravitySensorSubscriptionEnabled()
  13. {
  14. ···
  15. SensorConnector::SubscribeRotationSensor();
  16. }
  17. // foundation/window/window_manager/dmserver/src/sensor_connector.cpp
  18. void SensorConnector::SubscribeRotationSensor()
  19. {
  20. WLOGFI("dms: subscribe rotation-related sensor");
  21. ScreenRotationController::Init();
  22. ···
  23. }

知识分享

如果应用的方向需要随系统切换,可以在module.json5ability中配置orientationauto_rotation_restricted

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/237084?site
推荐阅读
相关标签
  

闽ICP备14008679号