Android 开发者选项-模拟辅助显示设备

目录

    • 概述
    • 使用
    • 开关的代码实现方式
    • 系统部分的处理:
    • 参考

概述

在这里插入图片描述

    在Android开发中,模拟辅助显示设备通常指的是通过Android开发者选项来设置的一种虚拟显示设备,它允许开发者在一个设备上模拟另一个设备的显示特性。这种功能对于测试应用程序在不同屏幕尺寸、分辨率和DPI(每英寸点数)下的表现非常有用。另一个作用是, 它可以通过特定的开发技巧和功能来充当副屏,实现多屏显示的效果。这种功能在开发测试、多任务处理以及特定应用场景(如车载系统)中非常有用。

使用

如何打开

  1. 打开设置
  2. 进入开发者选项 (方法自行查阅)
  3. 选择 模拟辅助显示设备
    在这里插入图片描述

在这里插入图片描述
这个窗口会以浮动窗口的方式显示在上层, 支持的基本操作:

  • 拖动到任意位置
  • 缩放 (长按或多触摸)

开关的代码实现方式

参考系统设置的源代码:

布局文件: packages/apps/Settings/res/xml/development_prefs.xml

        <ListPreferenceandroid:key="overlay_display_devices"android:title="@string/overlay_display_devices_title"android:entries="@array/overlay_display_devices_entries"android:entryValues="@array/overlay_display_devices_values" />

列表和对应的值: frameworks/base/packages/SettingsLib/res/values/arrays.xml

    <!-- Titles for overlay display devices preference. [CHAR LIMIT=35] --><string-array name="overlay_display_devices_entries"><item>None</item><item>480p</item><item>480p (secure)</item><item>720p</item><item>720p (secure)</item><item>1080p</item><item>1080p (secure)</item><item>4K</item><item>4K (secure)</item><item>4K (upscaled)</item><item>4K (upscaled, secure)</item><item>720p, 1080p (dual screen)</item></string-array><!-- Values for overlay display devices preference. --><string-array name="overlay_display_devices_values" translatable="false" ><item></item><item>720x480/142</item><item>720x480/142,secure</item><item>1280x720/213</item><item>1280x720/213,secure</item><item>1920x1080/320</item><item>1920x1080/320,secure</item><item>3840x2160/320</item><item>3840x2160/320,secure</item><item>1920x1080/320|3840x2160/640</item><item>1920x1080/320|3840x2160/640,secure</item><item>1280x720/213;1920x1080/320</item></string-array>

packages/apps/Settings/src/com/android/settings/development/DevelopmentSettings.java

   private void updateOverlayDisplayDevicesOptions() {String value = Settings.Global.getString(getActivity().getContentResolver(),Settings.Global.OVERLAY_DISPLAY_DEVICES);if (value == null) {value = "";}CharSequence[] values = mOverlayDisplayDevices.getEntryValues();for (int i = 0; i < values.length; i++) {if (value.contentEquals(values[i])) {mOverlayDisplayDevices.setValueIndex(i);mOverlayDisplayDevices.setSummary(mOverlayDisplayDevices.getEntries()[i]);return;}}mOverlayDisplayDevices.setValueIndex(0);mOverlayDisplayDevices.setSummary(mOverlayDisplayDevices.getEntries()[0]);}

查看和设置当前配置的值:

# 查看
settings get global overlay_display_devices                                                                                                                                                                                                           
720x480/142# 配置
settings put global overlay_display_devices 1920x1080/320

在应用获得权限的前提下, 可以尝试使用代码来获取和设置:

//获取String overlay_display_devices = Settings.Global.getString(getContentResolver(), "overlay_display_devices");
//设置Settings.Global.putString(getContentResolver(), "overlay_display_devices", "");

系统部分的处理:

frameworks/base/services/core/java/com/android/server/display/OverlayDisplayAdapter.java

    @Overridepublic void registerLocked() {super.registerLocked();getHandler().post(new Runnable() {@Overridepublic void run() {getContext().getContentResolver().registerContentObserver(Settings.Global.getUriFor(Settings.Global.OVERLAY_DISPLAY_DEVICES),true, new ContentObserver(getHandler()) {@Overridepublic void onChange(boolean selfChange) {updateOverlayDisplayDevices();}});updateOverlayDisplayDevices();}});}
