I am trying to implement Broadcast receiver to implement notification pop-up upon SMS received on my Android device. However I have set a condition to detect only specific SMSs from pre-defined senders and then pop-up a notification. Here is what I have coded till now :
public class MyBroadcastReceiver extends BroadcastReceiver
{
private static final String TAG = "MyBroadCastReceiver";
String str = "";
static Context context;
String sender;
#Override
public void onReceive(Context arg0, Intent arg1)
{
// Log.i(TAG,"OnReceive ++ ");
Bundle bndl = arg1.getExtras();
SmsMessage[] msg = null;
if (null != bndl)
{
//---retrieve the SMS message received---
Object[] pdus = (Object[]) bndl.get("pdus");
msg = new SmsMessage[pdus.length];
if(msg[0].getOriginatingAddress().endsWith("AIRMTA") ||
msg[0].getOriginatingAddress().endsWith("ICICIB") ||
msg[0].getOriginatingAddress().endsWith("FCHRGE") ||
msg[0].getOriginatingAddress().endsWith("MYAMEX") ||
msg[0].getOriginatingAddress().endsWith("MOBIKW") ||
msg[0].getOriginatingAddress().endsWith("OLACAB") ||
msg[0].getOriginatingAddress().endsWith("HDFCB") ||
msg[0].getOriginatingAddress().endsWith("AIRMNY")
)
{
for (int i=0; i<msg.length; i++)
{
msg[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
// str += "SMS From " + msg[i].getOriginatingAddress();
sender = msg[i].getOriginatingAddress();
str += " :\r\n";
str += msg[i].getMessageBody().toString();
str += "\n";
context = arg0;
}
//---display incoming SMS as a Android Toast---
// Toast.makeText(arg0, str, Toast.LENGTH_SHORT).show();
//---Create a status bar notification for incoming sms-->
int mNotificationId = 001;
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);
mBuilder.setContentTitle(sender);
mBuilder.setContentText(str);
mBuilder.setTicker("New Message Alert!");
mBuilder.setSmallIcon(R.drawable.notification);
Intent resultIntent = new Intent(arg0, MainActivity.class);
PendingIntent resultPendingIntent = PendingIntent.getActivity(arg0, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotifyMgr = (NotificationManager) arg0.getSystemService(Context.NOTIFICATION_SERVICE);
mNotifyMgr.notify(mNotificationId, mBuilder.build());
MapsFragment obj = new MapsFragment();
obj.initilizeMap();
}
}
}
}
Unfortunately the application is crashing every time I receive an SMS, be it from any sender. I am not able to understand what is going wrong with the code !
Can anyone help me out on this ?
Here is the log cat error report :
Process: com.techfrk.fetchinboxsms, PID: 21956
java.lang.RuntimeException: Unable to start receiver com.techfrk.fetchinboxsms.MyBroadcastReceiver: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.telephony.SmsMessage.getOriginatingAddress()' on a null object reference
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2616)
at android.app.ActivityThread.access$1700(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1380)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
You get a NullPointerException exception because your msg array is always empty when calling msg[0].getOriginatingAddress().endsWith().
With msg = new SmsMessage[pdus.length] you create an empty array with the size of pdus.length but this does not add any objects to it.
Instead of
if(msg[0].getOriginatingAddress().endsWith("AIRMTA") ||
msg[0].getOriginatingAddress().endsWith("ICICIB") ||
msg[0].getOriginatingAddress().endsWith("FCHRGE") ||
msg[0].getOriginatingAddress().endsWith("MYAMEX") ||
msg[0].getOriginatingAddress().endsWith("MOBIKW") ||
msg[0].getOriginatingAddress().endsWith("OLACAB") ||
msg[0].getOriginatingAddress().endsWith("HDFCB") ||
msg[0].getOriginatingAddress().endsWith("AIRMNY")
)
{
for (int i=0; i<msg.length; i++)
{
msg[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
// str += "SMS From " + msg[i].getOriginatingAddress();
sender = msg[i].getOriginatingAddress();
str += " :\r\n";
str += msg[i].getMessageBody().toString();
str += "\n";
context = arg0;
}
}
you should do something like
SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(arg1);
if(messages.length < 1) return;
SmsMessage sms = messages[0];
sender = sms.getOriginatingAddress();
str = sms.getMessageBody().toString();
if (sms.getOriginatingAddress().endsWith("AIRMTA")) { // add all your needed statements
// show your notification
}
Please keep in mind that this code is extremely simplified for a better understanding.
Related
onReceive method doesn't gets called.
I checked the broadcast receiver code for calls and it works fine.
The following code works on my Intex Elyt Dual (7.0) but don't work on other with 6.0.1.
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "on Receive", Toast.LENGTH_SHORT).show();
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for (int i = 0; i < msgs.length; ++i) {
// Convert Object array
hereComesNewSMS = hereComesNewSMS++ ;
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
// Sender's phone number
str += "SMS from " + msgs[i].getOriginatingAddress() + " : ";
// Fetch the text message
str += msgs[i].getMessageBody().toString();
str += "\n";
latestSMSnumber = msgs[i].getOriginatingAddress();
latestSMScontent = str;
}
// Display the entire SMS Message
Log.e("TAG1 number: ", latestSMSnumber);
Log.e("TAG2 content: ", str);
}
I have built an SMS messaging app, which both sends and receives text messages. In MainActivity, I have a two-dimensional array of people's names and phone numbers, and in my sending class, I have a for loop which sends the same message to all of the recipients by going through each of the numbers:
for (i=0; i<names.length; i++) {
phoneNo = names[i][2] + names[i][3];
sendMessage(phoneNo, message);
}
private void sendMessage(String phoneNo, String message) {
try {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNo, null, message, null, null);
Toast.makeText(getApplicationContext(), "SMS sent", Toast.LENGTH_LONG).show();
}
catch (Exception e) {
Toast.makeText(getApplicationContext(), "SMS failed. Please try again!", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
When I send a message through the app, I can see very clearly from my own Samsung messaging app that the same message gets sent to each of the numbers in the list, which is perfect.
This is my shortened receiver class:
public class Receiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
SmsMessage[] smgs = null;
String infoSender = "";
String infoSMS = "";
if (extras != null) {
// Retrieve the sms message received
Object[] pdus = (Object[]) extras.get("pdus");
smgs = new SmsMessage[pdus.length];
for (int i = 0; i < smgs.length; i++) {
smgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
infoSender += smgs[i].getOriginatingAddress();
infoSMS += smgs[i].getMessageBody().toString();
}
}
I have found that despite the message being sent out once to each recipient, some recipients (with this app) receive it more than once consecutively. Hence, I suspected that there was something wrong with my receiver code, which is seemingly treating one received message as several consecutive received messages. This is not a consistent problem, as different people receive the consecutive messages at different times.
However, what I've also found is that if I hardcode phoneNo in the sending class to just one phone number, or if I have only one phone number in the array in MainActivity, then this problem doesn't occur. The message still gets sent out once to that one phone number only, but the receiver will always receive it just once as intended.
I am so confused by this now, so can somebody please give some suggestions as to what I could try? Literally in the last minute, I thought that it could be a problem with createFromPdu being deprecated? If so, please advise how to change my receiver code, as I couldn't find anything which resembles my current code too much.
Many thanks in advance:-)
Do like this you are making mistake check below code.
if (bundle != null) {
// get sms objects
Object[] pdus = (Object[]) bundle.get("pdus");
if (pdus.length == 0) {
return;
}
// large message might be broken into many
SmsMessage[] messages = new SmsMessage[pdus.length];
StringBuilder sb = new StringBuilder();
for (int i = 0; i < pdus.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
sb.append(messages[i].getMessageBody());
}
senderNum = messages[0].getOriginatingAddress();
message = sb.toString();
}
Update: To check default app
public class Receiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
final String myPackageName = context.getPackageName();
if (Telephony.Sms.getDefaultSmsPackage(context).equals(
myPackageName)) {
// you are default
Bundle extras = intent.getExtras();
SmsMessage[] smgs = null;
String infoSender = "";
String infoSMS = "";
if (extras != null) {
// Retrieve the sms message received
Object[] pdus = (Object[]) extras.get("pdus");
smgs = new SmsMessage[pdus.length];
for (int i = 0; i < smgs.length; i++) {
smgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
infoSender += smgs[i].getOriginatingAddress();
infoSMS += smgs[i].getMessageBody().toString();
}
}
} else {
// you are not ignore
}
} else {
// for below KitKat do like normal
Bundle extras = intent.getExtras();
SmsMessage[] smgs = null;
String infoSender = "";
String infoSMS = "";
if (extras != null) {
// Retrieve the sms message received
Object[] pdus = (Object[]) extras.get("pdus");
smgs = new SmsMessage[pdus.length];
for (int i = 0; i < smgs.length; i++) {
smgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
infoSender += smgs[i].getOriginatingAddress();
infoSMS += smgs[i].getMessageBody().toString();
}
}
}
}
}
i hope this modication of your code base will help solve your problem
public class Receiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
SmsMessage[] smgs = null;
String infoSender = "";
String infoSMS = "";
if (extras != null) {
try{
// Retrieve the sms message received
Object[] pdus = (Object[]) extras.get("pdus");
if(pdus.length==0){return;}
smgs = new SmsMessage[pdus.length];
for (int i = 0; i < smgs.length; i++) {
smgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
infoSMS += smgs[i].getMessageBody();
}
infoSender = smgs[0].getOriginatingAddress();
}catch(Exception e){
e.printStackTrace ();
}
}
}
}
I have near about six Activities and a service class with BroadcastReceiver that run in background for receiving SMS. I receive SMS on OnReceive Method of BroadcastReceiver now I would like to store incomming sms data in database for that I have made a SMSSync Class for smsProcess which pass data to dbase now I call this smsProcess on OnReceive method this work fine but I think when more sms received at same time the I got found problem I think it was due to database. Sir please tell me what is best method to store sms data after receiving it On receive and then show in activities. Sory for my bad English or if not understand. Thanks in advance sir pl revert back answer I will wait for..I tag code for On Receive method
thanks
Om Parkash Kaushik
public SMSReceiver(Context ctx){
this.context = ctx;
sync = new SMSSync(context);
dba = new DataBaseAdapter(ctx);
}
#Override
public void onReceive(Context context,final Intent intents){
if (intents.getAction().equals(ConstantClass.SMS_RECEIVED)) {
try{
Bundle bundle = intents.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++)
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
String msg=null;
String temp = null;
for (SmsMessage message : messages) {
msg = message.getMessageBody();
temp = message.getOriginatingAddress();
}
if(msg.length()>5 && msg.startsWith("<") && msg.contains(">")){
String len = msg.substring(1, 3);
int tl = temp.length();
int l = tl - no;
address = temp.substring(l,tl);
int value =Integer.valueOf(len, 16).intValue();
int index = msg.indexOf(">");
if(value == index+1){
dba.Open();
int id = dba.getCordiId(address);
Cursor cur = dba.getCoord(id);
if(cur!=null)
cur.moveToFirst();
final String Phnumber = cur.getString(cur.getColumnIndex(DataBaseAdapter.Key_MbNo));
if(Phnumber.equals(address)){
int count = dba.getDeviceCount(ConstantClass.dbName[1]);
if(count<=0){
dba.InsertCurrentCoord(id,id);
}else{
Strsql = new String("UPDATE " + ConstantClass.dbName[1] + " SET " + DataBaseAdapter.Key_ReceiverCoord + " = " +
Integer.toString(id) + " WHERE " + DataBaseAdapter.Key_ID + " = ?");
dba.UpdateQuery(Strsql, Integer.toString(1));
}
dba.Close();
sync.smsProcess(msg);
abortBroadcast();
/************Now deleting the SMS from the Inbox*********************/
removeMessage(SMSReceiver.this.context, Phnumber);
if(msg.substring(3, 4).equals("2"))
ConstantClass.isAuditrequestSend = false;
/*******after receiving the sms opening the Main Screen.*****************/
if(ConstantClass.Clear_Main_Screen==true){
Intent intent = new Intent(context,ZigbeeActivity.class);
context.startActivity(intent);
}
}else{
Toast.makeText(SMSReceiver.this.context, address, Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(SMSReceiver.this.context, "message Corrupt" + address, Toast.LENGTH_LONG).show();
}
}
}
}catch(Exception e){
dlg = new ExceptionDialog(SMSReceiver.this.context,"On Sms Receiver" + address ,e.getMessage());
dlg.show();
}
}
}
I have done the same application related to yours. But instead of saving all received sms i want to save only bank transaction related sms. I hope the following code will helps you..
ReceiveSms.java
if(smsg.contains("credit") /***********/ || msg.contains("amount"))
{
Toast.makeText(context, "message related to transcation", Toast.LENGTH_SHORT).show();
dbh.smsservice(smsg);
}
DbHandler.java
public void smsservice(String sms)
{
// TODO Auto-generated method stub
String smessg="INSERT INTO SMSDETAILS(SMSMESS) VALUES('"+sms+"') ";
sdb.execSQL(smessg);
System.out.println("values of sms inserted"+smessg);
}
Android documentation for SMSManagers sendTextMessage function
public void sendTextMessage (String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent)
deliveryIntent if not NULL this PendingIntent is broadcast when the message is delivered to the recipient. The raw pdu of the status report is in the extended data ("pdu")
I could not understand if deliveryIntent is fired when SMS is delivered to destinationAddress or scAddress and what is the meaning of "raw pdu of the status report is in the extended data ("pdu")" and how to get that report? .
I appreciate your effort.
It is broadcast when message is delivered to destinationAddress.
The PDU may be extracted from the Intent.getExtras().get("pdu") when registered BroadcastReceiver receives the Intent broadcast you define with PendingIntent.getBroadcast(Context, int requestCode, Intent, int flags). For example:
private void sendSMS(String phoneNumber, String message) {
String DELIVERED = "DELIVERED";
PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0,
new Intent(DELIVERED), 0);
registerReceiver(
new BroadcastReceiver() {
#Override
public void onReceive(Context arg0, Intent arg1) {
Object pdu = arg1.getExtras().get("pdu");
... // Do something with pdu
}
},
new IntentFilter(DELIVERED));
SmsManager smsMngr = SmsManager.getDefault();
smsMngr.sendTextMessage(phoneNumber, null, message, null, deliveredPI);
}
Then you need to parse extracted PDU, SMSLib should be able to do that.
Just to build on a.ch's answer, heres how you can extract the delivery report from an intent:
public static final SmsMessage[] getMessagesFromIntent(Intent intent) {
Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
if (messages == null || messages.length == 0) {
return null;
}
byte[][] pduObjs = new byte[messages.length][];
for (int i = 0, len = messages.length; i < len; i++) {
pduObjs[i] = (byte[]) messages[i];
}
byte[][] pdus = new byte[pduObjs.length][];
SmsMessage[] msgs = new SmsMessage[pdus.length];
for (int i = 0, count = pdus.length; i < count; i++) {
pdus[i] = pduObjs[i];
msgs[i] = SmsMessage.createFromPdu(pdus[i]);
}
return msgs;
}
Full credit to the great project at: http://code.google.com/p/android-smspopup/
Anyone know how to send non-printing characters via SMS in Android?
I tried the following code but it does not work...The recipient will not receive the correct string.
String msg = "Testing special char" +(char) 3;
sendSMS(num,msg);//defined method
Or is there any other way to insert some kind of tags into a SMS, so that the recipient can perform some actions accordingly?
By default you send sms text messages in ascii format. Try to send binary SMS.
As there is an Android tag on the question, here is what I found while researching the topic (code from codetheory.in).
Send:
// Get the default instance of SmsManager
SmsManager smsManager = SmsManager.getDefault();
String phoneNumber = "9999999999";
byte[] smsBody = "Let me know if you get this SMS".getBytes();
short port = 6734;
// Send a text based SMS
smsManager.sendDataMessage(phoneNumber, null, port, smsBody, null, null);
Receive:
public class SmsReceiver extends BroadcastReceiver {
private String TAG = SmsReceiver.class.getSimpleName();
public SmsReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
// Get the data (SMS data) bound to intent
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str = "";
if (bundle != null){
// Retrieve the Binary SMS data
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
// For every SMS message received (although multipart is not supported with binary)
for (int i=0; i<msgs.length; i++) {
byte[] data = null;
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
str += "Binary SMS from " + msgs[i].getOriginatingAddress() + " :";
str += "\nBINARY MESSAGE: ";
// Return the User Data section minus the
// User Data Header (UDH) (if there is any UDH at all)
data = msgs[i].getUserData();
// Generally you can do away with this for loop
// You'll just need the next for loop
for (int index=0; index < data.length; index++) {
str += Byte.toString(data[index]);
}
str += "\nTEXT MESSAGE (FROM BINARY): ";
for (int index=0; index < data.length; index++) {
str += Character.toString((char) data[index]);
}
str += "\n";
}
// Dump the entire message
// Toast.makeText(context, str, Toast.LENGTH_LONG).show();
Log.d(TAG, str);
}
}
}