14

How can I tell whether an android device has physical keys or the software navigation bar? I need to change the layout dependant on whether the software navigation is drawn.

For example the HTC Desire C has hardware keys: enter image description here

I should clarify - Im looking at the navigation bar, not the keyboard. Home, back etc. I've tried:

        getResources().getConfiguration().keyboard);
        getResources().getConfiguration().navigation);
        getResources().getConfiguration().navigationHidden);

return the same values on both devices.

serenskye
  • 3,297
  • 4
  • 30
  • 49

4 Answers4

54

Solved by doing this the first time the app is launched and saving to preferences:

public static boolean hasSoftKeys(WindowManager windowManager){
    boolean hasSoftwareKeys = true;
    //c = context; use getContext(); in fragments, and in activities you can 
    //directly access the windowManager();

    if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN_MR1){
        Display d = c.getWindowManager().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;

        hasSoftwareKeys =  (realWidth - displayWidth) > 0 ||
                           (realHeight - displayHeight) > 0;
    } else {
        boolean hasMenuKey = ViewConfiguration.get(c).hasPermanentMenuKey();
        boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
        hasSoftwareKeys = !hasMenuKey && !hasBackKey;
    }
    return hasSoftwareKeys;
}
ZooMagic
  • 497
  • 6
  • 12
serenskye
  • 3,297
  • 4
  • 30
  • 49
  • 1
    The method `getRealMetrics` is only available in API 17 (i.e. the Android 4.2) - You're implying that you don't know the device, so you can't really rely on this method being there. – Rich S Jul 09 '13 at 18:14
  • I agree this method because `ViewConfiguration.get(context).hasPermanentMenuKey()` is tricky on some devices. So when API >= 17, I use this method instead. – AlexAndro Dec 18 '13 at 10:26
  • 3
    I, too, am now using this technique on devices >= API 17. Not to be too nit-picky, but your return statement might be a little more readable as: `return (realWidth > displayWidth) || (realHeight > displayHeight)` – benjamin davis Jun 18 '14 at 15:07
  • One note: if you do this from a service, and the service accidentally starts while the device is in full screen (i.e Youtube etc..), you'll get the wrong result. – Vlad Jan 04 '16 at 10:49
  • @benjamindavis you shouldn't nit on SO answers, it will stop ppl answering if they feel their code has to be perfect before posting. – serenskye Sep 13 '16 at 12:00
  • Tried many solutions of SO, this one worked seamless for me. Thank you. – Jay Donga Sep 28 '16 at 14:25
  • Why do you save it to preferences? Is it too expensive operation? – Tony May 08 '17 at 15:22
2

Here you go.. this should do what you want.

@SuppressLint("NewApi")
private static boolean hasSoftNavigation(Context context)
{
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH){
        return !ViewConfiguration.get(context).hasPermanentMenuKey();
    }
    return false;
}
Simon
  • 9,933
  • 44
  • 46
  • 4
    The new galaxy s5 doen't have a menu hardqare key and it still uses hard keys as home, recent and back... This is not a good options to use. – roiberg Jul 28 '14 at 12:58
0

private boolean isHardwareKeyboardAvailable() { return getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS; }

In addition, here is more info. http://developer.android.com/reference/android/content/res/Configuration.html#keyboard

EDIT - To check for physical keyboard

private boolean isPhysicalKeyboardAvailable() { return getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY; }

For more information on the different Configurations view http://developer.android.com/reference/android/content/res/Configuration.html#keyboard

I am sure one of those works.

2nd EDIT -

Check. Already asked.

Android: Programmatically detect if device has hardware menu button

Community
  • 1
  • 1
Synaero
  • 469
  • 5
  • 12
  • Nope, see above, I get the same keyboard for both devices! Configuration.KEYBOARD_NOKEYS; – serenskye Feb 13 '13 at 13:30
  • 2
    See the post, I said im not interested in the menu button, modern devices with hard buttons do not have the menu button – serenskye Feb 14 '13 at 08:46
  • I'd love to upvote this, especially since it solves my problem (determining if a hardware QWERTY keyboard is available), but I think the OP was asking for something different... – user149408 Nov 15 '15 at 21:07
0

Solution based on @serenskye

private fun Activity.hasSoftKeys(): Boolean {
    val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        display
    } else {
        windowManager.defaultDisplay
    } ?: return true

    val realDisplayMetrics = DisplayMetrics()
    display.getRealMetrics(realDisplayMetrics)

    val realHeight = realDisplayMetrics.heightPixels
    val realWidth = realDisplayMetrics.widthPixels

    val displayMetrics = DisplayMetrics()
    display.getMetrics(displayMetrics)

    val displayHeight = displayMetrics.heightPixels
    val displayWidth = displayMetrics.widthPixels

    return realWidth - displayWidth > 0 || realHeight - displayHeight > 0
}
ThinkDeep
  • 188
  • 1
  • 15