How to get screen size in Android, including virtual buttons? - android

For normal uses you can use the DisplayMetrics class and get the "renderable" size, but I want to figure out the actual physical screen size, which includes the virtual buttons height.
On my Galaxy Nexus the reported size no matter what I tried is 1196x720, what can I use to get the physical one which is 1280x720 ? Same goes for Nexus 7, Nexus 4 and Nexus 10 devices.
UPDATE : This is the final code I now use, including the fix :
//Activity A = this;
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager wm = (WindowManager) A.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
Display disp = wm.getDefaultDisplay();
int API_LEVEL = android.os.Build.VERSION.SDK_INT;
if (API_LEVEL >= 17)
{
disp.getRealMetrics(displayMetrics);
}
else
{
disp.getMetrics(displayMetrics);
}
int Width = displayMetrics.widthPixels;
int Height = displayMetrics.heightPixels;

You should use Display.getRealSize(Point) From the official docs here
The display area is described in two different ways.
The application display area specifies the part of the display that
may contain an application window, excluding the system decorations.
The application display area may be smaller than the real display area
because the system subtracts the space needed for decor elements such
as the status bar. Use the following methods to query the application
display area: getSize(Point), getRectSize(Rect) and
getMetrics(DisplayMetrics).
The real display area specifies the part
of the display that contains content including the system decorations.
Even so, the real display area may be smaller than the physical size
of the display if the window manager is emulating a smaller display
using (adb shell am display-size). Use the following methods to query
the real display area: getRealSize(Point),
getRealMetrics(DisplayMetrics).

The answer in the similar question seems to have a solution to get the real size of the display when API < 17 https://stackoverflow.com/a/15699681/601298
WindowManager w = activity.getWindowManager();
Display d = w.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
d.getMetrics(metrics);
// since SDK_INT = 1;
widthPixels = metrics.widthPixels;
heightPixels = metrics.heightPixels;
// includes window decorations (statusbar bar/menu bar)
if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17)
try {
widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);
heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);
} catch (Exception ignored) {
}
// includes window decorations (statusbar bar/menu bar)
if (Build.VERSION.SDK_INT >= 17)
try {
Point realSize = new Point();
Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
widthPixels = realSize.x;
heightPixels = realSize.y;
} catch (Exception ignored) {
}

Related

Does getSize() in Android include the height of the status bar?

Is there a way to tell if getSize() includes the height of the status bar? From testing on a few different phones it seems it does on some but not on others and it is frustrating when trying to make everything in the layout line up properly.
After spending a week on this problem and checked Google's documentation & many other posts here on Stackoverflow (about getting the screen size in pixels via getSize(), getRealSize(), getMetrics(DisplayMetrics metrics), getRealMetrics(DisplayMetrics metrics), etc ... I still have no clue about it.
This picture is giving a better picture of the problem.
On some phones and according to the above picture, the line 'Y/2' should be exactly at size.y / 2 (exact half of the screen between the navigation & the status bars), but is actually not in the middle : The 'Not X' distance on my picture is therefore equal to 'X - getStatusBarSize()'.
I have to add that i am using a ring object with an innerRadiusRatio 2.1 in XML.
But i don't think it's the reason because once i am using the code below, it works on phones where getSize() seems to include the height of the status bar :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Screen dimensions
display = getWindowManager().getDefaultDisplay();
size = new Point();
display.getSize(size);
//Get the screen dimensions
maxWidth = size.x
maxHeight = size.y - getStatusBarSize();
}
private int getStatusBarSize() {
Resources resources = getResources();
int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
return resources.getDimensionPixelSize(resourceId);
}
return 0;
}
While it works simply with maxheight = size.y on others phones (where it does not include the status bar height).
Thanks in advance guys for any help !
I was facing to the same issue more or less and this could be helpful :
// Get the size between the status & the navigation bars
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
// Real size of the screen (full screen)
Point realSize = new Point();
Display realDisplay = getWindowManager().getDefaultDisplay();
realDisplay.getRealSize(realSize);
//Get the screen dimensions
maxWidth = size.x;
maxHeight = size.y;
if (realSize.y - getNavBarSize() == size.y || realSize.y == size.y) {
Log.d(TAG, "onCreate: getSize() includes the status bar size");
maxHeight = size.y - getStatusBarSize();
}
I've had the same question and this is how I solved it.
Display.getSize() only sometimes includes the status bar height.
For the solution with .getRealSize() you also need the navigation bar height.
With the following solution you don't need the navigation bar height:
View contentView = requireActivity().getWindow().findViewById(Window.ID_ANDROID_CONTENT);
int height = contentView.getHeight() - statusBarHeight - actionBarHeight;
(You might have to get the height in contentView.post() if it returns 0.)

