android中双卡双待的那些代码

news/2024/11/8 4:35:31/

这阵子忙着整理项目了,所以就没怎么出新的文章了,不过下面写的这篇文章对大家很有帮助。关于双卡双待的信息获取,包含了imeiphonenumberoperatorName(sim卡生产商,国内就主要指三大运营商了)、NetworkType(这里就主要是4G、3G等了)。

前言:

睡着国内的双卡手机出现,导致获取双卡的信息也是成了一个头痛的事了。google给开发者暴露的api还是停留在单卡上,所以在这里我就整理出相关的代码,让更多的猿友少走弯路。

首先从phonenumber的获取着手吧,顺便带着大家一起去看下相关的源码,以前获取phonenumber我是这么获取的:

((TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number();

这里就调用了TelephonyManagergetLine1Number方法,这里顺道去源码看看getLine1Number是怎么获取的:

/*** Returns the phone number string for line 1, for example, the MSISDN* for a GSM phone. Return null if it is unavailable.* <p>* Requires Permission:*   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}*   OR*   {@link android.Manifest.permission#READ_SMS}* <p>* The default SMS app can also use this.*/public String getLine1Number() {return getLine1Number(getSubId());}

注:我这里源码都是android-25下面的,刚看了下android-23下面的源码是这么调用的:

/*** Returns the phone number string for line 1, for example, the MSISDN* for a GSM phone. Return null if it is unavailable.* <p>* Requires Permission:*   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}*   OR*   {@link android.Manifest.permission#READ_SMS}* <p>* The default SMS app can also use this.*/public String getLine1Number() {return getLine1NumberForSubscriber(getDefaultSubscription());}

还是有些区别的,起码方法的调用是不一样的,所以建议你在看该篇文章的时候还是把compileSdk升到25
compileSdkVersion 25
可以看到25的api是继续调了:getLine1Number(getSubId())该方法,那就继续往下走吧:

/*** Returns the phone number string for line 1, for example, the MSISDN* for a GSM phone for a particular subscription. Return null if it is unavailable.* <p>* Requires Permission:*   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}*   OR*   {@link android.Manifest.permission#READ_SMS}* <p>* The default SMS app can also use this.** @param subId whose phone number for line 1 is returned* @hide*/public String getLine1Number(int subId) {String number = null;try {ITelephony telephony = getITelephony();if (telephony != null)number = telephony.getLine1NumberForDisplay(subId, mContext.getOpPackageName());} catch (RemoteException ex) {} catch (NullPointerException ex) {}if (number != null) {return number;}try {IPhoneSubInfo info = getSubscriberInfo();if (info == null)return null;return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName());} catch (RemoteException ex) {return null;} catch (NullPointerException ex) {// This could happen before phone restarts due to crashingreturn null;}}

看到这的时候真的是心灰意冷啊,为什么这么说,该方法竟然是hide类型的方法,对于这种方法咋们就用到反射了,后面会详细介绍的,看看它的参数是如何解释的:
@param subId whose phone number for line 1 is returned反正我是英语不好的哈,接着我就去查了查相关的说法,这里去看看这篇文章是如何解释的(subid指的是什么),简单来说subbed指的就是sim卡的索引了,当有一个sim卡的时候subid=1,有两个的时候subid=2。依次类推就可以知道有几个卡subid就是多少了。不过这里的subid还是可以通过反射来获取subid,后面也会讲到如何获取我们的subbed:

private static final String SIM_LINE_NUMBER = "getLine1Number";
private static final String SIM_STATE = "getSimState";public static String getSimPhonenumber(Context context, int slotIdx) {if (PermissionUtil.hasSelfPermission(context, Manifest.permission.READ_PHONE_STATE) ||PermissionUtil.hasSelfPermission(context, "android.permission.READ_PRIVILEGED_PHONE_STATE")) {Log.d(TAG, "READ_PHONE_STATE permission has BEEN granted to getSimPhonenumber().");if (getSimStateBySlotIdx(context, slotIdx)) {return (String) getSimByMethod(context, SIM_LINE_NUMBER, getSubidBySlotId(context, slotIdx));}return null;} else {Log.d(TAG, "READ_PHONE_STATE permission has NOT been granted to getSimPhonenumber().");return null;}
}/***获取相应卡的状态* @param slotIdx:0(sim1),1(sim2)* @return true:使用中;false:未使用中*/
public static boolean getSimStateBySlotIdx(Context context, int slotIdx) {boolean isReady = false;Object getSimState = getSimByMethod(context, SIM_STATE, slotIdx);if (getSimState != null) {int simState = Integer.parseInt(getSimState.toString());if ((simState != TelephonyManager.SIM_STATE_ABSENT) && (simState != TelephonyManager.SIM_STATE_UNKNOWN)) {isReady = true;}}return isReady;
}/*** 通过slotid获取相应卡的subid* @param context* @param slotId* @return*/
public static int getSubidBySlotId(Context context, int slotId) {SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);try {Class<?> telephonyClass = Class.forName(subscriptionManager.getClass().getName());Class<?>[] parameter = new Class[1];parameter[0] = int.class;Method getSimState = telephonyClass.getMethod("getSubId", parameter);Object[] obParameter = new Object[1];obParameter[0] = slotId;Object ob_phone = getSimState.invoke(subscriptionManager, obParameter);if (ob_phone != null) {Log.d(TAG, "slotId:" + slotId + ";" + ((int[]) ob_phone)[0]);return ((int[]) ob_phone)[0];}} catch (Exception e) {e.printStackTrace();}return -1;
}/**
*通过反射调用相应的方法
*
*/
public static Object getSimByMethod(Context context, String method, int param) {TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);try {Class<?> telephonyClass = Class.forName(telephony.getClass().getName());Class<?>[] parameter = new Class[1];parameter[0] = int.class;Method getSimState = telephonyClass.getMethod(method, parameter);Object[] obParameter = new Object[1];obParameter[0] = param;Object ob_phone = getSimState.invoke(telephony, obParameter);if (ob_phone != null) {return ob_phone;}} catch (Exception e) {e.printStackTrace();}return null;
}

可以看到getSimPhonenumber方法需要slotIdx参数,这里还是去这篇文章看看slotldx是咋回事(slotldx到底是啥玩意),通过了解后,slotldx指的是那个卡槽了,如果当前要获取卡1,slotldx=0;如果是卡2,slotldx=1;到此知道为啥getSimPhonenumber方法需要定义这么个参数了吧。至于说getSimState方法,还是一样通过反射去获取每个卡的状态的,这里就不赘述源码了。上面可以看到获取subId的代码了吧,就是getSubidBySlotId方法了,这里通过反射调用了SubscriptionManager类中的getSubId方法,需要的参数也是我们的slotId。源码如下:

/** @hide */
public static int[] getSubId(int slotId) {if (!isValidSlotId(slotId)) {logd("[getSubId]- fail");return null;}int[] subId = null;try {ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));if (iSub != null) {subId = iSub.getSubId(slotId);}} catch (RemoteException ex) {// ignore it}return subId;
}

