DeliveryReportActivity.java revision 72735c62aba8fd2a9420a0f9f83d22543e3c164f
1/*
2 * Copyright (C) 2008 Esmertec AG.
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mms.ui;
19
20import com.android.mms.R;
21import com.android.mms.ui.RecipientList.Recipient;
22import com.google.android.mms.pdu.PduHeaders;
23import com.google.android.mms.util.SqliteWrapper;
24
25import android.app.ListActivity;
26import android.content.Intent;
27import android.database.Cursor;
28import android.net.Uri;
29import android.os.Bundle;
30import android.provider.Telephony.Mms;
31import android.provider.Telephony.Sms;
32import android.telephony.PhoneNumberUtils;
33import android.text.TextUtils;
34import android.util.Log;
35import android.view.LayoutInflater;
36import android.view.View;
37import android.view.Window;
38import android.widget.ListView;
39
40import java.util.ArrayList;
41import java.util.HashMap;
42import java.util.Iterator;
43import java.util.List;
44import java.util.Map;
45import java.util.Set;
46
47/**
48 * This is the UI for displaying a delivery report:
49 *
50 * This activity can handle the following parameters from the intent
51 * by which it is launched:
52 *
53 * thread_id long The id of the conversation from which to get the recipients
54 *      for the report.
55 * message_id long The id of the message about which a report should be displayed.
56 * message_type String The type of message (Sms or Mms).  This is used in
57 *      conjunction with the message id to retrive the particular message that
58 *      the report will be about.
59 */
60public class DeliveryReportActivity extends ListActivity {
61    private static final String LOG_TAG = "DeliveryReportActivity";
62
63    static final String[] MMS_REPORT_REQUEST_PROJECTION = new String[] {
64        Mms.Addr.ADDRESS,       //0
65        Mms.DELIVERY_REPORT,    //1
66        Mms.READ_REPORT         //2
67    };
68
69    static final String[] MMS_REPORT_STATUS_PROJECTION = new String[] {
70        Mms.Addr.ADDRESS,       //0
71        "delivery_status",      //1
72        "read_status"           //2
73    };
74
75    static final String[] SMS_REPORT_STATUS_PROJECTION = new String[] {
76        Sms.ADDRESS,            //0
77        Sms.STATUS              //1
78    };
79
80    // These indices must sync up with the projections above.
81    static final int COLUMN_RECIPIENT           = 0;
82    static final int COLUMN_DELIVERY_REPORT     = 1;
83    static final int COLUMN_READ_REPORT         = 2;
84    static final int COLUMN_DELIVERY_STATUS     = 1;
85    static final int COLUMN_READ_STATUS         = 2;
86
87    private long mMessageId;
88    private String mMessageType;
89
90    @Override
91    protected void onCreate(Bundle icicle) {
92        super.onCreate(icicle);
93        requestWindowFeature(Window.FEATURE_NO_TITLE);
94        setContentView(R.layout.delivery_report_activity);
95
96        Intent intent = getIntent();
97        mMessageId = getMessageId(icicle, intent);
98        mMessageType = getMessageType(icicle, intent);
99
100        initListView();
101        initListAdapter();
102    }
103
104    private void initListView() {
105        // Add the header for the list view.
106        LayoutInflater inflater = getLayoutInflater();
107        View header = inflater.inflate(R.layout.delivery_report_header, null);
108        getListView().addHeaderView(header, null, true);
109    }
110
111    private void initListAdapter() {
112        List<DeliveryReportItem> items = getReportItems();
113        if (items == null) {
114            items = new ArrayList<DeliveryReportItem>(1);
115            items.add(new DeliveryReportItem("", getString(R.string.status_none)));
116            Log.w(LOG_TAG, "cursor == null");
117        }
118        setListAdapter(new DeliveryReportAdapter(this, items));
119    }
120
121    @Override
122    public void onResume() {
123        super.onResume();
124        refreshDeliveryReport();
125    }
126
127    private void refreshDeliveryReport() {
128        ListView list = getListView();
129        list.invalidateViews();
130        list.requestFocus();
131    }
132
133    private long getMessageId(Bundle icicle, Intent intent) {
134        long msgId = 0L;
135
136        if (icicle != null) {
137            msgId = icicle.getLong("message_id");
138        }
139
140        if (msgId == 0L) {
141            msgId = intent.getLongExtra("message_id", 0L);
142        }
143
144        return msgId;
145    }
146
147    private String getMessageType(Bundle icicle, Intent intent) {
148        String msgType = null;
149
150        if (icicle != null) {
151            msgType = icicle.getString("message_type");
152        }
153
154        if (msgType == null) {
155            msgType = intent.getStringExtra("message_type");
156        }
157
158        return msgType;
159    }
160
161    private List<DeliveryReportItem> getReportItems() {
162        if (mMessageType.equals("sms")) {
163            return getSmsReportItems();
164        } else {
165            return getMmsReportItems();
166        }
167    }
168
169    private List<DeliveryReportItem> getSmsReportItems() {
170        String selection = "_id = " + mMessageId;
171        Cursor c = SqliteWrapper.query(this, getContentResolver(), Sms.CONTENT_URI,
172                              SMS_REPORT_STATUS_PROJECTION, selection, null, null);
173        if (c == null) {
174            return null;
175        }
176
177        try {
178            if (c.getCount() <= 0) {
179                return null;
180            }
181
182            List<DeliveryReportItem> items = new ArrayList<DeliveryReportItem>();
183            while (c.moveToNext()) {
184                items.add(new DeliveryReportItem(
185                                getString(R.string.recipient_label) + c.getString(COLUMN_RECIPIENT),
186                                getString(R.string.status_label) +
187                                    getSmsStatusText(c.getInt(COLUMN_DELIVERY_STATUS))));
188            }
189            return items;
190        } finally {
191            c.close();
192        }
193    }
194
195    private String getMmsReportStatusText(
196            MmsReportRequest request,
197            Map<String, MmsReportStatus> reportStatus) {
198        if (reportStatus == null) {
199            // haven't received any reports.
200            return getString(R.string.status_pending);
201        }
202
203        String recipient = request.getRecipient();
204        recipient = (Mms.isEmailAddress(recipient))?
205                Mms.extractAddrSpec(recipient): Recipient.filterPhoneNumber(recipient);
206        MmsReportStatus status = queryStatusByRecipient(reportStatus, recipient);
207        if (status == null) {
208            // haven't received any reports.
209            return getString(R.string.status_pending);
210        }
211
212        if (request.isReadReportRequested()) {
213            if (status.readStatus != 0) {
214                switch (status.readStatus) {
215                    case PduHeaders.READ_STATUS_READ:
216                        return getString(R.string.status_read);
217                    case PduHeaders.READ_STATUS__DELETED_WITHOUT_BEING_READ:
218                        return getString(R.string.status_unread);
219                }
220            }
221        }
222
223        switch (status.deliveryStatus) {
224            case 0: // No delivery report received so far.
225                return getString(R.string.status_pending);
226            case PduHeaders.STATUS_FORWARDED:
227            case PduHeaders.STATUS_RETRIEVED:
228                return getString(R.string.status_received);
229            case PduHeaders.STATUS_REJECTED:
230                return getString(R.string.status_rejected);
231            default:
232                return getString(R.string.status_failed);
233        }
234    }
235
236    private static MmsReportStatus queryStatusByRecipient(
237            Map<String, MmsReportStatus> status, String recipient) {
238        Set<String> recipientSet = status.keySet();
239        Iterator<String> iterator = recipientSet.iterator();
240        while (iterator.hasNext()) {
241            String r = iterator.next();
242            if (Mms.isEmailAddress(recipient)) {
243                if (TextUtils.equals(r, recipient)) {
244                    return status.get(r);
245                }
246            }
247            else if (PhoneNumberUtils.compare(r, recipient)) {
248                return status.get(r);
249            }
250        }
251        return null;
252    }
253
254    private List<DeliveryReportItem> getMmsReportItems() {
255        List<MmsReportRequest> reportReqs = getMmsReportRequests();
256        if (null == reportReqs) {
257            return null;
258        }
259
260        if (reportReqs.size() == 0) {
261            return null;
262        }
263
264        Map<String, MmsReportStatus> reportStatus = getMmsReportStatus();
265        List<DeliveryReportItem> items = new ArrayList<DeliveryReportItem>();
266        for (MmsReportRequest reportReq : reportReqs) {
267            String statusText = getString(R.string.status_label) +
268                getMmsReportStatusText(reportReq, reportStatus);
269            items.add(new DeliveryReportItem(getString(R.string.recipient_label) +
270                    reportReq.getRecipient(), statusText));
271        }
272        return items;
273    }
274
275    private Map<String, MmsReportStatus> getMmsReportStatus() {
276        Uri uri = Uri.withAppendedPath(Mms.REPORT_STATUS_URI,
277                                       String.valueOf(mMessageId));
278        Cursor c = SqliteWrapper.query(this, getContentResolver(), uri,
279                       MMS_REPORT_STATUS_PROJECTION, null, null, null);
280
281        if (c == null) {
282            return null;
283        }
284
285        try {
286            Map<String, MmsReportStatus> statusMap =
287                    new HashMap<String, MmsReportStatus>();
288
289            while (c.moveToNext()) {
290                String recipient = c.getString(COLUMN_RECIPIENT);
291                recipient = (Mms.isEmailAddress(recipient))?
292                                        Mms.extractAddrSpec(recipient):
293                                        Recipient.filterPhoneNumber(recipient);
294                MmsReportStatus status = new MmsReportStatus(
295                                        c.getInt(COLUMN_DELIVERY_STATUS),
296                                        c.getInt(COLUMN_READ_STATUS));
297                statusMap.put(recipient, status);
298            }
299            return statusMap;
300        } finally {
301            c.close();
302        }
303    }
304
305    private List<MmsReportRequest> getMmsReportRequests() {
306        Uri uri = Uri.withAppendedPath(Mms.REPORT_REQUEST_URI,
307                                       String.valueOf(mMessageId));
308        Cursor c = SqliteWrapper.query(this, getContentResolver(), uri,
309                      MMS_REPORT_REQUEST_PROJECTION, null, null, null);
310
311        if (c == null) {
312            return null;
313        }
314
315        try {
316            if (c.getCount() <= 0) {
317                return null;
318            }
319
320            List<MmsReportRequest> reqList = new ArrayList<MmsReportRequest>();
321            while (c.moveToNext()) {
322                reqList.add(new MmsReportRequest(
323                                c.getString(COLUMN_RECIPIENT),
324                                c.getInt(COLUMN_DELIVERY_REPORT),
325                                c.getInt(COLUMN_READ_REPORT)));
326            }
327            return reqList;
328        } finally {
329            c.close();
330        }
331    }
332
333    private String getSmsStatusText(int status) {
334        if (status == Sms.STATUS_NONE) {
335            // No delivery report requested
336            return getString(R.string.status_none);
337        } else if (status >= Sms.STATUS_FAILED) {
338            // Failure
339            return getString(R.string.status_failed);
340        } else if (status >= Sms.STATUS_PENDING) {
341            // Pending
342            return getString(R.string.status_pending);
343        } else {
344            // Success
345            return getString(R.string.status_received);
346        }
347    }
348
349    private static final class MmsReportStatus {
350        final int deliveryStatus;
351        final int readStatus;
352
353        public MmsReportStatus(int drStatus, int rrStatus) {
354            deliveryStatus = drStatus;
355            readStatus = rrStatus;
356        }
357    }
358
359    private static final class MmsReportRequest {
360        private final String mRecipient;
361        private final boolean mIsDeliveryReportRequsted;
362        private final boolean mIsReadReportRequested;
363
364        public MmsReportRequest(String recipient, int drValue, int rrValue) {
365            mRecipient = recipient;
366            mIsDeliveryReportRequsted = drValue == PduHeaders.VALUE_YES;
367            mIsReadReportRequested = rrValue == PduHeaders.VALUE_YES;
368        }
369
370        public String getRecipient() {
371            return mRecipient;
372        }
373
374        public boolean isDeliveryReportRequested() {
375            return mIsDeliveryReportRequsted;
376        }
377
378        public boolean isReadReportRequested() {
379            return mIsReadReportRequested;
380        }
381    }
382}
383