Height of status bar in Android [duplicate] - android

This question already has answers here:
Height of statusbar?
(14 answers)
Closed 2 years ago.
What's the height of the status bar in Android? Is it always the same?
From my measurements it seems that it's 25dp, but I'm not sure if it has the same height on all platforms.
(I want to know this to properly implement a fade transition from an activity that doesn't have status bar to one that does)

this question was answered before...
Height of statusbar?
Update::
Current method:
ok, the height of the status bar depends on the screen size, for example in a device
with 240 X 320 screen size the status bar height is 20px, for a device with 320 X 480 screen size the status bar height is 25px, for a device with 480 x 800 the status bar height must be 38px
so i recommend to use this script to get the status bar height
Rect rectangle = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
int statusBarHeight = rectangle.top;
int contentViewTop =
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleBarHeight= contentViewTop - statusBarHeight;
Log.i("*** Elenasys :: ", "StatusBar Height= " + statusBarHeight + " , TitleBar Height = " + titleBarHeight);
(old Method) to get the Height of the status bar on the onCreate() method of your Activity, use this method:
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}

Out of all the code samples I've used to get the height of the status bar, the only one that actually appears to work in the onCreate method of an Activity is this:
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
Apparently the actual height of the status bar is kept as an Android resource. The above code can be added to a ContextWrapper class (e.g. an Activity).
Found at http://mrtn.me/blog/2012/03/17/get-the-height-of-the-status-bar-in-android/

Hardcoding the size or using reflection to get the value of status_bar_height is considered bad practice. Chris Banes talked about this in at the Droidcon New York. The recommended way of getting the status bar size is via the OnApplyWindowInsetsListener:
myView.setOnApplyWindowInsetsListener { view, insets -> {
val statusBarSize = insets.systemWindowInsetTop
return insets
}
This was added in API 20 and is also backported via ViewAppCompat.

On MDPI devices, the status bar is 25px. We can use this as the base and multiply it by the density (rounded up) to get the status bar height on any device:
int statusBarHeight = Math.ceil(25 * context.getResources().getDisplayMetrics().density);
For reference: ldpi=.75, mdpi=1, hdpi=1.5, xhdpi=2

I've merged some solutions together:
public static int getStatusBarHeight(final Context context) {
final Resources resources = context.getResources();
final int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
return resources.getDimensionPixelSize(resourceId);
else
return (int) Math.ceil((VERSION.SDK_INT >= VERSION_CODES.M ? 24 : 25) * resources.getDisplayMetrics().density);
}
another alternative:
final View view = findViewById(android.R.id.content);
runJustBeforeBeingDrawn(view, new Runnable() {
#Override
public void run() {
int statusBarHeight = getResources().getDisplayMetrics().heightPixels - view.getMeasuredHeight();
}
});
EDIT: Alternative to runJustBeforeBeingDrawn: https://stackoverflow.com/a/28136027/878126

According to Material Guidance; height of status bar is 24 dp.
If you want get status bar height in pixels you can use below method:
private static int statusBarHeight(android.content.res.Resources res) {
return (int) (24 * res.getDisplayMetrics().density);
}
which can be called from activity with:
statusBarHeight(getResources());

The default height used to be 25dp. With Android Marshmallow (API 23) the height was reduced to 24dp.
Update: Please be aware that since the age of notches and punch-whole-cameras began, using a static height for the status bar no longer works. Please use window insets instead!

this also work with the refrence link
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}

Official height is 24dp,
as is stated officially by Google on Android Design webpage.

I have the same problem of having to get the status bar height in an onCreate. This works for me.
private static final int LOW_DPI_STATUS_BAR_HEIGHT = 19;
private static final int MEDIUM_DPI_STATUS_BAR_HEIGHT = 25;
private static final int HIGH_DPI_STATUS_BAR_HEIGHT = 38;
Inside the onCreate:
DisplayMetrics displayMetrics = new DisplayMetrics();
((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);
int statusBarHeight;
switch (displayMetrics.densityDpi) {
case DisplayMetrics.DENSITY_HIGH:
statusBarHeight = HIGH_DPI_STATUS_BAR_HEIGHT;
break;
case DisplayMetrics.DENSITY_MEDIUM:
statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;
break;
case DisplayMetrics.DENSITY_LOW:
statusBarHeight = LOW_DPI_STATUS_BAR_HEIGHT;
break;
default:
statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;
}
See:
http://developer.android.com/reference/android/util/DisplayMetrics.html
http://developer.android.com/guide/practices/ui_guidelines/icon_design.html

Kotlin version that combines two best solutions
fun getStatusBarHeight(): Int {
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
return if (resourceId > 0) resources.getDimensionPixelSize(resourceId)
else Rect().apply { window.decorView.getWindowVisibleDisplayFrame(this) }.top
}
Takes status_bar_height value if present
If status_bar_height is not present, calculates the status bar height from Window decor

Yes when i try it with View it provides the result of 25px.
Here is the whole code :
public class SpinActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout lySpin = new LinearLayout(this);
lySpin.setOrientation(LinearLayout.VERTICAL);
lySpin.post(new Runnable()
{
public void run()
{
Rect rect = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
int contentViewTop =
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleBarHeight = contentViewTop - statusBarHeight;
System.out.println("TitleBarHeight: " + titleBarHeight
+ ", StatusBarHeight: " + statusBarHeight);
}
}
}
}

