Android 根据SIM卡自动切换语言

1. 实现只在Google setup wizard情况下才切换SIM卡语言,其余时候(比如已经开机进入Home)不切换语言

在/frameworks/opt/telephony/src/java/com/android/internal/telephony/MccTable.java中添加:

public static void updateMccMncConfiguration(Context context, String mccmnc) {
       ...
            Slog.d(LOG_TAG, "updateMccMncConfiguration: mcc=" + mcc + ", mnc=" + mnc);
            Locale mccLocale = null;
            if (mcc != 0) {
                setTimezoneFromMccIfNeeded(context, mcc);
                mccLocale = getLocaleFromMcc(context, mcc,null);//添加这句读取SIM语言
            }

            try {
                Configuration config = new Configuration();
                boolean updateConfig = false;
                if (mcc != 0) {
                    config.mcc = mcc;
                    config.mnc = mnc == 0 ? Configuration.MNC_ZERO : mnc;
                    updateConfig = true;
                }

               //Add code BEGIN
                if(UPDATE_SIM_LANGUAGE) {
                    boolean isDeviceProvisioned = Settings.Global.getInt(
                            context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,0) != 0;
                    boolean setupCompleted = Settings.Secure.getInt(context.getContentResolver(),
                            Settings.Secure.USER_SETUP_COMPLETE,0) != 0;

                    if (mccLocale != null && !isDeviceProvisioned && !setupCompleted) {
                        Configuration sysConfig = new Configuration();
                        sysConfig = ActivityManager.getService().getConfiguration();;
                        LocaleList currentLocales = sysConfig.getLocales();
                        LocaleList newUserLocales = new LocaleList(mccLocale, currentLocales);
                        config.setLocales(newUserLocales);
                        updateConfig = true;
                        Settings.System.putConfiguration(context.getContentResolver(), config);
                    }
                }
               //Add code END

                if (updateConfig) {
                    Slog.d(LOG_TAG, "updateMccMncConfiguration updateConfig config=" + config);
                    ActivityManager.getService().updateConfiguration(config);
                } else {
                    Slog.d(LOG_TAG, "updateMccMncConfiguration nothing to update");
                }
            } catch (RemoteException e) {
                Slog.e(LOG_TAG, "Can't update configuration", e);
            }
        }
    }

此处有下面几个关键点。

Settings.Global.DEVICE_PROVISIONED 和 Settings.Secure.USER_SETUP_COMPLETE用来判断当前Google SetupWizard有没有结束。

如果还在SetupWizard画面,这两个值都是0;当SetupWizard结束,这两个会被设定为1.

ActivityManager.getService().updateConfiguration(config) 会呼叫到ActivityTaskManagerService里面,但真正走到update config之前,会有下面的code

if (values != null) {
    Settings.System.clearConfiguration(values);
}

也就是会把通过Configuration设定进来的Locale设定清除(不清楚为什么这么设定)

        /**
         * @hide Erase the fields in the Configuration that should be applied
         * by the settings.
         */
        public static void clearConfiguration(Configuration inoutConfig) {
            inoutConfig.fontScale = 0;
            if (!inoutConfig.userSetLocale && !inoutConfig.getLocales().isEmpty()) {
                inoutConfig.clearLocales();
            }
        }

因此,还需要再在frameworks/base/services/core/java/com/android/server/am/ActivityTaskManagerService.java中添加:

@Override
    public boolean updateConfiguration(Configuration values) {
        mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");

        ...

            final long origId = Binder.clearCallingIdentity();
            try {
                //Add code BEGIN
                if(UPDATE_SIM_LANGUAGE){
                    boolean isDeviceProvisioned = Settings.Global.getInt(
                            mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
                    boolean setupCompleted = Settings.Secure.getInt(mContext.getContentResolver(),
                            Settings.Secure.USER_SETUP_COMPLETE,0) != 0;

                    if(isDeviceProvisioned || setupCompleted){
                        if (values != null) {
                            Settings.System.clearConfiguration(values);
                        }
                    }
                }else { //保留原有
                    if (values != null) {
                        Settings.System.clearConfiguration(values);
                    }
                }
                //Add code END
                updateConfigurationLocked(values, null, false, false /* persistent */,
                        UserHandle.USER_NULL, false /* deferResume */,
                        mTmpUpdateConfigurationResult);
                return mTmpUpdateConfigurationResult.changes != 0;
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
    }

2. 如果想每次插入SIM卡都要切换成SIM卡语言,只需要把第一步里面关于isDeviceProvisioned和setupCompleted的判断拿掉就行,也就是每次插入SIM卡都会默认切换成SIM卡语言。

3. 如果只想SIM卡插入第一次才去切换,先把第一步的isDeviceProvisioned和setupCompleted的判断拿掉,再去判断Settings.System.SYSTEM_LOCALES是否已经包含当前SIM卡语言。

判断时候不要用mccLocale.toString(),会有zh-CN和zh_CN的差异,用mccLocale.getLanguage(),只去判断zh就好

WARNING:报BUG啦!

按照方法1修改代码后,功能可以实现,但是在Settings中设置startup security(开机启动需要解锁)的话,在开机到secure startup画面时,所有user setting不能被访问。

因此此时 Settings.Global.DEVICE_PROVISIONED 和Settings.Secure.USER_SETUP_COMPLETE读出来都是默认值!

因此需要再在Settings中CryptKeeper.java中去添加一个flag,activity start时候flag设为true,onDestroy时候清除flag。

这时在方法1添加判断的地方添加一个读Settings字段flag的功能,发现此时是secure startup时,切换语言的功能不要去执行!

原文地址:https://www.cnblogs.com/kunkka/p/12937251.html