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