Question

I want to Toast a message, whenever an sms is received.

I tried with explicitly putting intent filter in manifest and I partly succeeded, except that I don't want to invoke it when the app is killed, so with the advice of some programmers here, I tried making the broadcast receiver programmatically by putting two buttons in my user interface, namely register and unregister, so their sole purpose is to register and unregister the broadcast receiver.

My main aim is to run the broadcast receiver even if the app is the background (meeting the condition, user pressed register and after either using another app).
I have been using this tutorial: http://www.javacodegeeks.com/2012/09/android-broadcast-receiver.html, but basically modified it with the sms receiver.

here is my code:

package gates.apps.automaticmessageresponder;

import android.app.Activity;
import android.content.ComponentName;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;

 public class MainActivity extends Activity {

SmsReceiver broadcastReceiver=new SmsReceiver();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

public void register(View view){

    this.registerReceiver(broadcastReceiver, new IntentFilter(
             "android.provider.Telephony.SMS_RECEIVED"));
    Log.e("register","pressed");  

}
public void unRegister(View view){

     this.unregisterReceiver(broadcastReceiver);
     Log.e("unregister","pressed");

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

}

And the other class

package gates.apps.automaticmessageresponder;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.util.Log;
import android.widget.Toast;

public class SmsReceiver extends BroadcastReceiver {

// Get the object of SmsManager
final SmsManager sms = SmsManager.getDefault();

@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub

    // Retrieves a map of extended data from the intent.
    final Bundle bundle = intent.getExtras();

    try {

        if (bundle != null) {

            final Object[] pdusObj = (Object[]) bundle.get("pdus");

            for (int i = 0; i < pdusObj.length; i++) {

                SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
                String phoneNumber = currentMessage.getDisplayOriginatingAddress();

                String senderNum = phoneNumber;
                String message = currentMessage.getDisplayMessageBody();

                Log.i("SmsReceiver", "senderNum: "+ senderNum + "; message: " + message);


               // Show alert
                int duration = Toast.LENGTH_LONG;
                Toast toast = Toast.makeText(context, "senderNum: "+ senderNum + ", message: " + message, duration);
                toast.show();

            } // end for loop
          } // bundle is null

    } catch (Exception e) {
        Log.e("SmsReceiver", "Exception smsReceiver" +e);
    }
}
}

I did not modify the manifest file except that I added the permission to receive sms. Even I am getting in log,the register pressed and unpressed. I think the problem lies in register receiver button is getting invoked even without click, is that an abnormal behaviour? or my perception is wrong?

Was it helpful?

Solution

Instead of declaring BroadcastReceiver in manifest try as follows within your activity, That will tie it with Activity life cycle (Don't forget to add permissions in manifest file) :

public class ExampleMainActivity extends Activity {

   //Activity Stuff

   private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, final Intent intent) {

            //Do things you want with message.

            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            builder.setTitle("Title");
            builder.setMessage("You may add your things here");
            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {

                    dialog.dismiss();
                }
            });
            builder.show();
        }
    };

    protected void onResume() {
        super.onResume();

        // OR YOU CAN REGISTER UNREGISTER AS YOU WANT

        this.registerReceiver(broadcastReceiver, new IntentFilter(
                 "android.provider.Telephony.SMS_RECEIVED"));
    };

    @Override
    protected void onPause() {
        super.onPause();

         // OR YOU CAN REGISTER UNREGISTER AS YOU WANT

         this.unregisterReceiver(broadcastReceiver);
    }
}

Edit :

You can check this alternating solution using application preferences :

package gates.apps.automaticmessageresponder;

import android.app.Activity;
import android.content.ComponentName;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;

 public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

public void register(View view){

    SharedPreferences preferences = context.getSharedPreferences("FILE_NAME", Context.MODE_PRIVATE);
    Editor edit = preferences.edit();
    edit.putBoolean("isRegistered", true);
    edit.commit();

    Log.e("register","pressed");  

}
public void unRegister(View view){

    SharedPreferences preferences = context.getSharedPreferences("FILE_NAME", Context.MODE_PRIVATE);
    Editor edit = preferences.edit();
    edit.putBoolean("isRegistered", false);
    edit.commit();

     Log.e("unregister","pressed");

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

}

And

package gates.apps.automaticmessageresponder;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.util.Log;
import android.widget.Toast;

public class SmsReceiver extends BroadcastReceiver {

// Get the object of SmsManager
final SmsManager sms = SmsManager.getDefault();

@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub

    // Retrieves a map of extended data from the intent.
    final Bundle bundle = intent.getExtras();

    try {

        if (bundle != null) {

            final Object[] pdusObj = (Object[]) bundle.get("pdus");

            for (int i = 0; i < pdusObj.length; i++) {

                SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
                String phoneNumber = currentMessage.getDisplayOriginatingAddress();

                String senderNum = phoneNumber;
                String message = currentMessage.getDisplayMessageBody();

                Log.i("SmsReceiver", "senderNum: "+ senderNum + "; message: " + message);

        SharedPreferences preferences = context.getSharedPreferences("FILE_NAME", Context.MODE_PRIVATE);
        boolean isRegistered = preferences.getBoolean("isRegistered", false);

                if(isRegistered ) {
                    // Show alert
                    int duration = Toast.LENGTH_LONG;
                    Toast toast = Toast.makeText(context, "senderNum: "+ senderNum + ", 
                                        message: " + message, duration);
                    toast.show();
        }

            } // end for loop
          } // bundle is null

    } catch (Exception e) {
        Log.e("SmsReceiver", "Exception smsReceiver" +e);

    }

}

}

OTHER TIPS

A reason for this not working is because the register/unregister isn't tied to the activity lifecycle, potentially leaving multiple broadcast receivers being registered. Consider this scenario:

User navigates to MainActivity then taps on Register button. Then, the user leaves the activity (without unregistering) and the application may not have been killed. Note here that your Broadcast Reciever is still registered.

Then, sometime later, the user navigates back to the activity and registers again. Now, you have two different broadcast receivers listening on the action. You've pretty much leaked a receiver.

On to a solution: Register your receiver in the manifest. Use a shared preference key/value pair to save the register button click. Then, when you're onReceive gets called use the key/value pair state to determine whether you want to Toast or not.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top