默认输入法删除后无法自动切换到新输入法

简介: 默认输入法删除后无法自动切换到新输入法

平台


RK3288 + Android 5.1


问题


1. 系统初始版本为1.0.0, 包含了默认输入法 LatinIME(拉丁输入法) 和 OpenWnn(日文输入法)
2. OTA升级中, 内置讯飞输入法, 同时删除1.0.0版本中的两个输入法.
3. OTA升级后, 文本输入框无法正常调起输入法软键盘执行输入.
4. 打开设置 > 语言和输入法 > 键盘和输入法中, 当前输入法为空, 输入法中也没有看到 讯飞输入法


分析


Logcat 分析:


01-02 03:14:58.469 system_process W/InputMethodManagerService: Couldn't create dir.: /data/system/inputmethod
01-02 03:14:58.479 system_process W/InputMethodManagerService: Default IME is uninstalled. Choose new default IME.
01-02 03:14:58.480 system_process W/InputMethodManagerService: Unknown input method from prefs: com.android.inputmethod.latin/.LatinIME
    java.lang.IllegalArgumentException: Unknown id: com.android.inputmethod.latin/.LatinIME
        at com.android.server.InputMethodManagerService.setInputMethodLocked(InputMethodManagerService.java:1806)
        at com.android.server.InputMethodManagerService.updateInputMethodsFromSettingsLocked(InputMethodManagerService.java:1756)
        at com.android.server.InputMethodManagerService.updateFromSettingsLocked(InputMethodManagerService.java:1715)
        at com.android.server.InputMethodManagerService.<init>(InputMethodManagerService.java:744)
        at com.android.server.SystemServer.startOtherServices(SystemServer.java:553)
        at com.android.server.SystemServer.run(SystemServer.java:261)
        at com.android.server.SystemServer.main(SystemServer.java:175)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:963)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:758)


相关代码如下:


|--frameworks/base/services/core/java/com/android/server/InputMethodManagerService.java
void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
        if (enabledMayChange) {
            List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
            for (int i=0; i<enabled.size(); i++) {
                // We allow the user to select "disabled until used" apps, so if they
                // are enabling one of those here we now need to make it enabled.
                InputMethodInfo imm = enabled.get(i);
                try {
                    ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
                            PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                            mSettings.getCurrentUserId());
                    if (ai != null && ai.enabledSetting
                            == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
                        if (DEBUG) {
                            Slog.d(TAG, "Update state(" + imm.getId()
                                    + "): DISABLED_UNTIL_USED -> DEFAULT");
                        }
                        mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
                                PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
                                PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),
                                mContext.getBasePackageName());
                    }
                } catch (RemoteException e) {
                }
            }
        }
        // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
        // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
        // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
        // enabled.
        String id = mSettings.getSelectedInputMethod();
        // There is no input method selected, try to choose new applicable input method.
        if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
            id = mSettings.getSelectedInputMethod();
        }
        if (!TextUtils.isEmpty(id)) {
            try {
                setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
                mPreScanHelper.addScanItem(PreScanHelper.SCAN_TYPE_IME, mContext, id);
                mPreScanHelper.flushToFile();
            } catch (IllegalArgumentException e) {
                //LOG输出的地方.
                Slog.w(TAG, "Unknown input method from prefs: " + id, e);
                mCurMethodId = null;
                unbindCurrentMethodLocked(true, false);
            }
            mShortcutInputMethodsAndSubtypes.clear();
        } else {
            // There is no longer an input method set, so stop any current one.
            mCurMethodId = null;
            unbindCurrentMethodLocked(true, false);
        }
        // Here is not the perfect place to reset the switching controller. Ideally
        // mSwitchingController and mSettings should be able to share the same state.
        // TODO: Make sure that mSwitchingController and mSettings are sharing the
        // the same enabled IMEs list.
        mSwitchingController.resetCircularListLocked(mContext);
    }


于是, 出错的位置, 加上重置输入法的代码:


//("start reset IME");
                mCurMethodId = null;
                unbindCurrentMethodLocked(true, false);
    //AnsonCode clear input method after error.
    //mSettings.putSelectedInputMethod("");
    Settings.Secure.putStringForUser(mContext.getContentResolver(), 
      Settings.Secure.ENABLED_INPUT_METHODS, "", mSettings.getCurrentUserId());
    //("enable All IMES");
    mSettings.enableAllIMEsIfThereIsNoEnabledIME();
    //("reset Default IME");
    resetDefaultImeLocked(mContext);


1. 清空数据库中ENABLED_INPUT_METHODS已启用的输入法
2. 重置启用输入法
3. 重置默认输入法.


最开始, 并没有去清空数据库, 导致, 不管如何重置输入法, 系统都无法正常启用讯飞.


private void resetDefaultImeLocked(Context context) {
        // Do not reset the default (current) IME when it is a 3rd-party IME
        if (mCurMethodId != null
                && !InputMethodUtils.isSystemIme(mMethodMap.get(mCurMethodId))) {
            return;
        }
        InputMethodInfo defIm = null;
        for (InputMethodInfo imi : mMethodList) {
            if (defIm == null) {
                if (InputMethodUtils.isValidSystemDefaultIme(
                        mSystemReady, imi, context)) {
                    defIm = imi;
                    Slog.i(TAG, "Selected default: " + imi.getId());
                }
            }
        }
        if (defIm == null && mMethodList.size() > 0) {
            defIm = InputMethodUtils.getMostApplicableDefaultIME(
                    mSettings.getEnabledInputMethodListLocked());
            //在这里, 因为数据库中启用的输入法依然是latinIME, 所以, defIm一直为空.
            if (defIm != null) {
                Slog.i(TAG, "Default found, using " + defIm.getId());
            } else {
                Slog.i(TAG, "No default found");
            }
        }
        if (defIm != null) {
            setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
        }
    }


