Change the system display size programmatically Android N
Asked Answered
N

3

14

Background: Android N comes with a feature to change system Display Size from settings, in addition to the previously present feature of changing Font Size.

Change Display Size:

enter image description here

Image Source: pcmag.com

Question:

If an app has android.permission.WRITE_SETTINGS permission to change the settings, there are ways to change the system font size programatically as mentioned in How to programmatically change font settings of Device: font style and font size?. However I couldn't find a way to change the display size programmatically. Is it possible?

What I've tried?

I've checked the possible options in the list of Settings.System convenience functions provided for changing settings programmatically.

Update:

I've opened a feature request for the same here: https://code.google.com/p/android/issues/detail?id=214124 . If you feel it would be useful please star it.

Norikonorina answered 23/6, 2016 at 16:1 Comment(0)
T
7

Just share my approach to tackle this requirement. I achieve this function by using the dirty Java reflection method - although it's not that elegant.

The main reference source code files are:

And, follow the below steps, then you can get the required control:

  1. Read ZoomScreenSettings.java's onCreate() and commit(). They demonstrate how to correctly get and set the density value into the framework.
  2. Read DisplayDensityUtils.java. It shows how to use WindowManagerService to control the system density. Because we can't get the instance of DisplayDensityUtils via reflection, we need to understand which WindowManagerService methods are utilized.
  3. Use reflection to get WindowManagerService's instance, and write a DisplayDensityUtils-like class into your project.
// 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. Set or get the density value with your DisplayDensityUtils-like class. One thing just to mention is that, if you want to pass an index value (e.g., 2 for large display size), please feed it to your DisplayDensityUtils-like class's mValues array to get the actual density value which is the right one to pass to the framework. Getting the current density index also applies the same concept.
Tytybald answered 14/2, 2020 at 9:25 Comment(1)
This requires the permission WRITE_SECURE_SETTINGS, and only can be granted by adb :CPolaris
T
6

In manifest, under application: android:configChanges="density"

In an 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);
    }
}

Call it just after super.onCreate(..):

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

This will set the Display Size in-between the "Smaller" and "Small" settings of "Display Size" overriding any Display Size settings set by user. It self-adjusts correctly for 4in, 5.5in, 6in etc devices.. but I'm sure there would a better way than using those if statements.

Tamra answered 22/7, 2018 at 22:58 Comment(0)
L
1

While referring Settings.System , there is a [putConfiguration(ContentResolver cr, Configuration config)](https://developer.android.com/reference/android/provider/Settings.System.html#putConfiguration(android.content.ContentResolver, android.content.res.Configuration)) method. Use of this method is:

Convenience function to write a batch of configuration-related settings from a Configuration object.

In Configuration

This includes both user-specified configuration options (locale list and scaling) as well as device configurations (such as input modes, screen size and screen orientation).

Set configuration with SCREENLAYOUT_SIZE_MASK values for screen size. It is:

The SCREENLAYOUT_SIZE_MASK bits define the overall size of the screen. They may be one of SCREENLAYOUT_SIZE_SMALL, SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_LARGE, or SCREENLAYOUT_SIZE_XLARGE.

I hope its helps you.

Lepage answered 24/6, 2016 at 9:43 Comment(1)
@alanv Thanks for looking into it. It doesn't seem like it works. Can you please guide that Android Open Source Project - Issue Tracker is the right place to open the feature request for the same or do we need to request it somewhere else? Thanks pRaNay for the effort to help. Unfortunately, it doesn't seem to work.Norikonorina

© 2022 - 2024 — McMap. All rights reserved.