1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-27 11:42:16 -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"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1011" android:versionCode="1105"
android:versionName="1.011" package="com.fsck.k9"> android:versionName="1.105" package="com.fsck.k9">
<uses-sdk android:minSdkVersion="3"/> <uses-sdk android:minSdkVersion="3"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.READ_CONTACTS"/>
@ -204,6 +204,9 @@
<intent-filter> <intent-filter>
<action android:name="android.intent.action.DEVICE_STORAGE_OK" /> <action android:name="android.intent.action.DEVICE_STORAGE_OK" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver> </receiver>
<service <service
android:name="com.android.email.service.MailService" android:name="com.android.email.service.MailService"

View File

@ -33,6 +33,11 @@
android:title="@string/account_settings_action" android:title="@string/account_settings_action"
android:icon="@android:drawable/ic_menu_preferences" 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 <item
android:id="@+id/compact" android:id="@+id/compact"
android:title="@string/compact_action" android:title="@string/compact_action"

View File

@ -48,12 +48,23 @@
android:title="@string/list_folders_action" android:title="@string/list_folders_action"
android:icon="@drawable/ic_menu_navigate" 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 <item
android:id="@+id/check_mail" android:id="@+id/check_mail"
android:alphabeticShortcut="r" android:alphabeticShortcut="r"
android:title="@string/check_mail_action" android:title="@string/check_mail_action"
android:icon="@drawable/ic_menu_refresh" android:icon="@drawable/ic_menu_refresh"
/> />
<item
android:id="@+id/accounts"
android:title="@string/accounts_action"
android:icon="@drawable/ic_menu_account_list"
/>
<item <item
android:id="@+id/mark_all_as_read" android:id="@+id/mark_all_as_read"
android:title="@string/mark_all_as_read_action" 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_display_mode_second_class">Nebenordner</string>
<string name="folder_settings_folder_sync_mode_label">Synchronisationsklasse</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_first_class">Hauptordner</string>
<string name="folder_settings_folder_sync_mode_second_class">Nebenordner</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_label">Einstellungen Posteingang</string>
<string name="account_settings_incoming_summary">Einstellungen für Posteingangsserver bearbeiten.</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_class</item>
<item>@string/account_settings_folder_sync_mode_first_and_second_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_not_second_class</item>
<item>@string/account_settings_folder_sync_mode_none</item>
</string-array> </string-array>
<string-array name="account_settings_folder_sync_mode_values"> <string-array name="account_settings_folder_sync_mode_values">
@ -88,6 +89,23 @@
<item>FIRST_CLASS</item> <item>FIRST_CLASS</item>
<item>FIRST_AND_SECOND_CLASS</item> <item>FIRST_AND_SECOND_CLASS</item>
<item>NOT_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>
<string-array name="account_settings_folder_target_mode_entries"> <string-array name="account_settings_folder_target_mode_entries">
@ -111,7 +129,7 @@
</string-array> </string-array>
<string-array name="folder_settings_folder_display_mode_values"> <string-array name="folder_settings_folder_display_mode_values">
<item>NONE</item> <item>NO_CLASS</item>
<item>FIRST_CLASS</item> <item>FIRST_CLASS</item>
<item>SECOND_CLASS</item> <item>SECOND_CLASS</item>
</string-array> </string-array>
@ -120,12 +138,28 @@
<item>@string/folder_settings_folder_sync_mode_normal</item> <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_first_class</item>
<item>@string/folder_settings_folder_sync_mode_second_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>
<string-array name="folder_settings_folder_sync_mode_values"> <string-array name="folder_settings_folder_sync_mode_values">
<item>NONE</item> <item>NO_CLASS</item>
<item>FIRST_CLASS</item> <item>FIRST_CLASS</item>
<item>SECOND_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>
<string-array name="account_setup_delete_policy_entries"> <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 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> 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="end_of_folder">No more messages</string>
<string name="accounts_welcome"> <string name="accounts_welcome">
@ -210,11 +213,14 @@ 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_instructions">Select \"Show pictures\" to display embedded pictures.</string>
<string name="message_view_show_pictures_action">Show 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_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_title">Folders</string>
<string name="mailbox_select_dlg_new_mailbox_action">New folder</string> <string name="mailbox_select_dlg_new_mailbox_action">New folder</string>
<string name="new_mailbox_dlg_title">New folder name</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_copied_toast">Message copied</string>
<string name="message_moved_toast">Message moved</string> <string name="message_moved_toast">Message moved</string>
@ -376,12 +382,20 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
<string name="account_settings_folder_display_mode_first_class">Only 1st Class folders</string> <string name="account_settings_folder_display_mode_first_class">Only 1st Class folders</string>
<string name="account_settings_folder_display_mode_first_and_second_class">1st and 2nd Class folders</string> <string name="account_settings_folder_display_mode_first_and_second_class">1st and 2nd Class folders</string>
<string name="account_settings_folder_display_mode_not_second_class">All except 2nd Class folders</string> <string name="account_settings_folder_display_mode_not_second_class">All except 2nd Class folders</string>
<string name="account_settings_folder_sync_mode_label">Folder sync mode</string> <string name="account_settings_folder_sync_mode_label">Folder sync mode</string>
<string name="account_settings_folder_sync_mode_all">All</string> <string name="account_settings_folder_sync_mode_all">All</string>
<string name="account_settings_folder_sync_mode_first_class">Only 1st Class folders</string> <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_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_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_label">Move/copy destination folders</string>
<string name="account_settings_folder_target_mode_all">All</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_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_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_first_class">1st Class</string>
<string name="folder_settings_folder_sync_mode_second_class">2nd 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_label">Incoming settings</string>
<string name="account_settings_incoming_summary">Configure the incoming email server</string> <string name="account_settings_incoming_summary">Configure the incoming email server</string>

View File

@ -76,7 +76,14 @@
android:title="@string/account_settings_folder_sync_mode_label" android:title="@string/account_settings_folder_sync_mode_label"
android:entries="@array/account_settings_folder_sync_mode_entries" android:entries="@array/account_settings_folder_sync_mode_entries"
android:entryValues="@array/account_settings_folder_sync_mode_values" android:entryValues="@array/account_settings_folder_sync_mode_values"
android:dialogTitle="@string/account_settings_folder_sync_mode_label" /> 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 <ListPreference
android:key="folder_target_mode" android:key="folder_target_mode"

View File

@ -33,6 +33,13 @@
android:entryValues="@array/folder_settings_folder_sync_mode_values" android:entryValues="@array/folder_settings_folder_sync_mode_values"
android:dialogTitle="@string/folder_settings_folder_sync_mode_label" /> 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> </PreferenceCategory>

View File

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

View File

@ -35,6 +35,7 @@ public class Email extends Application {
/** /**
* If this is enabled there will be additional logging information sent to * If this is enabled there will be additional logging information sent to
* Log.d, including protocol dumps. * Log.d, including protocol dumps.
* Controlled by Preferences at run-time
*/ */
public static boolean DEBUG = false; 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. * The MIME type(s) of attachments we're willing to view.
*/ */
public static final String[] ACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] { public static final String[] ACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] {
"image/*", "*/*",
"audio/*",
"text/*",
}; };
/** /**
@ -134,6 +133,11 @@ public class Email extends Application {
public static final int WAKE_LOCK_TIMEOUT = 600000; public static final int WAKE_LOCK_TIMEOUT = 600000;
public static final int MANUAL_WAKE_LOCK_TIMEOUT = 120000; 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 * 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_ID = -4;
public static final int FETCHING_EMAIL_NOTIFICATION_MULTI_ACCOUNT_ID = -1; 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 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 // Backup formats in case they can't be fetched from the system
public static final String BACKUP_DATE_FORMAT = "MM-dd-yyyy"; public static final String BACKUP_DATE_FORMAT = "MM-dd-yyyy";
@ -237,7 +242,7 @@ public class Email extends Application {
DEBUG = prefs.getEnableDebugLogging(); DEBUG = prefs.getEnableDebugLogging();
DEBUG_SENSITIVE = prefs.getEnableSensitiveLogging(); DEBUG_SENSITIVE = prefs.getEnableSensitiveLogging();
MessagingController.getInstance(this).resetVisibleLimits(prefs.getAccounts()); MessagingController.getInstance(this).resetVisibleLimits(prefs.getAccounts());
/* /*
* We have to give MimeMessage a temp directory because File.createTempFile(String, String) * We have to give MimeMessage a temp directory because File.createTempFile(String, String)
* doesn't work in Android and MimeMessage does not have access to a Context. * doesn't work in Android and MimeMessage does not have access to a Context.
@ -249,7 +254,7 @@ public class Email extends Application {
*/ */
setServicesEnabled(this); setServicesEnabled(this);
MessagingController.getInstance(this).addListener(new MessagingListener() { MessagingController.getInstance(this).addListener(new MessagingListener() {
@Override @Override
public void synchronizeMailboxNewMessage(Account account, String folder, Message message) { public void synchronizeMailboxNewMessage(Account account, String folder, Message message) {
@ -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; package com.android.email;
import java.util.List;
import android.content.Context; import android.content.Context;
import com.android.email.mail.Folder; import com.android.email.mail.Folder;
@ -15,18 +17,14 @@ import com.android.email.mail.Part;
* changes in this class. * changes in this class.
*/ */
public class MessagingListener { public class MessagingListener {
public void accountStatusChanged(Account account, int unreadMessageCount) { public void accountStatusChanged(Account account, int unreadMessageCount) {
} }
public void accountSizeChanged(Account account, long oldSize, long newSize) public void accountSizeChanged(Account account, long oldSize, long newSize)
{ {
} }
public void accountReset(Account account) {
}
public void listFoldersStarted(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 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) { public void listLocalMessagesUpdateMessage(Account account, String folder, Message message) {
@ -128,6 +126,11 @@ public class MessagingListener {
public void messageUidChanged(Account account, String folder, String oldUid, String newUid) { public void messageUidChanged(Account account, String folder, String oldUid, String newUid) {
}
public void setPushActive(Account account, String folderName, boolean enabled)
{
} }
public void loadAttachmentStarted( public void loadAttachmentStarted(

View File

@ -264,6 +264,12 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
intent.putExtra(EXTRA_STARTUP, true); intent.putExtra(EXTRA_STARTUP, true);
context.startActivity(intent); 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 @Override
@ -332,10 +338,11 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
if (accounts.length > 0) { if (accounts.length > 0) {
mHandler.progress(Window.PROGRESS_START); mHandler.progress(Window.PROGRESS_START);
} }
pendingWork.clear();
for (Account account : accounts) { for (Account account : accounts) {
MessagingController.getInstance(getApplication()).getAccountUnreadCount(Accounts.this, account, mListener);
pendingWork.put(account, "true"); 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); setListAdapter(adapter);
new Thread()
{
public void run()
{
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
MessagingController.getInstance(getApplication()).listFolders(mAccount, MessagingController.getInstance(getApplication()).listFolders(mAccount,
false, mListener); false, mListener);
}
}.start();
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView adapterview, View view, int i, long l) 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.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Process;
import android.util.Config; import android.util.Config;
import android.util.Log; import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
@ -42,22 +41,15 @@ import com.android.email.MessagingController;
import com.android.email.MessagingListener; import com.android.email.MessagingListener;
import com.android.email.Preferences; import com.android.email.Preferences;
import com.android.email.R; 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.AccountSettings;
import com.android.email.activity.setup.FolderSettings; import com.android.email.activity.setup.FolderSettings;
import com.android.email.mail.Folder; import com.android.email.mail.Folder;
import com.android.email.mail.Message; import com.android.email.mail.Message;
import com.android.email.mail.MessagingException; import com.android.email.mail.MessagingException;
import com.android.email.mail.Store; import com.android.email.mail.Store;
import com.android.email.mail.store.LocalStore.LocalFolder;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.PowerManager.WakeLock; 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 * FolderList is the primary user interface for the program. This
@ -88,26 +80,13 @@ public class FolderList extends K9ListActivity {
private Account mAccount; private Account mAccount;
private String mInitialFolder;
private boolean mRestoringState;
private boolean mRefreshRemote;
private FolderListHandler mHandler = new FolderListHandler(); private FolderListHandler mHandler = new FolderListHandler();
private DateFormat dateFormat = null; private DateFormat dateFormat = null;
private DateFormat timeFormat = null; private DateFormat timeFormat = null;
private boolean sortAscending = true;
private boolean sortDateAscending = false;
private boolean mStartup = false; private boolean mStartup = false;
private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 1, 120000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
private DateFormat getDateFormat() { private DateFormat getDateFormat() {
if (dateFormat == null) { if (dateFormat == null) {
@ -145,17 +124,24 @@ public class FolderList extends K9ListActivity {
private static final int MSG_PROGRESS = 2; private static final int MSG_PROGRESS = 2;
private static final int MSG_DATA_CHANGED = 3; 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_FOLDER_LOADING = 7;
private static final int MSG_SYNC_MESSAGES = 13;
private static final int MSG_FOLDER_SYNCING = 18; private static final int MSG_FOLDER_SYNCING = 18;
private static final int MSG_SENDING_OUTBOX = 19; private static final int MSG_SENDING_OUTBOX = 19;
private static final int MSG_ACCOUNT_SIZE_CHANGED = 20; private static final int MSG_ACCOUNT_SIZE_CHANGED = 20;
private static final int MSG_WORKING_ACCOUNT = 21; private static final int MSG_WORKING_ACCOUNT = 21;
private static final int MSG_NEW_FOLDERS = 22;
@Override @Override
public void handleMessage(android.os.Message msg) { public void handleMessage(android.os.Message msg) {
switch (msg.what) { 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: case MSG_PROGRESS:
setProgressBarIndeterminateVisibility(msg.arg1 != 0); setProgressBarIndeterminateVisibility(msg.arg1 != 0);
break; 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(); android.os.Message msg = new android.os.Message();
msg.what = MSG_SYNC_MESSAGES; msg.obj = newFolders;
msg.obj = new Object[] { folder, messages }; msg.what = MSG_NEW_FOLDERS;
sendMessage(msg); sendMessage(msg);
} }
@ -285,55 +271,32 @@ public class FolderList extends K9ListActivity {
* queueing up a remote update of the folder. * queueing up a remote update of the folder.
*/ */
class FolderUpdateWorker implements Runnable { private void checkMail(FolderInfoHolder folder)
String mFolder; {
FolderInfoHolder mHolder; PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean mSynchronizeRemote; final WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email - UpdateWorker");
wakeLock.setReferenceCounted(false);
/** wakeLock.acquire(Email.WAKE_LOCK_TIMEOUT);
* Create a worker for the given folder and specifying whether the worker MessagingListener listener = new MessagingListener()
* should synchronize the remote folder or just the local one. {
* public void synchronizeMailboxFinished(Account account, String folder, int totalMessagesInMailbox, int numNewMessages) {
* @param folder if (!account.equals(mAccount)) {
* @param synchronizeRemote return;
*/
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);
} }
wakeLock.release();
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) { private static void actionHandleAccount(Context context, Account account, String initialFolder, boolean startup) {
@ -381,38 +344,39 @@ public class FolderList extends K9ListActivity {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
String initialFolder;
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
String savedFolderName = null; String savedFolderName = null;
Intent intent = getIntent(); Intent intent = getIntent();
mAccount = (Account)intent.getSerializableExtra(EXTRA_ACCOUNT); mAccount = (Account)intent.getSerializableExtra(EXTRA_ACCOUNT);
Log.v(Email.LOG_TAG, "savedInstanceState: " + (savedInstanceState==null)); Log.v(Email.LOG_TAG, "savedInstanceState: " + (savedInstanceState==null));
if (savedInstanceState == null) { if (savedInstanceState == null) {
mInitialFolder = intent.getStringExtra(EXTRA_INITIAL_FOLDER); initialFolder = intent.getStringExtra(EXTRA_INITIAL_FOLDER);
Log.v(Email.LOG_TAG, "EXTRA_INITIAL_FOLDER: " + mInitialFolder); Log.v(Email.LOG_TAG, "EXTRA_INITIAL_FOLDER: " + initialFolder);
mStartup = (boolean) intent.getBooleanExtra(EXTRA_STARTUP, false); mStartup = (boolean) intent.getBooleanExtra(EXTRA_STARTUP, false);
Log.v(Email.LOG_TAG, "startup: " + mStartup); Log.v(Email.LOG_TAG, "startup: " + mStartup);
if (mInitialFolder == null if (initialFolder == null
&& mStartup) { && mStartup) {
mInitialFolder = mAccount.getAutoExpandFolderName(); initialFolder = mAccount.getAutoExpandFolderName();
} }
} }
else { else {
mInitialFolder = null; initialFolder = null;
mStartup = false; mStartup = false;
savedFolderName = savedInstanceState.getString(STATE_CURRENT_FOLDER); savedFolderName = savedInstanceState.getString(STATE_CURRENT_FOLDER);
} }
Log.v(Email.LOG_TAG, "mInitialFolder: " + mInitialFolder); Log.v(Email.LOG_TAG, "mInitialFolder: " + initialFolder);
if (mInitialFolder != null if (initialFolder != null
&& !Email.FOLDER_NONE.equals(mInitialFolder)) { && !Email.FOLDER_NONE.equals(initialFolder)) {
onOpenFolder(mInitialFolder, true); onOpenFolder(initialFolder, true);
finish(); finish();
} }
else { else {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
final FolderList xxx = this;
mListView = getListView(); mListView = getListView();
mListView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET); mListView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);
mListView.setLongClickable(true); mListView.setLongClickable(true);
@ -421,7 +385,7 @@ public class FolderList extends K9ListActivity {
mListView.setOnItemClickListener(new OnItemClickListener() { mListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int itemPosition, long id) { public void onItemClick(AdapterView parent, View v, int itemPosition, long id) {
Log.v(Email.LOG_TAG,"We're clicking "+itemPosition+" -- "+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); registerForContextMenu(mListView);
@ -445,12 +409,6 @@ public class FolderList extends K9ListActivity {
setListAdapter(mAdapter); setListAdapter(mAdapter);
if (savedInstanceState != null) {
mRestoringState = true;
//onRestoreListState(savedInstanceState);
mRestoringState = false;
}
setTitle(mAccount.getDescription()); setTitle(mAccount.getDescription());
if (savedFolderName != null) if (savedFolderName != null)
@ -480,7 +438,6 @@ public class FolderList extends K9ListActivity {
MessagingController.getInstance(getApplication()).addListener(mAdapter.mListener); MessagingController.getInstance(getApplication()).addListener(mAdapter.mListener);
mAccount.refresh(Preferences.getPreferences(this)); mAccount.refresh(Preferences.getPreferences(this));
markAllRefresh();
onRefresh( !REFRESH_REMOTE ); onRefresh( !REFRESH_REMOTE );
@ -503,7 +460,9 @@ public class FolderList extends K9ListActivity {
//Shortcuts that work no matter what is selected //Shortcuts that work no matter what is selected
switch (keyCode) { switch (keyCode) {
case KeyEvent.KEYCODE_Q: { case KeyEvent.KEYCODE_Q:
//case KeyEvent.KEYCODE_BACK:
{
onAccounts(); onAccounts();
return true; return true;
} }
@ -525,22 +484,9 @@ public class FolderList extends K9ListActivity {
}//onKeyDown }//onKeyDown
private void onRefresh(final boolean forceRemote) { private void onRefresh(final boolean forceRemote) {
if (forceRemote) {
mRefreshRemote = true;
}
new Thread() { MessagingController.getInstance(getApplication()).listFolders(mAccount, forceRemote, mAdapter.mListener);
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() { private void onEditAccount() {
@ -552,21 +498,14 @@ public class FolderList extends K9ListActivity {
} }
private void onAccounts() { private void onAccounts() {
// If we're a child activity (say because Welcome dropped us straight to the message list if (mStartup || isTaskRoot())
// we won't have a parent activity and we'll need to get back to it {
if (mStartup Accounts.listAccounts(this);
|| isTaskRoot()) {
Intent intent = new Intent(this, Accounts.class);
intent.putExtra(Accounts.EXTRA_STARTUP, false);
startActivity(intent);
} }
finish(); finish();
} }
private void markAllRefresh() {
mAdapter.mListener.accountReset(mAccount);
}
private void onEmptyTrash(final Account account) { private void onEmptyTrash(final Account account) {
mHandler.dataChanged(); mHandler.dataChanged();
@ -583,6 +522,10 @@ public class FolderList extends K9ListActivity {
private void checkMail(final Account account) { private void checkMail(final Account account) {
MessagingController.getInstance(getApplication()).checkMail(this, account, true, true, mAdapter.mListener); 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) { @Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
@ -596,6 +539,11 @@ public class FolderList extends K9ListActivity {
return true; 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: case R.id.accounts:
onAccounts(); onAccounts();
@ -666,15 +614,13 @@ public class FolderList extends K9ListActivity {
case R.id.send_messages: case R.id.send_messages:
Log.i(Email.LOG_TAG, "sending pending messages from " + folder.name); Log.i(Email.LOG_TAG, "sending pending messages from " + folder.name);
sendMail(mAccount);
MessagingController.getInstance(getApplication()).sendPendingMessages(mAccount, null);
break; break;
case R.id.check_mail: case R.id.check_mail:
Log.i(Email.LOG_TAG, "refresh folder " + folder.name); Log.i(Email.LOG_TAG, "refresh folder " + folder.name);
checkMail(folder);
threadPool.execute(new FolderUpdateWorker(folder, true));
break; break;
@ -741,10 +687,6 @@ public class FolderList extends K9ListActivity {
MessagingController.getInstance(getApplication()).markAllMessagesRead(mAccount, mSelectedContextFolder.name); MessagingController.getInstance(getApplication()).markAllMessagesRead(mAccount, mSelectedContextFolder.name);
for (MessageInfoHolder holder : mSelectedContextFolder.messages) {
holder.read = true;
}
mSelectedContextFolder.unreadMessageCount = 0; mSelectedContextFolder.unreadMessageCount = 0;
mHandler.dataChanged(); mHandler.dataChanged();
@ -854,7 +796,7 @@ public class FolderList extends K9ListActivity {
} }
mHandler.progress(false); mHandler.progress(false);
MessagingController.getInstance(getApplication()).refreshListener(mAdapter.mListener);
mHandler.dataChanged(); mHandler.dataChanged();
} }
@ -902,24 +844,9 @@ public class FolderList extends K9ListActivity {
newFolders.add(holder); 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) { public void synchronizeMailboxStarted(Account account, String folder) {
@ -930,6 +857,7 @@ public class FolderList extends K9ListActivity {
mHandler.progress(true); mHandler.progress(true);
mHandler.folderLoading(folder, true); mHandler.folderLoading(folder, true);
mHandler.folderSyncing(folder); mHandler.folderSyncing(folder);
mHandler.dataChanged();
} }
@Override @Override
@ -937,23 +865,37 @@ public class FolderList extends K9ListActivity {
if (!account.equals(mAccount)) { if (!account.equals(mAccount)) {
return; 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.progress(false);
mHandler.folderLoading(folder, false); mHandler.folderLoading(folder, false);
// mHandler.folderStatus(folder, null); // mHandler.folderStatus(folder, null);
mHandler.folderSyncing(null); mHandler.folderSyncing(null);
refreshFolder(account, folder);
onRefresh( ! REFRESH_REMOTE ); }
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 @Override
@ -978,6 +920,23 @@ public class FolderList extends K9ListActivity {
} }
mHandler.folderSyncing(null); 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)) { if (!account.equals(mAccount)) {
return; return;
} }
refreshFolder(account, mAccount.getTrashFolderName());
onRefresh( ! REFRESH_REMOTE);
} }
@Override @Override
@ -1002,8 +960,7 @@ public class FolderList extends K9ListActivity {
if (!account.equals(mAccount)) { if (!account.equals(mAccount)) {
return; return;
} }
refreshFolder(account, folderName);
onRefresh( !REFRESH_REMOTE);
} }
@Override @Override
@ -1013,8 +970,7 @@ public class FolderList extends K9ListActivity {
} }
mHandler.sendingOutbox(false); mHandler.sendingOutbox(false);
refreshFolder(account, mAccount.getOutboxFolderName());
onRefresh( !REFRESH_REMOTE);
} }
@Override @Override
@ -1024,6 +980,8 @@ public class FolderList extends K9ListActivity {
} }
mHandler.sendingOutbox(true); mHandler.sendingOutbox(true);
mHandler.dataChanged();
} }
@Override @Override
@ -1033,6 +991,7 @@ public class FolderList extends K9ListActivity {
} }
mHandler.sendingOutbox(false); mHandler.sendingOutbox(false);
refreshFolder(account, mAccount.getOutboxFolderName());
} }
public void accountSizeChanged(Account account, long oldSize, long newSize) { public void accountSizeChanged(Account account, long oldSize, long newSize) {
@ -1115,6 +1074,11 @@ public class FolderList extends K9ListActivity {
statusText = (getDateFormat().format(lastCheckedDate) + " " + getTimeFormat() statusText = (getDateFormat().format(lastCheckedDate) + " " + getTimeFormat()
.format(lastCheckedDate)); .format(lastCheckedDate));
} }
if (folder.pushActive)
{
statusText = getString(R.string.folder_push_active_symbol) + statusText;
}
if (statusText != null) { if (statusText != null) {
holder.folderStatus.setText(statusText); holder.folderStatus.setText(statusText);
@ -1150,8 +1114,6 @@ public class FolderList extends K9ListActivity {
public String displayName; public String displayName;
public ArrayList<MessageInfoHolder> messages;
public long lastChecked; public long lastChecked;
public int unreadMessageCount; public int unreadMessageCount;
@ -1159,11 +1121,11 @@ public class FolderList extends K9ListActivity {
public boolean loading; public boolean loading;
public String status; public String status;
public boolean pushActive;
public boolean lastCheckFailed; public boolean lastCheckFailed;
public boolean needsRefresh = false;
/** /**
* Outbox is handled differently from any other folder. * Outbox is handled differently from any other folder.
*/ */
@ -1241,12 +1203,8 @@ public class FolderList extends K9ListActivity {
if (this.name.equals(mAccount.getSentFolderName())) { if (this.name.equals(mAccount.getSentFolderName())) {
this.displayName = String.format( getString(R.string.special_mailbox_name_sent_fmt), this.name); this.displayName = String.format( getString(R.string.special_mailbox_name_sent_fmt), this.name);
} }
if (this.messages == null) { this.lastChecked = folder.getLastUpdate();
this.messages = new ArrayList<MessageInfoHolder>();
}
this.lastChecked = folder.getLastChecked();
String mess = truncateStatus(folder.getStatus()); String mess = truncateStatus(folder.getStatus());

View File

@ -495,41 +495,41 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
upperSignature.setVisibility(View.GONE); upperSignature.setVisibility(View.GONE);
} }
mSignatureView.addTextChangedListener(sigwatcher); mSignatureView.addTextChangedListener(sigwatcher);
if (!mSourceMessageProcessed) { if (!mSourceMessageProcessed) {
updateFrom(); updateFrom();
updateSignature(); updateSignature();
if (ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action) || ACTION_FORWARD.equals(action) || ACTION_EDIT_DRAFT.equals(action)) { if (ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action) || ACTION_FORWARD.equals(action) || ACTION_EDIT_DRAFT.equals(action)) {
/* /*
* If we need to load the message we add ourself as a message listener here * If we need to load the message we add ourself as a message listener here
* so we can kick it off. Normally we add in onResume but we don't * so we can kick it off. Normally we add in onResume but we don't
* want to reload the message every time the activity is resumed. * want to reload the message every time the activity is resumed.
* There is no harm in adding twice. * There is no harm in adding twice.
*/ */
MessagingController.getInstance(getApplication()).addListener(mListener); MessagingController.getInstance(getApplication()).addListener(mListener);
MessagingController.getInstance(getApplication()).loadMessageForView( mAccount, mFolder, mSourceMessageUid, null); MessagingController.getInstance(getApplication()).loadMessageForView( mAccount, mFolder, mSourceMessageUid, null);
}
if (!ACTION_EDIT_DRAFT.equals(action)) {
String bccAddress = mAccount.getAlwaysBcc();
if (bccAddress!=null
&& !"".equals(bccAddress)) {
addAddress(mBccView, new Address(mAccount.getAlwaysBcc(), ""));
}
}
Log.d(Email.LOG_TAG, "action = " + action + ", mAccount = " + mAccount + ", mFolder = " + mFolder + ", mSourceMessageUid = " + mSourceMessageUid);
if ((ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action)) && mAccount != null && mFolder != null && mSourceMessageUid != null) {
Log.d(Email.LOG_TAG, "Setting message ANSWERED flag to true");
// TODO: Really, we should wait until we send the message, but that would require saving the original
// message info along with a Draft copy, in case it is left in Drafts for a while before being sent
MessagingController.getInstance(getApplication()).setMessageFlag(mAccount, mFolder, mSourceMessageUid, Flag.ANSWERED, true);
}
updateTitle();
} }
if (!ACTION_EDIT_DRAFT.equals(action)) {
String bccAddress = mAccount.getAlwaysBcc();
if (bccAddress!=null
&& !"".equals(bccAddress)) {
addAddress(mBccView, new Address(mAccount.getAlwaysBcc(), ""));
}
}
Log.d(Email.LOG_TAG, "action = " + action + ", mAccount = " + mAccount + ", mFolder = " + mFolder + ", mSourceMessageUid = " + mSourceMessageUid);
if ((ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action)) && mAccount != null && mFolder != null && mSourceMessageUid != null) {
Log.d(Email.LOG_TAG, "Setting message ANSWERED flag to true");
// TODO: Really, we should wait until we send the message, but that would require saving the original
// message info along with a Draft copy, in case it is left in Drafts for a while before being sent
MessagingController.getInstance(getApplication()).setMessageFlag(mAccount, mFolder, mSourceMessageUid, Flag.ANSWERED, true);
}
updateTitle();
}
if (ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action) || ACTION_EDIT_DRAFT.equals(action)) { if (ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action) || ACTION_EDIT_DRAFT.equals(action)) {
//change focus to message body. //change focus to message body.
mMessageContentView.requestFocus(); mMessageContentView.requestFocus();

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.LocalFolder;
import com.android.email.mail.store.LocalStore.LocalMessage; 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 * MessageList is the primary user interface for the program. This
@ -82,21 +77,15 @@ import java.util.concurrent.TimeUnit;
public class MessageList extends K9ListActivity { 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 DIALOG_MARK_ALL_AS_READ = 1;
private static final int ACTIVITY_CHOOSE_FOLDER_MOVE = 1; private static final int ACTIVITY_CHOOSE_FOLDER_MOVE = 1;
private static final int ACTIVITY_CHOOSE_FOLDER_COPY = 2; 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_ACCOUNT = "account";
private static final String EXTRA_STARTUP = "startup"; 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 EXTRA_FOLDER = "folder";
private static final String STATE_KEY_LIST = "com.android.email.activity.messagelist_state"; 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 String mFolderName;
private boolean mRestoringState;
private boolean mRefreshRemote;
private MessageListHandler mHandler = new MessageListHandler(); private MessageListHandler mHandler = new MessageListHandler();
private DateFormat dateFormat = null; private DateFormat dateFormat = null;
@ -165,8 +149,6 @@ public class MessageList extends K9ListActivity {
private boolean mStartup = false; private boolean mStartup = false;
private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 1, 120000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
private DateFormat getDateFormat() { private DateFormat getDateFormat() {
if (dateFormat == null) { if (dateFormat == null) {
String dateFormatS = android.provider.Settings.System.getString(getContentResolver(), String dateFormatS = android.provider.Settings.System.getString(getContentResolver(),
@ -232,23 +214,28 @@ public class MessageList extends K9ListActivity {
break; break;
case MSG_REMOVE_MESSAGE: { case MSG_REMOVE_MESSAGE: {
MessageInfoHolder message = (MessageInfoHolder)((Object[]) msg.obj)[1]; List<MessageInfoHolder> messages = (List<MessageInfoHolder>)((Object[]) msg.obj)[0];
mAdapter.messages.remove(message); for (MessageInfoHolder message : messages)
{
mAdapter.messages.remove(message);
}
mAdapter.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();
break; break;
} }
case MSG_ADD_MESSAGE: { 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)
{ {
index = (index * -1) - 1; int index = Collections.binarySearch( mAdapter.messages, message);
if (index < 0)
{
index = (index * -1) - 1;
}
mAdapter.messages.add(index, message);
} }
mAdapter.messages.add(index, message);
mAdapter.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();
break; break;
} }
@ -270,7 +257,7 @@ public class MessageList extends K9ListActivity {
case MSG_FOLDER_LOADING: case MSG_FOLDER_LOADING:
{ {
FolderInfoHolder folder = mAdapter.getFolder((String) msg.obj); FolderInfoHolder folder = mCurrentFolder;
if (folder != null) if (folder != null)
{ {
folder.loading = msg.arg1 != 0; 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(); android.os.Message msg = new android.os.Message();
msg.what = MSG_REMOVE_MESSAGE; msg.what = MSG_REMOVE_MESSAGE;
msg.obj = new Object[] { message.folder, message }; msg.obj = new Object[] { messages };
sendMessage(msg); sendMessage(msg);
} }
public void addMessage(MessageInfoHolder message) { public void addMessages(List<MessageInfoHolder> messages) {
android.os.Message msg = new android.os.Message(); android.os.Message msg = new android.os.Message();
msg.what = MSG_ADD_MESSAGE; msg.what = MSG_ADD_MESSAGE;
msg.obj = new Object[] { message.folder, message }; msg.obj = new Object[] { messages };
sendMessage(msg); sendMessage(msg);
} }
@ -412,9 +399,8 @@ public class MessageList extends K9ListActivity {
MessagingController.getInstance(getApplication()).loadMoreMessages( MessagingController.getInstance(getApplication()).loadMoreMessages(
mAccount, mAccount,
mFolderName, mFolderName,
mAdapter.mListener); mAdapter.mListener);
onRefresh(FORCE_REMOTE_SYNC);
return; return;
} else { } else {
MessageInfoHolder message = (MessageInfoHolder) mAdapter.getItem( itemPosition); MessageInfoHolder message = (MessageInfoHolder) mAdapter.getItem( itemPosition);
@ -432,15 +418,20 @@ public class MessageList extends K9ListActivity {
colorChipResId = colorChipResIds[mAccount.getAccountNumber() % colorChipResIds.length]; colorChipResId = colorChipResIds[mAccount.getAccountNumber() % colorChipResIds.length];
mAdapter = new MessageListAdapter(); mAdapter = new MessageListAdapter();
final Object previousData = getLastNonConfigurationInstance();
if (previousData != null) {
//noinspection unchecked
mAdapter.messages.addAll((List<MessageInfoHolder>) previousData);
}
mCurrentFolder = mAdapter.getFolder(mFolderName); mCurrentFolder = mAdapter.getFolder(mFolderName);
setListAdapter(mAdapter); setListAdapter(mAdapter);
if (savedInstanceState != null) { if (savedInstanceState != null) {
mRestoringState = true;
onRestoreListState(savedInstanceState); onRestoreListState(savedInstanceState);
mRestoringState = false;
} }
setTitle( setTitle(
@ -488,7 +479,7 @@ public class MessageList extends K9ListActivity {
MessagingController.getInstance(getApplication()).addListener( mAdapter.mListener); 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); NotificationManager notifMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notifMgr.cancel(mAccount.getAccountNumber()); notifMgr.cancel(mAccount.getAccountNumber());
@ -505,8 +496,9 @@ public class MessageList extends K9ListActivity {
} }
@Override public Object onRetainNonConfigurationInstance() {
return mAdapter.messages;
}
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
@ -515,7 +507,9 @@ public class MessageList extends K9ListActivity {
switch (keyCode) { switch (keyCode) {
case KeyEvent.KEYCODE_C: { onCompose(); return true;} 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; } 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) { 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 * 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 * 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(); 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() { private void onShowFolderList() {
// If we're a child activity (say because Welcome dropped us straight to the message list if (mStartup || isTaskRoot())
// we won't have a parent activity and we'll need to get back to it {
if (mStartup
|| isTaskRoot()) {
FolderList.actionHandleAccount(this, mAccount, false); FolderList.actionHandleAccount(this, mAccount, false);
} }
finish(); finish();
} }
@ -642,7 +616,12 @@ public class MessageList extends K9ListActivity {
mHandler.sortMessages(); mHandler.sortMessages();
} }
private void onAccounts() {
Accounts.listAccounts(this);
finish();
}
private void onCycleSort() { private void onCycleSort() {
SORT_TYPE[] sorts = SORT_TYPE.values(); SORT_TYPE[] sorts = SORT_TYPE.values();
int curIndex = 0; int curIndex = 0;
@ -677,11 +656,11 @@ public class MessageList extends K9ListActivity {
holder.folder.unreadMessageCount--; holder.folder.unreadMessageCount--;
} }
FolderInfoHolder trashHolder = mAdapter.getFolder(mAccount.getTrashFolderName()); // FolderInfoHolder trashHolder = mAdapter.getFolder(mAccount.getTrashFolderName());
//
if (trashHolder != null) { // if (trashHolder != null) {
trashHolder.needsRefresh = true; // trashHolder.needsRefresh = true;
} // }
mAdapter.removeMessage(holder); mAdapter.removeMessage(holder);
mListView.setSelection(position); mListView.setSelection(position);
@ -741,26 +720,22 @@ public class MessageList extends K9ListActivity {
String destFolderName = data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER); String destFolderName = data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER);
String srcFolderName = data.getStringExtra(ChooseFolder.EXTRA_CUR_FOLDER);
String uid = data.getStringExtra(ChooseFolder.EXTRA_MESSAGE_UID); String uid = data.getStringExtra(ChooseFolder.EXTRA_MESSAGE_UID);
FolderInfoHolder srcHolder = mAdapter.getFolder(srcFolderName); FolderInfoHolder srcHolder = mCurrentFolder;
FolderInfoHolder destHolder = mAdapter.getFolder(destFolderName); if (srcHolder != null && destFolderName != null) {
if (srcHolder != null && destHolder != null) {
MessageInfoHolder m = mAdapter.getMessage( uid); MessageInfoHolder m = mAdapter.getMessage( uid);
if (m != null) { if (m != null) {
switch (requestCode) { switch (requestCode) {
case ACTIVITY_CHOOSE_FOLDER_MOVE: case ACTIVITY_CHOOSE_FOLDER_MOVE:
onMoveChosen(m, destHolder); onMoveChosen(m, destFolderName);
break; break;
case ACTIVITY_CHOOSE_FOLDER_COPY: case ACTIVITY_CHOOSE_FOLDER_COPY:
onCopyChosen(m, destHolder); onCopyChosen(m, destFolderName);
break; 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) { if (MessagingController.getInstance(getApplication()).isMoveCapable(mAccount) == false) {
return; return;
} }
// String destFolderName = folder.name; if (folderName == null) {
// FolderInfoHolder destHolder = mAdapter.getFolder(destFolderName);
//
if (folder == null) {
return; return;
} }
@ -786,35 +758,23 @@ public class MessageList extends K9ListActivity {
if (holder.folder.unreadMessageCount > 0) { if (holder.folder.unreadMessageCount > 0) {
holder.folder.unreadMessageCount--; holder.folder.unreadMessageCount--;
} }
folder.unreadMessageCount++;
} }
folder.needsRefresh = true;
mAdapter.removeMessage(holder); 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) { if (MessagingController.getInstance(getApplication()).isCopyCapable(mAccount) == false) {
return; return;
} }
if (folderName == null) {
if (folder == null) {
return; return;
} }
if (holder.read == false) {
folder.unreadMessageCount++;
}
folder.needsRefresh = true;
MessagingController.getInstance(getApplication()).copyMessage(mAccount, 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) { private void onMarkAllAsRead(final Account account, final String folder) {
showDialog(DIALOG_MARK_ALL_AS_READ); showDialog(DIALOG_MARK_ALL_AS_READ);
} }
@ -916,12 +875,13 @@ public class MessageList extends K9ListActivity {
mHandler.sortMessages(); 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) { private void checkMail(Account account, String folderName) {
MessagingController.getInstance(getApplication()).synchronizeMailbox(account, folderName, mAdapter.mListener); MessagingController.getInstance(getApplication()).synchronizeMailbox(account, folderName, mAdapter.mListener);
sendMail(account);
}
private void sendMail(Account account) {
MessagingController.getInstance(getApplication()).sendPendingMessages(account, mAdapter.mListener);
} }
@Override @Override
@ -930,12 +890,20 @@ public class MessageList extends K9ListActivity {
case R.id.check_mail: case R.id.check_mail:
checkMail(mAccount, mFolderName); checkMail(mAccount, mFolderName);
return true; return true;
case R.id.send_messages:
sendMail(mAccount);
return true;
case R.id.compose: case R.id.compose:
onCompose(); onCompose();
return true; return true;
case R.id.accounts:
onAccounts();
return true;
case R.id.set_sort_date: case R.id.set_sort_date:
changeSort(SORT_TYPE.SORT_DATE); changeSort(SORT_TYPE.SORT_DATE);
@ -995,6 +963,13 @@ public class MessageList extends K9ListActivity {
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.message_list_option, 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; return true;
} }
@ -1193,7 +1168,7 @@ public class MessageList extends K9ListActivity {
return; return;
} }
mHandler.sortMessages(); mHandler.sortMessages();
mHandler.progress(false); mHandler.progress(false);
mHandler.folderLoading(folder, false); mHandler.folderLoading(folder, false);
} }
@ -1204,7 +1179,8 @@ public class MessageList extends K9ListActivity {
return; return;
} }
mHandler.sortMessages(); mHandler.sortMessages();
mHandler.progress(false); mHandler.progress(false);
mHandler.folderLoading(folder, false); mHandler.folderLoading(folder, false);
} }
@ -1234,12 +1210,12 @@ public class MessageList extends K9ListActivity {
@Override @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)) { if (!account.equals(mAccount) || !folder.equals(mFolderName)) {
return; 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); 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) { public void removeMessage(MessageInfoHolder holder) {
if (holder == null) { List<MessageInfoHolder> messages = new ArrayList<MessageInfoHolder>();
return; messages.add(holder);
} removeMessages(messages);
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();
}
}
}
private void addOrUpdateMessage(String folder, Message message) { private void addOrUpdateMessage(String folder, Message message) {
FolderInfoHolder f = getFolder(folder); FolderInfoHolder f = mCurrentFolder;
if (f == null) { if (f == null) {
return; return;
@ -1304,6 +1263,60 @@ public class MessageList extends K9ListActivity {
addOrUpdateMessage(f, message); 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 // XXX TODO - make this not use a for loop
public MessageInfoHolder getMessage( String messageUid) { public MessageInfoHolder getMessage( String messageUid) {
@ -1444,20 +1457,23 @@ public class MessageList extends K9ListActivity {
footerView.setId(R.layout.message_list_item_footer); footerView.setId(R.layout.message_list_item_footer);
FooterViewHolder holder = new FooterViewHolder(); FooterViewHolder holder = new FooterViewHolder();
holder.progress = (ProgressBar)footerView.findViewById(R.id.message_list_progress); holder.progress = (ProgressBar)footerView.findViewById(R.id.message_list_progress);
holder.progress.setIndeterminate(true);
holder.main = (TextView)footerView.findViewById(R.id.main_text); holder.main = (TextView)footerView.findViewById(R.id.main_text);
footerView.setTag(holder); footerView.setTag(holder);
} }
FooterViewHolder holder = (FooterViewHolder)footerView.getTag(); FooterViewHolder holder = (FooterViewHolder)footerView.getTag();
if (mCurrentFolder.loading) { if (mCurrentFolder.loading) {
holder.main.setText(getString(R.string.status_loading_more)); holder.main.setText(getString(R.string.status_loading_more));
mHandler.progress(true); holder.progress.setVisibility(ProgressBar.VISIBLE);
} else { } else {
if (mCurrentFolder.lastCheckFailed == false) { if (mCurrentFolder.lastCheckFailed == false) {
holder.main.setText(String.format(getString(R.string.load_more_messages_fmt).toString(), mAccount.getDisplayCount())); holder.main.setText(String.format(getString(R.string.load_more_messages_fmt).toString(), mAccount.getDisplayCount()));
} else { } else {
holder.main.setText(getString(R.string.status_loading_more_failed)); holder.main.setText(getString(R.string.status_loading_more_failed));
} }
holder.progress.setVisibility(ProgressBar.INVISIBLE);
} }
return footerView; return footerView;

View File

@ -113,10 +113,6 @@ public class MessageView extends K9Activity
private DateFormat timeFormat = null; private DateFormat timeFormat = null;
private Menu optionsMenu = null; 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() private DateFormat getDateFormat()
{ {
@ -154,7 +150,23 @@ public class MessageView extends K9Activity
private Listener mListener = new Listener(); private Listener mListener = new Listener();
private MessageViewHandler mHandler = new MessageViewHandler(); private MessageViewHandler mHandler = new MessageViewHandler();
public boolean onKeyDown(int keyCode, KeyEvent event) {
@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) { switch (keyCode) {
case KeyEvent.KEYCODE_DEL: { onDelete(); return true;} case KeyEvent.KEYCODE_DEL: { onDelete(); return true;}
case KeyEvent.KEYCODE_D: { onDelete(); return true;} case KeyEvent.KEYCODE_D: { onDelete(); return true;}
@ -174,26 +186,26 @@ public class MessageView extends K9Activity
if (event.isShiftPressed()) { if (event.isShiftPressed()) {
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
public void run() { public void run() {
mMessageContentView.zoomIn(); mMessageContentView.zoomIn();
} }
}); });
} else { } else {
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
public void run() { public void run() {
mMessageContentView.zoomOut(); mMessageContentView.zoomOut();
} }
}); });
} }
return true; return true;
} }
case KeyEvent.KEYCODE_H: { case KeyEvent.KEYCODE_H: {
Toast toast = Toast.makeText(this, R.string.message_help_key, Toast.LENGTH_LONG); Toast toast = Toast.makeText(this, R.string.message_help_key, Toast.LENGTH_LONG);
toast.show(); toast.show();
return true; return true;
} }
} }
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
class MessageViewHandler extends Handler { class MessageViewHandler extends Handler {
private static final int MSG_PROGRESS = 2; private static final int MSG_PROGRESS = 2;
@ -448,11 +460,11 @@ public class MessageView extends K9Activity
Uri uri = intent.getData(); Uri uri = intent.getData();
if (uri==null) { if (uri==null) {
mAccount = (Account) intent.getSerializableExtra(EXTRA_ACCOUNT); mAccount = (Account) intent.getSerializableExtra(EXTRA_ACCOUNT);
mFolder = intent.getStringExtra(EXTRA_FOLDER); mFolder = intent.getStringExtra(EXTRA_FOLDER);
mMessageUid = intent.getStringExtra(EXTRA_MESSAGE); mMessageUid = intent.getStringExtra(EXTRA_MESSAGE);
mFolderUids = intent.getStringArrayListExtra(EXTRA_FOLDER_UIDS); mFolderUids = intent.getStringArrayListExtra(EXTRA_FOLDER_UIDS);
Log.v(Email.LOG_TAG, "mAccount number: " + mAccount.getAccountNumber()); Log.v(Email.LOG_TAG, "mAccount number: " + mAccount.getAccountNumber());
Log.v(Email.LOG_TAG, "mFolder: " + mFolder); Log.v(Email.LOG_TAG, "mFolder: " + mFolder);
Log.v(Email.LOG_TAG, "mMessageUid: " + mMessageUid); Log.v(Email.LOG_TAG, "mMessageUid: " + mMessageUid);
@ -495,7 +507,7 @@ public class MessageView extends K9Activity
next = findViewById(R.id.next); next = findViewById(R.id.next);
previous = findViewById(R.id.previous); previous = findViewById(R.id.previous);
setOnClickListener(R.id.next); setOnClickListener(R.id.next);
setOnClickListener(R.id.previous); setOnClickListener(R.id.previous);
@ -509,7 +521,7 @@ public class MessageView extends K9Activity
Account.HideButtons hideButtons = mAccount.getHideMessageViewButtons(); Account.HideButtons hideButtons = mAccount.getHideMessageViewButtons();
//MessagingController.getInstance(getApplication()).addListener(mListener); // MessagingController.getInstance(getApplication()).addListener(mListener);
if (Account.HideButtons.ALWAYS == hideButtons) if (Account.HideButtons.ALWAYS == hideButtons)
{ {
hideButtons(); hideButtons();
@ -521,7 +533,7 @@ public class MessageView extends K9Activity
else // Account.HideButtons.KEYBOARD_AVAIL else // Account.HideButtons.KEYBOARD_AVAIL
{ {
final Configuration config = this.getResources().getConfiguration(); final Configuration config = this.getResources().getConfiguration();
if (config.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO ) if (config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO )
{ {
hideButtons(); hideButtons();
} }
@ -595,7 +607,7 @@ public class MessageView extends K9Activity
super.onResume(); super.onResume();
clearFormats(); clearFormats();
} }
private void onDelete() { private void onDelete() {
if (mMessage != null) { if (mMessage != null) {
Message messageToDelete = mMessage; Message messageToDelete = mMessage;
@ -1172,8 +1184,8 @@ public class MessageView extends K9Activity
if (!message.isSet(Flag.X_DOWNLOADED_FULL)) { if (!message.isSet(Flag.X_DOWNLOADED_FULL)) {
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
public void run() { public void run() {
mMessageContentView.loadUrl("file:///android_asset/downloading.html"); mMessageContentView.loadUrl("file:///android_asset/downloading.html");
} }
}); });
} }
try { try {
@ -1232,8 +1244,8 @@ public class MessageView extends K9Activity
else { else {
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
public void run() { public void run() {
mMessageContentView.loadUrl("file:///android_asset/empty.html"); mMessageContentView.loadUrl("file:///android_asset/empty.html");
} }
}); });
} }
@ -1261,7 +1273,7 @@ public class MessageView extends K9Activity
mHandler.invalidIdError(); mHandler.invalidIdError();
} }
else { else {
mHandler.networkError(); mHandler.networkError();
} }
mMessageContentView.loadUrl("file:///android_asset/empty.html"); mMessageContentView.loadUrl("file:///android_asset/empty.html");
} }
@ -1291,7 +1303,7 @@ public class MessageView extends K9Activity
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
public void run() { public void run() {
mMessageContentView.loadUrl("file:///android_asset/loading.html"); mMessageContentView.loadUrl("file:///android_asset/loading.html");
setProgressBarIndeterminateVisibility(true); setProgressBarIndeterminateVisibility(true);
} }
}); });
} }
@ -1357,7 +1369,7 @@ public class MessageView extends K9Activity
} }
catch (Exception e) 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(); toast.show();
} }
} }

View File

@ -5,6 +5,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; 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.ChooseFolder;
import com.android.email.activity.ChooseIdentity; import com.android.email.activity.ChooseIdentity;
import com.android.email.activity.ManageIdentities; import com.android.email.activity.ManageIdentities;
import com.android.email.mail.Store;
public class AccountSettings extends K9PreferenceActivity { public class AccountSettings extends K9PreferenceActivity {
private static final String EXTRA_ACCOUNT = "account"; 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_OUTGOING = "outgoing";
private static final String PREFERENCE_DISPLAY_MODE = "folder_display_mode"; 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_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_TARGET_MODE = "folder_target_mode";
private static final String PREFERENCE_DELETE_POLICY = "delete_policy"; private static final String PREFERENCE_DELETE_POLICY = "delete_policy";
private static final String PREFERENCE_AUTO_EXPAND_FOLDER = "account_setup_auto_expand_folder"; 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 RingtonePreference mAccountRingtone;
private ListPreference mDisplayMode; private ListPreference mDisplayMode;
private ListPreference mSyncMode; private ListPreference mSyncMode;
private ListPreference mPushMode;
private ListPreference mTargetMode; private ListPreference mTargetMode;
private ListPreference mDeletePolicy; private ListPreference mDeletePolicy;
private Preference mAutoExpandFolder; private Preference mAutoExpandFolder;
@ -82,6 +86,18 @@ public class AccountSettings extends K9PreferenceActivity {
mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT); 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); addPreferencesFromResource(R.xml.account_settings_preferences);
Preference category = findPreference(PREFERENCE_TOP_CATERGORY); 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 = (ListPreference) findPreference(PREFERENCE_TARGET_MODE);
mTargetMode.setValue(mAccount.getFolderTargetMode().name()); mTargetMode.setValue(mAccount.getFolderTargetMode().name());
mTargetMode.setSummary(mTargetMode.getEntry()); mTargetMode.setSummary(mTargetMode.getEntry());
@ -274,6 +304,7 @@ public class AccountSettings extends K9PreferenceActivity {
mAccount.setVibrate(mAccountVibrate.isChecked()); mAccount.setVibrate(mAccountVibrate.isChecked());
mAccount.setFolderDisplayMode(Account.FolderMode.valueOf(mDisplayMode.getValue())); mAccount.setFolderDisplayMode(Account.FolderMode.valueOf(mDisplayMode.getValue()));
mAccount.setFolderSyncMode(Account.FolderMode.valueOf(mSyncMode.getValue())); mAccount.setFolderSyncMode(Account.FolderMode.valueOf(mSyncMode.getValue()));
mAccount.setFolderPushMode(Account.FolderMode.valueOf(mPushMode.getValue()));
mAccount.setFolderTargetMode(Account.FolderMode.valueOf(mTargetMode.getValue())); mAccount.setFolderTargetMode(Account.FolderMode.valueOf(mTargetMode.getValue()));
mAccount.setDeletePolicy(Integer.parseInt(mDeletePolicy.getValue())); mAccount.setDeletePolicy(Integer.parseInt(mDeletePolicy.getValue()));
SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences(); SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences();

View File

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

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_TOP_CATERGORY = "folder_settings";
private static final String PREFERENCE_DISPLAY_CLASS = "folder_settings_folder_display_mode"; 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_SYNC_CLASS = "folder_settings_folder_sync_mode";
private static final String PREFERENCE_PUSH_CLASS = "folder_settings_folder_push_mode";
private LocalFolder mFolder; private LocalFolder mFolder;
private ListPreference mDisplayClass; private ListPreference mDisplayClass;
private ListPreference mSyncClass; private ListPreference mSyncClass;
private ListPreference mPushClass;
public static void actionSettings(Context context, Account account, String folderName) { public static void actionSettings(Context context, Account account, String folderName) {
Intent i = new Intent(context, FolderSettings.class); Intent i = new Intent(context, FolderSettings.class);
@ -52,18 +54,30 @@ public class FolderSettings extends K9PreferenceActivity {
String folderName = (String)getIntent().getSerializableExtra(EXTRA_FOLDER_NAME); String folderName = (String)getIntent().getSerializableExtra(EXTRA_FOLDER_NAME);
Account mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT); Account mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
try try
{ {
Store localStore = Store.getInstance(mAccount.getLocalStoreUri(), Store localStore = Store.getInstance(mAccount.getLocalStoreUri(),
getApplication()); getApplication());
mFolder = (LocalFolder) localStore.getFolder(folderName); mFolder = (LocalFolder) localStore.getFolder(folderName);
mFolder.refresh(Preferences.getPreferences(this)); mFolder.refresh(Preferences.getPreferences(this));
} }
catch (MessagingException me) catch (MessagingException me)
{ {
Log.e(Email.LOG_TAG, "Unable to edit folder " + folderName + " preferences", me); Log.e(Email.LOG_TAG, "Unable to edit folder " + folderName + " preferences", me);
return; 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); addPreferencesFromResource(R.xml.folder_settings_preferences);
@ -95,6 +109,20 @@ public class FolderSettings extends K9PreferenceActivity {
return false; 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 @Override
@ -113,10 +141,12 @@ public class FolderSettings extends K9PreferenceActivity {
private void saveSettings() { private void saveSettings() {
mFolder.setDisplayClass(FolderClass.valueOf(mDisplayClass.getValue())); mFolder.setDisplayClass(FolderClass.valueOf(mDisplayClass.getValue()));
mFolder.setSyncClass(FolderClass.valueOf(mSyncClass.getValue())); mFolder.setSyncClass(FolderClass.valueOf(mSyncClass.getValue()));
mFolder.setPushClass(FolderClass.valueOf(mPushClass.getValue()));
try try
{ {
mFolder.save(Preferences.getPreferences(this)); mFolder.save(Preferences.getPreferences(this));
Email.setServicesEnabled(this);
} }
catch (MessagingException me) catch (MessagingException me)
{ {

View File

@ -6,12 +6,13 @@ import com.android.email.Preferences;
public abstract class Folder { public abstract class Folder {
private String status = null; private String status = null;
private long lastChecked = 0; private long lastChecked = 0;
private long lastPush = 0;
public enum OpenMode { public enum OpenMode {
READ_WRITE, READ_ONLY, 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 { public enum FolderClass {
NONE, FIRST_CLASS, SECOND_CLASS; NONE, NO_CLASS, INHERITED, FIRST_CLASS, SECOND_CLASS;
} }
public enum FolderType { public enum FolderType {
@ -109,6 +110,17 @@ public abstract class Folder {
public abstract String getName(); public abstract String getName();
public abstract Flag[] getPermanentFlags() throws MessagingException; 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() { public boolean supportsFetchingFlags() {
return true; return true;
@ -129,15 +141,34 @@ public abstract class Folder {
this.lastChecked = lastChecked; 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() public FolderClass getDisplayClass()
{ {
return FolderClass.NONE; return FolderClass.NO_CLASS;
} }
public FolderClass getSyncClass() public FolderClass getSyncClass()
{ {
return getDisplayClass(); return getDisplayClass();
} }
public FolderClass getPushClass()
{
return getSyncClass();
}
public void refresh(Preferences preferences) throws MessagingException public void refresh(Preferences preferences) throws MessagingException
{ {
@ -154,6 +185,5 @@ public abstract class Folder {
this.status = status; this.status = status;
} }
} }

View File

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

View File

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

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; package com.android.email.mail;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import android.app.Application; import android.app.Application;
@ -85,5 +86,13 @@ public abstract class Store {
public boolean isMoveCapable() { public boolean isMoveCapable() {
return false; 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 { public Object readToken() throws IOException {
while (true) { while (true) {
Object token = parseToken(); Object token = parseToken();
if (token == null || !token.equals(")")) { if (token == null || !token.equals(")") || !token.equals("]")) {
return token; return token;
} }
} }
@ -107,9 +107,14 @@ public class ImapResponseParser {
int ch = mIn.peek(); int ch = mIn.peek();
if (ch == '(') { if (ch == '(') {
return parseList(); return parseList();
} else if (ch == '[') {
return parseSequence();
} else if (ch == ')') { } else if (ch == ')') {
expect(')'); expect(')');
return ")"; return ")";
} else if (ch == ']') {
expect(']');
return "]";
} else if (ch == '"') { } else if (ch == '"') {
return parseQuoted(); return parseQuoted();
} else if (ch == '{') { } else if (ch == '{') {
@ -169,6 +174,26 @@ public class ImapResponseParser {
} }
return list; 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 { private String parseAtom() throws IOException {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
@ -178,6 +203,7 @@ public class ImapResponseParser {
if (ch == -1) { if (ch == -1) {
throw new IOException("parseAtom(): end of stream reached"); throw new IOException("parseAtom(): end of stream reached");
} else if (ch == '(' || ch == ')' || ch == '{' || ch == ' ' || } else if (ch == '(' || ch == ')' || ch == '{' || ch == ' ' ||
ch == '[' || ch == ']' ||
// docs claim that flags are \ atom but atom isn't supposed to // docs claim that flags are \ atom but atom isn't supposed to
// contain // contain
// * and some falgs 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> * </pre>
*/ */
public class LocalStore extends Store implements Serializable { 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 static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN };
private String mPath; private String mPath;
@ -133,7 +133,7 @@ public class LocalStore extends Store implements Serializable {
mDb.execSQL("DROP TABLE IF EXISTS folders"); mDb.execSQL("DROP TABLE IF EXISTS folders");
mDb.execSQL("CREATE TABLE folders (id INTEGER PRIMARY KEY, name TEXT, " 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("CREATE INDEX IF NOT EXISTS folder_name ON folders (name)");
mDb.execSQL("DROP TABLE IF EXISTS messages"); mDb.execSQL("DROP TABLE IF EXISTS messages");
@ -273,10 +273,10 @@ public class LocalStore extends Store implements Serializable {
try { 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()) { while (cursor.moveToNext()) {
LocalFolder folder = new LocalFolder(cursor.getString(0)); 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); folders.add(folder);
} }
@ -489,9 +489,11 @@ public class LocalStore extends Store implements Serializable {
private long mFolderId = -1; private long mFolderId = -1;
private int mUnreadMessageCount = -1; private int mUnreadMessageCount = -1;
private int mVisibleLimit = -1; private int mVisibleLimit = -1;
private FolderClass displayClass = FolderClass.NONE; private FolderClass displayClass = FolderClass.NO_CLASS;
private FolderClass syncClass = FolderClass.NONE; private FolderClass syncClass = FolderClass.INHERITED;
private FolderClass pushClass = FolderClass.SECOND_CLASS;
private String prefId = null; private String prefId = null;
private String mPushState = null;
public LocalFolder(String name) { public LocalFolder(String name) {
this.mName = name; this.mName = name;
@ -499,7 +501,9 @@ public class LocalStore extends Store implements Serializable {
if (Email.INBOX.equals(getName())) if (Email.INBOX.equals(getName()))
{ {
syncClass = FolderClass.FIRST_CLASS; syncClass = FolderClass.FIRST_CLASS;
pushClass = FolderClass.FIRST_CLASS;
} }
} }
@ -514,7 +518,7 @@ public class LocalStore extends Store implements Serializable {
} }
Cursor cursor = null; Cursor cursor = null;
try { 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 = ?", + "where folders.name = ?",
new String[] { new String[] {
mName mName
@ -524,7 +528,7 @@ public class LocalStore extends Store implements Serializable {
int folderId = cursor.getInt(0); int folderId = cursor.getInt(0);
if (folderId > 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 { } else {
create(FolderType.HOLDS_MESSAGES); 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; mFolderId = id;
mUnreadMessageCount = unreadCount; mUnreadMessageCount = unreadCount;
mVisibleLimit = visibleLimit; mVisibleLimit = visibleLimit;
mPushState = pushState;
super.setStatus(status); super.setStatus(status);
// Only want to set the local variable stored in the super class. This class // Only want to set the local variable stored in the super class. This class
// does a DB update on setLastChecked // does a DB update on setLastChecked
super.setLastChecked(lastChecked); super.setLastChecked(lastChecked);
super.setLastPush(lastPushed);
} }
@Override @Override
@ -655,6 +661,13 @@ public class LocalStore extends Store implements Serializable {
mDb.execSQL("UPDATE folders SET last_updated = ? WHERE id = ?", mDb.execSQL("UPDATE folders SET last_updated = ? WHERE id = ?",
new Object[] { lastChecked, mFolderId }); 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 { public int getVisibleLimit() throws MessagingException {
open(OpenMode.READ_WRITE); open(OpenMode.READ_WRITE);
@ -676,6 +689,17 @@ public class LocalStore extends Store implements Serializable {
mDb.execSQL("UPDATE folders SET status = ? WHERE id = ?", mDb.execSQL("UPDATE folders SET status = ? WHERE id = ?",
new Object[] { status, mFolderId }); 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 @Override
public FolderClass getDisplayClass() public FolderClass getDisplayClass()
{ {
@ -685,9 +709,9 @@ public class LocalStore extends Store implements Serializable {
@Override @Override
public FolderClass getSyncClass() public FolderClass getSyncClass()
{ {
if (FolderClass.NONE == syncClass) if (FolderClass.INHERITED == syncClass)
{ {
return displayClass; return getDisplayClass();
} }
else else
{ {
@ -697,10 +721,27 @@ public class LocalStore extends Store implements Serializable {
public FolderClass getRawSyncClass() public FolderClass getRawSyncClass()
{ {
return syncClass; return syncClass;
} }
public FolderClass getPushClass()
{
if (FolderClass.INHERITED == pushClass)
{
return getSyncClass();
}
else
{
return pushClass;
}
}
public FolderClass getRawPushClass()
{
return pushClass;
}
public void setDisplayClass(FolderClass displayClass) public void setDisplayClass(FolderClass displayClass)
{ {
@ -711,6 +752,10 @@ public class LocalStore extends Store implements Serializable {
{ {
this.syncClass = syncClass; this.syncClass = syncClass;
} }
public void setPushClass(FolderClass pushClass)
{
this.pushClass = pushClass;
}
private String getPrefId() throws MessagingException private String getPrefId() throws MessagingException
{ {
@ -740,7 +785,7 @@ public class LocalStore extends Store implements Serializable {
SharedPreferences.Editor editor = preferences.getPreferences().edit(); 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 // 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"); editor.remove(id + ".displayMode");
} }
@ -749,7 +794,7 @@ public class LocalStore extends Store implements Serializable {
editor.putString(id + ".displayMode", displayClass.name()); 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"); editor.remove(id + ".syncMode");
} }
@ -757,6 +802,15 @@ public class LocalStore extends Store implements Serializable {
{ {
editor.putString(id + ".syncMode", syncClass.name()); 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(); editor.commit();
} }
@ -767,17 +821,21 @@ public class LocalStore extends Store implements Serializable {
try try
{ {
displayClass = FolderClass.valueOf(preferences.getPreferences().getString(id + ".displayMode", displayClass = FolderClass.valueOf(preferences.getPreferences().getString(id + ".displayMode",
FolderClass.NONE.name())); FolderClass.NO_CLASS.name()));
} }
catch (Exception e) catch (Exception e)
{ {
Log.e(Email.LOG_TAG, "Unable to load displayMode for " + getName(), 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())) if (Email.INBOX.equals(getName()))
{ {
defSyncClass = FolderClass.FIRST_CLASS; defSyncClass = FolderClass.FIRST_CLASS;
@ -794,6 +852,32 @@ public class LocalStore extends Store implements Serializable {
syncClass = defSyncClass; 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++; i++;
} }
populateHeaders(messagesForHeaders); populateHeaders(messagesForHeaders);
if (listener != null) {
listener.messagesFinished(i);
}
} }
finally { finally {
if (cursor != null) { if (cursor != null) {
@ -1085,9 +1171,7 @@ public class LocalStore extends Store implements Serializable {
LocalMessage lMessage = (LocalMessage)message; LocalMessage lMessage = (LocalMessage)message;
if (!message.isSet(Flag.SEEN)) { if (!message.isSet(Flag.SEEN)) {
if (getUnreadMessageCount() > 0) { setUnreadMessageCount(getUnreadMessageCount() - 1);
setUnreadMessageCount(getUnreadMessageCount() - 1);
}
lDestFolder.setUnreadMessageCount(lDestFolder.getUnreadMessageCount() + 1); lDestFolder.setUnreadMessageCount(lDestFolder.getUnreadMessageCount() + 1);
} }
@ -1105,6 +1189,7 @@ public class LocalStore extends Store implements Serializable {
LocalMessage placeHolder = new LocalMessage(oldUID, this); LocalMessage placeHolder = new LocalMessage(oldUID, this);
placeHolder.setFlagInternal(Flag.DELETED, true); placeHolder.setFlagInternal(Flag.DELETED, true);
placeHolder.setFlagInternal(Flag.SEEN, true);
appendMessages(new Message[] { placeHolder }); appendMessages(new Message[] { placeHolder });
} }
@ -1139,6 +1224,11 @@ public class LocalStore extends Store implements Serializable {
message.setUid(Email.LOCAL_UID_PREFIX + UUID.randomUUID().toString()); message.setUid(Email.LOCAL_UID_PREFIX + UUID.randomUUID().toString());
} }
else { 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. * 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); saveAttachment(messageId, attachment, copy);
} }
saveHeaders(messageId, (MimeMessage)message); saveHeaders(messageId, (MimeMessage)message);
if (message.isSet(Flag.SEEN) == false)
{
setUnreadMessageCount(getUnreadMessageCount() + 1);
}
} catch (Exception e) { } catch (Exception e) {
throw new MessagingException("Error appending message", e); throw new MessagingException("Error appending message", e);
} }
@ -1473,6 +1567,28 @@ public class LocalStore extends Store implements Serializable {
open(OpenMode.READ_ONLY); open(OpenMode.READ_ONLY);
mDb.execSQL("DELETE FROM messages WHERE folder_id = ? and date < ?", new Object[] { mDb.execSQL("DELETE FROM messages WHERE folder_id = ? and date < ?", new Object[] {
Long.toString(mFolderId), new Long(cutoff) } ); 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 @Override
@ -1760,7 +1876,8 @@ public class LocalStore extends Store implements Serializable {
* Update the unread count on the folder. * Update the unread count on the folder.
*/ */
try { 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; LocalFolder folder = (LocalFolder)mFolder;
if (set && !isSet(Flag.SEEN)) { if (set && !isSet(Flag.SEEN)) {
folder.setUnreadMessageCount(folder.getUnreadMessageCount() - 1); folder.setUnreadMessageCount(folder.getUnreadMessageCount() - 1);

View File

@ -2,8 +2,9 @@
package com.android.email.service; package com.android.email.service;
import com.android.email.Email; import com.android.email.Email;
import android.net.ConnectivityManager;
import android.util.Log; import android.util.Log;
import com.android.email.MessagingController;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
@ -22,5 +23,9 @@ public class BootReceiver extends BroadcastReceiver {
else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(intent.getAction())) { else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(intent.getAction())) {
MailService.actionReschedule(context); 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; package com.android.email.service;
import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@ -11,14 +12,15 @@ import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.Context; import android.content.Context;
import android.content.Intent; 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.IBinder;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.PowerManager.WakeLock; import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.util.Config; import android.util.Config;
import android.util.Log; import android.util.Log;
import android.text.TextUtils;
import android.net.Uri;
import com.android.email.Account; import com.android.email.Account;
import com.android.email.Email; import com.android.email.Email;
@ -26,29 +28,51 @@ import com.android.email.MessagingController;
import com.android.email.MessagingListener; import com.android.email.MessagingListener;
import com.android.email.Preferences; import com.android.email.Preferences;
import com.android.email.R; import com.android.email.R;
import com.android.email.activity.Accounts; import com.android.email.mail.Address;
import com.android.email.activity.FolderList; import com.android.email.mail.Message;
import com.android.email.mail.Folder;
import com.android.email.mail.MessagingException; 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 { 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_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_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_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 Listener mListener = new Listener();
private State state = null;
private int mStartId; private int mStartId;
public static void actionReschedule(Context context) { public static void actionReschedule(Context context) {
Intent i = new Intent(); Intent i = new Intent();
i.setClass(context, MailService.class); i.setClass(context, MailService.class);
i.setAction(MailService.ACTION_RESCHEDULE); i.setAction(MailService.ACTION_RESCHEDULE);
context.startService(i); 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) { public static void actionCancel(Context context) {
Intent i = new Intent(); Intent i = new Intent();
@ -56,6 +80,14 @@ public class MailService extends Service {
i.setAction(MailService.ACTION_CANCEL); i.setAction(MailService.ACTION_CANCEL);
context.startService(i); 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 @Override
public void onCreate() { public void onCreate() {
@ -65,54 +97,173 @@ public class MailService extends Service {
@Override @Override
public void onStart(Intent intent, int startId) { public void onStart(Intent intent, int startId) {
setForeground(true); // if it gets killed once, it'll never restart
Log.v(Email.LOG_TAG, "***** MailService *****: onStart(" + intent + ", " + startId + ")"); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
super.onStart(intent, startId); WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email");
this.mStartId = startId; wakeLock.setReferenceCounted(false);
wakeLock.acquire(Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT);
// MessagingController.getInstance(getApplication()).addListener(mListener); try
if (ACTION_CHECK_MAIL.equals(intent.getAction())) { {
//if (Config.LOGV) {
MessagingController.getInstance(getApplication()).log("***** MailService *****: checking mail"); ConnectivityManager connectivityManager = (ConnectivityManager)getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
Log.v(Email.LOG_TAG, "***** MailService *****: checking mail"); state = State.DISCONNECTED;
//} if (connectivityManager != null)
MessagingController controller = MessagingController.getInstance(getApplication());
Listener listener = (Listener)controller.getCheckMailListener();
if (listener == null)
{ {
MessagingController.getInstance(getApplication()).log("***** MailService *****: starting new check"); NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
if (netInfo != null)
mListener.wakeLockAcquire(); {
controller.setCheckMailListener(mListener); state = netInfo.getState();
controller.checkMail(this, null, false, false, mListener);
if (state == State.CONNECTED)
{
Log.i(Email.LOG_TAG, "Currently connected to a network");
}
else
{
Log.i(Email.LOG_TAG, "Current network state = " + state);
}
}
} }
else
setForeground(true); // if it gets killed once, it'll never restart
Log.v(Email.LOG_TAG, "***** MailService *****: onStart(" + intent + ", " + startId + ")");
super.onStart(intent, startId);
this.mStartId = startId;
// MessagingController.getInstance(getApplication()).addListener(mListener);
if (ACTION_CHECK_MAIL.equals(intent.getAction())) {
//if (Config.LOGV) {
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)
{
MessagingController.getInstance(getApplication()).log("***** MailService *****: starting new check");
mListener.wakeLockAcquire();
controller.setCheckMailListener(mListener);
controller.checkMail(this, null, false, false, mListener);
}
else
{
MessagingController.getInstance(getApplication()).log("***** MailService *****: renewing WakeLock");
listener.wakeLockAcquire();
}
}
reschedule();
// stopSelf(startId);
}
else if (ACTION_CANCEL.equals(intent.getAction())) {
if (Config.LOGV) {
Log.v(Email.LOG_TAG, "***** MailService *****: cancel");
}
MessagingController.getInstance(getApplication()).log("***** MailService *****: cancel");
cancel();
// stopSelf(startId);
}
else if (ACTION_RESCHEDULE.equals(intent.getAction())) {
if (Config.LOGV) {
Log.v(Email.LOG_TAG, "***** MailService *****: reschedule");
}
MessagingController.getInstance(getApplication()).log("***** MailService *****: 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()))
{ {
MessagingController.getInstance(getApplication()).log("***** MailService *****: renewing WakeLock"); schedulePushers();
try
listener.wakeLockAcquire(); {
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
} }
reschedule();
// stopSelf(startId);
} }
else if (ACTION_CANCEL.equals(intent.getAction())) { finally
if (Config.LOGV) { {
Log.v(Email.LOG_TAG, "***** MailService *****: cancel"); if (wakeLock != null)
{
wakeLock.release();
} }
MessagingController.getInstance(getApplication()).log("***** MailService *****: cancel");
cancel();
// stopSelf(startId);
} }
else if (ACTION_RESCHEDULE.equals(intent.getAction())) { }
if (Config.LOGV) {
Log.v(Email.LOG_TAG, "***** MailService *****: reschedule"); private void notifyConnectionStatus(boolean hasConnectivity)
} {
MessagingController.getInstance(getApplication()).log("***** MailService *****: reschedule"); NotificationManager notifMgr =
reschedule(); (NotificationManager)getApplication().getSystemService(Context.NOTIFICATION_SERVICE);
// stopSelf(startId); 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);
} }
} }
@ -132,13 +283,14 @@ public class MailService extends Service {
alarmMgr.cancel(pi); alarmMgr.cancel(pi);
} }
private void reschedule() { private boolean reschedule() {
boolean polling = true;
AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(); Intent i = new Intent();
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService"); i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
i.setAction(ACTION_CHECK_MAIL); i.setAction(ACTION_CHECK_MAIL);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0); PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
int shortestInterval = -1; int shortestInterval = -1;
for (Account account : Preferences.getPreferences(this).getAccounts()) { for (Account account : Preferences.getPreferences(this).getAccounts()) {
@ -151,7 +303,7 @@ public class MailService extends Service {
if (shortestInterval == -1) { if (shortestInterval == -1) {
Log.v(Email.LOG_TAG, "No next check scheduled for package " + getApplication().getPackageName()); Log.v(Email.LOG_TAG, "No next check scheduled for package " + getApplication().getPackageName());
alarmMgr.cancel(pi); alarmMgr.cancel(pi);
stopSelf(mStartId); polling = false;
} }
else else
{ {
@ -172,7 +324,70 @@ public class MailService extends Service {
alarmMgr.set(AlarmManager.RTC_WAKEUP, nextTime, pi); 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) { public IBinder onBind(Intent intent) {
@ -244,46 +459,16 @@ public class MailService extends Service {
NotificationManager notifMgr = NotificationManager notifMgr =
(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
int index = 0;
for (Account thisAccount : Preferences.getPreferences(context).getAccounts()) { for (Account thisAccount : Preferences.getPreferences(context).getAccounts()) {
Integer newMailCount = accountsChecked.get(thisAccount.getUuid()); Integer newMailCount = accountsChecked.get(thisAccount.getUuid());
int unreadMessageCount = -1;
if (newMailCount != null) if (newMailCount != null)
{ {
try try
{ {
unreadMessageCount = thisAccount.getUnreadMessageCount(context, getApplication()); int unreadMessageCount = thisAccount.getUnreadMessageCount(context, getApplication());
if (unreadMessageCount > 0 && newMailCount > 0) if (unreadMessageCount > 0 && newMailCount > 0)
{ {
String notice = getString(R.string.notification_new_one_account_fmt, unreadMessageCount, MessagingController.getInstance(getApplication()).notifyAccount(context, thisAccount, 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);
} }
else if (unreadMessageCount == 0) else if (unreadMessageCount == 0)
{ {
@ -298,7 +483,8 @@ public class MailService extends Service {
} }
}//for accounts }//for accounts
}//checkMailDone }//checkMailDone
private void release() private void release()
{ {
MessagingController controller = MessagingController.getInstance(getApplication()); MessagingController controller = MessagingController.getInstance(getApplication());
@ -322,4 +508,5 @@ public class MailService extends Service {
} }
} }
} }
} }