zoukankan      html  css  js  c++  java
  • Android源码开发笔记 软键盘与内置物理键盘共存以及外接蓝牙键盘不共存逻辑

    需求1: android设备自带九键的小键盘,此时小键盘被识别为HW Keyboard,默认与软键盘不能共存,需要使软键盘与物理键盘共存。

    实现:

    在网上找的别人总结的Android5.1的解决方法,需要解决的codebase为Android6.0,都可以用。

    方法一:(此方法在Android8.0 codebase已不可用) frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java中,如果把updateShowImeWithHardKeyboard()方法中的showImeWithHardKeyboard变量直接置为true,则可以实现软键盘与物理键盘的同时使用。(原本为读取Setting数据库字段来判断,所以也可以直接修改Setting字段来实现)

        public void updateShowImeWithHardKeyboard() {
            synchronized (mWindowMap) {
                final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(
                            mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0,
                            mCurrentUserId) == 1;if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) {
                    mShowImeWithHardKeyboard = showImeWithHardKeyboard;
                    mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
                }
            }
        }

    方法二:frameworks/base/core/java/android/inputmethodservice/InputMethodService.java,修改onEvaluateInputViewShown()方法直接返回true

    public boolean onEvaluateInputViewShown() {
        Configuration config = getResources().getConfiguration();
        //return config.keyboard == Configuration.KEYBOARD_NOKEYS
        //      || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
        return  true;
    }

    方法三:在外部需要修改的合适位置,直接将Setting字段修改掉,随时可以改回来,一劳永逸。

    Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1);// 1: Disabled,0: Enabled

     默认共存的话,其实最好的是修改frameworks/base/packages/SettingsProvider/res/values/default.xml

    <!-- Default for Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD -->
    <bool name="def_show_ime_with_hard_keyboard">false</bool>

    需求2:软键盘与内置物理键盘共存基础上,再外接蓝牙键盘。此时外接蓝牙键盘与软键盘不可共存。

    分析:此时外接键盘也被视为物理键盘,按照上面需求1的方法修改后,使蓝牙键盘与软键盘是共存的,所以不符合需求。需要找到蓝牙键盘连接上的位置,来把前面需求1改的地方取消掉。

    即:未连接蓝牙键盘时,将Setting字段改为共存模式,使软键盘与内置物理键盘共存;连接蓝牙键盘后,将Setting字段改为不共存模式,使软键盘与蓝牙键盘不共存(此时蓝牙键盘与内置物理键盘是共存的)。

    实现:本需求的难点为找到恰当的位置来修改Setting字段,此恰当位置为:蓝牙键盘连接成功或断开,以及蓝牙关闭。

    实现分析流程:

    1. 通过Settings中Bluetooth Settings部分可以看到,连接蓝牙键盘时,蓝牙设备的类型已经可以通过图标区分出来。这样就不用怀疑是否能够区分蓝牙键盘和其他蓝牙设备了。

    在packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDevicePreference.java中根据icon可以看到,不同种类的BT device已经可以区分了。

    private int getBtClassDrawable() {
            BluetoothClass btClass = mCachedDevice.getBtClass();
            if (btClass != null) {
                switch (btClass.getMajorDeviceClass()) {
                    case BluetoothClass.Device.Major.COMPUTER:
                        return R.drawable.ic_bt_laptop;
    
                    case BluetoothClass.Device.Major.PHONE:
                        return R.drawable.ic_bt_cellphone;
    
                    case BluetoothClass.Device.Major.PERIPHERAL:
                        return HidProfile.getHidClassDrawable(btClass);
    
                    case BluetoothClass.Device.Major.IMAGING:
                        return R.drawable.ic_bt_imaging;
    
                    default:
                        // unrecognized device class; continue
                }
            } else {
                Log.w(TAG, "mBtClass is null");
            }
    ...

    需要的蓝牙键盘在 HidProfile.getHidClassDrawable(btClass)获得。

    frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java

    public static int getHidClassDrawable(BluetoothClass btClass) {
            switch (btClass.getDeviceClass()) {
                case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
                case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
                    return R.drawable.ic_lockscreen_ime;
                case BluetoothClass.Device.PERIPHERAL_POINTING:
                    return R.drawable.ic_bt_pointing_hid;
                default:
                    return R.drawable.ic_bt_misc_hid;
            }
        }

     2. 通过抓系统蓝牙profile log来确认断开连接蓝牙键盘时,会在framework里面的Bluetooth的哪边被trigger到。

    adb logcat |grep Profile

    在连接/断开蓝牙键盘时,可以抓到下面的log:

    kunkka@kunkka-Lenovo:~$ adb logcat |grep Profile
    12-22 03:55:00.524  1257  1257 I SystemServer: SamplingProfiler Service
    12-22 04:29:41.923  3916  4051 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 0
    12-22 06:25:59.666  7284  7284 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 2
    12-22 06:25:59.668  3916  4051 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 2
    12-22 06:26:33.245  7284  7284 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 0
    12-22 06:26:33.245  3916  4051 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 0
    12-22 06:26:45.586  7284  7284 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 2
    12-22 06:26:45.587  3916  4051 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 2
    ...

    可以定位到frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java

    在onProfileStateChanged方法中可以看到,蓝牙连接和断开时都可以走到!而且去获得蓝牙设备类型的context也都有!这样问题解决一大半!

    在onProfileStateChanged方法中添加蓝牙连接和断开时的设备类型判断:

                if(mBtClass.getMajorDeviceClass() == BluetoothClass.Device.Major.PERIPHERAL
                        && (mBtClass.getDeviceClass() == BluetoothClass.Device.PERIPHERAL_KEYBOARD
                        || mBtClass.getDeviceClass() == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING)) {
                    Log.i("Kunkka0", "getMajorDeviceClass = Peripheral & getDeviceClass = KeyBoard");
                    if(newProfileState == 0) {// Disconnected
                        Log.i("Kunkka0","SET SHOW_IME_WITH_HARD_KEYBOARD TO 1");
                        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1);
                    }else {
                        Log.i("Kunkka0","SET SHOW_IME_WITH_HARD_KEYBOARD TO 0");
                        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0);
                    }
                }else {
                    Log.i("Kunkka0","getMajorDeviceClass() = "+mBtClass.getMajorDeviceClass()+", getDeviceClass = "+mBtClass.getDeviceClass());
                    Log.i("Kunkka0","PERIPHERAL = 1280, PERIPHERAL_KEYBOARD = 1344, PERIPHERAL_KEYBOARD_POINTING = 1472");
                }

    加完编译出image来测试,功能实现!

    但是,在关闭蓝牙时,蓝牙键盘就不能用了,但是此处不能收到状态变化!此时,关闭蓝牙,软键盘和蓝牙键盘都不能用了!

    3. 为了解决关闭蓝牙时的问题,再去搜索蓝牙开关状态变化的事件:

    在frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java中可以看到有:

        void onBluetoothStateChanged(int bluetoothState);
        void onScanningStateChanged(boolean started);
        void onDeviceAdded(CachedBluetoothDevice cachedDevice);
        void onDeviceDeleted(CachedBluetoothDevice cachedDevice);
        void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState);
        void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state);

    查看所有重载此事件的class,Open implementation-可以看到:

    下面几个都是Settings中的,但我们的需求不止在Settings中,所以看上面KeyboardUI和systemui下面的statusbar。

    StatusBar下面的BluetoothControllerImpl比较符合。

    打开frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java

    除了onBluetoothStateChanged外还有个updateConnected()方法,居然也可以侦测蓝牙设备连接状态!

    所以我们只需要在onBluetoothStateChanged()和updateConnected()中都加入事件侦测来修改Settings字段就可以了!

    4. 最终解决办法:

    a. 在onBluetoothStateChanged()中,当蓝牙关闭时,使键盘共存,保证软键盘和内置物理键盘的共存。

        @Override
        public void onBluetoothStateChanged(int bluetoothState) {
            mEnabled = bluetoothState == BluetoothAdapter.STATE_ON;
        
            if(!mEnabled) {
                Log.i("Kunkka0","onBluetoothStateChanged: SET SHOW_IME_WITH_HARD_KEYBOARD TO 1");
                Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1);
            }
    
            mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
        }

    b. 在updateConnected()中,当蓝牙键盘连接时,使软硬键盘不共存,蓝牙键盘断开时,使软硬件盘共存。

    private void updateConnected() {
            ...
            for (CachedBluetoothDevice device : getDevices()) {
                if (device.isConnected()) {
                    mLastDevice = device;
                }
    
                if(device.getBtClass().getMajorDeviceClass() == BluetoothClass.Device.Major.PERIPHERAL
                        && (device.getBtClass().getDeviceClass() == BluetoothClass.Device.PERIPHERAL_KEYBOARD
                        || device.getBtClass().getDeviceClass() == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING)) {
                    Log.i("Kunkka0", "getMajorDeviceClass = Peripheral & getDeviceClass = KeyBoard");
                    if(!device.isConnected()) {// Disconnected
                        Log.i("Kunkka0","SET SHOW_IME_WITH_HARD_KEYBOARD TO 1");
                        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1);
                    }else {
                        Log.i("Kunkka0","SET SHOW_IME_WITH_HARD_KEYBOARD TO 0");
                        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0);
                    }
                }else {
                    Log.i("Kunkka0","getMajorDeviceClass() = "+device.getBtClass().getMajorDeviceClass()+", getDeviceClass = "+device.getBtClass().getDeviceClass());
                    Log.i("Kunkka0","PERIPHERAL = 1280, PERIPHERAL_KEYBOARD = 1344, PERIPHERAL_KEYBOARD_POINTING = 1472");
                }
                
            }
            ...
        }

    测试,验证通过!

  • 相关阅读:
    Acdream 1174 Sum 暴力
    Acdream 1114 Number theory 莫比乌斯反演
    Acdream 1007 快速幂,模乘法
    UVa 10023
    UVa 11027
    UVa 11029
    UVa 10820
    UVa 10791
    UVa 11121
    UVa 106
  • 原文地址:https://www.cnblogs.com/kunkka/p/8081428.html
Copyright © 2011-2022 走看看