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