44

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

8 Answers 8

78

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

Sign up to request clarification or add additional context in comments.

8 Comments

This code works but instead of 'android' use '"android"'
Returns false in both cases.
Note that this always returns false on the Android emulators. See this commit message for an explanation.
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.
checked in one plus 3 enabling both its always returns false.
|
27

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));
    }

9 Comments

Thanks for your response. I am looking to determine soft navigation bar presence.
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
Thank you for such great information, because of this type of devices you can try my second solution (look updated answer)
Thanks man. Seems it will work for me. I tested on two available devices as expected.
Enjoy programming, if this answer help you , then accepting answer or upvote will be very appreciated :-)
|
17

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;
}

2 Comments

Agree that its a hack , but a great one. Kudos
This will probably not work on the new Huawei P20 and other devices with a top notch
11

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;
    }
}

6 Comments

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.
it is working for me but I am getting a warning about I can get a null pointer exception. Is it safe to use?
@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.
@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.
@Dahnark Oh, I see. Don't know sorry.
|
4

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;

}

1 Comment

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

Right answer and other are not actual now.
There are exist some options like 'Full Screen Display -> Full Screen Gestures' where navigation bar is hidden but all this methods returns that he is present.

I suggest you to use this way to check size of system views. In onCreate method:

ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content), 
  (v, insets) -> { 
      int navigationBarHeight = insets.getSystemWindowInsetBottom();
      return insets;
  });

Comments

1

Other answers don't help me. But it's quite useful to know if navigation bar is shown, especially after Android P/Q, where user can swipe it out of screen. I've encounter this article https://blog.stylingandroid.com/gesture-navigation-window-insets/ and made such method

fun hasNavBar(activity: Activity): Boolean {
    val temporaryHidden = activity.window.decorView.visibility and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION != 0
    if (temporaryHidden) return false
    val decorView = activity.window.decorView
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        decorView.rootWindowInsets?.let{
            return it.stableInsetBottom != 0
        }
    }
    return true
}

3 Comments

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

The point of finding the soft navigation enabled or not is to determine what is the size of the window provided and to set the layout according to.

There is a very powerful tool called decorView that sets the window from before so as to directly implement methods under it. It can be written like this:

val decorView = window.decorView
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE

Just start writing methods under it whichever you want to make inside the frame.

Found this one working after trying a ton of methods and tricks and this one is the only one working.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.