Check for navigation bar

JavaAndroidLayoutAndroid 4.0-Ice-Cream-SandwichAndroid 4.2-Jelly-Bean

Java Problem Overview


I am trying to check to see whether the android navigation bar is present on load so that I can adjust a layout accordingly, does anyone have any suggestions?

This is the navigation bar I am trying to detect: enter image description here

P.S. All I have found so far are 'bad' ways to try and remove the bar, which I dont want to do.

Java Solutions


Solution 1 - Java

Took me some time but I've found a more reliable way than relying on hasPermanentMenuKey() which doesn't work for newer phones like the HTC One which have no menu key but do have home & back keys so don't need (or show) the soft navigation bar. To get around this try the following code which checks for a back button too:

boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);

if(!hasMenuKey && !hasBackKey) {
    // Do whatever you need to do, this device has a navigation bar
}

Solution 2 - Java

There's no reliable way to check for a navigation bar. Using KeyCharacterMap.deviceHasKey you can check if certain physical keys are present on the device, but this information is not very useful since devices with physical keys can still have a navigation bar. Devices like the OnePlus One, or any device running a custom rom, have an option in the settings that disables the physical keys, and adds a navigation bar. There's no way to check if this option is enabled, and deviceHasKey still returns true for the keys that are disabled by this option.

This is the closest you can get:

boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
boolean hasHomeKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_HOME);

if (hasBackKey && hasHomeKey) {
    // no navigation bar, unless it is enabled in the settings
} else {
    // 99% sure there's a navigation bar
}

If the back and home button are not both physically present on the device, it must have a navigation bar, because the user otherwise wouldn't be able to navigate at all. However, you can never be 100% sure about this, since manufacturers can implement deviceHasKey wrong.

Solution 3 - Java

Another solution (a part of my class UtilsUISystem )

    public static boolean hasNavBar (Resources resources)
    {
        //Emulator
        if (Build.FINGERPRINT.startsWith("generic"))
            return true;

        int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
        return id > 0 && resources.getBoolean(id);
    }

Solution 4 - Java

Here is a quick answer that combines Pauland's and Philask's solutions. I'm afraid I don't have enough devices available to test if it works everywhere, though. I'd be interested to hear others' results.

boolean hasNavBar(Context context) {
    Resources resources = context.getResources();
    int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
    if (id > 0) {
        return resources.getBoolean(id);
    } else {    // Check for keys
        boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
        boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
        return !hasMenuKey && !hasBackKey;
    }
}

Solution 5 - Java

I've done like this, it works on every device I tested, and even on emulators:

public static boolean hasNavigationBar(Activity activity) {
    Rect rectangle = new Rect();
    DisplayMetrics displayMetrics = new DisplayMetrics();
    activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rectangle);
    activity.getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
    return displayMetrics.heightPixels != (rectangle.top + rectangle.height());
}

Solution 6 - Java

you could add this code to your activity's onCreate() method:

 View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
        (new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
                    // TODO: The navigation bar is visible. Make any desired
                    // adjustments to your UI, such as showing the action bar or
                    // other navigational controls.
                } else {
                    // TODO: The navigation bar is NOT visible. Make any desired
                    // adjustments to your UI, such as hiding the action bar or
                    // other navigational controls.
                }
            }
        });

Solution 7 - Java

This method worked for me

    int id = getResources().getIdentifier("config_showNavigationBar","bool","android");
        boolean result = id > 0 && getResources().getBoolean(id);
//
        if(result) {
           
            // Do whatever you need to do, this device has a soft Navigation Bar
        }

It worked for me and tested in many devices.

Solution 8 - Java

Something that should probably work better is to measure the screen.

Starting with API 17 there's getWindowManager().getDefaultDisplay().getRealSize(), which can be compared to size returned by getWindowManager().getDefaultDisplay().getSize().

If you get different results I think it's safe to say that there is a nav bar and if you get the same results there isn't one. One thing to pay attention to is your target SDK and supported screens, which might cause the result of getSize() to be scaled if Android thinks your app wouldn't work well on the current device without scaling.

Below API 17 you can measure the screen via getWindowManager().getDefaultDisplay().getMetrics() in both landscape and portrait mode, and again, different results probably mean there's a nav bar.

However, if you get the same results, you don't actually know, as phones can keep the nav bar on the shorter edge even when in landscape. An educated guess would be that if either the width or the height is 4% to 8% smaller than standard sizes like 1280x800, 1280x720, 1024x600, while the other dimension is equal, then again there probably is a nav bar. Don't bet on it, though. There are too many resolutions, which differ too little from one another for this to work well.

Solution 9 - Java

boolean hasNavBar(Context context) {
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        // navigation bar was introduced in Android 4.0 (API level 14)
        Resources resources = context.getResources();
        int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
        if (id > 0) {
            return resources.getBoolean(id);
        } else {    // Check for keys
            boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
            boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
            return !hasMenuKey && !hasBackKey;
        }
    } else {
        return false;
    }
}

Solution 10 - Java

I see the answers above, I want to indicate that the "not exist" can be regard as the height of 0; so it can be like this:

public static int getScreenH(Context context) {
    DisplayMetrics dm = new DisplayMetrics();
    dm = context.getResources().getDisplayMetrics();
    int h = dm.heightPixels;
    return h;
}

public static int getDpi(Context context) {

    DisplayMetrics displayMetrics1 = context.getResources().getDisplayMetrics();
    int height1 = displayMetrics1.heightPixels;

    int dpi = 0;
    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = windowManager.getDefaultDisplay();
    DisplayMetrics displayMetrics = new DisplayMetrics();

    @SuppressWarnings("rawtypes")
    Class c;
    try {
        c = Class.forName("android.view.Display");
        @SuppressWarnings("unchecked")
        Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
        method.invoke(display, displayMetrics);
        dpi = displayMetrics.heightPixels;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return dpi;
}

public static int getBottomStatusHeight(Context context) {
    int totalHeight = getDpi(context);

    int contentHeight = getScreenH(context);

    return totalHeight - contentHeight;
}

Solution 11 - Java

On Android 10 (API level 29), you can also check for the bottom window inset:

@RequiresApi(api = Build.VERSION_CODES.Q)
private boolean hasNavigationBar() {
    final WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets();
    if (windowInsets == null) {
            throw new RuntimeException("Window is not attached");
    }
    return windowInsets.getTappableElementInsets().bottom > 0;
}

Note that the window has to be attached for getRootWindowInsets() to return a non-null value, so you likely want to call this in onAttachedToWindow.

This solution is also used by LineageOS's launcher app Trebuchet (source), which is how I learned of it.

Solution 12 - Java

Solution: Only devices without permanent hardware keys have the navigation bar hence you can check for the API version and use hasPermanentMenuKey() to find hardware keys

 boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJonnoView Question on Stackoverflow
Solution 1 - JavaphilaskView Answer on Stackoverflow
Solution 2 - JavaRudeyView Answer on Stackoverflow
Solution 3 - JavaPaulandView Answer on Stackoverflow
Solution 4 - JavaTadView Answer on Stackoverflow
Solution 5 - JavaMatteoView Answer on Stackoverflow
Solution 6 - JavajoeView Answer on Stackoverflow
Solution 7 - JavaANAND SONIView Answer on Stackoverflow
Solution 8 - JavaciobiView Answer on Stackoverflow
Solution 9 - JavaKishan VaghelaView Answer on Stackoverflow
Solution 10 - Javauser2944157View Answer on Stackoverflow
Solution 11 - Javauser2623008View Answer on Stackoverflow
Solution 12 - JavaJonnoView Answer on Stackoverflow