MailboxFragmentAdapter.java revision c5ea3f522ac835907ec48e117e7918802950d595
1/*
2 * Copyright (C) 2011 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.FolderProperties;
21import com.android.email.R;
22import com.android.email.data.ClosingMatrixCursor;
23import com.android.email.data.ThrottlingCursorLoader;
24import com.android.emailcommon.Logging;
25import com.android.emailcommon.provider.EmailContent;
26import com.android.emailcommon.provider.EmailContent.Account;
27import com.android.emailcommon.provider.EmailContent.AccountColumns;
28import com.android.emailcommon.provider.EmailContent.Mailbox;
29import com.android.emailcommon.provider.EmailContent.Message;
30import com.android.emailcommon.utility.Utility;
31
32import android.content.Context;
33import android.content.Loader;
34import android.database.Cursor;
35import android.database.MatrixCursor;
36import android.database.MatrixCursor.RowBuilder;
37import android.database.MergeCursor;
38import android.util.Log;
39import android.view.View;
40import android.view.ViewGroup;
41import android.widget.ImageView;
42import android.widget.TextView;
43
44/**
45 * Cursor adapter for a fragment mailbox list.
46 */
47/*package*/ class MailboxFragmentAdapter extends MailboxesAdapter {
48    public MailboxFragmentAdapter(Context context, Callback callback) {
49        super(context, callback);
50    }
51
52    @Override
53    public void bindView(View view, Context context, Cursor cursor) {
54        final boolean isAccount = isAccountRow(cursor);
55        final int type = cursor.getInt(COLUMN_TYPE);
56        final long id = cursor.getLong(COLUMN_ID);
57
58        MailboxListItem listItem = (MailboxListItem)view;
59        listItem.mMailboxType = type;
60        listItem.mMailboxId = id;
61        listItem.mAdapter = this;
62
63        // Set the background depending on whether we're in drag mode, the mailbox is a valid
64        // target, etc.
65        mCallback.onBind(listItem);
66
67        // Set mailbox name
68        final TextView nameView = (TextView) view.findViewById(R.id.mailbox_name);
69        nameView.setText(getDisplayName(context, cursor));
70
71        // Set count
72        final int count;
73        switch (getCountTypeForMailboxType(cursor)) {
74            case COUNT_TYPE_UNREAD:
75                count = cursor.getInt(COLUMN_UNREAD_COUNT);
76                break;
77            case COUNT_TYPE_TOTAL:
78                count = cursor.getInt(COLUMN_MESSAGE_COUNT);
79                break;
80            default: // no count
81                count = 0;
82                break;
83        }
84        final TextView countView = (TextView) view.findViewById(R.id.message_count);
85
86        // If the unread count is zero, not to show countView.
87        if (count > 0) {
88            countView.setVisibility(View.VISIBLE);
89            countView.setText(Integer.toString(count));
90        } else {
91            countView.setVisibility(View.GONE);
92        }
93
94        // Set folder icon
95        ((ImageView) view.findViewById(R.id.folder_icon)).setImageDrawable(
96                FolderProperties.getInstance(context).getIcon(type, id));
97
98        final View chipView = view.findViewById(R.id.color_chip);
99        if (isAccount) {
100            chipView.setVisibility(View.VISIBLE);
101            chipView.setBackgroundColor(mResourceHelper.getAccountColor(id));
102        } else {
103            chipView.setVisibility(View.GONE);
104        }
105    }
106
107    @Override
108    public View newView(Context context, Cursor cursor, ViewGroup parent) {
109        return mInflater.inflate(R.layout.mailbox_list_item, parent, false);
110    }
111
112    /**
113     * Returns a cursor loader for the mailboxes of the given account. If <code>parentKey</code>
114     * refers to a valid mailbox ID [e.g. non-zero], restrict the loader to only those mailboxes
115     * contained by this parent mailbox.
116     */
117    public static Loader<Cursor> createLoader(Context context, long accountId, long parentKey) {
118        if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
119            Log.d(Logging.LOG_TAG, "MailboxFragmentAdapter#createLoader accountId=" + accountId);
120        }
121        if (accountId != Account.ACCOUNT_ID_COMBINED_VIEW) {
122            // STOPSHIP remove test when legacy protocols support folders; the parent key
123            // should never equal '0'
124            if (parentKey == 0) {
125                // load all mailboxes at the top level
126                return new MailboxFragmentLoader(context, accountId);
127            } else {
128                return new MailboxFragmentLoader(context, accountId, parentKey);
129            }
130        } else {
131            return new CombinedMailboxLoader(context);
132        }
133    }
134
135    /**
136     * Adds a new row into the given cursor.
137     */
138    private static void addMailboxRow(MatrixCursor cursor, long mailboxId, String displayName,
139            int mailboxType, int unreadCount, int messageCount) {
140        long listId = mailboxId;
141        if (mailboxId < 0) {
142            listId = Long.MAX_VALUE + mailboxId; // IDs for the list view must be positive
143        }
144        RowBuilder row = cursor.newRow();
145        row.add(listId);
146        row.add(mailboxId);
147        row.add(displayName);
148        row.add(mailboxType);
149        row.add(unreadCount);
150        row.add(messageCount);
151        row.add(ROW_TYPE_MAILBOX);
152    }
153
154    private static void addSummaryMailboxRow(MatrixCursor cursor, long id, int mailboxType,
155            int count, boolean showAlways) {
156        if (id >= 0) {
157            throw new IllegalArgumentException(); // Must be QUERY_ALL_*, which are all negative
158        }
159        if (showAlways || (count > 0)) {
160            addMailboxRow(cursor, id, "", mailboxType, count, count);
161        }
162    }
163
164    /**
165     * Loader for mailboxes of an account.
166     */
167    private static class MailboxFragmentLoader extends ThrottlingCursorLoader {
168        private final Context mContext;
169        private final long mAccountId;
170        private final long mParentKey;
171
172        // STOPSHIP remove when legacy protocols support folders; parent key must always be set
173        MailboxFragmentLoader(Context context, long accountId) {
174            super(context, EmailContent.Mailbox.CONTENT_URI,
175                    MailboxesAdapter.PROJECTION, MAILBOX_SELECTION_NO_PARENT,
176                    new String[] { Long.toString(accountId) },
177                    MAILBOX_ORDER_BY);
178            mContext = context;
179            mAccountId = accountId;
180            mParentKey = 0;
181        }
182
183        MailboxFragmentLoader(Context context, long accountId, long parentKey) {
184            super(context, EmailContent.Mailbox.CONTENT_URI,
185                    MailboxesAdapter.PROJECTION, MAILBOX_SELECTION_WITH_PARENT,
186                    new String[] { Long.toString(accountId), Long.toString(parentKey) },
187                    MAILBOX_ORDER_BY);
188            mContext = context;
189            mAccountId = accountId;
190            mParentKey = parentKey;
191        }
192
193        @Override
194        public void onContentChanged() {
195            if (sEnableUpdate) {
196                super.onContentChanged();
197            }
198        }
199
200        @Override
201        public Cursor loadInBackground() {
202            final Cursor mailboxesCursor = super.loadInBackground();
203
204            // Add "up" item if we are not viewing the top-level list
205            if (mParentKey > 0) {
206                // STOPSHIP Remove this commented block of code if truly not wanted by UX
207//                // Find the parent's parent ...
208//                Long superParentKey = Utility.getFirstRowLong(getContext(), Mailbox.CONTENT_URI,
209//                        new String[] { MailboxColumns.PARENT_KEY }, MailboxColumns.ID + "=?",
210//                        new String[] { Long.toString(mParentKey) }, null, 0);
211                Long superParentKey = MessageListXLFragmentManager.NO_MAILBOX;
212
213                if (superParentKey != null) {
214                    final MatrixCursor extraCursor = new MatrixCursor(getProjection());
215                    String label = mContext.getResources().getString(R.string.mailbox_name_go_back);
216                    addMailboxRow(extraCursor, superParentKey, label, Mailbox.TYPE_MAIL, 0, 0);
217                    return Utility.CloseTraceCursorWrapper.get(
218                            new MergeCursor(new Cursor[] {extraCursor, mailboxesCursor}));
219                }
220            }
221
222            // Add "Starred", only if the account has at least one starred message.
223            // TODO It's currently "combined starred", but the plan is to make it per-account
224            // starred.
225            final int accountStarredCount = Message.getFavoriteMessageCount(mContext, mAccountId);
226            if (accountStarredCount == 0) {
227                return Utility.CloseTraceCursorWrapper.get(mailboxesCursor); // no starred message
228            }
229
230            final MatrixCursor starredCursor = new MatrixCursor(getProjection());
231
232            final int totalStarredCount = Message.getFavoriteMessageCount(mContext);
233            addSummaryMailboxRow(starredCursor, Mailbox.QUERY_ALL_FAVORITES, Mailbox.TYPE_MAIL,
234                    totalStarredCount, true);
235
236            return Utility.CloseTraceCursorWrapper.get(
237                    new MergeCursor(new Cursor[] {starredCursor, mailboxesCursor}));
238        }
239    }
240
241    /**
242     * Loader for mailboxes in "Combined view".
243     */
244    /*package*/ static class CombinedMailboxLoader extends ThrottlingCursorLoader {
245        private static final String[] ACCOUNT_PROJECTION = new String[] {
246                    EmailContent.RECORD_ID, AccountColumns.DISPLAY_NAME,
247                };
248        private static final int COLUMN_ACCOUND_ID = 0;
249        private static final int COLUMN_ACCOUNT_DISPLAY_NAME = 1;
250
251        private final Context mContext;
252
253        public CombinedMailboxLoader(Context context) {
254            super(context, Account.CONTENT_URI, ACCOUNT_PROJECTION, null, null, null);
255            mContext = context;
256        }
257
258        @Override
259        public Cursor loadInBackground() {
260            final Cursor accounts = super.loadInBackground();
261            final MatrixCursor combinedWithAccounts = getCursor(mContext, accounts);
262
263            accounts.moveToPosition(-1);
264            while (accounts.moveToNext()) {
265                RowBuilder row =  combinedWithAccounts.newRow();
266                final long accountId = accounts.getLong(COLUMN_ACCOUND_ID);
267                row.add(accountId);
268                row.add(accountId);
269                row.add(accounts.getString(COLUMN_ACCOUNT_DISPLAY_NAME));
270                row.add(-1); // No mailbox type.  Shouldn't really be used.
271                final int unreadCount = Mailbox.getUnreadCountByAccountAndMailboxType(
272                        mContext, accountId, Mailbox.TYPE_INBOX);
273                row.add(unreadCount);
274                row.add(unreadCount);
275                row.add(ROW_TYPE_ACCOUNT);
276            }
277            return Utility.CloseTraceCursorWrapper.get(combinedWithAccounts);
278        }
279
280        /*package*/ static MatrixCursor getCursor(Context context,
281                Cursor innerCursor) {
282            MatrixCursor cursor = new ClosingMatrixCursor(PROJECTION, innerCursor);
283            // Combined inbox -- show unread count
284            addSummaryMailboxRow(cursor, Mailbox.QUERY_ALL_INBOXES, Mailbox.TYPE_INBOX,
285                    Mailbox.getUnreadCountByMailboxType(context, Mailbox.TYPE_INBOX), true);
286
287            // Favorite (starred) -- show # of favorites
288            addSummaryMailboxRow(cursor, Mailbox.QUERY_ALL_FAVORITES, Mailbox.TYPE_MAIL,
289                    Message.getFavoriteMessageCount(context), false);
290
291            // Drafts -- show # of drafts
292            addSummaryMailboxRow(cursor, Mailbox.QUERY_ALL_DRAFTS, Mailbox.TYPE_DRAFTS,
293                    Mailbox.getMessageCountByMailboxType(context, Mailbox.TYPE_DRAFTS), false);
294
295            // Outbox -- # of outstanding messages
296            addSummaryMailboxRow(cursor, Mailbox.QUERY_ALL_OUTBOX, Mailbox.TYPE_OUTBOX,
297                    Mailbox.getMessageCountByMailboxType(context, Mailbox.TYPE_OUTBOX), false);
298
299            return cursor;
300        }
301    }
302}
303