多屏 - SystemUI显示

基于Android R版本分析

在多个屏幕上显示StatusBar和NavigationBar,需要修改两个位置:

  • DisplayPolicy

    • 在DisplayPolicy中有两个变量:mHasStatusBarmHasNavigationBar,该变量用于判断当前屏幕中是否需要显示StatusBar和NavigationBar;

      • mHasStatusBar:默认在DefaultDisplay中显示,在其他非DefaultDisplay中不显示;
      • mHasNavigationBar:根据 "qemu.hw.mainkeys" 这个SystemProperties来标识是否需要显示;
  • SystemUI进程中:在SystemUI代码中,需要主动的遍历所有的DisplayIds ,为每一个Display配套一组StatusBar和NavigationBar,本质上其实就是为每一个Display创建两个Window窗口用于承载对应的StatusBar和NavigationBar,这个StatusBar和NavigationBar可以和主屏显示相同,也可以定制化副屏的StatusBar和NavigationBar;

DisplayPolicy patch

diff 复制代码
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2267bcb3..d6aa613b 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -157,6 +157,7 @@ import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.IntArray;
+import android.util.Log;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
@@ -649,18 +650,27 @@ public class DisplayPolicy {
 
         if (mDisplayContent.isDefaultDisplay) {
             mHasStatusBar = true;
+            // 在/frameworks/base/core/res/res/values/config.xml中定义的config_showNavigationBar:
+            // <bool name="config_showNavigationBar">false</bool>
             mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
 
             // Allow a system property to override this. Used by the emulator.
             // See also hasNavigationBar().
+            // 通过该SystemProperties来控制display是否需要显示navigation bar
             String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
+            /**
+             * qemu.hw.mainkeys = 1 //不存在
+             * qemu.hw.mainkeys = 0 //存在
+             */
             if ("1".equals(navBarOverride)) {
                 mHasNavigationBar = false;
             } else if ("0".equals(navBarOverride)) {
                 mHasNavigationBar = true;
             }
         } else {
-            mHasStatusBar = false;
+            // 默认在副屏中,StatusBar不显示,即使在SystemUI中强制使其显示,但是在DisplayPolicy中也不会标记
+            // StatusBar已显示
+            mHasStatusBar = true;
             mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
         }
 
@@ -748,6 +758,7 @@ public class DisplayPolicy {
         return mDockMode;
     }
 
+    // 在CUX SystemUI中判斷是否需要显示navigation bar就是通过DisplayPolicy中的hasNavigationBar实现的
     public boolean hasNavigationBar() {
         return mHasNavigationBar;
     }
@@ -3033,18 +3044,30 @@ public class DisplayPolicy {
 
     /**
      * Called when the configuration has changed, and it's safe to load new values from resources.
+     *
+     * onConfigurationChanged事件并不是只有屏幕方向改变才可以触发,其他的一些系统设置改变也可以触发,比如打开或者隐藏键盘
      */
     public void onConfigurationChanged() {
         final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
 
         final Resources res = getCurrentUserResources();
+        // 这个几个rotation代表了横竖屏设置的参数
+        /**
+         * portrait Rotation:肖像 旋转
+         * landscape Rotation:景观 旋转
+         */
         final int portraitRotation = displayRotation.getPortraitRotation();
         final int upsideDownRotation = displayRotation.getUpsideDownRotation();
         final int landscapeRotation = displayRotation.getLandscapeRotation();
         final int seascapeRotation = displayRotation.getSeascapeRotation();
         final int uiMode = mService.mPolicy.getUiMode();
 
+        /**
+         * 判断DisplayContent对应的DisplayPolicy中是否标记了已存在hasStatusBar
+         * 默认在副屏中不存在StatusBar
+         */
         if (hasStatusBar()) {
+            // 在判断允许存在StatusBar之后,StatusBarHeight的值就不能为0
             mStatusBarHeightForRotation[portraitRotation] =
                     mStatusBarHeightForRotation[upsideDownRotation] =
                             res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
@@ -3244,6 +3267,14 @@ public class DisplayPolicy {
      * decorations that could never be removed in Honeycomb. That is, system bar or
      * button bar.
      */
+    /**
+     * 应用区域分两种情况:
+     *   1、当导航栏显示的时候,应用区域会减去导航栏的高度
+     *   2、当状态栏显示的时候,应用区域的距离会减去状态栏的高度
+     *
+     *   在原生的逻辑中,只考虑了navigation bar的height和cutout的height,因为statusbar在副屏的height默认为0,
+     *   所以就没有考虑statusBar的height
+     */
     public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
             DisplayCutout displayCutout) {
         int height = fullHeight;
@@ -3288,6 +3319,13 @@ public class DisplayPolicy {
             // bar height.
             statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
         }
+        // 获取应用区域的高度
+        /**
+         * 应用区域分两种情况:
+         *   1、当导航栏显示的时候,应用区域会减去导航栏的高度
+         *   2、当状态栏显示的时候,应用区域的距离会减去状态栏的高度(StatusBar的height需要手动的进行删除,因为
+         *     getNonDecorDisplayHeight方法中没有考虑StatusBar)
+         */
         return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
                 - statusBarHeight;
     }
相关推荐
快点好好学习吧41 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
是誰萆微了承諾42 分钟前
php 对接deepseek
android·开发语言·php
Dxy12393102162 小时前
MySQL如何加唯一索引
android·数据库·mysql
Jing_jing_X3 小时前
CPU 架构:x86、x64、ARM 到底是什么?为什么程序不能通用?
arm开发·架构·cpu
冠希陈、3 小时前
PHP 判断是否是移动端,更新鸿蒙系统
android·开发语言·php
qq_177767375 小时前
React Native鸿蒙跨平台自定义复选框组件,通过样式数组实现选中/未选中状态的样式切换,使用链式调用替代样式数组,实现状态驱动的样式变化
javascript·react native·react.js·架构·ecmascript·harmonyos·媒体
小程故事多_806 小时前
深度搜索Agent架构全解析:从入门到进阶,解锁复杂问题求解密码
人工智能·架构·aigc
晚霞的不甘6 小时前
Flutter for OpenHarmony从零到一:构建《冰火人》双人合作闯关游戏
android·flutter·游戏·前端框架·全文检索·交互
2601_949833396 小时前
flutter_for_openharmony口腔护理app实战+饮食记录实现
android·javascript·flutter
独自破碎E6 小时前
【滑动窗口+字符计数数组】LCR_014_字符串的排列
android·java·开发语言