以编程方式更改系统显示大小 Android N

Posted

技术标签:

【中文标题】以编程方式更改系统显示大小 Android N【英文标题】:Change the system display size programmatically Android N 【发布时间】:2016-10-26 01:57:53 【问题描述】:

背景:除了之前提供的更改Font Size 的功能之外,android N 还具有从设置更改系统Display Size 的功能。

改变显示尺寸

图片来源:pcmag.com

问题

如果应用拥有android.permission.WRITE_SETTINGS 更改设置的权限,则可以通过How to programmatically change font settings of Device: font style and font size? 中提到的以编程方式更改系统字体大小的方法。但是我找不到以编程方式更改显示大小的方法。可能吗?

我尝试了什么?

我已经检查了Settings.System 为以编程方式更改设置提供的便利函数列表中的可能选项。

更新

我在这里打开了相同的功能请求:https://code.google.com/p/android/issues/detail?id=214124。如果觉得有用请star一下。

【问题讨论】:

【参考方案1】:

在引用 Settings.System 时,有一个 [putConfiguration(ContentResolver cr, Configuration config)](https://developer.android.com/reference/android/provider/Settings.System.html#putConfiguration(android.content.ContentResolver, android.content.res.Configuration)) 方法。 该方法的使用方法是:

Configuration对象写入一批配置相关设置的便捷函数。

在Configuration

这包括用户指定的配置选项(区域设置列表和缩放)以及设备配置(例如输入模式屏幕尺寸屏幕方向)。

使用SCREENLAYOUT_SIZE_MASK 屏幕尺寸值设置配置。 它是:

SCREENLAYOUT_SIZE_MASK 位定义屏幕的整体大小。它们可能是SCREENLAYOUT_SIZE_SMALL、SCREENLAYOUT_SIZE_NORMAL、SCREENLAYOUT_SIZE_LARGE 或SCREENLAYOUT_SIZE_XLARGE 之一。

希望对你有帮助。

【讨论】:

@alanv 感谢您的调查。它似乎不起作用。您能否指导Android Open Source Project - Issue Tracker 是打开相同功能请求的正确位置,还是我们需要在其他地方请求?感谢 pRaNay 的帮助。不幸的是,它似乎不起作用。【参考方案2】:

在清单中,在应用程序中:android:configChanges="density"

在活动/应用程序中:

public void adjustDisplayScale(Configuration configuration) 
    if (configuration != null) 
        Log.d("TAG", "adjustDisplayScale: " + configuration.densityDpi);
        if(configuration.densityDpi >= 485) //for 6 inch device OR for 538 ppi
            configuration.densityDpi = 500; //decrease "display size" by ~30
        else if(configuration.densityDpi >= 300) //for 5.5 inch device OR for 432 ppi
            configuration.densityDpi = 400; //decrease "display size" by ~30
        else if(configuration.densityDpi >= 100) //for 4 inch device OR for 233 ppi
            configuration.densityDpi = 200; //decrease "display size" by ~30
        DisplayMetrics metrics = getResources().getDisplayMetrics();
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.getDefaultDisplay().getMetrics(metrics);
        metrics.scaledDensity = configuration.densityDpi * metrics.density;
        this.getResources().updateConfiguration(configuration, metrics);
    

在 super.onCreate(..) 之后调用它:

protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    adjustDisplayScale( getResources().getConfiguration());

这将在“显示尺寸”的“较小”和“小”设置之间设置显示尺寸,覆盖用户设置的任何显示尺寸设置。 对于 4 英寸、5.5 英寸、6 英寸等设备,它自我调整正确。但我相信有比使用这些 if 语句更好的方法。

【讨论】:

【参考方案3】:

请分享我解决此要求的方法。我通过使用肮脏的 Java 反射方法来实现这个功能 - 虽然它不是那么优雅。

主要参考源代码文件有:

ScreenZoomSettings.java (https://github.com/aosp-mirror/platform_packages_apps_settings/blob/master/src/com/android/settings/display/ScreenZoomSettings.java) DisplayDensityUtils.java (http://androidxref.com/9.0.0_r3/xref/frameworks/base/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java) WindowManagerGlobal.java (http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/view/WindowManagerGlobal.java)

并且,按照以下步骤,就可以得到所需的控制:

    阅读ZoomScreenSettings.java 的onCreate() 和commit()。他们演示了如何正确获取密度值并将其设置到框架中。 阅读DisplayDensityUtils.java。它展示了如何使用WindowManagerService 来控制系统密度。因为我们无法通过反射得到DisplayDensityUtils的实例,所以我们需要了解使用了哪些WindowManagerService方法。 使用反射获取WindowManagerService的实例,并将DisplayDensityUtils-like类写入您的项目中。
// Where wm is short for window manager
val wmGlobalClz = Class.forName("android.view.WindowManagerGlobal")
val getWmServiceMethod = wmGlobalClz.getDeclaredMethod("getWindowManagerService")
val wmService = getWmServiceMethod.invoke(wmGlobalClz)

val wmInterfaceClz = Class.forName("android.view.IWindowManager")

// Now, we already have the ability to do many things we want.
// For instance, to get the default density value.
val getInitialDisplayDensityMethod = wmInterfaceClz.getDeclaredMethod(
        "getInitialDisplayDensity", 
        Integer.TYPE
)
val defaultDensity = getInitialDisplayDensityMethod.invoke(
        wmService,
        Display.DEFAULT_DISPLAY
) as Int

    使用DisplayDensityUtils-like 类设置或获取密度值。需要提及的一件事是,如果您想传递一个索引值(例如,2 表示大显示尺寸),请将其提供给您的 DisplayDensityUtils-like 类的 mValues 数组以获得实际的密度值,即正确的一个传递给框架。获取当前密度指数也适用相同的概念。

【讨论】:

这需要权限 WRITE_SECURE_SETTINGS,并且只能由 adb :C 授予

以上是关于以编程方式更改系统显示大小 Android N的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式更改整个应用程序中的字体大小,Android?

如何在 Android 中以编程方式更改按钮大小?

如何在 Android 2016 中以编程方式更改应用程序图标

如何以编程方式更改视图大小?

在 Android 中以编程方式更改 ImageView 的图像

以编程方式更改不同 iPad 屏幕分辨率上的 .xib 大小