Android多屏幕支持-Android12

这篇具有很好参考价值的文章主要介绍了Android多屏幕支持-Android12。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

android12-release


1、概览及相关文章

AOSP > 文档 > 心主题 > 多屏幕概览

术语
在这些文章中,主屏幕和辅助屏幕的定义如下:

主(默认)屏幕的屏幕 IDDEFAULT_DISPLAY
辅助屏幕的屏幕 ID 不是 DEFAULT_DISPLAY

主题区域 文章
开发和测试 推荐做法
测试和开发环境
常见问题解答
相关文章集 显示
系统装饰支持
输入法支持
单篇文章 多项恢复
Activity 启动政策
锁定屏幕
输入路由
多区音频

2、屏幕窗口配置

2.1 配置xml文件

/data/system/display_settings.xml 配置:

  • 模拟屏幕uniqueId 用于在名称属性中标识屏幕,对于模拟屏幕,此 ID 为 overlay:1
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<display-settings>
<config identifier="0" />
<display
  name="overlay:1"
  shouldShowSystemDecors="true"
  shouldShowIme="true" />
</display-settings>
  • 内置屏幕uniqueId 对于内置屏幕,示例值可以是 “local:45354385242535243453”。另一种方式是使用硬件端口信息,并设置 identifier=“1” 以与 DisplayWindowSettingsProvider#IDENTIFIER_PORT 对应,然后更新 name 以使用 "port:<port_id>" 格式
<?xmlversion='1.0' encoding='utf-8' standalone='yes' ?>
<display-settings>
<config identifier="1" />
<display
  name="port:12345"
  shouldShowSystemDecors="true"
  shouldShowIme="true" />
</display-settings>

2.2 DisplayInfo#uniqueId 屏幕标识

DisplayInfo#uniqueId,以添加稳定的标识符并区分本地、网络和虚拟屏幕

屏幕类型 格式
本地 local:<stable-id>
网络 network:<mac-address>
虚拟 virtual:<package-name-and-name>

2.3 adb查看信息

$ dumpsys SurfaceFlinger --display-id
# Example output.
Display 21691504607621632 (HWC display 0): port=0 pnpId=SHP displayName="LQ123P1JX32"
Display 9834494747159041 (HWC display 2): port=1 pnpId=HWP displayName="HP Z24i"
Display 1886279400700944 (HWC display 1): port=2 pnpId=AUS displayName="ASUS MB16AP"

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp#SurfaceFlinger::dumpDisplayIdentificationData

void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
    for (const auto& [token, display] : mDisplays) {
        const auto displayId = PhysicalDisplayId::tryCast(display->getId());
        if (!displayId) {
            continue;
        }
        const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
        if (!hwcDisplayId) {
            continue;
        }

        StringAppendF(&result,
                      "Display %s (HWC display %" PRIu64 "): ", to_string(*displayId).c_str(),
                      *hwcDisplayId);
        uint8_t port;
        DisplayIdentificationData data;
        if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
            result.append("no identification data\n");
            continue;
        }

        if (!isEdid(data)) {
            result.append("unknown identification data\n");
            continue;
        }

        const auto edid = parseEdid(data);
        if (!edid) {
            result.append("invalid EDID\n");
            continue;
        }

        StringAppendF(&result, "port=%u pnpId=%s displayName=\"", port, edid->pnpId.data());
        result.append(edid->displayName.data(), edid->displayName.length());
        result.append("\"\n");
    }
}

Android多屏幕支持-Android12,Android,# 图形界面,WMS,多屏幕

3、配置文件解析

3.1 xml字段读取

  • 文件路径:DATA_DISPLAY_SETTINGS_FILE_PATH = "system/display_settings.xml"VENDOR_DISPLAY_SETTINGS_FILE_PATH = "etc/display_settings.xml"Settings.Global.getString(resolver,DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH)DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH = "wm_display_settings_path"
  • FileData对象:fileData.mIdentifierType = getIntAttribute(parser, "identifier", IDENTIFIER_UNIQUE_ID)name = parser.getAttributeValue(null, "name")shouldShowIme = getBooleanAttribute(parser, "shouldShowIme", null /* defaultValue */)settingsEntry.mShouldShowSystemDecors = getBooleanAttribute(parser, "shouldShowSystemDecors", null /* defaultValue */)等等
private static final class FileData {
  int mIdentifierType;
  final Map<String, SettingsEntry> mSettings = new HashMap<>();

  @Override
  public String toString() {
      return "FileData{"
              + "mIdentifierType=" + mIdentifierType
              + ", mSettings=" + mSettings
              + '}';
  }
}
  • DisplayWindowSettings.java有关显示器的当前持久设置。提供显示设置的策略,并将设置值的持久性和查找委派给提供的{@link SettingsProvider}
