Android Telephony | SIM 卡管理和subId、slotId、phoneId 定义关系说明_android 获取 iccid phoneid slotid subid-程序员宅基地

技术标签: oracle  数据库  

相关业务背景

DSDS双卡双待 :手机可以插入两张手机卡,而且能同时待机,但是某一时刻只能有一张卡上有电话。

一个SIM卡代表一个账号,那么双卡手机就意味着多账户,需要增加多账户管理和业务处理。

  • 账号管理:双卡手机提供界面给设置默认打电话、发短信和上网卡等。
  • 业务管理:基于两卡的独立性,双卡设备需要提供双卡进行通话业务设置(呼叫限制、呼叫转移)和网络业务设置(数据开关、数据漫游开关、VoLTE、VoWiFi业务开关等)。

和单卡业务类似,只是处理前需要选定一个账号,因此就需要正确的subId、slotId、phoneId等参数确认和区分业务卡。

SIM卡有关ID介绍

为了区分不同的卡,在Android上实现了多种id,如:slotId、phoneId、subId等,定义区别如下:

XID 定义和特殊场景说明
ICCID

SIM 卡的唯一标识。

在SIM卡加载完成后,Telephony 以ICCID为关键字在数据库中查找,如果没有找到 ,则说明此卡第一次插入,则在数据库中添加此SIM卡记录(siminfo表);如果找到则更新原有记录,但是此记录在数据库中的序号不变,即subId不变。

Sub Id

siminfo表中的Primary Key,从1开始的整数,标识卡记录在数据库表中的顺序号。

第1张插入的卡是1,之后累加。

- SIM卡可以切换卡槽 ,但是subId不会变。phoneId和slotId会0/1变化。

- Android 平台,在手机关机时会将当前使用的SIM卡Slot ID设为-1,在下次开机时检测到加载成功的SIM卡后将对应的Slot ID设为0或1(这样当通过SubscriptionManager接口请求当前可用Sub info时,就能从db中检索SlotID不为-1的SIM卡即可)。

Phone Id Phone 实例对应的ID,双卡设备的phoneId是0或1。
Slot Id 卡槽ID,当前可以认为slotId 和 phoneId 是相同的。

ID 变化规则和关系

ICCID、Sub ID 和 slot ID 都是 siminfo 数据库中的字段

  • Phone ID 和 Slot ID 当前可认为是一样的,跟卡槽对应,卡1的 ID 是0,卡2是1;
  • 切换卡槽,subId不变,phoneId 和 slotId 变化
  • SubscrptionManager 提供接口对 phoneId 进行转换。
    • subId 指示当前使用的SIM卡,phoneId/slotId 只关注卡槽。
API 函数名 参数 ID 隐藏/公开 功能作用
getActiveSubscriptionInfo(int sudId) subId 公开 获取指定 subId 的当前可用的SIM卡信息
isNetworkRoaming(int subId) subId 公开 查询指定 subId 的漫游数据开关状态
getAcitiveSubscriptionInfoForSimSlotIndex(int slotIndex) slotId 公开 获取指定SlotId的当前可用SIM卡信息
getActiveSubscriptionInfoForIccIndex(String iccId) ICCID hide 获取指定ICCID的当前可用SIM卡信息
setDisplayName(String displayName, int subId) subId hide 将指定subId 的SIM卡显示名称保存到数据库
setDataRoaming(int roaming,  int subId) subId hide 将指定subId 的SIM卡漫游开关保存到数据库
getSlotIndex(int subId) subId hide 获取subId对应的slotId
getSubId(int slotIndex) subId hide 获取slotId对应的subId

数据库

双卡业务相关设置项分别保存在Settings 数据库、网络端(通话设置:呼叫转移和呼叫限制)和Telephony 数据库(telephony.db,需要权限)

获取telephony.db数据库文件:

adb  pull data/user_de/0/com.android.providers.telephony/databases

双卡设置在Settings 应用界面。

