4

I'm trying to create an application that will trigger a toast message if the phone receives an SMS containing a string that is stored in the default preferences. My problem is that I'm having trouble getting the toast to appear when the SMS is received. I've tested my code for the receiver with a declared string and it works, but when I use the preference stored one, it doesn't come up. Here is my sample code:

public class Main extends Activity{
private static final int RESULT_SETTINGS = 1;


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

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_settings:
            Intent i = new Intent(this, Settings.class);
            startActivityForResult(i, RESULT_SETTINGS);
            break;
    }
    return true;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case RESULT_SETTINGS: display(); break;
    }
}

private void display(){
    TextView displayv = (TextView) findViewById(R.id.mysettings);
    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
    // codes that display
}

And here is the receiver

public class WakeSMS extends BroadcastReceiver{

@Override
public void onReceive(Context context, Intent intent){
    SharedPreferences sharedPrefs = context.getSharedPreferences("sharedPrefs", context.MODE_PRIVATE);
    String trigger=sharedPrefs.getString("smsstr","NULL");

    Bundle bundle = intent.getExtras();
    SmsMessage[] msgs = null;
    String str= "SMS from";
    if(bundle != null){
        Object[] pdus =(Object[])bundle.get("pdus");
        msgs=new SmsMessage[pdus.length];
        for (int i = 0; i<msgs.length; i++){
            msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
            if(i==0){
                str+= msgs[i].getOriginatingAddress();
                str+=": ";
            }
            str+=msgs[i].getMessageBody().toString();
        }
        if(str.contains(trigger)){
            Toast.makeText(context, str, Toast.LENGTH_LONG).show();
        }
    }
}}

In my main activity, I can get my code to display the prefs but in the receiver it fails to trigger the toast. Is there anything I'm doing wrong? (My receiver is called WakeSMS because It's supposed to trigger an alarm in the future, but right now I just want it to trigger a toast for testing)

Edit: I have a feeling that the way I've declared my preferences in my code is perhaps off, but I'm at a loss trying to figure out what I'm doing wrong since the preferences' values can be displayed in the main activity, but cannot be used in the receiver.

  • so you are looking for a specific string in your message ? – Rachit Mishra Sep 01 '13 at 10:43
  • Yes, it's what its supposed to do. One of the application preferences a user can set is a trigger (which can be a word, or phrase) that is supposed to trigger the toast. In my code for the receiver above I have it set to use whatever the user will define in the application preferences, but it doesn't work. If I comment the declaration for sharedPrefs and trigger, then replace trigger in the last if with any string such as "money" then I can get the toast to show up if I receive an SMS with the word "money" in it. – Work in Progress Sep 01 '13 at 10:48
  • I use a helper class for fetching the strings from shared preferences, after that I just instantiate the helper class and call its getter methods to get a string from shared preferences, this works for me always, as a matter of fact I have to check for few words on a message recieved in my app. – Rachit Mishra Sep 01 '13 at 10:54
  • I didn't think of using a helper class, but I think a helper class is a good alternative, however I think having to set getters and setters every time my application expands (this is only one functionality of the app) is going to be a problem. I'm hoping someone can help me figure out what's wrong with my code or a better way of getting the job done, that would be of so much help. Thanks for the input, by the way! – Work in Progress Sep 01 '13 at 11:03
  • this my helper class, http://hastebin.com/duliluyoji.avrasm, see this if it works, with some changes. – Rachit Mishra Sep 01 '13 at 11:05
  • I've tried using the helper class but it causes my application to force close whenever the receiver is called on the receipt of an SMS. – Work in Progress Sep 01 '13 at 11:23
  • `PreferencesManager pm = new PreferencesManager(context)`, then pm.getString("tigger"), personally a helper class removes the hassle of getting SharedPrefernces everywhere in your app. – Rachit Mishra Sep 01 '13 at 11:26

1 Answers1

9

getDefaultSharedPreferences() returns you a SharedPreferences file with the name based on the app package. It is like saying

context.getSharedPreferences("com.your.package_preferences", context.MODE_PRIVATE);

Then in your receiver you say

context.getSharedPreferences("sharedPrefs", context.MODE_PRIVATE);

which gets you shared preferences with a different name.

Therefore you are saving to one SharedPreference file but attempting to retrieve from another.

Try using

getSharedPreferences("MySmsSharedPrefs", context.MODE_PRIVATE);

in both save and restore. i.e in the Acvtivity and the Receiver


Here is the sauce to confirm: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/preference/PreferenceManager.java

**
 * Gets a SharedPreferences instance that points to the default file that is
 * used by the preference framework in the given context.
 * 
 * @param context The context of the preferences whose values are wanted.
 * @return A SharedPreferences instance that can be used to retrieve and
 *         listen to values of the preferences.
 */
public static SharedPreferences getDefaultSharedPreferences(Context context) {
    return context.getSharedPreferences(getDefaultSharedPreferencesName(context),
            getDefaultSharedPreferencesMode());
}

private static String getDefaultSharedPreferencesName(Context context) {
    return context.getPackageName() + "_preferences";
}
Blundell
  • 75,855
  • 30
  • 208
  • 233
  • i think this is the best answer ! – Rachit Mishra Sep 01 '13 at 11:25
  • I've gotten it to work. Thanks a lot! I guess the problem I had was in the receiver, I was calling the wrong preferences. I didn't know that it was possible to use the package name and _preferences in the first field for getSharedPreferences. – Work in Progress Sep 01 '13 at 11:36
  • I had the similar problem. I would save it in fragment when will try to get value from in onReceive it would give me different value. So tried this solution. It still didn't wok for me. Then I found a different answer which gave the Idea of using MODE_MULTI_PROCESS instead of MODE_PRIVATE. That worked like a charm. Here is that answer. https://stackoverflow.com/a/10551235/7099939 – M Shaban Ali Dec 21 '22 at 13:56