1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.mms.transaction;
18
19import android.app.IntentService;
20import android.content.ContentUris;
21import android.content.ContentValues;
22import android.content.Context;
23import android.content.Intent;
24import android.database.Cursor;
25import android.database.sqlite.SqliteWrapper;
26import android.net.Uri;
27import android.provider.Telephony.Sms;
28import android.provider.Telephony.Sms.Inbox;
29import android.telephony.SmsMessage;
30import android.util.Log;
31
32import com.android.mms.LogTag;
33
34/**
35 * Service that gets started by the MessageStatusReceiver when a message status report is
36 * received.
37 */
38public class MessageStatusService extends IntentService {
39    private static final String[] ID_PROJECTION = new String[] { Sms._ID };
40    private static final String LOG_TAG = "MessageStatusReceiver";
41    private static final Uri STATUS_URI = Uri.parse("content://sms/status");
42
43    public MessageStatusService() {
44        // Class name will be the thread name.
45        super(MessageStatusService.class.getName());
46
47        // Intent should be redelivered if the process gets killed before completing the job.
48        setIntentRedelivery(true);
49    }
50
51    @Override
52    protected void onHandleIntent(Intent intent) {
53        // This method is called on a worker thread.
54
55        Uri messageUri = intent.getData();
56        byte[] pdu = intent.getByteArrayExtra("pdu");
57        String format = intent.getStringExtra("format");
58
59        SmsMessage message = updateMessageStatus(this, messageUri, pdu, format);
60
61        // Called on a background thread, so it's OK to block.
62        if (message != null && message.getStatus() < Sms.STATUS_PENDING) {
63            MessagingNotification.blockingUpdateNewMessageIndicator(this,
64                    MessagingNotification.THREAD_NONE, message.isStatusReportMessage());
65        }
66    }
67
68    private SmsMessage updateMessageStatus(Context context, Uri messageUri, byte[] pdu,
69            String format) {
70        SmsMessage message = SmsMessage.createFromPdu(pdu, format);
71        if (message == null) {
72            return null;
73        }
74        // Create a "status/#" URL and use it to update the
75        // message's status in the database.
76        Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
77                            messageUri, ID_PROJECTION, null, null, null);
78
79        try {
80            if (cursor.moveToFirst()) {
81                int messageId = cursor.getInt(0);
82
83                Uri updateUri = ContentUris.withAppendedId(STATUS_URI, messageId);
84                int status = message.getStatus();
85                boolean isStatusReport = message.isStatusReportMessage();
86                ContentValues contentValues = new ContentValues(2);
87
88                if (Log.isLoggable(LogTag.TAG, Log.DEBUG)) {
89                    log("updateMessageStatus: msgUrl=" + messageUri + ", status=" + status +
90                            ", isStatusReport=" + isStatusReport);
91                }
92
93                contentValues.put(Sms.STATUS, status);
94                contentValues.put(Inbox.DATE_SENT, System.currentTimeMillis());
95                SqliteWrapper.update(context, context.getContentResolver(),
96                                    updateUri, contentValues, null, null);
97            } else {
98                error("Can't find message for status update: " + messageUri);
99            }
100        } finally {
101            cursor.close();
102        }
103        return message;
104    }
105
106    private void error(String message) {
107        Log.e(LOG_TAG, "[MessageStatusReceiver] " + message);
108    }
109
110    private void log(String message) {
111        Log.d(LOG_TAG, "[MessageStatusReceiver] " + message);
112    }
113}
114