设置项 子设置项 Android KEY 保存位置
双卡设置 默认数据卡 Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION Settings数据库
默认通话卡 Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION
默认彩信卡 Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION
网络设置(卡 1和卡2) 数据开关 Settings.Global.Mobile_DATA + subId
数据漫游开关 Settings.Global.DATA_ROAMING + subId
网络模式选择 Settings.Global.PREFERRED_NETWORK_MODE + subId
VoLTE功能开关 SubscriptiionManager.ENHANCED_4G_MODE_ENABLED Telephony.db 的siminfo表
ViLTE功能开关 SubscriptiionManager.VT_IMS_ENABLED
WFC功能开关

SubscriptiionManager.WFC_IMS_ENABLED

代码案例

在注册状态变化时(onSubscriptionsChanged)更新PhoneId。

    //添加注册状态变化的监听器private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =new SubscriptionManager.OnSubscriptionsChangedListener() {@Overridepublic void onSubscriptionsChanged() {//获取上下文信息final Activity activity = getActivity();if (activity == null || activity.isFinishing() || activity.isDestroyed()) {return;}final List<SubscriptionInfo> mSubList =SubscriptionUtil.getAvailableSubscriptions(getContext());SubscriptionInfo mSubInfo = null;for (SubscriptionInfo subInfo : mSubList) {Log.d(TAG, "onSubscriptionsChanged: subInfo = " + subInfo.toString());if (subInfo.getSubscriptionId() == mSubId) {mSubInfo = subInfo;//校验PhoneId正常并更新的方法if (!SubscriptionManager.isValidPhoneId(mPhoneId)) {mPhoneId = SubscriptionManager.getPhoneId(mSubId);Log.d(TAG, "onSubscriptionsChanged: mPhoneId = " + mPhoneId);if (SubscriptionManager.isValidPhoneId(mPhoneId)) {mPhone = PhoneFactory.getPhone(mPhoneId);}}break;}}if (mSubInfo == null) {Log.d(TAG, "onSubscriptionsChanged: can't find subInfo for subId " + mSubId, so call finish()");}}};

通过subId获取phoneId。疑问:通过subid获取phoneId为什么会异常?
 

        if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {int mPhoneId = SubscriptionManager.getPhoneId(mSubId); //会异常啊if (!SubscriptionManager.isValidPhoneId(mPhoneId)) {mPhoneId = getPhoneIdFromSubId(mSubId, phoneId);log("getPhone: phoneIdFromSubId: " + phoneId);}//phoneId合法,则根据ID获取Phone对象if (SubscriptionManager.isValidPhoneId(phoneId)) {log("updatePhone :: isValidPhoneId: ");mPhone = PhoneFactory.getPhone(phoneId);}}//类似源码命名:getActiveSubscriptionInfoForIccIndex,通过iccid获取subId,用for。//通过subId 获取PhoneId(源码命名是For的)private int getPhoneIdFromSubId(int subId, int phoneId){int phoneIdFromSubId = phoneId;//获取注册信息列表List<SubscriptionInfo> subscriptionInfoList = mSubscriptionManager.getAvailableSubscriptionInfoList();String iccidForSub = null;if (subscriptionInfoList != null) {for (SubscriptionInfo si : subscriptionInfoList) {if (si.getSubscriptionId() == subId){iccidForSub = si.getIccId();break;}}}List<UiccCardInfo> cardsInfos = mTelephonyManager.getUiccCardsInfo();if (cardsInfo != null) {for (UiccCardInfo info : cardsInfos) {if (info != null) {String iccid = info.getIccId();if (iccidForSub != null && iccidForSub.equals(iccid)) {phoneIdFromSubId = info.getSlotIndex();break;}}}}return phoneIdFromSubId;}

这篇关于【笔记】Android Telephony | SIM 卡管理和subId、slotId、phoneId 定义关系说明的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zx249388847/article/details/136853644

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法