I want to read sms sent by user in my application before it sent. Is there any way to accomplish this?
This is not possible. Any application can use SmsManager to send an SMS, and such messages cannot be intercepted, except perhaps by custom firmware.
You cant block an outgoing sms.You can find out about it only after it has been sent. And you can do it by registering a content observer for sms, when the sms comes to sent box.
You may intercept incoming messages if you want.
Here is an example of a SMS interceptor that "cancels" the SMS if it contains some custom defined data:
For your application to receive the message before it shows up in the phone you will have to define a receiver in the manifest with a high priority. Example:
<receiver android:name=".SMSReceiver">
<intent-filter android:priority="9999">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Then, create the receiver:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;
public class SMSReceiver extends BroadcastReceiver{
private static final String CRITICAL_MESSAGE = "critical";
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str = "";
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 (msgs[i].getMessageBody().toString().equals(CRITICAL_MESSAGE)){
str = "Critical msg from " + msgs[i].getOriginatingAddress() + " !";
Toast.makeText(context, str, Toast.LENGTH_LONG).show();
abortBroadcast();
}
}
}
}
}
The above receiver cancels the SMS (aborts broadcast) if critical string is received.
Related
I am sure I must just be missing something obvious but this is currently baffling me.
I have a class which extends BroadcastReceiver this class is setup as a receiver int he manifest and it does correctly capture the sms received intent.
package gull.sana.textit;
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 SMSReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("SMSReceiver", "Intent received");
//---get the SMS message passed in---
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str = "";
if (bundle != null)
{
//---retrieve the SMS message received---
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]);
str += "SMS from " + msgs[i].getOriginatingAddress();
str += " :";
str += msgs[i].getMessageBody().toString();
str += "\n";
}
Log.d("SMS", str);
//---display the new SMS message---
Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
}
}
}
Now when I send in an SMS message I always get the first log message Log.d("SMSReceiver", "Intent received"); and I always get the Toast as I would expect, however, I never get the Log.d("SMS", str);
Am I doing something wrong? Why does the Toast appear yet the log on the line before never does?
It turns out that there are several buffers for log messages. The tags decide which buffer these logs go into. According to this https://stackoverflow.com/a/9011945/1475461 SMS is one of those tags that gets put into a different buffer.
The other buffer can be viewed with the following command
adb logcat -b radio
Thanks to #nKn for getting me along the right tracks.
This seems to be an old known issue when you use Log.* in combination with a tag called SMS. There seems not logical explaination to this but your code is working accordingly, it's just the Log.d() line that is not working correctly.
You should replace the tag SMS with some other, in that case it should work as expected (in this case, avoiding the bug).
I am having a requirement in my application where i need to integrate messaging in the app. I want to use android native SMS API to send the messages and receive them. The main challenge is that i don't want to show received messages in the Message application. All messages should be opened and send from my application only.
I have tried receiving following intent in my broadcastreceiver :
<intent-filter>
<action android:name="android.provider.telephony.SMS_RECEIVED"></action>
</intent-filter>
But when the message comes to my application at the same is is received by native Message application, which i don't want.
I have also tried sending data message on a specific port in emulator, it is sending the messgae but not received by my application as well as Message native app on other emulator.
Intent Filter is :
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<data android:port="8901"/>
<data android:scheme="sms"/>
</intent-filter>
I am using the sendDataMessage() function with the given port.
Is it possible send messages in a better and secure way so that there is no possibility to steal your data using the native SMS API in android ? If not what alternate I can go for implementing the same.
Here is what I had implemented and its working like exactly what i wanted.
After entering the phone number and Text message call this method .
private static final int MAX_SMS_MESSAGE_LENGTH = 160;
private static final int SMS_PORT = 8901;
private static final String SMS_DELIVERED = "SMS_DELIVERED";
private static final String SMS_SENT = "SMS_SENT";
private void sendSms(String phonenumber,String message) {
SmsManager manager = SmsManager.getDefault();
PendingIntent piSend = PendingIntent.getBroadcast(this, 0, new Intent(SMS_SENT), 0);
PendingIntent piDelivered = PendingIntent.getBroadcast(this, 0, new Intent(SMS_DELIVERED), 0);
byte[] data = new byte[message.length()];
for(int index=0; index<message.length() && index < MAX_SMS_MESSAGE_LENGTH; ++index)
{
data[index] = (byte)message.charAt(index);
}
manager.sendDataMessage(phonenumber, null, (short) SMS_PORT, data,piSend, piDelivered);
}
private BroadcastReceiver sendreceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
String info = "Send information: ";
switch(getResultCode())
{
case Activity.RESULT_OK: info += "send successful"; break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE: info += "send failed, generic failure"; break;
case SmsManager.RESULT_ERROR_NO_SERVICE: info += "send failed, no service"; break;
case SmsManager.RESULT_ERROR_NULL_PDU: info += "send failed, null pdu"; break;
case SmsManager.RESULT_ERROR_RADIO_OFF: info += "send failed, radio is off"; break;
}
Toast.makeText(getBaseContext(), info, Toast.LENGTH_SHORT).show();
}
};
private BroadcastReceiver deliveredreceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
String info = "Delivery information: ";
switch(getResultCode())
{
case Activity.RESULT_OK: info += "delivered"; break;
case Activity.RESULT_CANCELED: info += "not delivered"; break;
}
Toast.makeText(getBaseContext(), info, Toast.LENGTH_SHORT).show();
}
};
Your Receiver for messages should look like :
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.telephony.SmsMessage;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
public class MySMSReceiver extends BroadcastReceiver {
String action,from,message;
#Override
public void onReceive(Context context, Intent intent) {
action=intent.getAction();
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
if(null != bundle)
{
String info = "Binary SMS from ";
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
byte[] data = null;
for (int i=0; i<msgs.length; i++){
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
info += msgs[i].getOriginatingAddress();
info += "\n*****BINARY MESSAGE*****\n";
from= msgs[i].getOriginatingAddress();
data = msgs[i].getUserData();
for(int index=0; index<data.length; ++index) {
info += Character.toString((char)data[index]);
message += Character.toString((char)data[index]);
}
}
}
Intent showMessage=new Intent(context, AlertMessage.class);
showMessage.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
showMessage.putExtra("from", from);
showMessage.putExtra("message", message);
context.startActivity(showMessage);
}
}
I have created a simple activity AlertMessage.java to show received message.
The way I registered my broadcast receiver in Manifest :
<receiver android:name=".MySMSReceiver">
<intent-filter>
<action android:name="android.intent.action.DATA_SMS_RECEIVED" />
<data android:scheme="sms" />
<data android:port="8901" />
</intent-filter>
</receiver>
The port mentioned here must be the same which we specified in method sendSMS() for sending the message.
UPDATE :
Github Repository of working project
https://github.com/pyus-13/MySMSSender
According to me it's possible. You can set higher priority to your app, like
<intent-filter android:priority="100">
in your manifest.xml. So that all messages will pass through your app at first and you can store those messages in your database. At the same time, if you are aborting your broadcast, say
abortbroadcast();
you will not get any notifications also on anywhere.
It's not possible to prevent default Messaging application from receiving SMS messages in any way, because your application can't alter other apps' permissions.
I want my program to be able to receive sms from a special number("+9856874236"). But, if the SMS is from any other number, it should go to the phone's message inbox and not to my application.
please help me my dears
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.util.Log;
public class receiver extends BroadcastReceiver {
public String str = "";
#Override
public void onReceive(Context context, Intent intent) {
// ---get the SMS message passed in---
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
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]);
//for get sms from special number===============================
String msg_from = msgs[i].getOriginatingAddress();
Log.v("msg_from >>",msg_from);
if(msg_from.equals("+9830007546"))
{
//===============================
str += "SMS from " + msgs[i].getOriginatingAddress();
str += " :";
str += msgs[i].getMessageBody().toString();
str += "\n";
Intent act = new Intent(context, ReceiveSMS.class);
act.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
act.putExtra("message", str);
context.startActivity(act);
this.abortBroadcast();
}
}
// ---display the new SMS message---
// Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
}
}
}
main class :
private TextView showSms;
private String ReceivedSms;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
//this.setContentView(R.layout.receivesms);
/*Removing system bar from screen*/
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.receivesms);
Intent act = getIntent();
ReceivedSms = act.getStringExtra("message");
showSms = (TextView) this.findViewById(R.id.textView2);
showSms.setText(ReceivedSms);
Give your BroadcastReceiver a high priority in your AndroidManifest. This will put your receiver first in line to process the broadcast.
<receiver
android:name=".SmsReceiver">
<intent-filter
android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Inside your BroadcastReceiver, check if the number of the incoming sms equals your given number. If true, then cancel the broadcast with abortBroadcast().
Edit
There are a couple of things to watch out for:
When you do the number matching, be aware of phone number formatting. If the incoming number is 0123456789 and you use String.equals('+XX0123456789'), then your check will fail, even though its technically correct. Have a look at PhoneNumberUtils to find a solution for this.
If I recall correctly, some device manufacturers have given the default SMS application priority one on processing sms broadcasts. This will mess with your application. Be sure to test this out ;)
Assuming you meant to say that your special number should not show up in the inbox...
You cannot re-route the message being received by the phone. So instead you have to upon receiving that message then look it up in the MMS database and delete it, there is no other way.
I try to get text of Cell Broadcast message just like sms, but it does'not work:
public class SMSReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str = "";
if (bundle != null) {
// ---retrieve the SMS message received---
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]);
str =msgs[i].getOriginatingAddress();
str += " :";
str += msgs[i].getMessageBody().toString();
Do you know any way to get it?
I also spent some time on investigation of this question. And it seems that there is no public API to do that. But I can share some results from my reverse engineering research...
My Samsung Galaxy S is able to receive CB messages, so I decompiled SMS app and looked into the code. It has the following BroadcastReceiver in its manifest file:
<receiver android:name=".transaction.PrivilegedSmsReceiver">
...
<intent-filter>
<action android:name="android.provider.Telephony.CB_RECEIVED" />
</intent-filter>
<intent-filter>
<action android:name="android.provider.Telephony.CB_SETTINGS_AVAILABLE" />
</intent-filter>
<intent-filter>
<action android:name="android.provider.Telephony.SET_CB_ERR_RECEIVED" />
</intent-filter>
<intent-filter>
<action android:name="android.provider.Telephony.GET_CB_ERR_RECEIVED" />
</intent-filter>
</receiver>
Note the android.provider.Telephony.CB_RECEIVED intent-filter. I did not find any documentation about it, but from its name I assumed that it's the only broadcast that I need to catch for now.
Then I searched through the code of decompiled apk and found that it uses android.provider.Telephony.Sms.Intents->getCbMessagesFromIntent() interface to access retrieve CB messages, which returns CbMessage class instance. This interface is outdated even for simple SMS messages, so I assumed that CbMessage should work with pdus as SmsMessage does. Finally I found the source of SmsCbMessage class which is pretty similar to SmsMessage by API. It depends on 5-6 internal Android java files, so for simplicity I just grab them from the same site and included them into my project.
The broadcastReceiver is the same as yours except the class SmsMessage is replaced by SmsCbMessage:
public class CbReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//---get the CB message passed in---
Bundle bundle = intent.getExtras();
SmsCbMessage[] msgs = null;
String str = "";
if (bundle != null) {
//---retrieve the SMS message received---
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsCbMessage[pdus.length];
for (int i=0; i<msgs.length; i++) {
msgs[i] = SmsCbMessage.createFromPdu((byte[])pdus[i]);
str += "CB lang " + msgs[i].getLanguageCode();
str += " :";
str += msgs[i].getMessageBody().toString();
str += "\n";
}
//---display the new CB message---
abortBroadcast();
Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
}
}
}
After installing my application into my SGS phone with the receiver above, and enabling receiving CB messages in phone SMS application, my app was able to show CB messages in toast in parallel with receiving them by standard SMS application.
The issues are still needed to be resolved:
How to enable/disable/configure_channels of CB messages in my
application? SMS app uses getCbSettings()/setCbSettings() functions,
but I did not find them. So temporarily I used other app for that.
How to
abort CB message broadcast, so other apps do not receive them? It
seems abortBroadcast() does not work here, because the broadcast
message is not ordered (isOrderedBroadcast() returns false).
I am developing an android application in that i want to read the incoming message without knowing the user.I want to always run the incoming message checker in background.If a new message is received means i want to read the content of the message and that message contains some words(password) means i want to activate the application
Please explain me how to do that with sample code because i am new to android
Take a look at BroadCastReceivers you must implement and register a Reciever for android.provider.Telephony.SMS_RECEIVED
Here is a code snippet that lets you read messages as they arrive.
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;
public class SMSReceiver extends BroadcastReceiver
{
public void onReceive(Context context, Intent intent)
{
Bundle myBundle = intent.getExtras();
SmsMessage [] messages = null;
String strMessage = "";
if (myBundle != null)
{
Object [] pdus = (Object[]) myBundle.get("pdus");
messages = new SmsMessage[pdus.length];
for (int i = 0; i < messages.length; i++)
{
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
strMessage += "SMS From: " + messages[i].getOriginatingAddress();
strMessage += " : ";
strMessage += messages[i].getMessageBody();
strMessage += "\n";
}
Toast.makeText(context, strMessage, Toast.LENGTH_SHORT).show();
}
}
}
And here what you have to add to your AndroidManifest.xml file:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<receiver android:name=".SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>