解决Android 5.1物理键盘与软键盘的同时使用

在android 5.1系统中插入扫码枪物理设备后,软键盘无法弹出的问题。

1. 
在代码frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java中,如果把updateShowImeWithHardKeyboard()方法中的showImeWithHardKeyboard变量直接置为true,则可以实现软键盘与物理键盘的同时使用,但这样修改影响较大(哪些影响?),不推荐。

public void updateShowImeWithHardKeyboard() {
    //final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(
    //mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0,
    //mCurrentUserId) == 1;
    final  boolean  showImeWithHardKeyboard  =  true;
    synchronized (mWindowMap) {
    if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) {
        mShowImeWithHardKeyboard = showImeWithHardKeyboard;
        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
        }   
   }
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12


在代码frameworks/base/core/java/android/inputmethodservice/InputMethodService.java类的第1143行,修改onEvaluateInputViewShown()方法直接返回true

public boolean onEvaluateInputViewShown() {
    Configuration config = getResources().getConfiguration();
    //return config.keyboard == Configuration.KEYBOARD_NOKEYS
    //      || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
    return  true;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

以上两种方法物理键盘和软键盘都能同时使用。


物理键盘映射过程:
手机/system/usr/keylayout/*.kl :内核将keyCode映射成有含义的字符串
KeycodeLabels.h : framework 将字符串映射成keyEvent的keyCode
frameworks/.../res/values/attrs.xml


frameworks/base/services/java/com/android/server/wm/WindowManagerService.java

关键代码:行6618 computeScreenConfigurationLocked()方法中

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;  
  2.             if (hardKeyboardAvailable != mHardKeyboardAvailable) {  
  3.                 mHardKeyboardAvailable = hardKeyboardAvailable;  
  4.                 mHardKeyboardEnabled = !hardKeyboardAvailable;  
  5.                 mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);  
  6.                 mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);  
  7.             }  
  8.             if (!mHardKeyboardEnabled) {  
  9.                 config.keyboard = Configuration.KEYBOARD_NOKEYS;  
  10.             }  
将mHardKeyboardEnabled直接改成false

这样改软键盘是能用但是物理键盘是用不了的


最后研究代码frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java

如果把updateShowImeWithHardKeyboard方法中的showImeWithHardKeyboard变量直接置为true,则可以实现软键盘与物理键盘的同时使用,

但此举修改影响范围很大,不推荐。

    public void updateShowImeWithHardKeyboard() {
        //modified by Janning for enble the HardKeyboard start
        final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(
                mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0,
                mCurrentUserId) == 1;
        //final boolean showImeWithHardKeyboard = true;
        //modified by Janning for enble the HardKeyboard end
        synchronized (mWindowMap) {
            if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) {
                mShowImeWithHardKeyboard = showImeWithHardKeyboard;
                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
            }
        }
    }

后续继续研究代码发现在WindowManagerService.java的computeScreenConfigurationLocked方法中有通过判断当前物理键盘类型来控制是否同时启用软件盘的处理逻辑:

[java]  view plain  copy
  1. boolean computeScreenConfigurationLocked(Configuration config) {  
  2.         if (!mDisplayReady) {  
  3.             return false;  
  4.         }  
  5.   
  6.         // TODO(multidisplay): For now, apply Configuration to main screen only.  
  7.         final DisplayContent displayContent = getDefaultDisplayContentLocked();  
  8.   
  9.         // Use the effective "visual" dimensions based on current rotation  
  10.         final boolean rotated = (mRotation == Surface.ROTATION_90  
  11.                 || mRotation == Surface.ROTATION_270);  
  12.         final int realdw = rotated ?  
  13.                 displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;  
  14.         final int realdh = rotated ?  
  15.                 displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;  
  16.         int dw = realdw;  
  17.         int dh = realdh;  
  18.   
  19.         if (mAltOrientation) {  
  20.             if (realdw > realdh) {  
  21.                 // Turn landscape into portrait.  
  22.                 int maxw = (int)(realdh/1.3f);  
  23.                 if (maxw < realdw) {  
  24.                     dw = maxw;  
  25.                 }  
  26.             } else {  
  27.                 // Turn portrait into landscape.  
  28.                 int maxh = (int)(realdw/1.3f);  
  29.                 if (maxh < realdh) {  
  30.                     dh = maxh;  
  31.                 }  
  32.             }  
  33.         }  
  34.   
  35.         if (config != null) {  
  36.             config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :  
  37.                     Configuration.ORIENTATION_LANDSCAPE;  
  38.         }  
  39.   
  40.         // Update application display metrics.  
  41.         final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);  
  42.         final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);  
  43.         final DisplayInfo displayInfo = displayContent.getDisplayInfo();  
  44.         synchronized(displayContent.mDisplaySizeLock) {  
  45.             displayInfo.rotation = mRotation;  
  46.             displayInfo.logicalWidth = dw;  
  47.             displayInfo.logicalHeight = dh;  
  48.             displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;  
  49.             displayInfo.appWidth = appWidth;  
  50.             displayInfo.appHeight = appHeight;  
  51.             displayInfo.getLogicalMetrics(mRealDisplayMetrics,  
  52.                     CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);  
  53.             displayInfo.getAppMetrics(mDisplayMetrics);  
  54.             mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(  
  55.                     displayContent.getDisplayId(), displayInfo);  
  56.         }  
  57.         if (false) {  
  58.             Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);  
  59.         }  
  60.   
  61.         final DisplayMetrics dm = mDisplayMetrics;  
  62.         mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,  
  63.                 mCompatDisplayMetrics);  
  64.   
  65.         if (config != null) {  
  66.             config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)  
  67.                     / dm.density);  
  68.             config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)  
  69.                     / dm.density);  
  70.             computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);  
  71.   
  72.             config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);  
  73.             config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);  
  74.             config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);  
  75.             config.densityDpi = displayContent.mBaseDisplayDensity;  
  76.   
  77.             // Update the configuration based on available input devices, lid switch,  
  78.             // and platform configuration.  
  79.             config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;  
  80.             config.keyboard = Configuration.KEYBOARD_NOKEYS;  
  81.             config.navigation = Configuration.NAVIGATION_NONAV;  
  82.   
  83.             int keyboardPresence = 0;  
  84.             int navigationPresence = 0;  
  85.             final InputDevice[] devices = mInputManager.getInputDevices();  
  86.             final int len = devices.length;  
  87.             for (int i = 0; i < len; i++) {  
  88.                 InputDevice device = devices[i];  
  89.                 if (!device.isVirtual()) {  
  90.                     final int sources = device.getSources();  
  91.                     final int presenceFlag = device.isExternal() ?  
  92.                             WindowManagerPolicy.PRESENCE_EXTERNAL :  
  93.                                     WindowManagerPolicy.PRESENCE_INTERNAL;  
  94.   
  95.                     if (mIsTouchDevice) {  
  96.                         if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==  
  97.                                 InputDevice.SOURCE_TOUCHSCREEN) {  
  98.                             config.touchscreen = Configuration.TOUCHSCREEN_FINGER;  
  99.                         }  
  100.                     } else {  
  101.                         config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;  
  102.                     }  
  103.   
  104.                     if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {  
  105.                         config.navigation = Configuration.NAVIGATION_TRACKBALL;  
  106.                         navigationPresence |= presenceFlag;  
  107.                     } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD  
  108.                             && config.navigation == Configuration.NAVIGATION_NONAV) {  
  109.                         config.navigation = Configuration.NAVIGATION_DPAD;  
  110.                         navigationPresence |= presenceFlag;  
  111.                     }  
  112.                     // 判断该物理设备的类型, InputDevice.KEYBOARD_TYPE_ALPHABETIC 是表示物理键盘设备  
  113.                     if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {  
  114.                         config.keyboard = Configuration.KEYBOARD_QWERTY;  
  115.                         keyboardPresence |= presenceFlag;  
  116.                     }  
  117.                     // 获取物理设备名称,判断是否是指定的名称,如果是则把 config.keyboard  
  118.                     // 的属性置为 Configuration.KEYBOARD_NOKEYS ,如此则可以同时兼容软键盘  
  119.                     // 物理键盘与软键盘可以同时启用  
  120.                     // Add by Janning start  
  121.                     // for show IME with HardKeyboard  
  122.                     if (device.getName().equals("XXX-vinput-keypad")) {  
  123.                         Slog.w("SLCODE""the hard device name is: " + device.getName());  
  124.                         config.keyboard = Configuration.KEYBOARD_NOKEYS;  
  125.                     }  
  126.                     // Add by Janning end  
  127.                 }  
  128.             }  
  129.   
  130.             if (config.navigation == Configuration.NAVIGATION_NONAV && mHasPermanentDpad) {  
  131.                 config.navigation = Configuration.NAVIGATION_DPAD;  
  132.                 navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;  
  133.             }  
  134.   
  135.             // Determine whether a hard keyboard is available and enabled.  
  136.             boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;  
  137.             if (hardKeyboardAvailable != mHardKeyboardAvailable) {  
  138.                 mHardKeyboardAvailable = hardKeyboardAvailable;  
  139.                 mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);  
  140.                 mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);  
  141.             }  
  142.             if (mShowImeWithHardKeyboard) {  
  143.                 config.keyboard = Configuration.KEYBOARD_NOKEYS;  
  144.             }  
  145.   
  146.             // Let the policy update hidden states.  
  147.             config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;  
  148.             config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;  
  149.             config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;  
  150.             mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);  
  151.         }  
  152.   
  153.         return true;  
  154.     }  
  155.   
  156.     public boolean isHardKeyboardAvailable() {  
  157.         synchronized (mWindowMap) {  
  158.             return mHardKeyboardAvailable;  
  159.         }  
  160.     }  
  161.   
  162.     public void updateShowImeWithHardKeyboard() {  
  163.         // 此处修改也可以实现物理键盘与软键盘的同时启用,即把showImeWithHardKeyboard 直接置为 true,  
  164.         // 但此方法影响太大,不推荐该方案,建议根据设备名称判断 修改config.keyboard 属性值(代码见上文)  
  165.         //changed by Janning start  
  166.         //modified by Janning for enble the HardKeyboard start  
  167.         final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(  
  168.                 mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0,  
  169.                 mCurrentUserId) == 1;  
  170.         //final boolean showImeWithHardKeyboard = true;  
  171.         //modified by Janning for enble the HardKeyboard end  
  172.         //changed by Janning end  
  173.         synchronized (mWindowMap) {  
  174.             if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) {  
  175.                 mShowImeWithHardKeyboard = showImeWithHardKeyboard;  
  176.                 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);  
  177.             }  
  178.         }  
  179.     }  


经过测试以上修改可以实现物理键盘与软键盘的同时启用,完美解决问题。


二、插入物理键盘后通知栏不想弹出键盘布局通知的问题修改

当插入物理键盘后通知栏会弹出相应的选择键盘布局通知,对于该通知可以选择隐藏:
根据字符串查找到是在 frameworks\base\services\core\java\com\android\server\input\InputManagerService.java 中调用显示该通知的,
进一步分析代码发现是在 deliverInputDevicesChanged 方法中控制通知的显示。
[java]  view plain  copy
  1. // Must be called on handler.  
  2. private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {  
  3.     // Scan for changes.  
  4.     int numFullKeyboardsAdded = 0;  
  5.     mTempInputDevicesChangedListenersToNotify.clear();  
  6.     mTempFullKeyboards.clear();  
  7.     final int numListeners;  
  8.     final int[] deviceIdAndGeneration;  
  9.     synchronized (mInputDevicesLock) {  
  10.         if (!mInputDevicesChangedPending) {  
  11.             return;  
  12.         }  
  13.         mInputDevicesChangedPending = false;  
  14.   
  15.         numListeners = mInputDevicesChangedListeners.size();  
  16.         for (int i = 0; i < numListeners; i++) {  
  17.             mTempInputDevicesChangedListenersToNotify.add(  
  18.                     mInputDevicesChangedListeners.valueAt(i));  
  19.         }  
  20.   
  21.         final int numDevices = mInputDevices.length;  
  22.         deviceIdAndGeneration = new int[numDevices * 2];  
  23.         for (int i = 0; i < numDevices; i++) {  
  24.             final InputDevice inputDevice = mInputDevices[i];  
  25.             deviceIdAndGeneration[i * 2] = inputDevice.getId();  
  26.             deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();  
  27.   
  28.             if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {  
  29.                 if (!containsInputDeviceWithDescriptor(oldInputDevices,  
  30.                         inputDevice.getDescriptor())) {  
  31.                     mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);  
  32.                 } else {  
  33.                     mTempFullKeyboards.add(inputDevice);  
  34.                 }  
  35.             }  
  36.         }  
  37.     }  
  38.   
  39.     // Notify listeners.  
  40.     for (int i = 0; i < numListeners; i++) {  
  41.         mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(  
  42.                 deviceIdAndGeneration);  
  43.     }  
  44.     mTempInputDevicesChangedListenersToNotify.clear();  
  45.   
  46.     // Check for missing keyboard layouts.  
  47.     if (mNotificationManager != null) {  
  48.         final int numFullKeyboards = mTempFullKeyboards.size();  
  49.         boolean missingLayoutForExternalKeyboard = false;  
  50.         boolean missingLayoutForExternalKeyboardAdded = false;  
  51.         boolean multipleMissingLayoutsForExternalKeyboardsAdded = false;  
  52.         InputDevice keyboardMissingLayout = null;  
  53.         synchronized (mDataStore) {  
  54.             for (int i = 0; i < numFullKeyboards; i++) {  
  55.                 final InputDevice inputDevice = mTempFullKeyboards.get(i);  
  56.                 final String layout =  
  57.                         getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());  
  58.                 if (layout == null) {  
  59.                     missingLayoutForExternalKeyboard = true;  
  60.                     if (i < numFullKeyboardsAdded) {  
  61.                         missingLayoutForExternalKeyboardAdded = true;  
  62.                         if (keyboardMissingLayout == null) {  
  63.                             keyboardMissingLayout = inputDevice;  
  64.                         } else {  
  65.                             multipleMissingLayoutsForExternalKeyboardsAdded = true;  
  66.                         }  
  67.                     }  
  68.                 }  
  69.             }  
  70.         }  
  71.         if (missingLayoutForExternalKeyboard) {  
  72.             if (missingLayoutForExternalKeyboardAdded) {  
  73.                 if (multipleMissingLayoutsForExternalKeyboardsAdded) {  
  74.                     // We have more than one keyboard missing a layout, so drop the  
  75.                     // user at the generic input methods page so they can pick which  
  76.                     // one to set.  
  77.                     showMissingKeyboardLayoutNotification(null);  
  78.                 } else {  
  79.                     // 当前只插入一个物理键盘时,获取该设备名称判断是否是指定的物理键盘名,  
  80.                     // 如果是,则不显示键盘布局通知,否则显示通知  
  81.                     // Modify by Janning begin  
  82.                     if (keyboardMissingLayout != null  
  83.                             && !keyboardMissingLayout.getName().equals("XXXX-vinput-keypad")) {  
  84.                         showMissingKeyboardLayoutNotification(keyboardMissingLayout);  
  85.                     }  
  86.                     // Modify by Janning end  
  87.                 }  
  88.             }  
  89.         } else if (mKeyboardLayoutNotificationShown) {  
  90.             hideMissingKeyboardLayoutNotification();  
  91.         }  
  92.     }  
  93.     mTempFullKeyboards.clear();  
  94. }  


private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
       
         。。。。。。。。。。。。。。。。

            if (missingLayoutForExternalKeyboard) {
                if (missingLayoutForExternalKeyboardAdded) {
                    if (multipleMissingLayoutsForExternalKeyboardsAdded) {
                        // We have more than one keyboard missing a layout, so drop the
                        // user at the generic input methods page so they can pick which
                        // one to set.
                        showMissingKeyboardLayoutNotification(null);
                    } else {
                        // 如果只插入了一个物理键盘则判断该物理键盘的名称是否是指定的,如果是则不让其显示键盘布局的通知
                        // Modify by Janning begin
                        if (keyboardMissingLayout != null
                                && !keyboardMissingLayout.getName().equals("XXXX-vinput-keypad")) {
                            showMissingKeyboardLayoutNotification(keyboardMissingLayout);
                        }
                        // Modify by Janning end

                    }
                }
            } else if (mKeyboardLayoutNotificationShown) {
                hideMissingKeyboardLayoutNotification();
            }
        }
        mTempFullKeyboards.clear();
    }

https://blog.csdn.net/u014770862/article/details/52459166
https://blog.csdn.net/jiuxiaoyunwu/article/details/49993931

猜你喜欢

转载自blog.csdn.net/xzx208/article/details/79852640
今日推荐