Android4.4 Telephony流程分析——SIM卡开机时的初始化

本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉。


本文主要介绍MTK Android开机时,SIM卡的Framework部分初始化过程。

先看一段注释:

  1. /* Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed" 
  2. * notifications. When such notification arrives UiccController will call 
  3. * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS 
  4. * request appropriate tree of uicc objects will be created. 
  5. * 
  6. * Following is class diagram for uicc classes: 
  7. * 
  8. *                       UiccController 
  9. *                            # 
  10. *                            | 
  11. *                        UiccCard 
  12. *                          #   # 
  13. *                          |   ------------------ 
  14. *                    UiccCardApplication    CatService 
  15. *                      #            # 
  16. *                      |            | 
  17. *                 IccRecords    IccFileHandler 
  18. *                 ^ ^ ^           ^ ^ ^ ^ ^ 
  19. *    SIMRecords---- | |           | | | | ---SIMFileHandler 
  20. *    RuimRecords----- |           | | | ----RuimFileHandler 
  21. *    IsimUiccRecords---           | | -----UsimFileHandler 
  22. *                                 | ------CsimFileHandler 
  23. *                                 ----IsimFileHandler 
  24. * 
  25. * Legend: # stands for Composition 
  26. *         ^ stands for Generalization 
  27. */  

这是UiccController.Java文件开头对UiccController的注释,意思很明显UiccController是对Android SIM卡管理的控制器。

下面是SIM卡初始化序列图:



UiccController的初始化是在phone进程启动的时候,PhoneFactory调用makeDefaultPhone()创建默认的Phone,然后走MTK双卡流程中,调用MTKPhoneFactory.makeDefaultPhone()创建的,

  1. {  
  2.     for (int l2 = 0; l2 < PhoneConstants.GEMINI_SIM_NUM; l2++)  
  3.         if (j1 == l2)  
  4.             ai[l2] = j;  
  5.         else  
  6.             ai[l2] = 1;  
  7.   
  8.     I = new RIL(context, ai[0], l, 0);  
  9.     J = new RIL(context, ai[1], l, 1);  
  10. }  
  11. UiccController.make(context, I, 0);  
  12. UiccController.make(context, J, 1);  
  13. GSMPhone agsmphone[] = new GSMPhone[PhoneConstants.GEMINI_SIM_NUM];  

上面是反编译MTK的static_gemini_intermediates库看到的,在RIL创建完成时,使用UiccController.make()初始化:

  1. public static UiccController make(Context c, CommandsInterface ci, int simId) {  
  2.     synchronized (mLock) {  
  3.         if (FeatureOption.MTK_GEMINI_SUPPORT) {  
  4.             if(mInstance[simId] != null) {  
  5.                 throw new RuntimeException("UiccController.make() should only be called once");  
  6.             }  
  7.             mInstance[simId] = new UiccController(c, ci, simId);  
  8.             return mInstance[simId];  
  9.         } else {  
  10.             if (mInstance[0] != null) {  
  11.                 throw new RuntimeException("UiccController.make() should only be called once");  
  12.             }  
  13.             mInstance[0] = new UiccController(c, ci);  
  14.             return mInstance[0];  
  15.         }  
  16.     }  
  17. }  