private void updateOverlayDisplayDevices() {synchronized (getSyncRoot()) {updateOverlayDisplayDevicesLocked();}}private void updateOverlayDisplayDevicesLocked() {String value = Settings.Global.getString(getContext().getContentResolver(),Settings.Global.OVERLAY_DISPLAY_DEVICES);if (value == null) {value = "";}if (value.equals(mCurrentOverlaySetting)) {return;}mCurrentOverlaySetting = value;if (!mOverlays.isEmpty()) {Slog.i(TAG, "Dismissing all overlay display devices.");for (OverlayDisplayHandle overlay : mOverlays) {overlay.dismissLocked();}mOverlays.clear();}int count = 0;for (String part : value.split(";")) {Matcher displayMatcher = DISPLAY_PATTERN.matcher(part);if (displayMatcher.matches()) {if (count >= 4) {Slog.w(TAG, "Too many overlay display devices specified: " + value);break;}String modeString = displayMatcher.group(1);String flagString = displayMatcher.group(2);ArrayList<OverlayMode> modes = new ArrayList<>();for (String mode : modeString.split("\\|")) {Matcher modeMatcher = MODE_PATTERN.matcher(mode);if (modeMatcher.matches()) {try {int width = Integer.parseInt(modeMatcher.group(1), 10);int height = Integer.parseInt(modeMatcher.group(2), 10);int densityDpi = Integer.parseInt(modeMatcher.group(3), 10);if (width >= MIN_WIDTH && width <= MAX_WIDTH&& height >= MIN_HEIGHT && height <= MAX_HEIGHT&& densityDpi >= DisplayMetrics.DENSITY_LOW&& densityDpi <= DisplayMetrics.DENSITY_XXXHIGH) {modes.add(new OverlayMode(width, height, densityDpi));continue;} else {Slog.w(TAG, "Ignoring out-of-range overlay display mode: " + mode);}} catch (NumberFormatException ex) {}} else if (mode.isEmpty()) {continue;}}if (!modes.isEmpty()) {int number = ++count;String name = getContext().getResources().getString(com.android.internal.R.string.display_manager_overlay_display_name,number);int gravity = chooseOverlayGravity(number);boolean secure = flagString != null && flagString.contains(",secure");Slog.i(TAG, "Showing overlay display device #" + number+ ": name=" + name + ", modes=" + Arrays.toString(modes.toArray()));mOverlays.add(new OverlayDisplayHandle(name, modes, gravity, secure, number));continue;}}Slog.w(TAG, "Malformed overlay display devices setting: " + value);}}

