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卡自適應變化.

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/19356.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/19356.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/19356.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【前端】vue+element項目中select下拉框label想要顯示多個值多個字段

Vue Element項目中select下拉框label想要顯示多個值 <el-selectv-model"form.plantId"collapse-tagsfilterableplaceholder"請選擇品種種類"style"width: 270px;"><el-optionv-for"item in plantIdArray":key"item.id&…

前端首屏加載速度慢問題?怎么解決

前端首屏加載速度慢是用戶體驗中的一個關鍵問題&#xff0c;它直接影響用戶對網站的第一印象以及用戶留存率。首屏加載時間是指從用戶輸入網址到頁面首屏內容完全呈現在用戶面前所需的時間。這個指標對于搜索引擎優化&#xff08;SEO&#xff09;和用戶體驗都至關重要。下面將探…

CSS:浮動

? 文檔流&#xff1a; 由于網頁默認是一個二維平面&#xff0c;當我們在網頁中一行行擺放標簽時&#xff0c;塊標簽會獨占一行&#xff0c;行標簽則只占自身大小&#xff0c;這種情況下要實現網頁布局就很麻煩了&#xff0c;所以我們就需要通過一些方法來改變這種默認的布局方…

centos7離線安裝pthon3.8

centos7離線安裝pthon3.8 因服務器無外網環境&#xff0c;所以事先需要把所有離線的依賴都準備好。 安裝前的準備 先在有外網環境的機器上準備依賴 安裝 centos-release-scl 第三方yum源 yum install centos-release-scl安裝 yum 依賴下載插件 yum install yum-plugin-do…

Javascript 位運算符(,|,^,<<,>>,>>>)

文章目錄 一、什么是位運算&#xff1f;二、如何使用1. 位與&#xff08;AND&#xff09;&#xff1a;&用途&#xff08;1&#xff09;數據清零&#xff08;2&#xff09;判斷奇偶 2. 位或&#xff08;OR&#xff09;&#xff1a;|用途&#xff08;1&#xff09;向下取整 3…

GO語言 gin框架 簡述

原文地址 基本路由 Go語言中文文檔 一、簡介 Gin是一個golang的輕量級web框架&#xff0c;性能不錯&#xff0c;API友好。 Gin支持Restful風格的API&#xff0c;可以直接從URL路徑上接收api參數或者URL參數&#xff0c;也可是使用json或者表單 數據綁定的方式接收參數。 Gin響…

【傳知代碼】BERT論文解讀及情感分類實戰-論文復現

文章目錄 概述原理介紹BERT模型架構任務1 Masked LM&#xff08;MLM&#xff09;任務2 Next Sentence Prediction (NSP)模型輸入下游任務微調GLUE數據集SQuAD v1.1 和 v2.0NER 情感分類實戰IMDB影評情感數據集數據集構建模型構建 核心代碼超參數設置訓練結果注意事項 小結 本文…

AIOps在線評測基準首階段建設完成,面向社區發布真實運維數據!

本文根據必示科技算法研究員、產品總監聶曉輝博士在2024 CCF國際AIOps挑戰賽線下宣講會上的演講整理成文。 2024年1月份OpenAIOps社區成立&#xff0c;隨著越來越多的社區成員加入&#xff0c;各項工作在有條不紊的推進中。在線評測基準系統&#xff08;AIOps Live Benchmark&a…

積鼎CFDPro水文水動力模型,專為中小流域洪水“四預”研發的流體仿真技術

水動力模型與水文模型是水利工程與水文學研究中不可或缺的兩大工具。水動力模型著重于流體運動的動力學機制&#xff0c;通過一系列方程組捕捉水流的時空變化&#xff0c;而概念性水文模型則側重于流域尺度的水文循環過程&#xff0c;利用物理概念與經驗關系進行近似模擬。兩者…

Windows系統部署YOLOv5 v6.1版本的訓練與推理環境保姆級教程

文章目錄 一 概述二 依賴環境(prerequisites)2.1 硬件環境2.2 軟件環境 三 環境安裝3.1 創建并激活虛擬環境3.2 安裝Pytorch與torchvision3.3 校驗Pytorch安裝3.4 下載 YOLOv5 v6.1 源碼3.5 安裝 YOLOv5 依賴3.6 下載預訓練模型3.7 安裝其他依賴3.8 測試環境安裝3.9 測試訓練流…