UiccController的创建使用了单例模式,使用时调用getInstance()获取,

  1. public static UiccController getInstance(int simId) {  
  2.     synchronized (mLock) {  
  3.         if (FeatureOption.MTK_GEMINI_SUPPORT) {  
  4.             if(mInstance[simId] == null) {  
  5.                 throw new RuntimeException(  
  6.                     "UiccController.getInstance can't be called before make()");  
  7.             }  
  8.             return mInstance[simId];  
  9.         } else {  
  10.             if (mInstance[0] == null) {  
  11.                 throw new RuntimeException(  
  12.                     "UiccController.getInstance can't be called before make()");  
  13.             }  
  14.             return mInstance[0];  
  15.         }  
  16.     }  
  17. }  
  18.   
  19. private UiccController(Context c, CommandsInterface ci, int simId) {  
  20.     if (DBG) log("Creating UiccController simId " + simId);  
  21.     mContext = c;  
  22.     mCi = ci;  
  23.     mSimId = simId;  
  24.     mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);  
  25.     // TODO remove this once modem correctly notifies the unsols  
  26.     mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);  
  27.     mCi.registerForVirtualSimOn(this, EVENT_VIRTUAL_SIM_ON, null);  
  28.     mCi.registerForVirtualSimOff(this, EVENT_VIRTUAL_SIM_OFF, null);  
  29.     mCi.registerForSimMissing(this, EVENT_SIM_MISSING, null);  
  30.     mCi.registerForSimRecovery(this, EVENT_SIM_RECOVERY, null);  
  31.     mCi.registerForSimPlugOut(this, EVENT_SIM_PLUG_OUT, null);  
  32.     mCi.registerForSimPlugIn(this, EVENT_SIM_PLUG_IN, null);  
  33.     mCi.registerForInvalidSimDetected(this, EVENT_INVALID_SIM_DETECTED, null);  
  34.   
  35.     IntentFilter filter = new IntentFilter();  
  36.     filter.addAction("android.intent.action.ACTION_SHUTDOWN_IPO");  
  37.     filter.addAction(GeminiPhone.EVENT_INITIALIZATION_FRAMEWORK_DONE);  
  38.     filter.addAction(TelephonyIntents.ACTION_SIM_INFO_UPDATE);  
  39.     filter.addAction(ACTION_RESET_MODEM);  
  40.     mContext.registerReceiver(mIntentReceiver, filter);  
  41. }  

下面开始解析上面序列图:

step1,rild主动上报射频信号状态RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED。

step4,对信号进行判断,看看返回当前射频状态:

  1. private RadioState getRadioStateFromInt(int stateInt) {  
  2.     RadioState state;  
  3.   
  4.     /* RIL_RadioState ril.h */  
  5.     switch(stateInt) {  
  6.         case 0: state = RadioState.RADIO_OFF; break;  
  7.         case 1: state = RadioState.RADIO_UNAVAILABLE; break;  
  8.         case 2: state = RadioState.SIM_NOT_READY; break;  
  9.         case 3: state = RadioState.SIM_LOCKED_OR_ABSENT; break;  
  10.         case 4: state = RadioState.SIM_READY; break;  
  11.         case 5: state = RadioState.RUIM_NOT_READY; break;  
  12.         case 6: state = RadioState.RUIM_READY; break;  
  13.         case 7: state = RadioState.RUIM_LOCKED_OR_ABSENT; break;  
  14.         case 8: state = RadioState.NV_NOT_READY; break;  
  15.         case 9: state = RadioState.NV_READY; break;  
  16.         case 10: state = RadioState.RADIO_ON; break;  
  17.         case 15: state = RadioState.RADIO_OFF; break;  
  18.   
  19.         default:  
  20.             throw new RuntimeException(  
  21.                         "Unrecognized RIL_RadioState: " + stateInt);  
  22.     }  
  23.     return state;  
  24. }  

一般刚开机射频是RADIO_OFF的,之后转为RADIO_ON。

