Как определить, видна ли программная клавиатура на устройстве Android? - PullRequest
202 голосов
/ 20 января 2011

Есть ли в Android способ определить, видна ли на экране программная ("мягкая") клавиатура?

Ответы [ 24 ]

2 голосов
/ 22 февраля 2014

Я сделал это, установив GlobalLayoutListener следующим образом:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightView = activityRootView.getHeight();
                int widthView = activityRootView.getWidth();
                if (1.0 * widthView / heightView > 3) {
                    //Make changes for Keyboard not visible
                } else {
                    //Make changes for keyboard visible
                }
            }
        });
2 голосов
/ 23 ноября 2018

Это должно работать, если вам нужно проверить состояние клавиатуры:

fun Activity.isKeyboardOpened(): Boolean {
    val r = Rect()

    val activityRoot = getActivityRoot()
    val visibleThreshold = dip(UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP)

    activityRoot.getWindowVisibleDisplayFrame(r)

    val heightDiff = activityRoot.rootView.height - r.height()

    return heightDiff > visibleThreshold;
}

fun Activity.getActivityRoot(): View {
    return (findViewById<ViewGroup>(android.R.id.content)).getChildAt(0);
}

Где UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP = 100 и dip () - это функция anko, которая преобразует dpToPx:

fun dip(value: Int): Int {
    return (value * Resources.getSystem().displayMetrics.density).toInt()
}
2 голосов
/ 30 сентября 2015

В моем случае у меня был только один EditText для управления в моем макете, поэтому я нашел это решение.Это работает хорошо, в основном это пользовательский EditText, который прослушивает фокус и отправляет локальную трансляцию, если фокус меняется или если нажата кнопка назад / сделано.Чтобы работать, вам нужно поместить в макет манекен View с android:focusable="true" и android:focusableInTouchMode="true", потому что при вызове clearFocus() фокус будет переназначен на первый фокусируемый вид.Пример фиктивного представления:

<View
android:layout_width="1dp"
android:layout_height="1dp"
android:focusable="true"
android:focusableInTouchMode="true"/>

Дополнительная информация

Решение, которое обнаруживает разницу в изменениях макета, работает не очень хорошо, поскольку сильно зависит от плотности экрана, поскольку 100px может быть много на одном устройстве, а на других - ничего, вы можете получить ложные срабатывания.Также разные производители имеют разные клавиатуры.

2 голосов
/ 04 сентября 2018

Так что после долгого времени игры с AccessibilityServices, вставками окон, определением высоты экрана и т. Д., Я думаю, я нашел способ сделать это.

Отказ от ответственности: он использует скрытый метод в Android, что означает, что он может быть непоследовательным. Тем не менее, в моем тестировании, похоже, работает.

Метод: InputMethodManager # getInputMethodWindowVisibleHeight () , и существует с Lollipop (5.0).

Вызов, который возвращает высоту в пикселях текущей клавиатуры. Теоретически клавиатура не должна быть высотой 0 пикселей, поэтому я сделал простую проверку высоты (в Kotlin):

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
if (imm.inputMethodWindowVisibleHeight > 0) {
    //keyboard is shown
else {
    //keyboard is hidden
}

Я использую Android Hidden API , чтобы избежать размышлений, когда я вызываю скрытые методы (я делаю это много для приложений, которые я разрабатываю, в основном это приложения для хакерских приложений / настройки), но это должно быть возможно с помощью отражения а также:

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
val windowHeightMethod = InputMethodManager::class.java.getMethod("getInputMethodWindowVisibleHeight")
val height = windowHeightMethod.invoke(imm) as Int
//use the height val in your logic
1 голос
/ 03 августа 2015

В Android вы можете обнаружить через оболочку ADB.Я написал и использую этот метод:

{
        JSch jsch = new JSch();
        try {
            Session session = jsch.getSession("<userName>", "<IP>", 22);
            session.setPassword("<Password>");
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();

            ChannelExec channel = (ChannelExec)session.openChannel("exec");
            BufferedReader in = new BufferedReader(new    
            InputStreamReader(channel.getInputStream()));
            channel.setCommand("C:/Android/android-sdk/platform-tools/adb shell dumpsys window 
            InputMethod | findstr \"mHasSurface\"");
            channel.connect();

            String msg = null;
            String msg2 = " mHasSurface=true";

            while ((msg = in.readLine()) != null) {
                Boolean isContain = msg.contains(msg2);
                log.info(isContain);
                if (isContain){
                    log.info("Hiding keyboard...");
                    driver.hideKeyboard();
                }
                else {
                    log.info("No need to hide keyboard.");
                }
            }

            channel.disconnect();
            session.disconnect();

        } catch (JSchException | IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
1 голос
/ 19 августа 2017

Ответ @iWantScala отличный, но у меня не работает
rootView.getRootView().getHeight() всегда имеет одинаковое значение

Один из способов - определить две переменные

private int maxRootViewHeight = 0;
private int currentRootViewHeight = 0;

добавить глобальный слушатель

rootView.getViewTreeObserver()
    .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            currentRootViewHeight = rootView.getHeight();
            if (currentRootViewHeight > maxRootViewHeight) {
                maxRootViewHeight = currentRootViewHeight;
            }
        }
    });

, затем проверьте

if (currentRootViewHeight >= maxRootViewHeight) {
    // Keyboard is hidden
} else {
    // Keyboard is shown
}

отлично работает

