Android源碼開發筆記 軟鍵盤與內建物理鍵盤共存以及外接藍芽鍵盤不共存邏輯

來源:互聯網
上載者:User

標籤:系統   enc   中斷連線   on()   3.2   connect   dcl   board   strong   

需求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

 

需求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:

[email protected]:~$ adb logcat |grep Profile12-22 03:55:00.524  1257  1257 I SystemServer: SamplingProfiler Service12-22 04:29:41.923  3916  4051 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 012-22 06:25:59.666  7284  7284 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 212-22 06:25:59.668  3916  4051 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 212-22 06:26:33.245  7284  7284 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 012-22 06:26:33.245  3916  4051 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 012-22 06:26:45.586  7284  7284 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 212-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");            }                    }        ...    }

測試,驗證通過!

Android源碼開發筆記 軟鍵盤與內建物理鍵盤共存以及外接藍芽鍵盤不共存邏輯

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.