240x320 - 20px
320x480 - 25px
480x800+ - 38px

Try this:
Rect rect = new Rect();
Window win = this.getWindow();
win.getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
int contentViewTop = win.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleBarHeight = contentViewTop - statusBarHeight;
Log.d("ID-ANDROID-CONTENT", "titleBarHeight = " + titleBarHeight );
it didn't work for me in the onCreate method for the activity, but did when I put it in an onClickListener and gave me a measurement of 25

the height of the status bar is 24dp in android 6.0
<!-- Height of the status bar -->
<dimen name="status_bar_height">24dp</dimen>
<!-- Height of the bottom navigation / system bar. -->
<dimen name="navigation_bar_height">48dp</dimen>
you can find the answer in the source code: frameworks\base\core\res\res\values\dimens.xml

To solve this, I used a combination approach.
This is necessary as on tablets the system bar already subtracts it's pixels when display.getHeight() is called.
So I first check if a system bar is present, and then Ben Claytons approach, which works fine on phones.
public int getStatusBarHeight() {
int statusBarHeight = 0;
if (!hasOnScreenSystemBar()) {
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
statusBarHeight = getResources().getDimensionPixelSize(resourceId);
}
}
return statusBarHeight;
}
private boolean hasOnScreenSystemBar() {
Display display = getWindowManager().getDefaultDisplay();
int rawDisplayHeight = 0;
try {
Method getRawHeight = Display.class.getMethod("getRawHeight");
rawDisplayHeight = (Integer) getRawHeight.invoke(display);
} catch (Exception ex) {
}
int UIRequestedHeight = display.getHeight();
return rawDisplayHeight - UIRequestedHeight > 0;
}

Thanks to #Niklas +1 this is the correct way to do it.
public class MyActivity extends Activity implements android.support.v4.View.OnApplyWindowInsetsListener {
Rect windowInsets;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
View rootview = findViewById(android.R.id.content);
android.support.v4.View.ViewCompat.setOnApplyWindowInsetsListener(rootview, this);
}
android.support.v4.View.WindowInsetsCompat android.support.v4.View.OnApplyWindowInsetsListener.OnApplyWindowInsets(View v, android.support.v4.View.WindowInsetsCompat insets)
{
windowInsets = new Rect();
windowInsets.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
//StatusBarHeight = insets.getSystemWindowInsetTop();
//Refresh/Adjust view accordingly
return insets;
}
}
Please excuse me if the code isn't 100% correct, converted it from Xamarin C# but this is the just of it. Works with Notches, etc.

Toggled Fullscreen Solution:
This solution may look like a workaround, but it actually accounts for whether your app is fullscreen (aka hiding the status bar) or not:
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point(); display.getSize(size);
int barheight = size.y - findViewById(R.id.rootView).getHeight();
This way, if your app is currently fullscreen, barheight will equal 0.
Personally I had to use this to correct absolute TouchEvent coordinates to account for the status bar as so:
#Override
public boolean onTouch(View view,MotionEvent event) {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point(); display.getSize(size);
int YCoord = (int)event.getRawY() - size.y + rootView.getHeight());
}
And that will get the absolute y-coordinate whether the app be fullscreen or not.
Enjoy

The reason why the top answer does not work for some people is because you cannot get the dimensions of a view until it is ready to render. Use an OnGlobalLayoutListener to get said dimensions when you actually can:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ViewGroup decorView = (ViewGroup) this.getWindow().getDecorView();
decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= 16) {
decorView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
// Nice one, Google
decorView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
Rect rect = new Rect();
decorView.getWindowVisibleDisplayFrame(rect);
rect.top; // This is the height of the status bar
}
}
}
This is the most reliable method.

