Detect soft navigation bar availability in android device progmatically?

27,139

Solution 1

Following method worked for me and tested in many devices.

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

Note: Verified this method in real device

Solution 2

As i know you can detect it by

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

But it required APIs 14+


If above solution doesn't work for you then try below method

public boolean isNavigationBarAvailable(){

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

        return (!(hasBackKey && hasHomeKey));
    }

Solution 3

Its a hack but it works fine. Try it.

public static boolean hasSoftKeys(WindowManager windowManager){
  Display d = windowManager.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;

  return (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0;
}

Solution 4

The accepted answer should work fine on most real devices, but it doesn't work in the emulators.

However, in Android 4.0 and above, there's an internal API that also works on the emulators: IWindowManager.hasNavigationBar(). You can access it using reflection:

/**
 * Returns {@code null} if this couldn't be determined.
 */
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@SuppressLint("PrivateApi")
public static Boolean hasNavigationBar() {
    try {
        Class<?> serviceManager = Class.forName("android.os.ServiceManager");
        IBinder serviceBinder = (IBinder)serviceManager.getMethod("getService", String.class).invoke(serviceManager, "window");
        Class<?> stub = Class.forName("android.view.IWindowManager$Stub");
        Object windowManagerService = stub.getMethod("asInterface", IBinder.class).invoke(stub, serviceBinder);
        Method hasNavigationBar = windowManagerService.getClass().getMethod("hasNavigationBar");
        return (boolean)hasNavigationBar.invoke(windowManagerService);
    } catch (ClassNotFoundException | ClassCastException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        Log.w("YOUR_TAG_HERE", "Couldn't determine whether the device has a navigation bar", e);
        return null;
    }
}

Solution 5

Try this method,in this way you can detect if the navigation bar exist.

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public boolean hasNavBar(Context context) {
    Point realSize = new Point();
    Point screenSize = new Point();
    boolean hasNavBar = false;
    DisplayMetrics metrics = new DisplayMetrics();
    this.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
    realSize.x = metrics.widthPixels;
    realSize.y = metrics.heightPixels;
    getWindowManager().getDefaultDisplay().getSize(screenSize);
    if (realSize.y != screenSize.y) {
        int difference = realSize.y - screenSize.y;
        int navBarHeight = 0;
        Resources resources = context.getResources();
        int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
        if (resourceId > 0) {
            navBarHeight = resources.getDimensionPixelSize(resourceId);
        }
        if (navBarHeight != 0) {
            if (difference == navBarHeight) {
                hasNavBar = true;
            }
        }

    }
    return hasNavBar;

}
Share:
27,139
Raghu Mudem
Author by

Raghu Mudem

I am Developer with aspiration to work with global environment

Updated on July 09, 2022

Comments

  • Raghu Mudem
    Raghu Mudem almost 2 years

    I am trying to determine soft navigation bar through the android program. I didn't find straight way to determine. Is there anyway to find the navigation bar availability.

    Soft Navigation bar image is here.

    enter image description here

  • Raghu Mudem
    Raghu Mudem about 9 years
    Thanks for your response. I am looking to determine soft navigation bar presence.
  • Raghu Mudem
    Raghu Mudem about 9 years
    The device don't have permanentmenu key is not equalant to device have soft navigation bar. Some device don't have permanentmenu key and don't have soft navigation bar also. Please look this device gsmarena.com/asus_zenfone_5-pictures-5952.php
  • IshRoid
    IshRoid about 9 years
    Thank you for such great information, because of this type of devices you can try my second solution (look updated answer)
  • Raghu Mudem
    Raghu Mudem about 9 years
    Thanks man. Seems it will work for me. I tested on two available devices as expected.
  • IshRoid
    IshRoid about 9 years
    Enjoy programming, if this answer help you , then accepting answer or upvote will be very appreciated :-)
  • MattButtMatt
    MattButtMatt almost 8 years
    This code works but instead of 'android' use '"android"'
  • CoolMind
    CoolMind over 7 years
    Returns false in both cases.
  • Thomas Cirksena
    Thomas Cirksena about 7 years
    For me only the first solution works. The second failed on nexus 5
  • Hamzeh Soboh
    Hamzeh Soboh about 7 years
    No idea why hasBackKey equals true on Sony Xperia Z3. Which make the second solution fail.
  • Sam
    Sam about 7 years
    Note that this always returns false on the Android emulators. See this commit message for an explanation.
  • Sam
    Sam about 7 years
    Despite not working on the emulators, this is very close to what the Android source code does, so it should be pretty accurate on real devices.
  • PriyankaChauhan
    PriyankaChauhan almost 7 years
    Thanks bro you saved my life !
  • weaknespase
    weaknespase over 6 years
    Of course, using internal api sort of stings, but hey, it works across all my devices (at least up to API25). Extra + for not being Context-dependent.
  • Saksham Khurana
    Saksham Khurana over 6 years
    Agree that its a hack , but a great one. Kudos
  • Muneef M
    Muneef M over 6 years
    checked in one plus 3 enabling both its always returns false.
  • JavierSegoviaCordoba
    JavierSegoviaCordoba over 6 years
    it is working for me but I am getting a warning about I can get a null pointer exception. Is it safe to use?
  • Sam
    Sam over 6 years
    @Dahnark it's an internal API, so there's no guarantee it will work on a given device. The method in my example returns null so you can detect when it didn't work. You need to decide what to do when that happens and add code for it.
  • JavierSegoviaCordoba
    JavierSegoviaCordoba over 6 years
    @Sam I know, but is it possible to avoid this warning? really I am using if-else to the three possibilities (has nav, hasn't nav, null), but I am still getting the warning.
  • Sam
    Sam over 6 years
    @Dahnark Oh, I see. Don't know sorry.
  • SpaceBison
    SpaceBison about 6 years
    This will probably not work on the new Huawei P20 and other devices with a top notch
  • Nah
    Nah about 6 years
    How can we get bar height in PX or DP?
  • Raghu Mudem
    Raghu Mudem almost 6 years
    Hello @MuhammadHannan, you could use the following method to get the any resource size in pixel. resources.getDimensionPixelSize(id);
  • Nik
    Nik about 5 years
    Is there any way to get Notification bar is visible or not in Android P?
  • Serdar Samancıoğlu
    Serdar Samancıoğlu about 5 years
    This is not a correct answer! This solution only checks if device has physical navigation button, but there are also devices where both exists.
  • mypetlion
    mypetlion almost 5 years
    Please edit your answer to explain the code you've provided. Putting an explanation of the code directly in your answer will help future readers to understand what it does and how.
  • parmakli
    parmakli almost 5 years
    What is unclear in my answer? First part is checking HIDE_NAVIGATION ui visibility flag of activity window decorView and second is checking bottom inset of those decorView. Works from 23 API.
  • mypetlion
    mypetlion almost 5 years
    Nothing is particularly unclear, but it is generally encouraged to comment or explain code snippets on this site. OP made the question because they don't know how to solve the problem, which might mean that they have never seen some or any of the individual statements in your code (if they had seen it before, they probably could have solved the problem themselves). So there is value in going through and adding a comment for each chunk of your code. The explanation can go into the answer itself, not a comment, please.
  • Anh Duy
    Anh Duy over 4 years
    We can not use config_showNavigationBar or KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK) to detect navigation bar visible or not. Because this ways always returns true on some devices Huawei and Samsung such as A70. This is my solution: stackoverflow.com/questions/20264268/… . We can get real height of the navigation bar displaying on screen to detect it visible or not.
  • Anh Duy
    Anh Duy over 4 years
    I tested on Samsung A70 and some Huawei devices. This solution is incorrect, the method always returns true. My solution is base on the current height of navigation bar displaying on the screen to detect it's visible or not. stackoverflow.com/questions/20264268/…
  • Gerrit Humberg
    Gerrit Humberg over 3 years
    Great work! But you should adjust your code a little bit as this will only work for portrait mode, but the device might also be in landscape orientation.