在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
2
在代码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()方法中
- boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
- if (hardKeyboardAvailable != mHardKeyboardAvailable) {
- mHardKeyboardAvailable = hardKeyboardAvailable;
- mHardKeyboardEnabled = !hardKeyboardAvailable;
- mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
- mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
- }
- if (!mHardKeyboardEnabled) {
- config.keyboard = Configuration.KEYBOARD_NOKEYS;
- }
这样改软键盘是能用但是物理键盘是用不了的
最后研究代码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);
- }
- }
- }
经过测试以上修改可以实现物理键盘与软键盘的同时启用,完美解决问题。
二、插入物理键盘后通知栏不想弹出键盘布局通知的问题修改
- // 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();
- }
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();
}