• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps How to Receive and Handle SMS on Android

KaterinaDekha

Lurker
Jul 30, 2015
4
0
Author: Apriorit (Driver Development Team)

Permanent link: http://apriorit.com/our-company/dev-blog/227-handle-sms-on-android

This article is useful for you if you want to develop your own SMS (or another service) handler. As a sample, I choose received SMS handler that receives SMS, encrypts them, and puts into the SMS table of the Android system database.

Android Manifest
Manifest is a very important part of an Android application. You can find everything about the Android manifest by this link.

And now I’ll try to describe every line that is important for us.

The first are permissions . The application must receive, write and read SMS from the database. Permissions can be obtained as follows:

1.<uses-permission android:name="android.permission.WRITE_SMS"/>

2.<uses-permission android:name="android.permission.READ_SMS"/>

3.<uses-permission android:name="android.permission.RECEIVE_SMS"/>

Now it’s time to write a standard activity starting. This is a part of an application that will show us SMS and will decrypt encrypted ones. There is nothing special:

1.<activity android:name=".SecureMessagesActivity"android:label="@String/app_name">

2. <intent-filter>

3. <action android:name="android.intent.action.MAIN"/>

4. <category android:name="android.intent.category.LAUNCHER"/>

5. </intent-filter>

6.</activity>

And now we need to catch all received SMS into our SMS receiver:

1.<receiver android:name=".SmsReceiver"android:exported="true">

2. <intent-filter android:priority="999">

3. <action android:name="android.provider.Telephony.SMS_RECEIVED"/>

4. </intent-filter>

5.</receiver>

Where

android:exported indicates that the SmsReceiver class must receive event not only from the application but also from the whole Android system.

android:priority=”999” indicates that receiver has the highest priority and will catch the SMS event before the system. Be careful with this because incorrect work of your receiver can corrupt the system or important data in your device. You can read about priority values here.

<action android:name="android.provider.Telephony.SMS_RECEIVED" /> indicates that we want to get received SMS.

View Model
The project contains only one XML layout. There is one button and one list. The button is used for getting inbox SMS from the system and the list is used for showing messages.

Here is the XML layout code:

01.<?xmlversion="1.0"encoding="utf-8"?>

02.<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

03. android:eek:rientation="vertical"android:layout_width="fill_parent"

04. android:layout_height="fill_parent"android:id="@+id/MainLayout"

05. android:background="@android:color/background_light">

06.

07. <Buttonandroid:layout_height="wrap_content"

08. android:layout_width="match_parent"android:id="@+id/UpdateList"

09. android:layout_margin="2dip"

10. android:text="Update SMS list"/>

11.

12. <ListViewandroid:id="@+id/SMSList"

13. android:layout_height="wrap_content"

14. android:layout_width="match_parent"

15. android:layout_margin="2dip"/>

16.

17.</LinearLayout>

And the UI screenshot:

C:\Users\DEKHA~1.EKA\AppData\Local\Temp\msohtmlclip1\01\clip_image002.jpg


Listeners will be described later.

Encryption/Decryption
All incoming SMS will be encrypted. For this reason, the class, which provides encrypting and decrypting, is added.

I use the AES algorithm and standard Android libraries. You can use this class for your own purposes.

String encrypt( String password, String data ) – encrypts string where the key will be generated using a password string. The returned value is a Base64 string that was previously encrypted.

01.// Encrypts string and encodes in Base64

02.publicstaticString encrypt( String password, String data ) throwsException

03.{

04. byte[] secretKey = generateKey( password.getBytes() );

05. byte[] clear = data.getBytes();

06.

07. SecretKeySpec secretKeySpec = newSecretKeySpec( secretKey, CIPHER_ALGORITHM );

08. Cipher cipher = Cipher.getInstance( CIPHER_ALGORITHM );

09. cipher.init( Cipher.ENCRYPT_MODE, secretKeySpec );

10.

11. byte[] encrypted = cipher.doFinal( clear );

12. String encryptedString = Base64.encodeToString( encrypted, Base64.DEFAULT );

13.

14. returnencryptedString;

15.}

String decrypt( String password, String encryptedData ) – decrypts a Base64 string with a password string.

01.// Decrypts string encoded in Base64

02.publicstaticString decrypt( String password, String encryptedData ) throwsException

03.{

04. byte[] secretKey = generateKey( password.getBytes() );

05.

06. SecretKeySpec secretKeySpec = newSecretKeySpec( secretKey, CIPHER_ALGORITHM );

07. Cipher cipher = Cipher.getInstance( CIPHER_ALGORITHM );

08. cipher.init( Cipher.DECRYPT_MODE, secretKeySpec );

09.

10. byte[] encrypted = Base64.decode( encryptedData, Base64.DEFAULT );

11. byte[] decrypted = cipher.doFinal( encrypted );

12.

13. returnnewString( decrypted );

14.}

byte[] generateKey( byte[] seed ) – generates a secret key using a seed (String.getBytes() in our case). A secret key is a byte array generated for the specific encryption algorithm.

01.publicstaticbyte[] generateKey( byte[] seed ) throwsException

