March3April4
March3April4

Reputation: 2281

Android how to force screen density by default

By magnifying the screen by "Settings / Displays", I've found that my galaxy s9+'s screen density changes to 430 dpi to somewhere over 600dpi.

This makes the layout and images to change to xxhdpi to xxxhdpi.

If I have a textView which has the fixed size of 16dp,

it was 16 * 3 px in xxhdpi, and will become 16 * 4 px in xxxhdpi.

This makes my layout(of course texts from editTexts or textViews) to become much bigger since the actual density of the device never changes, which google(or the maker samsumg) intended for this function.

But I do not want this to happen in my app.

I've tried to fix it by doing this ;

Configuration configuration = activity.getResources().getConfiguration();

if (configuration.densityDpi != 430) { 
                configuration.densityDpi = 430;    
}

DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
WindowManager wm = (WindowManager) activity.getSystemService(activity.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(metrics);
metrics.scaledDensity = configuration.densityDpi * metrics.density;
activity.getResources().updateConfiguration(configuration, metrics);

This forces the screen density to become 430 and works fine on galaxy s9+. But, as a matter of fact, the default density will not be 430 for all devices.

How can I figure out the default density of the device which runs my application?

Or is there a configuration to ignore the magnify effect for my application?

Upvotes: 5

Views: 4999

Answers (2)

alx_gord
alx_gord

Reputation: 180

Here`s a modified @March3April4 solution (in Kotlin) that works with density, resolution, and font scale changes. Override attachBaseContext function of Activity.

override fun attachBaseContext(newBase: Context) {
    val configuration = newBase.resources.configuration
    val displayMetrics = newBase.resources.displayMetrics

    val snap = 20
    val exactDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2
    val dpi = displayMetrics.densityDpi.toFloat()

    if (dpi - exactDpi > snap) {
        val targetDpi = (ceil((exactDpi / snap).toDouble()) * snap).toInt()

        configuration.densityDpi = targetDpi
        configuration.setTo(configuration)
    }

    if (configuration.fontScale != 1.0f) {
        configuration.fontScale = 1.0f
    }

    val newContext = newBase.createConfigurationContext(configuration)
    super.attachBaseContext(newContext)
}

Upvotes: 0

March3April4
March3April4

Reputation: 2281

This seems to work for me.

        DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();

        int snap = 20;
        float exactDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2;
        float dpi = displayMetrics.densityDpi;

        if (dpi - exactDpi > snap) {

            int targetDpi = (int) (Math.ceil(exactDpi / snap) * snap);

            Configuration config = activity.getResources().getConfiguration();

            ErrorController.showMessage("adjustDisplayScale : " + config.densityDpi);

            ErrorController.showMessage("targetDpi : " + targetDpi);


            displayMetrics.densityDpi = targetDpi;
            config.densityDpi = targetDpi;
            displayMetrics.setTo(displayMetrics);
            config.setTo(config);
            activity.getResources().updateConfiguration(config, displayMetrics);
        }

Upvotes: 4

Related Questions