step6,设置射频的新状态,比较新状态和旧状态对比,看看发生了什么变化,step9~step13(还有其他的,没有列出)对变化作出响应,具体看下面的源码:

  1. /** 
  2.  * Store new RadioState and send notification based on the changes 
  3.  * 
  4.  * This function is called only by RIL.java when receiving unsolicited 
  5.  * RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 
  6.  * 
  7.  * RadioState has 5 values : RADIO_OFF, RADIO_UNAVAILABLE, SIM_NOT_READY, 
  8.  * SIM_LOCKED_OR_ABSENT, and SIM_READY. 
  9.  * 
  10.  * @param newState new RadioState decoded from RIL_UNSOL_RADIO_STATE_CHANGED 
  11.  */  
  12. protected void setRadioState(RadioState newState) {  
  13.     RadioState oldState;  
  14.   
  15.     synchronized (mStateMonitor) {  
  16.         Rlog.v(LOG_TAG, "setRadioState old: " + mState + " new " + newState);  
  17.   
  18.         oldState = mState;  
  19.         mState = newState;  
  20.   
  21.         // For CTA feature, sim1 is radio on if no sim card inserted.   
  22.         // In rild, it is in the state of SIM_LOCKED_OR_ABSENT.  
  23.         // if the sim card is pin locked, then after turn on radio of sim, it still the state of SIM_LOCKED_OR_ABSENT  
  24.         // special handle for this scenario, always notify radio changed if the state is SIM_LOCKED_OR_ABSENT  
  25.         if (oldState == mState && mState != RadioState.SIM_LOCKED_OR_ABSENT) {  
  26.             // no state transition  
  27.             return;  
  28.         }  
  29.   
  30.         // FIXME: Use Constants or Enums  
  31.         if(mState.getType() == 0) {  
  32.             mSimState = mState;  
  33.             mRuimState = mState;  
  34.             mNvState = mState;  
  35.         }  
  36.         else if (mState.getType() == 1) {  
  37.             if(mSimState != mState) {  
  38.                 mIccStatusChangedRegistrants.notifyRegistrants();  
  39.             }  
  40.             mSimState = mState;  
  41.         }  
  42.         else if (mState.getType() == 2) {  
  43.             if(mRuimState != mState) {  
  44.                 mIccStatusChangedRegistrants.notifyRegistrants();  
  45.             }  
  46.             mRuimState = mState;  
  47.         }  
  48.         else if (mState.getType() == 3) {  
  49.             mNvState = mState;  
  50.         }  
  51.   
  52.         mRadioStateChangedRegistrants.notifyRegistrants(new AsyncResult(null, mState, null));  
  53.   
  54.         if (mState.isAvailable() && !oldState.isAvailable()) {  
  55.             Rlog.d(LOG_TAG,"Notifying: radio available");  
  56.             mAvailRegistrants.notifyRegistrants();  
  57.             onRadioAvailable();  
  58.         }  
  59.   
  60.         if (!mState.isAvailable() && oldState.isAvailable()) {  
  61.             Rlog.d(LOG_TAG,"Notifying: radio not available");  
  62.             mNotAvailRegistrants.notifyRegistrants();  
  63.         }  
  64.   
  65.         if (mState.isOn() && !oldState.isOn()) {  
  66.             Rlog.d(LOG_TAG,"Notifying: Radio On");  
  67.             mOnRegistrants.notifyRegistrants();  
  68.         }  
  69.   
  70.         if ((!mState.isOn() || !mState.isAvailable())  
  71.             && !((!oldState.isOn() || !oldState.isAvailable()))  
  72.         ) {  
  73.             Rlog.d(LOG_TAG,"Notifying: radio off or not available");  
  74.             mOffOrNotAvailRegistrants.notifyRegistrants();  
  75.         }  
  76.   
  77.         /* Radio Technology Change events 
  78.          * NOTE: isGsm and isCdma have no common states in RADIO_OFF or RADIO_UNAVAILABLE; the 
  79.          *   current phone is determined by mPhoneType 
  80.          * NOTE: at startup no phone have been created and the RIL determines the mPhoneType 
  81.          *   looking based on the networkMode set by the PhoneFactory in the constructor 
  82.          */  
  83.   
  84.         if (mState.isGsm() && oldState.isCdma()) {  
  85.             Rlog.d(LOG_TAG,"Notifying: radio technology change CDMA to GSM");  
  86.             mVoiceRadioTechChangedRegistrants.notifyRegistrants();  
  87.         }  
  88.   
  89.         if (mState.isGsm() && !oldState.isOn() && (mPhoneType == PhoneConstants.PHONE_TYPE_CDMA)) {  
  90.             Rlog.d(LOG_TAG,"Notifying: radio technology change CDMA OFF to GSM");  
  91.             mVoiceRadioTechChangedRegistrants.notifyRegistrants();  
  92.         }  
  93.   
  94.         if (mState.isCdma() && oldState.isGsm()) {  
  95.             Rlog.d(LOG_TAG,"Notifying: radio technology change GSM to CDMA");  
  96.             mVoiceRadioTechChangedRegistrants.notifyRegistrants();  
  97.         }  
  98.   
  99.         if (mState.isCdma() && !oldState.isOn() && (mPhoneType == PhoneConstants.PHONE_TYPE_GSM)) {  
  100.             Rlog.d(LOG_TAG,"Notifying: radio technology change GSM OFF to CDMA");  
  101.             mVoiceRadioTechChangedRegistrants.notifyRegistrants();  
  102.         }  
  103.     }  
  104. }  

