28

I'd like to be able to do some stuff when the SIM state change, i.e. play a sound when SIM PIN is required, but I think there are no Broadcast events that can be intercepted by a broadcast receiver for this... registering for android.intent.action.PHONE_STATE does only tell you when the CALL-STATE changes.. An alternative can be starting a service that registers a PhoneStateListener and reacts upon a LISTEN_SERVICE_STATE (when the state is OUT-OF-STATE it can get the SIM state from the TelephonyManager and look if the state is SIM_STATE_PIN_REQUIRED). So, my questions are:

1) Is there any broadcast intent that I can use to intercept a SIM state change or a Service State change?

2) is it a bad idea to install a PhoneStateListener within a Service and use it to deliver intents to the Service itself upon the notification of a phone state changed received by the PhoneStateListener?

Gianni Costanzi
  • 6,054
  • 11
  • 48
  • 74

3 Answers3

33

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 Wasser
  • 93,459
  • 16
  • 209
  • 274
  • 1
    Many thanks! Where should I have found this information within the Android Reference Docs? Under which class is this intent documented? – Gianni Costanzi May 11 '12 at 15:00
  • 6
    I have no idea if or where this is documented. I've discovered this empirically by watching the logcat to see what Intents are broadcast when certain telephony events occur and then writing small test programs that listen for these events and dump their contents. Since a lot of this is vendor-specific you pretty much have to figure it out for yourself. Glad I could be of some help. – David Wasser May 11 '12 at 16:54
  • I've tested on my HTC One X and it works, many many thanks! I don't understand why some things are so poorly documented in the official SDK reference (or maybe the documentation exists but it is difficult to be found) – Gianni Costanzi May 12 '12 at 06:37
  • Thanks to you David, I was able to publish my first Android app SIM Locked Notifier: https://play.google.com/store/apps/details?id=org.slaytanic.SIMLockedRingNotifier – Gianni Costanzi May 15 '12 at 07:44
  • Congratulations! Best of luck on your application – David Wasser May 15 '12 at 08:58
  • Since you give me a great help showing me this broadcast event *SIM_STATE_CHANGED* I'll try asking you another thing.. I'm wondering about how to determine from which API level is this broadcast intent supported, since it is not documented anywhere.. I've asked a question [here](http://stackoverflow.com/questions/10861340/from-which-sdk-level-is-android-intent-action-sim-state-changed-broadcast-intent). – Gianni Costanzi Jun 02 '12 at 11:01
  • What does the IMSI state mean? – gonzobrains May 25 '13 at 03:09
  • 3
    it is not mentioned in the docs the android source code has these intent's with a TelephonyIntents class with a warning to never listen to them https://android.googlesource.com/platform/frameworks/base/+/cd92588/telephony/java/com/android/internal/telephony/TelephonyIntents.java – Illegal Argument Sep 19 '15 at 15:08
  • @IllegalArgument where can we find this warning? – Tim Apr 19 '16 at 12:44
5

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.
        }
    }
}
Tim
  • 41,901
  • 18
  • 127
  • 145
2

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.

VladimirVip
  • 384
  • 3
  • 13
  • "I believe that on some devices you will not get the internal broadcas" - I think you encounter a security feature where broadcast wont be delivered if the app has not yet been started by the user or force stopped – Patrick Jun 05 '15 at 13:17