Android M 判断手机是否有SIM卡的逆推

来源:互联网 发布:阿拉曼战役 知乎 编辑:程序博客网 时间:2024/05/22 15:49

一、一般的判断是从数据库中查找的:

先是:

Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI,null, selection, selectionArgs, null);

然后:

SubscriptionInfo subInfo = getSubInfoRecord(cursor);

最后:循环 游标 添加到 subList 中:

 if (subInfo != null)    {        if (subList == null)        {            subList = new ArrayList<SubscriptionInfo>();        }        subList.add(subInfo);    }

即:\frameworks\opt\telephony\src\java\com\android\internal\telephony\SubscriptionController.java
中的getSubInfo()的调用,这里会去查询数据库中存储的值。

二、直接从Modem中读取数据:

位置:\frameworks\base\telephony\java\android\telephony\TelephonyManager.java

流程如下:

2.1

telephonyManager.hasIccCard() 

2.2

public boolean hasIccCard() {    return hasIccCard(getDefaultSim());} 

2.3

    public boolean hasIccCard(int slotId) {        try {            ITelephony telephony = getITelephony();            if (telephony == null)                return false;            return telephony.hasIccCardUsingSlotId(slotId);        } catch (RemoteException ex) {            // Assume no ICC card if remote exception which shouldn't happen            return false;        } catch (NullPointerException ex) {            // This could happen before phone restarts due to crashing            return false;        }    }

2.4

位置:packages\services\Telephony\src\com\android\phone\PhoneInterfaceManager.java
PhoneInterfaceManager.java 继承了 ITelephony
所以 走到 PhoneInterfaceManager的hasIccCardUsingSlotId:

@Override    public boolean hasIccCardUsingSlotId(int slotId) {        int subId[] = mSubscriptionController.getSubIdUsingSlotId(slotId);        final Phone phone = getPhone(subId[0]);        if (subId != null && phone != null) {            return phone.getIccCard().hasIccCard();        } else {            return false;        }    }

2.5

位置:\frameworks\opt\telephony\src\java\com\android\internal\telephony\IccCard.java
在IccCard接口中:

public boolean hasIccCard();

位置:\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\IccCardProxy.java
然后IccCardProxy中实现:

public class IccCardProxy extends Handler implements IccCard

最后hasIccCard实现如下:

public boolean hasIccCard() {    synchronized (mLock) {        if (mUiccCard != null && mUiccCard.getCardState() != CardState.CARDSTATE_ABSENT) {            return true;        }        return false;    }}

2.6

位置:\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\UiccCard.java
UiccCard中:

public CardState getCardState() {    synchronized (mLock) {        return mCardState;    }}

2.7

UiccCard的构造函数和update函数都有对 mCardState 的赋值,当iccCard状态改变之后我们要做的就是更新操作:

public void update(Context c, CommandsInterface ci, IccCardStatus ics){    mCardState = ics.mCardState;    ... ...}

2.8

位置:\frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\UiccController.java
然后我们来看调用 update() 的地方,可以看到 UiccController的onGetIccCardStatusDone() 当中有调用:

    private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {        if (ar.exception != null) {            Rlog.e(LOG_TAG,"Error getting ICC status. "                    + "RIL_REQUEST_GET_ICC_STATUS should "                    + "never return an error", ar.exception);            return;        }        if (!isValidCardIndex(index)) {            Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index);            return;        }        IccCardStatus status = (IccCardStatus)ar.result;        if (mUiccCards[index] == null) {            //Create new card            mUiccCards[index] = new UiccCard(mContext, mCis[index], status, index);        } else {            //Update already existing card            mUiccCards[index].update(mContext, mCis[index] , status);        }        if (DBG) log("Notifying IccChangedRegistrants");        mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));    }

2.9

在handleMessage中,我们看到起调用:

case EVENT_ICC_STATUS_CHANGED:    mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));    break;case EVENT_GET_ICC_STATUS_DONE:    onGetIccCardStatusDone(ar, index);    break;

从下 往上我们可知道,
当消息为EVENT_GET_ICC_STATUS_DONE时,调用onGetIccCardStatusDone;
当消息为EVENT_ICC_STATUS_CHANGED 时,获取EVENT_GET_ICC_STATUS_DONE 消息。

位置:\frameworks\opt\telephony\src\java\com\android\internal\telephony\RIL.java
通过调用RILJ的getIccCardStatus来获取 icc 的状态:

@Override    public void    getIccCardStatus(Message result) {        //Note: This RIL request has not been renamed to ICC,        //       but this request is also valid for SIM and RUIM        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));        send(rr);    }

2.10

至于EVENT_ICC_STATUS_CHANGED 的消息,则是在UiccController的构造函数中 一开始的时候就注册了监听:

private UiccController(Context c, CommandsInterface []ci) {        if (DBG) log("Creating UiccController");        mContext = c;        mCis = ci;        for (int i = 0; i < mCis.length; i++) {            Integer index = new Integer(i);            mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);            mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index);            mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index);            mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index);        }    }

三、总结

至此,转入 RILJ 处理(进入getIccCardStatus( ),之后再转入modem处理)。
注册情况可参考UICC架构中的UiccController的构造函数的说明。

原创粉丝点击