I am trying to do mobile number verification without using third party. For this my logic is this:-
User enter their mobile number with country code
When they click on verify button a intent will send a sms to user-defined mobile number with random unique id
after that app broadcast will wait for 2 minute and when it receive sms then user can login or sign-up
Is this logic right or it need some modification?
To send sms i am using this code, but dont know how i can recieve and validate number.
String phoneNumber = "9999999999";
String smsBody = "Message from the API";
// Get the default instance of SmsManager
SmsManager smsManager = SmsManager.getDefault();
// Send a text based SMS
smsManager.sendTextMessage(phoneNumber, null, smsBody, null, null);
UPDATE:-
Not receiving message on samsung device.
this requires android.permission.INTERACT_ACROSS_USERS_FULL
First I generate a random number within range 10000 to 99999.
Random rNo = new Random();
final int code = rNo.nextInt((99999 - 10000) + 1) + 10000;
Next I display a popup mentioning the user that a message will be sent from the mobile to verify the number. This is done using AlertDialog.
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Verify Phone Number");
builder.setMessage("An sms will be sent to the number " + phNo + " for verification. Charges will apply as per your plan");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(final DialogInterface dialog, int which) {
//code to send sms here with the code value
final ProgressDialog progressdialog = ProgressDialog.show(getActivity(), "Waiting for SMS", "Please hold on");
final CountDownTimer timer = new CountDownTimer(120000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
Log.v("ranjapp", "Ticking " + millisUntilFinished / 1000);
progressdialog.setMessage("Waiting for the message " + millisUntilFinished / 1000);
}
#Override
public void onFinish() {
getActivity().unregisterReceiver(receiver);
progressdialog.dismiss();
}
}.start();
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
if (readSMS(intent, code)) {
Log.v("ranjapp", "SMS read");
timer.cancel();
try {
getActivity().unregisterReceiver(receiver);
} catch (Exception e) {
}
}
}
}
};
getActivity().registerReceiver(receiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
}
}
);
builder.setNegativeButton("CANCEL", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}
);
builder.show();
Explanation of above code:
After user acknowledges to send sms an sms is sent with the code to the entered number and this number should be the one that user is using himself. So we will wait for an sms with the code, to receive the sms and read its content we will create a BroadCastReceiver to listen to incoming sms.
Now also we need to start a timer so that we wait for only 2 minutes for the sms, so we start a CountDownTimer for 2 minutes at the end of 2 minutes the countdowntimer will unregister the receiver. The receiver is unregistered even if the code is received in the incoming sms so that we can free the resources.
Code to readSMS, if the code is found true is returned else false is returned,
boolean readSMS(Intent intent, int code) {
try {
Bundle bundle = intent.getExtras();
if (bundle != null) {
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();
if (message.contains(String.valueOf(code)))
return true;
}
}
} catch (Exception e) {
Log.v("ranjapp", "Exception here " + e.toString());
return false;
}
return false;
}
To send SMS use below method:
public static void sendSMS(Context context, String incomingNumber, String sms) {
DateTimeFormatter dtfOut = DateTimeFormat.forPattern("YYYY-MM-dd HH:MM:SS");
SmsManager smsManager = SmsManager.getDefault(); //send sms
try {
ArrayList<String> parts = smsManager.divideMessage(sms);
smsManager.sendMultipartTextMessage(incomingNumber, null, parts, null, null);
RecContDBHelper recContDBHelper = new RecContDBHelper(context);
recContDBHelper.insertRecord(new ContactData("", incomingNumber, dtfOut.print(MutableDateTime.now())));
Log.v("ranjith", "Sms to be sent is " + sms);
} catch (Exception e) {
Log.v("ranjith", e + "");
}
}
In AndroidManifest.xml you need to have these permissions:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
You can use a Content Provider to access the sms inbox!
ContentResolver contentResolver =getContentResolver();
Uri uri = Uri.parse("content://sms/inbox");
//query here
Related
I have a problem with sending SMS.
it keeps sending SMS. How to only send one SMS?
the text toast will keep on displaying, you have to close the app to stop sending sms.
I try the return, but it is not work.
private void sendSMS(String address, String time){
SmsManager smsManager = SmsManager.getDefault();
String name = sharedPreferences.getString("pre_key_name", null);
String phoneNum = sharedPreferences.getString("pre_key_phone", null);
String smsContent = time + name + "in" + address + "falls!";
smsManager.sendTextMessage(phoneNum, null, smsContent ,null, null);
Toast.makeText(context, "message send success", Toast.LENGTH_SHORT).show();
}
public Handler handler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.arg1 > 0){
countingView.setText(" " + msg.arg1 + context.getApplicationContext().getResources().getString(R.string.fall_contacts));
}else{
if(dialog != null){
dialog.dismiss();
if(isVibrate){
stopVibrate();
}
stopAlarm();
sendSMS(locationAddress, locationTime);
return;
}
timer.cancel();
}
}
};
To check whether an SMS has been sent or not, just use a boolean value.
private boolean hasSentSMS = false; //declaring outside of the handler
if (!hasSentSMS) {
sendSMS(locationAddress, locationTime);
hasSentSMS = true;
}
I am currently working on a simple android application to read an SMS and print it in TexView instead of Toast. but in receiver activity, we do not initialise "findbyid" so we can't print the SMS in textView. now I am showing SMS in Toast to test but I do not want it in a toast. I am also read questions/answer and also other articles but can't find what I want.
receiver activity,
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.util.Log;
import android.widget.Toast;
public class read_sms extends BroadcastReceiver {
// Get the object of SmsManager
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
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("SmsReciver", "senderNum: " + senderNum + ", message: " + message);
//ourSMS.getSmsDetails(senderNum, message);
// Show SMS notification
//Toast.makeText(context, "senderNum: "+ senderNum + ", message: " + message, Toast.LENGTH_LONG).show();
if(message.equals("Milind")){
Toast.makeText(context, "sms matched", Toast.LENGTH_LONG).show();
}else {
Toast.makeText(context, "not matched", Toast.LENGTH_LONG).show();
}
} // end of for loop
} // bundle
} catch (Exception e) {
// TODO: handle exception
Log.e("SmsReciver", "Exception smsReciver" + e);
}
}
}
my home activity is empty because I can't find which code placed here.
public class home extends AppCompatActivity {
TextView SMS_textview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
SMS_textview = (TextView) findViewById(R.id.sms_text);
}
}
change that TextView to
public static TextView SMS_textview;
add method
public void recivedSms(String message)
{
try
{
SMS_textview.setText(message);
}
catch (Exception e)
{
}
}
in read_sms class add the following code when you recieve sms
home Sms = new home();
Sms.recivedSms(message );
Register your Receiver in your activity whenever you Receive a text in receiver
use this code in your Receiver class
Intent broadcastIntent = new Intent();
broadcastIntent.putExtra("your key", your Value);
broadcastIntent.setAction("link from you have recieve a text");
context.sendBroadcast(broadcastIntent);
after this register a broadcast Receiver in your activity like this
private void registerSmsReciever() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("link from you have recieve a text");
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("onReceive", "Sms recieved in progress");
String message= intent.getStringExtra("key");
textView.setText(intent.getStringExtra("key"));
}
};
registerReceiver(broadcastReceiver, intentFilter);
}
I need to set TextView object of Main3Activity (Activity class) from IncomingSms (Non activity class).
public class IncomingSms extends BroadcastReceiver {
final SmsManager sms = SmsManager.getDefault();
#Override
public void onReceive(Context context, Intent 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 senderNum = currentMessage.getDisplayOriginatingAddress();
String message = currentMessage.getDisplayMessageBody();
if (message.equalsIgnoreCase("FIRE DETECTED")) {
//Problem start here: I cant able to set TextView object of Main3Activity
Main3Activity main3Activity = new Main3Activity();
TextView tv = (TextView) main3Activity.findViewById(R.id.firealert);
tv.setText(message);
//Problem end here
Log.i("SmsReceived", "senderNum: " + senderNum + "; message: " + message);
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, message, duration);
toast.show();
}
}
}
} catch(Exception e) {
Log.e("SmsReceiver", "Exception smsReceiver" + e);
}
}
}
create an interface class save it as java class then
public interface SmsListener {
public void messageReceived(String messageText);
}
and
final SmsManager sms = SmsManager.getDefault();
private static SmsListener mListener;
#Override
public void onReceive(Context context, Intent 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 senderNum = currentMessage.getDisplayOriginatingAddress();
String message = currentMessage.getDisplayMessageBody();
if (message.equalsIgnoreCase("FIRE DETECTED") ){
mListener.messageReceived(message); //add this
Log.i("SmsReceived", "senderNum: "+ senderNum + "; message: " + message);
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, message, duration);
toast.show();
}
}
}
} catch (Exception e) {
Log.e("SmsReceiver", "Exception smsReceiver" +e);
}
}
public static void bindListener(SmsListener listener) {
mListener = listener;
}
And in your Main3Activity onCreate method
TextView tv=(TextView) main3Activity.findViewById(R.id.firealert);
SmsReceiver.bindListener(new SmsListener() {
#Override
public void messageReceived(String messageText) {
Log.d("Text",messageText);
tv.setText(messageText);
}
});
You can't create the activity instance like that.
Solution:
1. Create a broadcast receiver in your activity and register for a custom intent.
2. Send a custom broadcast intent from your sms receiver. So basically that will reach activity receiver and then you can simply update the text there.
In case your activity is not started, simply create a activity intent and pass the sms text as part of the intent extras.
I am trying to send an urgent SMS from my application. I have to make sure that the SMS is being sent successfully.
The SMS is being sent after the boot of the Android system and after a check is being made.
So I have a service class that handles the BOOT_COMPLETED intent-filter. This class makes a check and if something is true then it tries to send an SMS message via another class that "extends Service"
After it makes sure that the sms is successfully sent, both services (the one that handles the boot call and the one that sends the sms) must exit.
Question 1: How to make my sms sending function be called with a timeout without getting the application being unresponsive message? Currently I am using this (I don't know if it is the correct way to do it, though it works):
Timer mTimer = new Timer();
//wait a small timeout prior to sending the message.
mTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
this.cancel(); //I don't want to run the timer more than once
sms_sender sms = new sms_sender();
sms.sendSMS(phoneNumber, messageText);
}
}, 30000, 30000); //run sendSMS() after 30 seconds
Question 2: How to implement the sendSMS function so as to retry every 30 seconds after realizing that the last attempt was a fail?
Question 3: How to stop both services after I realize that the SMS was successfully sent?
This is my code which does not work:
public class sms_sender extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
final String SENT = "SMS_SENT";
public void sendSMS(final String phoneNumber, final String message, final boolean check_result)
{
PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(SENT), 0);
registerReceiver(new BroadcastReceiver(){
#Override
public void onReceive(Context arg0, Intent arg1) {
if(!check_result)
return;
switch (getResultCode())
{
case Activity.RESULT_OK:
//exit
stopSelf();
return;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
case SmsManager.RESULT_ERROR_NO_SERVICE:
case SmsManager.RESULT_ERROR_NULL_PDU:
case SmsManager.RESULT_ERROR_RADIO_OFF:
//try again in 1 minute
Timer mTimer = new Timer();
mTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
this.cancel(); //no need to run again, if it fails, this exact code will run again
sendSMS(phoneNumber, message, true);
}
}, 60000, 60000);
return;
}
}
}, new IntentFilter(SENT));
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNumber, null, message, sentPI, null);
}
}
Currently the program crashes on the PendingIntent call. I tried to implement the BroadCastReceiver on the onCreate method using private member variables so as to call the sendSMS() function again through the onReceive method, but the onReceive never seemed to run.
-- EDIT --
So, this is my final working code. I guess that my case is special because it doesn't work on a UI thread. I have a Broadcast Receiver that runs on Boot. I am trying to send an SMS message until it is successfully sent.
This Boot Broadcast Receiver starts a service. This is some code from it:
public class service extends Service{
static public service serv;
//member variable. Initializing to null so as to know whether to unregister the service or not
private BroadcastReceiver messageSent = null;
...
...
#Override
public void onStart(Intent intent, int startid)
{
serv=this; //will use this static variable in order to shutdown the service when the message is successfully sent
...
...
if(somethingIsTrue()){
//register receiver
messageSent = new sent_message();
registerReceiver(messageSent, new IntentFilter(sms_sender.INTENT_MESSAGE_SENT));
startMessageServiceIntent(messageText, phoneNumber); //function code can be found on accepted answer
}
}
}
The sent_message class is the following:
public class sent_message extends BroadcastReceiver {
private Context pubCon;
private void startMessageServiceIntent(String message, String receiver) {
Intent i = new Intent(pubCon, sms_sender.class);
i.putExtra(sms_sender.EXTRA_MESSAGE, message);
i.putExtra(sms_sender.EXTRA_RECEIVERS, new String[] { receiver });
pubCon.startService(i);
}
#Override
public void onReceive(Context context, Intent intent) {
pubCon=context;
switch (getResultCode()) {
case Activity.RESULT_OK:
//all went OK, stop the service where this is called from
service.serv.stopSelf();
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
case SmsManager.RESULT_ERROR_NO_SERVICE:
case SmsManager.RESULT_ERROR_NULL_PDU:
case SmsManager.RESULT_ERROR_RADIO_OFF:
//try sending the message again after 30s
new Handler().postDelayed(new Runnable(){
#Override
public void run(){
startMessageServiceIntent(service.messageText, service.phoneNumber);
}
}, 30000);
break;
}
}
}
And a simplified (accepts only one receiver) version of the sms_sender class is the following:
public class sms_sender extends IntentService {
public static final String INTENT_MESSAGE_SENT = "message.sent";
public static final String INTENT_MESSAGE_DELIVERED = "message.delivered";
public static final String EXTRA_MESSAGE = "extra.message";
public static final String EXTRA_RECEIVERS = "extra.receivers";
public sms_sender() {
super("sms_sender");
}
private static class IDGenerator {
private static final AtomicInteger counter = new AtomicInteger();
public static int nextValue() {
return counter.getAndIncrement();
}
}
public void sendSMS(String message, String receiver) {
SmsManager sm = SmsManager.getDefault();
PendingIntent sentPI = null;
Intent sentIntent = new Intent(INTENT_MESSAGE_SENT);
int sentID = IDGenerator.nextValue();
sentPI = PendingIntent.getBroadcast(sms_sender.this, sentID, sentIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
try {
sm.sendTextMessage(receiver, null, message, sentPI, null);
} catch (IllegalArgumentException e) {
System.out.println("Illegal argument");
}
}
protected void onHandleIntent(Intent intent) {
String message = intent.getStringExtra(EXTRA_MESSAGE);
String[] receivers = intent.getStringArrayExtra(EXTRA_RECEIVERS);
sendSMS(message, receivers[0]);
}
}
Here is what I have done:
public class SMSSender extends IntentService {
public static final String INTENT_MESSAGE_SENT = "message.sent";
public static final String INTENT_MESSAGE_DELIVERED = "message.delivered";
public static final String EXTRA_MESSAGE = "extra.message";
public static final String EXTRA_RECEIVERS = "extra.receivers";
public SMSSender() {
super("SMSSender");
}
private final String TAG = "SendSMS";
private static class IDGenerator {
private static final AtomicInteger counter = new AtomicInteger();
public static int nextValue() {
return counter.getAndIncrement();
}
}
private void sendSMS(String message, String[] receivers) {
SmsManager sm = SmsManager.getDefault();
ArrayList<String> parts = sm.divideMessage(message);
PendingIntent sentPI = null;
PendingIntent deliveredPI = null;
Intent sentIntent = new Intent(INTENT_MESSAGE_SENT);
int sentID = IDGenerator.nextValue();
sentPI = PendingIntent.getBroadcast(SMSSender.this, sentID, sentIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
Intent deliveryIntent = new Intent(INTENT_MESSAGE_DELIVERED);
int deliveredID = IDGenerator.nextValue();
deliveredPI = PendingIntent.getBroadcast(SMSSender.this, deliveredID,
deliveryIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Log.i(TAG, "sending SMS: parts: " + parts.size() + " message: "
+ message);
if (parts.size() > 1) {
ArrayList<PendingIntent> sentIntents = null;
ArrayList<PendingIntent> deliveredIntents = null;
sentIntents = new ArrayList<PendingIntent>();
deliveredIntents = new ArrayList<PendingIntent>();
for (int i = 0; i < parts.size(); i++) {
sentIntents.add(sentPI);
deliveredIntents.add(deliveredPI);
}
for (String receiver : receivers) {
try {
sm.sendMultipartTextMessage(receiver, null, parts,
sentIntents, deliveredIntents);
} catch (IllegalArgumentException e) {
Log.e(TAG, "illegal receiver: " + receiver);
}
}
} else {
for (String receiver : receivers) {
try {
sm.sendTextMessage(receiver, null, parts.get(0), sentPI,
deliveredPI);
} catch (IllegalArgumentException e) {
Log.e(TAG, "illegal receiver: " + receiver);
}
}
}
}
#Override
protected void onHandleIntent(Intent intent) {
String message = intent.getStringExtra(EXTRA_MESSAGE);
String[] receivers = intent.getStringArrayExtra(EXTRA_RECEIVERS);
sendSMS(message, receivers);
}
And to use it:
private void startMessageServiceIntent(String message, String receiver) {
Intent i = new Intent(context, SMSSender.class);
i.putExtra(SMSSender.EXTRA_MESSAGE, message);
i.putExtra(SMSSender.EXTRA_RECEIVERS, new String[] { receiver });
startService(i)
}
Notice it supports multiple receivers, which this method does not demonstrate/use.
Remember in your manifest:
<uses-permission android:name="android.permission.SEND_SMS" />
<service android:name="your.package.SMSSender" android:enabled="true" />
Optionally you can listen for when messages are sent and/or delivered:
#Override
protected void onCreate() {
...
// ---when the SMS has been sent---
private BroadcastReceiver messageSent; // <- stored as a field
messageSent = new SentMessage();
registerReceiver(messageSent, new IntentFilter(SMSSender.INTENT_MESSAGE_SENT));
// ---when the SMS has been delivered---
private BroadcastReceiver messageDelivered; // <- stored as a field
messageDelivered = new MessageDelivered();
registerReceiver(messageDelivered, new IntentFilter(
SMSSender.INTENT_MESSAGE_DELIVERED));
}
#Override
protected void onDestroy() { // remember to unregister
unregisterReceiver(messageSent);
unregisterReceiver(messageDelivered );
}
I know this does not demonstrate answers to all your questions but I hope that it is sufficient.
Edit: Added my implementations of messageSent and messageDelivered
These are specific to my implementation, so includes some code that you cannot use, it is simply for demonstration.
Message sent:
public class SentMessage extends BroadcastReceiver {
private final String TAG = "SentMessage";
#Override
public void onReceive(Context context, Intent intent) {
long _id = intent.getLongExtra(EXTRA_ID, -1);
long protocol_id = intent.getLongExtra(EXTRA_PROTOCOL, -1);
Log.d(TAG, "SentMessage");
switch (getResultCode()) {
case Activity.RESULT_OK:
Log.d(TAG, "RESULT_OK");
if (MessageData.sentMessage(_id, protocol_id)) {
try {
Database.messageSent(_id);
} catch (DatabaseRowNotFoundException e) {
Log.e(TAG, e.toString(), e);
}
}
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Log.d(TAG, "RESULT_ERROR_GENERIC_FAILURE");
MessageData.postponeMessage(_id);
ApplicationData.hasSignal(false);
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Log.d(TAG, "RESULT_ERROR_NO_SERVICE");
MessageData.postponeMessage(_id);
ApplicationData.hasSignal(false);
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Log.d(TAG, "RESULT_ERROR_NULL_PDU");
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Log.d(TAG, "RESULT_ERROR_RADIO_OFF");
MessageData.postponeMessage(_id);
ApplicationData.hasSignal(false);
break;
}
}
Message delivered:
public class DeliveredMessage extends BroadcastReceiver {
private final String TAG = "DeliveredMessage ";
#Override
public void onReceive(Context context, Intent intent) {
long _id = intent.getLongExtra(EXTRA_ID, -1);
long protocol_id = intent.getLongExtra(EXTRA_PROTOCOL, -1);
switch (getResultCode()) {
case Activity.RESULT_OK:
if (_id != -1 && MessageData.deliveredMessage(_id, protocol_id)) {
try {
Database.messageDelivered(_id);
Cursor messageCursor = Database.getCursorByID(MessageOutboxContentProvider.CONTENT_URI, MessageOutboxContentProvider._ID, _id);
messageCursor.close();
} catch (DatabaseRowNotFoundException e) {
Log.e(TAG, e.toString(), e);
}
}
break;
case Activity.RESULT_CANCELED:
break;
}
}
}
I was in the need for reliable sending too, so kept references to all pending messages in a database, which I would frequently scan for postponed messages. A message would get postponed if there is no radio, or the sending simply fails for whatever reason.
I also used GCM together with SMS to get the message delivered as fast as possible, sending messages using both channels at the same time.
Edit2: Oh well, might as well address the questions, we are almost there anyway:
Question 1: Since using IntentService the sending is done in the background.
You only want the sending to happen once after a delay so you should do this instead:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// send sms
}
}, delay);
Question 2: Easy, when your sent message broadcast detects an error do the above method. You could add an extra information, besides receiver and message, counting the number of retries up until now so you have a chance of stopping the send/retry loop.
Question 3: The sending stops by itself, as it is an Intent Service. As for the other service the most simple approach, I think, would be to send a common broadcast, which is picked up by your main activity. This way you can get a hold of the service the right place and stop it.
I know this has been asked multiple times, but I am having problems making it work or figuring out what will work best. I need to have the sms wait 2-3 seconds between each message before sending another message. I have looked at and tried handlers, timers and thread sleep and I am not sure which one would be the best use in my situation, or how to make it work right. I am still new to programming, so please take it easy on me.
// ---sends an SMS message---
private void sendSMS(String phoneNumber, String message) {
int i;
SmsManager sms = SmsManager.getDefault();
int amount = 10; // just making 10 the default if the EditText has an
// invalid value
try {
amount = Integer.parseInt(smsamount.getText().toString());
} catch (NumberFormatException smsamount) {
}
if (amount < 501) {
for (i = 0; i < amount; i++) {
sms.sendTextMessage(phoneNumber, null, message, sentPI, null);
}
if you want to use 2 seconds delay between each sms, use a ScheduledExecutorService thread pool (1 thread is probably enough cause you don't send parallel) and call schedule method with the code to send the sms.
For each call, raise the delay parameter by 2 seconds (0,2,4,6,...)
Hope it helps.
Maybe something like this. I've not tested it, but the idea of using a ScheduledExecutorService should be what you're after.
public class SMS extends Activity {
private final static OnClickListener EMPTY_ON_CLICK_LISTENER = new EmptyOnClickListener();
TextView smsamount;
// ---sends an SMS message---
private void sendSMS(String phoneNumber, String message) {
// just making 10 the default if the EditText has an invalid value
int amount = 10;
try {
amount = Integer.parseInt(smsamount.getText().toString());
} catch (NumberFormatException smsamount) {
// Ignore
}
sendSMS(phoneNumber, message, amount);
}
// ---sends an SMS message---
private void sendSMS(String phoneNumber, String message, int count) {
if (count >= 501) {
new AlertDialog.Builder(SMS.this).setTitle("Maximum amount of messages exceeded!")
.setMessage("Please enter 500 or less for the amount of messages")
.setNeutralButton("Ok", EMPTY_ON_CLICK_LISTENER).show();
// Quit early when we know we can't go any further.
return;
}
String SENT = "SMS_SENT";
PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(SENT), 0);
// ---when the SMS has been sent---
registerReceiver(new SmsSentBroadcastReceiver(getBaseContext()), new IntentFilter(SENT));
int delaySeconds = 3;
ScheduledExecutorService scheduler = new SmsScheduler().sendSmsMessages(phoneNumber, message, sentPI, delaySeconds,
count);
// You may cancel the scheduled messages with the scheduler.
// scheduler.shutdownNow();
new AlertDialog.Builder(SMS.this).setTitle("Attention!")
.setMessage("Your messages will start sending shortly, please do not press the send sms button again")
.setNeutralButton("Ok", EMPTY_ON_CLICK_LISTENER).show();
}
private static class SmsSentBroadcastReceiver extends BroadcastReceiver {
Context context;
public SmsSentBroadcastReceiver(Context context) {
this.context = context;
}
#Override
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Toast.makeText(context, "SMS sent", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(context, "Generic failure", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(context, "No service", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(context, "Null PDU", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(context, "Radio off", Toast.LENGTH_SHORT).show();
break;
}
}
}
private static class EmptyOnClickListener implements OnClickListener {
public void onClick(DialogInterface dialog, int which) {
// Does nothing
}
}
private static class SmsScheduler {
public ScheduledExecutorService sendSmsMessages(final String phoneNumber, final String message,
final PendingIntent sentIntent, int count, int delaySeconds) {
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
final SmsManager sms = SmsManager.getDefault();
// Create the task that will send a SMS message
final Runnable sender = new Runnable() {
public void run() {
sms.sendTextMessage(phoneNumber, null, message, sentIntent, null);
}
};
// Schedule the messages to be sent at intervals of delaySeconds.
for (int i = 0; i < count; i++) {
scheduler.schedule(sender, delaySeconds * i, TimeUnit.SECONDS);
}
return scheduler;
}
}
}