How can I send an SMS from a BroadcastReceiver and check its status?
Asked Answered
W

2

5

So this is my BroadcastReceiver

public class IncomingSMSListener extends BroadcastReceiver {
private static final String SMS_EXTRA_NAME = "pdus";

@Override
public void onReceive(Context context, Intent intent) {
    SmsMessage[] messages = fetchSMSMessagesFromIntent(intent);
}

private SmsMessage[] fetchSMSMessagesFromIntent(Intent intent) {
    ArrayList<SmsMessage> receivedMessages = new ArrayList<SmsMessage>();
    Object[] messages = (Object[]) intent.getExtras().get(SMS_EXTRA_NAME);
    for (Object message : messages) {
        SmsMessage finalMessage = SmsMessage
                .createFromPdu((byte[]) message);
        receivedMessages.add(finalMessage);
    }
    return receivedMessages.toArray(new SmsMessage[0]);
}

}

I'm being able to read the incoming message just fine and all, but let's say from here I want to forward the message to another phone number and make sure it got sent. I know I can do SmsManager.sendTextMessage() but how do I set up the PendingIntent part to be notified whether the SMS got sent or not?

Witte answered 15/8, 2011 at 2:58 Comment(0)
W
6

OK, ended up finding the solution in the end. Since the context passed in to the onReceive() method in the BroadCastReceiver doesn't let me register other BroadcastReceivers to listen for the "message sent" event, I ended up getting a grip of the app context and doing what follows:

In the BroadcastReceiver:

SmsManager smsManager = SmsManager.getDefault();
    Intent intent = new Intent(SENT_SMS_FLAG);
    PendingIntent sentIntent = PendingIntent.getBroadcast(context, 0,
            intent, 0);
    SMSForwarderApp.getAppContext().registerReceiver(
            new MessageSentListener(),
            new IntentFilter(SENT_SMS_FLAG));
    smsManager.sendTextMessage("Here goes the destination of the SMS", null,
            "Here goes the content of the SMS", sentIntent, null);

SENT_SMS_FLAG is simply a static string that uniquely identifies the intent I just made. My MessageSentListener looks like this:

public class MessageSentListener extends BroadcastReceiver{

@Override
public void onReceive(Context context, Intent intent) {
    int resultCode = this.getResultCode();
    boolean successfullySent = resultCode == Activity.RESULT_OK;
    //That boolean up there indicates the status of the message
    SMSForwarderApp.getAppContext().unregisterReceiver(this);
            //Notice how I get the app context again here and unregister this broadcast
            //receiver to clear it from the system since it won't be used again
}

}

Witte answered 15/8, 2011 at 23:12 Comment(1)
If you did not unregister MessageSentListener you could face multiple entries, a problem i was facing. Thank you!Living
O
1

If anyone else was like me and trying to find out how to do this in Kotlin, here's some code that might help in your quest:

Just a few things to note:

  1. You can test the try/catch by simply toggling Airplane Mode in the emulator.
  2. You can test a failed SMS in the emulator by composing a text that exceeds the normal SMS character limit.
  3. Because this is all in a try/catch block, please be aware that any exceptions that might arise due to API changes won't be highlighted in red in the Logcat window.
  4. Further note that Google Play has tightened requirements on apps that send SMS recently, so please be aware that if anyone intends to try to upload something like this to Google Play, they may be required to provide a lot of extra justification.

Here's the code (as heavily adapted from the US Naval Academy's site):

package com.example.texter

import android.app.Activity
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.telephony.SmsManager
import android.widget.Toast

