1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-30 13:12:25 -05:00

Issue 4: Implements Push Mail for IMAP accounts using IMAP IDLE

This commit contains the entirety of the changes performed in the
issue4-1.X branch from revision 718 through revision 851.  Because the
issue4-1.X branch was up-to-date with trunk revision 847 at revision
849, the source of this commit was not an "svn merge".  Instead, it is
merely a copy of all changed files from the issue4-1.X branch to my
trunk working copy and a straight commit.

Also:
Issue 551
Issue 628
Issue 650
Issue 654
Issue 656
Issue 682
Issue 696
This commit is contained in:
Daniel Applebaum 2009-10-22 00:41:06 +00:00
parent 78da963031
commit 959404cc68
33 changed files with 3328 additions and 1203 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1011"
android:versionName="1.011" package="com.fsck.k9">
android:versionCode="1105"
android:versionName="1.105" package="com.fsck.k9">
<uses-sdk android:minSdkVersion="3"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
@ -204,6 +204,9 @@
<intent-filter>
<action android:name="android.intent.action.DEVICE_STORAGE_OK" />
</intent-filter>
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<service
android:name="com.android.email.service.MailService"

View File

@ -33,6 +33,11 @@
android:title="@string/account_settings_action"
android:icon="@android:drawable/ic_menu_preferences"
/>
<item
android:id="@+id/send_messages"
android:title="@string/send_messages_action"
android:icon="@drawable/ic_menu_refresh"
/>
<item
android:id="@+id/compact"
android:title="@string/compact_action"

View File

@ -47,6 +47,12 @@
android:alphabeticShortcut="f"
android:title="@string/list_folders_action"
android:icon="@drawable/ic_menu_navigate"
/>
<item
android:id="@+id/send_messages"
android:alphabeticShortcut="r"
android:title="@string/send_messages_action"
android:icon="@drawable/ic_menu_refresh"
/>
<item
android:id="@+id/check_mail"
@ -54,6 +60,11 @@
android:title="@string/check_mail_action"
android:icon="@drawable/ic_menu_refresh"
/>
<item
android:id="@+id/accounts"
android:title="@string/accounts_action"
android:icon="@drawable/ic_menu_account_list"
/>
<item
android:id="@+id/mark_all_as_read"
android:title="@string/mark_all_as_read_action"

View File

@ -368,9 +368,10 @@ Willkommen zum K-9 Mail Setup. K-9 ist eine Open-Source E-Mail-Anwendung für A
<string name="folder_settings_folder_display_mode_second_class">Nebenordner</string>
<string name="folder_settings_folder_sync_mode_label">Synchronisationsklasse</string>
<string name="folder_settings_folder_sync_mode_normal">Wie Anzeigeklasse</string>
<string name="folder_settings_folder_sync_mode_normal">Keine</string>
<string name="folder_settings_folder_sync_mode_first_class">Hauptordner</string>
<string name="folder_settings_folder_sync_mode_second_class">Nebenordner</string>
<string name="folder_settings_folder_sync_mode_inherited">Wie Anzeigeklasse</string>
<string name="account_settings_incoming_label">Einstellungen Posteingang</string>
<string name="account_settings_incoming_summary">Einstellungen für Posteingangsserver bearbeiten.</string>

View File

@ -81,6 +81,7 @@
<item>@string/account_settings_folder_sync_mode_first_class</item>
<item>@string/account_settings_folder_sync_mode_first_and_second_class</item>
<item>@string/account_settings_folder_sync_mode_not_second_class</item>
<item>@string/account_settings_folder_sync_mode_none</item>
</string-array>
<string-array name="account_settings_folder_sync_mode_values">
@ -88,6 +89,23 @@
<item>FIRST_CLASS</item>
<item>FIRST_AND_SECOND_CLASS</item>
<item>NOT_SECOND_CLASS</item>
<item>NONE</item>
</string-array>
<string-array name="account_settings_folder_push_mode_entries">
<item>@string/account_settings_folder_push_mode_all</item>
<item>@string/account_settings_folder_push_mode_first_class</item>
<item>@string/account_settings_folder_push_mode_first_and_second_class</item>
<item>@string/account_settings_folder_push_mode_not_second_class</item>
<item>@string/account_settings_folder_push_mode_none</item>
</string-array>
<string-array name="account_settings_folder_push_mode_values">
<item>ALL</item>
<item>FIRST_CLASS</item>
<item>FIRST_AND_SECOND_CLASS</item>
<item>NOT_SECOND_CLASS</item>
<item>NONE</item>
</string-array>
<string-array name="account_settings_folder_target_mode_entries">
@ -111,7 +129,7 @@
</string-array>
<string-array name="folder_settings_folder_display_mode_values">
<item>NONE</item>
<item>NO_CLASS</item>
<item>FIRST_CLASS</item>
<item>SECOND_CLASS</item>
</string-array>
@ -120,12 +138,28 @@
<item>@string/folder_settings_folder_sync_mode_normal</item>
<item>@string/folder_settings_folder_sync_mode_first_class</item>
<item>@string/folder_settings_folder_sync_mode_second_class</item>
<item>@string/folder_settings_folder_sync_mode_inherited</item>
</string-array>
<string-array name="folder_settings_folder_sync_mode_values">
<item>NONE</item>
<item>NO_CLASS</item>
<item>FIRST_CLASS</item>
<item>SECOND_CLASS</item>
<item>INHERITED</item>
</string-array>
<string-array name="folder_settings_folder_push_mode_entries">
<item>@string/folder_settings_folder_push_mode_normal</item>
<item>@string/folder_settings_folder_push_mode_first_class</item>
<item>@string/folder_settings_folder_push_mode_second_class</item>
<item>@string/folder_settings_folder_push_mode_inherited</item>
</string-array>
<string-array name="folder_settings_folder_push_mode_values">
<item>NO_CLASS</item>
<item>FIRST_CLASS</item>
<item>SECOND_CLASS</item>
<item>INHERITED</item>
</string-array>
<string-array name="account_setup_delete_policy_entries">

View File

@ -146,6 +146,9 @@
Long-press the Outbox to find the "Send messages" action in order to initiate another sending attempt.\u000A\u000a
The <xliff:g id="errorFolder">%s</xliff:g> folder may contain error messages regarding the failures.</string>
<string name="alert_header">K-9 alert</string>
<string name="no_connection_alert">Syncing and sending suspended due to lack of network.</string>
<string name="end_of_folder">No more messages</string>
<string name="accounts_welcome">
@ -210,12 +213,15 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
<string name="message_view_show_pictures_instructions">Select \"Show pictures\" to display embedded pictures.</string>
<string name="message_view_show_pictures_action">Show pictures</string>
<string name="message_view_fetching_attachment_toast">Fetching attachment.</string>
<string name="message_view_no_viewer">Unable to find viewer for <xliff:g id="mimetype">%s</xliff:g>.</string>
<string name="mailbox_select_dlg_title">Folders</string>
<string name="mailbox_select_dlg_new_mailbox_action">New folder</string>
<string name="new_mailbox_dlg_title">New folder name</string>
<string name="folder_push_active_symbol">(Push)</string>
<string name="message_copied_toast">Message copied</string>
<string name="message_moved_toast">Message moved</string>
<string name="message_deleted_toast">Message deleted</string>
@ -382,6 +388,14 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
<string name="account_settings_folder_sync_mode_first_class">Only 1st Class folders</string>
<string name="account_settings_folder_sync_mode_first_and_second_class">1st and 2nd Class folders</string>
<string name="account_settings_folder_sync_mode_not_second_class">All except 2nd Class folders</string>
<string name="account_settings_folder_sync_mode_none">None</string>
<string name="account_settings_folder_push_mode_label">Folder push mode</string>
<string name="account_settings_folder_push_mode_all">All</string>
<string name="account_settings_folder_push_mode_first_class">Only 1st Class folders</string>
<string name="account_settings_folder_push_mode_first_and_second_class">1st and 2nd Class folders</string>
<string name="account_settings_folder_push_mode_not_second_class">All except 2nd Class folders</string>
<string name="account_settings_folder_push_mode_none">None</string>
<string name="account_settings_folder_target_mode_label">Move/copy destination folders</string>
<string name="account_settings_folder_target_mode_all">All</string>
@ -396,9 +410,16 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
<string name="folder_settings_folder_display_mode_second_class">2nd Class</string>
<string name="folder_settings_folder_sync_mode_label">Folder sync class</string>
<string name="folder_settings_folder_sync_mode_normal">Same as display class</string>
<string name="folder_settings_folder_sync_mode_normal">None</string>
<string name="folder_settings_folder_sync_mode_first_class">1st Class</string>
<string name="folder_settings_folder_sync_mode_second_class">2nd Class</string>
<string name="folder_settings_folder_sync_mode_inherited">Same as display class</string>
<string name="folder_settings_folder_push_mode_label">Folder push class</string>
<string name="folder_settings_folder_push_mode_normal">None</string>
<string name="folder_settings_folder_push_mode_first_class">1st Class</string>
<string name="folder_settings_folder_push_mode_second_class">2nd Class</string>
<string name="folder_settings_folder_push_mode_inherited">Same as sync class</string>
<string name="account_settings_incoming_label">Incoming settings</string>
<string name="account_settings_incoming_summary">Configure the incoming email server</string>

View File

@ -78,6 +78,13 @@
android:entryValues="@array/account_settings_folder_sync_mode_values"
android:dialogTitle="@string/account_settings_folder_sync_mode_label" />
<ListPreference
android:key="folder_push_mode"
android:title="@string/account_settings_folder_push_mode_label"
android:entries="@array/account_settings_folder_push_mode_entries"
android:entryValues="@array/account_settings_folder_push_mode_values"
android:dialogTitle="@string/account_settings_folder_push_mode_label" />
<ListPreference
android:key="folder_target_mode"
android:title="@string/account_settings_folder_target_mode_label"

View File

@ -33,6 +33,13 @@
android:entryValues="@array/folder_settings_folder_sync_mode_values"
android:dialogTitle="@string/folder_settings_folder_sync_mode_label" />
<ListPreference
android:key="folder_settings_folder_push_mode"
android:title="@string/folder_settings_folder_push_mode_label"
android:entries="@array/folder_settings_folder_push_mode_entries"
android:entryValues="@array/folder_settings_folder_push_mode_values"
android:dialogTitle="@string/folder_settings_folder_push_mode_label" />
</PreferenceCategory>

View File