还有imeioperatorNameNetworkType都可以通过相应的方法获取了:

private static final String SIM_OPERATOR_NAME = "getNetworkOperatorName";
private static final String SIM_NETWORK_TYPE = "getNetworkType";
private static final String SIM_IMEI = "getImei";//获取相应卡的imei
public static String getSimImei(Context context, int slotIdx) {if (PermissionUtil.hasSelfPermission(context, Manifest.permission.READ_PHONE_STATE) ||PermissionUtil.hasSelfPermission(context, "android.permission.READ_PRIVILEGED_PHONE_STATE")) {Log.d(TAG, "READ_PHONE_STATE permission has BEEN granted to getSimImei().");if (getSimStateBySlotIdx(context, slotIdx)) {//sim1if (slotIdx == 0) {//这里的参数传的是slotldxreturn (String) getSimByMethod(context, SIM_IMEI, 0);} else if (slotIdx == 1) {return (String) getSimByMethod(context, SIM_IMEI, 1);}}return null;} else {Log.d(TAG, "READ_PHONE_STATE permission has NOT been granted to getSimImei().");return null;}
}public static String getSimNetworkName(Context context, int slotIdx) {if (getSimStateBySlotIdx(context, slotIdx)) {return getNetworkName((int)getSimByMethod(context, SIM_NETWORK_TYPE, getSubidBySlotId(context, slotIdx)));}return "UNKNOWN";
}public static String getSimOperatorName(Context context, int slotIdx) {if (getSimStateBySlotIdx(context, slotIdx)) {return (String) getSimByMethod(context, SIM_OPERATOR_NAME, getSubidBySlotId(context, slotIdx));}return null;
}

到此相关的属性获取基本ok了,大家如果还需要获取什么属性,直接去TelephonyManager查看相关的源码。还有一个就是插卡和拔卡的监听、网络变化的监听:

//网络变化的监听
public class SimConnectReceive extends BroadcastReceiver {private static final String TAG = SimConnectReceive.class.getSimpleName();public final static String ACTION_SIM_STATE_CHANGED = ConnectivityManager.CONNECTIVITY_ACTION;@Overridepublic void onReceive(Context context, Intent intent) {if (intent.getAction().equals(ACTION_SIM_STATE_CHANGED)) {Log.d(TAG, "onReceive");EventBus.getDefault().post(new SimConnectChange());}}
}//插卡和拔卡的监听
public class SimStateReceive extends BroadcastReceiver {private static final String TAG = SimStateReceive.class.getSimpleName();public final static String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";@Overridepublic void onReceive(Context context, Intent intent) {if (intent.getAction().equals(ACTION_SIM_STATE_CHANGED)) {Log.d(TAG, "onReceive");EventBus.getDefault().post(new SimStateChange());}}
}

还有就是不要忘了manifest中权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

对于6.0的动态权限处理也是添加该权限的判断。

demo.png
最后贴上该功能的代码:
github传送门
thanks:DualSIMCard
有什么问题可以email我:a1002326270@163.com


http://www.ppmy.cn/news/553443.html

相关文章

Android双卡双待编程识别

&#xfeff;&#xfeff; 如今&#xff0c;尤其是在中国&#xff0c;双卡双待如此普及和如此广泛&#xff0c;双卡双待已经成为智能手机的事实上的标准。大势所趋&#xff0c;为此&#xff0c;Android从Android 5.1开始&#xff0c;从Android SDK API层面开始支持双卡双待或1个…

【后端】使用TS编写任务管理系统----Express

文章目录 常见的后端框架安装并且声明文件库项目基本配置编写任务管理后端API添加任务查看任务设置任务完成状态删除任务 总结 node -v v16.13.0https://github.com/dL-hx/server-side 常见的后端框架 expresskoa… 安装并且声明文件库 $ npm i express $ npm i types/exp…

DevOps系列文章之Docker部署web ssh工具sshwifty

一、介绍 1.sshwifty简介 sshwifty是一款Web SSH & Telnet&#xff08;WebSSH & WebTelnet 客户端工具。 2.shwifty 特点 shwifty 是为 Web 设计的 SSH 和 Telnet 连接器。它可以部署在您的计算机或服务器上&#xff0c;为任何兼容&#xff08;标准&#xff09;的网络…

CentOS下安装cups实现局域网共享HP1020打印机

前言 老式打印机旧电脑局域网打印机 准备工作 HP1020打印机&#xff1b;CentOS主机&#xff0c;并接入局域网&#xff0c;分配固定IP&#xff1b;Windows或Mac、Linux电脑一台。 将打印机usb连入CentOS主机。 安装打印机驱动 在/usr目录下新建Downloads文件夹 mkdir /us…

蔡康永:我要的三国就是威力无双。0氪玩家玩了两个礼拜后

我玩王者荣耀好几年了&#xff0c;每天都要撸几把&#xff0c;风雨无阻&#xff0c;不知道为什么&#xff0c;最近突然就不想玩了&#xff0c;想找点其他游戏玩玩。 想起了多年前玩街机游戏时候的青骢岁月&#xff0c;那时候要是能捡到一个游戏币比捡到钱还高兴。当时印象最深…

配置Confluent Schema Registry使用IAM认证连通AWS MSK

Confluent Schema Registry在运行时需要连通Kafka集群进行一些必要的操作,例如Confluent Schema Registry会在Kafka上创建并使用一个名为_schemas的Topic。另一方面,AWS MSK推荐使用的认证方式是IAM,这是开源Kafka集群所不具有的特性。当我们需要将Confluent Schema Registr…

如何设置笔记本电脑充电到70%就停止充电_笔记本电脑电池保护如何设置_win10设置电池保护_win10设置电池70%电量就停止充电

首先为了我的标题诈骗道歉——你根本无法在win10的系统设置里面找到任何有关于70&#xff05;电量停止充电的选项&#xff0c;这个选项是各大笔记本厂商设计的。 对于华为matebook16&#xff1a; 华为电脑管家&#xff1a; 在设置中心的嗲暖设置里面就可以选择了&#xff1a;…

关于ThinkPad笔记本电脑显示“电源已接通,未充电”

ThinkPad系列的笔记本经常会有电池方面的问题&#xff0c;最多的就是“电源已接通&#xff0c;未充电”这样令人头痛的问题&#xff08;我已遇到三次&#xff0c;换了一次电源&#xff09; 对于这种问题&#xff0c;我们基本尝试以下几种做法&#xff1a; 1.关机&#xff0c;拆…