javaandroidmobilescreen-orientationandroid-orientation

Android APIs frequently return incorrect screen resolutions after device rotation


I need to know the dimensions of an app in pixels for screen capture purposes. Previously I used methods like getRealMetrics to get the resolution and this works flawlessly under normal circumstances but have recently discovered (seemingly on Android versions 30+) that if the device is rotated the width and height values returned by the APIs will sometimes update to reflect the view being rotated but other times will not.

EDIT: I'm starting to suspect this may be due to behavior changes in WindowManager and it not being updated properly?

This all seems to work correctly on Android 29 and below but for some reason newer versions of android don't seem to update values derived from the WindowManager properly.

For example, if my app is 200px high and 100px wide in portrait mode, rotating into landscape will sometimes update to 100px high, 200px wide, but just as often it will continue to return 200px high, 100px wide indefinitely. In my experience so far there is no clear reason for why it sometimes updates correctly but other times does not.

My code is very simple and looks roughly like this. I have tried using getRealMetrics as well as the more recent getCurrentWindowMetrics where appropriate and even very deprecated methods like getWidth for the sake of testing but each one returns the same correct or incorrect value in sync with one another. (In other words, after each rotation they all are either correct or incorrect, so they are seemingly all getting data from the same ground "truth"). Considering this seems to be more common if not exclusive to newer devices I was really hoping that using the newer getCurrentWindowMetrics would work but no such luck.

EDIT Tried playing around with display.getRotation() and noticed that it always returned 0 no matter what I did so something fundamental isn't being set correctly.

Also note this isn't outwardly a race condition since once the rotation occurs the correct or incorrect values continue to be returned by the APIs until another rotation, at which point it's roughly 50/50 on whether on this rotation the values will be updated correctly on not.

import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
import android.view.WindowMetrics;
import androidx.annotation.NonNull;

public class DisplayUtil {

  private static WindowManager windowManagerInstance;


  public static void getScreenDimensions() {
    Display getOrient = windowManagerInstance.getDefaultDisplay();

    if (VERSION.SDK_INT >= VERSION_CODES.R) {
      WindowMetrics metrics = windowManagerInstance.getCurrentWindowMetrics();
    } else {
      DisplayMetrics metrics = new DisplayMetrics();
      windowManagerInstance.getDefaultDisplay().getRealMetrics(metrics);
    }
  }

  public static synchronized void setWindowManager(WindowManager windowManager) {
    windowManagerInstance = windowManager;
  }
}

Has anyone else experienced this behavior before? Is this expected behavior or a known bug somehow? The inconsistency really throws me off. Is there some way something in my app is to blame here?

Example screenshot here, where "old" and "new" methods return (approximately) the same incorrect values.

Example screenshot here, where "old" and "new" methods return (approximately) the same incorrect values.


Solution

  • Turns out my suspicions were correct and all I had to do was update the WindowManager when appropriate! In this case I had a WindowCallback class that implemented Window.Callback and I could perform the update to the window manager there. The callback was called anytime the device orientation changed so the WindowManager object was always updated when the height and width flipped. A little annoying this is only an issue on newer versions of android (I think 30+) but glad it's resolved.