0

Basically what I'm trying to do is when I change the sim in my phone I want to send a message to a number that my sim has been changed. Here's my manifest: I have added the permission to send sms and intent to track the sim change

<uses-permission android:name="android.permission.SEND_SMS" />
   <receiver android:name=".SimChangeReceiver">
            <intent-filter>
                <action android:name="android.intent.action.SIM_STATE_CHANGED"/>
            </intent-filter>
        </receiver>

Here's the broadcast receiver I used.

public class SimChangeReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        Toast.makeText(context, "SIM state changed", Toast.LENGTH_SHORT).show();
        SmsManager smsmanager=SmsManager.getDefault();
        smsmanager.sendTextMessage(mynumber,null,"sim has been changed",null,null);

    }
}

The problem is when I change the sim, the Toast happens couple of times and the message gets send 4 times exactly to mynumber. Why is it happening? Can I put some limit to it to just send the message only once? I'm new to Android. So forgive me if I can't find the problem.

Asok
  • 1
  • 2

1 Answers1

0

The broadcast with action android.intent.action.SIM_STATE_CHANGED is fired multiple times when a SIM card is changed.

You will need to add a logic to suppress the duplicate calls when you are doing something critical like sending a message.

Refer this for more information: https://stackoverflow.com/a/10553473/1468093

EDIT:

The approach you should take to damp multiple broadcasts highly depends on your application for what you are trying to do. I can think of the following approaches:

  • You may damp it by storing the history and checking if the message was sent within last 5 seconds or whatever is your threshold

    @Override
    public void onReceive(Context context, Intent intent) {
        if (System.currentTimeMillis() - db.getLastActionTakenTime() > 5 * SECONDS) {
            // Do the thing
    
            db.saveActionTakenTime();
        }
    }
    
  • Start a new service to do what you want only if the service is not already started, this will ensure that the message is sent just once.

    @Override
    public void onReceive(Context context, Intent intent) {
        new Handler().postDelayed(new Runnable(
            @Override
            public void run() {
                doTheThing(context);
            }
        ), 2 * SECONDS);
    }
    
    public synchronized void doTheThing(Context context) {
        Intent serviceIntent = new Intent(context, MyActionService.class);
    
        if (peekService(serviceIntent) == null) { // To check if the service is not started
            context.startService(serviceIntent);
        }
    }
    
    
    public class MyActionService extends Service {
    
        public int onStartCommand() {
            // Do the thing
    
            return super.onStartCommand();
        }
    }
    

Note: Assuming your task takes at least 2 seconds to complete

Community
  • 1
  • 1
Kamran Ahmed
  • 7,661
  • 4
  • 30
  • 55
  • Can I really declare an intent in the manifest in the format android.intent.action.SIM_STATE_CHANGED with extras: ss = READY, reason = null ? Is there really a keyword extras and reason? – Asok Apr 24 '17 at 15:46
  • Nope, there isn't. And you cannot even trustfully put a check for one of the extra values as *It is possible that different manufacturers and different models behave differently* – Kamran Ahmed Apr 25 '17 at 04:46
  • I cannot think of any better logic than damping multiple calls within a few seconds by keeping a record of when it was fired last. – Kamran Ahmed Apr 25 '17 at 04:48
  • Can you please give me an example? – Asok Apr 25 '17 at 13:58
  • Check the updated answer. – Kamran Ahmed Apr 25 '17 at 16:17