step7,通知注册了 mIccStatusChangedRegistrants的观察者,SIM卡(GSM卡和USIM卡)状态改变了,SIM卡准备好了。UiccController注册了它,看前面UiccController的构造函数,这里EVENT_ICC_STATUS_CHANGED关联了两个RIL URC事件,除了这里说的这个,还有 RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 。所以,当Radio或者SIM卡状态发生变化时,都会第一时间通知 UiccController。

step8,对它感兴趣的有,GsmServiceStateTracker(更新网络状态)、SIMRecords(用IccFileHandler读取SIM卡内置紧急号码)SIMRecordsEx(向RILD查询20位的Iccid)。

step14,处理step7中mIccStatusChangedRegistrants发出的通知。

step15~step16,请求查询现在SIM卡的状态,请求id位RIL_REQUEST_GET_SIM_STATUS。

step17~step20,Rild反馈RIL_REQUEST_GET_SIM_STATUS请求。step19,responseIccCardStatus()方法中会对SIM卡状态进行解析:

  1. private Object  
  2. responseIccCardStatus(Parcel p) {  
  3.     IccCardApplicationStatus appStatus;  
  4.   
  5.     IccCardStatus cardStatus = new IccCardStatus();  
  6.     cardStatus.setCardState(p.readInt());  
  7.     cardStatus.setUniversalPinState(p.readInt());  
  8.     cardStatus.mGsmUmtsSubscriptionAppIndex = p.readInt();  
  9.     cardStatus.mCdmaSubscriptionAppIndex = p.readInt();  
  10.     cardStatus.mImsSubscriptionAppIndex = p.readInt();  
  11.     int numApplications = p.readInt();  
  12.   
  13.     // limit to maximum allowed applications  
  14.     if (numApplications > IccCardStatus.CARD_MAX_APPS) {  
  15.         numApplications = IccCardStatus.CARD_MAX_APPS;  
  16.     }  
  17.     cardStatus.mApplications = new IccCardApplicationStatus[numApplications];  
  18.     for (int i = 0 ; i < numApplications ; i++) {  
  19.         appStatus = new IccCardApplicationStatus();  
  20.         appStatus.app_type       = appStatus.AppTypeFromRILInt(p.readInt());  
  21.         appStatus.app_state      = appStatus.AppStateFromRILInt(p.readInt());  
  22.         appStatus.perso_substate = appStatus.PersoSubstateFromRILInt(p.readInt());  
  23.         appStatus.aid            = p.readString();  
  24.         appStatus.app_label      = p.readString();  
  25.         appStatus.pin1_replaced  = p.readInt();  
  26.         appStatus.pin1           = appStatus.PinStateFromRILInt(p.readInt());  
  27.         appStatus.pin2           = appStatus.PinStateFromRILInt(p.readInt());  
  28.         cardStatus.mApplications[i] = appStatus;  
  29.     }  
  30.     return cardStatus;  
  31. }  

