MessageListAdapter.java revision 161375d2c4eff31add607fc0befa5c781c6fd7f1
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.MmsException; 22 23import android.content.Context; 24import android.database.Cursor; 25import android.os.Handler; 26import android.provider.BaseColumns; 27import android.provider.Telephony.Mms; 28import android.provider.Telephony.MmsSms; 29import android.provider.Telephony.Sms; 30import android.provider.Telephony.MmsSms.PendingMessages; 31import android.provider.Telephony.Sms.Conversations; 32import android.util.Config; 33import android.util.Log; 34import android.view.LayoutInflater; 35import android.view.View; 36import android.view.ViewGroup; 37import android.widget.CursorAdapter; 38import android.widget.ListView; 39 40import java.util.LinkedHashMap; 41import java.util.Map; 42 43/** 44 * The back-end data adapter of a message list. 45 */ 46public class MessageListAdapter extends CursorAdapter { 47 private static final String TAG = "MessageListAdapter"; 48 private static final boolean DEBUG = false; 49 private static final boolean LOCAL_LOGV = Config.LOGV && DEBUG; 50 51 static final String[] PROJECTION = new String[] { 52 // TODO: should move this symbol into android.provider.Telephony. 53 MmsSms.TYPE_DISCRIMINATOR_COLUMN, 54 BaseColumns._ID, 55 Conversations.THREAD_ID, 56 // For SMS 57 Sms.ADDRESS, 58 Sms.BODY, 59 Sms.DATE, 60 Sms.READ, 61 Sms.TYPE, 62 Sms.STATUS, 63 Sms.LOCKED, 64 Sms.ERROR_CODE, 65 // For MMS 66 Mms.SUBJECT, 67 Mms.SUBJECT_CHARSET, 68 Mms.DATE, 69 Mms.READ, 70 Mms.MESSAGE_TYPE, 71 Mms.MESSAGE_BOX, 72 Mms.DELIVERY_REPORT, 73 Mms.READ_REPORT, 74 PendingMessages.ERROR_TYPE, 75 Mms.LOCKED 76 }; 77 78 // The indexes of the default columns which must be consistent 79 // with above PROJECTION. 80 static final int COLUMN_MSG_TYPE = 0; 81 static final int COLUMN_ID = 1; 82 static final int COLUMN_THREAD_ID = 2; 83 static final int COLUMN_SMS_ADDRESS = 3; 84 static final int COLUMN_SMS_BODY = 4; 85 static final int COLUMN_SMS_DATE = 5; 86 static final int COLUMN_SMS_READ = 6; 87 static final int COLUMN_SMS_TYPE = 7; 88 static final int COLUMN_SMS_STATUS = 8; 89 static final int COLUMN_SMS_LOCKED = 9; 90 static final int COLUMN_SMS_ERROR_CODE = 10; 91 static final int COLUMN_MMS_SUBJECT = 11; 92 static final int COLUMN_MMS_SUBJECT_CHARSET = 12; 93 static final int COLUMN_MMS_DATE = 13; 94 static final int COLUMN_MMS_READ = 14; 95 static final int COLUMN_MMS_MESSAGE_TYPE = 15; 96 static final int COLUMN_MMS_MESSAGE_BOX = 16; 97 static final int COLUMN_MMS_DELIVERY_REPORT = 17; 98 static final int COLUMN_MMS_READ_REPORT = 18; 99 static final int COLUMN_MMS_ERROR_TYPE = 19; 100 static final int COLUMN_MMS_LOCKED = 20; 101 102 private static final int CACHE_SIZE = 50; 103 104 protected LayoutInflater mInflater; 105 private final ListView mListView; 106 private final LinkedHashMap<Long, MessageItem> mMessageItemCache; 107 private final ColumnsMap mColumnsMap; 108 private OnDataSetChangedListener mOnDataSetChangedListener; 109 private Handler mMsgListItemHandler; 110 private String mHighlight; 111 112 public MessageListAdapter( 113 Context context, Cursor c, ListView listView, 114 boolean useDefaultColumnsMap, String highlight, boolean autoRequery) { 115 super(context, c, autoRequery /* auto-requery */); 116 mHighlight = highlight != null ? highlight.toLowerCase() : null; 117 118 mInflater = (LayoutInflater) context.getSystemService( 119 Context.LAYOUT_INFLATER_SERVICE); 120 mListView = listView; 121 mMessageItemCache = new LinkedHashMap<Long, MessageItem>( 122 10, 1.0f, true) { 123 @Override 124 protected boolean removeEldestEntry(Map.Entry eldest) { 125 return size() > CACHE_SIZE; 126 } 127 }; 128 129 if (useDefaultColumnsMap) { 130 mColumnsMap = new ColumnsMap(); 131 } else { 132 mColumnsMap = new ColumnsMap(c); 133 } 134 } 135 136 @Override 137 public void bindView(View view, Context context, Cursor cursor) { 138 if (view instanceof MessageListItem) { 139 String type = cursor.getString(mColumnsMap.mColumnMsgType); 140 long msgId = cursor.getLong(mColumnsMap.mColumnMsgId); 141 142 MessageItem msgItem = getCachedMessageItem(type, msgId, cursor); 143 if (msgItem != null) { 144 ((MessageListItem) view).bind(msgItem); 145 ((MessageListItem) view).setMsgListItemHandler(mMsgListItemHandler); 146 } 147 } 148 } 149 150 public interface OnDataSetChangedListener { 151 void onDataSetChanged(MessageListAdapter adapter); 152 void onContentChanged(MessageListAdapter adapter); 153 } 154 155 public void setOnDataSetChangedListener(OnDataSetChangedListener l) { 156 mOnDataSetChangedListener = l; 157 } 158 159 public void setMsgListItemHandler(Handler handler) { 160 mMsgListItemHandler = handler; 161 } 162 163 @Override 164 public void notifyDataSetChanged() { 165 super.notifyDataSetChanged(); 166 if (LOCAL_LOGV) { 167 Log.v(TAG, "MessageListAdapter.notifyDataSetChanged()."); 168 } 169 170 mListView.setSelection(mListView.getCount()); 171 mMessageItemCache.clear(); 172 173 if (mOnDataSetChangedListener != null) { 174 mOnDataSetChangedListener.onDataSetChanged(this); 175 } 176 } 177 178 @Override 179 protected void onContentChanged() { 180 if (mAutoRequery) { 181 super.onContentChanged(); 182 return; 183 } 184 if (mCursor != null && !mCursor.isClosed()) { 185 if (mOnDataSetChangedListener != null) { 186 mOnDataSetChangedListener.onContentChanged(this); 187 } 188 } 189 } 190 191 @Override 192 public View newView(Context context, Cursor cursor, ViewGroup parent) { 193 return mInflater.inflate(R.layout.message_list_item, parent, false); 194 } 195 196 public MessageItem getCachedMessageItem(String type, long msgId, Cursor c) { 197 MessageItem item = mMessageItemCache.get(getKey(type, msgId)); 198 if (item == null) { 199 try { 200 item = new MessageItem(mContext, type, c, mColumnsMap, mHighlight); 201 mMessageItemCache.put(getKey(item.mType, item.mMsgId), item); 202 } catch (MmsException e) { 203 Log.e(TAG, e.getMessage()); 204 } 205 } 206 return item; 207 } 208 209 private static long getKey(String type, long id) { 210 if (type.equals("mms")) { 211 return -id; 212 } else { 213 return id; 214 } 215 } 216 217 public static class ColumnsMap { 218 public int mColumnMsgType; 219 public int mColumnMsgId; 220 public int mColumnSmsAddress; 221 public int mColumnSmsBody; 222 public int mColumnSmsDate; 223 public int mColumnSmsRead; 224 public int mColumnSmsType; 225 public int mColumnSmsStatus; 226 public int mColumnSmsLocked; 227 public int mColumnSmsErrorCode; 228 public int mColumnMmsSubject; 229 public int mColumnMmsSubjectCharset; 230 public int mColumnMmsDate; 231 public int mColumnMmsRead; 232 public int mColumnMmsMessageType; 233 public int mColumnMmsMessageBox; 234 public int mColumnMmsDeliveryReport; 235 public int mColumnMmsReadReport; 236 public int mColumnMmsErrorType; 237 public int mColumnMmsLocked; 238 239 public ColumnsMap() { 240 mColumnMsgType = COLUMN_MSG_TYPE; 241 mColumnMsgId = COLUMN_ID; 242 mColumnSmsAddress = COLUMN_SMS_ADDRESS; 243 mColumnSmsBody = COLUMN_SMS_BODY; 244 mColumnSmsDate = COLUMN_SMS_DATE; 245 mColumnSmsType = COLUMN_SMS_TYPE; 246 mColumnSmsStatus = COLUMN_SMS_STATUS; 247 mColumnSmsLocked = COLUMN_SMS_LOCKED; 248 mColumnSmsErrorCode = COLUMN_SMS_ERROR_CODE; 249 mColumnMmsSubject = COLUMN_MMS_SUBJECT; 250 mColumnMmsSubjectCharset = COLUMN_MMS_SUBJECT_CHARSET; 251 mColumnMmsMessageType = COLUMN_MMS_MESSAGE_TYPE; 252 mColumnMmsMessageBox = COLUMN_MMS_MESSAGE_BOX; 253 mColumnMmsDeliveryReport = COLUMN_MMS_DELIVERY_REPORT; 254 mColumnMmsReadReport = COLUMN_MMS_READ_REPORT; 255 mColumnMmsErrorType = COLUMN_MMS_ERROR_TYPE; 256 mColumnMmsLocked = COLUMN_MMS_LOCKED; 257 } 258 259 public ColumnsMap(Cursor cursor) { 260 // Ignore all 'not found' exceptions since the custom columns 261 // may be just a subset of the default columns. 262 try { 263 mColumnMsgType = cursor.getColumnIndexOrThrow( 264 MmsSms.TYPE_DISCRIMINATOR_COLUMN); 265 } catch (IllegalArgumentException e) { 266 Log.w("colsMap", e.getMessage()); 267 } 268 269 try { 270 mColumnMsgId = cursor.getColumnIndexOrThrow(BaseColumns._ID); 271 } catch (IllegalArgumentException e) { 272 Log.w("colsMap", e.getMessage()); 273 } 274 275 try { 276 mColumnSmsAddress = cursor.getColumnIndexOrThrow(Sms.ADDRESS); 277 } catch (IllegalArgumentException e) { 278 Log.w("colsMap", e.getMessage()); 279 } 280 281 try { 282 mColumnSmsBody = cursor.getColumnIndexOrThrow(Sms.BODY); 283 } catch (IllegalArgumentException e) { 284 Log.w("colsMap", e.getMessage()); 285 } 286 287 try { 288 mColumnSmsDate = cursor.getColumnIndexOrThrow(Sms.DATE); 289 } catch (IllegalArgumentException e) { 290 Log.w("colsMap", e.getMessage()); 291 } 292 293 try { 294 mColumnSmsType = cursor.getColumnIndexOrThrow(Sms.TYPE); 295 } catch (IllegalArgumentException e) { 296 Log.w("colsMap", e.getMessage()); 297 } 298 299 try { 300 mColumnSmsStatus = cursor.getColumnIndexOrThrow(Sms.STATUS); 301 } catch (IllegalArgumentException e) { 302 Log.w("colsMap", e.getMessage()); 303 } 304 305 try { 306 mColumnSmsLocked = cursor.getColumnIndexOrThrow(Sms.LOCKED); 307 } catch (IllegalArgumentException e) { 308 Log.w("colsMap", e.getMessage()); 309 } 310 311 try { 312 mColumnSmsErrorCode = cursor.getColumnIndexOrThrow(Sms.ERROR_CODE); 313 } catch (IllegalArgumentException e) { 314 Log.w("colsMap", e.getMessage()); 315 } 316 317 try { 318 mColumnMmsSubject = cursor.getColumnIndexOrThrow(Mms.SUBJECT); 319 } catch (IllegalArgumentException e) { 320 Log.w("colsMap", e.getMessage()); 321 } 322 323 try { 324 mColumnMmsSubjectCharset = cursor.getColumnIndexOrThrow(Mms.SUBJECT_CHARSET); 325 } catch (IllegalArgumentException e) { 326 Log.w("colsMap", e.getMessage()); 327 } 328 329 try { 330 mColumnMmsMessageType = cursor.getColumnIndexOrThrow(Mms.MESSAGE_TYPE); 331 } catch (IllegalArgumentException e) { 332 Log.w("colsMap", e.getMessage()); 333 } 334 335 try { 336 mColumnMmsMessageBox = cursor.getColumnIndexOrThrow(Mms.MESSAGE_BOX); 337 } catch (IllegalArgumentException e) { 338 Log.w("colsMap", e.getMessage()); 339 } 340 341 try { 342 mColumnMmsDeliveryReport = cursor.getColumnIndexOrThrow(Mms.DELIVERY_REPORT); 343 } catch (IllegalArgumentException e) { 344 Log.w("colsMap", e.getMessage()); 345 } 346 347 try { 348 mColumnMmsReadReport = cursor.getColumnIndexOrThrow(Mms.READ_REPORT); 349 } catch (IllegalArgumentException e) { 350 Log.w("colsMap", e.getMessage()); 351 } 352 353 try { 354 mColumnMmsErrorType = cursor.getColumnIndexOrThrow(PendingMessages.ERROR_TYPE); 355 } catch (IllegalArgumentException e) { 356 Log.w("colsMap", e.getMessage()); 357 } 358 359 try { 360 mColumnMmsLocked = cursor.getColumnIndexOrThrow(Mms.LOCKED); 361 } catch (IllegalArgumentException e) { 362 Log.w("colsMap", e.getMessage()); 363 } 364 } 365 } 366} 367