Android12.0 SIM卡语言自适应
文章目录
- 需求
- 语言设定
- Settings中语言切换流程
- 检测到SIM卡,更新系统语言
- 最终修改
需求
要求系统语言跟随SIM卡的语言变化。
语言设定
(1)系统预置语言, 即在makefile中指定的语言
(2)重启, 如果未插卡, 则系统语言为预置的语言
(3)重启插入SIM卡开机, 会自适应为SIM卡的语言
(4)如果有手动设置语言, 以后开机, 不管插入的是哪个国家的卡, 都会显示设置的语言, 不会根据SIM卡自适应变化.
Settings中语言切换流程
当在系统设置中手动设置语言拖拽结束后,会调用updateLocalesWhenAnimationStops(ll)方法
- vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
public void updateLocalesWhenAnimationStops(final LocaleList localeList) {if (localeList.equals(mLocalesToSetNext)) {return;}// This will only update the Settings application to make things feel more responsive,// the system will be updated later, when animation stopped.LocaleList.setDefault(localeList);mLocalesToSetNext = localeList;final RecyclerView.ItemAnimator itemAnimator = mParentView.getItemAnimator();itemAnimator.isRunning(new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {@Overridepublic void onAnimationsFinished() {if (mLocalesToSetNext == null || mLocalesToSetNext.equals(mLocalesSetLast)) {// All animations finished, but the locale list did not changereturn;}// 语言条目发生改变,调用到framework下的LocalePicker进行更新LocalePicker.updateLocales(mLocalesToSetNext);mLocalesSetLast = mLocalesToSetNext;new ShortcutsUpdateTask(mContext).execute();mLocalesToSetNext = null;mNumberFormatter = NumberFormat.getNumberInstance(Locale.getDefault());}});}
然后调用LocalePicker的updateLocales()方法进行更新
- frameworks/base/core/java/com/android/internal/app/LocalePicker.java
/*** Requests the system to update the list of system locales.* Note that the system looks halted for a while during the Locale migration,* so the caller need to take care of it.*/@UnsupportedAppUsagepublic static void updateLocales(LocaleList locales) {if (locales != null) {locales = removeExcludedLocales(locales);}// Note: the empty list case is covered by Configuration.setLocales().try {final IActivityManager am = ActivityManager.getService();final Configuration config = am.getConfiguration();// 切换后的语言信息更新到Configurationconfig.setLocales(locales);config.userSetLocale = true; // 手动设置的标志am.updatePersistentConfigurationWithAttribution(config,ActivityThread.currentOpPackageName(), null);// Trigger the dirty bit for the Settings Provider.BackupManager.dataChanged("com.android.providers.settings");} catch (RemoteException e) {// Intentionally left blank}}
又转入到ActivityManagerService中处理
- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Overridepublic void updatePersistentConfigurationWithAttribution(Configuration values,String callingPackage, String callingAttributionTag) {enforceCallingPermission(CHANGE_CONFIGURATION, "updatePersistentConfiguration()");enforceWriteSettingsPermission("updatePersistentConfiguration()", callingPackage,callingAttributionTag);if (values == null) {throw new NullPointerException("Configuration must not be null");}int userId = UserHandle.getCallingUserId();// 这里的mActivityTaskManager就是ActivityTaskManagerServicemActivityTaskManager.updatePersistentConfiguration(values, userId);}
继续传递到ActivityTaskManagerService中处理updateConfigurationLocked()
- frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
public void updatePersistentConfiguration(Configuration values, @UserIdInt int userId) {final long origId = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) {// 配置发生改变(尺寸,字体),都会执行updateConfigurationLocked(values, null, false, true, userId,false /* deferResume */);}} finally {Binder.restoreCallingIdentity(origId);}}
在ActivityTaskManagerService内部经过一系列处理,最终执行到updateGlobalConfigurationLocked()
int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,boolean persistent, int userId) {mTempConfig.setTo(getGlobalConfiguration());// 判断是否发生变化final int changes = mTempConfig.updateFrom(values);if (changes == 0) {return 0;}...if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {// 这里的locales包含所有已添加的语言,如果是第一次开机就是系统默认语言[en_US]final LocaleList locales = values.getLocales();int bestLocaleIndex = 0;if (locales.size() > 1) {if (mSupportedSystemLocales == null) {// 所有系统支持的语言mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();}bestLocaleIndex = Math.max(0, locales.getFirstMatchIndex(mSupportedSystemLocales));}// 如果是values.userSetLocale=true,设置系统属性SystemProperties.set("persist.sys.locale",locales.get(bestLocaleIndex).toLanguageTag());LocaleList.setDefault(locales, bestLocaleIndex);final Message m = PooledLambda.obtainMessage(ActivityTaskManagerService::sendLocaleToMountDaemonMsg, this,locales.get(bestLocaleIndex));mH.sendMessage(m);}mTempConfig.seq = increaseConfigurationSeqLocked();Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig);...// Update stored global config and notify everyone about the change.mRootWindowContainer.onConfigurationChanged(mTempConfig); // 整个系统界面进行更新return changes;}
检测到SIM卡,更新系统语言
SIM卡ready后,会调用updateMccMncConfiguration()方法更新卡的MCC/MNC信息
- frameworks/opt/telephony/src/java/com/android/internal/telephony/MccTable.java
/*** Updates MCC and MNC device configuration information for application retrieving* correct version of resources. If MCC is 0, MCC and MNC will be ignored (not set).* @param context Context to act on.* @param mccmnc truncated imsi with just the MCC and MNC - MNC assumed to be from 4th to end*/public static void updateMccMncConfiguration(Context context, String mccmnc) {Rlog.d(LOG_TAG, "updateMccMncConfiguration mccmnc='" + mccmnc);if (TelephonyUtils.IS_DEBUGGABLE) {String overrideMcc = SystemProperties.get("persist.sys.override_mcc");if (!TextUtils.isEmpty(overrideMcc)) {mccmnc = overrideMcc;Rlog.d(LOG_TAG, "updateMccMncConfiguration overriding mccmnc='" + mccmnc + "'");}}if (!TextUtils.isEmpty(mccmnc)) {int mccInt;try {mccInt = Integer.parseInt(mccmnc.substring(0, 3));} catch (NumberFormatException | StringIndexOutOfBoundsException ex) {Rlog.e(LOG_TAG, "Error parsing mccmnc: " + mccmnc + ". ex=" + ex);return;}if (mccInt != 0) {ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);if (!activityManager.updateMccMncConfiguration(mccmnc.substring(0, 3), mccmnc.substring(3))) {Rlog.d(LOG_TAG, "updateMccMncConfiguration: update mccmnc="+ mccmnc + " failure");} else {Rlog.d(LOG_TAG, "updateMccMncConfiguration: update mccmnc="+ mccmnc + " success");}} else {Rlog.d(LOG_TAG, "updateMccMncConfiguration nothing to update");}}}
mcc参数不为0,继续往下执行到ActivityManagerService的updateMccMncConfiguration
- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Overridepublic boolean updateConfiguration(Configuration values) {return mActivityTaskManager.updateConfiguration(values);}@Overridepublic boolean updateMccMncConfiguration(String mcc, String mnc) {int mccInt, mncInt;try {mccInt = Integer.parseInt(mcc);mncInt = Integer.parseInt(mnc);} catch (NumberFormatException | StringIndexOutOfBoundsException ex) {Slog.e(TAG, "Error parsing mcc: " + mcc + " mnc: " + mnc + ". ex=" + ex);return false;}Configuration config = new Configuration();config.mcc = mccInt;config.mnc = mncInt == 0 ? Configuration.MNC_ZERO : mncInt;return mActivityTaskManager.updateConfiguration(config);}
mcc/mnc参数没有问题更新Configuration,与Settings中设置语言一样执行到ActivityTaskManagerService中处理
- frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@Overridepublic boolean updateConfiguration(Configuration values) {mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");synchronized (mGlobalLock) {if (mWindowManager == null) {Slog.w(TAG, "Skip updateConfiguration because mWindowManager isn't set");return false;}if (values == null) {// sentinel: fetch the current configuration from the window managervalues = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);}mH.sendMessage(PooledLambda.obtainMessage(ActivityManagerInternal::updateOomLevelsForDisplay, mAmInternal,DEFAULT_DISPLAY));final long origId = Binder.clearCallingIdentity();try {if (values != null) {Settings.System.clearConfiguration(values);}updateConfigurationLocked(values, null, false, false /* persistent */,UserHandle.USER_NULL, false /* deferResume */,mTmpUpdateConfigurationResult);return mTmpUpdateConfigurationResult.changes != 0;} finally {Binder.restoreCallingIdentity(origId);}}}
最终走updateConfigurationLocked(),与Settings中设置语言一样的流程。
最终修改
- frameworks/opt/telephony/src/java/com/android/internal/telephony/MccTable.java
// add for SIM language adaptiveimport android.content.res.Configuration;import android.os.LocaleList;import android.os.RemoteException;import android.app.ActivityManagerNative;// add end/*** Updates MCC and MNC device configuration information for application retrieving* correct version of resources. If MCC is 0, MCC and MNC will be ignored (not set).* @param context Context to act on.* @param mccmnc truncated imsi with just the MCC and MNC - MNC assumed to be from 4th to end*/public static void updateMccMncConfiguration(Context context, String mccmnc) {Rlog.d(LOG_TAG, "updateMccMncConfiguration mccmnc='" + mccmnc);if (TelephonyUtils.IS_DEBUGGABLE) {String overrideMcc = SystemProperties.get("persist.sys.override_mcc");if (!TextUtils.isEmpty(overrideMcc)) {mccmnc = overrideMcc;Rlog.d(LOG_TAG, "updateMccMncConfiguration overriding mccmnc='" + mccmnc + "'");}}if (!TextUtils.isEmpty(mccmnc)) {int mccInt;int mncInt;try {mccInt = Integer.parseInt(mccmnc.substring(0, 3));// add for SIM language adaptivemncInt = Integer.parseInt(mccmnc.substring(3));// add end} catch (NumberFormatException | StringIndexOutOfBoundsException ex) {Rlog.e(LOG_TAG, "Error parsing mccmnc: " + mccmnc + ". ex=" + ex);return;}if (mccInt != 0) {// add for SIM language adaptivetry {Configuration config = new Configuration();config.mcc = mccInt;config.mnc = mncInt == 0 ? Configuration.MNC_ZERO : mncInt;// 根据MCC获取语言和国家码(对应的表是sTable)Locale mccLocale = LocaleUtils.getLocaleFromMcc(context, mccInt, null); // 根据sim卡的mcc参数获取的Locale不为空并且没有设置过语言,根据sim卡信息设置语言if (mccLocale != null && canUpdateLocale()){Configuration configLocal = new Configuration();configLocal = ActivityManagerNative.getDefault().getConfiguration();LocaleList userLocale = configLocal.getLocales();// sim卡语言置顶LocaleList newUserLocale = new LocaleList(mccLocale, userLocale);config.setLocales(newUserLocale);config.userSetLocale = true;config.fontScale = 1.0f;ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);if (!activityManager.updateConfiguration(config)) {Rlog.d(LOG_TAG, "updateConfiguration: update mccmnc="+ mccmnc + " failure");} else {Rlog.d(LOG_TAG, "updateConfiguration: update mccmnc="+ mccmnc + " success");}return;}} catch (RemoteException e) {throw e.rethrowFromSystemServer();}// add endActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);if (!activityManager.updateMccMncConfiguration(mccmnc.substring(0, 3), mccmnc.substring(3))) {Rlog.d(LOG_TAG, "updateMccMncConfiguration: update mccmnc="+ mccmnc + " failure");} else {Rlog.d(LOG_TAG, "updateMccMncConfiguration: update mccmnc="+ mccmnc + " success");}} else {Rlog.d(LOG_TAG, "updateMccMncConfiguration nothing to update");}}}// add for SIM language adaptiveprivate static boolean canUpdateLocale() {return !userHasPersistedLocale();}private static boolean userHasPersistedLocale() {String persistSysLanguage = SystemProperties.get("persist.sys.locale", "");return !(persistSysLanguage.isEmpty());}// add end
- frameworks/base/core/java/android/app/ActivityManager.java
import android.content.res.Configuration;// add for SIM language adaptivepublic boolean updateConfiguration(@NonNull Configuration values) {try {return getService().updateConfiguration(values);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}// add end
修改完之后
(1)系统预置语言, 即在makefile中指定的语言
(2)重启, 如果未插卡, 则系统语言为预置的语言
(3)重启插入SIM卡开机, 会自适应为SIM卡的语言
(4)如果有手动设置语言, 以后开机, 不管插入的是哪个国家的卡, 都会显示设置的语言, 不会根据SIM卡自适应变化.
相关文章:
Android12.0 SIM卡语言自适应
文章目录 需求语言设定Settings中语言切换流程检测到SIM卡,更新系统语言最终修改 需求 要求系统语言跟随SIM卡的语言变化。 语言设定 (1)系统预置语言, 即在makefile中指定的语言 (2)重启, 如果未插卡, 则系统语言为预置的语言 (3)重启插入SIM卡开机, 会自适应为…...
滴滴一季度营收同比增长14.9%至491亿元 经调整EBITA盈利9亿元
【头部财经】5月29日,滴滴在其官网发布2024年一季度业绩报告。一季度滴滴实现总收入491亿元,同比增长14.9%;经调整EBITA(非公认会计准则口径)盈利9亿元。其中,中国出行一季度实现收入445亿元,同…...
C语言 指针——指针变量的定义、初始化及解引用
目录 指针 内存如何编址? 如何对变量进行寻址? 用什么类型的变量来存放变量的地址? 如何显示变量的地址?编辑 使用未初始化的指针会怎样? NULL是什么? 如何访问指针变量指向的存储单元中的数据? 指针变量的…...
详解 Spark 的运行架构
一、核心组件 1. Driver Spark 驱动器节点,用于执行 Spark 任务中的 main 方法,负责实际代码的执行工作主要负责: 将用户程序转化为作业 (job)在 Executor 之间调度任务 (task)跟踪 Executor 的执行情况通过 UI 展示查询运行情况 2. Exec…...
盲盒小程序开发,为市场带来的新机遇
近年来,盲盒市场一直处于热门行业中,发展非常快速。在互联网的支持下,也衍生出了线上盲盒小程序,实现了线上线下双发展的态势。 盲盒小程序作为一种新的盲盒购物方式,受到了盲盒消费者的喜爱,为盲盒行业的…...
stm32学习-流水灯
接线 注意:LED灯长一点的引脚是正极。 配置GPIO 1.使用RCC开启GPIO时钟 void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState); void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); void RCC_APB1Perip…...
GIGE 协议摘录
系列文章目录 GIGE 学习笔记 GIGE 协议摘录 文章目录 系列文章目录引言第 1 章 设备发现1.1 链路选择1.1.1 单链路配置1.1.2 多链路配置1.1.3 链路聚合组配置 LAG 1.2 IP配置1.2.1 协议选择1.2.2 静态IP1.2.3 DHCP1.2.4 链接本地地址 LLA 1.3 设备枚举1.3.1 GVCP设备发现广播设…...
服务器的远程桌面无法连接,服务器远程桌面无法连接问题处理教程
服务器的远程桌面无法连接,服务器远程桌面无法连接问题处理教程。 一、问题概述 服务器远程桌面无法连接是日常运维中常见的问题之一。它可能由多种原因造成,如网络问题、服务器配置错误、远程桌面服务未启动等。本教程将指导您逐步排查并解决这些问题。…...
【机器学习300问】105、计算机视觉(CV)领域有哪些子任务?
计算机视觉作为人工智能的重要分支,发展至今已经在诸多领域取得显著的成果。在众多的计算机视觉任务中,图像分类、目标检测与定位、语义分割和实例分割是四个基本而关键的子任务,它们在不同的应用场景下扮演着重要角色。这四个子任务虽然各具…...
安卓手机APP开发__超宽带(UWB)通信
安卓手机APP开发__超宽带(UWB)通信 目录 概述 控制方/发起方与控制方/响应方 参数范围 后台测距 STS 配置 步骤 使用限制 代码示例 示例应用 UWB 范围 RxJava3 支持 生态系统支持 支持 UWB 的移动设备 第三方 SDK 概述 注意 :UWB 目前仅支持 Jetpac…...
儿童股骨干骨折用儿童悬吊如何进行康复
儿童股骨干骨折后的悬吊康复训练,应根据骨折的具体情况和儿童的年龄来制定个性化的康复计划。悬吊康复训练主要目的是通过减轻骨折部位的压力,促进骨折愈合,同时保持和增强儿童的肌肉力量和关节活动能力。 悬吊康复训练的方法 1.垂直悬吊皮牵…...
vscode plantuml插件安装使用(windows)
1、安装JDK,网址 https://www.oracle.com/java/technologies/,添加系统变量JAVA_HOME 2、安装graphviz,网址 Download | Graphviz, 并添加用户变量GRAPHVIZ_DOT 3、vscode安装插件plantuml 4、新增wsd文件,按照使用…...
Linux内核编译流程3.10
一、内核源代码编译流程 编译环境: cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) Linux内核版本: uname -r 3.10.0-693.el7.x86_64 编译内核源代码版本:linux-4.19.90-all-arch-master cp /boot/config-xxx到内核源代码目录/.configmake menuconfi…...
OSPF多区域组网实验(华为)
思科设备参考:OSPF多区域组网实验(思科) 技术简介 OSPF多区域功能通过划分网络为多个逻辑区域来提高网络的可扩展性和管理性能。每个区域内部运行独立的SPF计算,而区域之间通过区域边界路由器进行路由信息交换。这种划分策略适用…...
解密MySQL二进制日志:深度探究mysqlbinlog工具
欢迎来到我的博客,代码的世界里,每一行都是一个故事 🎏:你只管努力,剩下的交给时间 🏠 :小破站 解密MySQL二进制日志:深度探究mysqlbinlog工具 前言mysqlbinlog工具概述mysqlbinlog的…...
妙解设计模式之策略模式
目录 策略模式的概念生活中的例子编程中的例子 软件工程中的实际应用数据排序文件压缩支付方式图形绘制 策略模式的概念 策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,把它们一个个封装起来,并…...
Linux DHCP server 配置
参考:linux dhcp配置多vlan ip_linux 接口vlan-CSDN博客 配置静态IP地址: 给固定的MAC地址分配指定的IP地址,固定的IP地址不必包含在指定的IP池中,如果包含在IP地址池中,固定的IP地址会从IP地址池中移除 配置方法&…...
深入解析力扣166题:分数到小数(模拟长除法与字符串操作详解及模拟面试问答)
力扣166题:分数到小数 在本篇文章中,我们将详细解读力扣第166题“分数到小数”。通过学习本篇文章,读者将掌握如何使用多种方法来解决这一问题,并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释和ASCII图解&am…...
新疆 | 金石商砼效率革命背后的逻辑
走进标杆企业,感受名企力量,探寻学习优秀企业领先之道。 本期要跟砼行们推介的标杆企业是新疆砼行业的龙头企业:新疆兵团建工金石商品混凝土有限责任公司(以下简称:新疆金石)。 从年产80万方到120万方&am…...
Dinky MySQLCDC 整库同步到 Doris
资源:flink 1.17.0、dinky 1.0.2、doris-2.0.1-rc04 问题:Cannot deserialize value of type int from String ,detailMessageunknowndatabases ,not a valid int value 2024-05-29 16:52:20.136 ERROR org.apache.doris.flink.…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
