Android (AOSP)连接实体键盘关闭“使用屏幕键盘”调用键盘处依然显示屏幕键盘

发布于:2025-07-20 ⋅ 阅读:(15) ⋅ 点赞:(0)

首先感谢以下博文与作者提供方案与思路

Android P控制虚拟键盘的显示和隐藏_show ime with external keyboard-CSDN博客

现象是,使用蓝牙键盘。在设置-系统-键盘-实体键盘-使用屏幕键盘开关进行开与关,发现无论开关状态谷歌屏幕键盘都是存在的。BUG认为开关关上以后应该不显示谷歌屏幕键盘。

/home/bcr/Documents/lcx/111.png

思路:

修改了InputMethodManager.showSoftInput(View, int)方法,添加了以下逻辑:

  1. 检查是否连接了物理键盘
  2. 检查Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD设置
  3. 如果连接了物理键盘且设置为不显示虚拟键盘,则直接返回false,阻止虚拟键盘显示

这个修改直接针对问题的根源:在显示虚拟键盘的入口处进行拦截。由于showSoftInput()是所有应用调用虚拟键盘的共同路径,修改这个方法应该能够有效解决问题。

方案:

frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java

首先添加一个检测是否连接了物理键盘方法

    /**
     * 检测是否连接了物理键盘
     * 
     * @return 如果连接了物理键盘返回true,否则返回false
     */
    private boolean isHardKeyboardConnected(Context context) {
        // 方法1:通过Configuration检查
        // Configuration config = context.getResources().getConfiguration();
        // if (config.keyboard != Configuration.KEYBOARD_NOKEYS) {
        //     return true;
        // }
        
        // 方法2:通过InputManager检查(更可靠)
        InputManager inputManager = context.getSystemService(InputManager.class);
        if (inputManager != null) {
            int[] deviceIds = inputManager.getInputDeviceIds();
            for (int id : deviceIds) {
                InputDevice device = inputManager.getInputDevice(id);
                // 检查设备是否是物理键盘
                if (device != null && !device.isVirtual() && device.isFullKeyboard()) {
                    return true;
                }
            }
        }
        
        return false;
    }

修改showSoftInput(View view, @ShowFlags int flags)

    /**
     * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without
     * a result receiver: explicitly request that the current input method's
     * soft input area be shown to the user, if needed.
     *
     * @param view The currently focused view, which would like to receive soft keyboard input.
     *             Note that this view is only considered focused here if both it itself has
     *             {@link View#isFocused view focus}, and its containing window has
     *             {@link View#hasWindowFocus window focus}. Otherwise the call fails and
     *             returns {@code false}.
     */
    public boolean showSoftInput(View view, @ShowFlags int flags) {
        // 获取Context对象,通过view
        Context context = view.getContext();
        //linchengxian
        // 检查是否连接了物理键盘
        boolean hasHardKeyboard = isHardKeyboardConnected(context);
        
        // 检查是否设置为在物理键盘连接时显示虚拟键盘
        boolean showImeWithHardKeyboard = Settings.Secure.getInt(
                context.getContentResolver(),
                Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0;
        Log.d(TAG, "showSoftInput() hasHardKeyboard: " +hasHardKeyboard+
                        "showImeWithHardKeyboard: "+showImeWithHardKeyboard);
        // 如果连接了物理键盘且设置为不显示虚拟键盘,则直接返回false
        if (hasHardKeyboard && !showImeWithHardKeyboard) {
            if (DEBUG) {
                Log.d(TAG, "showSoftInput() blocked: physical keyboard connected and " +
                        "SHOW_IME_WITH_HARD_KEYBOARD is disabled");
            }
            return false;
        }
        
        // Re-dispatch if there is a context mismatch.
        final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
        if (fallbackImm != null) {
            return fallbackImm.showSoftInput(view, flags);
        }

        return showSoftInput(view, flags, null);
    }

最后导包(用方法二Configuration不需要):

import android.view.InputDevice;
import android.content.res.Configuration;
import android.hardware.input.InputManager;

部分解释:

showSoftInput方法有多个重载版本,形成了以下调用链:

  1. showSoftInput(View, int) - 最简单的公开接口
  2. showSoftInput(View, int, ResultReceiver) - 添加结果接收器
  3. showSoftInput(View, int, ResultReceiver, int) - 添加显示/隐藏原因
  4. showSoftInput(View, ImeTracker.Token, int, ResultReceiver, int) - 最终实现版本

可能的原因

  • InputMethodManager.showSoftInput()方法没有正确检查SHOW_IME_WITH_HARD_KEYBOARD设置
  • 或者没有正确检测物理键盘的连接状态
  • 或者特定输入法(如谷歌拼音)可能有自己的逻辑覆盖了系统设置

后续测试 发现以上方案只针对点击输入框的情况,如果用外接键盘输入后,键盘还会显示出来。初步推测和谷歌输入法有关:

使用屏幕键盘、实体键盘相关设置有两处:

一个是BUG中的设置-系统下,一个是键盘Gboard设置中

(最新版本Gboard,如果不去手动升级最新,Gboard并没有显示屏幕键盘功能,只要你使用了物理键盘会自动收回屏幕键盘)
而逻辑会先遵循键盘Gboard设置中的设置,例如:设置下我将使用屏幕键盘关闭,使用屏幕键盘打开。则会使用屏幕键盘
观察了谷歌机Pixel7,发现可能Google也知道这块的矛盾,在Pixel7中已经将设置-系统下的使用屏幕键盘开关去除