On Android 4.1 and higher, you can set your application's content to appear behind the status bar, so that the content doesn't resize as the status bar hides and shows. To do this, use SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN. You may also need to use SYSTEM_UI_FLAG_LAYOUT_STABLE to help your app maintain a stable layout.
When you use this approach, it becomes your responsibility to ensure that critical parts of your app's UI (for example, the built-in controls in a Maps application) don't end up getting covered by system bars. This could make your app unusable. In most cases you can handle this by adding the android:fitsSystemWindows attribute to your XML layout file, set to true. This adjusts the padding of the parent ViewGroup to leave space for the system windows. This is sufficient for most applications.
In some cases, however, you may need to modify the default padding to get the desired layout for your app. To directly manipulate how your content lays out relative to the system bars (which occupy a space known as the window's "content insets"), override fitSystemWindows(Rect insets). The fitSystemWindows() method is called by the view hierarchy when the content insets for a window have changed, to allow the window to adjust its content accordingly. By overriding this method you can handle the insets (and hence your app's layout) however you want.
form:
https://developer.android.com/training/system-ui/status.html#behind

If you know exactly the size VS height
like
for example in a device with 320 X 480 screen size the status bar height is 25px, for a device with 480 x 800 the status bar height must be 38px
then you can just get the width of your view / the screen size you can just use an if else statement to get the height of status bar

Since multi-window mode is available now, your app may not have statusbar on top.
Following solution handle all the cases automatically for you.
android:fitsSystemWindows="true"
or programatically
findViewById(R.id.your_root_view).setFitsSystemWindows(true);
you may also get root view by
findViewById(android.R.id.content).getRootView();
or
getWindow().getDecorView().findViewById(android.R.id.content)
For more details on getting root-view refer - https://stackoverflow.com/a/4488149/9640177

This issue recently became relevant for me because of the notch in my Pixel 3XL. I really liked android developer's solution, but I wanted to be able to get the status bar height at will, since it was specifically necessary for a full screen animation that I needed to play. The function below enabled a reliable query:
private val DEFAULT_INSET = 96
fun getInsets(view: View?): Int {
var inset = DEFAULT_INSET
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//Safe because only P supports notches
inset = view?.rootWindowInsets?.stableInsetTop ?: DEFAULT_INSET
}
return inset
}
fun blurView(rootView: View?, a: SpacesActivity?) {
val screenBitmap = getBitmapFromView(rootView!!)
val heightDifference = getInsets(rootView)
val croppedMap = Bitmap.createBitmap(
screenBitmap, 0, heightDifference,
screenBitmap.width,
screenBitmap.height - heightDifference)
val blurredScreen = blurBitmap(croppedMap)
if (blurredScreen != null) {
val myDrawable = BitmapDrawable(a!!.resources, blurredScreen)
a.errorHudFrameLayout?.background = myDrawable
a.appBarLayout?.visibility = View.INVISIBLE
}
}
And then in the activity class:
fun blurView() {
this.runOnUiThread {
Helper.blurView(this)
}
}
You will of course want to make pass a weak reference of the activity to the static Helper class method parameter, but for the sake of brevity I refrained in this example. The blurBitmapand errorHudFrameLayout are omitted for the same reason, since they don't directly pertain to obtaining the height of the status bar.

Related

How to find dimensions for status bar, navigation bar and screen in Android AccessibilityService

I have a Java app (API 23). In it I have a MainActivity and an AccessibilityService. In the AccessibilityService:
#Override
public void onServiceConnected() {
oView = new LinearLayout(this);
oView.setBackgroundColor(0x88ff0000); // The translucent red color
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
width,
height,
xPos, yPos,
WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT
);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(oView, params);
}
I need to adjust the width, height, xPos and yPos so it covers the whole screen including the status bar and navigation bar. That means I have to find the dimensions for the status bar, screen, and navigation bar (I can work out the values I need once I have those).
I found Height of statusbar? - best answer seemed to be
ViewCompat.setOnApplyWindowInsetsListener(rootView, new OnApplyWindowInsetsListener() {
#Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
//THIS is the value you want.
int statusBarHeight = insets.getSystemWindowInsetTop();
int navigationBar = insets.getSystemWindowInsetBottom();
// Let the view handle insets as it likes.
return ViewCompat.onApplyWindowInsets(v, insets);
}
});
But what rootView can I use, since there's no guarantee my Activity will be visible? And do I have to move the creation of the view from onServiceConnected() to inside onApplyWindowInsets()?
Is this really the best way to do this?
Follow up questions to bear in mind for the above - depending on the above and whether it answers them too, I will ask here or in a separate question:
What happens when the screen rotates? What if the status bar and/or navigation bar disappear (for example, if it goes fullscreen)? Seems like I need to handle that, re-read the heights, and re-create the view. Any thoughts or guidance on how to do that would be welcomed.
=== Update - Progress so far ===
I thought I only needed screen size plus info about the status bar (size, location), but Navigation Bar is sometimes on the left side of the screen so I need that, and Keyboard might affect things too.
I can get screen size with
Display myDisplay = wm.getDefaultDisplay();
Display.Mode mode = myDisplay.getMode();
int height = mode.getPhysicalHeight();
int width = mode.getPhysicalWidth();
I'm still working on the various location and sizes. I tried creating a view and then reading insets but it gave me the wrong answers. So unless a better answer arises I will probably have to use
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
But that can give wrong answers in some cases if Status bar is hidden, and it doesn't tell me where on the screen it is. I'm still working on that; got a few things to try, so we'll see.
Handling rotation in a service can be done using onConfigurationChanged() - see How do I use a service to monitor Orientation change in Android
Hope that helps someone - please, desperately searching for those final pieces.
Update: There's a problem when the screen is rotated upside-down. See Find placement of Android Navigation Bar without Insets (inside Service)
I'm currently working on a solution with my own research combined with https://stackoverflow.com/a/55348825/1910690
But I really wish I could just use Insets, or something like that.
==============
I tried a bunch of things that seemed to fail because I didn't have an activity; it's possible if I had poked around some more I would have made it work with Insets, and I still hope for an answer using them as they are more official and allow for notches etc.
In the meantime I finally pieced various answers together to make the following. It would probably work for a normal Service as well as an AccessibilityService.
The point is that at the end of onGlobalLayout() inside CreateLayoutHelperWnd() you have the complete information on screen size, orientation, status bar and navigation bar visibility and size, and you know that either you've just started your service or something changed. I found that it gets called twice sometimes even though nothing changed, probably because sometimes it does 'hide status+nav bar' and then 'change orientation' (same results for both), and sometimes it does it the other way around (different results) so I have wrapped the results in a class, and I compare the new results with the results from the last time and only do something if a result changed (that's why I use so many global variables, because those got moved later to the special class).
Please note that this is my first serious foray into Android and Java, so apologies if it's badly done - comments welcomed. It also doesn't handle error checking (eg StatusBar not found). Also note that I have not tested this extensively across multiple devices, I have no idea what it does with folding devices, multiple displays, or even split-screen; but I tried to account for the issues I saw in the various solutions (eg reading Status Bar height sometimes gives the wrong answer when it's closed on some devices, so I try to check if it is open or closed). I'll update if needed as I test more.
In the AccessibilityService:
// global variables
int statusBarHeight = -1;
int navigationBarHeight = -1;
int screenWidth = -1;
int screenHeight = -1;
View layoutHelperWnd;
#Override
public void onServiceConnected() {
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
CreateLayoutHelperWnd(wm);
}
public void onUnbind() {
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
DestroyLayoutHelperWnd(wm);
}
private void DestroyLayoutHelperWnd(WindowManager wm) {
wm.removeView(layoutHelperWnd);
}
private void CreateLayoutHelperWnd(WindowManager wm) {
final WindowManager.LayoutParams p = new WindowManager.LayoutParams();
p.type = Build.VERSION.SDK_INT < Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY :
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
p.gravity = Gravity.RIGHT | Gravity.TOP;
p.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
p.width = WindowManager.LayoutParams.MATCH_PARENT;
p.height = WindowManager.LayoutParams.MATCH_PARENT;
p.format = PixelFormat.TRANSPARENT;
layoutHelperWnd = new View(this); //View helperWnd;
wm.addView(layoutHelperWnd, p);
final ViewTreeObserver vto = layoutHelperWnd.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// catches orientation change and fullscreen/not fullscreen change
// read basic screen setup - not sure if needed every time, but can't hurt
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
ReadScreenDimensions(wm); // sets up screenWidth and screenHeight
statusBarHeight = GetStatusBarHeight();
navigationBarHeight = GetNavigationBarHeight();
int windowHeight = layoutHelperWnd.getHeight();
int windowWidth = layoutHelperWnd.getWidth();
Boolean isFullScreen, isStatusBar, isNavigationBar;
isFullScreen = isStatusBar = isNavigationBar = false;
Configuration config = getResources().getConfiguration();
if (config.orientation == ORIENTATION_LANDSCAPE) {
// landscape - screenWidth is for comparison to windowHeight (top to bottom), status bar may be on top, nav bar may be on right
if (screenWidth != windowHeight)
isStatusBar = true;
if (screenHeight != windowWidth)
isNavigationBar = true;
}
else {
// portrait, square, unknown - screenHeight is for comparison to windowHeight (top to bottom), status bar may be on top, nav bar may be on bottom
if (screenHeight != windowHeight) {
int difference = screenHeight - windowHeight;
if (difference == statusBarHeight)
isStatusBar = true;
else if (difference == navigationBarHeight)
isNavigationBar = true;
else {
isStatusBar = true;
isNavigationBar = true;
}
}
}
if (!isStatusBar && !isNavigationBar)
isFullScreen = true;
Log.v(TAG,"Screen change:\nScreen W,H: (" + screenWidth + ", " + screenHeight + ")\nOrientation: " + (config.orientation == ORIENTATION_LANDSCAPE ? "Landscape" : config.orientation == ORIENTATION_PORTRAIT ? "Portrait" : "Unknown") +
"\nWindow W,H: (" + windowWidth + ", " + windowHeight + ")\n" + "Status bar H: " + statusBarHeight + ", present: " + isStatusBar + "\nNavigation bar H: " + navigationBarHeight + ", present: " + isNavigationBar + "\nFullScreen: " + isFullScreen);
// do any updates required to the service's assets here
}
});
}
public void ReadScreenDimensions(WindowManager wm) {
Display myDisplay = wm.getDefaultDisplay();
Display.Mode mode = myDisplay.getMode();
screenHeight = mode.getPhysicalHeight();
screenWidth = mode.getPhysicalWidth();
}
public int GetStatusBarHeight() {
// returns 0 for no result found
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public int GetNavigationBarHeight() {
// returns 0 for no result found
int result = 0;
int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
return getResources().getDimensionPixelSize(resourceId);
}
return result;
}
You will also need to add to your manifest (for the app, not the service):
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
and in your main activity call isSystemAlertPermissionGranted() and then do something meaningful depending on what is returned (possibly waiting until onActivityResult() in some cases). Er, I basically grabbed this wholesale from various places and have not changed it much or at all. :)
public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE= 1234;
public boolean isSystemAlertPermissionGranted() {
// if this doesn't work, try https://stackoverflow.com/questions/46208897/android-permission-denied-for-window-type-2038-using-type-application-overlay
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
return false;
}
else
{
Log.v(TAG,"Permission is granted");
return true;
}
}
else { //permission is automatically granted on sdk<23 upon installation
Log.v(TAG, "Permission is granted");
return true;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
// Check if the app get the permission
if (Settings.canDrawOverlays(this)) {
// Run your logic with newly-granted permission.
} else {
// Permission not granted. Change your logic accordingly.
// App can re-request permission anytime.
}
}
}

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.)

Dimension of soft buttons bar

Is there a way to determine the dimension (width) of the menu bar of devices without hard menu buttons? (like the archos devices).
I need to know the usable dimension of the screen...
This method is very useful in order to set the layout padding in Android KitKat (4.4). Using this, you can avoid the soft buttons bar overlapping over your layout.
The getRealMetrics method is only available with API 17 and +, but I'm only using the following method I wrote for devices on API 19+
#SuppressLint("NewApi")
private int getSoftbuttonsbarHeight() {
// getRealMetrics is only available with API 17 and +
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return 0;
}
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int usableHeight = metrics.heightPixels;
getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
int realHeight = metrics.heightPixels;
return realHeight > usableHeight ? realHeight - usableHeight : 0;
}
Tested upon Nexus 5 & Nexus 7 2013.
A very late answer but for anyone that encounters this problem. A simple way to get the amount of usable space offsetting any soft keys/navigation bar or even the status bar, is to use getWindowVisibleDisplayFrame(Rect) from the Apps DecorView. This will load a Rect object with the dimension of the display that is actually usable.
Since you cannot directly get a reference to the Activiy's DecorView, you need to first get the Activity's window using the accessor method, getWindow(). This will return the window object that holds the Activity and other screen elements. To get the decorView that contains the activity as well as the screen decorations i.e. the status bar, navigation bar/soft button bar, call accessor method getDecorView(). Once your have a reference to the DecorView call getWindowVisibleDisplayFrame(Rect) and you will have a loaded Rect object.
Starting Andorid 3.2, the height of system status bar is not included in DisplayMetrics's height, you have to use undocumented APIs (Display.getRawWidth() and Display.getRawHeight()) to get the physical screen width or height.
Method mGetRawW = Display.class.getMethod("getRawWidth");
Method mGetRawH = Display.class.getMethod("getRawHeight");
int nW = (Integer)mGetRawW.invoke(dp);
int nH = (Integer)mGetRawH.invoke(dp);
UPDATED: For API 13-16, you have to use the above code to get real width/height. For API 17+, you can now use the new public API, Display.getRealSize()
for me, in android note 10, I need to get navigation bar height by dimen:
fun getSoftNavigationBarSize(resources: Resources): Int {
var result = 0
val resourceId: Int = resources.getIdentifier("navigation_bar_height", "dimen", "android")
if (resourceId > 0) {
result = resources.getDimensionPixelSize(resourceId)
}
return result
}

Display metrics minus status bar?

I need to get the dimensions of the display rectangle that the application can use on the device. For that I tried using:
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
My problem is that it gives me the height of the whole display and the display has a "status / notification" bar on top that the application can't use.
I need the acual dimension that the application can use.
To help you understand the question better I'll leave an image:
The biggest trick to all of this is that you can't usually gain access to a true value of that view's size until layout is complete. Which means onCreate() (and often onResume() also) are too early in the process to do the calculation. The following code will get you a view representing the content view of the Activity, at which point you can examine its height and width:
View content = getWindow().findViewById(Window.ID_ANDROID_CONTENT);
Log.d("DISPLAY", content.getWidth() + " x " + content.getHeight());
This also accounts for any title views you may have set in the Activity. You could also obtain a reference to the root layout you set as the content view when the XML is inflated and do the same thing if that layout is set to fill_parent in both dimensions.
A good method where I often make calls like this is onWindowFocusChanged() which will be called at the point when your Activity is just about visible to the user.
Hope that Helps!
This call is independent of the point of time you call it:
...
Point dimensions = getDisplayDimensions(context);
int width = dimensions.x;
int height = dimensions.y;
...
#NonNull
public static Point getDisplayDimensions( Context context )
{
WindowManager wm = ( WindowManager ) context.getSystemService( Context.WINDOW_SERVICE );
Display display = wm.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics( metrics );
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
// find out if status bar has already been subtracted from screenHeight
display.getRealMetrics( metrics );
int physicalHeight = metrics.heightPixels;
int statusBarHeight = getStatusBarHeight( context );
int navigationBarHeight = getNavigationBarHeight( context );
int heightDelta = physicalHeight - screenHeight;
if ( heightDelta == 0 || heightDelta == navigationBarHeight )
{
screenHeight -= statusBarHeight;
}
return new Point( screenWidth, screenHeight );
}
public static int getStatusBarHeight( Context context )
{
Resources resources = context.getResources();
int resourceId = resources.getIdentifier( "status_bar_height", "dimen", "android" );
return ( resourceId > 0 ) ? resources.getDimensionPixelSize( resourceId ) : 0;
}
public static int getNavigationBarHeight( Context context )
{
Resources resources = context.getResources();
int resourceId = resources.getIdentifier( "navigation_bar_height", "dimen", "android" );
return ( resourceId > 0 ) ? resources.getDimensionPixelSize( resourceId ) : 0;
}
The trick is that it compares the screen display metrics (what you want modulo the status bar) and the "real metrics", which is the physical pixels of the device.
The status bar height then is subtracted ad-hoc if that did not happen yet.
(In my tests the navigation bar, containing back and home buttons, was already subtracted.)

Height of statusbar?

