android中雙卡雙待的那些代碼(增長當前sim卡網絡處理)

這陣子忙着整理項目了,因此就沒怎麼出新的文章了,不過下面寫的這篇文章對你們頗有幫助。關於雙卡雙待的信息獲取,包含了imeiphonenumberoperatorName(sim卡生產商,國內就主要指三大運營商了)、NetworkType(這裏就主要是4G、3G等了)。java

前言:

睡着國內的雙卡手機出現,致使獲取雙卡的信息也是成了一個頭痛的事了。google給開發者暴露的api仍是停留在單卡上,因此在這裏我就整理出相關的代碼,讓更多的猿友少走彎路。android

首先從phonenumber的獲取着手吧,順便帶着你們一塊兒去看下相關的源碼,之前獲取phonenumber我是這麼獲取的:git

((TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE))
                    .getLine1Number();
複製代碼

這裏就調用了TelephonyManagergetLine1Number方法,這裏順道去源碼看看getLine1Number是怎麼獲取的:github

/** * 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下面的源碼是這麼調用的:api

/** * 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升到25compileSdkVersion 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 crashing
            return null;
        }
    }
複製代碼

看到這的時候真的是心灰意冷啊,爲何這麼說,該方法居然是hide類型的方法,對於這種方法咋們就用到反射了,後面會詳細介紹的,看看它的參數是如何解釋的: @param subId whose phone number for line 1 is returned反正我是英語很差的哈,接着我就去查了查相關的說法,這裏去看看這篇文章是如何解釋的(subid指的是什麼),簡單來講subid指的就是sim卡的索引了,當有一個sim卡的時候subid=1,有兩個的時候subid=2。依次類推就能夠知道有幾個卡subid就是多少了。不過這裏的subid仍是能夠經過反射來獲取subid,後面也會講到如何獲取咱們的subid:app

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。源碼以下:ide

/** @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均可以經過相應的方法獲取了:post

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)) {
            //sim1
            if (slotIdx == 0) {
                //這裏的參數傳的是slotldx
                return (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查看相關的源碼。還有一個就是插卡和拔卡的監聽、網絡變化的監聽:ui

//網絡變化的監聽
public class SimConnectReceive extends BroadcastReceiver {
    private static final String TAG = SimConnectReceive.class.getSimpleName();
    public final static String ACTION_SIM_STATE_CHANGED = ConnectivityManager.CONNECTIVITY_ACTION;

    @Override
    public 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";

    @Override
    public 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" />

demo.png

歡迎客官到本店光臨:184793647(qq羣)

最後貼上該功能的代碼:

github傳送門

thanks:DualSIMCard

csdn傳送門

有什麼問題能夠email我:a1002326270@163.com

相關文章
相關標籤/搜索