step21,onGetIccCardStatusDone()中更新SIM卡状态mUiccCard.update(),如果第一次运行,mUiccCard对象还没有创建,则先创建,再更新。

  1. private synchronized void onGetIccCardStatusDone(AsyncResult ar, boolean isUpdateSiminfo) {  
  2.     if (ar.exception != null) {  
  3.         Rlog.e(LOG_TAG,"[SIM " + mSimId + "] Error getting ICC status. "  
  4.                 + "RIL_REQUEST_GET_ICC_STATUS should "  
  5.                 + "never return an error", ar.exception);  
  6.         return;  
  7.     }  
  8.   
  9.     IccCardStatus status = (IccCardStatus)ar.result;  
  10.   
  11.     if (status.mCardState == IccCardStatus.CardState.CARDSTATE_PRESENT) {  
  12.         if (DBG) log("onGetIccCardStatusDone, disableSimMissingNotification because card is present");  
  13.         disableSimMissingNotification();  
  14.     }  
  15.   
  16.     if (mUiccCard == null) {  
  17.         //Create new card  
  18.         //ALPS01311133: We also need to update SIM Info when SIM hot plug.  
  19.         mUiccCard = new UiccCard(mContext, mCi, status, mSimId, isUpdateSiminfo);  
  20.     } else {  
  21.         //Update already existing card  
  22.         mUiccCard.update(mContext, mCi , status, isUpdateSiminfo);  
  23.     }  
  24.   
  25.     if (DBG) log("Notifying IccChangedRegistrants, isUpdateSiminfo:" + isUpdateSiminfo);  
  26.     mIccChangedRegistrants.notifyRegistrants();  
  27. }  

step23,更新时,如果 UiccCardApplication还没有创建,则先创建,同时需要根据SIM类型创建IccFileHandler具体子类对象(用来读取SIM数据)和IccRecords具体子类对象(记录SIM数据),否则直接更新。

  1. public void update(Context c, CommandsInterface ci, IccCardStatus ics, boolean isUpdateSimInfo) {  
  2.     synchronized (mLock) {  
  3.         if (mDestroyed) {  
  4.             loge("Updated after destroyed! Fix me!");  
  5.             return;  
  6.         }  
  7.         CardState oldState = mCardState;  
  8.         mCardState = ics.mCardState;  
  9.         mUniversalPinState = ics.mUniversalPinState;  
  10.         mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;  
  11.         mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;  
  12.         mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;  
  13.         mContext = c;  
  14.         mCi = ci;  
  15.         //update applications  
  16.         if (DBG) log(ics.mApplications.length + " applications");  
  17.         for ( int i = 0; i < mUiccApplications.length; i++) {  
  18.             if (mUiccApplications[i] == null) {  
  19.                 //Create newly added Applications  
  20.                 if (i < ics.mApplications.length) {  
  21.                     mUiccApplications[i] = new UiccCardApplication(this,  
  22.                             ics.mApplications[i], mContext, mCi);  
  23.                     mIccRecords = mUiccApplications[i].getIccRecords();  
  24.                     mIccFileHandler = mUiccApplications[i].getIccFileHandler();  
  25.                 }  
  26.             } else if (i >= ics.mApplications.length) {  
  27.                 //Delete removed applications  
  28.                 if (DBG) log("update mUiccApplications[" + i + "] dispose");  
  29.                 mUiccApplications[i].dispose();  
  30.                 mUiccApplications[i] = null;  
  31.             } else {  
  32.                 //Update the rest  
  33.                 if (DBG) log("update mUiccApplications[" + i + "] update");  
  34.                 mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);  
  35.             }  
  36.         }  
  37.         //if (!mIccRecordsList.isEmpty()){  
  38.        //    for (IccRecords mIccRecords: mIccRecordsList)  
  39.        if (mIccRecords != null)  
  40.            mIccRecords.registerForImsiReady(mHandler, EVENT_IMSI_READY, null);  
  41.   
  42.         if (DBG) log("update mUiccApplications.length: " + mUiccApplications.length);  
  43.         if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {  
  44.             // Initialize or Reinitialize CatService  
  45.             mCatService = CatService.getInstance(mCi,  
  46.                                                  mContext,  
  47.                                                  this);  
  48.         } else {  
  49.             if (mCatService != null) {  
  50.                 mCatService.dispose();  
  51.             }  
  52.             mCatService = null;  
  53.         }  
  54.   
  55.         sanitizeApplicationIndexes();  
  56.   
  57.   
  58.         RadioState radioState = mCi.getRadioState();  
  59.         if (DBG) log("update: radioState=" + radioState + " mLastRadioState="  
  60.                 + mLastRadioState);  
  61.         if(isUpdateSimInfo) { //SIM卡热插拔会用到这里  
  62.             // No notifications while radio is off or we just powering up  
  63.             //if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {  
  64.             if (radioState != RadioState.RADIO_UNAVAILABLE) {  
  65.                 if (mCardState == CardState.CARDSTATE_ABSENT) {  
  66.                     if (DBG) log("update: notify card removed");  
  67.                     mAbsentRegistrants.notifyRegistrants();  
  68.                     mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null));  
  69.                     //Update SIM inserted state  
  70.                     if (FeatureOption.MTK_GEMINI_SUPPORT) {  
  71.                         Phone defaultPhone = PhoneFactory.getDefaultPhone();  
  72.                         ((GeminiPhone)defaultPhone).setSimInsertedState(getMySimId(), false);  
  73.                     }  
  74.                 } else if (oldState == CardState.CARDSTATE_ABSENT &&  
  75.                         mCardState != CardState.CARDSTATE_ABSENT) {  
  76.                     if (DBG) log("update: notify card added");  
  77.                     mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));  
  78.                 }  
  79.             }  
  80.         }  
  81.         mLastRadioState = radioState;  
  82.     }  
  83. }  
