Android 监听双卡信号强度(更新到android10
背景介绍
Android一开始设计并没有考虑双卡的情况,很多APi都是对默认的sim卡做操作,需要监听两张sim卡的信号强度,必须采用一些特殊的方式,比如反射。
该文章基于android10的源代码做分析,对网上一种通过反射改PhoneStateListener中mSubId的方法(点这了解)做了修正,使其适应android10版本
相关Android类
android.telephony.PhoneStateListener
android.telephony.TelephonyManager
代码
Android 10 中在TelePhonymanager中更新了一个createForSubscriptionId(int),我们可以从源代码的头部注释中找到
* a listener to receive notification of telephony state changes.
* <p>
* The returned TelephonyManager will use the default subscription for all calls.
* To call an API for a specific subscription, use {@link #createForSubscriptionId(int)}. e.g.
* <code>
* telephonyManager = defaultSubTelephonyManager.createForSubscriptionId(subId);
* </code>
* <p>
createForSubscriptionId(int)方法参数的int是sim卡的subscription ID,返回一个TelePhonyManager实例,这个实例对应传入参数对应的sim卡,而不再对应默认的sim卡
调用方式如下
TelephonyManager mTM=((TelephonyManager)
mcontext.getSystemService(Context.TELEPHONY_SERVICE)).createForSubscriptionId(mSubID);
如果手机系统是android 10,那么可以直接 mPSL=new PhoneStateListener(),
然后mTM.listen(mPSL, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS |
PhoneStateListener.LISTEN_CELL_INFO | PhoneStateListener.LISTEN_CELL_LOCATION);
相关的使用说明在https://developer.android.google.cn/about/versions/10/non-sdk-q?hl=zh-cn中可以搜到
Landroid/telephony/PhoneStateListener;-><init>(Ljava/lang/Integer;)V # alternative: {@link PhoneStateListener()} use default constructor without passing subId. To listen for specific subscription, use {@TelephonyManager#createForSubscriptionId(int subId)} and {@link TelephonyManager#listen(PhoneStateListener psl)};
我们再查看TelePhonyManager源代码给的listen函数
public void listen(PhoneStateListener listener, int events) {
if (mContext == null) return;
try {
boolean notifyNow = (getITelephony() != null);
ITelephonyRegistry registry = getTelephonyRegistry();
if (registry != null) {
// subId from PhoneStateListener is deprecated Q on forward, use the subId from
// TelephonyManager instance. keep using subId from PhoneStateListener for pre-Q.
int subId = mSubId;
if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) {
// since mSubId in PhoneStateListener is deprecated from Q on forward, this is
// the only place to set mSubId and its for "informational" only.
// TODO: remove this once we completely get rid of mSubId in PhoneStateListener
listener.mSubId = (events == PhoneStateListener.LISTEN_NONE)
? SubscriptionManager.INVALID_SUBSCRIPTION_ID : subId;
} else if (listener.mSubId != null) {
subId = listener.mSubId;
}
registry.listenForSubscriber(subId, getOpPackageName(),
listener.callback, events, notifyNow);
} else {
Rlog.w(TAG, "telephony registry not ready.");
}
} catch (RemoteException ex) {
// system process dead
}
}
重点看中间有一个if判断,如果手机系统是android10或以上,listener的mSubId就会被telephonymanager中的subId替代,如果手机系统是android10以下,那么telephonymanager的subId就会被listener.mSubId替代。
所以存在这么一种情况,手机系统是android10以下,mTM=createForSubscriptionId(int)传入的是sim卡1的subId,然后listener中的mSubId是默认sim卡2的subId,然后mTM中的subId被listener中的替代。。。这个时候mTM监听的sim卡就不是sim卡1 的信号强度了。。。
所以在手机系统低于android10的时候需要把listener的mSubId也同步修改了,因为PhoneStateListener中的mSubID不是public属性,所以需要用到反射
private void setListeningSimCard(int subId) {
try {
Field field = PhoneStateListener.class.getDeclaredField("mSubId");
field.setAccessible(true);
// field.setInt(mPSL,subId);
field.set(mPSL,new Integer(subId));
}catch (Exception e){
e.printStackTrace();
}
}
注意:我找过网上许多博客,很多都是使用field.setInt()方法,但是在Android10中mSubId类型由int变成了Integer,所以需要改成field.set() ,希望这个能帮助到你。
最后给一个比较完整的调用的代码,两张不同的sim卡传入不同的subId,并创建对应的mTM和mPSL就可以实现对两张sim卡的同时监听。
TelephonyManager mTM;
PhoneStateListener mPSL;
Context mcontext; // 可以是activity的context
int subId; //从SubscriptionManager中可以拿到双卡对应的subId
mTM=((TelephonyManager) mcontext.getSystemService(Context.TELEPHONY_SERVICE)).createForSubscriptionId(subId);
mPSL = new PhoneStateListener();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
setListeningSimCard(subId);
}
mTM.listen(mPSL, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS | PhoneStateListener.LISTEN_CELL_INFO | PhoneStateListener.LISTEN_CELL_LOCATION);
参考
https://blog.csdn.net/qq_29333911/article/details/78962907
https://developer.android.google.cn/about/versions/10/non-sdk-q?hl=zh-cn