I am making a project about Camera2API, usually by default it detect what the display size is and crop/cut the size using MeasuredSpec. My problem is that I don't know how to declare the actual camera hardware fully to get of what the camera actually see. Here is part of the code of what I am trying to do:
val cameraRes = Camera2BasicFragment().configureTransform(width, height) as Size
val cameraWidth = cameraRes.width
val cameraHeight = cameraRes.height
My aim is to make the camera hardware on any device literally and import it as a preview size, in order to make calculations of the crop/cut mechanism. I would be happy to get some help or conclusion whether or not, if it's true or not and avoid to be stretched in Portrait, in Landscape it doesn't stretch the TextureView, but on Portrait is squeezed or stretched completely. Here is the entire code:
class AutoFitTextureView #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : TextureView(context, attrs, defStyle) {
//private val SENSOR_INFO_PHYSICAL_SIZE: CameraCharacteristics.Key<SizeF>? = null
private val TAG: String = "Camera2APIPreviewResolution"
private var ratioWidth = 0 //Width for preview
private var ratioHeight = 0 //Height for preview
fun nodAspectRatio(width: Int, height: Int) {
if (width < 0 || height < 0) {
throw IllegalArgumentException("Size cannot be negative.")
}
val cameraRes = Camera2BasicFragment().configureTransform(width, height) as Size
val cameraWidth = cameraRes.width
val cameraHeight = cameraRes.height
val size = Point(width, height)
val windowManager: WindowManager = context.getSystemService(Service.WINDOW_SERVICE) as WindowManager
val display: Display = windowManager.defaultDisplay
display.getRealSize(size)
val displayWidth = size.x
val displayHeight = size.y
ratioWidth = width
ratioHeight = height
if (cameraWidth < cameraHeight) {
height != width
}
val coefWidth = displayWidth
val coefHeight = displayHeight
if (coefWidth < coefHeight) {
ratioWidth = displayWidth
ratioHeight = displayHeight * coefWidth
if (ratioHeight > displayHeight) {
ratioHeight - displayHeight
}
} else {
ratioWidth = displayWidth
ratioHeight = displayHeight
if (ratioWidth > displayWidth) {
ratioWidth - displayWidth
}
}
Log.d("Camera2APICamera", "width:$cameraWidth, height:$cameraHeight")
Log.d("Camera2APIDisplay", "width:$displayWidth, height:$displayHeight")
Log.d("Camera2APICoef", "width:$coefWidth, height:$coefHeight")
Log.d("Camera2APIResolution", "width:$ratioWidth, height:$ratioHeight")
requestLayout()
}
#SuppressLint("DrawAllocation")
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = MeasureSpec.getSize(heightMeasureSpec)
if (ratioWidth == 0 || ratioHeight == 0) {
setMeasuredDimension(width, height)
/**It's forced stretched when either width or height are 0*/
} else {
/** This is made for calculation formula if width is less than the height as calculated and another if statement provided the Portrait and Landscape*/
if (width < height * ratioWidth / ratioHeight) {
setMeasuredDimension(width, width * ratioHeight / ratioWidth)
} else {
setMeasuredDimension(height * ratioWidth / ratioHeight, height)
}
}
}
}
And this is the message of the debug:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.camera2apikotlin4, PID: 18559
java.lang.ClassCastException: kotlin.Unit cannot be cast to android.util.Size
at com.example.camera2apikotlin4.AutoFitTextureView.nodAspectRatio(AutoFitTextureView.kt:35)
at com.example.camera2apikotlin4.Camera2BasicFragment.setUpCameraOutputs(Camera2BasicFragment.kt:364)
at com.example.camera2apikotlin4.Camera2BasicFragment.openCamera(Camera2BasicFragment.kt:422)
at com.example.camera2apikotlin4.Camera2BasicFragment.access$openCamera(Camera2BasicFragment.kt:33)
at com.example.camera2apikotlin4.Camera2BasicFragment$surfaceTextureListener$1.onSurfaceTextureAvailable(Camera2BasicFragment.kt:44)
I need the width of the screen. But recently found Android defaultDisplay deprecacted with message:
Getter for defaultDisplay: Display!' is deprecated. Deprecated in Java
Code:
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
return displayMetrics.widthPixels
Please suggest an alternative.
defaultDisplay was marked as deprecated in API level 30 (Android R) and above.
This means if you have a minimum SDK configuration below API level 30, you should have both implementations with the old deprecated code and the new recommended code.
After fixing the problem correctly you can use #Suppress("DEPRECATION") to suppress warnings
Example: Kotlin solution
val outMetrics = DisplayMetrics()
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
val display = activity.display
display?.getRealMetrics(outMetrics)
} else {
#Suppress("DEPRECATION")
val display = activity.windowManager.defaultDisplay
#Suppress("DEPRECATION")
display.getMetrics(outMetrics)
}
WindowManager.getDefaultDisplay() was deprecated in API level 30 in favour of Context.getDisplay() method which requires minimum API level 30.
At the moment, androidx.core.content.ContextCompat doesn't seem to offer any backwards compatible getDisplay() method.
If you only need to retrieve the default display, instead of using different methods for different API levels as other answers suggest, you can you DisplayManager.getDisplay(Display.DEFAULT_DISPLAY) method (supported since API 17) to achieve the same result.
Deprecated code:
val defaultDisplay = getSystemService<WindowManager>()?.defaultDisplay
New code:
val defaultDisplay = getSystemService<DisplayManager>()?.getDisplay(Display.DEFAULT_DISPLAY)
Ref: androidx.core source code
If what you need is to get the size of the Window, the new Jetpack WindowManager library provides a common API surface for new Window Manager features (e.g. foldable devices and Chrome OS) throughout old and new platform versions.
dependencies {
implementation "androidx.window:window:1.0.0-beta02"
}
Jetpack WindowManager offers two ways to retrieve WindowMetrics information, as an asynchronous stream or synchronously.
Asynchronous WindowMetrics flow:
Use WindowInfoRepository#currentWindowMetrics to get notified by the library when there’s a window size change, independent of whether this change fires a configuration change.
import androidx.window.layout.WindowInfoRepository
import androidx.window.layout.WindowInfoRepository.Companion.windowInfoRepository
import androidx.window.layout.WindowMetrics
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.flowWithLifecycle
lifecycleScope.launch(Dispatchers.Main) {
windowInfoRepository().currentWindowMetrics.flowWithLifecycle(lifecycle)
.collect { windowMetrics: WindowMetrics ->
val currentBounds = windowMetrics.bounds // E.g. [0 0 1350 1800]
val width = currentBounds.width()
val height = currentBounds.height()
}
}
Note: lifecycleScope and flowWithLifecycle() are part of Jetpack Lifecycle library.
Synchronous WindowMetrics:
Use WindowMetricsCalculator when writing code in a view where the asynchronous API can be too hard to deal with (such as onMeasure or during testing).
import androidx.window.layout.WindowMetricsCalculator
import androidx.window.layout.WindowMetrics
val windowMetrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(activity)
val currentBounds = windowMetrics.bounds // E.g. [0 0 1350 1800]
val width = currentBounds.width()
val height = currentBounds.height()
Ref: Unbundling the WindowManager | Android Developers Medium
This method was deprecated in API level 30.
Use Context.getDisplay() instead.
Deprecated method: getDefaultDisplay
New Method: getDisplay
Try something like this:
private Display getDisplay(#NonNull WindowManager windowManager) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// This one (context) may or may not have a display associated with it, due to it being
// an application context
return getDisplayPostR();
} else {
return getDisplayPreR(windowManager);
}
}
#RequiresApi(api = Build.VERSION_CODES.R)
private Display getDisplayPostR() {
// We can't get the WindowManager by using the context we have, because that context is a
// application context, which isn't associated with any display. Instead, grab the default
// display, and create a DisplayContext, from which we can use the WindowManager or
// just get that Display from there.
//
// Note: the default display doesn't have to be the one where the app is on, however the
// getDisplays which returns a Display[] has a length of 1 on Pixel 3.
//
// This gets rid of the exception interrupting the onUserLogin() method
Display defaultDisplay = DisplayManagerCompat.getInstance(context).getDisplay(Display.DEFAULT_DISPLAY);
Context displayContext = context.createDisplayContext(defaultDisplay);
return displayContext.getDisplay();
}
#SuppressWarnings("deprecation")
private Display getDisplayPreR(#NonNull WindowManager windowManager) {
return windowManager.getDefaultDisplay();
}
or to get the actual size:
private Point getScreenResolution() {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
if (wm == null) {
return null;
}
Display display = getDisplay(wm);
return getSize(display, wm);
}
private Point getSize(Display forWhichDisplay, WindowManager windowManager) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return getSizePostR(windowManager);
} else {
return getSizePreR(forWhichDisplay);
}
}
#RequiresApi(api = Build.VERSION_CODES.R)
private Point getSizePostR(#NonNull WindowManager windowManager) {
WindowMetrics currentWindowMetrics = windowManager.getCurrentWindowMetrics();
Rect bounds = currentWindowMetrics.getBounds();
// Get the insets, such as titlebar and other decor views
WindowInsets windowInsets = currentWindowMetrics.getWindowInsets();
Insets insets = windowInsets.getInsets(WindowInsets.Type.navigationBars());
// If cutouts exist, get the max of what we already calculated and the system's safe insets
if (windowInsets.getDisplayCutout() != null) {
insets = Insets.max(
insets,
Insets.of(
windowInsets.getDisplayCutout().getSafeInsetLeft(),
windowInsets.getDisplayCutout().getSafeInsetTop(),
windowInsets.getDisplayCutout().getSafeInsetRight(),
windowInsets.getDisplayCutout().getSafeInsetBottom()
)
);
}
// Calculate the inset widths/heights
int insetsWidth = insets.right + insets.left;
int insetsHeight = insets.top + insets.bottom;
// Get the display width
int displayWidth = bounds.width() - insetsWidth;
int displayHeight = bounds.height() - insetsHeight;
return new Point(displayWidth, displayHeight);
}
// This was deprecated in API 30
#SuppressWarnings("deprecation")
private Point getSizePreR(Display display) {
Point size = new Point();
if (isRealDisplaySizeAvailable()) {
display.getRealSize(size);
} else {
display.getSize(size);
}
return size;
}
private static boolean isRealDisplaySizeAvailable() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
}
I use DisplayCompatManager to get width and height on android R-Above and use DisplayMatrics to get it on other android version.
So, this is my code ( + #Suppress("DEPRECATION") )
private fun screenValue() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val defaultDisplay =
DisplayManagerCompat.getInstance(this).getDisplay(Display.DEFAULT_DISPLAY)
val displayContext = createDisplayContext(defaultDisplay!!)
width = displayContext.resources.displayMetrics.widthPixels
height = displayContext.resources.displayMetrics.heightPixels
Log.e(tag, "width (ANDOIRD R/ABOVE): $width")
Log.e(tag, "height (ANDOIRD R/ABOVE) : $height")
} else {
val displayMetrics = DisplayMetrics()
#Suppress("DEPRECATION")
windowManager.defaultDisplay.getMetrics(displayMetrics)
height = displayMetrics.heightPixels
width = displayMetrics.widthPixels
Log.e(tag, "width (BOTTOM ANDROID R): $width")
Log.e(tag, "height (BOTTOM ANDROID R) : $height")
}
}
If you want see my gist in github
In Api Level 31 method Display.getRealMetrics() was deprecated as well. The recommended way is to use WindowManager#getCurrentWindowMetrics(). I prefer the following approach to get screen size:
object ScreenSizeCompat {
private val api: Api =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) ApiLevel30()
else Api()
/**
* Returns screen size in pixels.
*/
fun getScreenSize(context: Context): Size = api.getScreenSize(context)
#Suppress("DEPRECATION")
private open class Api {
open fun getScreenSize(context: Context): Size {
val display = context.getSystemService(WindowManager::class.java).defaultDisplay
val metrics = if (display != null) {
DisplayMetrics().also { display.getRealMetrics(it) }
} else {
Resources.getSystem().displayMetrics
}
return Size(metrics.widthPixels, metrics.heightPixels)
}
}
#RequiresApi(Build.VERSION_CODES.R)
private class ApiLevel30 : Api() {
override fun getScreenSize(context: Context): Size {
val metrics: WindowMetrics = context.getSystemService(WindowManager::class.java).currentWindowMetrics
return Size(metrics.bounds.width(), metrics.bounds.height())
}
}
}
And to get, for example, screen height use it in Activity:
ScreenSizeCompat.getScreenSize(this).height
Anyone looking to do it in java here you go:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
Display display = this.getDisplay();
DisplayMetrics displayMetrics = new DisplayMetrics();
display.getRealMetrics(displayMetrics);
float density = getResources().getDisplayMetrics().density;
float dpHeight = displayMetrics.heightPixels / density;
float dpWidth = displayMetrics.widthPixels / density;
Log.d(TAG, "OmesChecka R: "+"second width:"+dpWidth+"second h:"+dpHeight);
}else {
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics ();
display.getMetrics(outMetrics);
float density = getResources().getDisplayMetrics().density;
float dpHeight = outMetrics.heightPixels / density;
float dpWidth = outMetrics.widthPixels / density;
Log.d(TAG, "OmesChecka: "+"second width:"+dpWidth+"second h:"+dpHeight);
}
Since I had to go to several places to get the complete answer, here it is in one post:
getDefaultDisplay method is depreciated as of Android API 30 (Android 11), but still works.
Even so, because it's depreciated you should use the new method for Android 11, and still implement the old method for Android 10 or earlier.
Here's the code, with comments: (To run this you need viewBinding enabled in your build.gradle (since I'm not using findViewByID), an activity_main.xml with your top level layout named "main_activity", a button view named "calculate_button", and three text views named "android_version", "screen_height" and "screen_width".)
package com.example.test
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.WindowManager
import com.example.test.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.calculateButton.setOnClickListener { calcScreenSize() }
}
private fun calcScreenSize() { //All in one function to calculate and display screen size in pixels
val metrics = DisplayMetrics()
var width: Int = 0
var height: Int = 0
val version = android.os.Build.VERSION.SDK_INT //Check android version. Returns API # ie 29 (Android 10), 30 (Android 11)
if (version >= android.os.Build.VERSION_CODES.R) { //If API is version 30 (Android 11) or greater, use the new method for getting width/height
binding.androidVersion.setText("Android API Version: $version")
binding.mainActivity.display?.getRealMetrics(metrics) //New method
width = metrics.widthPixels
height = metrics.heightPixels
binding.screenHeight.setText("Height: $height") //Display Width and Height in Text Views
binding.screenWidth.setText("Width: $width")
} else {
binding.androidVersion.setText("Android API Version: $version") //If API is less than version 30 (ie 29 (Android 10)), use the old method for getting width/height
#Suppress("DEPRECATION") //Suppress the "Deprecation" warning
windowManager.defaultDisplay.getMetrics(metrics) //Old method
width = metrics.widthPixels
height = metrics.heightPixels
binding.screenHeight.setText("Height: $height") //Display Width and Height in Text Views
binding.screenWidth.setText("Width: $width")
}
}
}
Here is a java solution attempting the least amount of code, imports, and further depreciated methods as possible. I leave potential device insets in my game to keep the view as large as possible. However, the commented code will shorten width and height for insets.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowMetrics windowMetrics = ((Activity) context).getWindowManager().getCurrentWindowMetrics();
//Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility(WindowInsets.Type.systemBars());
screenWidth = windowMetrics.getBounds().width();// - insets.left - insets.right;
screenHeight = windowMetrics.getBounds().height();// - insets.top - insets.bottom;
} else {
Display display = ((Activity) context).getWindowManager().getDefaultDisplay();//getDefaultDisplay depreciated getMetrics() depreciated
Point size = new Point();
display.getSize(size);
screenWidth = size.x;
screenHeight = size.y;
try {
Point realSize = new Point();
Display.class.getMethod("getRealSize", Point.class).invoke(display, realSize);
screenWidth = realSize.x;
screenHeight = realSize.y;
} catch (Exception ignored) {
}
}
How do I calculate the dimensions of an Android device in kotlin?
I have tried:
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
var width = displayMetrics.widthPixels
var height = displayMetrics.heightPixels
It gives me the following error:
"getter for defaultDisplay: Display!' is deprecated. Deprecated in Java:"
Thank you
If you look into the docs for WindowManager.getDefaultDisplay() you'll find that there's a suggestion on what to use instead:
Deprecated: Use Context#getDisplay() instead.
The new way to do it now is with context, This method is the one I used to obtain the real height, depending on the orientation of the screen
Note * Make sure for the context of an activity or fragment
fun getDisplayHeight(context: Context): Int {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val displayMetrics = DisplayMetrics()
try {
context.display?.getRealMetrics(displayMetrics)
} catch (e: NoSuchMethodError) {
windowManager.defaultDisplay.getRealMetrics(displayMetrics)
}
return if (context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
minOf(displayMetrics.widthPixels, displayMetrics.heightPixels)
} else {
maxOf(displayMetrics.widthPixels, displayMetrics.heightPixels)
}
}
You can refer to the following documentation for more details.
https://developer.android.com/reference/kotlin/android/view/WindowManager?hl=en#getDefaultDisplay()
How can I tell whether an android device has physical keys or the software navigation bar? I need to change the layout dependant on whether the software navigation is drawn.
For example the HTC Desire C has hardware keys:
I should clarify - Im looking at the navigation bar, not the keyboard. Home, back etc. I've tried:
getResources().getConfiguration().keyboard);
getResources().getConfiguration().navigation);
getResources().getConfiguration().navigationHidden);
return the same values on both devices.
Solved by doing this the first time the app is launched and saving to preferences:
public static boolean hasSoftKeys(WindowManager windowManager){
boolean hasSoftwareKeys = true;
//c = context; use getContext(); in fragments, and in activities you can
//directly access the windowManager();
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN_MR1){
Display d = c.getWindowManager().getDefaultDisplay();
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
d.getRealMetrics(realDisplayMetrics);
int realHeight = realDisplayMetrics.heightPixels;
int realWidth = realDisplayMetrics.widthPixels;
DisplayMetrics displayMetrics = new DisplayMetrics();
d.getMetrics(displayMetrics);
int displayHeight = displayMetrics.heightPixels;
int displayWidth = displayMetrics.widthPixels;
hasSoftwareKeys = (realWidth - displayWidth) > 0 ||
(realHeight - displayHeight) > 0;
} else {
boolean hasMenuKey = ViewConfiguration.get(c).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
hasSoftwareKeys = !hasMenuKey && !hasBackKey;
}
return hasSoftwareKeys;
}
Here you go.. this should do what you want.
#SuppressLint("NewApi")
private static boolean hasSoftNavigation(Context context)
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH){
return !ViewConfiguration.get(context).hasPermanentMenuKey();
}
return false;
}
Solution based on #serenskye
private fun Activity.hasSoftKeys(): Boolean {
val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
display
} else {
windowManager.defaultDisplay
} ?: return true
val realDisplayMetrics = DisplayMetrics()
display.getRealMetrics(realDisplayMetrics)
val realHeight = realDisplayMetrics.heightPixels
val realWidth = realDisplayMetrics.widthPixels
val displayMetrics = DisplayMetrics()
display.getMetrics(displayMetrics)
val displayHeight = displayMetrics.heightPixels
val displayWidth = displayMetrics.widthPixels
return realWidth - displayWidth > 0 || realHeight - displayHeight > 0
}
To avoid deprecation of getMetrics() as of Android S (API Level 31), you can use currentWindowMetrics of the WindowManager and do the comparison of real display & the app's window display:
#RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
fun Activity.hasSoftNavigationBar(): Boolean {
val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
display
} else {
windowManager.defaultDisplay
} ?: return true
val displayWidth = Resources.getSystem().displayMetrics.widthPixels
val displayHeight = Resources.getSystem().displayMetrics.heightPixels
val realWidth: Int
val realHeight: Int
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
realWidth = windowManager.currentWindowMetrics.bounds.height()
realHeight = windowManager.currentWindowMetrics.bounds.width()
} else {
val realDisplayMetrics = DisplayMetrics()
display.getRealMetrics(realDisplayMetrics)
realWidth = realDisplayMetrics.widthPixels
realHeight = realDisplayMetrics.heightPixels
}
return realWidth - displayWidth > 0 || realHeight - displayHeight > 0
}
private boolean isHardwareKeyboardAvailable() { return getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS; }
In addition, here is more info. http://developer.android.com/reference/android/content/res/Configuration.html#keyboard
EDIT - To check for physical keyboard
private boolean isPhysicalKeyboardAvailable() { return getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY; }
For more information on the different Configurations view
http://developer.android.com/reference/android/content/res/Configuration.html#keyboard
I am sure one of those works.
2nd EDIT -
Check. Already asked.
Android: Programmatically detect if device has hardware menu button
How can I get the screen width and height and use this value in:
#Override protected void onMeasure(int widthSpecId, int heightSpecId) {
Log.e(TAG, "onMeasure" + widthSpecId);
setMeasuredDimension(SCREEN_WIDTH, SCREEN_HEIGHT -
game.findViewById(R.id.flag).getHeight());
}
Using this code, you can get the runtime display's width & height:
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
int width = displayMetrics.widthPixels;
In a view you need to do something like this:
((Activity) getContext()).getWindowManager()
.getDefaultDisplay()
.getMetrics(displayMetrics);
In some scenarios, where devices have a navigation bar, you have to check at runtime:
public boolean showNavigationBar(Resources resources)
{
int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
return id > 0 && resources.getBoolean(id);
}
If the device has a navigation bar, then count its height:
private int getNavigationBarHeight() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int usableHeight = metrics.heightPixels;
getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
int realHeight = metrics.heightPixels;
if (realHeight > usableHeight)
return realHeight - usableHeight;
else
return 0;
}
return 0;
}
So the final height of the device is:
int height = displayMetrics.heightPixels + getNavigationBarHeight();
There is a very simple answer and without pass context
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
Note: if you want the height include navigation bar, use method below
WindowManager windowManager =
(WindowManager) BaseApplication.getApplication().getSystemService(Context.WINDOW_SERVICE);
final Display display = windowManager.getDefaultDisplay();
Point outPoint = new Point();
if (Build.VERSION.SDK_INT >= 19) {
// include navigation bar
display.getRealSize(outPoint);
} else {
// exclude navigation bar
display.getSize(outPoint);
}
if (outPoint.y > outPoint.x) {
mRealSizeHeight = outPoint.y;
mRealSizeWidth = outPoint.x;
} else {
mRealSizeHeight = outPoint.x;
mRealSizeWidth = outPoint.y;
}
Just to update the answer by parag and SpK to align with current SDK backward compatibility from deprecated methods:
int Measuredwidth = 0;
int Measuredheight = 0;
Point size = new Point();
WindowManager w = getWindowManager();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
w.getDefaultDisplay().getSize(size);
Measuredwidth = size.x;
Measuredheight = size.y;
}else{
Display d = w.getDefaultDisplay();
Measuredwidth = d.getWidth();
Measuredheight = d.getHeight();
}
It’s very easy to get in Android:
int width = Resources.getSystem().getDisplayMetrics().widthPixels;
int height = Resources.getSystem().getDisplayMetrics().heightPixels;
Why not
DisplayMetrics displaymetrics = getResources().getDisplayMetrics();
Then use
displayMetrics.widthPixels
and
displayMetrics.heightPixels
• Kotlin Version via Extension Property
If you want to know the size of the screen in pixels as well as dp, using these extension properties really helps:
DimensionUtils.kt
import android.content.Context
import android.content.res.Resources
import android.graphics.Rect
import android.graphics.RectF
import android.os.Build
import android.util.DisplayMetrics
import android.view.WindowManager
import kotlin.math.roundToInt
/**
* #author aminography
*/
private val displayMetrics: DisplayMetrics by lazy { Resources.getSystem().displayMetrics }
/**
* Returns boundary of the screen in pixels (px).
*/
val screenRectPx: Rect
get() = displayMetrics.run { Rect(0, 0, widthPixels, heightPixels) }
/**
* Returns boundary of the screen in density independent pixels (dp).
*/
val screenRectDp: RectF
get() = screenRectPx.run { RectF(0f, 0f, right.px2dp, bottom.px2dp) }
/**
* Returns boundary of the physical screen including system decor elements (if any) like navigation
* bar in pixels (px).
*/
val Context.physicalScreenRectPx: Rect
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
(applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager)
.run { DisplayMetrics().also { defaultDisplay.getRealMetrics(it) } }
.run { Rect(0, 0, widthPixels, heightPixels) }
} else screenRectPx
/**
* Returns boundary of the physical screen including system decor elements (if any) like navigation
* bar in density independent pixels (dp).
*/
val Context.physicalScreenRectDp: RectF
get() = physicalScreenRectPx.run { RectF(0f, 0f, right.px2dp, bottom.px2dp) }
/**
* Converts any given number from pixels (px) into density independent pixels (dp).
*/
val Number.px2dp: Float
get() = this.toFloat() / displayMetrics.density
/**
* Converts any given number from density independent pixels (dp) into pixels (px).
*/
val Number.dp2px: Int
get() = (this.toFloat() * displayMetrics.density).roundToInt()
Usage:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val widthPx = screenRectPx.width()
val heightPx = screenRectPx.height()
println("[PX] screen width: $widthPx , height: $heightPx")
val widthDp = screenRectDp.width()
val heightDp = screenRectDp.height()
println("[DP] screen width: $widthDp , height: $heightDp")
println()
val physicalWidthPx = physicalScreenRectPx.width()
val physicalHeightPx = physicalScreenRectPx.height()
println("[PX] physical screen width: $physicalWidthPx , height: $physicalHeightPx")
val physicalWidthDp = physicalScreenRectDp.width()
val physicalHeightDp = physicalScreenRectDp.height()
println("[DP] physical screen width: $physicalWidthDp , height: $physicalHeightDp")
}
}
Result:
When the device is in portrait orientation:
[PX] screen width: 1440 , height: 2392
[DP] screen width: 360.0 , height: 598.0
[PX] physical screen width: 1440 , height: 2560
[DP] physical screen width: 360.0 , height: 640.0
When the device is in landscape orientation:
[PX] screen width: 2392 , height: 1440
[DP] screen width: 598.0 , height: 360.0
[PX] physical screen width: 2560 , height: 1440
[DP] physical screen width: 640.0 , height: 360.0
You can get width and height from context
java:
int width= context.getResources().getDisplayMetrics().widthPixels;
int height= context.getResources().getDisplayMetrics().heightPixels;
kotlin
val width: Int = context.resources.displayMetrics.widthPixels
val height: Int = context.resources.displayMetrics.heightPixels
Try below code :-
1.
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
2.
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth(); // deprecated
int height = display.getHeight(); // deprecated
or
int width = getWindowManager().getDefaultDisplay().getWidth();
int height = getWindowManager().getDefaultDisplay().getHeight();
3.
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
metrics.heightPixels;
metrics.widthPixels;
Some methods, applicable for retrieving screen size, are deprecated in API Level 31, including Display.getRealMetrics() and Display.getRealSize(). Starting from API Level 30 we can use WindowManager#getCurrentWindowMetrics(). The clean way to get screen size is to create some Compat class, e.g.:
object ScreenMetricsCompat {
private val api: Api =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) ApiLevel30()
else Api()
/**
* Returns screen size in pixels.
*/
fun getScreenSize(context: Context): Size = api.getScreenSize(context)
#Suppress("DEPRECATION")
private open class Api {
open fun getScreenSize(context: Context): Size {
val display = context.getSystemService(WindowManager::class.java).defaultDisplay
val metrics = if (display != null) {
DisplayMetrics().also { display.getRealMetrics(it) }
} else {
Resources.getSystem().displayMetrics
}
return Size(metrics.widthPixels, metrics.heightPixels)
}
}
#RequiresApi(Build.VERSION_CODES.R)
private class ApiLevel30 : Api() {
override fun getScreenSize(context: Context): Size {
val metrics: WindowMetrics = context.getSystemService(WindowManager::class.java).currentWindowMetrics
return Size(metrics.bounds.width(), metrics.bounds.height())
}
}
}
Calling ScreenMetricsCompat.getScreenSize(this).height in Activity we can get a screen height.
I suggest you create extension functions.
/**
* Return the width and height of the screen
*/
val Context.screenWidth: Int
get() = resources.displayMetrics.widthPixels
val Context.screenHeight: Int
get() = resources.displayMetrics.heightPixels
/**
* Pixel and Dp Conversion
*/
val Float.toPx get() = this * Resources.getSystem().displayMetrics.density
val Float.toDp get() = this / Resources.getSystem().displayMetrics.density
val Int.toPx get() = (this * Resources.getSystem().displayMetrics.density).toInt()
val Int.toDp get() = (this / Resources.getSystem().displayMetrics.density).toInt()
DisplayMetrics lDisplayMetrics = getResources().getDisplayMetrics();
int widthPixels = lDisplayMetrics.widthPixels;
int heightPixels = lDisplayMetrics.heightPixels;
For kotlin user's
fun Activity.displayMetrics(): DisplayMetrics {
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
return displayMetrics
}
And in Activity you could use it like
resources.displayMetrics.let { displayMetrics ->
val height = displayMetrics.heightPixels
val width = displayMetrics.widthPixels
}
Or in fragment
activity?.displayMetrics()?.run {
val height = heightPixels
val width = widthPixels
}
As getMetrics and getRealMetrics are deprecated, Google recommends to determine the screen width and height as follows:
WindowMetrics windowMetrics = getActivity().getWindowManager().getMaximumWindowMetrics();
Rect bounds = windowMetrics.getBounds();
int widthPixels = bounds.width();
int heightPixels = bounds.height();
However, I've figured out another methode that gives me the same results:
Configuration configuration = mContext.getResources().getConfiguration();
Display.Mode mode = display.getMode();
int widthPixels = mode.getPhysicalWidth();
int heightPixels = mode.getPhysicalHeight();
None of the answers here work correctly for Chrome OS multiple displays, or soon-to-come Foldables.
When looking for the current configuration, always use the configuration from your current activity in getResources().getConfiguration(). Do not use the configuration from your background activity or the one from the system resource. The background activity does not have a size, and the system's configuration may contain multiple windows with conflicting sizes and orientations, so no usable data can be extracted.
So the answer is
val config = context.getResources().getConfiguration()
val (screenWidthPx, screenHeightPx) = config.screenWidthDp.dp to config.screenHeightDp.dp
DisplayMetrics dimension = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dimension);
int width = dimension.widthPixels;
int height = dimension.heightPixels;
Get the value of screen width and height.
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
width = size.x;
height = size.y;
As an android official document said for the default display use Context#getDisplay() because this method was deprecated in API level 30.
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
This code given below is in kotlin and is written accodring to the latest version of Android help you determine width and height:
fun getWidth(context: Context): Int {
var width:Int = 0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val displayMetrics = DisplayMetrics()
val display: Display? = context.getDisplay()
display!!.getRealMetrics(displayMetrics)
return displayMetrics.widthPixels
}else{
val displayMetrics = DisplayMetrics()
this.windowManager.defaultDisplay.getMetrics(displayMetrics)
width = displayMetrics.widthPixels
return width
}
}
fun getHeight(context: Context): Int {
var height: Int = 0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val displayMetrics = DisplayMetrics()
val display = context.display
display!!.getRealMetrics(displayMetrics)
return displayMetrics.heightPixels
}else {
val displayMetrics = DisplayMetrics()
this.windowManager.defaultDisplay.getMetrics(displayMetrics)
height = displayMetrics.heightPixels
return height
}
}
fun Activity.getRealScreenSize(): Pair<Int, Int> { //<width, height>
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val size = Point()
display?.getRealSize(size)
Pair(size.x, size.y)
} else {
val size = Point()
windowManager.defaultDisplay.getRealSize(size)
Pair(size.x, size.y)
}}
This is an extension function and you can use in your activity in this way:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val pair = getRealScreenSize()
pair.first //to get width
pair.second //to get height
}
I use the following code to get the screen dimensions
getWindow().getDecorView().getWidth()
getWindow().getDecorView().getHeight()
Full way to do it, that returns the true resolution (including when the user has changed the resolution) is to use "getRealSize".
I've noticed that all other available functions, including the ones the docs say to use instead of this - have some cases that the result is smaller.
Here's the code to do it:
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Point size = new Point();
wm.getDefaultDisplay().getRealSize(size);
final int width = size.x, height = size.y;
And since this can change on different orientation, here's a solution (in Kotlin), to get it right no matter the orientation:
/**
* returns the natural orientation of the device: Configuration.ORIENTATION_LANDSCAPE or Configuration.ORIENTATION_PORTRAIT .<br></br>
* The result should be consistent no matter the orientation of the device
*/
#JvmStatic
fun getScreenNaturalOrientation(context: Context): Int {
//based on : http://stackoverflow.com/a/9888357/878126
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val config = context.resources.configuration
val rotation = windowManager.defaultDisplay.rotation
return if ((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) && config.orientation == Configuration.ORIENTATION_LANDSCAPE || (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) && config.orientation == Configuration.ORIENTATION_PORTRAIT)
Configuration.ORIENTATION_LANDSCAPE
else
Configuration.ORIENTATION_PORTRAIT
}
/**
* returns the natural screen size (in pixels). The result should be consistent no matter the orientation of the device
*/
#JvmStatic
fun getScreenNaturalSize(context: Context): Point {
val screenNaturalOrientation = getScreenNaturalOrientation(context)
val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val point = Point()
wm.defaultDisplay.getRealSize(point)
val currentOrientation = context.resources.configuration.orientation
if (currentOrientation == screenNaturalOrientation)
return point
else return Point(point.y, point.x)
}
Display display = ((WindowManager) this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int mWidthScreen = display.getWidth();
int mHeightScreen = display.getHeight();
public class DisplayInfo {
int screen_height=0, screen_width=0;
WindowManager wm;
DisplayMetrics displaymetrics;
DisplayInfo(Context context) {
getdisplayheightWidth(context);
}
void getdisplayheightWidth(Context context) {
wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
displaymetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(displaymetrics);
screen_height = displaymetrics.heightPixels;
screen_width = displaymetrics.widthPixels;
}
public int getScreen_height() {
return screen_height;
}
public int getScreen_width() {
return screen_width;
}
}
Seems like all these answers fail for my Galaxy M51 with Android 11. After doing some research around I found this code :
WindowMetrics windowmetrics = MainActivity.getWindowManager().getCurrentWindowMetrics();
Rect rect = windowmetrics.getBounds();
int width = rect.right;
int height =rect.bottom;
shows my true device resolution of 1080x2400, the rest only return 810x1800.
Methods shown here are deprecated/outdated but this is still working.Require API 13
check it out
Display disp= getWindowManager().getDefaultDisplay();
Point dimensions = new Point();
disp.getSize(size);
int width = size.x;
int height = size.y;
As an android official document said for the default display use Context#getDisplay() because this method was deprecated in API level 30.
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
This bowl of code help to determine width and height.
public static int getWidth(Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
Display display = context.getDisplay();
if (display != null) {
display.getRealMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
return -1;
}
For the Height:
public static int getHeight(Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
Display display = context.getDisplay();
if (display != null) {
display.getRealMetrics(displayMetrics);
return displayMetrics.heightPixels;
}
return -1;
}
Try this code for Kotlin
val display = windowManager.defaultDisplay
val size = Point()
display.getSize(size)
var DEVICE_WIDTH = size.x
var DEVICE_HEIGHT = size.y
Just use the function below that returns width and height of the screen size as an array of integers
private int[] getScreenSIze(){
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int h = displaymetrics.heightPixels;
int w = displaymetrics.widthPixels;
int[] size={w,h};
return size;
}
On your onCreate function or button click add the following code to output the screen sizes as shown below
int[] screenSize= getScreenSIze();
int width=screenSize[0];
int height=screenSize[1];
screenSizes.setText("Phone Screen sizes \n\n width = "+width+" \n Height = "+height);
I updated answer for Kotlin language!
For Kotlin: You should call Window Manager and get metrics. After that easy way.
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
var width = displayMetrics.widthPixels
var height = displayMetrics.heightPixels
How can we use it effectively in independent activity way with Kotlin language?
Here, I created a method in general Kotlin class. You can use it in all activities.
private val T_GET_SCREEN_WIDTH:String = "screen_width"
private val T_GET_SCREEN_HEIGHT:String = "screen_height"
private fun getDeviceSizes(activity:Activity, whichSize:String):Int{
val displayMetrics = DisplayMetrics()
activity.windowManager.defaultDisplay.getMetrics(displayMetrics)
return when (whichSize){
T_GET_SCREEN_WIDTH -> displayMetrics.widthPixels
T_GET_SCREEN_HEIGHT -> displayMetrics.heightPixels
else -> 0 // Error
}
}
I found weigan's answer best one in this page, here is how you can use that in Xamarin.Android:
public int GetScreenWidth()
{
return Resources.System.DisplayMetrics.WidthPixels;
}
public int GetScreenHeight()
{
return Resources.System.DisplayMetrics.HeightPixels;
}
Screen resolution is total no of pixel in screen. Following program will extract the screen resolution of the device. It will print screen width and height. Those values are in pixel.
public static Point getScreenResolution(Context context) {
// get window managers
WindowManager manager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
Point point = new Point();
display.getSize(point);
// get width and height
int width = point.x;
int height = point.y;
return point;
}