MessagesAdapter.java revision 06a2f4a3b1322fb6fecb908bd04e777199529ce7
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.email.activity;
18
19import com.android.email.Email;
20import com.android.email.ResourceHelper;
21import com.android.email.Utility;
22import com.android.email.data.ThrottlingCursorLoader;
23import com.android.email.provider.EmailContent;
24import com.android.email.provider.EmailContent.Message;
25import com.android.email.provider.EmailContent.MessageColumns;
26
27import android.content.Context;
28import android.content.Loader;
29import android.database.Cursor;
30import android.os.Bundle;
31import android.util.Log;
32import android.view.View;
33import android.view.ViewGroup;
34import android.widget.CursorAdapter;
35
36import java.util.HashSet;
37import java.util.Set;
38
39
40/**
41 * This class implements the adapter for displaying messages based on cursors.
42 */
43/* package */ class MessagesAdapter extends CursorAdapter {
44    private static final String STATE_CHECKED_ITEMS =
45            "com.android.email.activity.MessagesAdapter.checkedItems";
46
47    /* package */ static final String[] MESSAGE_PROJECTION = new String[] {
48        EmailContent.RECORD_ID, MessageColumns.MAILBOX_KEY, MessageColumns.ACCOUNT_KEY,
49        MessageColumns.DISPLAY_NAME, MessageColumns.SUBJECT, MessageColumns.TIMESTAMP,
50        MessageColumns.FLAG_READ, MessageColumns.FLAG_FAVORITE, MessageColumns.FLAG_ATTACHMENT,
51        MessageColumns.FLAGS, MessageColumns.SNIPPET
52    };
53
54    public static final int COLUMN_ID = 0;
55    public static final int COLUMN_MAILBOX_KEY = 1;
56    public static final int COLUMN_ACCOUNT_KEY = 2;
57    public static final int COLUMN_DISPLAY_NAME = 3;
58    public static final int COLUMN_SUBJECT = 4;
59    public static final int COLUMN_DATE = 5;
60    public static final int COLUMN_READ = 6;
61    public static final int COLUMN_FAVORITE = 7;
62    public static final int COLUMN_ATTACHMENTS = 8;
63    public static final int COLUMN_FLAGS = 9;
64    public static final int COLUMN_SNIPPET = 10;
65
66    private final ResourceHelper mResourceHelper;
67
68    /** If true, show color chips. */
69    private boolean mShowColorChips;
70
71    /**
72     * Set of seleced message IDs.
73     */
74    private final HashSet<Long> mSelectedSet = new HashSet<Long>();
75
76    /**
77     * Callback from MessageListAdapter.  All methods are called on the UI thread.
78     */
79    public interface Callback {
80        /** Called when the use starts/unstars a message */
81        void onAdapterFavoriteChanged(MessageListItem itemView, boolean newFavorite);
82        /** Called when the user selects/unselects a message */
83        void onAdapterSelectedChanged(MessageListItem itemView, boolean newSelected,
84                int mSelectedCount);
85    }
86
87    private final Callback mCallback;
88
89    public MessagesAdapter(Context context, Callback callback) {
90        super(context.getApplicationContext(), null, 0 /* no auto requery */);
91        mResourceHelper = ResourceHelper.getInstance(context);
92        mCallback = callback;
93    }
94
95    public void onSaveInstanceState(Bundle outState) {
96        Set<Long> checkedset = getSelectedSet();
97        long[] checkedarray = new long[checkedset.size()];
98        int i = 0;
99        for (Long l : checkedset) {
100            checkedarray[i] = l;
101            i++;
102        }
103        outState.putLongArray(STATE_CHECKED_ITEMS, checkedarray);
104    }
105
106    public void loadState(Bundle savedInstanceState) {
107        Set<Long> checkedset = getSelectedSet();
108        for (long l: savedInstanceState.getLongArray(STATE_CHECKED_ITEMS)) {
109            checkedset.add(l);
110        }
111    }
112
113    /**
114     * Set true for combined mailboxes.
115     */
116    public void setShowColorChips(boolean show) {
117        mShowColorChips = show;
118    }
119
120    public Set<Long> getSelectedSet() {
121        return mSelectedSet;
122    }
123
124    public boolean isSelected(MessageListItem itemView) {
125        return mSelectedSet.contains(itemView.mMessageId);
126    }
127
128    @Override
129    public void bindView(View view, Context context, Cursor cursor) {
130        // Reset the view (in case it was recycled) and prepare for binding
131        MessageListItem itemView = (MessageListItem) view;
132        itemView.bindViewInit(this);
133
134        // Load the public fields in the view (for later use)
135        itemView.mMessageId = cursor.getLong(COLUMN_ID);
136        itemView.mMailboxId = cursor.getLong(COLUMN_MAILBOX_KEY);
137        final long accountId = cursor.getLong(COLUMN_ACCOUNT_KEY);
138        itemView.mAccountId = accountId;
139        itemView.mRead = cursor.getInt(COLUMN_READ) != 0;
140        itemView.mIsFavorite = cursor.getInt(COLUMN_FAVORITE) != 0;
141        itemView.mHasInvite =
142            (cursor.getInt(COLUMN_FLAGS) & Message.FLAG_INCOMING_MEETING_INVITE) != 0;
143        itemView.mHasAttachment = cursor.getInt(COLUMN_ATTACHMENTS) != 0;
144        itemView.mTimestamp = cursor.getLong(COLUMN_DATE);
145        itemView.mSender = cursor.getString(COLUMN_DISPLAY_NAME);
146        itemView.mSnippet = cursor.getString(COLUMN_SNIPPET);
147        itemView.mSubject = cursor.getString(COLUMN_SUBJECT);
148        itemView.mSnippetLineCount = MessageListItem.NEEDS_LAYOUT;
149        itemView.mColorChipPaint =
150            mShowColorChips ? mResourceHelper.getAccountColorPaint(accountId) : null;
151    }
152
153    @Override
154    public View newView(Context context, Cursor cursor, ViewGroup parent) {
155        //return mInflater.inflate(R.layout.message_list_item, parent, false);
156        MessageListItem item = new MessageListItem(context);
157        item.setVisibility(View.VISIBLE);
158        return item;
159    }
160
161    public void toggleSelected(MessageListItem itemView) {
162        updateSelected(itemView, !isSelected(itemView));
163    }
164
165    /**
166     * This is used as a callback from the list items, to set the selected state
167     *
168     * <p>Must be called on the UI thread.
169     *
170     * @param itemView the item being changed
171     * @param newSelected the new value of the selected flag (checkbox state)
172     */
173    private void updateSelected(MessageListItem itemView, boolean newSelected) {
174        if (newSelected) {
175            mSelectedSet.add(itemView.mMessageId);
176        } else {
177            mSelectedSet.remove(itemView.mMessageId);
178        }
179        if (mCallback != null) {
180            mCallback.onAdapterSelectedChanged(itemView, newSelected, mSelectedSet.size());
181        }
182    }
183
184    /**
185     * This is used as a callback from the list items, to set the favorite state
186     *
187     * <p>Must be called on the UI thread.
188     *
189     * @param itemView the item being changed
190     * @param newFavorite the new value of the favorite flag (star state)
191     */
192    public void updateFavorite(MessageListItem itemView, boolean newFavorite) {
193        changeFavoriteIcon(itemView, newFavorite);
194        if (mCallback != null) {
195            mCallback.onAdapterFavoriteChanged(itemView, newFavorite);
196        }
197    }
198
199    private void changeFavoriteIcon(MessageListItem view, boolean isFavorite) {
200        view.invalidate();
201    }
202
203    public static Loader<Cursor> createLoader(Context context, long mailboxId) {
204        if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
205            Log.d(Email.LOG_TAG, "MessagesAdapter createLoader mailboxId=" + mailboxId);
206        }
207        return new MessagesCursorLoader(context, mailboxId);
208
209    }
210
211    private static class MessagesCursorLoader extends ThrottlingCursorLoader {
212        private final Context mContext;
213        private final long mMailboxId;
214
215        public MessagesCursorLoader(Context context, long mailboxId) {
216            // Initialize with no where clause.  We'll set it later.
217            super(context, EmailContent.Message.CONTENT_URI,
218                    MESSAGE_PROJECTION, null, null,
219                    EmailContent.MessageColumns.TIMESTAMP + " DESC");
220            mContext = context;
221            mMailboxId = mailboxId;
222        }
223
224        @Override
225        public Cursor loadInBackground() {
226            // Determine the where clause.  (Can't do this on the UI thread.)
227            setSelection(Utility.buildMailboxIdSelection(mContext, mMailboxId));
228
229            // Then do a query.
230            return super.loadInBackground();
231        }
232    }
233}
234