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