Android 監聽雙卡信號強度(更新到android10

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章