2

I am trying to detect SMS received and read it via texttospeech.

when i declare the Broadcast Receiver in manifest it doesn't work. But it works when done dynamically in an activity.

I am aware that some Broadcast actions cant be caught in a receiver when declared in manifest and requires an activity(as mentioned here), but have seen people using RECEIVE_SMS in manifest as in here.

I don't know what I am doing wrong. Any help would be greatly appreciated!

AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.bulsy.smstalk1">
        <uses-permission android:name="android.permission.RECEIVE_SMS" />
        <uses-permission android:name="android.permission.READ_SMS" />
        <uses-permission android:name="android.permission.SEND_SMS"/>
        <uses-permission android:name="android.permission.READ_CONTACTS" />

        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <receiver android:name="com.bulsy.smstalk1.SmsListener"
                   android:enabled="true" 
                   android:permission="android.permission.BROADCAST_SMS"
                   android:exported="true">   
                <intent-filter android:priority="2147483647">//this doesnt work
                    <category android:name="android.intent.category.DEFAULT" />
                    <action android:name="android.provider.Telephony.SMS_RECEIVED" />
                </intent-filter>
            </receiver>
        </application>   
    </manifest>

SmsListener.java

public class SmsListener extends BroadcastReceiver{

    private SharedPreferences preferences;
    TextToSpeech textToSpeech;
    String msg_from;
    public SmsListener()
    {

    }

    @Override
    public void onReceive(final Context context, Intent intent) {
        // TODO Auto-generated method stub
        if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){

            Bundle bundle = intent.getExtras();           //---get the SMS message passed in---
            SmsMessage[] msgs = null;

            if (bundle != null){
                //---retrieve the SMS message received---
                try{
                    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]);
                        msg_from = msgs[i].getOriginatingAddress();
                        final String msgBody = msgs[i].getMessageBody();
                        textToSpeech = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
                            @Override
                            public void onInit(int status) {
                                if(status != TextToSpeech.ERROR) {
                                    textToSpeech.setLanguage(Locale.UK);
                                    String fromName = getContactName(context,msg_from);
                                    fromName = fromName==null? msg_from:fromName;
                                    textToSpeech.speak("You have a text message from " + fromName + ". Content: " + msgBody , TextToSpeech.QUEUE_FLUSH, null);
                                }
                            }
                        }
                        );


                    }
                }catch(Exception e){
//                            Log.d("Exception caught",e.getMessage());
                }
            }
        }
    }

MainActivity.java

    public class MainActivity extends AppCompatActivity {

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

        SmsListener smsListener = new SmsListener();//Dynamically setting the receiver. this works.
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.provider.Telephony.SMS_RECEIVED");
        this.registerReceiver(smsListener,filter);
    }
}
Community
  • 1
  • 1
Anil P Babu
  • 1,235
  • 3
  • 26
  • 47
  • 1
    Are you sure the ``'s `name` is pointing to the right place? When you test your manifest Receiver, are you launching your `MainActivity` at least once after installation? Btw, the `` is not necessary in the ``, and the `enabled` and `exported` attributes aren't needed on the ``. – Mike M. Sep 16 '16 at 07:50
  • The receiver should be pointing to the rightplace. com.bulsy.smstalk1.SmsListener. `com.bulsy.smstalk1` is my package name and `SmsListener` is my class name. Even tried with `.SmsListener` and `SmsListener`. None worked. I removed `enabled exported category` attributes. Still didn't work. – Anil P Babu Sep 16 '16 at 08:09
  • 1
    Yeah, the ``, `exported`, and `enabled` won't prevent it from working. I was just saying you don't need them. Those `name` attributes are fine, if your Receiver is in the same folder/package as `MainActivity`. Also, what about my other question? Are you running your `Activity` once after installation when you test the manifest Receiver? – Mike M. Sep 16 '16 at 08:19
  • Yes. It will be. It is the launcher activity. So in android studio if I launch the app in my phone installation takes place first and then the app is run with the launcher activity triggered. – Anil P Babu Sep 18 '16 at 03:00
  • 1
    How are you determining that the Receiver isn't working? I just noticed you don't have any log prints or `Toast`s or anything there. The TTS is probably not going to work in a manifest-registered instance, since the Receiver will die before the engine's ready. You'll need to move that functionality to a `Service`, in that case, but you should first see if that's the problem, if it's just the TTS not working. – Mike M. Sep 18 '16 at 05:38
  • 1
    It worked!! You got it spot on! Kindly post it as an answer if it doesn't matter, so i can accept it. – Anil P Babu Sep 19 '16 at 04:29
  • does this work on oreo? because i have the same problem broadcast is not working for oreo. rest of the versions are working fine. – Raza Dec 04 '18 at 06:53

1 Answers1

2

The root of the problem here is the lifetime of a manifest-registered Receiver instance. An instance of such a Receiver will only be alive until the onReceive() method completes. The TextToSpeech object will not be ready before the Receiver dies, and without any other indication of the Receiver working, it appears as though the Receiver has just failed.

The solution is to move the TextToSpeech functionality to a Service you can run from the Receiver, and pass the necessary info as extras on the Intent used to start it.

Mike M.
  • 38,532
  • 8
  • 99
  • 95
  • is an `IntentService` sufficient to execute whatever needs to be done when the SMS is received ? – Someone Somewhere Jun 25 '18 at 16:45
  • @SomeoneSomewhere Probably not for a `TextToSpeech` instance, for the same reason as the Receiver, unless you do something to block in `onHandleIntent()`. I've not tested anything, though. – Mike M. Jun 25 '18 at 19:27