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