class ClassTexter {
    fun mmSendText(mvText: String, mvNumber: String, mvApplicationContext: Context): Boolean {
        //Note: Because The Following Section is wrapped in a try/catch:
        //Exceptions might be trickier to spot in the Logcat since they aren't highlighted red.
        try {
            val mvSmsManager: SmsManager =
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    mvApplicationContext.getSystemService(SmsManager::class.java)
                } else {
                    SmsManager.getDefault()
                }
            val mvSentIntent = PendingIntent.getBroadcast(
                mvApplicationContext,
                0,
                Intent("SMS SENT"),
                PendingIntent.FLAG_IMMUTABLE
            )
            val mvDelvieredIntent = PendingIntent.getBroadcast(
                mvApplicationContext,
                0,
                Intent("SMS DELIVERED"),
                PendingIntent.FLAG_IMMUTABLE
            )

            val mvConfirmSentBroadcastReceiver: BroadcastReceiver =
                object : BroadcastReceiver() {
                    override fun onReceive(mvContext: Context, mvIntent: Intent) {
                        if (resultCode == Activity.RESULT_OK) {
                            Toast.makeText(
                                mvApplicationContext, "Text Dispatched!",
                                Toast.LENGTH_SHORT
                            ).show()
                            mvApplicationContext.unregisterReceiver(this) //<-- Otherwise, We'll Keep Displaying Previous Successes/Failures On Subsequent Ones
                        }
                        else
                        {
                            Toast.makeText(
                               mvApplicationContext, "Dispatch Failed!", //<-- This Part Can Be Tested By Exceeding SMS Character Limit
                               Toast.LENGTH_SHORT
                            ).show()
                            mvApplicationContext.unregisterReceiver(this) //<-- Otherwise, We'll Keep Displaying Previous Successes/Failures On Subsequent Ones
                        }
                    }
                }
            val mvConfirmDeliveryBroadcastReceiver: BroadcastReceiver =
                object : BroadcastReceiver() {
                    override fun onReceive(mvContext: Context, mvIntent: Intent) {
                        if (resultCode == Activity.RESULT_OK) {
                            Toast.makeText(
                                mvApplicationContext, "Text Delivered!",
                                Toast.LENGTH_SHORT
                            ).show()
                            mvApplicationContext.unregisterReceiver(this) //<-- Otherwise, We'll Keep Displaying Previous Successes/Failures On Subsequent Ones
                        }
                        else
                        {
                            Toast.makeText(
                                mvApplicationContext, "Delivery Failed!",
                                Toast.LENGTH_SHORT
                            ).show()
                            mvApplicationContext.unregisterReceiver(this) //<-- Otherwise, We'll Keep Displaying Previous Successes/Failures On Subsequent Ones
                        }
                    }
                }

            val mvSentIntentFilter = IntentFilter("SMS SENT")
            val mvDeliveredIntentFilter = IntentFilter("SMS DELIVERED")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                mvApplicationContext.registerReceiver(
                    mvConfirmSentBroadcastReceiver,
                    mvSentIntentFilter,
                    Context.RECEIVER_EXPORTED
                )
                mvApplicationContext.registerReceiver(
                    mvConfirmDeliveryBroadcastReceiver,
                    mvDeliveredIntentFilter,
                    Context.RECEIVER_EXPORTED
                )
            } else {
                mvApplicationContext.registerReceiver(
                    mvConfirmSentBroadcastReceiver,
                    mvSentIntentFilter
                )
                mvApplicationContext.registerReceiver(
                    mvConfirmDeliveryBroadcastReceiver,
                    mvDeliveredIntentFilter
                )
            }


            mvSmsManager.sendTextMessage(
                mvNumber.filter { it.isDigit() },
                null,
                mvText,
                mvSentIntent,
                mvDelvieredIntent
            )

            //Confirm With Toast
                Toast.makeText(
                    mvApplicationContext, "Please stand by!",
                    Toast.LENGTH_SHORT
                ).show()

            return true

        } catch (mvEx: Exception) {
            Toast.makeText(
                mvApplicationContext, "Please try again!", //<-- This Part Can Be Tested With "Airplane Mode"
                Toast.LENGTH_LONG
            ).show()
            mvEx.printStackTrace()
            return false
        }
    }
}
Oppress answered 19/12, 2023 at 20:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.