也就是说, 若不清空数据库, 则会输入LOG: No default found


defIm为空的原因, 见下面代码.


|--frameworks/base/core/java/com/android/internal/inputmethod/InputMethodUtils.java
    public static InputMethodInfo getMostApplicableDefaultIME(List<InputMethodInfo> enabledImes) {
        if (enabledImes == null || enabledImes.isEmpty()) {
            return null;
        }
        // We'd prefer to fall back on a system IME, since that is safer.
        int i = enabledImes.size();
        int firstFoundSystemIme = -1;
        while (i > 0) {
            i--;
            final InputMethodInfo imi = enabledImes.get(i);
            if (InputMethodUtils.isSystemImeThatHasEnglishKeyboardSubtype(imi)
                    && !imi.isAuxiliaryIme()) {
                return imi;
            }
            if (firstFoundSystemIme < 0 && InputMethodUtils.isSystemIme(imi)
                    && !imi.isAuxiliaryIme()) {
                firstFoundSystemIme = i;
            }
        }
        return enabledImes.get(Math.max(firstFoundSystemIme, 0));
    }
        public List<InputMethodInfo> getEnabledInputMethodListLocked() {
            return createEnabledInputMethodListLocked(
                    getEnabledInputMethodsAndSubtypeListLocked());
        }
        public List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() {
            ArrayList<Pair<String, ArrayList<String>>> imsList
                    = new ArrayList<Pair<String, ArrayList<String>>>();
            final String enabledInputMethodsStr = getEnabledInputMethodsStr();
            if (TextUtils.isEmpty(enabledInputMethodsStr)) {
                return imsList;
            }
            mInputMethodSplitter.setString(enabledInputMethodsStr);
            while (mInputMethodSplitter.hasNext()) {
                String nextImsStr = mInputMethodSplitter.next();
                mSubtypeSplitter.setString(nextImsStr);
                if (mSubtypeSplitter.hasNext()) {
                    ArrayList<String> subtypeHashes = new ArrayList<String>();
                    // The first element is ime id.
                    String imeId = mSubtypeSplitter.next();
                    while (mSubtypeSplitter.hasNext()) {
                        subtypeHashes.add(mSubtypeSplitter.next());
                    }
                    imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes));
                }
            }
            return imsList;
        }
        public String getEnabledInputMethodsStr() {
            mEnabledInputMethodsStrCache = Settings.Secure.getStringForUser(
                    mResolver, Settings.Secure.ENABLED_INPUT_METHODS, mCurrentUserId);
            if (DEBUG) {
                Slog.d(TAG, "getEnabledInputMethodsStr: " + mEnabledInputMethodsStrCache
                        + ", " + mCurrentUserId);
            }
            return mEnabledInputMethodsStrCache;
        }


补充


跟输入法相关的两个数据库变量:
   Settings.Secure.ENABLED_INPUT_METHODS 使用/启用输入法, 这会显示在设置中的输入法列表
   Settings.Secure.DEFAULT_INPUT_METHOD 默认输入法
  查看数据库:
  sqlite3 /data/data/com.android.providers.settings/databases/settings.db
  select * from secure;
  可以看出当前输入法的值:
  50|enabled_input_methods|com.iflytek.inputmethod/.FlyIME
  51|default_input_method|com.iflytek.inputmethod/.FlyIME


相关文章
|
7月前
|
Windows
win11默认输入法字符集切换
在使用 IntelliJ 系列应用开发时,老是会时不时的将Windows的输入法就变为了繁体,后面就仔细的搜索了下,发现就是由于Windows11的字符集切换快捷键是 ctrl+shift+F , 而在 IntelliJ 系列产品中 ctrl+shift+F 是其中一个比较常用的快捷键(例如:IDEA中就使用改快捷键用来作为全局搜索),就导致了在开发了一段时间后,Windows的输入法就变为了繁体。
189 0
|
7月前
|
安全 搜索推荐 定位技术
Win10电脑桌面此电脑、网络、回收站与用户的文件等系统自带图标取消显示的方法
Win10电脑桌面此电脑、网络、回收站与用户的文件等系统自带图标取消显示的方法
270 1
|
Java Shell 数据库
AndroidQ(10.0) 默认铃声修改
AndroidQ(10.0) 默认铃声修改
457 0
PS的标题栏以选项卡方式打开名字太长,导致切换标题的时候不方便,如何缩短标题栏?
Q:如图:PS的标题栏以选项卡方式打开名字太长,导致切换标题的时候不方便,如何缩短标题栏?
428 0
PS的标题栏以选项卡方式打开名字太长,导致切换标题的时候不方便,如何缩短标题栏?
|
Windows
Win系统 - 系统双击文件总弹出属性窗口如何解决?
Win系统 - 系统双击文件总弹出属性窗口如何解决?
312 0
Win系统 - 系统双击文件总弹出属性窗口如何解决?
|
Windows
Windows 技术篇 - 2021年最新版win10设置默认输入法,时间和语言找不到默认输入法设置解决方法
Windows 技术篇 - 2021年最新版win10设置默认输入法,时间和语言找不到默认输入法设置解决方法
594 0
Windows 技术篇 - 2021年最新版win10设置默认输入法,时间和语言找不到默认输入法设置解决方法
|
缓存 Windows
Windows语言栏不见了,解决办法。任务栏的语言栏没了、不显示了。语言栏异常导致不能输入中文。默认中文输入法设置。
Windows语言栏不见了,解决办法。任务栏的语言栏没了、不显示了。语言栏异常导致不能输入中文。默认中文输入法设置。
474 0
Windows语言栏不见了,解决办法。任务栏的语言栏没了、不显示了。语言栏异常导致不能输入中文。默认中文输入法设置。