02.{

03. KeyGenerator keyGenerator = KeyGenerator.getInstance( CIPHER_ALGORITHM );

04. SecureRandom secureRandom = SecureRandom.getInstance( RANDOM_GENERATOR_ALGORITHM );

05. secureRandom.setSeed( seed );

06. keyGenerator.init( RANDOM_KEY_SIZE, secureRandom );

07. SecretKey secretKey = keyGenerator.generateKey();

08. returnsecretKey.getEncoded();

09.}



Handle Received SMS
The main class that receives the SMS is SmsReceiver. It extends BroadcastReceiver class. This is the main concept of any Android service or receiver. Any child of BroadcastReceiver must contain the onReceive method, which receives Context and Intent parameters. You can find all additional information on the Android developer documentation site.

So, we get event and go into the onReceive method. The first line is:

Bundle extras = intent.getExtras();
The Bundle object is a simple map. It contains pairs of keys and values. SMS are placed in this bundle. The key of SMS is pdus:

1.publicstaticfinalString SMS_EXTRA_NAME =”pdus”;

2.…

3.Object[] smsExtra = (Object[]) extras.get( SMS_EXTRA_NAME );

After this, the smsExtra value contains arrays of bytes. Here is a full example:

01.publicvoidonReceive( Context context, Intent intent )

02. {

03. // Get the SMS map from Intent

04. Bundle extras = intent.getExtras();

05.

06. String messages = "";

07.

08. if( extras != null)

09. {

10. // Get received SMS array

11. Object[] smsExtra = (Object[]) extras.get( SMS_EXTRA_NAME );

12.

13. // Get ContentResolver object for pushing encrypted SMS to the incoming folder

14. ContentResolver contentResolver = context.getContentResolver();

15.

16. for( inti = 0; i < smsExtra.length; ++i )

17. {

18. SmsMessage sms = SmsMessage.createFromPdu((byte[])smsExtra);

19.

20. String body = sms.getMessageBody().toString();

21. String address = sms.getOriginatingAddress();

22.

23. messages += "SMS from "+ address + " :\n";

24. messages += body + "\n";

25.

26. // Here you can add any your code to work with incoming SMS

27. // I added encrypting of all received SMS

28.

29. putSmsToDatabase( contentResolver, sms );

30. }

31.

32. // Display SMS message

33. Toast.makeText( context, messages, Toast.LENGTH_SHORT ).show();

34. }

35.

36. // WARNING!!!

37. // If you uncomment the next line then received SMS will not be put to incoming.

38. // Be careful!

39. // this.abortBroadcast();

40. }

So, when the SMS list gets into smsExtra, then SMS should be parsed. And the method createFromPdu from SmsMessage class should be called for this. I do not write about the methods and fields of SmsMessage class because it is documented enough.

So, SmsReceiver gets the SMS and now can do anything with it. In the example, SMS are encrypted and put into the SMS table of the device database. I need this to allow the encrypted SMS viewing by the default Android SMS viewer.

Of course, the PDU (Protocol Description Unit) can be parsed and generated manually, but its format can be changed anytime by Google. If you are interested in researching the PDU format, you can analyze it at Android sources: for CDMA phones and for GSM phones.

When SMS is got, it is shown using the Toast class. And I want to tell you about the last commented line:

// this.abortBroadcast();
I commented it because it’s dangerous. As you remember, the receiver catches SMS events before the system works with it. So, the abortBroadcast method stops the SMS dispatching to other receivers. If something is going wrong, the SMS will not be saved.

You can see the full example at the attached sources.

Read and Decrypt SMS
I want to tell you why the activity is needed. Below the click listener for the button on the main screen is listed. In the following code, all SMS that are placed in Inbox are read and then the sender information and SMS text are put into the list:

01.publicvoidonClick( View v )

02.{

03. ContentResolver contentResolver = getContentResolver();

04. Cursor cursor = contentResolver.query( Uri.parse( "content://sms/inbox"), null, null, null, null);

05.

06. intindexBody = cursor.getColumnIndex( SmsReceiver.BODY );

07. intindexAddr = cursor.getColumnIndex( SmsReceiver.ADDRESS );

08.

09. if( indexBody < 0|| !cursor.moveToFirst() ) return;

10.

11. smsList.clear();

12.

13. do

14. {

15. String str = "Sender: "+ cursor.getString( indexAddr ) + "\n"+ cursor.getString( indexBody );

16. smsList.add( str );

17. }

18. while( cursor.moveToNext() );

19.

20. ListView smsListView = (ListView) findViewById( R.id.SMSList );

21. smsListView.setAdapter( newArrayAdapter<String>( this, android.R.layout.simple_list_item_1, smsList) );

22. smsListView.setOnItemClickListener( this);

23.}

The SMS text is obtained from the list, decrypted and then shown. SmsReceiver.PASSWORD can be changed in any way. The list item listener is as follows:

01.publicvoidonItemClick( AdapterView<?> parent, View view, intpos, longid )

02. {

03. try

04. {

05. String sender = smsList.get( pos ).split("\n")[0];

06. String encryptedData = smsList.get( pos ).split("\n")[1];

07. String data = sender + "\n"+ StringCryptor.decrypt( newString(SmsReceiver.PASSWORD), encryptedData );

08. Toast.makeText( this, data, Toast.LENGTH_SHORT ).show();

09. }

10. catch(Exception e)

11. {

12. e.printStackTrace();

13. }

14. }



You can download the sample project sources at the official article page http://apriorit.com/our-company/dev-blog/227-handle-sms-on-android.
 

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones