I'm working on a cross-platform app which has been ported to Android. Due to its non-Android heritage it doesn't make extensive use of Android UI elements – the main app window is one single View
.
I would like to implement translucent system (status and navigation) bars, as supported from KitKat onwards, while ensuring that UI elements inside the main View
are not obstructed by them.
This answer shows how to get the default height for these bars (there is also navigation_bar_height_landscape
for navigation bar height in landscape mode, and navigation_bar_width
for the width of a vertical navigation bar). But these are only the system's default sizes and contain no information if the navigation bar is currently being shown, and whether it is showing at the right or on the bottom edge of the screen.
The other answers I have found so far probably work fine for non-translucent system bars: they simply compare total screen size to the size of the main app view, and the difference is the space occupied by the system bars. However, with translucent system bars, the size difference is zero and this approach won't work.
How can I reliably determine if the navigation bar is being displayed, and in which position?
Looking around a bit, including this part of the AOSP code, I came up with the following:
// determine if navigation bar is going to be shown
boolean isNavShowing;
if (Build.VERSION.SDK_INT >= 13) {
isNavShowing = ViewConfiguration.get(activity.getApplication()).hasPermanentMenuKey();
}
// determine where the navigation bar would be displayed
boolean isNavAtBottom;
if (Build.VERSION.SDK_INT >= 13) {
isNavAtBottom = (activity.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE)
|| (activity.getResources().getConfiguration().smallestScreenWidthDp >= 600);
}
You can then calculate the following insets:
status_bar_height
navigation_bar_width
navigation_bar_height_landscape
; else navigation_bar_height
.Defaults, as per dimens.xml, are:
status_bar_height
: 24 dpnavigation_bar_height
: 48 dpnavigation_bar_height_landscape
: 48 dpnavigation_bar_width
: 48 dp(you might want to fall back to these if somehow you fail to get the actual values.)
The logic for isNavShowing
is a variation on something I implemented a while ago. It reliably detects the presence of a physical Menu button even on a OnePlusOne running CyanogenMod (where the user can switch between a navigation bar and hardware buttons via Settings). Even when adding a software Menu button to the navigation bar (which seems to be a CM addition), the navigation bar is still detected correctly.
The logic for isNavAtBottom
is mostly taken from the findNavigationBar()
function in the source file I linked above and should work unless you are using a heavily customized build of Android.