创建OverlayDisplayDevice, 并显示

    /*** Functions as a handle for overlay display devices which are created and* destroyed asynchronously.** Guarded by the {@link DisplayManagerService.SyncRoot} lock.*/private final class OverlayDisplayHandle implements OverlayDisplayWindow.Listener {private static final int DEFAULT_MODE_INDEX = 0;private final String mName;private final List<OverlayMode> mModes;private final int mGravity;private final boolean mSecure;private final int mNumber;private OverlayDisplayWindow mWindow;private OverlayDisplayDevice mDevice;private int mActiveMode;public OverlayDisplayHandle(String name, List<OverlayMode> modes, int gravity,boolean secure, int number) {mName = name;mModes = modes;mGravity = gravity;mSecure = secure;mNumber = number;mActiveMode = 0;showLocked();}private void showLocked() {mUiHandler.post(mShowRunnable);}public void dismissLocked() {mUiHandler.removeCallbacks(mShowRunnable);mUiHandler.post(mDismissRunnable);}private void onActiveModeChangedLocked(int index) {mUiHandler.removeCallbacks(mResizeRunnable);mActiveMode = index;if (mWindow != null) {mUiHandler.post(mResizeRunnable);}}// Called on the UI thread.@Overridepublic void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate,long presentationDeadlineNanos, int state) {synchronized (getSyncRoot()) {IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure);mDevice = new OverlayDisplayDevice(displayToken, mName, mModes, mActiveMode,DEFAULT_MODE_INDEX, refreshRate, presentationDeadlineNanos,mSecure, state, surfaceTexture, mNumber) {@Overridepublic void onModeChangedLocked(int index) {onActiveModeChangedLocked(index);}};sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);}}

参考

Android双屏异显(Presentation)与后台动态配置副屏内容
Android双屏异显以及原理分析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/63714.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android 常用三方框架

说实话&#xff0c; 我是比较讨厌三方框架的&#xff0c; 比如一个eventbus 底层逻辑就是个观察者模式&#xff0c;当然他的场景涵盖的比较丰富&#xff0c; 单从 单一原则来说&#xff0c; 还是一个简单的观察者模式就能解决问题&#xff0c; 何必要添加那么多文件到我们的项目…

[COLM 2024] V-STaR: Training Verifiers for Self-Taught Reasoners

本文是对 STaR 的改进方法&#xff0c;COLM 是 Conference On Language Models&#xff0c;大模型领域新出的会议&#xff0c;在国际上很知名&#xff0c;不过目前还没有被列入 ccf list&#xff08;新会议一般不会列入&#xff09;&#xff1b;作者来自高校、微软研究院和 Goo…

从C#中的结构体和类的区别中看引用和值的问题

在 C#中&#xff0c;结构体&#xff08;struct&#xff09;和类&#xff08;class&#xff09;都是用于创建自定义数据类型的方式&#xff0c;但它们在很多方面存在着显著的区别。掌握他们的区别至少不会产生一些我们不了解情况下发生的错误。 文章目录 一、作为参数传递时的差…

Spann3R:基于DUSt3R的密集捕获数据增量式重建方法

来自作者Hengyi Wang在b站3D视觉工坊中对于该论文透彻的讲解&#xff0c;这里是相关重要部分的截屏。这篇博客的用途主要是自己做记录&#xff0c;其次分享给感兴趣的同学&#xff0c;最后谢谢作者大佬的认真讲解。 作者是按照这样的次序来介绍的&#xff1a; 首先从传统的三…

Python4-分支与循环

记录python学习&#xff0c;直到学会基本的爬虫&#xff0c;使用python搭建接口自动化测试就算学会了&#xff0c;在进阶webui自动化&#xff0c;app自动化 python基础3-分支与循环语句 python中 有哪些基本值是被当作true或者false的呢?if语句示例被视为 False 的情况被视为…

SAP-ABAP开发学习-面向对象OOALV(1)

本文目录 一、概述 面向对象开发特点 二、类与对象 程序中类的创建 Class构成要素 对象 方法 一、概述 随着SAP R/3 4.0版本的开发&#xff0c;ABAP语言开始引入了面向对象的开发概念。这在ABAP语言的发展过程中&#xff0c;面向对象&#xff08;Object-oriented&#…

【实用技能】如何在 .NET C# 中的邮件合并过程中操作表格单元格

TX Text Control 中的邮件合并 类是一个强大的库&#xff0c;旨在通过将数据合并到模板中来自动创建文档。它充当结构化数据&#xff08;例如来自数据库、JSON 或 XML&#xff09;和动态文档生成之间的桥梁&#xff0c;对于需要自动化文档工作流程的应用程序来说非常有用。 TX…

有源模拟滤波器的快速设计

本文章是笔者整理的备忘笔记。希望在帮助自己温习避免遗忘的同时&#xff0c;也能帮助其他需要参考的朋友。如有谬误&#xff0c;欢迎大家进行指正。 一、概述 几乎所有电子电路中都能看到有源模拟滤波器的身影。音频系统使用滤波器进行频带限制和平衡。通信系统设计使用滤波…

如何使用Python库连接Redis

1、redis-py 库封装一个 Redis 工具类可以帮助我们简化 Redis 的操作并提高代码的复用性和可维护性。 安装redis pip install redisimport redis import logginglogging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__)class RedisUtils:def __init__(s…

【代码随想录day57】【C++复健】 53. 寻宝(prim算法);53. 寻宝(kruskal算法)

53. 寻宝&#xff08;prim算法&#xff09; 好像在研究生的算法课上学过prim算法和kruskal算法&#xff0c;不过当时只是了解了一下大致的概念和流程&#xff0c;并没有涉及到如何去写代码的部分&#xff0c;今天也算是学习了一下这两个算法的代码应该如何去实现&#xff0c;还…

使用OpenTK展示3D点云图像(C#)

最近在研究3D显示&#xff0c;找到一款在winform上展示3D点云的控件&#xff0c;并且实现了点线面的展示&#xff0c;及光照渲染纹理贴图等功能&#xff0c;如下面几张图所展示。 一些基础知识可以在LearnOpenTK - OpenTK 这个网站上学习到。 我这边使用的是openTK3.3.3版本&a…

MetaGPT源码 (Memory 类)

目录 MetaGPT源码&#xff1a;Memory 类例子 MetaGPT源码&#xff1a;Memory 类 这段代码定义了一个名为 Memory 的类&#xff0c;用于存储和管理消息(Message)对象。Memory 提供了多种操作消息的功能&#xff0c;包括添加单条或批量消息、按角色或内容筛选消息、删除最新消息…

pythonOpenCV篇:0基础带你python入门之常用函数

① 二值化函数 功能&#xff1a;将图像转换为二值图像&#xff08;黑白图像&#xff09;&#xff0c;将像素值分为两种类别&#xff1a;前景&#xff08;白&#xff09;和背景&#xff08;黑&#xff09;。函数&#xff1a;cv2.threshold()参数&#xff1a; src&#xff1a;输…

小发现,如何高级的顺序输出,逆序输出整数的每一位(栈,队列)

当我还是初学者的时候&#xff0c;我经常思考有没有比慢慢求每一位数字然后考虑正序&#xff0c;逆序输出要快的办法...长期琢磨&#xff0c;必有所获&#xff01; 我刚学数据结构的时候还没意识到栈&#xff0c;队列还能这样用&#xff0c;虽然说有点杀鸡用牛刀的感觉&#x…

详细解析RNNoise:基于深度学习的语音噪声抑制技术

引言 在语音通信、语音识别以及音频处理领域&#xff0c;噪声抑制是一个至关重要的任务。环境噪声&#xff0c;如风声、交通声和人群声&#xff0c;通常会影响语音的清晰度和质量&#xff0c;特别是在远程通信和在线会议中。为了提高语音质量&#xff0c;许多噪声抑制技术应运…

【笔记】架构上篇Day6 法则四:为什么要顺应技术的生命周期?

法则四&#xff1a;为什么要顺应技术的生命周期&#xff1f; 简介&#xff1a;包含模块一 架构师的六大生存法则-法则四&#xff1a;为什么要顺应技术的生命周期&#xff1f;&法则四&#xff1a;架构设计中怎么判断和利用技术趋势&#xff1f; 2024-08-29 17:30:07 你好&am…

跟李笑来学美式俚语(Most Common American Idioms): Part 66

Most Common American Idioms: Part 66 前言 本文是学习李笑来的Most Common American Idioms这本书的学习笔记&#xff0c;自用。 Github仓库链接&#xff1a;https://github.com/xiaolai/most-common-american-idioms 使用方法: 直接下载下来&#xff08;或者clone到本地…

【Sentinel Go】新手指南、流量控制、熔断降级和并发隔离控制

随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开…

代码随想录第43天

300.最长递增子序列 # Dynamic programming. class Solution:def lengthOfLIS(self, nums: List[int]) -> int:if not nums: return 0dp [1] * len(nums)for i in range(len(nums)):for j in range(i):if nums[j] < nums[i]: # 如果要求非严格递增&#xff0c;将此行 …

Anaconda Conda Pip 的区别与联系

在Python生态中,Anaconda、Conda和Pip是三个非常重要的工具,它们在包管理和环境管理方面发挥着关键作用。 Anaconda Anaconda是一个为科学计算而设计的Python发行版,它集成了Conda、Python以及大量的数据科学相关库,如NumPy、Pandas等。Anaconda的主要优势在于它提供了一个…