@ -49,6 +49,7 @@ public class Account implements Serializable {
String mAutoExpandFolderName;
FolderMode mFolderDisplayMode;
FolderMode mFolderSyncMode;
FolderMode mFolderPushMode;
FolderMode mFolderTargetMode;
int mAccountNumber;
boolean mVibrate;
@ -59,7 +60,7 @@ public class Account implements Serializable {
List<Identity> identities;
public enum FolderMode {
ALL, FIRST_CLASS, FIRST_AND_SECOND_CLASS, NOT_SECOND_CLASS;
NONE, ALL, FIRST_CLASS, FIRST_AND_SECOND_CLASS, NOT_SECOND_CLASS;
}
public enum HideButtons {
@ -87,6 +88,7 @@ public class Account implements Serializable {
mVibrate = false;
mFolderDisplayMode = FolderMode.NOT_SECOND_CLASS;
mFolderSyncMode = FolderMode.FIRST_CLASS;
mFolderPushMode = FolderMode.FIRST_CLASS;
mFolderTargetMode = FolderMode.NOT_SECOND_CLASS;
mHideMessageViewButtons = HideButtons.NEVER;
mRingtoneUri = "content://settings/system/notification_sound";
@ -238,6 +240,17 @@ public class Account implements Serializable {
mFolderSyncMode = FolderMode.FIRST_CLASS;
}
try
{
mFolderPushMode = FolderMode.valueOf(preferences.getPreferences().getString(mUuid + ".folderPushMode",
FolderMode.FIRST_CLASS.name()));
}
catch (Exception e)
{
mFolderPushMode = FolderMode.FIRST_CLASS;
}
try
{
mFolderTargetMode = FolderMode.valueOf(preferences.getPreferences().getString(mUuid + ".folderTargetMode",
@ -460,6 +473,7 @@ public class Account implements Serializable {
editor.remove(mUuid + ".lastFullSync");
editor.remove(mUuid + ".folderDisplayMode");
editor.remove(mUuid + ".folderSyncMode");
editor.remove(mUuid + ".folderPushMode");
editor.remove(mUuid + ".folderTargetMode");
editor.remove(mUuid + ".hideButtonsEnum");
editor.remove(mUuid + ".signatureBeforeQuotedText");
@ -523,6 +537,7 @@ public class Account implements Serializable {
editor.putString(mUuid + ".ringtone", mRingtoneUri);
editor.putString(mUuid + ".folderDisplayMode", mFolderDisplayMode.name());
editor.putString(mUuid + ".folderSyncMode", mFolderSyncMode.name());
editor.putString(mUuid + ".folderPushMode", mFolderPushMode.name());
editor.putString(mUuid + ".folderTargetMode", mFolderTargetMode.name());
editor.putBoolean(mUuid + ".signatureBeforeQuotedText", this.mIsSignatureBeforeQuotedText);
@ -573,6 +588,10 @@ public class Account implements Serializable {
folder.getName().equals(getSentFolderName()) == false &&
folder.getName().equals(getErrorFolderName()) == false)
{
if (aMode == Account.FolderMode.NONE)
{
continue;
}
if (aMode == Account.FolderMode.FIRST_CLASS &&
fMode != Folder.FolderClass.FIRST_CLASS)
{
@ -741,6 +760,16 @@ public class Account implements Serializable {
mFolderSyncMode = syncMode;
}
public FolderMode getFolderPushMode()
{
return mFolderPushMode;
}
public void setFolderPushMode(FolderMode syncMode)
{
mFolderPushMode = syncMode;
}
public boolean isShowOngoing()
{
return mNotifySync;

View File

@ -35,6 +35,7 @@ public class Email extends Application {
/**
* If this is enabled there will be additional logging information sent to
* Log.d, including protocol dumps.
* Controlled by Preferences at run-time
*/
public static boolean DEBUG = false;
@ -65,9 +66,7 @@ public class Email extends Application {
* The MIME type(s) of attachments we're willing to view.
*/
public static final String[] ACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] {
"image/*",
"audio/*",
"text/*",
"*/*",
};
/**
@ -135,6 +134,11 @@ public class Email extends Application {
public static final int MANUAL_WAKE_LOCK_TIMEOUT = 120000;
public static final int PUSH_WAKE_LOCK_TIMEOUT = 30000;
public static final int MAIL_SERVICE_WAKE_LOCK_TIMEOUT = 30000;
/**
* LED color used for the new email notitication
*/
@ -161,6 +165,7 @@ public class Email extends Application {
public static final int FETCHING_EMAIL_NOTIFICATION_ID = -4;
public static final int FETCHING_EMAIL_NOTIFICATION_MULTI_ACCOUNT_ID = -1;
public static final int FETCHING_EMAIL_NOTIFICATION_NO_ACCOUNT = -2;
public static final int CONNECTIVITY_ID = -3;
// Backup formats in case they can't be fetched from the system
public static final String BACKUP_DATE_FORMAT = "MM-dd-yyyy";
@ -272,6 +277,8 @@ public class Email extends Application {
}
}
});
MailService.appStarted(this);
}
}

View File

@ -0,0 +1,14 @@
package com.android.email;
public class EmailReceivedIntent {
public static final String ACTION_EMAIL_RECEIVED = "com.android.email.intent.action.EMAIL_RECEIVED";
public static final String EXTRA_ACCOUNT = "com.android.email.intent.extra.ACCOUNT";
public static final String EXTRA_FOLDER = "com.android.email.intent.extra.FOLDER";
public static final String EXTRA_SENT_DATE = "com.android.email.intent.extra.SENT_DATE";
public static final String EXTRA_FROM = "com.android.email.intent.extra.FROM";
public static final String EXTRA_TO = "com.android.email.intent.extra.TO";
public static final String EXTRA_CC = "com.android.email.intent.extra.CC";
public static final String EXTRA_BCC = "com.android.email.intent.extra.BCC";
public static final String EXTRA_SUBJECT = "com.android.email.intent.extra.SUBJECT";
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,8 @@
package com.android.email;
import java.util.List;
import android.content.Context;
import com.android.email.mail.Folder;
@ -23,10 +25,6 @@ public class MessagingListener {
{
}
public void accountReset(Account account) {
}
public void listFoldersStarted(Account account) {
}
@ -45,7 +43,7 @@ public class MessagingListener {
public void listLocalMessages(Account account, String folder, Message[] messages) {
}
public void listLocalMessagesAddMessage(Account account, String folder, Message message) {
public void listLocalMessagesAddMessages(Account account, String folder, List<Message> messages) {
}
public void listLocalMessagesUpdateMessage(Account account, String folder, Message message) {
@ -130,6 +128,11 @@ public class MessagingListener {
}
public void setPushActive(Account account, String folderName, boolean enabled)
{
}
public void loadAttachmentStarted(
Account account,
Message message,

View File

@ -265,6 +265,12 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
context.startActivity(intent);
}
public static void listAccounts(Context context) {
Intent intent = new Intent(context, Accounts.class);
intent.putExtra(EXTRA_STARTUP, false);
context.startActivity(intent);
}
@Override
public void onCreate(Bundle icicle) {
@ -332,10 +338,11 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
if (accounts.length > 0) {
mHandler.progress(Window.PROGRESS_START);
}
pendingWork.clear();
for (Account account : accounts) {
MessagingController.getInstance(getApplication()).getAccountUnreadCount(Accounts.this, account, mListener);
pendingWork.put(account, "true");
MessagingController.getInstance(getApplication()).getAccountUnreadCount(Accounts.this, account, mListener);
}
}

View File

@ -77,16 +77,10 @@ public class ChooseFolder extends K9ListActivity
setListAdapter(adapter);
new Thread()
{
public void run()
{
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
MessagingController.getInstance(getApplication()).listFolders(mAccount,
false, mListener);
}
}.start();
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView adapterview, View view, int i, long l)

View File

@ -16,7 +16,6 @@ import android.content.Intent;
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;
@ -42,22 +41,15 @@ import com.android.email.MessagingController;
import com.android.email.MessagingListener;
import com.android.email.Preferences;
import com.android.email.R;
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.Folder;
import com.android.email.mail.Message;
import com.android.email.mail.MessagingException;
import com.android.email.mail.Store;
import com.android.email.mail.store.LocalStore.LocalFolder;
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
@ -88,27 +80,14 @@ public class FolderList extends K9ListActivity {
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 boolean sortAscending = true;
private boolean sortDateAscending = false;
private boolean mStartup = 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(),
@ -145,17 +124,24 @@ public class FolderList extends K9ListActivity {
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;
private static final int MSG_NEW_FOLDERS = 22;
@Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_NEW_FOLDERS:
ArrayList<FolderInfoHolder> newFolders = (ArrayList<FolderInfoHolder>)msg.obj;
mAdapter.mFolders.clear();
mAdapter.mFolders.addAll(newFolders);
mHandler.dataChanged();
break;
case MSG_PROGRESS:
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
break;
@ -224,10 +210,10 @@ public class FolderList extends K9ListActivity {
}
}
public void synchronizeMessages(FolderInfoHolder folder, Message[] messages) {
public void newFolders(ArrayList<FolderInfoHolder> newFolders) {
android.os.Message msg = new android.os.Message();
msg.what = MSG_SYNC_MESSAGES;
msg.obj = new Object[] { folder, messages };
msg.obj = newFolders;
msg.what = MSG_NEW_FOLDERS;
sendMessage(msg);
}
@ -285,55 +271,32 @@ public class FolderList extends K9ListActivity {
* 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);
private void checkMail(FolderInfoHolder folder)
{
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email - UpdateWorker");
final 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;
MessagingListener listener = new MessagingListener()
{
public void synchronizeMailboxFinished(Account account, String folder, int totalMessagesInMailbox, int numNewMessages) {
if (!account.equals(mAccount)) {
return;
}
} 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();
}
@Override
public void synchronizeMailboxFailed(Account account, String folder,
String message) {
if (!account.equals(mAccount)) {
return;
}
wakeLock.release();
}
};
MessagingController.getInstance(getApplication()).synchronizeMailbox(mAccount, folder.name, listener);
sendMail(mAccount);
}
private static void actionHandleAccount(Context context, Account account, String initialFolder, boolean startup) {
@ -381,38 +344,39 @@ public class FolderList extends K9ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
String initialFolder;
super.onCreate(savedInstanceState);
String savedFolderName = null;
Intent intent = getIntent();
mAccount = (Account)intent.getSerializableExtra(EXTRA_ACCOUNT);
Log.v(Email.LOG_TAG, "savedInstanceState: " + (savedInstanceState==null));
if (savedInstanceState == null) {
mInitialFolder = intent.getStringExtra(EXTRA_INITIAL_FOLDER);
Log.v(Email.LOG_TAG, "EXTRA_INITIAL_FOLDER: " + mInitialFolder);
initialFolder = intent.getStringExtra(EXTRA_INITIAL_FOLDER);
Log.v(Email.LOG_TAG, "EXTRA_INITIAL_FOLDER: " + initialFolder);
mStartup = (boolean) intent.getBooleanExtra(EXTRA_STARTUP, false);
Log.v(Email.LOG_TAG, "startup: " + mStartup);
if (mInitialFolder == null
if (initialFolder == null
&& mStartup) {
mInitialFolder = mAccount.getAutoExpandFolderName();
initialFolder = mAccount.getAutoExpandFolderName();
}
}
else {
mInitialFolder = null;
initialFolder = null;
mStartup = false;
savedFolderName = savedInstanceState.getString(STATE_CURRENT_FOLDER);
}
Log.v(Email.LOG_TAG, "mInitialFolder: " + mInitialFolder);
if (mInitialFolder != null
&& !Email.FOLDER_NONE.equals(mInitialFolder)) {
onOpenFolder(mInitialFolder, true);
Log.v(Email.LOG_TAG, "mInitialFolder: " + initialFolder);
if (initialFolder != null
&& !Email.FOLDER_NONE.equals(initialFolder)) {
onOpenFolder(initialFolder, true);
finish();
}
else {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
final FolderList xxx = this;
mListView = getListView();
mListView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);
mListView.setLongClickable(true);
@ -421,7 +385,7 @@ public class FolderList extends K9ListActivity {
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, false);
MessageList.actionHandleFolder(FolderList.this, mAccount, ((FolderInfoHolder)mAdapter.getItem(id)).name, false);
}
});
registerForContextMenu(mListView);
@ -445,12 +409,6 @@ public class FolderList extends K9ListActivity {
setListAdapter(mAdapter);
if (savedInstanceState != null) {
mRestoringState = true;
//onRestoreListState(savedInstanceState);
mRestoringState = false;
}
setTitle(mAccount.getDescription());
if (savedFolderName != null)
@ -480,7 +438,6 @@ public class FolderList extends K9ListActivity {
MessagingController.getInstance(getApplication()).addListener(mAdapter.mListener);
mAccount.refresh(Preferences.getPreferences(this));
markAllRefresh();
onRefresh( !REFRESH_REMOTE );
@ -503,7 +460,9 @@ public class FolderList extends K9ListActivity {
//Shortcuts that work no matter what is selected
switch (keyCode) {
case KeyEvent.KEYCODE_Q: {
case KeyEvent.KEYCODE_Q:
//case KeyEvent.KEYCODE_BACK:
{
onAccounts();
return true;
}
@ -525,22 +484,9 @@ public class FolderList extends K9ListActivity {
}//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() {
@ -552,19 +498,12 @@ public class FolderList extends K9ListActivity {
}
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 (mStartup
|| isTaskRoot()) {
Intent intent = new Intent(this, Accounts.class);
intent.putExtra(Accounts.EXTRA_STARTUP, false);
startActivity(intent);
}
finish();
if (mStartup || isTaskRoot())
{
Accounts.listAccounts(this);
}
private void markAllRefresh() {
mAdapter.mListener.accountReset(mAccount);
finish();
}
private void onEmptyTrash(final Account account) {
@ -584,6 +523,10 @@ public class FolderList extends K9ListActivity {
MessagingController.getInstance(getApplication()).checkMail(this, account, true, true, mAdapter.mListener);
}
private void sendMail(Account account) {
MessagingController.getInstance(getApplication()).sendPendingMessages(account, mAdapter.mListener);
}
@Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.compose:
@ -596,6 +539,11 @@ public class FolderList extends K9ListActivity {
return true;
case R.id.send_messages:
Log.i(Email.LOG_TAG, "sending pending messages");
MessagingController.getInstance(getApplication()).sendPendingMessages(mAccount, null);
return true;
case R.id.accounts:
onAccounts();
@ -666,15 +614,13 @@ public class FolderList extends K9ListActivity {
case R.id.send_messages:
Log.i(Email.LOG_TAG, "sending pending messages from " + folder.name);
MessagingController.getInstance(getApplication()).sendPendingMessages(mAccount, null);
sendMail(mAccount);
break;
case R.id.check_mail:
Log.i(Email.LOG_TAG, "refresh folder " + folder.name);
threadPool.execute(new FolderUpdateWorker(folder, true));
checkMail(folder);
break;
@ -741,10 +687,6 @@ public class FolderList extends K9ListActivity {
MessagingController.getInstance(getApplication()).markAllMessagesRead(mAccount, mSelectedContextFolder.name);
for (MessageInfoHolder holder : mSelectedContextFolder.messages) {
holder.read = true;
}
mSelectedContextFolder.unreadMessageCount = 0;
mHandler.dataChanged();
@ -854,7 +796,7 @@ public class FolderList extends K9ListActivity {
}
mHandler.progress(false);
MessagingController.getInstance(getApplication()).refreshListener(mAdapter.mListener);
mHandler.dataChanged();
}
@ -902,24 +844,9 @@ public class FolderList extends K9ListActivity {
newFolders.add(holder);
}
mFolders.clear();
Collections.sort(newFolders);
mHandler.newFolders(newFolders);
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) {
@ -930,6 +857,7 @@ public class FolderList extends K9ListActivity {
mHandler.progress(true);
mHandler.folderLoading(folder, true);
mHandler.folderSyncing(folder);
mHandler.dataChanged();
}
@Override
@ -937,23 +865,37 @@ public class FolderList extends K9ListActivity {
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 );
refreshFolder(account, folder);
}
private void refreshFolder(Account account, String folderName)
{
// There has to be a cheaper way to get at the localFolder object than this
try {
if (account != null && folderName != null)
{
Folder localFolder = (Folder) Store.getInstance(account.getLocalStoreUri(), getApplication()).getFolder(folderName);
if (localFolder != null)
{
FolderInfoHolder folderHolder = getFolder(folderName);
if (folderHolder != null)
{
folderHolder.populate(localFolder);
mHandler.dataChanged();
}
}
}
}
catch (Exception e) {
Log.e(Email.LOG_TAG, "Exception while populating folder", e);
}
}
@Override
@ -978,6 +920,23 @@ public class FolderList extends K9ListActivity {
}
mHandler.folderSyncing(null);
mHandler.dataChanged();
}
@Override
public void setPushActive(Account account, String folderName, boolean enabled)
{
if (!account.equals(mAccount)) {
return;
}
FolderInfoHolder holder = getFolder(folderName);
if (holder != null) {
holder.pushActive = enabled;
mHandler.dataChanged();
}
}
@ -993,8 +952,7 @@ public class FolderList extends K9ListActivity {
if (!account.equals(mAccount)) {
return;
}
onRefresh( ! REFRESH_REMOTE);
refreshFolder(account, mAccount.getTrashFolderName());
}
@Override
@ -1002,8 +960,7 @@ public class FolderList extends K9ListActivity {
if (!account.equals(mAccount)) {
return;
}
onRefresh( !REFRESH_REMOTE);
refreshFolder(account, folderName);
}
@Override
@ -1013,8 +970,7 @@ public class FolderList extends K9ListActivity {
}
mHandler.sendingOutbox(false);
onRefresh( !REFRESH_REMOTE);
refreshFolder(account, mAccount.getOutboxFolderName());
}
@Override
@ -1024,6 +980,8 @@ public class FolderList extends K9ListActivity {
}
mHandler.sendingOutbox(true);
mHandler.dataChanged();
}
@Override
@ -1033,6 +991,7 @@ public class FolderList extends K9ListActivity {
}
mHandler.sendingOutbox(false);
refreshFolder(account, mAccount.getOutboxFolderName());
}
public void accountSizeChanged(Account account, long oldSize, long newSize) {
@ -1116,6 +1075,11 @@ public class FolderList extends K9ListActivity {
.format(lastCheckedDate));
}
if (folder.pushActive)
{
statusText = getString(R.string.folder_push_active_symbol) + statusText;
}
if (statusText != null) {
holder.folderStatus.setText(statusText);
holder.folderStatus.setVisibility(View.VISIBLE);
@ -1150,8 +1114,6 @@ public class FolderList extends K9ListActivity {
public String displayName;
public ArrayList<MessageInfoHolder> messages;
public long lastChecked;
public int unreadMessageCount;
@ -1160,9 +1122,9 @@ public class FolderList extends K9ListActivity {
public String status;
public boolean lastCheckFailed;
public boolean pushActive;
public boolean needsRefresh = false;
public boolean lastCheckFailed;
/**
* Outbox is handled differently from any other folder.
@ -1242,11 +1204,7 @@ public class FolderList extends K9ListActivity {
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();
this.lastChecked = folder.getLastUpdate();
String mess = truncateStatus(folder.getStatus());

View File

@ -59,11 +59,6 @@ import com.android.email.mail.store.LocalStore;
import com.android.email.mail.store.LocalStore.LocalFolder;
import com.android.email.mail.store.LocalStore.LocalMessage;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* MessageList is the primary user interface for the program. This
@ -82,21 +77,15 @@ import java.util.concurrent.TimeUnit;
public class MessageList extends K9ListActivity {
private static final String INTENT_DATA_PATH_SUFFIX = "/accounts";
private static final int DIALOG_MARK_ALL_AS_READ = 1;
private static final int ACTIVITY_CHOOSE_FOLDER_MOVE = 1;
private static final int ACTIVITY_CHOOSE_FOLDER_COPY = 2;
private static final boolean FORCE_REMOTE_SYNC = true;
private static final String EXTRA_ACCOUNT = "account";
private static final String EXTRA_STARTUP = "startup";
private static final String EXTRA_CLEAR_NOTIFICATION = "clearNotification";
private static final String EXTRA_FOLDER = "folder";
private static final String STATE_KEY_LIST = "com.android.email.activity.messagelist_state";
@ -146,11 +135,6 @@ public class MessageList extends K9ListActivity {
*/
private String mFolderName;
private boolean mRestoringState;
private boolean mRefreshRemote;
private MessageListHandler mHandler = new MessageListHandler();
private DateFormat dateFormat = null;
@ -165,8 +149,6 @@ public class MessageList extends K9ListActivity {
private boolean mStartup = 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(),
@ -232,15 +214,19 @@ public class MessageList extends K9ListActivity {
break;
case MSG_REMOVE_MESSAGE: {
MessageInfoHolder message = (MessageInfoHolder)((Object[]) msg.obj)[1];
List<MessageInfoHolder> messages = (List<MessageInfoHolder>)((Object[]) msg.obj)[0];
for (MessageInfoHolder message : messages)
{
mAdapter.messages.remove(message);
}
mAdapter.notifyDataSetChanged();
break;
}
case MSG_ADD_MESSAGE: {
MessageInfoHolder message = (MessageInfoHolder)((Object[]) msg.obj)[1];
List<MessageInfoHolder> messages = (List<MessageInfoHolder>)((Object[]) msg.obj)[0];
for (MessageInfoHolder message : messages)
{
int index = Collections.binarySearch( mAdapter.messages, message);
if (index < 0)
@ -249,6 +235,7 @@ public class MessageList extends K9ListActivity {
}
mAdapter.messages.add(index, message);
}
mAdapter.notifyDataSetChanged();
break;
}
@ -270,7 +257,7 @@ public class MessageList extends K9ListActivity {
case MSG_FOLDER_LOADING:
{
FolderInfoHolder folder = mAdapter.getFolder((String) msg.obj);
FolderInfoHolder folder = mCurrentFolder;
if (folder != null)
{
folder.loading = msg.arg1 != 0;
@ -297,17 +284,17 @@ public class MessageList extends K9ListActivity {
}
}
public void removeMessage(MessageInfoHolder message) {
public void removeMessage(List<MessageInfoHolder> messages) {
android.os.Message msg = new android.os.Message();
msg.what = MSG_REMOVE_MESSAGE;
msg.obj = new Object[] { message.folder, message };
msg.obj = new Object[] { messages };
sendMessage(msg);
}
public void addMessage(MessageInfoHolder message) {
public void addMessages(List<MessageInfoHolder> messages) {
android.os.Message msg = new android.os.Message();
msg.what = MSG_ADD_MESSAGE;
msg.obj = new Object[] { message.folder, message };
msg.obj = new Object[] { messages };
sendMessage(msg);
}
@ -414,7 +401,6 @@ public class MessageList extends K9ListActivity {
mFolderName,
mAdapter.mListener);
onRefresh(FORCE_REMOTE_SYNC);
return;
} else {
MessageInfoHolder message = (MessageInfoHolder) mAdapter.getItem( itemPosition);
@ -433,14 +419,19 @@ public class MessageList extends K9ListActivity {
mAdapter = new MessageListAdapter();
final Object previousData = getLastNonConfigurationInstance();
if (previousData != null) {
//noinspection unchecked
mAdapter.messages.addAll((List<MessageInfoHolder>) previousData);
}
mCurrentFolder = mAdapter.getFolder(mFolderName);
setListAdapter(mAdapter);
if (savedInstanceState != null) {
mRestoringState = true;
onRestoreListState(savedInstanceState);
mRestoringState = false;
}
setTitle(
@ -488,7 +479,7 @@ public class MessageList extends K9ListActivity {
MessagingController.getInstance(getApplication()).addListener( mAdapter.mListener);
onRefresh(!FORCE_REMOTE_SYNC);
MessagingController.getInstance(getApplication()).listLocalMessages(mAccount, mFolderName, mAdapter.mListener);
NotificationManager notifMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notifMgr.cancel(mAccount.getAccountNumber());
@ -505,8 +496,9 @@ public class MessageList extends K9ListActivity {
}
@Override public Object onRetainNonConfigurationInstance() {
return mAdapter.messages;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
@ -515,7 +507,9 @@ public class MessageList extends K9ListActivity {
switch (keyCode) {
case KeyEvent.KEYCODE_C: { onCompose(); return true;}
case KeyEvent.KEYCODE_Q: { onShowFolderList(); return true; }
case KeyEvent.KEYCODE_Q:
//case KeyEvent.KEYCODE_BACK:
{ onShowFolderList(); return true; }
case KeyEvent.KEYCODE_O: { onCycleSort(); return true; }
@ -563,28 +557,20 @@ public class MessageList extends K9ListActivity {
private void onRefresh(final boolean forceRemote) {
if (forceRemote) {
mRefreshRemote = true;
}
new Thread() {
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
if (forceRemote) {
MessagingController.getInstance(getApplication()).synchronizeMailbox(mAccount, mFolderName, mAdapter.mListener);
MessagingController.getInstance(getApplication()).sendPendingMessages(mAccount, null);
}
MessagingController.getInstance(getApplication()).listLocalMessages(mAccount, mFolderName, mAdapter.mListener);
}
}
.start();
}
private void onOpenMessage( MessageInfoHolder message) {
if (message.folder.name.equals(mAccount.getDraftsFolderName())) {
MessageCompose.actionEditDraft(this, mAccount, message.message);
} else {
// Need to get the list before the sort starts
ArrayList<String> folderUids = new ArrayList<String>();
for (MessageInfoHolder holder : mAdapter.messages) {
folderUids.add(holder.uid);
}
MessageView.actionView(this, mAccount, message.folder.name, message.uid, folderUids);
}
/*
* We set read=true here for UI performance reasons. The actual value will
* get picked up on the refresh when the Activity is resumed but that may
@ -598,26 +584,14 @@ public class MessageList extends K9ListActivity {
mHandler.sortMessages();
}
if (message.folder.name.equals(mAccount.getDraftsFolderName())) {
MessageCompose.actionEditDraft(this, mAccount, message.message);
} else {
ArrayList<String> folderUids = new ArrayList<String>();
for (MessageInfoHolder holder : mAdapter.messages) {
folderUids.add(holder.uid);
}
MessageView.actionView(this, mAccount, message.folder.name, message.uid, folderUids);
}
}
private void onShowFolderList() {
// 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 (mStartup
|| isTaskRoot()) {
if (mStartup || isTaskRoot())
{
FolderList.actionHandleAccount(this, mAccount, false);
}
finish();
}
@ -643,6 +617,11 @@ public class MessageList extends K9ListActivity {
}
private void onAccounts() {
Accounts.listAccounts(this);
finish();
}
private void onCycleSort() {
SORT_TYPE[] sorts = SORT_TYPE.values();
int curIndex = 0;
@ -677,11 +656,11 @@ public class MessageList extends K9ListActivity {
holder.folder.unreadMessageCount--;
}
FolderInfoHolder trashHolder = mAdapter.getFolder(mAccount.getTrashFolderName());
if (trashHolder != null) {
trashHolder.needsRefresh = true;
}
// FolderInfoHolder trashHolder = mAdapter.getFolder(mAccount.getTrashFolderName());
//
// if (trashHolder != null) {
// trashHolder.needsRefresh = true;
// }
mAdapter.removeMessage(holder);
mListView.setSelection(position);
@ -741,26 +720,22 @@ public class MessageList extends K9ListActivity {
String destFolderName = data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER);
String srcFolderName = data.getStringExtra(ChooseFolder.EXTRA_CUR_FOLDER);
String uid = data.getStringExtra(ChooseFolder.EXTRA_MESSAGE_UID);
FolderInfoHolder srcHolder = mAdapter.getFolder(srcFolderName);
FolderInfoHolder srcHolder = mCurrentFolder;
FolderInfoHolder destHolder = mAdapter.getFolder(destFolderName);
if (srcHolder != null && destHolder != null) {
if (srcHolder != null && destFolderName != null) {
MessageInfoHolder m = mAdapter.getMessage( uid);
if (m != null) {
switch (requestCode) {
case ACTIVITY_CHOOSE_FOLDER_MOVE:
onMoveChosen(m, destHolder);
onMoveChosen(m, destFolderName);
break;
case ACTIVITY_CHOOSE_FOLDER_COPY:
onCopyChosen(m, destHolder);
onCopyChosen(m, destFolderName);
break;
}
@ -770,15 +745,12 @@ public class MessageList extends K9ListActivity {
}
private void onMoveChosen(MessageInfoHolder holder, FolderInfoHolder folder) {
private void onMoveChosen(MessageInfoHolder holder, String folderName) {
if (MessagingController.getInstance(getApplication()).isMoveCapable(mAccount) == false) {
return;
}
// String destFolderName = folder.name;
// FolderInfoHolder destHolder = mAdapter.getFolder(destFolderName);
//
if (folder == null) {
if (folderName == null) {
return;
}
@ -786,35 +758,23 @@ public class MessageList extends K9ListActivity {
if (holder.folder.unreadMessageCount > 0) {
holder.folder.unreadMessageCount--;
}
folder.unreadMessageCount++;
}
folder.needsRefresh = true;
mAdapter.removeMessage(holder);
MessagingController.getInstance(getApplication()).moveMessage(mAccount, holder.message.getFolder().getName(), holder.message, folder.name, null);
MessagingController.getInstance(getApplication()).moveMessage(mAccount, holder.message.getFolder().getName(), holder.message, folderName, null);
}
private void onCopyChosen(MessageInfoHolder holder, FolderInfoHolder folder) {
private void onCopyChosen(MessageInfoHolder holder, String folderName) {
if (MessagingController.getInstance(getApplication()).isCopyCapable(mAccount) == false) {
return;
}
if (folder == null) {
if (folderName == null) {
return;
}
if (holder.read == false) {
folder.unreadMessageCount++;
}
folder.needsRefresh = true;
MessagingController.getInstance(getApplication()).copyMessage(mAccount,
holder.message.getFolder().getName(), holder.message, folder.name, null);
holder.message.getFolder().getName(), holder.message, folderName, null);
}
@ -831,7 +791,6 @@ public class MessageList extends K9ListActivity {
}
private void onMarkAllAsRead(final Account account, final String folder) {
showDialog(DIALOG_MARK_ALL_AS_READ);
}
@ -916,12 +875,13 @@ public class MessageList extends K9ListActivity {
mHandler.sortMessages();
}
// 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);
sendMail(account);
}
private void sendMail(Account account) {
MessagingController.getInstance(getApplication()).sendPendingMessages(account, mAdapter.mListener);
}
@Override
@ -930,12 +890,20 @@ public class MessageList extends K9ListActivity {
case R.id.check_mail:
checkMail(mAccount, mFolderName);
return true;
case R.id.send_messages:
sendMail(mAccount);
return true;
case R.id.compose:
onCompose();
return true;
case R.id.accounts:
onAccounts();
return true;
case R.id.set_sort_date:
changeSort(SORT_TYPE.SORT_DATE);
@ -995,6 +963,13 @@ public class MessageList extends K9ListActivity {
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.message_list_option, menu);
if (mCurrentFolder.outbox) {
menu.findItem(R.id.check_mail).setVisible(false);
} else {
menu.findItem(R.id.send_messages).setVisible(false);
}
return true;
}
@ -1205,6 +1180,7 @@ public class MessageList extends K9ListActivity {
}
mHandler.sortMessages();
mHandler.progress(false);
mHandler.folderLoading(folder, false);
}
@ -1234,12 +1210,12 @@ public class MessageList extends K9ListActivity {
@Override
public void listLocalMessagesAddMessage(Account account, String folder, Message message) {
public void listLocalMessagesAddMessages(Account account, String folder, List<Message> messages) {
if (!account.equals(mAccount) || !folder.equals(mFolderName)) {
return;
}
addOrUpdateMessage(folder, message);
addOrUpdateMessages(folder, messages);
}
@ -1263,40 +1239,23 @@ public class MessageList extends K9ListActivity {
mAnsweredIcon = getResources().getDrawable( R.drawable.ic_mms_answered_small);
}
public void removeMessages(List<MessageInfoHolder> holders) {
if (holders == null) {
return;
}
mHandler.removeMessage(holders);
}
public void removeMessage(MessageInfoHolder holder) {
if (holder == null) {
return;
}
if (holder.folder == null) {
return;
}
mHandler.removeMessage(holder);
}
private void addOrUpdateMessage(FolderInfoHolder folder, Message message) {
MessageInfoHolder m = getMessage( message.getUid());
if (m == null) {
m = new MessageInfoHolder(message, folder);
mHandler.addMessage(m);
} else {
if (message.isSet(Flag.DELETED)) {
removeMessage(m);
} else {
m.populate(message, folder);
mHandler.sortMessages();
}
}
List<MessageInfoHolder> messages = new ArrayList<MessageInfoHolder>();
messages.add(holder);
removeMessages(messages);
}
private void addOrUpdateMessage(String folder, Message message) {
FolderInfoHolder f = getFolder(folder);
FolderInfoHolder f = mCurrentFolder;
if (f == null) {
return;
@ -1305,6 +1264,60 @@ public class MessageList extends K9ListActivity {
addOrUpdateMessage(f, message);
}
private void addOrUpdateMessage(FolderInfoHolder folder, Message message) {
List<Message> messages = new ArrayList<Message>();
messages.add(message);
addOrUpdateMessages(folder, messages);
}
private void addOrUpdateMessages(String folder, List<Message> messages) {
FolderInfoHolder f = mCurrentFolder;
if (f == null) {
return;
}
addOrUpdateMessages(f, messages);
}
private void addOrUpdateMessages(FolderInfoHolder folder, List<Message> messages) {
boolean needsSort = false;
List<MessageInfoHolder> messagesToAdd = new ArrayList<MessageInfoHolder>();
List<MessageInfoHolder> messagesToRemove = new ArrayList<MessageInfoHolder>();
for (Message message : messages)
{
MessageInfoHolder m = getMessage( message.getUid());
if (m == null)
{
m = new MessageInfoHolder(message, folder);
messagesToAdd.add(m);
} else {
if (message.isSet(Flag.DELETED)) {
messagesToRemove.add(m);
} else {
m.populate(message, folder);
needsSort = true;
}
}
}
if (messagesToRemove.size() > 0)
{
removeMessages(messagesToRemove);
}
if (messagesToAdd.size() > 0)
{
mHandler.addMessages(messagesToAdd);
}
if (needsSort)
{
mHandler.sortMessages();
}
}
// XXX TODO - make this not use a for loop
public MessageInfoHolder getMessage( String messageUid) {
MessageInfoHolder searchHolder = new MessageInfoHolder();
@ -1444,20 +1457,23 @@ public class MessageList extends K9ListActivity {
footerView.setId(R.layout.message_list_item_footer);
FooterViewHolder holder = new FooterViewHolder();
holder.progress = (ProgressBar)footerView.findViewById(R.id.message_list_progress);
holder.progress.setIndeterminate(true);
holder.main = (TextView)footerView.findViewById(R.id.main_text);
footerView.setTag(holder);
}
FooterViewHolder holder = (FooterViewHolder)footerView.getTag();
if (mCurrentFolder.loading) {
holder.main.setText(getString(R.string.status_loading_more));
mHandler.progress(true);
holder.progress.setVisibility(ProgressBar.VISIBLE);
} else {
if (mCurrentFolder.lastCheckFailed == false) {
holder.main.setText(String.format(getString(R.string.load_more_messages_fmt).toString(), mAccount.getDisplayCount()));
} else {
holder.main.setText(getString(R.string.status_loading_more_failed));
}
holder.progress.setVisibility(ProgressBar.INVISIBLE);
}
return footerView;

View File

@ -114,10 +114,6 @@ public class MessageView extends K9Activity
private Menu optionsMenu = null;
//Shall we use more threads? How often will the user move from non-fully-downloaded
//messages to another non-fully-downloaded message more than 3 times?
// private final ExecutorService threadPool = Executors.newFixedThreadPool(3);
private DateFormat getDateFormat()
{
if (dateFormat == null)
@ -154,6 +150,22 @@ public class MessageView extends K9Activity
private Listener mListener = new Listener();
private MessageViewHandler mHandler = new MessageViewHandler();
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
boolean ret = false;
if (KeyEvent.ACTION_DOWN == event.getAction())
{
ret = onKeyDown(event.getKeyCode(), event);
}
if (ret == false)
{
ret = super.dispatchKeyEvent(event);
}
return ret;
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DEL: { onDelete(); return true;}
@ -509,7 +521,7 @@ public class MessageView extends K9Activity
Account.HideButtons hideButtons = mAccount.getHideMessageViewButtons();
//MessagingController.getInstance(getApplication()).addListener(mListener);
// MessagingController.getInstance(getApplication()).addListener(mListener);
if (Account.HideButtons.ALWAYS == hideButtons)
{
hideButtons();
@ -521,7 +533,7 @@ public class MessageView extends K9Activity
else // Account.HideButtons.KEYBOARD_AVAIL
{
final Configuration config = this.getResources().getConfiguration();
if (config.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO )
if (config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO )
{
hideButtons();
}
@ -1357,7 +1369,7 @@ public class MessageView extends K9Activity
}
catch (Exception e)
{
Toast toast = Toast.makeText(MessageView.this, e.getMessage(), Toast.LENGTH_LONG);
Toast toast = Toast.makeText(MessageView.this, getString(R.string.message_view_no_viewer, attachment.contentType), Toast.LENGTH_LONG);
toast.show();
}
}

View File

@ -5,6 +5,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
@ -25,6 +26,7 @@ import com.android.email.R;
import com.android.email.activity.ChooseFolder;
import com.android.email.activity.ChooseIdentity;
import com.android.email.activity.ManageIdentities;
import com.android.email.mail.Store;
public class AccountSettings extends K9PreferenceActivity {
private static final String EXTRA_ACCOUNT = "account";
@ -49,6 +51,7 @@ public class AccountSettings extends K9PreferenceActivity {
private static final String PREFERENCE_OUTGOING = "outgoing";
private static final String PREFERENCE_DISPLAY_MODE = "folder_display_mode";
private static final String PREFERENCE_SYNC_MODE = "folder_sync_mode";
private static final String PREFERENCE_PUSH_MODE = "folder_push_mode";
private static final String PREFERENCE_TARGET_MODE = "folder_target_mode";
private static final String PREFERENCE_DELETE_POLICY = "delete_policy";
private static final String PREFERENCE_AUTO_EXPAND_FOLDER = "account_setup_auto_expand_folder";
@ -66,6 +69,7 @@ public class AccountSettings extends K9PreferenceActivity {
private RingtonePreference mAccountRingtone;
private ListPreference mDisplayMode;
private ListPreference mSyncMode;
private ListPreference mPushMode;
private ListPreference mTargetMode;
private ListPreference mDeletePolicy;
private Preference mAutoExpandFolder;
@ -82,6 +86,18 @@ public class AccountSettings extends K9PreferenceActivity {
mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
boolean isPushCapable = false;
Store store = null;
try
{
store = Store.getInstance(mAccount.getStoreUri(), getApplication());
isPushCapable = store.isPushCapable();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Could not get remote store", e);
}
addPreferencesFromResource(R.xml.account_settings_preferences);
Preference category = findPreference(PREFERENCE_TOP_CATERGORY);
@ -139,6 +155,20 @@ public class AccountSettings extends K9PreferenceActivity {
}
});
mPushMode = (ListPreference) findPreference(PREFERENCE_PUSH_MODE);
mPushMode.setEnabled(isPushCapable);
mPushMode.setValue(mAccount.getFolderPushMode().name());
mPushMode.setSummary(mPushMode.getEntry());
mPushMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
final String summary = newValue.toString();
int index = mPushMode.findIndexOfValue(summary);
mPushMode.setSummary(mPushMode.getEntries()[index]);
mPushMode.setValue(summary);
return false;
}
});
mTargetMode = (ListPreference) findPreference(PREFERENCE_TARGET_MODE);
mTargetMode.setValue(mAccount.getFolderTargetMode().name());
mTargetMode.setSummary(mTargetMode.getEntry());
@ -274,6 +304,7 @@ public class AccountSettings extends K9PreferenceActivity {
mAccount.setVibrate(mAccountVibrate.isChecked());
mAccount.setFolderDisplayMode(Account.FolderMode.valueOf(mDisplayMode.getValue()));
mAccount.setFolderSyncMode(Account.FolderMode.valueOf(mSyncMode.getValue()));
mAccount.setFolderPushMode(Account.FolderMode.valueOf(mPushMode.getValue()));
mAccount.setFolderTargetMode(Account.FolderMode.valueOf(mTargetMode.getValue()));
mAccount.setDeletePolicy(Integer.parseInt(mDeletePolicy.getValue()));
SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences();

View File

@ -104,16 +104,9 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
setMessage(R.string.account_setup_check_settings_check_incoming_msg);
store = Store.getInstance(mAccount.getStoreUri(), getApplication());
store.checkSettings();
new Thread() {
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
MessagingController.getInstance(getApplication()).listFolders(mAccount, true, null);
MessagingController.getInstance(getApplication()).synchronizeMailbox(mAccount, Email.INBOX , null);
}
}.start();
MessagingController.getInstance(getApplication()).synchronizeMailbox( mAccount, Email.INBOX , null);
}
if (mDestroyed) {

View File

@ -32,11 +32,13 @@ public class FolderSettings extends K9PreferenceActivity {
private static final String PREFERENCE_TOP_CATERGORY = "folder_settings";
private static final String PREFERENCE_DISPLAY_CLASS = "folder_settings_folder_display_mode";
private static final String PREFERENCE_SYNC_CLASS = "folder_settings_folder_sync_mode";
private static final String PREFERENCE_PUSH_CLASS = "folder_settings_folder_push_mode";
private LocalFolder mFolder;
private ListPreference mDisplayClass;
private ListPreference mSyncClass;
private ListPreference mPushClass;
public static void actionSettings(Context context, Account account, String folderName) {
Intent i = new Intent(context, FolderSettings.class);
@ -65,6 +67,18 @@ public class FolderSettings extends K9PreferenceActivity {
return;
}
boolean isPushCapable = false;
Store store = null;
try
{
store = Store.getInstance(mAccount.getStoreUri(), getApplication());
isPushCapable = store.isPushCapable();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Could not get remote store", e);
}
addPreferencesFromResource(R.xml.folder_settings_preferences);
Preference category = findPreference(PREFERENCE_TOP_CATERGORY);
@ -95,6 +109,20 @@ public class FolderSettings extends K9PreferenceActivity {
return false;
}
});
mPushClass = (ListPreference) findPreference(PREFERENCE_PUSH_CLASS);
mPushClass.setEnabled(isPushCapable);
mPushClass.setValue(mFolder.getRawPushClass().name());
mPushClass.setSummary(mPushClass.getEntry());
mPushClass.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
final String summary = newValue.toString();
int index = mPushClass.findIndexOfValue(summary);
mPushClass.setSummary(mPushClass.getEntries()[index]);
mPushClass.setValue(summary);
return false;
}
});
}
@Override
@ -113,10 +141,12 @@ public class FolderSettings extends K9PreferenceActivity {
private void saveSettings() {
mFolder.setDisplayClass(FolderClass.valueOf(mDisplayClass.getValue()));
mFolder.setSyncClass(FolderClass.valueOf(mSyncClass.getValue()));
mFolder.setPushClass(FolderClass.valueOf(mPushClass.getValue()));
try
{
mFolder.save(Preferences.getPreferences(this));
Email.setServicesEnabled(this);
}
catch (MessagingException me)
{

View File

@ -6,12 +6,13 @@ import com.android.email.Preferences;
public abstract class Folder {
private String status = null;
private long lastChecked = 0;
private long lastPush = 0;
public enum OpenMode {
READ_WRITE, READ_ONLY,
}
// NONE is obsolete, it will be translated to NO_CLASS for display and to INHERITED for sync and push
public enum FolderClass {
NONE, FIRST_CLASS, SECOND_CLASS;
NONE, NO_CLASS, INHERITED, FIRST_CLASS, SECOND_CLASS;
}
public enum FolderType {
@ -110,6 +111,17 @@ public abstract class Folder {
public abstract Flag[] getPermanentFlags() throws MessagingException;
/**
*
* @param oldPushState
* @param message
* @return empty string to clear the pushState, null to leave the state as-is
*/
public String getNewPushState(String oldPushState, Message message)
{
return null;
}
public boolean supportsFetchingFlags() {
return true;
}//isFlagSupported
@ -129,15 +141,34 @@ public abstract class Folder {
this.lastChecked = lastChecked;
}
public long getLastPush()
{
return lastPush;
}
public void setLastPush(long lastCheckedDisplay) throws MessagingException
{
this.lastPush = lastCheckedDisplay;
}
public long getLastUpdate()
{
return Math.max(getLastChecked(), getLastPush());
}
public FolderClass getDisplayClass()
{
return FolderClass.NONE;
return FolderClass.NO_CLASS;
}
public FolderClass getSyncClass()
{
return getDisplayClass();
}
public FolderClass getPushClass()
{
return getSyncClass();
}
public void refresh(Preferences preferences) throws MessagingException
{
@ -155,5 +186,4 @@ public abstract class Folder {
}
}

View File

@ -5,4 +5,6 @@ public interface MessageRetrievalListener {
public void messageStarted(String uid, int number, int ofTotal);
public void messageFinished(Message message, int number, int ofTotal);
public void messagesFinished(int total);
}

View File

@ -10,10 +10,20 @@ public class MessagingException extends Exception {
super(message);
}
public MessagingException(String message, boolean perm) {
super(message);
permanentFailure = perm;
}
public MessagingException(String message, Throwable throwable) {
super(message, throwable);
}
public MessagingException(String message, boolean perm, Throwable throwable) {
super(message, throwable);
permanentFailure = perm;
}
public boolean isPermanentFailure()
{
return permanentFailure;

View File

@ -0,0 +1,14 @@
package com.android.email.mail;
import java.util.List;
public interface PushReceiver
{
public void pushInProgress();
public void pushComplete();
public void messagesArrived(String folderName, List<Message> mess);
public void messagesFlagsChanged(String folderName, List<Message> mess);
public String getPushState(String folderName);
public void pushError(String errorMessage, Exception e);
public void setPushActive(String folderName, boolean enabled);
}

View File

@ -0,0 +1,14 @@
package com.android.email.mail;
public interface Pusher
{
public void start();
public void refresh();
public void stop();
/**
*
* @return milliseconds of required refresh interval
*/
public int getRefreshInterval();
}

View File

@ -2,6 +2,7 @@
package com.android.email.mail;
import java.util.HashMap;
import java.util.List;
import android.app.Application;
@ -85,5 +86,13 @@ public abstract class Store {
public boolean isMoveCapable() {
return false;
}
public boolean isPushCapable() {
return false;
}
public Pusher getPusher(PushReceiver receiver, List<String> names)
{
return null;
}
}

View File

@ -91,7 +91,7 @@ public class ImapResponseParser {
public Object readToken() throws IOException {
while (true) {
Object token = parseToken();
if (token == null || !token.equals(")")) {
if (token == null || !token.equals(")") || !token.equals("]")) {
return token;
}
}
@ -107,9 +107,14 @@ public class ImapResponseParser {
int ch = mIn.peek();
if (ch == '(') {
return parseList();
} else if (ch == '[') {
return parseSequence();
} else if (ch == ')') {
expect(')');
return ")";
} else if (ch == ']') {
expect(']');
return "]";
} else if (ch == '"') {
return parseQuoted();
} else if (ch == '{') {
@ -170,6 +175,26 @@ public class ImapResponseParser {
return list;
}
private ImapList parseSequence() throws IOException {
expect('[');
ImapList list = new ImapList();
Object token;
while (true) {
token = parseToken();
if (token == null) {
break;
} else if (token instanceof InputStream) {
list.add(token);
break;
} else if (token.equals("]")) {
break;
} else {
list.add(token);
}
}
return list;
}
private String parseAtom() throws IOException {
StringBuffer sb = new StringBuffer();
int ch;
@ -178,6 +203,7 @@ public class ImapResponseParser {
if (ch == -1) {
throw new IOException("parseAtom(): end of stream reached");
} else if (ch == '(' || ch == ')' || ch == '{' || ch == ' ' ||
ch == '[' || ch == ']' ||
// docs claim that flags are \ atom but atom isn't supposed to
// contain
// * and some falgs contain *

File diff suppressed because it is too large Load Diff

View File

@ -67,7 +67,7 @@ import java.io.StringReader;
* </pre>
*/
public class LocalStore extends Store implements Serializable {
private static final int DB_VERSION = 26;
private static final int DB_VERSION = 29;
private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN };
private String mPath;
@ -133,7 +133,7 @@ public class LocalStore extends Store implements Serializable {
mDb.execSQL("DROP TABLE IF EXISTS folders");
mDb.execSQL("CREATE TABLE folders (id INTEGER PRIMARY KEY, name TEXT, "
+ "last_updated INTEGER, unread_count INTEGER, visible_limit INTEGER, status TEXT)");
+ "last_updated INTEGER, unread_count INTEGER, visible_limit INTEGER, status TEXT, push_state TEXT, last_pushed INTEGER)");
mDb.execSQL("CREATE INDEX IF NOT EXISTS folder_name ON folders (name)");
mDb.execSQL("DROP TABLE IF EXISTS messages");
@ -273,10 +273,10 @@ public class LocalStore extends Store implements Serializable {
try {
cursor = mDb.rawQuery("SELECT name, id, unread_count, visible_limit, last_updated, status FROM folders", null);
cursor = mDb.rawQuery("SELECT name, id, unread_count, visible_limit, last_updated, status, push_state, last_pushed FROM folders", null);
while (cursor.moveToNext()) {
LocalFolder folder = new LocalFolder(cursor.getString(0));
folder.open(cursor.getInt(1), cursor.getInt(2), cursor.getInt(3), cursor.getLong(4), cursor.getString(5));
folder.open(cursor.getInt(1), cursor.getInt(2), cursor.getInt(3), cursor.getLong(4), cursor.getString(5), cursor.getString(6), cursor.getLong(7));
folders.add(folder);
}
@ -489,9 +489,11 @@ public class LocalStore extends Store implements Serializable {
private long mFolderId = -1;
private int mUnreadMessageCount = -1;
private int mVisibleLimit = -1;
private FolderClass displayClass = FolderClass.NONE;
private FolderClass syncClass = FolderClass.NONE;
private FolderClass displayClass = FolderClass.NO_CLASS;
private FolderClass syncClass = FolderClass.INHERITED;
private FolderClass pushClass = FolderClass.SECOND_CLASS;
private String prefId = null;
private String mPushState = null;
public LocalFolder(String name) {
this.mName = name;
@ -499,8 +501,10 @@ public class LocalStore extends Store implements Serializable {
if (Email.INBOX.equals(getName()))
{
syncClass = FolderClass.FIRST_CLASS;
pushClass = FolderClass.FIRST_CLASS;
}
}
public long getId() {
@ -514,7 +518,7 @@ public class LocalStore extends Store implements Serializable {
}
Cursor cursor = null;
try {
cursor = mDb.rawQuery("SELECT id, unread_count, visible_limit, last_updated, status FROM folders "
cursor = mDb.rawQuery("SELECT id, unread_count, visible_limit, last_updated, status, push_state, last_pushed FROM folders "
+ "where folders.name = ?",
new String[] {
mName
@ -524,7 +528,7 @@ public class LocalStore extends Store implements Serializable {
int folderId = cursor.getInt(0);
if (folderId > 0)
{
open(cursor.getInt(0), cursor.getInt(1), cursor.getInt(2), cursor.getLong(3), cursor.getString(4));
open(cursor.getInt(0), cursor.getInt(1), cursor.getInt(2), cursor.getLong(3), cursor.getString(4), cursor.getString(5), cursor.getLong(6) );
}
} else {
create(FolderType.HOLDS_MESSAGES);
@ -538,15 +542,17 @@ public class LocalStore extends Store implements Serializable {
}
}
private void open(int id, int unreadCount, int visibleLimit, long lastChecked, String status) throws MessagingException
private void open(int id, int unreadCount, int visibleLimit, long lastChecked, String status, String pushState, long lastPushed) throws MessagingException
{
mFolderId = id;
mUnreadMessageCount = unreadCount;
mVisibleLimit = visibleLimit;
mPushState = pushState;
super.setStatus(status);
// Only want to set the local variable stored in the super class. This class
// does a DB update on setLastChecked
super.setLastChecked(lastChecked);
super.setLastPush(lastPushed);
}
@Override
@ -656,6 +662,13 @@ public class LocalStore extends Store implements Serializable {
new Object[] { lastChecked, mFolderId });
}
public void setLastPush(long lastChecked) throws MessagingException {
open(OpenMode.READ_WRITE);
super.setLastPush(lastChecked);
mDb.execSQL("UPDATE folders SET last_pushed = ? WHERE id = ?",
new Object[] { lastChecked, mFolderId });
}
public int getVisibleLimit() throws MessagingException {
open(OpenMode.READ_WRITE);
return mVisibleLimit;
@ -676,6 +689,17 @@ public class LocalStore extends Store implements Serializable {
mDb.execSQL("UPDATE folders SET status = ? WHERE id = ?",
new Object[] { status, mFolderId });
}
public void setPushState(String pushState) throws MessagingException
{
open(OpenMode.READ_WRITE);
mPushState = pushState;
mDb.execSQL("UPDATE folders SET push_state = ? WHERE id = ?",
new Object[] { pushState, mFolderId });
}
public String getPushState()
{
return mPushState;
}
@Override
public FolderClass getDisplayClass()
{
@ -685,9 +709,9 @@ public class LocalStore extends Store implements Serializable {
@Override
public FolderClass getSyncClass()
{
if (FolderClass.NONE == syncClass)
if (FolderClass.INHERITED == syncClass)
{
return displayClass;
return getDisplayClass();
}
else
{
@ -697,11 +721,28 @@ public class LocalStore extends Store implements Serializable {
public FolderClass getRawSyncClass()
{
return syncClass;
}
public FolderClass getPushClass()
{
if (FolderClass.INHERITED == pushClass)
{
return getSyncClass();
}
else
{
return pushClass;
}
}
public FolderClass getRawPushClass()
{
return pushClass;
}
public void setDisplayClass(FolderClass displayClass)
{
this.displayClass = displayClass;
@ -711,6 +752,10 @@ public class LocalStore extends Store implements Serializable {
{
this.syncClass = syncClass;
}
public void setPushClass(FolderClass pushClass)
{
this.pushClass = pushClass;
}
private String getPrefId() throws MessagingException
{
@ -740,7 +785,7 @@ public class LocalStore extends Store implements Serializable {
SharedPreferences.Editor editor = preferences.getPreferences().edit();
// there can be a lot of folders. For the defaults, let's not save prefs, saving space, except for INBOX
if (displayClass == FolderClass.NONE && !Email.INBOX.equals(getName()))
if (displayClass == FolderClass.NO_CLASS && !Email.INBOX.equals(getName()))
{
editor.remove(id + ".displayMode");
}
@ -749,7 +794,7 @@ public class LocalStore extends Store implements Serializable {
editor.putString(id + ".displayMode", displayClass.name());
}
if (syncClass == FolderClass.NONE && !Email.INBOX.equals(getName()))
if (syncClass == FolderClass.INHERITED && !Email.INBOX.equals(getName()))
{
editor.remove(id + ".syncMode");
}
@ -758,6 +803,15 @@ public class LocalStore extends Store implements Serializable {
editor.putString(id + ".syncMode", syncClass.name());
}
if (pushClass == FolderClass.SECOND_CLASS && !Email.INBOX.equals(getName()))
{
editor.remove(id + ".pushMode");
}
else
{
editor.putString(id + ".pushMode", pushClass.name());
}
editor.commit();
}
public void refresh(Preferences preferences) throws MessagingException {
@ -767,17 +821,21 @@ public class LocalStore extends Store implements Serializable {
try
{
displayClass = FolderClass.valueOf(preferences.getPreferences().getString(id + ".displayMode",
FolderClass.NONE.name()));
FolderClass.NO_CLASS.name()));
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Unable to load displayMode for " + getName(), e);
displayClass = FolderClass.NONE;
displayClass = FolderClass.NO_CLASS;
}
if (displayClass == FolderClass.NONE)
{
displayClass = FolderClass.NO_CLASS;
}
FolderClass defSyncClass = FolderClass.NONE;
FolderClass defSyncClass = FolderClass.INHERITED;
if (Email.INBOX.equals(getName()))
{
defSyncClass = FolderClass.FIRST_CLASS;
@ -794,6 +852,32 @@ public class LocalStore extends Store implements Serializable {
syncClass = defSyncClass;
}
if (syncClass == FolderClass.NONE)
{
syncClass = FolderClass.INHERITED;
}
FolderClass defPushClass = FolderClass.SECOND_CLASS;
if (Email.INBOX.equals(getName()))
{
defPushClass = FolderClass.FIRST_CLASS;
}
try
{
pushClass = FolderClass.valueOf(preferences.getPreferences().getString(id + ".pushMode",
defPushClass.name()));
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Unable to load pushMode for " + getName(), e);
pushClass = defPushClass;
}
if (pushClass == FolderClass.NONE)
{
pushClass = FolderClass.INHERITED;
}
}
@ -1039,7 +1123,9 @@ public class LocalStore extends Store implements Serializable {
i++;
}
populateHeaders(messagesForHeaders);
if (listener != null) {
listener.messagesFinished(i);
}
}
finally {
if (cursor != null) {
@ -1085,9 +1171,7 @@ public class LocalStore extends Store implements Serializable {
LocalMessage lMessage = (LocalMessage)message;
if (!message.isSet(Flag.SEEN)) {
if (getUnreadMessageCount() > 0) {
setUnreadMessageCount(getUnreadMessageCount() - 1);
}
lDestFolder.setUnreadMessageCount(lDestFolder.getUnreadMessageCount() + 1);
}
@ -1105,6 +1189,7 @@ public class LocalStore extends Store implements Serializable {
LocalMessage placeHolder = new LocalMessage(oldUID, this);
placeHolder.setFlagInternal(Flag.DELETED, true);
placeHolder.setFlagInternal(Flag.SEEN, true);
appendMessages(new Message[] { placeHolder });
}
@ -1139,6 +1224,11 @@ public class LocalStore extends Store implements Serializable {
message.setUid(Email.LOCAL_UID_PREFIX + UUID.randomUUID().toString());
}
else {
Message oldMessage = getMessage(message.getUid());
if (oldMessage != null && oldMessage.isSet(Flag.SEEN) == false)
{
setUnreadMessageCount(getUnreadMessageCount() - 1);
}
/*
* The message may already exist in this Folder, so delete it first.
*/
@ -1202,6 +1292,10 @@ public class LocalStore extends Store implements Serializable {
saveAttachment(messageId, attachment, copy);
}
saveHeaders(messageId, (MimeMessage)message);
if (message.isSet(Flag.SEEN) == false)
{
setUnreadMessageCount(getUnreadMessageCount() + 1);
}
} catch (Exception e) {
throw new MessagingException("Error appending message", e);
}
@ -1473,6 +1567,28 @@ public class LocalStore extends Store implements Serializable {
open(OpenMode.READ_ONLY);
mDb.execSQL("DELETE FROM messages WHERE folder_id = ? and date < ?", new Object[] {
Long.toString(mFolderId), new Long(cutoff) } );
resetUnreadCount();
}
private void resetUnreadCount()
{
try
{
int newUnread = 0;
Message[] messages = getMessages(null);
for (Message message : messages)
{
if (message.isSet(Flag.SEEN) == false)
{
newUnread++;
}
}
setUnreadMessageCount(newUnread);
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Unable to fetch all messages from LocalStore", e);
}
}
@Override
@ -1760,7 +1876,8 @@ public class LocalStore extends Store implements Serializable {
* Update the unread count on the folder.
*/
try {
if (flag == Flag.DELETED || flag == Flag.X_DESTROYED || flag == Flag.SEEN) {
if (flag == Flag.DELETED || flag == Flag.X_DESTROYED
|| (flag == Flag.SEEN && !isSet(Flag.DELETED))) {
LocalFolder folder = (LocalFolder)mFolder;
if (set && !isSet(Flag.SEEN)) {
folder.setUnreadMessageCount(folder.getUnreadMessageCount() - 1);

View File

@ -2,8 +2,9 @@
package com.android.email.service;
import com.android.email.Email;
import android.net.ConnectivityManager;
import android.util.Log;
import com.android.email.MessagingController;
import android.content.BroadcastReceiver;
import android.content.Context;
@ -22,5 +23,9 @@ public class BootReceiver extends BroadcastReceiver {
else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(intent.getAction())) {
MailService.actionReschedule(context);
}
else if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
MailService.connectivityChange(context, !noConnectivity);
}
}
}

View File

@ -1,6 +1,7 @@
package com.android.email.service;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
@ -11,14 +12,15 @@ import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.NetworkInfo.State;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.util.Config;
import android.util.Log;
import android.text.TextUtils;
import android.net.Uri;
import com.android.email.Account;
import com.android.email.Email;
@ -26,21 +28,29 @@ import com.android.email.MessagingController;
import com.android.email.MessagingListener;
import com.android.email.Preferences;
import com.android.email.R;
import com.android.email.activity.Accounts;
import com.android.email.activity.FolderList;
import com.android.email.mail.Folder;
import com.android.email.mail.Address;
import com.android.email.mail.Message;
import com.android.email.mail.MessagingException;
import com.android.email.mail.Store;
import com.android.email.mail.Pusher;
import com.android.email.EmailReceivedIntent;
/**
*/
public class MailService extends Service {
private static final String ACTION_APP_STARTED = "com.android.email.intent.action.MAIL_SERVICE_APP_STARTED";
private static final String ACTION_CHECK_MAIL = "com.android.email.intent.action.MAIL_SERVICE_WAKEUP";
private static final String ACTION_RESCHEDULE = "com.android.email.intent.action.MAIL_SERVICE_RESCHEDULE";
private static final String ACTION_CANCEL = "com.android.email.intent.action.MAIL_SERVICE_CANCEL";
private static final String ACTION_REFRESH_PUSHERS = "com.android.email.intent.action.MAIL_SERVICE_REFRESH_PUSHERS";
private static final String CONNECTIVITY_CHANGE = "com.android.email.intent.action.MAIL_SERVICE_CONNECTIVITY_CHANGE";
private static final String CANCEL_CONNECTIVITY_NOTICE = "com.android.email.intent.action.MAIL_SERVICE_CANCEL_CONNECTIVITY_NOTICE";
private static final String HAS_CONNECTIVITY = "com.android.email.intent.action.MAIL_SERVICE_HAS_CONNECTIVITY";
private Listener mListener = new Listener();
private State state = null;
private int mStartId;
public static void actionReschedule(Context context) {
@ -50,6 +60,20 @@ public class MailService extends Service {
context.startService(i);
}
public static void appStarted(Context context) {
Intent i = new Intent();
i.setClass(context, MailService.class);
i.setAction(MailService.ACTION_APP_STARTED);
context.startService(i);
}
// private static void checkMail(Context context) {
// Intent i = new Intent();
// i.setClass(context, MailService.class);
// i.setAction(MailService.ACTION_CHECK_MAIL);
// context.startService(i);
// }
public static void actionCancel(Context context) {
Intent i = new Intent();
i.setClass(context, MailService.class);
@ -57,6 +81,14 @@ public class MailService extends Service {
context.startService(i);
}
public static void connectivityChange(Context context, boolean hasConnectivity) {
Intent i = new Intent();
i.setClass(context, MailService.class);
i.setAction(MailService.CONNECTIVITY_CHANGE);
i.putExtra(HAS_CONNECTIVITY, hasConnectivity);
context.startService(i);
}
@Override
public void onCreate() {
super.onCreate();
@ -65,6 +97,35 @@ public class MailService extends Service {
@Override
public void onStart(Intent intent, int startId) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email");
wakeLock.setReferenceCounted(false);
wakeLock.acquire(Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT);
try
{
ConnectivityManager connectivityManager = (ConnectivityManager)getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
state = State.DISCONNECTED;
if (connectivityManager != null)
{
NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
if (netInfo != null)
{
state = netInfo.getState();
if (state == State.CONNECTED)
{
Log.i(Email.LOG_TAG, "Currently connected to a network");
}
else
{
Log.i(Email.LOG_TAG, "Current network state = " + state);
}
}
}
setForeground(true); // if it gets killed once, it'll never restart
Log.v(Email.LOG_TAG, "***** MailService *****: onStart(" + intent + ", " + startId + ")");
super.onStart(intent, startId);
@ -76,7 +137,8 @@ public class MailService extends Service {
MessagingController.getInstance(getApplication()).log("***** MailService *****: checking mail");
Log.v(Email.LOG_TAG, "***** MailService *****: checking mail");
//}
if (state == State.CONNECTED)
{
MessagingController controller = MessagingController.getInstance(getApplication());
Listener listener = (Listener)controller.getCheckMailListener();
if (listener == null)
@ -93,6 +155,7 @@ public class MailService extends Service {
listener.wakeLockAcquire();
}
}
reschedule();
// stopSelf(startId);
@ -111,9 +174,97 @@ public class MailService extends Service {
Log.v(Email.LOG_TAG, "***** MailService *****: reschedule");
}
MessagingController.getInstance(getApplication()).log("***** MailService *****: reschedule");
reschedule();
boolean polling = reschedule();
boolean pushing = reschedulePushers();
if (polling == false && pushing == false)
{
Log.i(Email.LOG_TAG, "Neither pushing nor polling, so stopping");
stopSelf(startId);
}
// stopSelf(startId);
}
else if (ACTION_REFRESH_PUSHERS.equals(intent.getAction()))
{
schedulePushers();
try
{
if (state == State.CONNECTED)
{
Log.i(Email.LOG_TAG, "Refreshing pushers");
Collection<Pusher> pushers = MessagingController.getInstance(getApplication()).getPushers();
for (Pusher pusher : pushers)
{
pusher.refresh();
}
}
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Exception while refreshing pushers", e);
}
}
else if (CONNECTIVITY_CHANGE.equals(intent.getAction()))
{
boolean hasConnectivity = intent.getBooleanExtra(HAS_CONNECTIVITY, true);
Log.i(Email.LOG_TAG, "Got connectivity action with hasConnectivity = " + hasConnectivity);
notifyConnectionStatus(hasConnectivity);
if (hasConnectivity)
{
reschedulePushers();
// TODO: Make it send pending outgoing messages here
//checkMail(getApplication());
}
else
{
stopPushers();
}
}
else if (CANCEL_CONNECTIVITY_NOTICE.equals(intent.getAction()))
{
notifyConnectionStatus(true);
}
else if (ACTION_APP_STARTED.equals(intent.getAction()))
{
// Not needed for now, but might be useful later
}
}
finally
{
if (wakeLock != null)
{
wakeLock.release();
}
}
}
private void notifyConnectionStatus(boolean hasConnectivity)
{
NotificationManager notifMgr =
(NotificationManager)getApplication().getSystemService(Context.NOTIFICATION_SERVICE);
if (hasConnectivity == false)
{
String notice = getApplication().getString(R.string.no_connection_alert);
String header = getApplication().getString(R.string.alert_header);
Notification notif = new Notification(R.drawable.stat_notify_email_generic,
header, System.currentTimeMillis());
Intent i = new Intent();
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
i.setAction(MailService.CANCEL_CONNECTIVITY_NOTICE);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
notif.setLatestEventInfo(getApplication(), header, notice, pi);
notif.flags = Notification.FLAG_ONGOING_EVENT;
notifMgr.notify(Email.CONNECTIVITY_ID, notif);
}
else
{
notifMgr.cancel(Email.CONNECTIVITY_ID);
}
}
@Override
@ -132,7 +283,8 @@ public class MailService extends Service {
alarmMgr.cancel(pi);
}
private void reschedule() {
private boolean reschedule() {
boolean polling = true;
AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent();
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
@ -151,7 +303,7 @@ public class MailService extends Service {
if (shortestInterval == -1) {
Log.v(Email.LOG_TAG, "No next check scheduled for package " + getApplication().getPackageName());
alarmMgr.cancel(pi);
stopSelf(mStartId);
polling = false;
}
else
{
@ -172,7 +324,70 @@ public class MailService extends Service {
alarmMgr.set(AlarmManager.RTC_WAKEUP, nextTime, pi);
}
return polling;
}
private void stopPushers()
{
MessagingController.getInstance(getApplication()).stopAllPushing();
}
private boolean reschedulePushers()
{
boolean pushing = false;
Log.i(Email.LOG_TAG, "Rescheduling pushers");
stopPushers();
if (state == State.CONNECTED)
{
for (Account account : Preferences.getPreferences(this).getAccounts()) {
Log.i(Email.LOG_TAG, "Setting up pushers for account " + account.getDescription());
Pusher pusher = MessagingController.getInstance(getApplication()).setupPushing(account);
if (pusher != null)
{
pushing = true;
Log.i(Email.LOG_TAG, "Starting configured pusher for account " + account.getDescription());
pusher.start();
}
}
schedulePushers();
}
return pushing;
}
private void schedulePushers()
{
int minInterval = -1;
Collection<Pusher> pushers = MessagingController.getInstance(getApplication()).getPushers();
for (Pusher pusher : pushers)
{
int interval = pusher.getRefreshInterval();
if (interval != -1 && (interval < minInterval || minInterval == -1))
{
minInterval = interval;
}
}
if (Email.DEBUG)
{
Log.v(Email.LOG_TAG, "Pusher refresh interval = " + minInterval);
}
if (minInterval != -1)
{
AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
long nextTime = System.currentTimeMillis() + minInterval;
String checkString = "Next pusher refresh scheduled for " + new Date(nextTime);
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, checkString);
}
Intent i = new Intent();
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
i.setAction(ACTION_REFRESH_PUSHERS);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
alarmMgr.set(AlarmManager.RTC_WAKEUP, nextTime, pi);
}
}
public IBinder onBind(Intent intent) {
@ -244,46 +459,16 @@ public class MailService extends Service {
NotificationManager notifMgr =
(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
int index = 0;
for (Account thisAccount : Preferences.getPreferences(context).getAccounts()) {
Integer newMailCount = accountsChecked.get(thisAccount.getUuid());
int unreadMessageCount = -1;
if (newMailCount != null)
{
try
{
unreadMessageCount = thisAccount.getUnreadMessageCount(context, getApplication());
int unreadMessageCount = thisAccount.getUnreadMessageCount(context, getApplication());
if (unreadMessageCount > 0 && newMailCount > 0)
{
String notice = getString(R.string.notification_new_one_account_fmt, unreadMessageCount,
thisAccount.getDescription());
Notification notif = new Notification(R.drawable.stat_notify_email_generic,
getString(R.string.notification_new_title), System.currentTimeMillis() + (index*1000));
notif.number = unreadMessageCount;
Intent i = FolderList.actionHandleAccountIntent(context, thisAccount);
PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);
notif.setLatestEventInfo(context, getString(R.string.notification_new_title), notice, pi);
// JRV XXX TODO - Do we also need to notify the messagelist here?
String ringtone = thisAccount.getRingtone();
notif.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone);
if (thisAccount.isVibrate()) {
notif.defaults |= Notification.DEFAULT_VIBRATE;
}
notif.flags |= Notification.FLAG_SHOW_LIGHTS;
notif.ledARGB = Email.NOTIFICATION_LED_COLOR;
notif.ledOnMS = Email.NOTIFICATION_LED_ON_TIME;
notif.ledOffMS = Email.NOTIFICATION_LED_OFF_TIME;
notifMgr.notify(thisAccount.getAccountNumber(), notif);
MessagingController.getInstance(getApplication()).notifyAccount(context, thisAccount, unreadMessageCount);
}
else if (unreadMessageCount == 0)
{
@ -299,6 +484,7 @@ public class MailService extends Service {
}//for accounts
}//checkMailDone
private void release()
{
MessagingController controller = MessagingController.getInstance(getApplication());
@ -322,4 +508,5 @@ public class MailService extends Service {
}
}
}
}