Get the size of the screen not using getMetrics

I'd like to get the size of the screen of the phones but it keeps giving me wrong values, I already used
WindowManager windowmanager = (WindowManager)
getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
Display display = windowmanager.getDefaultDisplay();
DisplayMetrics displayMetrics = new DisplayMetrics();
display.getMetrics(displayMetrics);
float deviceWidth = displayMetrics.widthPixels;
float deviceHeight = displayMetrics.ydpi;
I tried this code too :
Resources resources = getResources();
Configuration config = resources.getConfiguration();
DisplayMetrics dm = resources.getDisplayMetrics();
// Note, screenHeightDp isn't reliable
// (it seems to be too small by the height of the status bar),
// but we assume screenWidthDp is reliable.
// Note also, dm.widthPixels,dm.heightPixels aren't reliably pixels
// (they get confused when in screen compatibility mode, it seems),
// but we assume their ratio is correct.
double screenWidthInPixels = (double)config.screenWidthDp *dm.density;
double screenHeightInPixels = screenWidthInPixels * dm.heightPixels / dm.widthPixels;
deviceWidth = (int)(screenWidthInPixels + .5);
deviceHeight = (int)(screenHeightInPixels + .5);
And also that :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Point realSize = new Point();
display.getRealSize(realSize);
deviceWidth= realSize.x;
deviceHeight = realSize.y;
}
But on my Samsung S7 on sdk 7.0 I got 1920x1080 that is wrong because on a S7 on sdk 6.0.1 I got 2560x1440 that is the real value.
I tried a lot of solution but found nothing good.
Thanks
Your code is correct. Just in case if you wondering why you get that values, it is because your phone will automatically set the default resolution size to 1920x1080 after updated to 7.0 (Nougat) to conserve the battery life. One of the new features in Nougat is display scaling option, where you can set your phone (in this case, S7) to 3 available modes (WQHD (2560x1440), FHD (1920x1080), and HD (1280x720)). Try go to Settings -> Display and change the settings to your needs. You can read more here: Galaxy S7 on Nougat defaults to 1080p
use this
getWindowManager().getDefaultDisplay().getHeight();
getWindowManager().getDefaultDisplay().getWidth();
This will work for sure.
try {
display.getRealSize(size);
height = size.y;
width=size.x;
} catch (NoSuchMethodError e) {
height = display.getHeight();
width=display.getWidth();
}
Try this link
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
The method below return a Point that contain display size (x as Width and y as Height):
public static Point checkDisplaySize(Context context) {
Point tempDisplaySize = new Point();
try {
WindowManager manager = (WindowManager) context().getSystemService(Context.WINDOW_SERVICE);
if (manager != null) {
Display display = manager.getDefaultDisplay();
if (display != null) {
display.getSize(tempDisplaySize);
Log.d("tmessages", "display size = " + displaySize.x + " " + displaySize.y);
}
}
} catch (Exception e) {
Log.e("tmessages", e.getMessage(), e);
}
return tempDisplaySize;
}
P.S: This is the Code Telegram uses to get display size.

Android proper way to fit layout on all devices horizontally and vertically

