android5.0 物理键盘与软键盘同时使用修改

最近工作中遇到在android 5.0 系统插入硬件盘物理设备后,软键盘无法弹出的问题,在网上查找了相关资料:

参考:http://blog.csdn.net/DrakeBlue/article/details/39049495

          http://blog.csdn.net/hclydao/article/details/44240799

          http://blog.csdn.net/jdsjlzx/article/details/39495319

物理键盘映射过程:
手机/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
  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方法中有通过判断当前物理键盘类型来控制是否同时启用软件盘的处理逻辑:

boolean computeScreenConfigurationLocked(Configuration config) {
        if (!mDisplayReady) {
            return false;
        }

        // TODO(multidisplay): For now, apply Configuration to main screen only.
        final DisplayContent displayContent = getDefaultDisplayContentLocked();

        // Use the effective "visual" dimensions based on current rotation
        final boolean rotated = (mRotation == Surface.ROTATION_90
                || mRotation == Surface.ROTATION_270);
        final int realdw = rotated ?
                displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
        final int realdh = rotated ?
                displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
        int dw = realdw;
        int dh = realdh;

        if (mAltOrientation) {
            if (realdw > realdh) {
                // Turn landscape into portrait.
                int maxw = (int)(realdh/1.3f);
                if (maxw < realdw) {
                    dw = maxw;
                }
            } else {
                // Turn portrait into landscape.
                int maxh = (int)(realdw/1.3f);
                if (maxh < realdh) {
                    dh = maxh;
                }
            }
        }

        if (config != null) {
            config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
                    Configuration.ORIENTATION_LANDSCAPE;
        }

        // Update application display metrics.
        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
        synchronized(displayContent.mDisplaySizeLock) {
            displayInfo.rotation = mRotation;
            displayInfo.logicalWidth = dw;
            displayInfo.logicalHeight = dh;
            displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
            displayInfo.appWidth = appWidth;
            displayInfo.appHeight = appHeight;
            displayInfo.getLogicalMetrics(mRealDisplayMetrics,
                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
            displayInfo.getAppMetrics(mDisplayMetrics);
            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
                    displayContent.getDisplayId(), displayInfo);
        }
        if (false) {
            Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);
        }

        final DisplayMetrics dm = mDisplayMetrics;
        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
                mCompatDisplayMetrics);

        if (config != null) {
            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
                    / dm.density);
            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
                    / dm.density);
            computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);

            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
            config.densityDpi = displayContent.mBaseDisplayDensity;

            // Update the configuration based on available input devices, lid switch,
            // and platform configuration.
            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
            config.keyboard = Configuration.KEYBOARD_NOKEYS;
            config.navigation = Configuration.NAVIGATION_NONAV;

            int keyboardPresence = 0;
            int navigationPresence = 0;
            final InputDevice[] devices = mInputManager.getInputDevices();
            final int len = devices.length;
            for (int i = 0; i < len; i++) {
                InputDevice device = devices[i];
                if (!device.isVirtual()) {
                    final int sources = device.getSources();
                    final int presenceFlag = device.isExternal() ?
                            WindowManagerPolicy.PRESENCE_EXTERNAL :
                                    WindowManagerPolicy.PRESENCE_INTERNAL;

                    if (mIsTouchDevice) {
                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
                                InputDevice.SOURCE_TOUCHSCREEN) {
                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
                        }
                    } else {
                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
                    }

                    if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
                        navigationPresence |= presenceFlag;
                    } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
                            && config.navigation == Configuration.NAVIGATION_NONAV) {
                        config.navigation = Configuration.NAVIGATION_DPAD;
                        navigationPresence |= presenceFlag;
                    }
                    // 判断该物理设备的类型, InputDevice.KEYBOARD_TYPE_ALPHABETIC 是表示物理键盘设备
                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
                        config.keyboard = Configuration.KEYBOARD_QWERTY;
                        keyboardPresence |= presenceFlag;
                    }
                    // 获取物理设备名称,判断是否是指定的名称,如果是则把 config.keyboard
                    // 的属性置为 Configuration.KEYBOARD_NOKEYS ,如此则可以同时兼容软键盘
                    // 物理键盘与软键盘可以同时启用
                    // Add by Janning start
                    // for show IME with HardKeyboard
                    if (device.getName().equals("XXX-vinput-keypad")) {
                        Slog.w("SLCODE", "the hard device name is: " + device.getName());
                        config.keyboard = Configuration.KEYBOARD_NOKEYS;
                    }
                    // Add by Janning end
                }
            }

            if (config.navigation == Configuration.NAVIGATION_NONAV && mHasPermanentDpad) {
                config.navigation = Configuration.NAVIGATION_DPAD;
                navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;
            }

            // Determine whether a hard keyboard is available and enabled.
            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
                mHardKeyboardAvailable = hardKeyboardAvailable;
                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
            }
            if (mShowImeWithHardKeyboard) {
                config.keyboard = Configuration.KEYBOARD_NOKEYS;
            }

            // Let the policy update hidden states.
            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
        }

        return true;
    }

    public boolean isHardKeyboardAvailable() {
        synchronized (mWindowMap) {
            return mHardKeyboardAvailable;
        }
    }

    public void updateShowImeWithHardKeyboard() {
        // 此处修改也可以实现物理键盘与软键盘的同时启用,即把showImeWithHardKeyboard 直接置为 true,
        // 但此方法影响太大,不推荐该方案,建议根据设备名称判断 修改config.keyboard 属性值(代码见上文)
        //changed by Janning start
        //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
        //changed by Janning end
        synchronized (mWindowMap) {
            if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) {
                mShowImeWithHardKeyboard = showImeWithHardKeyboard;
                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
            }
        }
    }


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


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

