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