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