Showing posts with label SMS. Show all posts
Showing posts with label SMS. Show all posts

Friday, February 3, 2012

Sending SMS on Android and tracking it

Lets look at how to send an SMS. It's pretty simple though. A few lines of code and your SMS is gone. To make it more convenient and meaningful, we should also be able to track and let the user know when the SMS is sent and when it is delivered. For a start, I won't be looking into how to trap the error messages here and log or show it to the user. May be, when I get some more time, I will update this post. For now, lets track our SMS.
        Intent sentIntent = new Intent(INTENT_ACTION_SENT);
        PendingIntent pendingSentIntent = PendingIntent.getBroadcast(this,
                REQUEST_CODE_ACTION_SENT, sentIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        Intent deliveryIntent = new Intent(INTENT_ACTION_DELIVERY);
        PendingIntent pendingDeliveryIntent = PendingIntent.getBroadcast(this,
                REQUEST_CODE_ACTION_DELIVERY, deliveryIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        SmsManager smsManager = SmsManager.getDefault();

        // Second parameter is the service center number. Use null if you want
        // to use the default number
        smsManager.sendTextMessage(number, null, message, pendingSentIntent,
                pendingDeliveryIntent);

In the above code snipped, you can see that we are passing 2 pending intents to the SMSManager, one of which will be fired when the SMS is sent, and the other, when the SMS is delivered. It would also let you know the error type if the sending or delivery fails, so that you can take action for the errors. INTENT_ACTION_SENT and INTENT_ACTION_DELIVERY are string constants, which are just some random actions required to setup of the PendingIntents and receive them back.

Setting up the SMS is super easy. How do we track or listen to the updates, which happen through the PendingIntents? Well, those pending intents could be for starting an Activity, a Service or sending out a Broadcast. As you can see, here, I have used a Broadcast, to keep it simple. So, in our activity, we would need to register BroadcastReceivers for the same actions.
        IntentFilter filter = new IntentFilter(INTENT_ACTION_SENT);
        filter.addAction(INTENT_ACTION_DELIVERY);

        registerReceiver(smsSentDeliveredReceiver, filter);

Now, the onReceive() method will be fired, when those events happen, and thus you can notify the user about when the message is sent and delivered.
        String action = intent.getAction();
        Log.i(TAG, "Received: " + action);

        if (action.equals(INTENT_ACTION_SENT)) {
            Log.i(TAG, "Message: Sent");
            Toast.makeText(this, "Message sent", Toast.LENGTH_LONG).show();
        } else if (action.equals(INTENT_ACTION_DELIVERY)) {
            Log.i(TAG, "Message: Delivered");
            Toast.makeText(this, "Message delivered", Toast.LENGTH_LONG).show();
        }

You can find the sample app and the source code here. Give it a run.

Note: Using this example, you cannot send SMS to real numbers from an emulator. The SMS will be sent, but it will never be delivered.

Monday, September 7, 2009

SMS Blocking in Android

Recently, I tried to develop an app that would block sms from certain numbers that you can choose. It seems that you cannot completely block the incoming sms. These were the problems that I faced while working with this app.

1. There are no APIs supplied, that handles the SMS inbox (I mean, no content providersm which can be directly queried to fetch records from the sms table). However, you have a workaround of finding the tables where the sms is stored, and then querying and updating that table. Well, there is actually a content provider, that exposes this table to other applications, but it is not documented anywhere. So, I have to hardcode the column values. This is potentially dangerous, if in the next Donut release, Google changes the column names, my application would fall apart.

2. On receiving of an SMS, I have 2 things to do. Remove the SMS from the sms table, and disable the notification. Deleting the sms from the table was pretty easy, but I couldn't find a way to remove the Notification. Perhaps, there is no way that we can disable this notification. One workaround might be, to temporarily change the Notification settings, the moment you sense an incoming message from a blocked number. And, after you delete the message from the sms table, you just turn on the notification. I haven't worked on this, but this might just work.

3. If the Messaging application is already open, and an sms arrives, weird things start to happen. I can see the blocked sms being deleted, and the list of sms gets updated. But the next message in the list is marked as "Unread". Probably, this is done by the Notification, I don't know.

4. SMS broadcast, is definitely, an un-ordered one. So, the easiest way, that could have worked, would have been just to abort the broadcast. But in this case, you don't have this option. so, once you recieve this broadcast, you have to manually go and delete the message, by matching the incoming number, timestamp etc. Timestamp method isn't foolproof. Because, the timestamp you receive, is the timestamp of the broadcast, and not the time when the sms is written into the DB. So they wont match. You should pick up the incoming number, and check for the timestamp within a range of about 1 seconds. This should give you the sms that you need to delete.

5. There's another problem. When you recieve the broadcast, the system wont write the sms into the table, before it is sure that all the broadcast receivers have done their work. So, it waits for some time, and then writes the sms into the table. Before this, if you try to delete the sms, obviously, you would not find it in the table. So, make your code sleep for about a second, and then go and delete the SMS. That should do it. But, the most important problem still persists. THE NOTIFICATION. I guess, it can't be removed.