欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > Android 开发者选项-模拟辅助显示设备

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

2025/9/15 11:25:56 来源:https://blog.csdn.net/ansondroider/article/details/144396040  浏览:    关键词: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双屏异显以及原理分析

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词