Hello I want to ask about the most efficient way to adjust layout in all devices mobile and tablets sometimes I can't use wrap_content and layout_weight
I set size in some percentage to the device size in java like this:
ImageView img;
Display display = getWindowManager().getDefaultDisplay();
width = display.getWidth();
height = display.getHeight();
img.getLayoutParams().width = width* 7 / 10;
and when rotating screen I use this method to change percentage
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE&& getResources().getBoolean(R.bool.isTablet)) {
width=(int) (width * 0.7);
}
I am asking If this procedure is more efficient than using multi XML files for each screen size / orientation
Actually it depends on the scenario. Sometimes maintaining xml is efficient and easy sometimes dynamic calculation is necessary. You can go through the link https://developer.android.com/guide/practices/screens_support.html . It will give you some ideas. In your above code for width/height calculation sometimes you may not get proper result for some devices. Below is the code that will support all version of android device Resolution(Width, Height) accurately at runtime.
private void calculateDeviceResolution(Activity context) {
Display display = context.getWindowManager().getDefaultDisplay();
if (Build.VERSION.SDK_INT >= 17) {
//new pleasant way to get real metrics
DisplayMetrics realMetrics = new DisplayMetrics();
display.getRealMetrics(realMetrics);
realWidth = realMetrics.widthPixels;
realHeight = realMetrics.heightPixels;
} else if (Build.VERSION.SDK_INT >= 14) {
//reflection for this weird in-between time
try {
Method mGetRawH = Display.class.getMethod("getRawHeight");
Method mGetRawW = Display.class.getMethod("getRawWidth");
realWidth = (Integer) mGetRawW.invoke(display);
realHeight = (Integer) mGetRawH.invoke(display);
} catch (Exception e) {
//this may not be 100% accurate, but it's all we've got
realWidth = display.getWidth();
realHeight = display.getHeight();
Constants.errorLog("Display Info", "Couldn't use reflection to get the real display metrics.");
}
} else {
//This should be close, as lower API devices should not have window navigation bars
realWidth = display.getWidth();
realHeight = display.getHeight();
}
}

Samsung devices intermittently reporting incorrect screen width

In our application, we need to determine screen width at startup. We have tried to get this width using a few different methods (see list below), but Samsung devices, especially their Galaxy devices, are sometimes giving us incorrect values.
We have a Galaxy s6 with a resolution of 1440 x 2560 pixels. Most of the time the device will report a width of 1440, but occasionally it will give us a width of 1080.
We have tried getting the width the following ways:
1)
getResources().getDisplayMetrics().widthPixels;
2)
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
3)
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getRealSize(size);
But in all cases we see an incorrect width being returned. We see incorrect values reliably when our application is launched for the very first time. Any help would be hugely appreciated.
Have you tried this?
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenWidth = metrics.widthPixels;
UPDATE
And a little bit hardcore.
You may find more here.
This is our getDeviceWidth() method for ages and we never had any trouble with it, but i guess it's your second version?! Please verify and comment. (Ensure you call this after your views are created.)
public static int getDeviceWidth(Activity activity) {
Display display = activity.getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size.x;
}
Otherwise i would try to get the y-position (or width) of an dummy layout which has sets its width to match_parent.
And test your getWidth on start and after app is running (f.e. on button click). Does it return wrong width during run time too?
In my method, I haven't run into any issues before in terms of not locating the right location of something or the exact size of any Android screen.
My method finds the screen size in inches and the screen height and width in pixels and inches
In my app this method is how I check if my app is being used by a tablet:
private void tabletChanges() {
DisplayMetrics dm = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
int dens = dm.densityDpi;
double wi = (double)width/dm.xdpi;
double hi = (double)height/dm.ydpi;
double x = Math.pow(wi,2);
double y = Math.pow(hi,2);
double screenInches = Math.sqrt(x+y);
if(screenInches >= 7){
//Do certain things
}
}

Generating non icon images

I want to add image resources to an Android app that won't be used for icons. I wanted to know what is the right way of doing it while supporting multiple device screen sizes. The only solution I can think of is resizing the image to different pixel (width, height) combinations and storing them in their appropriate drawable folders.
For images that are icons, I use the Android studio image asset tool to automatically generate different sized icons. I want that for images that are not icons(won't be placed in the toolbar and similar places).
Solution that worked for me
Used Android Asset Studio, Generic Icon Generator
to generate the resource images for the different device resolutions.
I think you can try this:
Create folder drawable-nodpi and put your images inside it.
Use this code to find the width of the device:
public static int getWidth() {
int width = 400;
try {
WindowManager wm = (WindowManager) DataBackApplication.getInstance().getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
if (Build.VERSION.SDK_INT > 12) {
Point size = new Point();
display.getSize(size);
width = size.x;
} else {
width = display.getWidth(); // Deprecated
}
} catch (Exception e) {
e.printStackTrace();
}
return width;
}
Build your layout.
Load image using this code:
int width = getWidth();
int imgWidth = width/6;
int imgHeight = width/9;
Glide.with(PermissionActivity.this)
.load(R.drawable.privacy_mobile_img)
.override(imgWidth, imgHeight )
.into(imgUserPerm);
Use Glide to load the image because it will resize it for small, mid, or any size device. I used width / 6 as an example, you can adjust as needed.

Categories

Resources