@Nullable
private static FileData readSettings(ReadableSettingsStorage storage) {
    InputStream stream;
    try {
        stream = storage.openRead();
    } catch (IOException e) {
        Slog.i(TAG, "No existing display settings, starting empty");
        return null;
    }
    FileData fileData = new FileData();
    boolean success = false;
    try {
        TypedXmlPullParser parser = Xml.resolvePullParser(stream);
        int type;
        while ((type = parser.next()) != XmlPullParser.START_TAG
                && type != XmlPullParser.END_DOCUMENT) {
            // Do nothing.
        }

        if (type != XmlPullParser.START_TAG) {
            throw new IllegalStateException("no start tag found");
        }

        int outerDepth = parser.getDepth();
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            String tagName = parser.getName();
            if (tagName.equals("display")) {
                readDisplay(parser, fileData);
            } else if (tagName.equals("config")) {
                readConfig(parser, fileData);
            } else {
                Slog.w(TAG, "Unknown element under <display-settings>: "
                        + parser.getName());
                XmlUtils.skipCurrentTag(parser);
            }
        }
        success = true;
    } catch (IllegalStateException e) {
        Slog.w(TAG, "Failed parsing " + e);
    } catch (NullPointerException e) {
        Slog.w(TAG, "Failed parsing " + e);
    } catch (NumberFormatException e) {
        Slog.w(TAG, "Failed parsing " + e);
    } catch (XmlPullParserException e) {
        Slog.w(TAG, "Failed parsing " + e);
    } catch (IOException e) {
        Slog.w(TAG, "Failed parsing " + e);
    } catch (IndexOutOfBoundsException e) {
        Slog.w(TAG, "Failed parsing " + e);
    } finally {
        try {
            stream.close();
        } catch (IOException ignored) {
        }
    }
    if (!success) {
        fileData.mSettings.clear();
    }
    return fileData;
}

private static int getIntAttribute(TypedXmlPullParser parser, String name, int defaultValue) {
    return parser.getAttributeInt(null, name, defaultValue);
}

@Nullable
private static Integer getIntegerAttribute(TypedXmlPullParser parser, String name,
        @Nullable Integer defaultValue) {
    try {
        return parser.getAttributeInt(null, name);
    } catch (Exception ignored) {
        return defaultValue;
    }
}

@Nullable
private static Boolean getBooleanAttribute(TypedXmlPullParser parser, String name,
        @Nullable Boolean defaultValue) {
    try {
        return parser.getAttributeBoolean(null, name);
    } catch (Exception ignored) {
        return defaultValue;
    }
}

private static void readDisplay(TypedXmlPullParser parser, FileData fileData)
        throws NumberFormatException, XmlPullParserException, IOException {
    String name = parser.getAttributeValue(null, "name");
    if (name != null) {
        SettingsEntry settingsEntry = new SettingsEntry();
        settingsEntry.mWindowingMode = getIntAttribute(parser, "windowingMode",
                WindowConfiguration.WINDOWING_MODE_UNDEFINED /* defaultValue */);
        settingsEntry.mUserRotationMode = getIntegerAttribute(parser, "userRotationMode",
                null /* defaultValue */);
        settingsEntry.mUserRotation = getIntegerAttribute(parser, "userRotation",
                null /* defaultValue */);
        settingsEntry.mForcedWidth = getIntAttribute(parser, "forcedWidth",
                0 /* defaultValue */);
        settingsEntry.mForcedHeight = getIntAttribute(parser, "forcedHeight",
                0 /* defaultValue */);
        settingsEntry.mForcedDensity = getIntAttribute(parser, "forcedDensity",
                0 /* defaultValue */);
        settingsEntry.mForcedScalingMode = getIntegerAttribute(parser, "forcedScalingMode",
                null /* defaultValue */);
        settingsEntry.mRemoveContentMode = getIntAttribute(parser, "removeContentMode",
                REMOVE_CONTENT_MODE_UNDEFINED /* defaultValue */);
        settingsEntry.mShouldShowWithInsecureKeyguard = getBooleanAttribute(parser,
                "shouldShowWithInsecureKeyguard", null /* defaultValue */);
        settingsEntry.mShouldShowSystemDecors = getBooleanAttribute(parser,
                "shouldShowSystemDecors", null /* defaultValue */);
        final Boolean shouldShowIme = getBooleanAttribute(parser, "shouldShowIme",
                null /* defaultValue */);
        if (shouldShowIme != null) {
            settingsEntry.mImePolicy = shouldShowIme ? DISPLAY_IME_POLICY_LOCAL
                    : DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
        } else {
            settingsEntry.mImePolicy = getIntegerAttribute(parser, "imePolicy",
                    null /* defaultValue */);
        }
        settingsEntry.mFixedToUserRotation = getIntegerAttribute(parser, "fixedToUserRotation",
                null /* defaultValue */);
        settingsEntry.mIgnoreOrientationRequest = getBooleanAttribute(parser,
                "ignoreOrientationRequest", null /* defaultValue */);
        settingsEntry.mIgnoreDisplayCutout = getBooleanAttribute(parser,
                "ignoreDisplayCutout", null /* defaultValue */);
        settingsEntry.mDontMoveToTop = getBooleanAttribute(parser,
                "dontMoveToTop", null /* defaultValue */);

        fileData.mSettings.put(name, settingsEntry);
    }
    XmlUtils.skipCurrentTag(parser);
}

