在安卓N系统中如何通过程序改变系统显示大小

14

背景: Android N版本增加了一个“显示大小”变更系统设置的功能,此外还提供了之前存在的“字体大小”变更功能。

更改显示大小:

enter image description here

图片来源:pcmag.com

问题:

如果一个应用程序拥有android.permission.WRITE_SETTINGS权限来更改设置,则可以按照如何以编程方式更改设备字体样式和字体大小的方法中所述的方法来以编程方式更改系统字体大小。但是我无法找到一种以编程方式更改显示大小的方法,这可行吗?

我尝试了什么?

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

更新:

我已在此处开放了相同的功能请求: https://code.google.com/p/android/issues/detail?id=214124。如果您认为这将有用,请对其进行标记。

3个回答

7

我分享我的解决这个问题的方法。尽管不太优雅,但我使用了Java反射技术实现了该功能。

主要参考源代码文件如下:

接下来,按照以下步骤操作,即可获得所需控制:

  1. 查看 ZoomScreenSettings.java 的 onCreate() 和 commit() 方法。它们演示了如何正确地获取和设置密度值到框架中。
  2. 查看 DisplayDensityUtils.java。它展示了如何使用 WindowManagerService 控制系统密度。由于我们无法通过反射获取 DisplayDensityUtils 的实例,因此需要了解哪些 WindowManagerService 方法被使用。
  3. 使用反射获取 WindowManagerService 的实例,并在您的项目中编写类似于 DisplayDensityUtils 的类。
// 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

  1. 使用类似于DisplayDensityUtils的工具类设置或获取密度值。需要注意的一点是,如果您想传递一个索引值(例如,大型显示器为2),请将其提供给DisplayDensityUtils类的mValues数组以获取实际的密度值,这才是应该传递给框架的正确值。获取当前密度索引也适用相同的概念。

1
这需要 WRITE_SECURE_SETTINGS 权限,只能通过 adb 授予。 - Pablo Cegarra

5
在清单文件(manifest)中,位于应用程序(application)下面: android:configChanges="density" 在一个活动(activity)/应用程序(application)中:
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语句更好的方法。


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_SMALLSCREENLAYOUT_SIZE_NORMALSCREENLAYOUT_SIZE_LARGESCREENLAYOUT_SIZE_XLARGE之一。

希望这有所帮助。


@alanv 感谢您关注此事。看起来它似乎不起作用。您能否指导一下,Android开源项目 - 问题跟踪器 是正确的地方来提出相同功能的请求,还是我们需要在其他地方提出请求?感谢pRaNay的帮助。不幸的是,它似乎不起作用。 - Shobhit Puri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接