k-9/src/com/android/email/activity/FolderList.java

1163 lines
39 KiB
Java
Raw Normal View History

r62972@17h: jesse | 2009-05-07 10:49:32 -0400 First stab at a folderlist that doesn't know or care about messages r62973@17h: jesse | 2009-05-07 10:50:11 -0400 A very broken first stab at a message list that only knows about one folder. r62974@17h: jesse | 2009-05-07 10:50:44 -0400 When you go from an account list to an individual account, open a folderlist, not an fml r62975@17h: jesse | 2009-05-07 10:51:24 -0400 Update Welcome activity to open an ml instead of an fml r62976@17h: jesse | 2009-05-07 10:51:59 -0400 When setting up accounts is over, open an fl instead of an fml r62977@17h: jesse | 2009-05-07 10:52:51 -0400 Update MessageView to use folderinfoholders and messageinfoholders from the 'correct' classes. r62978@17h: jesse | 2009-05-07 10:59:07 -0400 MailService now notifies the fl instead of the fml. Not sure if it should also notify the ml. - will require testing r62979@17h: jesse | 2009-05-07 11:01:09 -0400 Switch MessagingController's notifications from notifying the FML to notifying an ML r62980@17h: jesse | 2009-05-07 11:25:22 -0400 Update AndroidManifest to know about the new world order r62981@17h: jesse | 2009-05-07 11:26:11 -0400 Try to follow the android sdk docs for intent creation r62982@17h: jesse | 2009-05-07 11:28:30 -0400 reset MessageList for another try at the conversion r62983@17h: jesse | 2009-05-07 11:47:33 -0400 This version doesn't crash and has a working 'folder' layer. now to clean up the message list layer r62984@17h: jesse | 2009-05-07 15:18:04 -0400 move step 1 r62985@17h: jesse | 2009-05-07 15:18:37 -0400 move step 1 r62986@17h: jesse | 2009-05-07 15:22:47 -0400 rename step 1 r62987@17h: jesse | 2009-05-07 17:38:02 -0400 checkpoint to move r62988@17h: jesse | 2009-05-07 17:40:01 -0400 checkpointing a state with a working folder list and a message list that doesn't explode r62989@17h: jesse | 2009-05-07 17:40:26 -0400 Remove debugging cruft from Welcome r62990@17h: jesse | 2009-05-07 22:00:12 -0400 Basic functionality works. r62991@17h: jesse | 2009-05-08 04:19:52 -0400 added a tool to build a K-9 "Beta" r62992@17h: jesse | 2009-05-08 04:20:03 -0400 remove a disused file r62993@17h: jesse | 2009-05-09 06:07:02 -0400 upgrading build infrastructure for the 1.5 sdk r62994@17h: jesse | 2009-05-09 06:22:02 -0400 further refine onOpenMessage, removing more folder assumptions r62995@17h: jesse | 2009-05-09 20:07:20 -0400 Make the Welcome activity open the autoexpandfolder rather than INBOX r62996@17h: jesse | 2009-05-09 20:14:10 -0400 MessageList now stores the Folder name it was working with across pause-reload r62997@17h: jesse | 2009-05-09 20:14:26 -0400 Removing dead code from FolderList r63060@17h: jesse | 2009-05-10 00:07:33 -0400 Replace the old message list refreshing code which cleared and rebuilt the list from scratch with code which updates or deletes existing messages. Add "go back to folder list" code r63061@17h: jesse | 2009-05-10 00:07:50 -0400 fix message list menus for new world order r63062@17h: jesse | 2009-05-10 00:08:11 -0400 Remove message list options from folder list menus r63063@17h: jesse | 2009-05-10 00:10:02 -0400 remove more message list options from the folder list r63064@17h: jesse | 2009-05-10 00:10:19 -0400 fix build.xml for the new android world order r63065@17h: jesse | 2009-05-10 00:39:23 -0400 reformatted in advance of bug tracing r63066@17h: jesse | 2009-05-10 05:53:28 -0400 fix our 'close' behavior to not leave extra activities around clean up more vestigal code r63067@17h: jesse | 2009-05-10 18:44:25 -0400 Improve "back button / accounts" workflow from FolderList -> AccountList r63068@17h: jesse | 2009-05-10 19:11:47 -0400 * Add required code for the 'k9beta' build r63069@17h: jesse | 2009-05-10 19:12:05 -0400 Make the folder list white backgrounded. r63070@17h: jesse | 2009-05-10 19:12:26 -0400 * Include our required libraries in build.xml r63071@17h: jesse | 2009-05-10 19:13:07 -0400 Added directories for our built code and our generated code r63072@17h: jesse | 2009-05-10 19:13:36 -0400 Added a "back" button image r63073@17h: jesse | 2009-05-10 20:13:50 -0400 Switch next/prev buttons to triangles for I18N and eventual "more easy-to-hit buttons" win r63074@17h: jesse | 2009-05-10 20:17:18 -0400 Tidy Accounts.java for some perf hacking. r63081@17h: jesse | 2009-05-10 22:13:33 -0400 First pass reformatting of the MessagingController r63082@17h: jesse | 2009-05-10 23:50:28 -0400 MessageList now correctly updates when a background sync happens r63083@17h: jesse | 2009-05-10 23:50:53 -0400 Tidying FolderList r63084@17h: jesse | 2009-05-10 23:51:09 -0400 tidy r63085@17h: jesse | 2009-05-10 23:51:27 -0400 tidy r63086@17h: jesse | 2009-05-11 00:17:06 -0400 Properly update unread counts in the FolderList after sync r63087@17h: jesse | 2009-05-11 01:38:14 -0400 Minor refactoring for readability. replace a boolean with a constant. r63090@17h: jesse | 2009-05-11 02:58:31 -0400 now that the foreground of message lists is light, we don't need the light messagebox r63091@17h: jesse | 2009-05-11 17:15:02 -0400 Added a string for "back to folder list" r63092@17h: jesse | 2009-05-11 17:15:24 -0400 Added a message list header with a back button r63093@17h: jesse | 2009-05-11 17:15:54 -0400 Remove the "folder list" button from the options menu. no sense duplicating it r63094@17h: jesse | 2009-05-11 17:17:06 -0400 Refactored views, adding our replacement scrollable header r63184@17h: jesse | 2009-05-12 07:07:15 -0400 fix weird bug where message lists could show a header element for a child r63185@17h: jesse | 2009-05-12 07:08:12 -0400 Add new-style headers to folder lists. reimplement "get folder by name" to not use a bloody for loop r63211@17h: jesse | 2009-05-12 18:37:48 -0400 Restore the former glory of the "load more messages" widget. it still needs an overhaul r63296@17h: jesse | 2009-05-12 23:23:21 -0400 Get the indeterminate progress bar to show up again when you click "get more messages" r63297@17h: jesse | 2009-05-13 02:40:39 -0400 Fixed off-by-one errors in click and keybindings for messagelist r63298@17h: jesse | 2009-05-13 06:04:01 -0400 Put the folder title in the name of the folderSettings popup r63299@17h: jesse | 2009-05-13 06:04:49 -0400 Reformatting. Removing debug logging r63300@17h: jesse | 2009-05-13 06:05:32 -0400 Fixing "wrong item selected" bugs in the FolderList r63328@17h: jesse | 2009-05-13 13:20:00 -0400 Update MessageView for 1.5 r63329@17h: jesse | 2009-05-13 13:50:29 -0400 A couple fixes to "picking the right item" Titles on the message context menu r63330@17h: jesse | 2009-05-13 13:58:37 -0400 Added an "open" context menu item to the folder list r63347@17h: jesse | 2009-05-13 18:00:02 -0400 Try to get folderlists to sort in a stable way, so they jump around less in the ui r63349@17h: jesse | 2009-05-13 20:37:19 -0400 Switch to using non-message-passing based notifications for redisplay of message lists, cut down redisplay frequency to not overload the display r63432@17h: jesse | 2009-05-16 13:38:49 -0400 Android 1.5 no longer gives us apache.commons.codec by default and apache.commons.logging by default. Import them so we have em. There's probably something smarter to do here. r63438@17h: jesse | 2009-05-16 14:12:06 -0400 removed dead code r63439@17h: jesse | 2009-05-16 14:30:57 -0400 Minor tidy r63440@17h: jesse | 2009-05-16 14:39:34 -0400 First pass implementation making MessageList streamy for faster startup r63441@17h: jesse | 2009-05-16 21:57:41 -0400 There's no reason for the FolderList to list local messages r63442@17h: jesse | 2009-05-16 21:58:57 -0400 Switch to actually refreshing the message list after each item is loaded r63450@17h: jesse | 2009-05-16 22:34:18 -0400 Default to pulling items out of the LocalStore by date, descending. (since that's the uneditable default ordering) This makes our messages come out of the store in the order the user should see them r63451@17h: jesse | 2009-05-16 22:34:44 -0400 Set some new defaults for the FolderList r63452@17h: jesse | 2009-05-16 22:35:43 -0400 set some new message list item defaults r63456@17h: jesse | 2009-05-17 12:56:10 -0400 It's not clear that Pop and WebDav actually set us an InternalDate. I'd rather use that so that spam doesn't topsort. But I also want this to _work_ r63457@17h: jesse | 2009-05-17 12:56:47 -0400 actually check to make sure we have a message to remove before removing it. r63458@17h: jesse | 2009-05-17 13:10:07 -0400 Flip "security type" to before the port number, since changing security type is the thing more users are likely to know/care about and resets port number r63469@17h: jesse | 2009-05-17 18:42:39 -0400 Provisional fix for "see the FoldeRList twice" bug r63471@17h: jesse | 2009-05-17 20:47:41 -0400 Remove title bar from the message view r63544@17h: jesse | 2009-05-20 23:53:38 -0400 folderlist tidying before i dig into the jumpy ordering bug r63545@17h: jesse | 2009-05-20 23:56:00 -0400 Killing dead variables r63546@17h: jesse | 2009-05-21 00:58:36 -0400 make the whole title section clicky r63556@17h: jesse | 2009-05-21 01:48:13 -0400 Fix where we go when someone deletes a message r63558@17h: jesse | 2009-05-21 22:44:46 -0400 Working toward switchable themes r63563@17h: jesse | 2009-05-21 23:53:09 -0400 Make the MessageList's colors actually just inherit from the theme, rather than hardcoding black r63567@17h: jesse | 2009-05-22 10:14:13 -0400 Kill a now-redundant comment r63571@17h: jesse | 2009-05-22 19:43:30 -0400 further theme-independence work r63572@17h: jesse | 2009-05-22 19:55:23 -0400 gete -> get (typo fix) r63573@17h: jesse | 2009-05-22 22:48:49 -0400 First cut of a global prefs system as well as a theme preference. not that it works yet r63577@17h: jesse | 2009-05-24 14:49:52 -0400 Once a user has actually put in valid user credentials, start syncing mail and folders in the background instantly. This gives us a much better "new startup" experience r63578@17h: jesse | 2009-05-24 14:55:00 -0400 MessageList doesn't need FolderUpdateWorker r63579@17h: jesse | 2009-05-24 17:57:15 -0400 Fix "get message by uid" Switch to showing messages 10 by 10, rather than 1 by 1 for huge loadtime performance improvements r63587@17h: jesse | 2009-05-24 19:19:56 -0400 Cut down LocalMessage creation to not generate a MessageId or date formatter. r63589@17h: jesse | 2009-05-24 22:22:32 -0400 Switch to null-escaping email address boundaries, rather than a VERY expensive URL-encoding r63590@17h: jesse | 2009-05-24 22:23:21 -0400 Clean up our "auto-refresh the list when adding messages after a sync" r63593@17h: jesse | 2009-05-24 22:53:45 -0400 replace isDateToday with a "rolling 18 hour window" variant that's more likely to give the user a useful answer and is 30x faster. r63595@17h: jesse | 2009-05-24 23:54:14 -0400 When instantiating messges from the LocalStore, there's no need to clear headers before setting them, nor is there a need to set a generated message id r63596@17h: jesse | 2009-05-24 23:54:39 -0400 make an overridable setGeneratedMessageId r63597@17h: jesse | 2009-05-24 23:54:55 -0400 Remove new lies from comments r63598@17h: jesse | 2009-05-24 23:55:35 -0400 Replace insanely expensive message header "name" part quoting with something consistent and cheap that does its work on the way INTO the database r63605@17h: jesse | 2009-05-25 17:28:24 -0400 bring back the 1.1 sdk build.xml r63606@17h: jesse | 2009-05-25 22:32:11 -0400 Actually enable switchable themese and compilation on 1.1 r63692@17h: jesse | 2009-05-29 23:55:17 -0400 Switch back to having titles for folder and message lists. Restore auto-open-folder functionality r63694@17h: jesse | 2009-05-30 18:50:39 -0400 Remove several off-by-one errors introduced by yesterday's return to android titlebars r63696@17h: jesse | 2009-05-30 23:45:03 -0400 use convertView properly for performance and memory imrpovement in FolderList and MessageList r63698@17h: jesse | 2009-05-31 19:42:59 -0400 Switch to using background shading to indicate "not yet fetched" r63701@17h: jesse | 2009-05-31 21:28:47 -0400 Remving code we don't actually need these bits of apache commons on 1.1
2009-05-31 21:35:05 -04:00
package com.android.email.activity;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.AlertDialog;
import android.app.Dialog;
import com.android.email.K9ListActivity;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
import android.util.Config;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.BaseAdapter;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.android.email.Account;
import com.android.email.Email;
import com.android.email.MessagingController;
import com.android.email.MessagingListener;
import com.android.email.Preferences;
import com.android.email.R;
import com.android.email.Utility;
import com.android.email.MessagingController.SORT_TYPE;
import com.android.email.activity.FolderList.FolderInfoHolder;
import com.android.email.activity.MessageList.MessageInfoHolder;
import com.android.email.activity.setup.AccountSettings;
import com.android.email.activity.setup.FolderSettings;
import com.android.email.mail.Address;
import com.android.email.mail.Flag;
import com.android.email.mail.Folder;
import com.android.email.mail.Message;
import com.android.email.mail.MessagingException;
import com.android.email.mail.Store;
import com.android.email.mail.Message.RecipientType;
import com.android.email.mail.store.LocalStore;
import com.android.email.mail.store.LocalStore.LocalFolder;
import com.android.email.mail.store.LocalStore.LocalMessage;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* FolderList is the primary user interface for the program. This
* Activity shows list of the Account's folders
*/
public class FolderList extends K9ListActivity {
private static final String INTENT_DATA_PATH_SUFFIX = "/accounts";
private static final int DIALOG_MARK_ALL_AS_READ = 1;
private static final String EXTRA_ACCOUNT = "account";
private static final String EXTRA_INITIAL_FOLDER = "initialFolder";
private static final String EXTRA_CLEAR_NOTIFICATION = "clearNotification";
private static final boolean REFRESH_REMOTE = true;
private ListView mListView;
private FolderListAdapter mAdapter;
private LayoutInflater mInflater;
private Account mAccount;
private String mInitialFolder;
private boolean mRestoringState;
private boolean mRefreshRemote;
private FolderListHandler mHandler = new FolderListHandler();
private DateFormat dateFormat = null;
private DateFormat timeFormat = null;
private SORT_TYPE sortType = SORT_TYPE.SORT_DATE;
private boolean sortAscending = true;
private boolean sortDateAscending = false;
private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 1, 120000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
private DateFormat getDateFormat() {
if (dateFormat == null) {
String dateFormatS = android.provider.Settings.System.getString(getContentResolver(),
android.provider.Settings.System.DATE_FORMAT);
if (dateFormatS != null) {
dateFormat = new java.text.SimpleDateFormat(dateFormatS);
} else {
dateFormat = new java.text.SimpleDateFormat(Email.BACKUP_DATE_FORMAT);
}
}
return dateFormat;
}
private DateFormat getTimeFormat() {
if (timeFormat == null) {
String timeFormatS = android.provider.Settings.System.getString(getContentResolver(),
android.provider.Settings.System.TIME_12_24);
boolean b24 = !(timeFormatS == null || timeFormatS.equals("12"));
timeFormat = new java.text.SimpleDateFormat(b24 ? Email.TIME_FORMAT_24 : Email.TIME_FORMAT_12);
}
return timeFormat;
}
private void clearFormats() {
dateFormat = null;
timeFormat = null;
}
class FolderListHandler extends Handler {
private static final int MSG_PROGRESS = 2;
private static final int MSG_DATA_CHANGED = 3;
private static final int MSG_EXPAND_GROUP = 5;
private static final int MSG_FOLDER_LOADING = 7;
private static final int MSG_SYNC_MESSAGES = 13;
private static final int MSG_FOLDER_SYNCING = 18;
private static final int MSG_SENDING_OUTBOX = 19;
private static final int MSG_ACCOUNT_SIZE_CHANGED = 20;
private static final int MSG_WORKING_ACCOUNT = 21;
@Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_PROGRESS:
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
break;
case MSG_DATA_CHANGED:
mAdapter.notifyDataSetChanged();
break;
case MSG_FOLDER_LOADING: {
FolderInfoHolder folder = mAdapter.getFolder((String) msg.obj);
if (folder != null) {
folder.loading = msg.arg1 != 0;
}
break;
}
case MSG_ACCOUNT_SIZE_CHANGED: {
Long[] sizes = (Long[])msg.obj;
String toastText = getString(R.string.account_size_changed, mAccount.getDescription(), SizeFormatter.formatSize(getApplication(), sizes[0]), SizeFormatter.formatSize(getApplication(), sizes[1]));
Toast toast = Toast.makeText(getApplication(), toastText, Toast.LENGTH_LONG);
toast.show();
break;
}
case MSG_WORKING_ACCOUNT: {
int res = msg.arg1;
String toastText = getString(res, mAccount.getDescription());
Toast toast = Toast.makeText(getApplication(), toastText, Toast.LENGTH_SHORT);
toast.show();
break;
}
case MSG_FOLDER_SYNCING: {
String folderName = (String)((Object[]) msg.obj)[0];
String dispString;
dispString = mAccount.getDescription();
if (folderName != null) {
dispString += " (" + getString(R.string.status_loading) + folderName + ")";
}
setTitle(dispString);
break;
}
case MSG_SENDING_OUTBOX: {
boolean sending = (msg.arg1 != 0);
String dispString;
dispString = mAccount.getDescription();
if (sending) {
dispString += " (" + getString(R.string.status_sending) + ")";
}
setTitle(dispString);
break;
}
default:
super.handleMessage(msg);
}
}
public void synchronizeMessages(FolderInfoHolder folder, Message[] messages) {
android.os.Message msg = new android.os.Message();
msg.what = MSG_SYNC_MESSAGES;
msg.obj = new Object[] { folder, messages };
sendMessage(msg);
}
public void workingAccount(int res) {
android.os.Message msg = new android.os.Message();
msg.what = MSG_WORKING_ACCOUNT;
msg.arg1 = res;
sendMessage(msg);
}
public void accountSizeChanged(long oldSize, long newSize) {
android.os.Message msg = new android.os.Message();
msg.what = MSG_ACCOUNT_SIZE_CHANGED;
msg.obj = new Long[] { oldSize, newSize };
sendMessage(msg);
}
public void folderLoading(String folder, boolean loading) {
android.os.Message msg = new android.os.Message();
msg.what = MSG_FOLDER_LOADING;
msg.arg1 = loading ? 1 : 0;
msg.obj = folder;
sendMessage(msg);
}
public void progress(boolean progress) {
android.os.Message msg = new android.os.Message();
msg.what = MSG_PROGRESS;
msg.arg1 = progress ? 1 : 0;
sendMessage(msg);
}
public void dataChanged() {
sendEmptyMessage(MSG_DATA_CHANGED);
}
public void folderSyncing(String folder) {
android.os.Message msg = new android.os.Message();
msg.what = MSG_FOLDER_SYNCING;
msg.obj = new String[] { folder };
sendMessage(msg);
}
public void sendingOutbox(boolean sending) {
android.os.Message msg = new android.os.Message();
msg.what = MSG_SENDING_OUTBOX;
msg.arg1 = sending ? 1 : 0;
sendMessage(msg);
}
}
/**
* This class is responsible for reloading the list of local messages for a
* given folder, notifying the adapter that the message have been loaded and
* queueing up a remote update of the folder.
*/
class FolderUpdateWorker implements Runnable {
String mFolder;
FolderInfoHolder mHolder;
boolean mSynchronizeRemote;
/**
* Create a worker for the given folder and specifying whether the worker
* should synchronize the remote folder or just the local one.
*
* @param folder
* @param synchronizeRemote
*/
public FolderUpdateWorker(FolderInfoHolder folder, boolean synchronizeRemote) {
mFolder = folder.name;
mHolder = folder;
mSynchronizeRemote = synchronizeRemote;
}
public void run() {
// Lower our priority
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email - UpdateWorker");
wakeLock.setReferenceCounted(false);
wakeLock.acquire(Email.WAKE_LOCK_TIMEOUT);
// Synchronously load the list of local messages
try {
try {
Store localStore = Store.getInstance(mAccount.getLocalStoreUri(), getApplication());
LocalFolder localFolder = (LocalFolder) localStore.getFolder(mFolder);
if (localFolder.getMessageCount() == 0 && localFolder.getLastChecked() <= 0) {
mSynchronizeRemote = true;
}
} catch (MessagingException me) {
Log.e(Email.LOG_TAG, "Unable to get count of local messages for folder " + mFolder, me);
}
if (mSynchronizeRemote) {
// Tell the MessagingController to run a remote update of this folder
// at it's leisure
MessagingController.getInstance(getApplication()).synchronizeMailbox(mAccount, mFolder, mAdapter.mListener);
}
} finally {
wakeLock.release();
}
}
}
public static void actionHandleAccount(Context context, Account account, String initialFolder) {
Intent intent = new Intent(context, FolderList.class);
intent.putExtra(EXTRA_ACCOUNT, account);
if (initialFolder != null) {
intent.putExtra(EXTRA_INITIAL_FOLDER, initialFolder);
}
context.startActivity(intent);
}
public static void actionHandleAccount(Context context, Account account) {
actionHandleAccount(context, account, null);
}
public static Intent actionHandleAccountIntent(Context context, Account account, String initialFolder) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(Email.INTENT_DATA_URI_PREFIX + INTENT_DATA_PATH_SUFFIX + "/" + account.getAccountNumber()), context, FolderList.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(EXTRA_ACCOUNT, account);
intent.putExtra(EXTRA_CLEAR_NOTIFICATION, true);
if (initialFolder != null) {
intent.putExtra(EXTRA_INITIAL_FOLDER, initialFolder);
}
return intent;
}
public static Intent actionHandleAccountIntent(Context context, Account account) {
return actionHandleAccountIntent(context, account, null);
}
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
final FolderList xxx = this;
mListView = getListView();
mListView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);
mListView.setLongClickable(true);
//mListView.setFastScrollEnabled(true); // XXX TODO - reenable when we switch to 1.5
mListView.setScrollingCacheEnabled(true);
mListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int itemPosition, long id){
Log.v(Email.LOG_TAG,"We're clicking "+itemPosition+" -- "+id);
MessageList.actionHandleFolder(xxx,mAccount, ((FolderInfoHolder)mAdapter.getItem(id)).name);
}
});
registerForContextMenu(mListView);
/*
* We manually save and restore the list's state because our adapter is
* slow.
*/
mListView.setSaveEnabled(false);
mInflater = getLayoutInflater();
Intent intent = getIntent();
mAccount = (Account)intent.getSerializableExtra(EXTRA_ACCOUNT);
if (savedInstanceState == null) {
mInitialFolder = intent.getStringExtra(EXTRA_INITIAL_FOLDER);
if (mInitialFolder == null) {
mInitialFolder = mAccount.getAutoExpandFolderName();
if (Email.FOLDER_NONE.equals(mInitialFolder)) {
mInitialFolder = null;
}
r62972@17h: jesse | 2009-05-07 10:49:32 -0400 First stab at a folderlist that doesn't know or care about messages r62973@17h: jesse | 2009-05-07 10:50:11 -0400 A very broken first stab at a message list that only knows about one folder. r62974@17h: jesse | 2009-05-07 10:50:44 -0400 When you go from an account list to an individual account, open a folderlist, not an fml r62975@17h: jesse | 2009-05-07 10:51:24 -0400 Update Welcome activity to open an ml instead of an fml r62976@17h: jesse | 2009-05-07 10:51:59 -0400 When setting up accounts is over, open an fl instead of an fml r62977@17h: jesse | 2009-05-07 10:52:51 -0400 Update MessageView to use folderinfoholders and messageinfoholders from the 'correct' classes. r62978@17h: jesse | 2009-05-07 10:59:07 -0400 MailService now notifies the fl instead of the fml. Not sure if it should also notify the ml. - will require testing r62979@17h: jesse | 2009-05-07 11:01:09 -0400 Switch MessagingController's notifications from notifying the FML to notifying an ML r62980@17h: jesse | 2009-05-07 11:25:22 -0400 Update AndroidManifest to know about the new world order r62981@17h: jesse | 2009-05-07 11:26:11 -0400 Try to follow the android sdk docs for intent creation r62982@17h: jesse | 2009-05-07 11:28:30 -0400 reset MessageList for another try at the conversion r62983@17h: jesse | 2009-05-07 11:47:33 -0400 This version doesn't crash and has a working 'folder' layer. now to clean up the message list layer r62984@17h: jesse | 2009-05-07 15:18:04 -0400 move step 1 r62985@17h: jesse | 2009-05-07 15:18:37 -0400 move step 1 r62986@17h: jesse | 2009-05-07 15:22:47 -0400 rename step 1 r62987@17h: jesse | 2009-05-07 17:38:02 -0400 checkpoint to move r62988@17h: jesse | 2009-05-07 17:40:01 -0400 checkpointing a state with a working folder list and a message list that doesn't explode r62989@17h: jesse | 2009-05-07 17:40:26 -0400 Remove debugging cruft from Welcome r62990@17h: jesse | 2009-05-07 22:00:12 -0400 Basic functionality works. r62991@17h: jesse | 2009-05-08 04:19:52 -0400 added a tool to build a K-9 "Beta" r62992@17h: jesse | 2009-05-08 04:20:03 -0400 remove a disused file r62993@17h: jesse | 2009-05-09 06:07:02 -0400 upgrading build infrastructure for the 1.5 sdk r62994@17h: jesse | 2009-05-09 06:22:02 -0400 further refine onOpenMessage, removing more folder assumptions r62995@17h: jesse | 2009-05-09 20:07:20 -0400 Make the Welcome activity open the autoexpandfolder rather than INBOX r62996@17h: jesse | 2009-05-09 20:14:10 -0400 MessageList now stores the Folder name it was working with across pause-reload r62997@17h: jesse | 2009-05-09 20:14:26 -0400 Removing dead code from FolderList r63060@17h: jesse | 2009-05-10 00:07:33 -0400 Replace the old message list refreshing code which cleared and rebuilt the list from scratch with code which updates or deletes existing messages. Add "go back to folder list" code r63061@17h: jesse | 2009-05-10 00:07:50 -0400 fix message list menus for new world order r63062@17h: jesse | 2009-05-10 00:08:11 -0400 Remove message list options from folder list menus r63063@17h: jesse | 2009-05-10 00:10:02 -0400 remove more message list options from the folder list r63064@17h: jesse | 2009-05-10 00:10:19 -0400 fix build.xml for the new android world order r63065@17h: jesse | 2009-05-10 00:39:23 -0400 reformatted in advance of bug tracing r63066@17h: jesse | 2009-05-10 05:53:28 -0400 fix our 'close' behavior to not leave extra activities around clean up more vestigal code r63067@17h: jesse | 2009-05-10 18:44:25 -0400 Improve "back button / accounts" workflow from FolderList -> AccountList r63068@17h: jesse | 2009-05-10 19:11:47 -0400 * Add required code for the 'k9beta' build r63069@17h: jesse | 2009-05-10 19:12:05 -0400 Make the folder list white backgrounded. r63070@17h: jesse | 2009-05-10 19:12:26 -0400 * Include our required libraries in build.xml r63071@17h: jesse | 2009-05-10 19:13:07 -0400 Added directories for our built code and our generated code r63072@17h: jesse | 2009-05-10 19:13:36 -0400 Added a "back" button image r63073@17h: jesse | 2009-05-10 20:13:50 -0400 Switch next/prev buttons to triangles for I18N and eventual "more easy-to-hit buttons" win r63074@17h: jesse | 2009-05-10 20:17:18 -0400 Tidy Accounts.java for some perf hacking. r63081@17h: jesse | 2009-05-10 22:13:33 -0400 First pass reformatting of the MessagingController r63082@17h: jesse | 2009-05-10 23:50:28 -0400 MessageList now correctly updates when a background sync happens r63083@17h: jesse | 2009-05-10 23:50:53 -0400 Tidying FolderList r63084@17h: jesse | 2009-05-10 23:51:09 -0400 tidy r63085@17h: jesse | 2009-05-10 23:51:27 -0400 tidy r63086@17h: jesse | 2009-05-11 00:17:06 -0400 Properly update unread counts in the FolderList after sync r63087@17h: jesse | 2009-05-11 01:38:14 -0400 Minor refactoring for readability. replace a boolean with a constant. r63090@17h: jesse | 2009-05-11 02:58:31 -0400 now that the foreground of message lists is light, we don't need the light messagebox r63091@17h: jesse | 2009-05-11 17:15:02 -0400 Added a string for "back to folder list" r63092@17h: jesse | 2009-05-11 17:15:24 -0400 Added a message list header with a back button r63093@17h: jesse | 2009-05-11 17:15:54 -0400 Remove the "folder list" button from the options menu. no sense duplicating it r63094@17h: jesse | 2009-05-11 17:17:06 -0400 Refactored views, adding our replacement scrollable header r63184@17h: jesse | 2009-05-12 07:07:15 -0400 fix weird bug where message lists could show a header element for a child r63185@17h: jesse | 2009-05-12 07:08:12 -0400 Add new-style headers to folder lists. reimplement "get folder by name" to not use a bloody for loop r63211@17h: jesse | 2009-05-12 18:37:48 -0400 Restore the former glory of the "load more messages" widget. it still needs an overhaul r63296@17h: jesse | 2009-05-12 23:23:21 -0400 Get the indeterminate progress bar to show up again when you click "get more messages" r63297@17h: jesse | 2009-05-13 02:40:39 -0400 Fixed off-by-one errors in click and keybindings for messagelist r63298@17h: jesse | 2009-05-13 06:04:01 -0400 Put the folder title in the name of the folderSettings popup r63299@17h: jesse | 2009-05-13 06:04:49 -0400 Reformatting. Removing debug logging r63300@17h: jesse | 2009-05-13 06:05:32 -0400 Fixing "wrong item selected" bugs in the FolderList r63328@17h: jesse | 2009-05-13 13:20:00 -0400 Update MessageView for 1.5 r63329@17h: jesse | 2009-05-13 13:50:29 -0400 A couple fixes to "picking the right item" Titles on the message context menu r63330@17h: jesse | 2009-05-13 13:58:37 -0400 Added an "open" context menu item to the folder list r63347@17h: jesse | 2009-05-13 18:00:02 -0400 Try to get folderlists to sort in a stable way, so they jump around less in the ui r63349@17h: jesse | 2009-05-13 20:37:19 -0400 Switch to using non-message-passing based notifications for redisplay of message lists, cut down redisplay frequency to not overload the display r63432@17h: jesse | 2009-05-16 13:38:49 -0400 Android 1.5 no longer gives us apache.commons.codec by default and apache.commons.logging by default. Import them so we have em. There's probably something smarter to do here. r63438@17h: jesse | 2009-05-16 14:12:06 -0400 removed dead code r63439@17h: jesse | 2009-05-16 14:30:57 -0400 Minor tidy r63440@17h: jesse | 2009-05-16 14:39:34 -0400 First pass implementation making MessageList streamy for faster startup r63441@17h: jesse | 2009-05-16 21:57:41 -0400 There's no reason for the FolderList to list local messages r63442@17h: jesse | 2009-05-16 21:58:57 -0400 Switch to actually refreshing the message list after each item is loaded r63450@17h: jesse | 2009-05-16 22:34:18 -0400 Default to pulling items out of the LocalStore by date, descending. (since that's the uneditable default ordering) This makes our messages come out of the store in the order the user should see them r63451@17h: jesse | 2009-05-16 22:34:44 -0400 Set some new defaults for the FolderList r63452@17h: jesse | 2009-05-16 22:35:43 -0400 set some new message list item defaults r63456@17h: jesse | 2009-05-17 12:56:10 -0400 It's not clear that Pop and WebDav actually set us an InternalDate. I'd rather use that so that spam doesn't topsort. But I also want this to _work_ r63457@17h: jesse | 2009-05-17 12:56:47 -0400 actually check to make sure we have a message to remove before removing it. r63458@17h: jesse | 2009-05-17 13:10:07 -0400 Flip "security type" to before the port number, since changing security type is the thing more users are likely to know/care about and resets port number r63469@17h: jesse | 2009-05-17 18:42:39 -0400 Provisional fix for "see the FoldeRList twice" bug r63471@17h: jesse | 2009-05-17 20:47:41 -0400 Remove title bar from the message view r63544@17h: jesse | 2009-05-20 23:53:38 -0400 folderlist tidying before i dig into the jumpy ordering bug r63545@17h: jesse | 2009-05-20 23:56:00 -0400 Killing dead variables r63546@17h: jesse | 2009-05-21 00:58:36 -0400 make the whole title section clicky r63556@17h: jesse | 2009-05-21 01:48:13 -0400 Fix where we go when someone deletes a message r63558@17h: jesse | 2009-05-21 22:44:46 -0400 Working toward switchable themes r63563@17h: jesse | 2009-05-21 23:53:09 -0400 Make the MessageList's colors actually just inherit from the theme, rather than hardcoding black r63567@17h: jesse | 2009-05-22 10:14:13 -0400 Kill a now-redundant comment r63571@17h: jesse | 2009-05-22 19:43:30 -0400 further theme-independence work r63572@17h: jesse | 2009-05-22 19:55:23 -0400 gete -> get (typo fix) r63573@17h: jesse | 2009-05-22 22:48:49 -0400 First cut of a global prefs system as well as a theme preference. not that it works yet r63577@17h: jesse | 2009-05-24 14:49:52 -0400 Once a user has actually put in valid user credentials, start syncing mail and folders in the background instantly. This gives us a much better "new startup" experience r63578@17h: jesse | 2009-05-24 14:55:00 -0400 MessageList doesn't need FolderUpdateWorker r63579@17h: jesse | 2009-05-24 17:57:15 -0400 Fix "get message by uid" Switch to showing messages 10 by 10, rather than 1 by 1 for huge loadtime performance improvements r63587@17h: jesse | 2009-05-24 19:19:56 -0400 Cut down LocalMessage creation to not generate a MessageId or date formatter. r63589@17h: jesse | 2009-05-24 22:22:32 -0400 Switch to null-escaping email address boundaries, rather than a VERY expensive URL-encoding r63590@17h: jesse | 2009-05-24 22:23:21 -0400 Clean up our "auto-refresh the list when adding messages after a sync" r63593@17h: jesse | 2009-05-24 22:53:45 -0400 replace isDateToday with a "rolling 18 hour window" variant that's more likely to give the user a useful answer and is 30x faster. r63595@17h: jesse | 2009-05-24 23:54:14 -0400 When instantiating messges from the LocalStore, there's no need to clear headers before setting them, nor is there a need to set a generated message id r63596@17h: jesse | 2009-05-24 23:54:39 -0400 make an overridable setGeneratedMessageId r63597@17h: jesse | 2009-05-24 23:54:55 -0400 Remove new lies from comments r63598@17h: jesse | 2009-05-24 23:55:35 -0400 Replace insanely expensive message header "name" part quoting with something consistent and cheap that does its work on the way INTO the database r63605@17h: jesse | 2009-05-25 17:28:24 -0400 bring back the 1.1 sdk build.xml r63606@17h: jesse | 2009-05-25 22:32:11 -0400 Actually enable switchable themese and compilation on 1.1 r63692@17h: jesse | 2009-05-29 23:55:17 -0400 Switch back to having titles for folder and message lists. Restore auto-open-folder functionality r63694@17h: jesse | 2009-05-30 18:50:39 -0400 Remove several off-by-one errors introduced by yesterday's return to android titlebars r63696@17h: jesse | 2009-05-30 23:45:03 -0400 use convertView properly for performance and memory imrpovement in FolderList and MessageList r63698@17h: jesse | 2009-05-31 19:42:59 -0400 Switch to using background shading to indicate "not yet fetched" r63701@17h: jesse | 2009-05-31 21:28:47 -0400 Remving code we don't actually need these bits of apache commons on 1.1
2009-05-31 21:35:05 -04:00
}
}
mAdapter = new FolderListAdapter();
final Object previousData = getLastNonConfigurationInstance();
if (previousData != null) {
//noinspection unchecked
mAdapter.mFolders = (ArrayList<FolderInfoHolder>) previousData;
}
setListAdapter(mAdapter);
if (savedInstanceState != null) {
mRestoringState = true;
//onRestoreListState(savedInstanceState);
mRestoringState = false;
}
setTitle(mAccount.getDescription());
if (mInitialFolder != null) {
onOpenFolder(mInitialFolder);
}
}
@Override public Object onRetainNonConfigurationInstance() {
return mAdapter.mFolders;
}
@Override public void onPause() {
super.onPause();
MessagingController.getInstance(getApplication()).removeListener(mAdapter.mListener);
}
/**
* On resume we refresh the folder list (in the background) and we refresh the
* messages for any folder that is currently open. This guarantees that things
* like unread message count and read status are updated.
*/
@Override public void onResume() {
super.onResume();
clearFormats();
MessagingController.getInstance(getApplication()).addListener(mAdapter.mListener);
mAccount.refresh(Preferences.getPreferences(this));
markAllRefresh();
onRefresh( !REFRESH_REMOTE );
NotificationManager notifMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notifMgr.cancel(mAccount.getAccountNumber());
notifMgr.cancel(-1000 - mAccount.getAccountNumber());
}
@Override public boolean onKeyDown(int keyCode, KeyEvent event) {
//Shortcuts that work no matter what is selected
switch (keyCode) {
case KeyEvent.KEYCODE_Q: {
onAccounts();
return true;
}
case KeyEvent.KEYCODE_S: {
onEditAccount();
return true;
}
case KeyEvent.KEYCODE_H: {
Toast toast = Toast.makeText(this, R.string.message_list_help_key, Toast.LENGTH_LONG);
toast.show();
return true;
}
}//switch
return super.onKeyDown(keyCode, event);
}//onKeyDown
private void onRefresh(final boolean forceRemote) {
if (forceRemote) {
mRefreshRemote = true;
}
new Thread() {
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
MessagingController.getInstance(getApplication()).listFolders(mAccount, forceRemote, mAdapter.mListener);
if (forceRemote) {
MessagingController.getInstance(getApplication()).sendPendingMessages(mAccount, null);
}
}
}
.start();
}
private void onEditAccount() {
AccountSettings.actionSettings(this, mAccount);
}
private void onEditFolder(Account account, String folderName) {
FolderSettings.actionSettings(this, account, folderName);
}
private void onAccounts() {
// If we're a child activity (say because Welcome dropped us straight to the message list
// we won't have a parent activity and we'll need to get back to it
if (isTaskRoot()) {
startActivity(new Intent(this, Accounts.class));
}
finish();
}
private void markAllRefresh() {
mAdapter.mListener.accountReset(mAccount);
}
private void onEmptyTrash(final Account account) {
mHandler.dataChanged();
MessagingListener listener = new MessagingListener() {
@Override
public void controllerCommandCompleted(boolean moreToDo) {
Log.v(Email.LOG_TAG, "Empty Trash background task completed");
}
};
MessagingController.getInstance(getApplication()).emptyTrash(account, listener);
}
private void checkMail(final Account account) {
MessagingController.getInstance(getApplication()).checkMail(this, account, true, true, mAdapter.mListener);
}
private void checkMail(Account account, String folderName) {
MessagingController.getInstance(getApplication()).synchronizeMailbox(account, folderName, mAdapter.mListener);
}
@Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.check_mail:
checkMail(mAccount);
return true;
case R.id.list_folders:
onRefresh( REFRESH_REMOTE );
return true;
case R.id.account_settings:
onEditAccount();
return true;
case R.id.empty_trash:
onEmptyTrash(mAccount);
return true;
case R.id.compact:
onCompact(mAccount);
return true;
case R.id.clear:
onClear(mAccount);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void onOpenFolder(FolderInfoHolder folder) {
onOpenFolder(folder.name);
}
private void onOpenFolder(String folder) {
MessageList.actionHandleFolder(this, mAccount, folder);
}
private void onCompact(Account account) {
mHandler.workingAccount(R.string.compacting_account);
MessagingController.getInstance(getApplication()).compact(account, null);
}
private void onClear(Account account) {
mHandler.workingAccount(R.string.clearing_account);
MessagingController.getInstance(getApplication()).clear(account, null);
}
@Override public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.folder_list_option, menu);
return true;
}
@Override public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item .getMenuInfo();
FolderInfoHolder folder = (FolderInfoHolder) mAdapter.getItem(info.position);
switch (item.getItemId()) {
case R.id.open_folder:
onOpenFolder(folder);
break;
case R.id.send_messages:
Log.i(Email.LOG_TAG, "sending pending messages from " + folder.name);
MessagingController.getInstance(getApplication()).sendPendingMessages(mAccount, null);
break;
case R.id.check_mail:
Log.i(Email.LOG_TAG, "refresh folder " + folder.name);
threadPool.execute(new FolderUpdateWorker(folder, true));
break;
case R.id.folder_settings:
Log.i(Email.LOG_TAG, "edit folder settings for " + folder.name);
onEditFolder(mAccount, folder.name);
break;
case R.id.empty_trash:
Log.i(Email.LOG_TAG, "empty trash");
onEmptyTrash(mAccount);
break;
}
return super.onContextItemSelected(item);
}
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
getMenuInflater().inflate(R.menu.folder_context, menu);
FolderInfoHolder folder = (FolderInfoHolder) mAdapter.getItem(info.position);
menu.setHeaderTitle((CharSequence) folder.displayName);
if (!folder.name.equals(mAccount.getTrashFolderName()))
menu.findItem(R.id.empty_trash).setVisible(false);
if (folder.outbox) {
menu.findItem(R.id.check_mail).setVisible(false);
} else {
menu.findItem(R.id.send_messages).setVisible(false);
}
menu.setHeaderTitle(folder.displayName);
}
private String truncateStatus(String mess) {
if (mess != null && mess.length() > 27) {
mess = mess.substring(0, 27);
}
return mess;
}
class FolderListAdapter extends BaseAdapter {
private ArrayList<FolderInfoHolder> mFolders = new ArrayList<FolderInfoHolder>();
public Object getItem(long position) {
return getItem((int)position);
}
public Object getItem(int position) {
return mFolders.get(position);
}
public long getItemId(int position) {
return position ;
}
public int getCount() {
return mFolders.size();
}
public boolean isEnabled(int item) {
return true;
}
public boolean areAllItemsEnabled() {
return true;
}
private MessagingListener mListener = new MessagingListener() {
@Override
public void listFoldersStarted(Account account) {
if (!account.equals(mAccount)) {
return;
}
mHandler.progress(true);
}
@Override
public void listFoldersFailed(Account account, String message) {
if (!account.equals(mAccount)) {
return;
}
mHandler.progress(false);
if (Config.LOGV) {
Log.v(Email.LOG_TAG, "listFoldersFailed " + message);
}
}
@Override
public void listFoldersFinished(Account account) {
if (!account.equals(mAccount)) {
return;
}
mHandler.progress(false);
mHandler.dataChanged();
}
@Override
public void listFolders(Account account, Folder[] folders) {
if (!account.equals(mAccount)) {
return;
}
ArrayList<FolderInfoHolder> newFolders = new ArrayList<FolderInfoHolder>();
Account.FolderMode aMode = account.getFolderDisplayMode();
for (Folder folder : folders) {
try {
folder.refresh( Preferences.getPreferences(getApplication().getApplicationContext()) );
Folder.FolderClass fMode = folder.getDisplayClass();
if ((aMode == Account.FolderMode.FIRST_CLASS && fMode != Folder.FolderClass.FIRST_CLASS)
|| (aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS &&
fMode != Folder.FolderClass.FIRST_CLASS &&
fMode != Folder.FolderClass.SECOND_CLASS)
|| (aMode == Account.FolderMode.NOT_SECOND_CLASS && fMode == Folder.FolderClass.SECOND_CLASS)) {
continue;
}
} catch (MessagingException me) {
Log.e(Email.LOG_TAG, "Couldn't get prefs to check for displayability of folder " + folder.getName(), me);
}
FolderInfoHolder holder = null;
int folderIndex = getFolderIndex(folder.getName());
if (folderIndex >= 0 ) {
holder = (FolderInfoHolder) getItem(folderIndex);
}
if (holder == null) {
holder = new FolderInfoHolder(folder);
} else {
holder.populate(folder);
}
newFolders.add(holder);
}
mFolders.clear();
mFolders.addAll(newFolders);
Collections.sort(mFolders);
mHandler.dataChanged();
mRefreshRemote = false;
}
@Override
public void accountReset(Account account) {
if (!account.equals(mAccount)) {
return;
}
for (FolderInfoHolder folder : mFolders) {
folder.needsRefresh = true;
}
}
public void synchronizeMailboxStarted(Account account, String folder) {
if (!account.equals(mAccount)) {
return;
}
mHandler.progress(true);
mHandler.folderLoading(folder, true);
mHandler.folderSyncing(folder);
}
@Override
public void synchronizeMailboxFinished(Account account, String folder, int totalMessagesInMailbox, int numNewMessages) {
if (!account.equals(mAccount)) {
return;
}
// There has to be a cheaper way to get at the localFolder object than this
try {
Folder localFolder = (Folder) Store.getInstance(account.getLocalStoreUri(), getApplication()).getFolder(folder);
getFolder(folder).populate(localFolder);
}
catch (MessagingException e) {
}
mHandler.progress(false);
mHandler.folderLoading(folder, false);
// mHandler.folderStatus(folder, null);
mHandler.folderSyncing(null);
onRefresh( ! REFRESH_REMOTE );
}
@Override
public void synchronizeMailboxFailed(Account account, String folder,
String message) {
if (!account.equals(mAccount)) {
return;
}
mHandler.progress(false);
mHandler.folderLoading(folder, false);
// String mess = truncateStatus(message);
// mHandler.folderStatus(folder, mess);
FolderInfoHolder holder = getFolder(folder);
if (holder != null) {
holder.lastChecked = 0;
}
mHandler.folderSyncing(null);
}
@Override
public void messageDeleted(Account account,
String folder, Message message) {
synchronizeMailboxRemovedMessage(account,
folder, message);
}
@Override
public void emptyTrashCompleted(Account account) {
if (!account.equals(mAccount)) {
return;
}
onRefresh( ! REFRESH_REMOTE);
}
@Override
public void folderStatusChanged(Account account, String folderName) {
if (!account.equals(mAccount)) {
return;
}
onRefresh( !REFRESH_REMOTE);
}
@Override
public void sendPendingMessagesCompleted(Account account) {
if (!account.equals(mAccount)) {
return;
}
mHandler.sendingOutbox(false);
onRefresh( !REFRESH_REMOTE);
}
@Override
public void sendPendingMessagesStarted(Account account) {
if (!account.equals(mAccount)) {
return;
}
mHandler.sendingOutbox(true);
}
@Override
public void sendPendingMessagesFailed(Account account) {
if (!account.equals(mAccount)) {
return;
}
mHandler.sendingOutbox(false);
}
public void accountSizeChanged(Account account, long oldSize, long newSize) {
if (!account.equals(mAccount)) {
return;
}
mHandler.accountSizeChanged(oldSize, newSize);
}
};
public int getFolderIndex(String folder) {
FolderInfoHolder searchHolder = new FolderInfoHolder();
searchHolder.name = folder;
return mFolders.indexOf((Object) searchHolder);
}
public FolderInfoHolder getFolder(String folder) {
FolderInfoHolder holder = null;
int index = getFolderIndex(folder);
if(index >= 0 ){
holder = (FolderInfoHolder) getItem(index);
if (holder != null) {
return holder;
}
}
return null;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (position <= getCount()) {
return getItemView(position, convertView, parent);
} else {
// XXX TODO - should catch an exception here
return null;
}
}
public View getItemView(int itemPosition, View convertView, ViewGroup parent) {
FolderInfoHolder folder = (FolderInfoHolder) getItem(itemPosition);
View view;
if ((convertView != null) && (convertView.getId() == R.layout.folder_list_item)) {
view = convertView;
} else {
view = mInflater.inflate(R.layout.folder_list_item, parent, false);
view.setId(R.layout.folder_list_item);
}
FolderViewHolder holder = (FolderViewHolder) view.getTag();
if (holder == null) {
holder = new FolderViewHolder();
holder.folderName = (TextView) view.findViewById(R.id.folder_name);
holder.newMessageCount = (TextView) view.findViewById(R.id.folder_unread_message_count);
holder.folderStatus = (TextView) view.findViewById(R.id.folder_status);
holder.rawFolderName = folder.name;
view.setTag(holder);
}
if (folder == null) {
return view;
}
holder.folderName.setText(folder.displayName);
String statusText = "";
if (folder.loading) {
statusText = getString(R.string.status_loading);
} else if (folder.status != null) {
statusText = folder.status;
} else if (folder.lastChecked != 0) {
Date lastCheckedDate = new Date(folder.lastChecked);
statusText = (getDateFormat().format(lastCheckedDate) + " " + getTimeFormat()
.format(lastCheckedDate));
}
if (statusText != null) {
holder.folderStatus.setText(statusText);
holder.folderStatus.setVisibility(View.VISIBLE);
} else {
holder.folderStatus.setText(null);
holder.folderStatus.setVisibility(View.GONE);
}
if (folder.unreadMessageCount != 0) {
holder.newMessageCount.setText(Integer
.toString(folder.unreadMessageCount));
holder.newMessageCount.setVisibility(View.VISIBLE);
} else {
holder.newMessageCount.setVisibility(View.GONE);
}
return view;
}
public boolean hasStableIds() {
return false;
}
public boolean isItemSelectable(int position) {
return true;
}
}
public class FolderInfoHolder implements Comparable<FolderInfoHolder> {
public String name;
public String displayName;
public ArrayList<MessageInfoHolder> messages;
public long lastChecked;
public int unreadMessageCount;
public boolean loading;
public String status;
public boolean lastCheckFailed;
public boolean needsRefresh = false;
/**
* Outbox is handled differently from any other folder.
*/
public boolean outbox;
public boolean equals(Object o) {
if (this.name.equals(((FolderInfoHolder)o).name)) {
return true;
} else {
return false;
}
}
public int compareTo(FolderInfoHolder o) {
String s1 = this.name;
String s2 = o.name;
if (Email.INBOX.equalsIgnoreCase(s1) && Email.INBOX.equalsIgnoreCase(s2)) {
return 0;
} else if (Email.INBOX.equalsIgnoreCase(s1)) {
return -1;
} else if (Email.INBOX.equalsIgnoreCase(s2)) {
return 1;
} else
return s1.compareTo(s2);
}
// constructor for an empty object for comparisons
public FolderInfoHolder() {
}
public FolderInfoHolder(Folder folder) {
populate(folder);
}
public void populate (Folder folder) {
int unreadCount = 0;
try {
folder.open(Folder.OpenMode.READ_WRITE);
unreadCount = folder.getUnreadMessageCount();
} catch (MessagingException me) {
Log.e(Email.LOG_TAG, "Folder.getUnreadMessageCount() failed", me);
}
this.name = folder.getName();
if (this.name.equalsIgnoreCase(Email.INBOX)) {
this.displayName = getString(R.string.special_mailbox_name_inbox);
} else {
this.displayName = folder.getName();
}
if (this.name.equals(mAccount.getOutboxFolderName())) {
this.displayName = String.format( getString(R.string.special_mailbox_name_outbox_fmt), this.name);
this.outbox = true;
}
if (this.name.equals(mAccount.getDraftsFolderName())) {
this.displayName = String.format( getString(R.string.special_mailbox_name_drafts_fmt), this.name);
}
if (this.name.equals(mAccount.getTrashFolderName())) {
this.displayName = String.format( getString(R.string.special_mailbox_name_trash_fmt), this.name);
}
if (this.name.equals(mAccount.getSentFolderName())) {
this.displayName = String.format( getString(R.string.special_mailbox_name_sent_fmt), this.name);
}
if (this.messages == null) {
this.messages = new ArrayList<MessageInfoHolder>();
}
this.lastChecked = folder.getLastChecked();
String mess = truncateStatus(folder.getStatus());
this.status = mess;
this.unreadMessageCount = unreadCount;
try {
folder.close(false);
} catch (MessagingException me) {
Log.e(Email.LOG_TAG, "Folder.close() failed", me);
}
}
}
class FolderViewHolder {
public TextView folderName;
public TextView folderStatus;
public TextView newMessageCount;
public String rawFolderName;
}
}