Is there a way to get the height of the statusbar + titlebar? Checking the dev forum shows the same question but no solution (that I could find).
I know we can get it after the initial layout pass, but I'm looking to get it in onCreate() of my activity.
Thanks
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight= rectgle.top;
int contentViewTop=
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight= contentViewTop - StatusBarHeight;
Log.i("*** Jorgesys :: ", "StatusBar Height= " + StatusBarHeight + " , TitleBar Height = " + TitleBarHeight);
Get the Height of the status bar on the onCreate() method of your Activity, use this method:
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
For those, like me, who want to use it in your XML layouts:
<...
android:layout_marginTop="#*android:dimen/status_bar_height"
... />
Don't be confused by that Android Studio (2.2 Preview 3 -- at the moment of writing) doesn't support this notion. The runtime does. I took it from the Google's source code.
Although this is an old question, I found that the answer didn't work in onCreate():
I found this code from here which does work in the onCreate() method
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
I hope this helps to anyone that runs into this issue.
The supported way of getting status bar height is to use WindowInsets class starting from API 21+:
customView.setOnApplyWindowInsetsListener((view, insets) -> {
// Handle insets
return insets.consumeSystemWindowInsets();
});
or WindowInsetsCompat for support libraries:
ViewCompat.setOnApplyWindowInsetsListener(customView, (view, insets) -> {
// Handle insets
return insets.consumeSystemWindowInsets();
});
You can also override the onApplyWindowInsets method inside the view:
public class CustomView extends View {
#Override
public WindowInsets onApplyWindowInsets(final WindowInsets insets) {
final int statusBarHeight = insets.getStableInsetTop();
return insets.consumeStableInsets();
}
}
For further details, I'd recommend checking Chris Banes talk - Becoming a master window fitter (slides available here).
You could also take the dimension of the status bar found in the dimens.xml file of android using the way that this blog post describes.
This can get the height of the statusbar without the need to wait for drawing.
Quoting the code from the blog post:
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
You need to put this method in a ContextWrapper class.
I would suggest next code:
Rect rect = new Rect();
Window window = activity.getWindow();
if (window != null) {
window.getDecorView().getWindowVisibleDisplayFrame(rect);
android.view.View v = window.findViewById(Window.ID_ANDROID_CONTENT);
android.view.Display display = ((android.view.WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
//return result title bar height
return display.getHeight() - v.getBottom() + rect.top;
}
Two examples:
1) Device 1
brand: samsung,
device: maguro,
board: tuna,
cpu_abi: armeabi-v7a,
display: ICL53F.M420KREL08,
manufacturer: samsung,
model: Galaxy Nexus,
ver.release: 4.0.2,
ver.sdk: 14;
Screen resolution: 1280 x 720.There are no hardware buttons on this device.
Results:
rect: left=0 right=720 top=72 bottom=1208;
v: left=0 right=720 top=72 bottom=1208;
display: height=1208 width=720;
correct result=72;
Device 1 has title bar at the top of the screen and status bar with software buttons at the bottom of the screen.
2) Device 2
device: bravo,
board: bravo,
cpu_abi: armeabi-v7a,
display: FRG83G,
manufacturer: HTC,
model: HTC Desire,
ver.release: 2.2.2,
ver.sdk: 8,
Screen resolution: 800 x 400. This device has hardware buttons.
Results:
rect: left=0 right=480 top=38 bottom=800;
v: left=0 right=480 top=0 bottom=800;
display: height=800 width=480;
correct result: phone_bar_height=38;
Device 2 has title bar at the top of the screen and hasn't status bar at all.
Two solutions were suggested above:
A) v.getTop() - rect.top
(it is incorrect for device 1 - it gives 0 instead of 72)
B) display.getHeight() - v.getHeight()
(it is incorrect for device 2 - it gives 0 instead of 38)
Variant:
display.getHeight() - v.getBottom() + rect.top
gives correct results in both cases.
Update
3) One more example (third device):
brand: LGE,
device: v909,
cpu_abi: armeabi-v7a,
display: HMJ37,
model: LG-V909,
ver.release: 3.1,
ver.sdk: 12
rect: left=0 right=1280 top=0 bottom=720
v: left=0 right=1280 top=0 bottom=720
Display: height=768 width=1280
phone_bar_height=48
Device 3 has horizontal orientation, hasn't title bar at the top of the screen and has status bar at the bottom of the screen.
So, here:
int size_of_title_bar = rect.top;
int size_of_status_bar = display.getHeight() - v.getBottom();
It's correct for devices 2 and 3. I am not sure about device 1. User sent me screenshot of device 1. There is a status bar with software button there. But expression "display.getHeight() - v.getBottom()" gives 0.
Attach a runnable to one of your views in your onCreate method, and place the above code in there. This will cause the application to calculate the status bar + titlescreen height when they are attached to the screen.
Take a look at the code below:
myView.post(new Runnable() {
#Override
public void run() {
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight= rectgle.top;
int contentViewTop= window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight= contentViewTop - StatusBarHeight;
}
});
If this still doesn't do the trick, try invoking the view's postDelayed method instead of post and adding a millisecond value as the second argument.
This may seem unrelated but most of the time, the reason that people look for the status bar height is to offset their own views so they are not placed under it.
By setting fitsSystemWindows on the view you want to "push down" to give space to the status bar, it will be done automatically and according to the size of the status bar on each device. Padding will be added to the view that has this property set to true.
Keep in mind that padding will only be added to the first view in the hierarchy with fitSystemWindows set to true
This applies to cases where the status bar is translucent for example. Make sure that you set a Theme to the activity that doesn't have fitSystemWindows set, otherwise the padding will be added to the activity instead (because it's first in the hierarchy).
This article is a good read on the subject
As of API 23 there is a better solution to getting the status bar height. API 23 adds a WindowInsets feature, so you can use this code to get the size of the system insets, in this case at the top.
public int getStatusBarHeight() {
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
return binding.mainContent.getRootWindowInsets().getStableInsetTop();
}
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if(resourceId != 0) {
return getResources().getDimensionPixelSize(resourceId);
}
return 0;
}
Note that getRootWindowInsets() will return null until after the View has been attached to a Window so it can't be used directly in onCreate() but you can add a listener for the window attach and do it there - here I am adding the status bar inset to the size of my toolbar, which I hide and show, along with the status bar. When it's shown, I want the status bar over the top of it so I add the status bar height to the toolbar's top padding.
binding.mainContent.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
#Override
public void onViewAttachedToWindow(View view) {
binding.toolbar.setPadding(binding.toolbar.getPaddingLeft(),
binding.toolbar.getPaddingTop() + getStatusBarHeight(),
binding.toolbar.getPaddingRight(), binding.toolbar.getPaddingBottom());
binding.mainContent.removeOnAttachStateChangeListener(this);
}
#Override
public void onViewDetachedFromWindow(View view) {
}
});
I think better way to calculate that is to get height of fullscreen minus our main layout
phoneBarsHeight = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight()
- mainView.getHeight();
And you can put it in onGlobalLayout(). This works on tablets too, I tried it on Theme.NoTitleBar, but it must always works.
Maybe you can even enhance it and use it onCreate() by changing mainView.getHeight() to mainView.getMeasuredHeight().
The solution posted by Jorgesys is very good, but it doesn't work inside onCreate() method.
I guess it's because statusbar and titlebar are created after onCreate().
The solution is easy - you should put code inside runnable and execute it after onCreate() by using root.post((Runnable action) );
So the whole solution:
root = (ViewGroup)findViewById(R.id.root);
root.post(new Runnable() {
public void run(){
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight= rectgle.top;
int contentViewTop=
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight= contentViewTop - StatusBarHeight;
Log.i("*** jakkubu :: ", "StatusBar Height= " + StatusBarHeight +
" , TitleBar Height = " + TitleBarHeight);
}
});
I find it here
Ok. Final answer!!! One that does not have side-effects, relies on documented behavior, supports Q, cutouts, devices with different status-bar size depending on orientation, &c.
protected void onCreate(Bundle savedInstanceState) {
...
setContentView(R.layout.activity_main);
....
// Use The topmost view of the activity, which
// is guaranteed to be asked about window insets/
View rootView = findViewById(R.id.root_view_of_your_activity);
ViewCompat.setOnApplyWindowInsetsListener(rootView, new OnApplyWindowInsetsListener() {
#Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets)
{
//THIS is the value you want.
statusBarHeight = insets.getSystemWindowInsetTop();
// Let the view handle insets as it likes.
return ViewCompat.onApplyWindowInsets(v,insets);
}
});
The callback occurs after onStart(), before first layout, and occasionally thereafter.
Current actual way:
Kotlin:
ViewCompat.setOnApplyWindowInsetsListener(toolbar) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars())
view.updateLayoutParams<MarginLayoutParams> {
topMargin = insets.top
}
WindowInsetsCompat.CONSUMED
}
Java:
ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
mlp.topMargin = insets.top;
v.setLayoutParams(mlp);
return WindowInsetsCompat.CONSUMED;
}
Google recommends using it like this if you want to support edge-to-edge in your app.
Targeting API 30, I've used successfully updated Nicklas answer (ref:https://stackoverflow.com/a/47125610/2163045)
In my example I'm adjusting dynamically custom toolbar height in fullscreen WindowCompat.setDecorFitsSystemWindows(window, false) Activity
Tested on GooglePixel 5
class MyActivity : ViewBindingActivity<LayoutBinding>() {
...
override fun created(binding: LayoutBinding, savedInstanceState: Bundle?) {
binding.root.setOnApplyWindowInsetsListener { _, insets ->
val statusBarHeight = insets.getInsets(WindowInsets.Type.statusBars()).top // <- HERE YOU ARE
val toolbarHeight = getDimenPx(R.dimen.toolbar_height)
binding.toolbar.layoutParams.height = statusBarHeight + toolbarHeight
insets
}
}
}

Categories

Resources