MailboxListFragment.java revision 37e21ab968e3944b10304a620c3b0ecfe5175668
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.Utility; 21import com.android.email.provider.EmailContent; 22import com.android.email.provider.EmailContent.Mailbox; 23import com.android.email.provider.EmailContent.MailboxColumns; 24import com.android.email.provider.EmailContent.Message; 25import com.android.email.provider.EmailContent.MessageColumns; 26 27import android.app.Activity; 28import android.app.ListFragment; 29import android.database.Cursor; 30import android.os.AsyncTask; 31import android.os.Bundle; 32import android.view.ContextMenu; 33import android.view.ContextMenu.ContextMenuInfo; 34import android.view.MenuItem; 35import android.view.View; 36import android.widget.AdapterView; 37import android.widget.AdapterView.OnItemClickListener; 38import android.widget.ListView; 39 40/** 41 * This fragment presents a list of mailboxes for a given account. The "API" includes the 42 * following elements which must be provided by the host Activity. 43 * 44 * - call bindActivityInfo() to provide the account ID and set callbacks 45 * - provide callbacks for onOpen and onRefresh 46 * - pass-through implementations of onCreateContextMenu() and onContextItemSelected() (temporary) 47 */ 48public class MailboxListFragment extends ListFragment implements OnItemClickListener { 49 50 private static final String MAILBOX_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?" + 51 " AND " + MailboxColumns.TYPE + "<" + Mailbox.TYPE_NOT_EMAIL + 52 " AND " + MailboxColumns.FLAG_VISIBLE + "=1"; 53 private static final String MESSAGE_MAILBOX_ID_SELECTION = MessageColumns.MAILBOX_KEY + "=?"; 54 55 // Account & mailboxes access 56 private long mAccountId; 57 private LoadMailboxesTask mLoadMailboxesTask; 58 private MessageCountTask mMessageCountTask; 59 private long mDraftMailboxKey = -1; 60 private long mTrashMailboxKey = -1; 61 62 // UI Support 63 private Activity mActivity; 64 private MailboxesAdapter mListAdapter; 65 private Callback mCallback; 66 67 /** 68 * Callback interface that owning activities must implement 69 */ 70 public interface Callback { 71 public void onRefresh(long accountId, long mailboxId); 72 public void onOpen(long accountId, long mailboxId); 73 } 74 75 /** 76 * Called to do initial creation of a fragment. This is called after 77 * {@link #onAttach(Activity)} and before {@link #onActivityCreated(Bundle)}. 78 */ 79 @Override 80 public void onCreate(Bundle savedInstanceState) { 81 super.onCreate(savedInstanceState); 82 } 83 84 @Override 85 public void onActivityCreated(Bundle savedInstanceState) { 86 super.onActivityCreated(savedInstanceState); 87 88 mActivity = getActivity(); 89 90 ListView listView = getListView(); 91 listView.setOnItemClickListener(this); 92 listView.setItemsCanFocus(false); 93 registerForContextMenu(listView); 94 95 mListAdapter = new MailboxesAdapter(mActivity); 96 } 97 98 /** 99 * Called by activity during onCreate() to bind additional information 100 * @param accountId the account we're looking at 101 * @param callback if non-null, UI clicks (e.g. refresh or open) will be delivered here 102 */ 103 public void bindActivityInfo(long accountId, Callback callback) { 104 mAccountId = accountId; 105 mCallback = callback; 106 } 107 108 /** 109 * Called when the Fragment is visible to the user. 110 */ 111 @Override 112 public void onStart() { 113 super.onStart(); 114 mLoadMailboxesTask = new LoadMailboxesTask(mAccountId); 115 mLoadMailboxesTask.execute(); 116 } 117 118 /** 119 * Called when the fragment is visible to the user and actively running. 120 */ 121 @Override 122 public void onResume() { 123 super.onResume(); 124 updateMessageCount(); 125 } 126 127 /** 128 * Called when the Fragment is no longer started. 129 */ 130 @Override 131 public void onStop() { 132 super.onStop(); 133 Utility.cancelTaskInterrupt(mLoadMailboxesTask); 134 mLoadMailboxesTask = null; 135 Utility.cancelTaskInterrupt(mMessageCountTask); 136 mMessageCountTask = null; 137 } 138 139 /** 140 * Called when the fragment is no longer in use. 141 */ 142 @Override 143 public void onDestroy() { 144 super.onDestroy(); 145 146 mListAdapter.changeCursor(null); 147 } 148 149 /** 150 * This is called via the activity 151 * TODO This will be removed when possible 152 */ 153 @Override 154 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) { 155 AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) info; 156 Cursor c = (Cursor) getListView().getItemAtPosition(menuInfo.position); 157 String folderName = Utility.FolderProperties.getInstance(mActivity) 158 .getDisplayName(Integer.valueOf(c.getString(mListAdapter.COLUMN_TYPE))); 159 if (folderName == null) { 160 folderName = c.getString(mListAdapter.COLUMN_DISPLAY_NAME); 161 } 162 163 menu.setHeaderTitle(folderName); 164 mActivity.getMenuInflater().inflate(R.menu.mailbox_list_context, menu); 165 } 166 167 /** 168 * This is called via the activity 169 * TODO This will be removed when possible 170 */ 171 @Override 172 public boolean onContextItemSelected(MenuItem item) { 173 AdapterView.AdapterContextMenuInfo info = 174 (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); 175 176 switch (item.getItemId()) { 177 case R.id.refresh: 178 if (mCallback != null) { 179 mCallback.onRefresh(mAccountId, info.id); 180 } 181 return true; 182 case R.id.open: 183 if (mCallback != null) { 184 mCallback.onOpen(mAccountId, info.id); 185 } 186 return true; 187 } 188 return false; 189 } 190 191 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 192 if (mCallback != null) { 193 mCallback.onOpen(mAccountId, id); 194 } 195 } 196 197 /** 198 * Async task for loading the mailboxes for a given account 199 */ 200 private class LoadMailboxesTask extends AsyncTask<Void, Void, Object[]> { 201 202 private long mAccountKey; 203 204 /** 205 * Special constructor to cache some local info 206 */ 207 public LoadMailboxesTask(long accountId) { 208 mAccountKey = accountId; 209 } 210 211 @Override 212 protected Object[] doInBackground(Void... params) { 213 long draftMailboxKey = -1; 214 long trashMailboxKey = -1; 215 Cursor c = mActivity.managedQuery( 216 EmailContent.Mailbox.CONTENT_URI, 217 mListAdapter.PROJECTION, 218 MAILBOX_SELECTION, 219 new String[] { String.valueOf(mAccountKey) }, 220 MailboxColumns.TYPE + "," + MailboxColumns.DISPLAY_NAME); 221 c.moveToPosition(-1); 222 while (c.moveToNext()) { 223 long mailboxId = c.getInt(mListAdapter.COLUMN_ID); 224 switch (c.getInt(mListAdapter.COLUMN_TYPE)) { 225 case Mailbox.TYPE_DRAFTS: 226 draftMailboxKey = mailboxId; 227 break; 228 case Mailbox.TYPE_TRASH: 229 trashMailboxKey = mailboxId; 230 break; 231 } 232 } 233 Object[] result = new Object[3]; 234 result[0] = c; 235 result[1] = draftMailboxKey; 236 result[2] = trashMailboxKey; 237 return result; 238 } 239 240 @Override 241 protected void onPostExecute(Object[] results) { 242 if (results == null) return; 243 Cursor cursor = (Cursor) results[0]; 244 mDraftMailboxKey = (Long) results[1]; 245 mTrashMailboxKey = (Long) results[2]; 246 247 if (cursor.isClosed()) return; 248 mListAdapter.changeCursor(cursor); 249 setListAdapter(mListAdapter); 250 updateMessageCount(); 251 } 252 } 253 254 private class MessageCountTask extends AsyncTask<Void, Void, int[]> { 255 256 @Override 257 protected int[] doInBackground(Void... params) { 258 int[] counts = new int[2]; 259 if (mDraftMailboxKey != -1) { 260 counts[0] = EmailContent.count(mActivity, Message.CONTENT_URI, 261 MESSAGE_MAILBOX_ID_SELECTION, 262 new String[] { String.valueOf(mDraftMailboxKey)}); 263 } else { 264 counts[0] = 0; 265 } 266 if (mTrashMailboxKey != -1) { 267 counts[1] = EmailContent.count(mActivity, Message.CONTENT_URI, 268 MESSAGE_MAILBOX_ID_SELECTION, 269 new String[] { String.valueOf(mTrashMailboxKey)}); 270 } else { 271 counts[1] = 0; 272 } 273 return counts; 274 } 275 276 @Override 277 protected void onPostExecute(int[] counts) { 278 if (counts == null) { 279 return; 280 } 281 int countDraft = counts[0]; 282 int countTrash = counts[1]; 283 mListAdapter.setMessageCounts(countDraft, countTrash); 284 } 285 } 286 287 private void updateMessageCount() { 288 if (mAccountId == -1 || mListAdapter.getCursor() == null) { 289 return; 290 } 291 if (mMessageCountTask != null 292 && mMessageCountTask.getStatus() != MessageCountTask.Status.FINISHED) { 293 mMessageCountTask.cancel(true); 294 } 295 mMessageCountTask = (MessageCountTask) new MessageCountTask().execute(); 296 } 297} 298