jupyter notebook更改位置

1.找到jupyer的配置文件 一般在c盤用戶的.jupter文件夾下 2. 用記事本打開這個配置文件&#xff0c;定位到c.NotebookApp.notebook_dir /path_to_your_directory 替換你的位置 3.找到jupyer圖標的位置&#xff0c;打開屬性 添加要存放的位置在目標文件的末尾&#xff0c;重新…

python | spacy,一個神奇的 Python 庫!

本文來源公眾號“python”&#xff0c;僅用于學術分享&#xff0c;侵權刪&#xff0c;干貨滿滿。 原文鏈接&#xff1a;spacy&#xff0c;一個神奇的 Python 庫&#xff01; 大家好&#xff0c;今天為大家分享一個神奇的 Python 庫 - spacy。 Github地址&#xff1a;https:/…

一個全面了解Xilinx FPGA IP核的窗口:《Xilinx系列FPGA芯片IP核詳解》(可下載)

隨著摩爾定律的逐漸放緩&#xff0c;傳統的芯片設計方法面臨著越來越多的挑戰。而FPGA以其并行處理能力和可編程性&#xff0c;為解決復雜問題提供了新的途徑。它允許設計者在同一個芯片上實現多種不同的功能模塊&#xff0c;極大地提高了資源的利用率和系統的綜合性能。 FPGA…

領域數據模型建設步驟

領域數據模型建設步驟 以某音樂app為例: 1.數據調研和業務調研&#xff0c;識別業務過程&#xff0c;實體&#xff0c;關鍵指標 業務過程&#xff1a;播放&#xff0c;收藏&#xff0c;下載&#xff0c;點擊&#xff0c;購買&#xff0c;支付 實體&#xff1a;音樂&#xff0c…

HCIA-ARP

ARP的由來 ARP這一種協議它會是在我們HCIA中第一個需要完全掌握的一個協議&#xff0c;不然對于數據通訊來說大家都會一直覺得很繞圈 協議棧&#xff0c;網線&#xff0c;網卡&#xff0c;它們組成了我們最小的數據通信的小脈絡注&#xff1a;可以了解ARP攻擊&#xff08;冒充訪…

使用Java和MyBatis獲取表頭與數據

使用Java和MyBatis獲取表頭與數據 在數據處理與展示中&#xff0c;經常需要將數據庫查詢結果中的表頭&#xff08;列名&#xff09;與實際數據提取出來。本文將介紹如何通過Java的JDBC和MyBatis來實現這一需求。 1. 使用JDBC獲取表頭與數據 在JDBC中&#xff0c;可以使用Res…

文獻解讀-群體基因組第二期|《中國人群中PAX2新生突變的檢測及表型分析:一項單中心研究》

關鍵詞&#xff1a;應用遺傳流行病學&#xff1b;群體測序&#xff1b;群體基因組&#xff1b;基因組變異檢測&#xff1b; 文獻簡介 標題&#xff08;英文&#xff09;&#xff1a;Detection of De Novo PAX2 Variants and Phenotypes in Chinese Population: A Single-Cente…

new CCDIKSolver( OOI.kira, iks ); // 創建逆運動學求解器

demo案例 new CCDIKSolver(OOI.kira, iks); 在使用某個特定的庫或框架來創建一個逆運動學&#xff08;Inverse Kinematics, IK&#xff09;求解器實例。逆運動學在機器人學、動畫和計算機圖形學等領域中非常重要&#xff0c;它用于根據期望的末端執行器&#xff08;如機器人的…

Compose第四彈 Compose項目

目標&#xff1a; 1.可供學習的Compose項目 一、官方提供項目 谷歌官方提供的Compose項目&#xff1a; GitHub - android/compose-samples: Official Jetpack Compose samples. 項目及主要頁面展現 1.1 Reply項目 1.首頁底部TAB欄 2.側邊欄菜單&#xff1a;拖動滑出和收起…

建設現代智能工業-智能化、數字化、自動化節能減排

建設現代智能工業-智能化節能減排 遵循“一體化”能源管理(Integrated Energy Management)的設計宗旨&#xff0c;集成城市各領域(如工業.交通、建筑等&#xff09;的能源生產和消費信息&#xff0c;面向城市政府、企業、公眾三類實體&#xff0c;提供“一體化”的綜合能源管理…