private static void readConfig(TypedXmlPullParser parser, FileData fileData)
        throws NumberFormatException,
        XmlPullParserException, IOException {
    fileData.mIdentifierType = getIntAttribute(parser, "identifier",
            IDENTIFIER_UNIQUE_ID);
    XmlUtils.skipCurrentTag(parser);
}

3.2 简要时序图

Android多屏幕支持-Android12,Android,# 图形界面,WMS,多屏幕

4、每屏幕焦点

每个屏幕焦点

为了同时支持多个以单个屏幕为目标的输入源,可以将 Android 10 配置为支持多个聚焦窗口,每个屏幕最多支持一个。当多个用户同时与同一设备交互并使用不同的输入方法或设备(例如 Android Automotive)时,此功能仅适用于特殊类型的设备。

强烈建议不要为常规设备启用此功能,包括跨屏设备或用于类似桌面设备体验的设备。这主要是出于安全方面的考虑,因为这样做可能会导致用户不确定哪个窗口具有输入焦点

想象一下,用户在文本输入字段中输入安全信息,也许是登录某个银行应用或者输入包含敏感信息的文本。恶意应用可以创建一个虚拟的屏幕外屏幕用于执行 activity,也可以使用文本输入字段执行 activity。合法 activity 和恶意 activity 均具有焦点,并且都显示一个有效的输入指示符(闪烁光标)。

不过,键盘(硬件或软件)的输入只能进入最顶层的 activity(最近启动的应用)。通过创建隐藏的虚拟屏幕,即使在主设备屏幕上使用软件键盘,恶意应用也可以获取用户输入。

使用 com.android.internal.R.bool.config_perDisplayFocusEnabled 设置每屏幕焦点。

兼容性
**问题:**在 Android 9 及更低版本中,系统中一次最多只有一个窗口具有焦点。

**解决方案:**在极少数情况下,来自同一进程的两个窗口都处于聚焦状态,则系统仅向在 Z 轴顺序中较高的窗口提供焦点。对于以 Android 10 为目标平台的应用,目前已取消这一限制,此时预计这些应用可以支持同时聚焦多个窗口。

实现
WindowManagerService#mPerDisplayFocusEnabled 用于控制此功能的可用性。在 ActivityManager 中,系统现在使用的是 ActivityDisplay#getFocusedStack(),而不是利用变量进行全局跟踪。ActivityDisplay#getFocusedStack() 根据 Z 轴顺序确定焦点,而不是通过缓存值来确定。这样一来,只有一个来源 WindowManager 需要跟踪 activity 的 Z 轴顺序。

如果必须要确定系统中最顶层的聚焦堆栈,ActivityStackSupervisor#getTopDisplayFocusedStack() 会采用类似的方法处理这些情况。系统将从上到下遍历这些堆栈,搜索第一个符合条件的堆栈。

InputDispatcher 现在可以有多个聚焦窗口(每个屏幕一个)。如果某个输入事件特定于屏幕,则该事件会被分派到相应屏幕中的聚焦窗口。否则,它会被分派到聚焦屏幕(即用户最近与之交互的屏幕)中的聚焦窗口。

请参阅 InputDispatcher::mFocusedWindowHandlesByDisplay 和 InputDispatcher::setFocusedDisplay()。聚焦应用也会通过 NativeInputManager::setFocusedApplication()InputManagerService 中分别更新。

WindowManager 中,系统还会单独跟踪聚焦窗口。请参阅 DisplayContent#mCurrentFocusDisplayContent#mFocusedApp 以及各自的用途。相关的焦点跟踪和更新方法已从 WindowManagerService 移至 DisplayContent文章来源地址https://www.toymoban.com/news/detail-647264.html

