Skip to main content

Intercepting Sent and Received SMS in Android

Android API provides a very easy to way to get applications notified for phone related events such as SMS received and SMS sent. In this blog post we will learn how our app can receive these two notifications.

Getting notified for Received SMS

BroadcastReceiver class allows applications to get notified for any android defined filter they want. All you have to do is to extend your class with BroadcastReceiver class and overrides its onReceive method. This method is called when Intent broadcast is received by this BroadcastReceiver. It has two parametes, first is a Context in which the receiver is running , second is the Intent which is being received. Its prototype in BroadcastReceiver class is like this
public abstract void onReceive(Context context,Intent intent);
So lets write our simple class whose onReceive method will be called on broadcast for any filter we are interested (in our case it is android.provider.Telephony.SMS_RECEIVED ).
public class MyReceivedSmsReceiver extends BroadcastReceiver {
    private static final String TAG="com.usmani.android.MyReceivedSmsReceiver";
    @Override
    public void onReceive(Context context,Intent intent){
        //if you have registered your class for multiple filters you can check
        //for which filter it is called like this
        if (intent.getAction().CompareTo("android.provider.Telephony.SMS_RECEIVED")==0){
            Bundle pudsBundle = intent.getExtras();
           Object[] pdus = (Object[]) pudsBundle.get("pdus");
           SmsMessage sms =SmsMessage.createFromPdu((byte[]) pdus[0]);  
           Log.i(TAG, sms.getMessageBody());
        }
    }
}
Now sms variable contains our sent SMS.

Registering your BroadcastReceiver

In order to make our BroadcastReceiver available, we have to register it with android system. There are two methods to do this
1) Describe your receiver in manifest file
2) Dynamically register it using code.

Lets check both the methods

1) Describing in manifest file
<receiver android:name="MyReceivedSmsReceiver" >
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>
2) Registering using code
BroadcastReceiver receiver=new MyReceivedSmsReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(receiver, filter);


Getting notified for Sent SMS

We cannot use BroadcastReceiver to get notified for Sent SMS. But don't worry we have an easy by using android's ContentObserver class. We register ContentObserver for our interested URI (in case of sms we will use "content://sms"). Whenever content is changed for which we have registered ContentObserver , its onChange method is called. onChange has two overloads
1) void onChange(boolean selfChange);
2) void onChange(boolean selfChange,Uri uri);
To receive onChange event we will create our class that extends ContentObserver and implement the above mentioned two methods. But for simplicity in this post we will implement the first overload only
public class MySentSmsHandler extends ContentObserver {
    private Context mContext;
    public MySentSmsHandler(Context context){
        mContext=context;
    } 
    public void onChange(boolean selfChange){
       Cursor cursor = context.getContentResolver().query(
Uri.parse(CONTENT_SMS), null, null, null, null);
if (cursor.moveToNext()) {
String protocol = cursor.getString(cursor.getColumnIndex("protocol"));
int type = cursor.getInt(cursor.getColumnIndex("type"));
// Only processing outgoing sms event & only when it
// is sent successfully (available in SENT box).
if (protocol != null || type != MESSAGE_TYPE_SENT) {
                    return;
}
int dateColumn = cursor.getColumnIndex("date");
int bodyColumn = cursor.getColumnIndex("body");
int addressColumn = cursor.getColumnIndex("address");
String from = "0";
String to = cursor.getString(addressColumn);
Date now = new Date(cursor.getLong(dateColumn));
String message = cursor.getString(bodyColumn); }
    }
}
Registering your ContentObserver

We can register our ContentObserver like this
ContentObserver observer=new MySentSmsHandler(context);
context.getContentResolver().registerContentObserver(
                Uri.parse("content://sms"), true, observer);

Comments

  1. Great blog! Is your theme custom made or did you download it from somewhere?
    A design like yours with a few simple tweeks would really make my blog shine.

    Please let me know where you got your theme. Cheers

    ReplyDelete

Post a Comment

Share your wisdom

Popular posts from this blog

Decoding JPEG image file using libavcodec

I got a chance to work on a video encoding application that decodes series of jpeg files and convert them into ogg theora video file. I used the infamous libavcodec library that is used in FFMPEG . I decided to write blog posts explaining how I decode jpeg images and convert them into ogg video file. This is the first part and in this I will explain how to decode jpeg images using libavcodec. To learn how to write decoded images as a ogg video file please read http://random-stuff-mine.blogspot.com/2017/07/encoding-raw-images-to-ogg-theora-video.html Before reading this blog post you must be aware of using and setting up libavcodec. I highly recommend this tutorial to get basics of using libavcodec http://www.ffmpeg.org/doxygen/0.6/api-example_8c-source.html Allocating input format context We will first allocate input format for reading the file. We will use avformat_open_input function that will allocate AVFormatContext structure passed to it , the function detects input typ

CryptographicException: An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information

I created a new Blazor Server app in Visual Studio 2019 and tried to run it. But I was getting this error CryptographicException: An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information. I couldn't find any reason or solution to this problem. I tried creating the project multiple times but same error. I created a new .Net Core Web App and added a new razor component and included that component in a razor page (cshtml file) like this @(await Html.RenderComponentAsync<GeofenceWork>(RenderMode.ServerPrerendered)) and <component type="typeof(GeofenceWork)" render-mode="serverprerendered" /> As soon as I navigate to this page that has component added I got the same error: CryptographicException: An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information. This was very frustrating. After hours of trying and searching I figured out the solution. 

Multithreaded C# TCP server to handle multiple clients

I decided to write a minimal multithreaded TCP based server as a blog post. Following class can serve as a skeleton for any small or large scale multithreaded TCP socket server. It do not contain much error handling , it is only to give an idea that how multithreaded server works and how it can process multiple clients using threading. using System; using System.Text; using System.Net; using System.Net.Sockets; using System.Threading; using System.Collections.Generic; namespace RandomStuffMine { public class MTServer {     public int Port{get;set;}     public Socket ServerSocket{get;set;}     private List<Client> Clients=new List<Client>();     private bool runServer=true;     public MTServer(int port)     {         Port=port;         ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);     }     public void Start()     {         Thread thr=new Thread(new ThreadStart(StartServer));         thr.IsBackground=t