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