到了这里,关于Android多屏幕支持-Android12的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • android手机安装ubuntu并创建ubuntu图形界面(1)

    在安卓手机上安装Ubuntu并创建图形界面 用手机直接打开网址 Termux | F-Droid - Free and Open Source Android App Repository  点击下载 apk 并安装。 安装后启动界面如下 vi  $PREFIX/etc/apt/sources.list 输入#,即将deb https://termux.org/packages/ stable main注释起来,随后在下一行输入: deb Index of /termux

    2024年02月09日
    浏览(54)
  • matlab 使用预训练神经网络和SVM进行苹果分级(带图形界面)支持其他物品图片分级或者分类

    目录 数据集: 实验代码:alexnet版 如果你的matlab不是正版,先看这里: 数据集结构: 训练代码: 训练结果:  图形界面: 界面展示: 其他:   输出结果:         实验思路是使用预训练神经网络对图片进行特征提取,然后再使用SVM对得到的特征进行处理。         写

    2024年02月09日
    浏览(55)
  • android 12.0长按Power弹出关机对话框去掉屏幕截图和紧急呼救功能

    在12.0的系统长按关机键,会弹出关机的对话框,关机对话框里面由关机重启截图和紧急呼叫等功能,而由于开发功能需求要求去掉屏幕截图和紧急呼叫等功能,所以就要先找到关机对框的代码 然后实现功能 功能分析: 长按电源键弹出关机对话框,通过adb shell命令发现 就是

    2024年02月06日
    浏览(77)
  • Android反射@hide API 方法、变量,支持Android11和Android12

    Android源码中现在有大量的方法和变量被@hide所修饰,而这些被hide修饰的方法和变量是不允许应用层进行反射获取的,所以富有探索精神的程序员们就开始想尽各种办法绕过系统hide限制来使用@hide修饰的方法和变量。 Android11之前 我们可以使用套娃的形式来欺骗系统,让系统误

    2024年02月11日
    浏览(64)
  • 【Android车载系列】第12章 车载渲染-SurfaceFlinger单独绘制到界面

    车载的 倒车影像 同学们知道是怎么实现的吗?等待Android设备开机再打开倒车影像App?车子挂到R档倒车如果等待这个流程实在太久,是否还有其它办法可以让车子挂R档直接展示倒车影像呢?大家思考一下。 我们从Android渲染的基础上思考,Android图像渲染到屏幕上通过 Surfac

    2024年02月04日
    浏览(87)
  • Android 12.0关机界面全屏显示(UI全屏显示)

    在12.0的系统定制化开发中,原生系统关机界面 UI是靠右边显示的,但是客户需求要求全屏显示 重启和关机功能键居中显示,所以就涉及到调整UI 然后全屏显示,需要实现窗口的全局布局实现全屏功能 在关机页面的布局中,经过adb shell命令查看系统关机界面的布局UI就是 Glo

    2024年02月07日
    浏览(43)
  • Android RK3588-12 hdmi-in Camera方式最大支持3个

      hdmi-in Camera最大支持3个     modified:   hardware/interfaces/camera/device/3.4/default/ExternalCameraDevice.cpp     modified:   hardware/interfaces/camera/device/3.4/default/ExternalCameraDeviceSession.cpp     modified:   hardware/interfaces/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h     modified:

    2024年02月08日
    浏览(49)
  • Android Framework解析——WMS原理

    作者:bobby_developer window:它是一个抽象类,具体实现类为 PhoneWindow ,它对 View 进行管理。Window是View的容器,View是Window的具体表现内容; windowManager:是一个接口类,继承自接口 ViewManager ,从它的名称就知道它是用来管理 Window 的,它的实现类为 WindowManagerImpl; WMS:是窗口的管理

    2024年02月13日
    浏览(44)
  • Android WMS——Window窗口(三)

            Window 是一个窗口的概念,是所有视图的载体,不管是 Activity,Dialog,还是 Toast,他们的视图都是附加在 Window 上面的。例如在桌面显示一个悬浮窗,就需要用到 Window 来实现。 WindowManager 是访问 Window 的入口。         Window 类是一个抽象类,他的实现类是 Phon

    2024年02月07日
    浏览(36)
  • android display 杂谈(三)WMS

    用来记录学习wms,后续会一点一点更新。。。。。。 代码:android14 WMS是在SystemServer进程中启动的 在SystemServer中的main方法中,调用run方法。 android14中,在startOtherServices中启动WindowManagerService 该代码执行了WMS的main方法,会在内部创建一个WMS。其中有一个参数inputManager也是在

    2024年02月05日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包