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