AccountSelectorAdapter.java revision 3af94be47732e200dec5e5c8c78cec02ff27445f
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.R; 21import com.android.email.Utility; 22import com.android.email.data.ThrottlingCursorLoader; 23import com.android.email.provider.EmailContent; 24import com.android.email.provider.EmailContent.Account; 25import com.android.email.provider.EmailContent.Mailbox; 26 27import android.content.Context; 28import android.content.Loader; 29import android.database.Cursor; 30import android.database.MatrixCursor; 31import android.database.MatrixCursor.RowBuilder; 32import android.view.LayoutInflater; 33import android.view.View; 34import android.view.ViewGroup; 35import android.widget.CursorAdapter; 36import android.widget.TextView; 37 38/** 39 * Adapter for the account selector on {@link MessageListXL}. 40 * 41 * TODO Test it! 42 * TODO Use layout? Or use the standard resources that ActionBarDemo uses? 43 * TODO Revisit the sort order when we get more detailed UI spec. (current sort order makes things 44 * simpler for now.) Maybe we can just use SimpleCursorAdapter. 45 */ 46public class AccountSelectorAdapter extends CursorAdapter { 47 /** Projection used to query from Account */ 48 private static final String[] ACCOUNT_PROJECTION = new String[] { 49 EmailContent.RECORD_ID, 50 EmailContent.Account.DISPLAY_NAME, 51 EmailContent.Account.EMAIL_ADDRESS, 52 }; 53 54 /** 55 * Projection for the resulting MatrixCursor -- must be {@link #ACCOUNT_PROJECTION} 56 * with "UNREAD_COUNT". 57 */ 58 private static final String[] RESULT_PROJECTION = new String[] { 59 EmailContent.RECORD_ID, 60 EmailContent.Account.DISPLAY_NAME, 61 EmailContent.Account.EMAIL_ADDRESS, 62 "UNREAD_COUNT" 63 }; 64 65 private static final int ID_COLUMN = 0; 66 private static final int DISPLAY_NAME_COLUMN = 1; 67 private static final int EMAIL_ADDRESS_COLUMN = 2; 68 private static final int UNREAD_COUNT_COLUMN = 3; 69 70 /** Sort order. Show the default account first. */ 71 private static final String ORDER_BY = 72 EmailContent.Account.IS_DEFAULT + " desc, " + EmailContent.Account.RECORD_ID; 73 74 private final LayoutInflater mInflater; 75 76 public static Loader<Cursor> createLoader(Context context) { 77 return new AccountsLoader(context); 78 } 79 80 public AccountSelectorAdapter(Context context, Cursor c) { 81 super(context, c, 0 /* no auto-requery */); 82 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 83 } 84 85 @Override 86 public View getDropDownView(int position, View convertView, ViewGroup parent) { 87 final View view = mInflater.inflate(R.layout.account_selector_dropdown, parent, false); 88 89 final TextView displayNameView = (TextView) view.findViewById(R.id.display_name); 90 final TextView emailAddressView = (TextView) view.findViewById(R.id.email_address); 91 final TextView unreadCountView = (TextView) view.findViewById(R.id.unread_count); 92 93 final String displayName = getAccountDisplayName(position); 94 final String emailAddress = getAccountEmailAddress(position); 95 96 displayNameView.setText(displayName); 97 98 // Show the email address only when it's different from the display name. 99 // If same, show " " instead of "", so that the text view won't get completely 100 // collapsed. (TextView's height will be 0px if it's "match_content" and the 101 // content is "".) 102 emailAddressView.setText(emailAddress.equals(displayName) ? " " : emailAddress); 103 unreadCountView.setText(Integer.toString(getAccountUnreadCount(position))); 104 return view; 105 } 106 107 @Override 108 public void bindView(View view, Context context, Cursor cursor) { 109 TextView textView = (TextView) view.findViewById(R.id.display_name); 110 textView.setText(getAccountDisplayName(cursor)); 111 } 112 113 @Override 114 public View newView(Context context, Cursor cursor, ViewGroup parent) { 115 return mInflater.inflate(R.layout.account_selector, parent, false); 116 } 117 118 /** @return Account id extracted from a Cursor. */ 119 public static long getAccountId(Cursor c) { 120 return c.getLong(ID_COLUMN); 121 } 122 123 private String getAccountDisplayName(int position) { 124 final Cursor c = getCursor(); 125 return c.moveToPosition(position) ? getAccountDisplayName(c) : null; 126 } 127 128 private String getAccountEmailAddress(int position) { 129 final Cursor c = getCursor(); 130 return c.moveToPosition(position) ? getAccountEmailAddress(c) : null; 131 } 132 133 private int getAccountUnreadCount(int position) { 134 final Cursor c = getCursor(); 135 return c.moveToPosition(position) ? getAccountUnreadCount(c) : 0; 136 } 137 138 /** @return Account name extracted from a Cursor. */ 139 public static String getAccountDisplayName(Cursor cursor) { 140 return cursor.getString(DISPLAY_NAME_COLUMN); 141 } 142 143 /** @return Email address extracted from a Cursor. */ 144 public static String getAccountEmailAddress(Cursor cursor) { 145 return cursor.getString(EMAIL_ADDRESS_COLUMN); 146 } 147 148 /** @return Unread count extracted from a Cursor. */ 149 public static int getAccountUnreadCount(Cursor cursor) { 150 return cursor.getInt(UNREAD_COUNT_COLUMN); 151 } 152 153 /** 154 * Load the account list. The resulting cursor contains 155 * - Account info 156 * - # of unread messages in inbox 157 * - The "Combined view" row if there's more than one account. 158 */ 159 /* package */ static class AccountsLoader extends ThrottlingCursorLoader { 160 private final Context mContext; 161 162 public AccountsLoader(Context context) { 163 // Super class loads a regular account cursor, but we replace it in loadInBackground(). 164 super(context, EmailContent.Account.CONTENT_URI, ACCOUNT_PROJECTION, null, null, 165 ORDER_BY); 166 mContext = context; 167 } 168 169 @Override 170 public Cursor loadInBackground() { 171 // Fetch account list 172 final Cursor accountsCursor = super.loadInBackground(); 173 174 // Cursor that's actually returned. 175 // Use ClosingMatrixCursor so that accountsCursor gets closed too when it's closed. 176 final MatrixCursor resultCursor = new ClosingMatrixCursor(RESULT_PROJECTION, 177 accountsCursor); 178 accountsCursor.moveToPosition(-1); 179 180 // Build the cursor... 181 int totalUnread = 0; 182 while (accountsCursor.moveToNext()) { 183 // Add account, with its unread count. 184 final long accountId = accountsCursor.getLong(0); 185 final int unread = Mailbox.getUnreadCountByAccountAndMailboxType( 186 mContext, accountId, Mailbox.TYPE_INBOX); 187 188 RowBuilder rb = resultCursor.newRow(); 189 rb.add(accountId); 190 rb.add(getAccountDisplayName(accountsCursor)); 191 rb.add(getAccountEmailAddress(accountsCursor)); 192 rb.add(unread); 193 totalUnread += unread; 194 } 195 // Add "combined view" 196 final int countAccounts = resultCursor.getCount(); 197 if (countAccounts > 1) { 198 RowBuilder rb = resultCursor.newRow(); 199 200 // Add ID, display name, # of accounts, total unread count. 201 rb.add(Account.ACCOUNT_ID_COMBINED_VIEW); 202 rb.add(mContext.getResources().getString( 203 R.string.mailbox_list_account_selector_combined_view)); 204 rb.add(mContext.getResources().getQuantityString(R.plurals.number_of_accounts, 205 countAccounts, countAccounts)); 206 rb.add(totalUnread); 207 } 208 return Utility.CloseTraceCursorWrapper.get(resultCursor); 209 } 210 } 211 212 /** 213 * {@link MatrixCursor} which takes an extra {@link Cursor} to the constructor, and close 214 * it when self is closed. 215 */ 216 private static class ClosingMatrixCursor extends MatrixCursor { 217 private final Cursor mInnerCursor; 218 219 public ClosingMatrixCursor(String[] columnNames, Cursor innerCursor) { 220 super(columnNames); 221 mInnerCursor = innerCursor; 222 } 223 224 @Override 225 public void close() { 226 mInnerCursor.close(); 227 super.close(); 228 } 229 } 230} 231