Обнаруживать программную доступность панели навигации в устройстве Android программно?

Я пытаюсь определить мягкую панель навигации через программу android. Я не нашел прямой способ определить. Есть ли в любом случае найти доступность панели навигации.

Софт навигационной панели изображение здесь.

8 ответов

Решение

Следующий метод работал у меня и проверен на многих устройствах.

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

Примечание: проверено этот метод в реальном устройстве

Как я знаю, вы можете обнаружить это по

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

Но для этого нужны API 14+


Если вышеуказанное решение не работает для вас, попробуйте метод ниже

public boolean isNavigationBarAvailable(){

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

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

Это взломать, но он работает нормально. Попытайся.

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

Принятый ответ должен хорошо работать на большинстве реальных устройств, но он не работает в эмуляторах.

Однако в Android 4.0 и выше есть внутренний API, который также работает на эмуляторах: IWindowManager.hasNavigationBar (). Вы можете получить к нему доступ, используя отражение:

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

Попробуйте этот метод, таким образом вы можете определить, существует ли панель навигации.

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

}

Правильный ответ и прочее не актуальны сейчас.
Существуют некоторые опции, такие как "Полноэкранное отображение -> Полноэкранные жесты", где панель навигации скрыта, но все эти методы возвращают его присутствие.

Я предлагаю вам использовать этот способ для проверки размера системных представлений. В методе onCreate:

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

Другие ответы мне не помогают. Но очень полезно знать, отображается ли панель навигации, особенно после Android P/Q, где пользователь может смахивать ее с экрана. Я сталкивался с этой статьей https://blog.stylingandroid.com/gesture-navigation-window-insets/ и сделал такой метод

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
}

Смысл обнаружения включенной мягкой навигации заключается в том, чтобы определить размер предоставленного окна и установить макет в соответствии с ним. Есть очень мощный инструмент под названием decorViewкоторый устанавливает окно из предыдущего, чтобы напрямую реализовать методы под ним. Это можно написать так.

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

просто начните писать методы под ним, какие бы вы ни хотели сделать внутри фрейма. Нашел, что этот работает, попробовав массу методов и трюков, и это единственная надежда, что он поможет.

Другие вопросы по тегам