1. 程式人生 > >android5.0 物理鍵盤與軟鍵盤同時使用修改

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在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方法中有通過判斷當前物理鍵盤型別來控制是否同時啟用軟體盤的處理邏輯:

 

           
            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 方法中控制通知的顯示。
a>

             
             // 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