How to monitor SIM state change How to monitor SIM state change android android

How to monitor SIM state change


The Intent android.intent.action.SIM_STATE_CHANGED is broadcast when the SIM state changes. For example, on my HTC Desire with a T-Mobile SIM card, if I put the device into flight mode the following Intent is broadcast:

  • Intent: android.intent.action.SIM_STATE_CHANGED with extras: ss = NOT_READY, reason = null

If I then take it out of flight mode, the following Intents are broadcast:

  • Intent: android.intent.action.SIM_STATE_CHANGED with extras: ss = LOCKED, reason = PIN
  • Intent: android.intent.action.SIM_STATE_CHANGED with extras: ss = READY, reason = null
  • Intent: android.intent.action.SIM_STATE_CHANGED with extras: ss = IMSI, reason = null
  • Intent: android.intent.action.SIM_STATE_CHANGED with extras: ss = LOADED, reason = null

It is possible that different manufacturers and different models behave differently. As they say, "Your mileage may vary".


David's answer is spot on. I wanted to add some example code to help people get started with implementing such a state monitor.

/** * Handles broadcasts related to SIM card state changes. * <p> * Possible states that are received here are: * <p> * Documented: * ABSENT * NETWORK_LOCKED * PIN_REQUIRED * PUK_REQUIRED * READY * UNKNOWN * <p> * Undocumented: * NOT_READY (ICC interface is not ready, e.g. radio is off or powering on) * CARD_IO_ERROR (three consecutive times there was a SIM IO error) * IMSI (ICC IMSI is ready in property) * LOADED (all ICC records, including IMSI, are loaded) * <p> * Note: some of these are not documented in * https://developer.android.com/reference/android/telephony/TelephonyManager.html * but they can be found deeper in the source code, namely in com.android.internal.telephony.IccCardConstants. */public class SimStateChangedReceiver extends BroadcastReceiver {    /**     * This refers to com.android.internal.telehpony.IccCardConstants.INTENT_KEY_ICC_STATE.     * It seems not possible to refer it through a builtin class like TelephonyManager, so we     * define it here manually.     */    private static final String EXTRA_SIM_STATE = "ss";    @Override    public void onReceive(Context context, Intent intent) {        String state = intent.getExtras().getString(EXTRA_SIM_STATE);        if (state == null) {            return;        }        // Do stuff depending on state           switch (state) {                  case "ABSENT": break;            case "NETWORK_LOCKED": break;            // etc.        }    }}


The second approach of having a PhoneStateListener in a Service that listens for onServiceStateChanged() worked for me. I believe that on some devices you will not get the internal broadcast android.intent.action.SIM_STATE_CHANGED.