/* * Copyright (C) 2008 Esmertec AG. * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.mms.ui; import com.android.mms.R; import com.google.android.mms.MmsException; import android.content.Context; import android.database.Cursor; import android.os.Handler; import android.provider.BaseColumns; import android.provider.Telephony.Mms; import android.provider.Telephony.MmsSms; import android.provider.Telephony.Sms; import android.provider.Telephony.MmsSms.PendingMessages; import android.provider.Telephony.Sms.Conversations; import android.util.Config; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CursorAdapter; import android.widget.ListView; import java.util.LinkedHashMap; import java.util.Map; /** * The back-end data adapter of a message list. */ public class MessageListAdapter extends CursorAdapter { private static final String TAG = "MessageListAdapter"; private static final boolean DEBUG = false; private static final boolean LOCAL_LOGV = Config.LOGV && DEBUG; static final String[] PROJECTION = new String[] { // TODO: should move this symbol into android.provider.Telephony. MmsSms.TYPE_DISCRIMINATOR_COLUMN, BaseColumns._ID, Conversations.THREAD_ID, // For SMS Sms.ADDRESS, Sms.BODY, Sms.DATE, Sms.READ, Sms.TYPE, Sms.STATUS, Sms.LOCKED, // For MMS Mms.SUBJECT, Mms.SUBJECT_CHARSET, Mms.DATE, Mms.READ, Mms.MESSAGE_TYPE, Mms.MESSAGE_BOX, Mms.DELIVERY_REPORT, Mms.READ_REPORT, PendingMessages.ERROR_TYPE, Mms.LOCKED }; // The indexes of the default columns which must be consistent // with above PROJECTION. static final int COLUMN_MSG_TYPE = 0; static final int COLUMN_ID = 1; static final int COLUMN_THREAD_ID = 2; static final int COLUMN_SMS_ADDRESS = 3; static final int COLUMN_SMS_BODY = 4; static final int COLUMN_SMS_DATE = 5; static final int COLUMN_SMS_READ = 6; static final int COLUMN_SMS_TYPE = 7; static final int COLUMN_SMS_STATUS = 8; static final int COLUMN_SMS_LOCKED = 9; static final int COLUMN_MMS_SUBJECT = 10; static final int COLUMN_MMS_SUBJECT_CHARSET = 11; static final int COLUMN_MMS_DATE = 12; static final int COLUMN_MMS_READ = 13; static final int COLUMN_MMS_MESSAGE_TYPE = 14; static final int COLUMN_MMS_MESSAGE_BOX = 15; static final int COLUMN_MMS_DELIVERY_REPORT = 16; static final int COLUMN_MMS_READ_REPORT = 17; static final int COLUMN_MMS_ERROR_TYPE = 18; static final int COLUMN_MMS_LOCKED = 19; private static final int CACHE_SIZE = 50; protected LayoutInflater mInflater; private final ListView mListView; private final LinkedHashMap mMessageItemCache; private final ColumnsMap mColumnsMap; private OnDataSetChangedListener mOnDataSetChangedListener; private Handler mMsgListItemHandler; private String mHighlight; public MessageListAdapter( Context context, Cursor c, ListView listView, boolean useDefaultColumnsMap, String highlight) { super(context, c); mHighlight = highlight != null ? highlight.toLowerCase() : null; mInflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); mListView = listView; mMessageItemCache = new LinkedHashMap( 10, 1.0f, true) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > CACHE_SIZE; } }; if (useDefaultColumnsMap) { mColumnsMap = new ColumnsMap(); } else { mColumnsMap = new ColumnsMap(c); } } @Override public void bindView(View view, Context context, Cursor cursor) { if (view instanceof MessageListItem) { String type = cursor.getString(mColumnsMap.mColumnMsgType); long msgId = cursor.getLong(mColumnsMap.mColumnMsgId); MessageItem msgItem = getCachedMessageItem(type, msgId, cursor); if (msgItem != null) { ((MessageListItem) view).bind(msgItem); ((MessageListItem) view).setMsgListItemHandler(mMsgListItemHandler); } } } public interface OnDataSetChangedListener { void onDataSetChanged(MessageListAdapter adapter); } public void setOnDataSetChangedListener(OnDataSetChangedListener l) { mOnDataSetChangedListener = l; } public void setMsgListItemHandler(Handler handler) { mMsgListItemHandler = handler; } @Override public void notifyDataSetChanged() { super.notifyDataSetChanged(); if (LOCAL_LOGV) { Log.v(TAG, "MessageListAdapter.notifyDataSetChanged()."); } mListView.setSelection(mListView.getCount()); mMessageItemCache.clear(); if (mOnDataSetChangedListener != null) { mOnDataSetChangedListener.onDataSetChanged(this); } } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return mInflater.inflate(R.layout.message_list_item, parent, false); } public MessageItem getCachedMessageItem(String type, long msgId, Cursor c) { MessageItem item = mMessageItemCache.get(getKey(type, msgId)); if (item == null) { try { item = new MessageItem(mContext, type, c, mColumnsMap, mHighlight); mMessageItemCache.put(getKey(item.mType, item.mMsgId), item); } catch (MmsException e) { Log.e(TAG, e.getMessage()); } } return item; } private static long getKey(String type, long id) { if (type.equals("mms")) { return -id; } else { return id; } } public static class ColumnsMap { public int mColumnMsgType; public int mColumnMsgId; public int mColumnSmsAddress; public int mColumnSmsBody; public int mColumnSmsDate; public int mColumnSmsRead; public int mColumnSmsType; public int mColumnSmsStatus; public int mColumnSmsLocked; public int mColumnMmsSubject; public int mColumnMmsSubjectCharset; public int mColumnMmsDate; public int mColumnMmsRead; public int mColumnMmsMessageType; public int mColumnMmsMessageBox; public int mColumnMmsDeliveryReport; public int mColumnMmsReadReport; public int mColumnMmsErrorType; public int mColumnMmsLocked; public ColumnsMap() { mColumnMsgType = COLUMN_MSG_TYPE; mColumnMsgId = COLUMN_ID; mColumnSmsAddress = COLUMN_SMS_ADDRESS; mColumnSmsBody = COLUMN_SMS_BODY; mColumnSmsDate = COLUMN_SMS_DATE; mColumnSmsType = COLUMN_SMS_TYPE; mColumnSmsStatus = COLUMN_SMS_STATUS; mColumnSmsLocked = COLUMN_SMS_LOCKED; mColumnMmsSubject = COLUMN_MMS_SUBJECT; mColumnMmsSubjectCharset = COLUMN_MMS_SUBJECT_CHARSET; mColumnMmsMessageType = COLUMN_MMS_MESSAGE_TYPE; mColumnMmsMessageBox = COLUMN_MMS_MESSAGE_BOX; mColumnMmsDeliveryReport = COLUMN_MMS_DELIVERY_REPORT; mColumnMmsReadReport = COLUMN_MMS_READ_REPORT; mColumnMmsErrorType = COLUMN_MMS_ERROR_TYPE; mColumnMmsLocked = COLUMN_MMS_LOCKED; } public ColumnsMap(Cursor cursor) { // Ignore all 'not found' exceptions since the custom columns // may be just a subset of the default columns. try { mColumnMsgType = cursor.getColumnIndexOrThrow( MmsSms.TYPE_DISCRIMINATOR_COLUMN); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnMsgId = cursor.getColumnIndexOrThrow(BaseColumns._ID); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnSmsAddress = cursor.getColumnIndexOrThrow(Sms.ADDRESS); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnSmsBody = cursor.getColumnIndexOrThrow(Sms.BODY); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnSmsDate = cursor.getColumnIndexOrThrow(Sms.DATE); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnSmsType = cursor.getColumnIndexOrThrow(Sms.TYPE); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnSmsStatus = cursor.getColumnIndexOrThrow(Sms.STATUS); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnSmsLocked = cursor.getColumnIndexOrThrow(Sms.LOCKED); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnMmsSubject = cursor.getColumnIndexOrThrow(Mms.SUBJECT); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnMmsSubjectCharset = cursor.getColumnIndexOrThrow(Mms.SUBJECT_CHARSET); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnMmsMessageType = cursor.getColumnIndexOrThrow(Mms.MESSAGE_TYPE); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnMmsMessageBox = cursor.getColumnIndexOrThrow(Mms.MESSAGE_BOX); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnMmsDeliveryReport = cursor.getColumnIndexOrThrow(Mms.DELIVERY_REPORT); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnMmsReadReport = cursor.getColumnIndexOrThrow(Mms.READ_REPORT); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnMmsErrorType = cursor.getColumnIndexOrThrow(PendingMessages.ERROR_TYPE); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } try { mColumnMmsLocked = cursor.getColumnIndexOrThrow(Mms.LOCKED); } catch (IllegalArgumentException e) { Log.w("colsMap", e.getMessage()); } } } }