UiccCardApplication执行update()操作时,如果此时SIM卡应用的状态是APPSTATE_READY,这要进行如下操作:

  1. if (mAppState != oldAppState) {  
  2.     if (DBG) log(oldAppType + " changed state: " + oldAppState + " -> " + mAppState);  
  3.     // If the app state turns to APPSTATE_READY, then query FDN status,  
  4.     //as it might have failed in earlier attempt.  
  5.     if (mAppState == AppState.APPSTATE_READY) {  
  6.         queryFdn();//读取FDN数据  
  7.         queryPin1State();//查询pin状态  
  8.     }  
  9.     notifyPinLockedRegistrantsIfNeeded(null);  
  10.     notifyReadyRegistrantsIfNeeded(null);  
  11. }  
如果SIM卡被锁住了,则会通知弹出解锁框。

step31,通知去读取SIM卡的IMSI。

step32,创建SIM Toolkit Telephony Service。

step33,通知所有关注mIccChangedRegistrants变化的观察者,如IccCardProxy(代理各种类型的SIM卡)、ServiceStateTracker。这里说一下ServiceStateTracker收到mIccChangedRegistrants变化通知后做的事件:

  1. case EVENT_ICC_CHANGED:  
  2.     onUpdateIccAvailability();  
  3.     break;  

onUpdateIccAvailability()方法是在 ServiceStateTracker中定义,在其子类中实现的,我们看看GsmServiceStateTracker中的实现:

  1. @Override  
  2. protected void onUpdateIccAvailability() {  
  3.     if (mUiccController == null ) {  
  4.         return;  
  5.     }  
  6.   
  7.     UiccCardApplication newUiccApplication =  
  8.             mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);  
  9.   
  10.     if (mUiccApplcation != newUiccApplication) {  
  11.         if (mUiccApplcation != null) {  
  12.             log("Removing stale icc objects.");  
  13.             mUiccApplcation.unregisterForReady(this);  
  14.             if (mIccRecords != null) {  
  15.                 mIccRecords.unregisterForRecordsLoaded(this);  
  16.             }  
  17.             mIccRecords = null;  
  18.             mUiccApplcation = null;  
  19.         }  
  20.         if (newUiccApplication != null) {  
  21.             log("New card found");  
  22.             mUiccApplcation = newUiccApplication;  
  23.             mIccRecords = mUiccApplcation.getIccRecords();  
  24.             mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);  
  25.             if (mIccRecords != null) {  
  26.                 mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);  
  27.             }  
  28.         }  
  29.     }  
  30. }  

这里很重要的操作就是注册了这两个事件监听:

  1. mIccRecords = mUiccApplcation.getIccRecords();//When the app state turns to APPSTATE_READY  
  2.    mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);//sim卡联系人读取后发出  



接下来还有很多状态变化,各种状态变化太复杂了,先说到这吧。。。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值