当插入物理键盘后通知栏会弹出相应的选择键盘布局通知,对于该通知可以选择隐藏:
根据字符串查找到是在 frameworks\base\services\core\java\com\android\server\input\InputManagerService.java 中调用显示该通知的,
进一步分析代码发现是在 deliverInputDevicesChanged 方法中控制通知的显示。
    // Must be called on handler.
    private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
        // Scan for changes.
        int numFullKeyboardsAdded = 0;
        mTempInputDevicesChangedListenersToNotify.clear();
        mTempFullKeyboards.clear();
        final int numListeners;
        final int[] deviceIdAndGeneration;
        synchronized (mInputDevicesLock) {
            if (!mInputDevicesChangedPending) {
                return;
            }
            mInputDevicesChangedPending = false;

            numListeners = mInputDevicesChangedListeners.size();
            for (int i = 0; i < numListeners; i++) {
                mTempInputDevicesChangedListenersToNotify.add(
                        mInputDevicesChangedListeners.valueAt(i));
            }

            final int numDevices = mInputDevices.length;
            deviceIdAndGeneration = new int[numDevices * 2];
            for (int i = 0; i < numDevices; i++) {
                final InputDevice inputDevice = mInputDevices[i];
                deviceIdAndGeneration[i * 2] = inputDevice.getId();
                deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();

                if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
                    if (!containsInputDeviceWithDescriptor(oldInputDevices,
                            inputDevice.getDescriptor())) {
                        mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
                    } else {
                        mTempFullKeyboards.add(inputDevice);
                    }
                }
            }
        }

        // Notify listeners.
        for (int i = 0; i < numListeners; i++) {
            mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
                    deviceIdAndGeneration);
        }
        mTempInputDevicesChangedListenersToNotify.clear();

        // Check for missing keyboard layouts.
        if (mNotificationManager != null) {
            final int numFullKeyboards = mTempFullKeyboards.size();
            boolean missingLayoutForExternalKeyboard = false;
            boolean missingLayoutForExternalKeyboardAdded = false;
            boolean multipleMissingLayoutsForExternalKeyboardsAdded = false;
            InputDevice keyboardMissingLayout = null;
            synchronized (mDataStore) {
                for (int i = 0; i < numFullKeyboards; i++) {
                    final InputDevice inputDevice = mTempFullKeyboards.get(i);
                    final String layout =
                            getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
                    if (layout == null) {
                        missingLayoutForExternalKeyboard = true;
                        if (i < numFullKeyboardsAdded) {
                            missingLayoutForExternalKeyboardAdded = true;
                            if (keyboardMissingLayout == null) {
                                keyboardMissingLayout = inputDevice;
                            } else {
                                multipleMissingLayoutsForExternalKeyboardsAdded = true;
                            }
                        }
                    }
                }
            }
            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();
    }


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();
    }

你可能感兴趣的:(android,开发)