1 голос
/ 27 мая 2016
final View activityRootView = findViewById(R.id.rootlayout);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {

            Rect r = new Rect();
            activityRootView.getWindowVisibleDisplayFrame(r);

            int screenHeight = activityRootView.getRootView().getHeight();
            Log.e("screenHeight", String.valueOf(screenHeight));
            int heightDiff = screenHeight - (r.bottom - r.top);
            Log.e("heightDiff", String.valueOf(heightDiff));
            boolean visible = heightDiff > screenHeight / 3;
            Log.e("visible", String.valueOf(visible));
            if (visible) {
                Toast.makeText(LabRegister.this, "I am here 1", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(LabRegister.this, "I am here 2", Toast.LENGTH_SHORT).show();
            }
        }
});
0 голосов
/ 19 декабря 2014

Существует прямой способ выяснить это.Кроме того, он не требует изменений макета.
Так что он работает и в полноэкранном режиме с погружением.
Но, к сожалению, он работает не на всех устройствах.Поэтому вы должны протестировать его на своем устройстве (ах).

Хитрость заключается в том, что вы пытаетесь скрыть или показать экранную клавиатуру и зафиксировать результат этой попытки.
Если все работает правильно, то клавиатурана самом деле не показано или скрыто.Мы просто запрашиваем состояние.

Чтобы оставаться в курсе, вы просто повторяете эту операцию, например, каждые 200 миллисекунд, используя обработчик.

Приведенная ниже реализация выполняет только одну проверку.
Если вы делаете несколько проверок, вам следует включить все (_keyboardVisible) тесты.

public interface OnKeyboardShowHide
{
    void    onShowKeyboard( Object param );
    void    onHideKeyboard( Object param );
}

private static Handler      _keyboardHandler    = new Handler();
private boolean             _keyboardVisible    = false;
private OnKeyboardShowHide  _keyboardCallback;
private Object              _keyboardCallbackParam;

public void start( OnKeyboardShowHide callback, Object callbackParam )
{
    _keyboardCallback      = callback;
    _keyboardCallbackParam = callbackParam;
    //
    View view = getCurrentFocus();
    if (view != null)
    {
        InputMethodManager imm = (InputMethodManager) getSystemService( Activity.INPUT_METHOD_SERVICE );
        imm.hideSoftInputFromWindow( view.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY, _keyboardResultReceiver );
        imm.showSoftInput( view, InputMethodManager.SHOW_IMPLICIT, _keyboardResultReceiver );
    }
    else // if (_keyboardVisible)
    {
        _keyboardVisible = false;
        _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
    }
}

private ResultReceiver      _keyboardResultReceiver = new ResultReceiver( _keyboardHandler )
{
    @Override
    protected void onReceiveResult( int resultCode, Bundle resultData )
    {
        switch (resultCode)
        {
            case InputMethodManager.RESULT_SHOWN :
            case InputMethodManager.RESULT_UNCHANGED_SHOWN :
                // if (!_keyboardVisible)
                {
                    _keyboardVisible = true;
                    _keyboardCallback.onShowKeyboard( _keyboardCallbackParam );
                }
                break;
            case InputMethodManager.RESULT_HIDDEN :
            case InputMethodManager.RESULT_UNCHANGED_HIDDEN :
                // if (_keyboardVisible)
                {
                    _keyboardVisible = false;
                    _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
                }
                break;
        }
    }
};
0 голосов
/ 03 июня 2016

a может использовать:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    Log.d(
    getClass().getSimpleName(), 
    String.format("conf: %s", newConfig));

    if (newConfig.hardKeyboardHidden != hardKeyboardHidden) {
        onHardwareKeyboardChange(newConfig.hardKeyboardHidden);

        hardKeyboardHidden = newConfig.hardKeyboardHidden;
    }

    if (newConfig.keyboardHidden != keyboardHidden) {
        onKeyboardChange(newConfig.keyboardHidden);

        keyboardHidden = newConfig.hardKeyboardHidden;
    }

}

public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
public static final int KEYBOARDHIDDEN_NO = 1;
public static final int KEYBOARDHIDDEN_YES = 2;
public static final int KEYBOARDHIDDEN_SOFT = 3;

//todo
private void onKeyboardChange(int keyboardHidden) {

}

//todo
private void onHardwareKeyboardChange(int hardKeyboardHidden) {

}
0 голосов
/ 01 июня 2016

Вот обходной путь, чтобы узнать, видна ли программная клавиша.

  1. Проверка запуска служб в системе с помощью ActivityManager.getRunningServices (max_count_of_services);
  2. Из возвращенного ActivityManager.RunningServiceInfoэкземпляры, проверьте значение clientCount для службы программной клавиатуры.
  3. Вышеупомянутый clientCount будет увеличиваться каждый раз, когда отображается программная клавиатура.Например, если clientCount изначально был равен 1, то при отображении клавиатуры было бы 2.
  4. При отклонении клавиатуры значение clientCount уменьшается.В этом случае он сбрасывается до 1.

У некоторых популярных клавиатур есть определенные ключевые слова в их именах классов:

  1. Google AOSP = IME
  2. Swype= IME
  3. Swiftkey = KeyboardService
  4. Fleksy = клавиатура
  5. Adaptxt = IME (KPTAdaptxtIME)
  6. Smart = Клавиатура (SmartKeyboard)

В ActivityManager.RunningServiceInfo проверьте наличие вышеуказанных шаблонов в ClassNames.Кроме того, ActivityManager.RunningServiceInfo's clientPackage = android, указывающий, что клавиатура привязана к системе.

Вышеупомянутая информация может быть объединена для строгого способа выяснить, видна ли программная клавиатура.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...