mirror of
https://github.com/moparisthebest/k-9
synced 2024-12-23 16:18:50 -05:00
Complete merge of DAmail functionality into K9mail. Following
features are added to K9mail: 1) Show unread message count on each folder 2) Sum unread count of all shown folders in an account to the account display 3) Periodically check selected folders for new mail, not just Inbox 4) Don't refresh folder when opened (unless folder is empty) 5) Show date and time of last sync for each folder 6) Fix timer for automatic periodic sync (use wakelock to assure completion) 7) Optimize local folder queries (speeds up account and folder lists) 8) Show Loading... message in status bar indicating which folder is being synced 9) Eliminate redundant sync of new messages (performance enhancement) 10) Improve notification text for multiple accounts 11) Do not automatically sync folders more often than the account-specific period 12) Use user-configured date and time formats 13) Select which folders are shown, using configurable Classes 14) Select which folders are synced, using configurable Classes 15) Added context (long press) menu to folders, to provide for Refresh and Folder Settings 16) Status light flashes purple when there are unread messages 17) Folder list more quickly eliminates display of deleted and out-of-Class folders. 18) Delete works 19) Mark all messages as read (in the folder context menu) 20) Notifications only for new unread messages 21) One minute synchronization frequency 22) Deleting an unread message decrements unread counter 23) Notifications work for POP3 accounts 24) Message deletes work for POP3 accounts 25) Explicit errors show in folder list 26) Stack traces saved to folder K9mail-errors 27) Clear pending actions (danger, for emergencies only!) 28) Delete policy in Account settings 29) DNS cache in InetAddress disabled 30) Trapped some crash-causing error conditions 31) Eliminate duplicate copies to Sent folder 32) Prevent crashes due to message listener concurrency 33) Empty Trash 34) Nuclear "Mark all messages as read" (marks all messages as read in server-side folder, irrespective of which messages have been downloaded) 35) Forward (alternate) to allow forwarding email through other programs 36) Accept text/plain Intents to allow other programs to send email through K9mail 37) Displays Outbox sending status 38) Manual retry of outbox sending when "Refresh"ing Outbox 39) Folder error status is persisted 40) Ability to log to arbitrary file Fixes K9 issues 11, 23, 24, 65, 69, 71, 79, 81, 82, 83, 87, 101, 104, 107, 120, 148, 154
This commit is contained in:
parent
72c4095ceb
commit
334d64141f
@ -8,7 +8,7 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<permission android:name="com.android.email.permission.READ_ATTACHMENT"
|
||||
android:permissionGroup="android.permission-group.MESSAGES"
|
||||
android:protectionLevel="dangerous"
|
||||
@ -72,6 +72,12 @@
|
||||
android:label="@string/account_settings_title_fmt"
|
||||
>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.email.activity.setup.FolderSettings"
|
||||
android:label="@string/folder_settings_title"
|
||||
>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.email.activity.Debug"
|
||||
@ -102,6 +108,12 @@
|
||||
<data android:mimeType="image/*" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<data android:mimeType="text/*" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:scheme="mailto" />
|
||||
@ -110,7 +122,7 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<receiver android:name="com.android.email.service.BootReceiver"
|
||||
android:enabled="false"
|
||||
android:enabled="true"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
|
@ -33,17 +33,17 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dip"
|
||||
android:layout_weight="1" />
|
||||
<Button
|
||||
android:id="@+id/reply_all"
|
||||
android:text="@string/reply_all_action"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dip"
|
||||
android:layout_weight="1" />
|
||||
<Button
|
||||
android:id="@+id/delete"
|
||||
android:text="@string/delete_action"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dip"
|
||||
android:layout_weight="1" />
|
||||
<Button
|
||||
android:id="@+id/forward"
|
||||
android:text="@string/forward_action"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dip"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
@ -39,11 +39,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:text="@string/account_setup_options_notify_label" />
|
||||
<CheckBox
|
||||
android:id="@+id/account_notify_ringtone"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:text="@string/account_setup_options_notify_ringtone_label" />
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
|
@ -8,7 +8,7 @@
|
||||
android:paddingLeft="36px"
|
||||
android:paddingRight="4px">
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_vertical">
|
||||
@ -26,11 +26,11 @@
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<View
|
||||
android:layout_height="0dip"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="0px"
|
||||
android:layout_weight="1" />
|
||||
<TextView
|
||||
android:id="@+id/new_message_count"
|
||||
android:id="@+id/folder_unread_message_count"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
|
@ -2,8 +2,12 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/open"
|
||||
android:title="@string/open_action" />
|
||||
<item android:id="@+id/empty_trash"
|
||||
android:title="@string/empty_trash_action" />
|
||||
<item android:id="@+id/edit_account"
|
||||
android:title="@string/account_settings_action" />
|
||||
<item android:id="@+id/delete_account"
|
||||
android:title="@string/remove_account_action" />
|
||||
<item android:id="@+id/clear_pending"
|
||||
android:title="@string/clear_pending_action" />
|
||||
</menu>
|
||||
|
22
res/menu/folder_context.xml
Normal file
22
res/menu/folder_context.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/mark_all_as_read"
|
||||
android:title="@string/mark_all_as_read_action"
|
||||
/>
|
||||
|
||||
<item
|
||||
android:id="@+id/empty_trash"
|
||||
android:title="@string/empty_trash_action"
|
||||
/>
|
||||
|
||||
<item
|
||||
android:id="@+id/refresh"
|
||||
android:title="@string/refresh_action"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/folder_settings"
|
||||
android:title="@string/folder_settings_action"
|
||||
/>
|
||||
|
||||
</menu>
|
@ -24,4 +24,8 @@
|
||||
android:id="@+id/mark_as_read"
|
||||
android:title="@string/mark_as_read_action"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/send_alternate"
|
||||
android:title="@string/send_alternate_action"
|
||||
/>
|
||||
</menu>
|
||||
|
@ -12,6 +12,12 @@
|
||||
android:title="@string/compose_action"
|
||||
android:icon="@drawable/ic_menu_compose"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/empty_trash"
|
||||
android:alphabeticShortcut="e"
|
||||
android:title="@string/empty_trash_action"
|
||||
android:icon="@drawable/ic_menu_delete"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/accounts"
|
||||
android:title="@string/accounts_action"
|
||||
|
@ -30,4 +30,10 @@
|
||||
android:title="@string/delete_action"
|
||||
android:icon="@drawable/ic_menu_delete"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/send_alternate"
|
||||
android:alphabeticShortcut="s"
|
||||
android:title="@string/send_alternate_action"
|
||||
android:icon="@drawable/ic_menu_forward_mail"
|
||||
/>
|
||||
</menu>
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
<string-array name="account_settings_check_frequency_entries">
|
||||
<item>@string/account_setup_options_mail_check_frequency_never</item>
|
||||
<item>@string/account_setup_options_mail_check_frequency_1min</item>
|
||||
<item>@string/account_setup_options_mail_check_frequency_5min</item>
|
||||
<item>@string/account_setup_options_mail_check_frequency_10min</item>
|
||||
<item>@string/account_setup_options_mail_check_frequency_15min</item>
|
||||
@ -27,6 +28,7 @@
|
||||
|
||||
<string-array name="account_settings_check_frequency_values">
|
||||
<item>-1</item>
|
||||
<item>1</item>
|
||||
<item>5</item>
|
||||
<item>10</item>
|
||||
<item>15</item>
|
||||
@ -47,4 +49,69 @@
|
||||
<item>50</item>
|
||||
<item>100</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="account_settings_folder_display_mode_entries">
|
||||
<item>@string/account_settings_folder_display_mode_all</item>
|
||||
<item>@string/account_settings_folder_display_mode_first_class</item>
|
||||
<item>@string/account_settings_folder_display_mode_first_and_second_class</item>
|
||||
<item>@string/account_settings_folder_display_mode_not_second_class</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="account_settings_folder_display_mode_values">
|
||||
<item>ALL</item>
|
||||
<item>FIRST_CLASS</item>
|
||||
<item>FIRST_AND_SECOND_CLASS</item>
|
||||
<item>NOT_SECOND_CLASS</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="account_settings_folder_sync_mode_entries">
|
||||
<item>@string/account_settings_folder_sync_mode_all</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_not_second_class</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="account_settings_folder_sync_mode_values">
|
||||
<item>ALL</item>
|
||||
<item>FIRST_CLASS</item>
|
||||
<item>FIRST_AND_SECOND_CLASS</item>
|
||||
<item>NOT_SECOND_CLASS</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="folder_settings_folder_display_mode_entries">
|
||||
<item>@string/folder_settings_folder_display_mode_normal</item>
|
||||
<item>@string/folder_settings_folder_display_mode_first_class</item>
|
||||
<item>@string/folder_settings_folder_display_mode_second_class</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="folder_settings_folder_display_mode_values">
|
||||
<item>NONE</item>
|
||||
<item>FIRST_CLASS</item>
|
||||
<item>SECOND_CLASS</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="folder_settings_folder_sync_mode_entries">
|
||||
<item>@string/folder_settings_folder_sync_mode_normal</item>
|
||||
<item>@string/folder_settings_folder_sync_mode_first_class</item>
|
||||
<item>@string/folder_settings_folder_sync_mode_second_class</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="folder_settings_folder_sync_mode_values">
|
||||
<item>NONE</item>
|
||||
<item>FIRST_CLASS</item>
|
||||
<item>SECOND_CLASS</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="account_setup_delete_policy_entries">
|
||||
<item>@string/account_setup_incoming_delete_policy_never_label</item>
|
||||
<item>@string/account_setup_incoming_delete_policy_delete_label</item>
|
||||
<item>@string/account_setup_incoming_delete_policy_markread_label</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="account_setup_delete_policy_values">
|
||||
<item>0</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
@ -31,16 +31,23 @@
|
||||
<string name="save_draft_action">Save as draft</string>
|
||||
<string name="retry_action">Retry</string>
|
||||
<string name="refresh_action">Refresh</string>
|
||||
<string name="mark_all_as_read_action">Mark all messages as read</string>
|
||||
<string name="add_account_action">Add account</string>
|
||||
<string name="compose_action">Compose</string>
|
||||
<string name="search_action">Search</string>
|
||||
<string name="preferences_action">Preferences</string>
|
||||
<string name="open_action">Open</string>
|
||||
<string name="account_settings_action">Account settings</string>
|
||||
<string name="folder_settings_action">Folder settings</string>
|
||||
<string name="remove_account_action">Remove account</string>
|
||||
<string name="clear_pending_action">Clear pending actions (danger!)</string>
|
||||
|
||||
<string name="accounts_action">Accounts</string>
|
||||
<string name="read_action">Read</string>
|
||||
<string name="mark_as_read_action">Mark as read</string>
|
||||
<string name="send_alternate_action">Forward (alternate)</string>
|
||||
<string name="send_alternate_chooser_title">Choose sender</string>
|
||||
|
||||
<string name="mark_as_unread_action">Mark as unread</string>
|
||||
<string name="move_to_action">Move to</string>
|
||||
<string name="folders_action">Folders</string>
|
||||
@ -53,6 +60,7 @@
|
||||
<string name="about_action">About</string>
|
||||
|
||||
<string name="accounts_context_menu_title">Account options</string>
|
||||
<string name="folder_context_menu_title">Folder options</string>
|
||||
|
||||
<string name="general_no_subject">(No subject)</string> <!-- Shown in place of the subject when a message has no subject. Showing this in parentheses is customary. -->
|
||||
|
||||
@ -69,8 +77,11 @@
|
||||
<string name="notification_new_multi_account_fmt">in <xliff:g id="number_accounts">%d</xliff:g> accounts</string>
|
||||
<string name="notification_unsent_title">Message not sent</string>
|
||||
|
||||
<string name="notification_bg_sync_ticker">Checking email: <xliff:g id="account">%s</xliff:g></string>
|
||||
<string name="notification_bg_sync_ticker">Checking email: <xliff:g id="account">%s</xliff:g>:<xliff:g id="folder">%s</xliff:g></string>
|
||||
<string name="notification_bg_sync_title">Checking email</string>
|
||||
<string name="notification_bg_send_ticker">Sending email: <xliff:g id="account">%s</xliff:g></string>
|
||||
<string name="notification_bg_send_title">Sending email</string>
|
||||
<string name="notification_bg_title_separator">:</string>
|
||||
|
||||
<string name="special_mailbox_name_inbox">Inbox</string>
|
||||
<string name="special_mailbox_name_outbox">Outbox</string>
|
||||
@ -78,6 +89,8 @@
|
||||
<string name="special_mailbox_name_drafts">Drafts</string>
|
||||
<string name="special_mailbox_name_trash">Trash</string>
|
||||
<string name="special_mailbox_name_sent">Sent</string>
|
||||
|
||||
<string name="end_of_folder">No more messages</string>
|
||||
|
||||
<string name="accounts_welcome">
|
||||
Welcome to K-9 Mail setup. K-9 is an open source email client for Android based on the standard Android Mail client.
|
||||
@ -86,6 +99,8 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
|
||||
* Better performance
|
||||
* Email signatures
|
||||
* Bcc-to-self
|
||||
* Folder subscriptions
|
||||
* All folder synchronization
|
||||
* Return-address configuration
|
||||
* Keyboard shortcuts
|
||||
* Better IMAP support
|
||||
@ -142,6 +157,7 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
|
||||
<string name="message_deleted_toast">Message deleted.</string>
|
||||
<string name="message_discarded_toast">Message discarded.</string>
|
||||
<string name="message_saved_toast">Message saved as draft.</string>
|
||||
<string name="message_delete_failed">Message could not be deleted.</string>
|
||||
|
||||
<string name="about_header">About <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="about_version">Version: <xliff:g id="version">%s</xliff:g></string>
|
||||
@ -189,10 +205,13 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
|
||||
<string name="account_setup_incoming_security_ssl_label">SSL (always)</string>
|
||||
<string name="account_setup_incoming_security_tls_optional_label">TLS (if available)</string>
|
||||
<string name="account_setup_incoming_security_tls_label">TLS (always)</string>
|
||||
<string name="account_setup_incoming_delete_policy_label">Delete email from server:</string>
|
||||
<string name="account_setup_incoming_delete_policy_never_label">Never</string>
|
||||
|
||||
<string name="account_setup_incoming_delete_policy_label">When I delete a message</string>
|
||||
<string name="account_setup_incoming_delete_policy_never_label">Do not delete on server</string>
|
||||
<string name="account_setup_incoming_delete_policy_7days_label">After 7 days</string>
|
||||
<string name="account_setup_incoming_delete_policy_delete_label">When I delete from Inbox</string>
|
||||
<string name="account_setup_incoming_delete_policy_delete_label">Delete from server</string>
|
||||
<string name="account_setup_incoming_delete_policy_markread_label">Mark as read on server</string>
|
||||
|
||||
<string name="account_setup_incoming_imap_path_prefix_label">IMAP path prefix</string>
|
||||
<string name="account_setup_incoming_imap_path_prefix_hint">Optional</string>
|
||||
<string name="account_setup_incoming_webdav_path_prefix_label">WebDav(Exchange) path prefix</string>
|
||||
@ -219,9 +238,11 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
|
||||
<string name="account_setup_outgoing_authentication_webdav_before_smtp_label">WebDav(Exchange) before SMTP</string>
|
||||
|
||||
<string name="account_setup_options_title">Account options</string>
|
||||
|
||||
<string name="account_setup_options_mail_check_frequency_label">Email checking frequency</string>
|
||||
<!-- Frequency also used in account_settings_* -->
|
||||
<string name="account_setup_options_mail_check_frequency_never">Never</string>
|
||||
<string name="account_setup_options_mail_check_frequency_1min">Every minute</string>
|
||||
<string name="account_setup_options_mail_check_frequency_5min">Every 5 minutes</string>
|
||||
<string name="account_setup_options_mail_check_frequency_10min">Every 10 minutes</string>
|
||||
<string name="account_setup_options_mail_check_frequency_15min">Every 15 minutes</string>
|
||||
@ -229,7 +250,6 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
|
||||
<string name="account_setup_options_mail_check_frequency_1hour">Every hour</string>
|
||||
<string name="account_setup_options_default_label">Send email from this account by default.</string>
|
||||
<string name="account_setup_options_notify_label">Notify me when email arrives.</string>
|
||||
<string name="account_setup_options_notify_ringtone_label">Play a sound when email arrives.</string>
|
||||
|
||||
<!-- Number of displayed messages, also used in account_settings_* -->
|
||||
<string name="account_setup_options_mail_display_count_label">Number of emails to display</string>
|
||||
@ -248,14 +268,41 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
|
||||
<string name="account_settings_default">Default account</string>
|
||||
<string name="account_settings_default_label">Default account</string>
|
||||
<string name="account_settings_default_summary">Send email from this account by default</string>
|
||||
<string name="account_settings_email_label">Your email address</string>
|
||||
<string name="account_settings_notify_label">Email notifications</string>
|
||||
<string name="account_settings_email_label">Your email address</string>
|
||||
<string name="account_settings_notify_summary">Notify in status bar when email arrives</string>
|
||||
<string name="account_settings_notify_ringtone_label">Ringtone notifications</string>
|
||||
<string name="account_settings_notify_ringtone_summary">Play a sound when email arrives</string>
|
||||
<string name="account_settings_show_combined_label">Show combined Inbox</string>
|
||||
|
||||
<string name="account_settings_display_sync">Display and synchronization</string>
|
||||
|
||||
<string name="account_settings_mail_check_frequency_label">Email check frequency</string>
|
||||
<string name="account_settings_second_class_check_frequency_label">2nd class check frequency</string>
|
||||
|
||||
<string name="account_settings_mail_display_count_label">Number of emails to display</string>
|
||||
|
||||
<string name="account_settings_folder_display_mode_label">Folder display mode</string>
|
||||
<string name="account_settings_folder_display_mode_all">All</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_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_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_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="folder_settings_title">Folder settings</string>
|
||||
<string name="folder_settings_folder_display_mode_label">Folder display class</string>
|
||||
<string name="folder_settings_folder_display_mode_normal">None</string>
|
||||
<string name="folder_settings_folder_display_mode_first_class">1st 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_normal">Same as display 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="account_settings_incoming_label">Incoming settings</string>
|
||||
<string name="account_settings_incoming_summary">Configure the incoming email server</string>
|
||||
<string name="account_settings_outgoing_label">Outgoing settings</string>
|
||||
@ -295,7 +342,9 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
|
||||
your correct email address and password, you may not have a paid
|
||||
\"Plus\" account. Please launch the Web browser to gain access to
|
||||
these mail accounts.</string>
|
||||
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">Unrecognized Certificate</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accept Key</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_reject">Reject Key</string>
|
||||
|
||||
</resources>
|
||||
|
@ -26,12 +26,10 @@
|
||||
android:summary=""
|
||||
android:dialogTitle="@string/account_settings_description_label" />
|
||||
|
||||
<ListPreference
|
||||
android:key="account_check_frequency"
|
||||
android:title="@string/account_settings_mail_check_frequency_label"
|
||||
android:entries="@array/account_settings_check_frequency_entries"
|
||||
android:entryValues="@array/account_settings_check_frequency_values"
|
||||
android:dialogTitle="@string/account_settings_mail_check_frequency_label" />
|
||||
<CheckBoxPreference
|
||||
android:key="account_default"
|
||||
android:title="@string/account_settings_default_label"
|
||||
android:summary="@string/account_settings_default_summary" />
|
||||
|
||||
<ListPreference
|
||||
android:key="account_display_count"
|
||||
@ -40,6 +38,40 @@
|
||||
android:entryValues="@array/account_settings_display_count_values"
|
||||
android:dialogTitle="@string/account_settings_mail_display_count_label" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/account_settings_display_sync">
|
||||
|
||||
<ListPreference
|
||||
android:key="account_check_frequency"
|
||||
android:title="@string/account_settings_mail_check_frequency_label"
|
||||
android:entries="@array/account_settings_check_frequency_entries"
|
||||
android:entryValues="@array/account_settings_check_frequency_values"
|
||||
android:dialogTitle="@string/account_settings_mail_check_frequency_label" />
|
||||
|
||||
|
||||
<ListPreference
|
||||
android:key="folder_display_mode"
|
||||
android:title="@string/account_settings_folder_display_mode_label"
|
||||
android:entries="@array/account_settings_folder_display_mode_entries"
|
||||
android:entryValues="@array/account_settings_folder_display_mode_values"
|
||||
android:dialogTitle="@string/account_settings_folder_display_mode_label" />
|
||||
|
||||
<ListPreference
|
||||
android:key="folder_sync_mode"
|
||||
android:title="@string/account_settings_folder_sync_mode_label"
|
||||
android:entries="@array/account_settings_folder_sync_mode_entries"
|
||||
android:entryValues="@array/account_settings_folder_sync_mode_values"
|
||||
android:dialogTitle="@string/account_settings_folder_sync_mode_label" />
|
||||
|
||||
<ListPreference
|
||||
android:key="delete_policy"
|
||||
android:title="@string/account_setup_incoming_delete_policy_label"
|
||||
android:entries="@array/account_setup_delete_policy_entries"
|
||||
android:entryValues="@array/account_setup_delete_policy_values"
|
||||
android:dialogTitle="@string/account_setup_incoming_delete_policy_label" />
|
||||
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="composition"
|
||||
android:title="@string/account_settings_composition_label" />
|
||||
@ -54,11 +86,6 @@
|
||||
android:title="@string/account_settings_notify_label"
|
||||
android:defaultValue="true"
|
||||
android:summary="@string/account_settings_notify_summary" />
|
||||
<CheckBoxPreference
|
||||
android:key="account_notify_ringtone"
|
||||
android:title="@string/account_settings_notify_ringtone_label"
|
||||
android:defaultValue="true"
|
||||
android:summary="@string/account_settings_notify_ringtone_summary" />
|
||||
|
||||
<RingtonePreference
|
||||
android:layout="?android:attr/preferenceLayoutChild"
|
||||
@ -89,13 +116,6 @@
|
||||
android:title="@string/account_settings_outgoing_label" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/account_settings_default">
|
||||
<CheckBoxPreference
|
||||
android:key="account_default"
|
||||
android:title="@string/account_settings_default_label"
|
||||
android:summary="@string/account_settings_default_summary" />
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
|
||||
|
||||
</PreferenceScreen>
|
||||
|
39
res/xml/folder_settings_preferences.xml
Normal file
39
res/xml/folder_settings_preferences.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="folder_settings">
|
||||
|
||||
<ListPreference
|
||||
android:key="folder_settings_folder_display_mode"
|
||||
android:title="@string/folder_settings_folder_display_mode_label"
|
||||
android:entries="@array/folder_settings_folder_display_mode_entries"
|
||||
android:entryValues="@array/folder_settings_folder_display_mode_values"
|
||||
android:dialogTitle="@string/folder_settings_folder_display_mode_label" />
|
||||
|
||||
<ListPreference
|
||||
android:key="folder_settings_folder_sync_mode"
|
||||
android:title="@string/folder_settings_folder_sync_mode_label"
|
||||
android:entries="@array/folder_settings_folder_sync_mode_entries"
|
||||
android:entryValues="@array/folder_settings_folder_sync_mode_values"
|
||||
android:dialogTitle="@string/folder_settings_folder_sync_mode_label" />
|
||||
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
@ -5,9 +5,17 @@ import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.android.email.mail.Folder;
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.Store;
|
||||
import com.android.email.mail.store.LocalStore;
|
||||
import com.android.email.mail.store.LocalStore.LocalFolder;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Account stores all of the settings for a single account defined by the user. It is able to save
|
||||
@ -17,6 +25,7 @@ public class Account implements Serializable {
|
||||
public static final int DELETE_POLICY_NEVER = 0;
|
||||
public static final int DELETE_POLICY_7DAYS = 1;
|
||||
public static final int DELETE_POLICY_ON_DELETE = 2;
|
||||
public static final int DELETE_POLICY_MARK_AS_READ = 3;
|
||||
|
||||
private static final long serialVersionUID = 2975156672298625121L;
|
||||
|
||||
@ -33,14 +42,19 @@ public class Account implements Serializable {
|
||||
int mDisplayCount;
|
||||
long mLastAutomaticCheckTime;
|
||||
boolean mNotifyNewMail;
|
||||
boolean mNotifyRingtone;
|
||||
String mDraftsFolderName;
|
||||
String mSentFolderName;
|
||||
String mTrashFolderName;
|
||||
String mOutboxFolderName;
|
||||
FolderMode mFolderDisplayMode;
|
||||
FolderMode mFolderSyncMode;
|
||||
int mAccountNumber;
|
||||
boolean mVibrate;
|
||||
String mRingtoneUri;
|
||||
|
||||
public enum FolderMode {
|
||||
ALL, FIRST_CLASS, FIRST_AND_SECOND_CLASS, NOT_SECOND_CLASS;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@ -59,9 +73,10 @@ public class Account implements Serializable {
|
||||
mDisplayCount = -1;
|
||||
mAccountNumber = -1;
|
||||
mNotifyNewMail = true;
|
||||
mNotifyRingtone = false;
|
||||
mSignature = "Sent from my Android phone with K-9. Please excuse my brevity.";
|
||||
mVibrate = false;
|
||||
mFolderDisplayMode = FolderMode.ALL;
|
||||
mFolderSyncMode = FolderMode.ALL;
|
||||
mRingtoneUri = "content://settings/system/notification_sound";
|
||||
}
|
||||
|
||||
@ -91,8 +106,6 @@ public class Account implements Serializable {
|
||||
+ ".lastAutomaticCheckTime", 0);
|
||||
mNotifyNewMail = preferences.mSharedPreferences.getBoolean(mUuid + ".notifyNewMail",
|
||||
false);
|
||||
mNotifyRingtone = preferences.mSharedPreferences.getBoolean(mUuid + ".notifyRingtone",
|
||||
false);
|
||||
mDeletePolicy = preferences.mSharedPreferences.getInt(mUuid + ".deletePolicy", 0);
|
||||
mDraftsFolderName = preferences.mSharedPreferences.getString(mUuid + ".draftsFolderName",
|
||||
"Drafts");
|
||||
@ -106,6 +119,26 @@ public class Account implements Serializable {
|
||||
mVibrate = preferences.mSharedPreferences.getBoolean(mUuid + ".vibrate", false);
|
||||
mRingtoneUri = preferences.mSharedPreferences.getString(mUuid + ".ringtone",
|
||||
"content://settings/system/notification_sound");
|
||||
try
|
||||
{
|
||||
mFolderDisplayMode = FolderMode.valueOf(preferences.mSharedPreferences.getString(mUuid + ".folderDisplayMode",
|
||||
FolderMode.NOT_SECOND_CLASS.name()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
mFolderDisplayMode = FolderMode.ALL;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mFolderSyncMode = FolderMode.valueOf(preferences.mSharedPreferences.getString(mUuid + ".folderSyncMode",
|
||||
FolderMode.FIRST_CLASS.name()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
mFolderSyncMode = FolderMode.ALL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
@ -218,6 +251,9 @@ public class Account implements Serializable {
|
||||
editor.remove(mUuid + ".accountNumber");
|
||||
editor.remove(mUuid + ".vibrate");
|
||||
editor.remove(mUuid + ".ringtone");
|
||||
editor.remove(mUuid + ".lastFullSync");
|
||||
editor.remove(mUuid + ".folderDisplayMode");
|
||||
editor.remove(mUuid + ".folderSyncMode");
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
@ -269,7 +305,6 @@ public class Account implements Serializable {
|
||||
editor.putInt(mUuid + ".displayCount", mDisplayCount);
|
||||
editor.putLong(mUuid + ".lastAutomaticCheckTime", mLastAutomaticCheckTime);
|
||||
editor.putBoolean(mUuid + ".notifyNewMail", mNotifyNewMail);
|
||||
editor.putBoolean(mUuid + ".notifyRingtone", mNotifyRingtone);
|
||||
editor.putInt(mUuid + ".deletePolicy", mDeletePolicy);
|
||||
editor.putString(mUuid + ".draftsFolderName", mDraftsFolderName);
|
||||
editor.putString(mUuid + ".sentFolderName", mSentFolderName);
|
||||
@ -278,6 +313,9 @@ public class Account implements Serializable {
|
||||
editor.putInt(mUuid + ".accountNumber", mAccountNumber);
|
||||
editor.putBoolean(mUuid + ".vibrate", mVibrate);
|
||||
editor.putString(mUuid + ".ringtone", mRingtoneUri);
|
||||
editor.putString(mUuid + ".folderDisplayMode", mFolderDisplayMode.name());
|
||||
editor.putString(mUuid + ".folderSyncMode", mFolderSyncMode.name());
|
||||
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
@ -303,6 +341,49 @@ public class Account implements Serializable {
|
||||
public int getAutomaticCheckIntervalMinutes() {
|
||||
return mAutomaticCheckIntervalMinutes;
|
||||
}
|
||||
|
||||
public int getUnreadMessageCount(Context context, Application application) throws MessagingException
|
||||
{
|
||||
int unreadMessageCount = 0;
|
||||
LocalStore localStore = (LocalStore) Store.getInstance(
|
||||
getLocalStoreUri(),
|
||||
application);
|
||||
Account.FolderMode aMode = getFolderDisplayMode();
|
||||
Preferences prefs = Preferences.getPreferences(context);
|
||||
for (LocalFolder folder : localStore.getPersonalNamespaces())
|
||||
{
|
||||
folder.refresh(prefs);
|
||||
Folder.FolderClass fMode = folder.getDisplayClass();
|
||||
|
||||
if (folder.getName().equals(getTrashFolderName()) == false &&
|
||||
folder.getName().equals(getDraftsFolderName()) == false &&
|
||||
folder.getName().equals(getOutboxFolderName()) == false &&
|
||||
folder.getName().equals(getSentFolderName()) == false &&
|
||||
folder.getName().equals(getErrorFolderName()) == false)
|
||||
{
|
||||
if (aMode == Account.FolderMode.FIRST_CLASS &&
|
||||
fMode != Folder.FolderClass.FIRST_CLASS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS &&
|
||||
fMode != Folder.FolderClass.FIRST_CLASS &&
|
||||
fMode != Folder.FolderClass.SECOND_CLASS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (aMode == Account.FolderMode.NOT_SECOND_CLASS &&
|
||||
fMode == Folder.FolderClass.SECOND_CLASS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
unreadMessageCount += folder.getUnreadMessageCount();
|
||||
}
|
||||
}
|
||||
|
||||
return unreadMessageCount;
|
||||
|
||||
}
|
||||
|
||||
public int getDisplayCount() {
|
||||
if (mDisplayCount == -1) {
|
||||
@ -337,15 +418,6 @@ public class Account implements Serializable {
|
||||
this.mLastAutomaticCheckTime = lastAutomaticCheckTime;
|
||||
}
|
||||
|
||||
public boolean isNotifyRingtone() {
|
||||
return mNotifyRingtone;
|
||||
}
|
||||
|
||||
public void setNotifyRingtone(boolean notifyRingtone) {
|
||||
this.mNotifyRingtone = notifyRingtone;
|
||||
}
|
||||
|
||||
|
||||
public boolean isNotifyNewMail() {
|
||||
return mNotifyNewMail;
|
||||
}
|
||||
@ -373,6 +445,11 @@ public class Account implements Serializable {
|
||||
public String getSentFolderName() {
|
||||
return mSentFolderName;
|
||||
}
|
||||
|
||||
public String getErrorFolderName()
|
||||
{
|
||||
return Email.ERROR_FOLDER_NAME;
|
||||
}
|
||||
|
||||
public void setSentFolderName(String sentFolderName) {
|
||||
mSentFolderName = sentFolderName;
|
||||
@ -405,4 +482,25 @@ public class Account implements Serializable {
|
||||
}
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
public FolderMode getFolderDisplayMode()
|
||||
{
|
||||
return mFolderDisplayMode;
|
||||
}
|
||||
|
||||
public void setFolderDisplayMode(FolderMode displayMode)
|
||||
{
|
||||
mFolderDisplayMode = displayMode;
|
||||
}
|
||||
|
||||
public FolderMode getFolderSyncMode()
|
||||
{
|
||||
return mFolderSyncMode;
|
||||
}
|
||||
|
||||
public void setFolderSyncMode(FolderMode syncMode)
|
||||
{
|
||||
mFolderSyncMode = syncMode;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,14 @@ public class Email extends Application {
|
||||
public static Application app = null;
|
||||
public static File tempDirectory;
|
||||
public static final String LOG_TAG = "k9";
|
||||
|
||||
/**
|
||||
* Some log messages can be sent to a file, so that the logs
|
||||
* can be read using unprivileged access (eg. Terminal Emulator)
|
||||
* on the phone, without adb. Set to null to disable
|
||||
*/
|
||||
public static final String logFile = null;
|
||||
//public static final String logFile = "/sdcard/k9mail/debug.log";
|
||||
|
||||
/**
|
||||
* If this is enabled there will be additional logging information sent to
|
||||
@ -33,6 +41,12 @@ public class Email extends Application {
|
||||
*/
|
||||
public static boolean DEBUG_SENSITIVE = false;
|
||||
|
||||
/**
|
||||
* Can create messages containing stack traces that can be forwarded
|
||||
* to the development team.
|
||||
*/
|
||||
public static boolean ENABLE_ERROR_FOLDER = true;
|
||||
public static String ERROR_FOLDER_NAME = "K9mail-errors";
|
||||
|
||||
/**
|
||||
* The MIME type(s) of attachments we're willing to send. At the moment it is not possible
|
||||
@ -41,7 +55,7 @@ public class Email extends Application {
|
||||
* with Intent.ACTION_SEND.
|
||||
*/
|
||||
public static final String[] ACCEPTABLE_ATTACHMENT_SEND_TYPES = new String[] {
|
||||
"*/*",
|
||||
"*/*"
|
||||
};
|
||||
|
||||
/**
|
||||
@ -103,7 +117,7 @@ public class Email extends Application {
|
||||
/**
|
||||
* Max time (in millis) the wake lock will be held for when background sync is happening
|
||||
*/
|
||||
public static final int WAKE_LOCK_TIMEOUT = 30000;
|
||||
public static final int WAKE_LOCK_TIMEOUT = 600000;
|
||||
|
||||
/**
|
||||
* LED color used for the new email notitication
|
||||
@ -120,8 +134,10 @@ public class Email extends Application {
|
||||
*/
|
||||
public static final int NOTIFICATION_LED_OFF_TIME = 2000;
|
||||
|
||||
public static final int NEW_EMAIL_NOTIFICATION_ID = 1;
|
||||
public static final int FETCHING_EMAIL_NOTIFICATION_ID = 2;
|
||||
// Must not conflict with an account number
|
||||
public static final int FETCHING_EMAIL_NOTIFICATION_ID = -4;
|
||||
public static final int FETCHING_EMAIL_NOTIFICATION_MULTI_ACCOUNT_ID = -1;
|
||||
public static final int FETCHING_EMAIL_NOTIFICATION_NO_ACCOUNT = -2;
|
||||
|
||||
/**
|
||||
* Called throughout the application when the number of accounts has changed. This method
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -79,16 +79,26 @@ public class MessagingListener {
|
||||
|
||||
public void checkMailFinished(Context context, Account account) {
|
||||
}
|
||||
|
||||
|
||||
public void checkMailFailed(Context context, Account account, String reason) {
|
||||
}
|
||||
|
||||
public void sendPendingMessagesStarted(Account account) {
|
||||
}
|
||||
|
||||
public void sendPendingMessagesCompleted(Account account) {
|
||||
}
|
||||
|
||||
public void sendPendingMessagesFailed(Account account) {
|
||||
}
|
||||
|
||||
|
||||
public void emptyTrashCompleted(Account account) {
|
||||
}
|
||||
|
||||
public void folderStatusChanged(Account account, String folderName) {
|
||||
}
|
||||
|
||||
public void messageUidChanged(Account account, String folder, String oldUid, String newUid) {
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import android.util.Log;
|
||||
public class Preferences {
|
||||
private static Preferences preferences;
|
||||
|
||||
SharedPreferences mSharedPreferences;
|
||||
public SharedPreferences mSharedPreferences;
|
||||
|
||||
private Preferences(Context context) {
|
||||
mSharedPreferences = context.getSharedPreferences("AndroidMail.Main", Context.MODE_PRIVATE);
|
||||
|
@ -37,6 +37,7 @@ import com.android.email.R;
|
||||
import com.android.email.activity.setup.AccountSettings;
|
||||
import com.android.email.activity.setup.AccountSetupBasics;
|
||||
import com.android.email.activity.setup.AccountSetupCheckSettings;
|
||||
import com.android.email.mail.Folder;
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.Store;
|
||||
import com.android.email.mail.store.LocalStore;
|
||||
@ -85,7 +86,7 @@ public class Accounts extends ListActivity implements OnItemClickListener, OnCli
|
||||
|
||||
NotificationManager notifMgr = (NotificationManager)
|
||||
getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notifMgr.cancel(1);
|
||||
notifMgr.cancelAll();
|
||||
|
||||
refresh();
|
||||
}
|
||||
@ -106,6 +107,16 @@ public class Accounts extends ListActivity implements OnItemClickListener, OnCli
|
||||
private void onRefresh() {
|
||||
MessagingController.getInstance(getApplication()).checkMail(this, null, null);
|
||||
}
|
||||
|
||||
private void onClearCommands(Account account) {
|
||||
MessagingController.getInstance(getApplication()).clearAllPending(account);
|
||||
}
|
||||
|
||||
private void onEmptyTrash(Account account)
|
||||
{
|
||||
MessagingController.getInstance(getApplication()).emptyTrash(account, null);
|
||||
}
|
||||
|
||||
|
||||
private void onCompose() {
|
||||
Account defaultAccount =
|
||||
@ -183,6 +194,12 @@ public class Accounts extends ListActivity implements OnItemClickListener, OnCli
|
||||
case R.id.open:
|
||||
onOpenAccount(account);
|
||||
break;
|
||||
case R.id.clear_pending:
|
||||
onClearCommands(account);
|
||||
break;
|
||||
case R.id.empty_trash:
|
||||
onEmptyTrash(account);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -286,6 +303,7 @@ getPackageManager().getPackageInfo(getPackageName(), 0);
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
|
||||
class AccountsAdapter extends ArrayAdapter<Account> {
|
||||
public AccountsAdapter(Account[] accounts) {
|
||||
@ -317,13 +335,7 @@ getPackageManager().getPackageInfo(getPackageName(), 0);
|
||||
}
|
||||
int unreadMessageCount = 0;
|
||||
try {
|
||||
LocalStore localStore = (LocalStore) Store.getInstance(
|
||||
account.getLocalStoreUri(),
|
||||
getApplication());
|
||||
LocalFolder localFolder = (LocalFolder) localStore.getFolder(Email.INBOX);
|
||||
if (localFolder.exists()) {
|
||||
unreadMessageCount = localFolder.getUnreadMessageCount();
|
||||
}
|
||||
unreadMessageCount = account.getUnreadMessageCount(Accounts.this, getApplication());
|
||||
}
|
||||
catch (MessagingException me) {
|
||||
/*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -370,6 +370,17 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
|
||||
return;
|
||||
}
|
||||
|
||||
String text = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||
if (text != null)
|
||||
{
|
||||
mMessageContentView.setText(text);
|
||||
}
|
||||
String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
|
||||
if (subject != null)
|
||||
{
|
||||
mSubjectView.setText(subject);
|
||||
}
|
||||
|
||||
String type = intent.getType();
|
||||
Uri stream = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
if (stream != null && type != null) {
|
||||
@ -397,7 +408,7 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
|
||||
mAccount,
|
||||
mFolder,
|
||||
mSourceMessageUid,
|
||||
mListener);
|
||||
null);
|
||||
}
|
||||
if (ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action) ||
|
||||
ACTION_EDIT_DRAFT.equals(action)) {
|
||||
|
@ -93,8 +93,31 @@ public class MessageView extends Activity
|
||||
private String mNextMessageUid = null;
|
||||
private String mPreviousMessageUid = null;
|
||||
|
||||
private DateFormat mDateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
||||
private DateFormat mTimeFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
|
||||
private DateFormat dateFormat = null;
|
||||
private DateFormat timeFormat = null;
|
||||
|
||||
|
||||
private DateFormat getDateFormat()
|
||||
{
|
||||
if (dateFormat == null)
|
||||
{
|
||||
dateFormat = android.pim.DateFormat.getDateFormat(getApplication());
|
||||
}
|
||||
return dateFormat;
|
||||
}
|
||||
private DateFormat getTimeFormat()
|
||||
{
|
||||
if (timeFormat == null)
|
||||
{
|
||||
timeFormat = android.pim.DateFormat.getTimeFormat(getApplication());
|
||||
}
|
||||
return timeFormat;
|
||||
}
|
||||
private void clearFormats()
|
||||
{
|
||||
dateFormat = null;
|
||||
timeFormat = null;
|
||||
}
|
||||
|
||||
private Listener mListener = new Listener();
|
||||
private MessageViewHandler mHandler = new MessageViewHandler();
|
||||
@ -109,7 +132,11 @@ public class MessageView extends Activity
|
||||
case KeyEvent.KEYCODE_F: { onForward(); return true;}
|
||||
case KeyEvent.KEYCODE_A: { onReplyAll(); return true; }
|
||||
case KeyEvent.KEYCODE_R: { onReply(); return true; }
|
||||
case KeyEvent.KEYCODE_J: { onPrevious(); return true; }
|
||||
case KeyEvent.KEYCODE_J:
|
||||
case KeyEvent.KEYCODE_P:
|
||||
{ onPrevious(); return true; }
|
||||
case KeyEvent.KEYCODE_SPACE:
|
||||
case KeyEvent.KEYCODE_N:
|
||||
case KeyEvent.KEYCODE_K: { onNext(); return true; }
|
||||
case KeyEvent.KEYCODE_Z: { if (event.isShiftPressed()) {
|
||||
mMessageContentView.zoomIn();
|
||||
@ -301,10 +328,10 @@ public class MessageView extends Activity
|
||||
mAttachments.setVisibility(View.GONE);
|
||||
mAttachmentIcon.setVisibility(View.GONE);
|
||||
|
||||
findViewById(R.id.reply).setOnClickListener(this);
|
||||
findViewById(R.id.delete).setOnClickListener(this);
|
||||
findViewById(R.id.forward).setOnClickListener(this);
|
||||
findViewById(R.id.show_pictures).setOnClickListener(this);
|
||||
setOnClickListener(R.id.reply);
|
||||
setOnClickListener(R.id.delete);
|
||||
setOnClickListener(R.id.forward);
|
||||
setOnClickListener(R.id.show_pictures);
|
||||
|
||||
// UrlInterceptRegistry.registerHandler(this);
|
||||
|
||||
@ -318,11 +345,12 @@ public class MessageView extends Activity
|
||||
mFolder = intent.getStringExtra(EXTRA_FOLDER);
|
||||
mMessageUid = intent.getStringExtra(EXTRA_MESSAGE);
|
||||
mFolderUids = intent.getStringArrayListExtra(EXTRA_FOLDER_UIDS);
|
||||
|
||||
findSurroundingMessagesUid();
|
||||
|
||||
|
||||
View next = findViewById(R.id.next);
|
||||
View previous = findViewById(R.id.previous);
|
||||
|
||||
findSurroundingMessagesUid();
|
||||
|
||||
/*
|
||||
* Next and Previous Message are not shown in landscape mode, so
|
||||
* we need to check before we use them.
|
||||
@ -331,6 +359,7 @@ public class MessageView extends Activity
|
||||
next.setOnClickListener(this);
|
||||
previous.setOnClickListener(this);
|
||||
|
||||
|
||||
previous.setVisibility(mPreviousMessageUid != null ? View.VISIBLE : View.GONE);
|
||||
next.setVisibility(mNextMessageUid != null ? View.VISIBLE : View.GONE);
|
||||
|
||||
@ -351,10 +380,19 @@ public class MessageView extends Activity
|
||||
mAccount,
|
||||
mFolder,
|
||||
mMessageUid,
|
||||
mListener);
|
||||
null);
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
private void setOnClickListener(int viewCode)
|
||||
{
|
||||
View thisView = findViewById(viewCode);
|
||||
if (thisView != null)
|
||||
{
|
||||
thisView.setOnClickListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void findSurroundingMessagesUid() {
|
||||
for (int i = 0, count = mFolderUids.size(); i < count; i++) {
|
||||
@ -374,6 +412,7 @@ public class MessageView extends Activity
|
||||
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
clearFormats();
|
||||
MessagingController.getInstance(getApplication()).addListener(mListener);
|
||||
}
|
||||
|
||||
@ -427,8 +466,22 @@ public class MessageView extends Activity
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void onSendAlternate() {
|
||||
if (mMessage != null) {
|
||||
MessagingController.getInstance(getApplication()).sendAlternate(this, mAccount, mMessage);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void onNext() {
|
||||
if (mNextMessageUid == null)
|
||||
{
|
||||
Toast.makeText(this,
|
||||
getString(R.string.end_of_folder),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
Bundle extras = new Bundle(1);
|
||||
extras.putBoolean(EXTRA_NEXT, true);
|
||||
MessageView.actionView(this, mAccount, mFolder, mNextMessageUid, mFolderUids, extras);
|
||||
@ -436,6 +489,13 @@ public class MessageView extends Activity
|
||||
}
|
||||
|
||||
private void onPrevious() {
|
||||
if (mPreviousMessageUid == null)
|
||||
{
|
||||
Toast.makeText(this,
|
||||
getString(R.string.end_of_folder),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
MessageView.actionView(this, mAccount, mFolder, mPreviousMessageUid, mFolderUids);
|
||||
finish();
|
||||
}
|
||||
@ -518,6 +578,9 @@ public class MessageView extends Activity
|
||||
case R.id.reply:
|
||||
onReply();
|
||||
break;
|
||||
case R.id.reply_all:
|
||||
onReplyAll();
|
||||
break;
|
||||
case R.id.delete:
|
||||
onDelete();
|
||||
break;
|
||||
@ -556,6 +619,9 @@ public class MessageView extends Activity
|
||||
case R.id.forward:
|
||||
onForward();
|
||||
break;
|
||||
case R.id.send_alternate:
|
||||
onSendAlternate();
|
||||
break;
|
||||
case R.id.mark_as_unread:
|
||||
onMarkAsUnread();
|
||||
break;
|
||||
@ -712,8 +778,8 @@ public class MessageView extends Activity
|
||||
String subjectText = message.getSubject();
|
||||
String fromText = Address.toFriendly(message.getFrom());
|
||||
String dateText = Utility.isDateToday(message.getSentDate()) ?
|
||||
mTimeFormat.format(message.getSentDate()) :
|
||||
mDateTimeFormat.format(message.getSentDate());
|
||||
getTimeFormat().format(message.getSentDate()) :
|
||||
getDateFormat().format(message.getSentDate());
|
||||
String toText = Address.toFriendly(message.getRecipients(RecipientType.TO));
|
||||
boolean hasAttachments = ((LocalMessage) message).getAttachmentCount() > 0;
|
||||
mHandler.setHeaders(subjectText,
|
||||
@ -773,7 +839,7 @@ public class MessageView extends Activity
|
||||
|
||||
/*
|
||||
* TODO this should be smarter, change to regex for img, but consider how to
|
||||
* get backgroung images and a million other things that HTML allows.
|
||||
* get background images and a million other things that HTML allows.
|
||||
*/
|
||||
if (text.contains("<img")) {
|
||||
mHandler.showShowPictures(true);
|
||||
|
@ -28,11 +28,13 @@ public class AccountSettings extends PreferenceActivity {
|
||||
private static final String PREFERENCE_DISPLAY_COUNT = "account_display_count";
|
||||
private static final String PREFERENCE_DEFAULT = "account_default";
|
||||
private static final String PREFERENCE_NOTIFY = "account_notify";
|
||||
private static final String PREFERENCE_NOTIFY_RINGTONE = "account_notify_ringtone";
|
||||
private static final String PREFERENCE_VIBRATE = "account_vibrate";
|
||||
private static final String PREFERENCE_RINGTONE = "account_ringtone";
|
||||
private static final String PREFERENCE_INCOMING = "incoming";
|
||||
private static final String PREFERENCE_OUTGOING = "outgoing";
|
||||
private static final String PREFERENCE_DISPLAY_MODE = "folder_display_mode";
|
||||
private static final String PREFERENCE_SYNC_MODE = "folder_sync_mode";
|
||||
private static final String PREFERENCE_DELETE_POLICY = "delete_policy";
|
||||
|
||||
private Account mAccount;
|
||||
|
||||
@ -41,9 +43,11 @@ public class AccountSettings extends PreferenceActivity {
|
||||
private ListPreference mDisplayCount;
|
||||
private CheckBoxPreference mAccountDefault;
|
||||
private CheckBoxPreference mAccountNotify;
|
||||
private CheckBoxPreference mAccountNotifyRingtone;
|
||||
private CheckBoxPreference mAccountVibrate;
|
||||
private RingtonePreference mAccountRingtone;
|
||||
private ListPreference mDisplayMode;
|
||||
private ListPreference mSyncMode;
|
||||
private ListPreference mDeletePolicy;
|
||||
|
||||
public static void actionSettings(Context context, Account account) {
|
||||
Intent i = new Intent(context, AccountSettings.class);
|
||||
@ -87,6 +91,45 @@ public class AccountSettings extends PreferenceActivity {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mDisplayMode = (ListPreference) findPreference(PREFERENCE_DISPLAY_MODE);
|
||||
mDisplayMode.setValue(mAccount.getFolderDisplayMode().name());
|
||||
mDisplayMode.setSummary(mDisplayMode.getEntry());
|
||||
mDisplayMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final String summary = newValue.toString();
|
||||
int index = mDisplayMode.findIndexOfValue(summary);
|
||||
mDisplayMode.setSummary(mDisplayMode.getEntries()[index]);
|
||||
mDisplayMode.setValue(summary);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mSyncMode = (ListPreference) findPreference(PREFERENCE_SYNC_MODE);
|
||||
mSyncMode.setValue(mAccount.getFolderSyncMode().name());
|
||||
mSyncMode.setSummary(mSyncMode.getEntry());
|
||||
mSyncMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final String summary = newValue.toString();
|
||||
int index = mSyncMode.findIndexOfValue(summary);
|
||||
mSyncMode.setSummary(mSyncMode.getEntries()[index]);
|
||||
mSyncMode.setValue(summary);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mDeletePolicy = (ListPreference) findPreference(PREFERENCE_DELETE_POLICY);
|
||||
mDeletePolicy.setValue("" + mAccount.getDeletePolicy());
|
||||
mDeletePolicy.setSummary(mDeletePolicy.getEntry());
|
||||
mDeletePolicy.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final String summary = newValue.toString();
|
||||
int index = mDeletePolicy.findIndexOfValue(summary);
|
||||
mDeletePolicy.setSummary(mDeletePolicy.getEntries()[index]);
|
||||
mDeletePolicy.setValue(summary);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mDisplayCount = (ListPreference) findPreference(PREFERENCE_DISPLAY_COUNT);
|
||||
mDisplayCount.setValue(String.valueOf(mAccount.getDisplayCount()));
|
||||
@ -108,9 +151,6 @@ public class AccountSettings extends PreferenceActivity {
|
||||
mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY);
|
||||
mAccountNotify.setChecked(mAccount.isNotifyNewMail());
|
||||
|
||||
mAccountNotifyRingtone = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY_RINGTONE);
|
||||
mAccountNotifyRingtone.setChecked(mAccount.isNotifyRingtone());
|
||||
|
||||
mAccountRingtone = (RingtonePreference) findPreference(PREFERENCE_RINGTONE);
|
||||
|
||||
// XXX: The following two lines act as a workaround for the RingtonePreference
|
||||
@ -159,14 +199,17 @@ public class AccountSettings extends PreferenceActivity {
|
||||
}
|
||||
mAccount.setDescription(mAccountDescription.getText());
|
||||
mAccount.setNotifyNewMail(mAccountNotify.isChecked());
|
||||
mAccount.setNotifyRingtone(mAccountNotifyRingtone.isChecked());
|
||||
mAccount.setAutomaticCheckIntervalMinutes(Integer.parseInt(mCheckFrequency.getValue()));
|
||||
mAccount.setDisplayCount(Integer.parseInt(mDisplayCount.getValue()));
|
||||
mAccount.setVibrate(mAccountVibrate.isChecked());
|
||||
mAccount.setFolderDisplayMode(Account.FolderMode.valueOf(mDisplayMode.getValue()));
|
||||
mAccount.setFolderSyncMode(Account.FolderMode.valueOf(mSyncMode.getValue()));
|
||||
mAccount.setDeletePolicy(Integer.parseInt(mDeletePolicy.getValue()));
|
||||
SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences();
|
||||
mAccount.setRingtone(prefs.getString(PREFERENCE_RINGTONE, null));
|
||||
mAccount.save(Preferences.getPreferences(this));
|
||||
Email.setServicesEnabled(this);
|
||||
// TODO: refresh folder list here
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -12,6 +12,7 @@ import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.method.DigitsKeyListener;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.AdapterView;
|
||||
@ -22,6 +23,7 @@ import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.email.Account;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.R;
|
||||
import com.android.email.Utility;
|
||||
@ -104,12 +106,15 @@ public class AccountSetupIncoming extends Activity implements OnClickListener {
|
||||
};
|
||||
|
||||
SpinnerOption deletePolicies[] = {
|
||||
new SpinnerOption(0,
|
||||
new SpinnerOption(Account.DELETE_POLICY_NEVER,
|
||||
getString(R.string.account_setup_incoming_delete_policy_never_label)),
|
||||
new SpinnerOption(1,
|
||||
getString(R.string.account_setup_incoming_delete_policy_7days_label)),
|
||||
new SpinnerOption(2,
|
||||
/*new SpinnerOption(Account.DELETE_POLICY_7DAYS,
|
||||
getString(R.string.account_setup_incoming_delete_policy_7days_label)),*/
|
||||
new SpinnerOption(Account.DELETE_POLICY_ON_DELETE,
|
||||
getString(R.string.account_setup_incoming_delete_policy_delete_label)),
|
||||
new SpinnerOption(Account.DELETE_POLICY_MARK_AS_READ,
|
||||
getString(R.string.account_setup_incoming_delete_policy_markread_label)),
|
||||
|
||||
};
|
||||
|
||||
ArrayAdapter<SpinnerOption> securityTypesAdapter = new ArrayAdapter<SpinnerOption>(this,
|
||||
@ -203,8 +208,6 @@ public class AccountSetupIncoming extends Activity implements OnClickListener {
|
||||
mAccountPorts = imapPorts;
|
||||
mAccountSchemes = imapSchemes;
|
||||
|
||||
findViewById(R.id.account_delete_policy_label).setVisibility(View.GONE);
|
||||
mDeletePolicyView.setVisibility(View.GONE);
|
||||
if (uri.getPath() != null && uri.getPath().length() > 0) {
|
||||
mImapPathPrefixView.setText(uri.getPath().substring(1));
|
||||
}
|
||||
@ -326,9 +329,10 @@ public class AccountSetupIncoming extends Activity implements OnClickListener {
|
||||
throw new Error(use);
|
||||
}
|
||||
|
||||
mAccount.setDeletePolicy((Integer)((SpinnerOption)mDeletePolicyView.getSelectedItem()).value);
|
||||
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, false);
|
||||
int deleteSpinnerVal = (Integer)((SpinnerOption)mDeletePolicyView.getSelectedItem()).value;
|
||||
|
||||
mAccount.setDeletePolicy(deleteSpinnerVal);
|
||||
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, false);
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
|
@ -28,7 +28,6 @@ public class AccountSetupOptions extends Activity implements OnClickListener {
|
||||
private CheckBox mDefaultView;
|
||||
|
||||
private CheckBox mNotifyView;
|
||||
private CheckBox mNotifyRingtoneView;
|
||||
|
||||
private Account mAccount;
|
||||
|
||||
@ -48,13 +47,14 @@ public class AccountSetupOptions extends Activity implements OnClickListener {
|
||||
mDisplayCountView = (Spinner)findViewById(R.id.account_display_count);
|
||||
mDefaultView = (CheckBox)findViewById(R.id.account_default);
|
||||
mNotifyView = (CheckBox)findViewById(R.id.account_notify);
|
||||
mNotifyRingtoneView = (CheckBox)findViewById(R.id.account_notify_ringtone);
|
||||
|
||||
findViewById(R.id.next).setOnClickListener(this);
|
||||
|
||||
SpinnerOption checkFrequencies[] = {
|
||||
new SpinnerOption(-1,
|
||||
getString(R.string.account_setup_options_mail_check_frequency_never)),
|
||||
new SpinnerOption(1,
|
||||
getString(R.string.account_setup_options_mail_check_frequency_1min)),
|
||||
new SpinnerOption(5,
|
||||
getString(R.string.account_setup_options_mail_check_frequency_5min)),
|
||||
new SpinnerOption(10,
|
||||
@ -96,7 +96,6 @@ public class AccountSetupOptions extends Activity implements OnClickListener {
|
||||
mDefaultView.setChecked(true);
|
||||
}
|
||||
mNotifyView.setChecked(mAccount.isNotifyNewMail());
|
||||
mNotifyRingtoneView.setChecked(mAccount.isNotifyRingtone());
|
||||
SpinnerOption.setSpinnerOptionValue(mCheckFrequencyView, mAccount
|
||||
.getAutomaticCheckIntervalMinutes());
|
||||
SpinnerOption.setSpinnerOptionValue(mDisplayCountView, mAccount
|
||||
@ -106,7 +105,6 @@ public class AccountSetupOptions extends Activity implements OnClickListener {
|
||||
private void onDone() {
|
||||
mAccount.setDescription(mAccount.getEmail());
|
||||
mAccount.setNotifyNewMail(mNotifyView.isChecked());
|
||||
mAccount.setNotifyRingtone(mNotifyRingtoneView.isChecked());
|
||||
mAccount.setAutomaticCheckIntervalMinutes((Integer)((SpinnerOption)mCheckFrequencyView
|
||||
.getSelectedItem()).value);
|
||||
mAccount.setDisplayCount((Integer)((SpinnerOption)mDisplayCountView
|
||||
|
136
src/com/android/email/activity/setup/FolderSettings.java
Normal file
136
src/com/android/email/activity/setup/FolderSettings.java
Normal file
@ -0,0 +1,136 @@
|
||||
|
||||
package com.android.email.activity.setup;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.RingtonePreference;
|
||||
|
||||
import com.android.email.Account;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.R;
|
||||
import com.android.email.mail.Folder;
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.Store;
|
||||
import com.android.email.mail.Folder.FolderClass;
|
||||
import com.android.email.mail.store.LocalStore.LocalFolder;
|
||||
|
||||
public class FolderSettings extends PreferenceActivity {
|
||||
|
||||
private static final String EXTRA_FOLDER_NAME = "com.android.email.folderName";
|
||||
private static final String EXTRA_ACCOUNT = "com.android.email.account";
|
||||
|
||||
private static final String PREFERENCE_TOP_CATERGORY = "folder_settings";
|
||||
private static final String PREFERENCE_DISPLAY_CLASS = "folder_settings_folder_display_mode";
|
||||
private static final String PREFERENCE_SYNC_CLASS = "folder_settings_folder_sync_mode";
|
||||
|
||||
private LocalFolder mFolder;
|
||||
|
||||
private ListPreference mDisplayClass;
|
||||
private ListPreference mSyncClass;
|
||||
|
||||
public static void actionSettings(Context context, Account account, String folderName) {
|
||||
Intent i = new Intent(context, FolderSettings.class);
|
||||
i.putExtra(EXTRA_FOLDER_NAME, folderName);
|
||||
i.putExtra(EXTRA_ACCOUNT, account);
|
||||
context.startActivity(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String folderName = (String)getIntent().getSerializableExtra(EXTRA_FOLDER_NAME);
|
||||
Account mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
|
||||
|
||||
try
|
||||
{
|
||||
Store localStore = Store.getInstance(mAccount.getLocalStoreUri(),
|
||||
getApplication());
|
||||
mFolder = (LocalFolder) localStore.getFolder(folderName);
|
||||
mFolder.refresh(Preferences.getPreferences(this));
|
||||
}
|
||||
catch (MessagingException me)
|
||||
{
|
||||
Log.e(Email.LOG_TAG, "Unable to edit folder " + folderName + " preferences", me);
|
||||
return;
|
||||
}
|
||||
|
||||
addPreferencesFromResource(R.xml.folder_settings_preferences);
|
||||
|
||||
Preference category = findPreference(PREFERENCE_TOP_CATERGORY);
|
||||
category.setTitle(getString(R.string.folder_settings_title));
|
||||
|
||||
mDisplayClass = (ListPreference) findPreference(PREFERENCE_DISPLAY_CLASS);
|
||||
mDisplayClass.setValue(mFolder.getDisplayClass().name());
|
||||
mDisplayClass.setSummary(mDisplayClass.getEntry());
|
||||
mDisplayClass.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final String summary = newValue.toString();
|
||||
int index = mDisplayClass.findIndexOfValue(summary);
|
||||
mDisplayClass.setSummary(mDisplayClass.getEntries()[index]);
|
||||
mDisplayClass.setValue(summary);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mSyncClass = (ListPreference) findPreference(PREFERENCE_SYNC_CLASS);
|
||||
mSyncClass.setValue(mFolder.getRawSyncClass().name());
|
||||
mSyncClass.setSummary(mSyncClass.getEntry());
|
||||
mSyncClass.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final String summary = newValue.toString();
|
||||
int index = mSyncClass.findIndexOfValue(summary);
|
||||
mSyncClass.setSummary(mSyncClass.getEntries()[index]);
|
||||
mSyncClass.setValue(summary);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
try
|
||||
{
|
||||
mFolder.refresh(Preferences.getPreferences(this));
|
||||
}
|
||||
catch (MessagingException me)
|
||||
{
|
||||
Log.e(Email.LOG_TAG, "Could not refresh folder preferences for folder " + mFolder.getName(), me);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveSettings() {
|
||||
mFolder.setDisplayClass(FolderClass.valueOf(mDisplayClass.getValue()));
|
||||
mFolder.setSyncClass(FolderClass.valueOf(mSyncClass.getValue()));
|
||||
|
||||
try
|
||||
{
|
||||
mFolder.save(Preferences.getPreferences(this));
|
||||
}
|
||||
catch (MessagingException me)
|
||||
{
|
||||
Log.e(Email.LOG_TAG, "Could not refresh folder preferences for folder " + mFolder.getName(), me);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
saveSettings();
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -18,6 +18,10 @@ public enum Flag {
|
||||
* these flags and Strings to represent user defined flags. At that point the below
|
||||
* flags should become user defined flags.
|
||||
*/
|
||||
/*
|
||||
* For POP3 to indicate that the message does not have SEEN info
|
||||
*/
|
||||
X_NO_SEEN_INFO,
|
||||
/**
|
||||
* Delete and remove from the LocalStore immediately.
|
||||
*/
|
||||
@ -45,4 +49,9 @@ public enum Flag {
|
||||
* This does not include attachments, which are never downloaded fully.
|
||||
*/
|
||||
X_DOWNLOADED_PARTIAL,
|
||||
|
||||
/**
|
||||
* Indicates that the copy of a message to the Sent folder has started.
|
||||
*/
|
||||
X_REMOTE_COPY_STARTED,
|
||||
}
|
||||
|
@ -1,11 +1,19 @@
|
||||
package com.android.email.mail;
|
||||
|
||||
import com.android.email.Preferences;
|
||||
|
||||
|
||||
public abstract class Folder {
|
||||
private String status = null;
|
||||
private long lastChecked = 0;
|
||||
public enum OpenMode {
|
||||
READ_WRITE, READ_ONLY,
|
||||
}
|
||||
|
||||
|
||||
public enum FolderClass {
|
||||
NONE, FIRST_CLASS, SECOND_CLASS;
|
||||
}
|
||||
|
||||
public enum FolderType {
|
||||
HOLDS_FOLDERS, HOLDS_MESSAGES,
|
||||
}
|
||||
@ -84,6 +92,10 @@ public abstract class Folder {
|
||||
|
||||
public abstract void setFlags(Message[] messages, Flag[] flags, boolean value)
|
||||
throws MessagingException;
|
||||
|
||||
public abstract void setFlags(Flag[] flags, boolean value) throws MessagingException;
|
||||
|
||||
public abstract String getUidFromMessageId(Message message) throws MessagingException;
|
||||
|
||||
public abstract Message[] expunge() throws MessagingException;
|
||||
|
||||
@ -104,4 +116,42 @@ public abstract class Folder {
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
public long getLastChecked()
|
||||
{
|
||||
return lastChecked;
|
||||
}
|
||||
|
||||
public void setLastChecked(long lastChecked) throws MessagingException
|
||||
{
|
||||
this.lastChecked = lastChecked;
|
||||
}
|
||||
|
||||
public FolderClass getDisplayClass()
|
||||
{
|
||||
return FolderClass.NONE;
|
||||
}
|
||||
|
||||
public FolderClass getSyncClass()
|
||||
{
|
||||
return getDisplayClass();
|
||||
}
|
||||
|
||||
public void refresh(Preferences preferences) throws MessagingException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public String getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) throws MessagingException
|
||||
{
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -83,6 +83,8 @@ public abstract class Message implements Part, Body {
|
||||
public boolean isMimeType(String mimeType) throws MessagingException {
|
||||
return getContentType().startsWith(mimeType);
|
||||
}
|
||||
|
||||
public void delete(String trashFolderName) throws MessagingException {} ;
|
||||
|
||||
/*
|
||||
* TODO Refactor Flags at some point to be able to store user defined flags.
|
||||
|
@ -7,6 +7,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
@ -17,6 +18,7 @@ import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@ -44,6 +46,7 @@ import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.Part;
|
||||
import com.android.email.mail.Store;
|
||||
import com.android.email.mail.CertificateValidationException;
|
||||
import com.android.email.mail.Folder.FolderType;
|
||||
import com.android.email.mail.internet.MimeBodyPart;
|
||||
import com.android.email.mail.internet.MimeHeader;
|
||||
import com.android.email.mail.internet.MimeMessage;
|
||||
@ -167,7 +170,7 @@ public class ImapStore extends Store {
|
||||
synchronized (mFolderCache) {
|
||||
folder = mFolderCache.get(name);
|
||||
if (folder == null) {
|
||||
folder = new ImapFolder(name);
|
||||
folder = new ImapFolder(this, name);
|
||||
mFolderCache.put(name, folder);
|
||||
}
|
||||
}
|
||||
@ -263,7 +266,10 @@ public class ImapStore extends Store {
|
||||
}
|
||||
|
||||
private void releaseConnection(ImapConnection connection) {
|
||||
mConnections.offer(connection);
|
||||
synchronized(mConnections)
|
||||
{
|
||||
mConnections.offer(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private String encodeFolderName(String name) {
|
||||
@ -307,14 +313,16 @@ public class ImapStore extends Store {
|
||||
private ImapConnection mConnection;
|
||||
private OpenMode mMode;
|
||||
private boolean mExists;
|
||||
private ImapStore store = null;
|
||||
|
||||
public ImapFolder(String name) {
|
||||
public ImapFolder(ImapStore nStore, String name) {
|
||||
store = nStore;
|
||||
this.mName = name;
|
||||
}
|
||||
|
||||
public String getPrefixedName() {
|
||||
String prefixedName = "";
|
||||
if(mPathPrefix.length() > 0 && !mName.equalsIgnoreCase(Email.INBOX)){
|
||||
if(mPathPrefix != null && mPathPrefix.length() > 0 && !Email.INBOX.equalsIgnoreCase(mName)){
|
||||
prefixedName += mPathPrefix + mPathDelimeter;
|
||||
}
|
||||
|
||||
@ -399,11 +407,14 @@ public class ImapStore extends Store {
|
||||
return mMode;
|
||||
}
|
||||
|
||||
public void close(boolean expunge) {
|
||||
public void close(boolean expunge) throws MessagingException {
|
||||
if (!isOpen()) {
|
||||
return;
|
||||
}
|
||||
// TODO implement expunge
|
||||
if (expunge)
|
||||
{
|
||||
expunge();
|
||||
}
|
||||
mMessageCount = -1;
|
||||
synchronized (this) {
|
||||
releaseConnection(mConnection);
|
||||
@ -1002,31 +1013,63 @@ public class ImapStore extends Store {
|
||||
while (response.more());
|
||||
} while(response.mTag == null);
|
||||
|
||||
/*
|
||||
* Try to find the UID of the message we just appended using the
|
||||
* Message-ID header.
|
||||
*/
|
||||
String[] messageIdHeader = message.getHeader("Message-ID");
|
||||
if (messageIdHeader == null || messageIdHeader.length == 0) {
|
||||
continue;
|
||||
String newUid = getUidFromMessageId(message);
|
||||
if (Config.LOGD)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "Got UID " + newUid + " for message");
|
||||
}
|
||||
|
||||
if (newUid != null)
|
||||
{
|
||||
message.setUid(newUid);
|
||||
}
|
||||
String messageId = messageIdHeader[0];
|
||||
List<ImapResponse> responses =
|
||||
mConnection.executeSimpleCommand(
|
||||
String.format("UID SEARCH (HEADER MESSAGE-ID %s)", messageId));
|
||||
for (ImapResponse response1 : responses) {
|
||||
if (response1.mTag == null && response1.get(0).equals("SEARCH")
|
||||
&& response1.size() > 1) {
|
||||
message.setUid(response1.getString(1));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
throw ioExceptionHandler(mConnection, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public String getUidFromMessageId(Message message) throws MessagingException
|
||||
{
|
||||
try
|
||||
{
|
||||
/*
|
||||
* Try to find the UID of the message we just appended using the
|
||||
* Message-ID header.
|
||||
*/
|
||||
String[] messageIdHeader = message.getHeader("Message-ID");
|
||||
|
||||
if (messageIdHeader == null || messageIdHeader.length == 0) {
|
||||
if (Config.LOGD)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "Did not get a message-id in order to search for UID");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
String messageId = messageIdHeader[0];
|
||||
if (Config.LOGD)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "Looking for UID for message with message-id " + messageId);
|
||||
}
|
||||
|
||||
List<ImapResponse> responses =
|
||||
mConnection.executeSimpleCommand(
|
||||
String.format("UID SEARCH (HEADER MESSAGE-ID %s)", messageId));
|
||||
for (ImapResponse response1 : responses) {
|
||||
if (response1.mTag == null && response1.get(0).equals("SEARCH")
|
||||
&& response1.size() > 1) {
|
||||
return response1.getString(1);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new MessagingException("Could not find UID for message based on Message-ID", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Message[] expunge() throws MessagingException {
|
||||
checkOpen();
|
||||
@ -1038,6 +1081,31 @@ public class ImapStore extends Store {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlags(Flag[] flags, boolean value)
|
||||
throws MessagingException {
|
||||
checkOpen();
|
||||
|
||||
ArrayList<String> flagNames = new ArrayList<String>();
|
||||
for (int i = 0, count = flags.length; i < count; i++) {
|
||||
Flag flag = flags[i];
|
||||
if (flag == Flag.SEEN) {
|
||||
flagNames.add("\\Seen");
|
||||
}
|
||||
else if (flag == Flag.DELETED) {
|
||||
flagNames.add("\\Deleted");
|
||||
}
|
||||
}
|
||||
try {
|
||||
mConnection.executeSimpleCommand(String.format("UID STORE 1:* %sFLAGS.SILENT (%s)",
|
||||
value ? "+" : "-",
|
||||
Utility.combine(flagNames.toArray(new String[flagNames.size()]), ' ')));
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
throw ioExceptionHandler(mConnection, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFlags(Message[] messages, Flag[] flags, boolean value)
|
||||
throws MessagingException {
|
||||
checkOpen();
|
||||
@ -1086,6 +1154,11 @@ public class ImapStore extends Store {
|
||||
}
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
protected ImapStore getStore()
|
||||
{
|
||||
return store;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1104,9 +1177,21 @@ public class ImapStore extends Store {
|
||||
}
|
||||
|
||||
mNextCommandTag = 1;
|
||||
|
||||
try
|
||||
{
|
||||
Security.setProperty("networkaddress.cache.ttl", "0");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.w(Email.LOG_TAG, "Could not set DNS ttl to 0", e);
|
||||
}
|
||||
|
||||
try {
|
||||
SocketAddress socketAddress = new InetSocketAddress(mHost, mPort);
|
||||
|
||||
SocketAddress socketAddress = new InetSocketAddress(mHost, mPort);
|
||||
|
||||
Log.i(Email.LOG_TAG, "Connecting to " + mHost + " @ IP addr " + socketAddress);
|
||||
|
||||
if (mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED ||
|
||||
mConnectionSecurity == CONNECTION_SECURITY_SSL_OPTIONAL) {
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
@ -1177,6 +1262,20 @@ public class ImapStore extends Store {
|
||||
throw new MessagingException(
|
||||
"Unable to open connection to IMAP server due to security error.", gse);
|
||||
}
|
||||
catch (ConnectException ce)
|
||||
{
|
||||
String ceMess = ce.getMessage();
|
||||
String[] tokens = ceMess.split("-");
|
||||
if (tokens != null && tokens.length > 1 && tokens[1] != null)
|
||||
{
|
||||
Log.e(Email.LOG_TAG, "Stripping host/port from ConnectionException", ce);
|
||||
throw new ConnectException(tokens[1].trim());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ce;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
@ -1245,11 +1344,19 @@ public class ImapStore extends Store {
|
||||
|
||||
public List<ImapResponse> executeSimpleCommand(String command, boolean sensitive)
|
||||
throws IOException, ImapException, MessagingException {
|
||||
if (Config.LOGV)
|
||||
{
|
||||
Log.v(Email.LOG_TAG, "Sending IMAP command " + command);
|
||||
}
|
||||
String tag = sendCommand(command, sensitive);
|
||||
ArrayList<ImapResponse> responses = new ArrayList<ImapResponse>();
|
||||
ImapResponse response;
|
||||
do {
|
||||
response = mParser.readResponse();
|
||||
if (Config.LOGV)
|
||||
{
|
||||
Log.v(Email.LOG_TAG, "Got IMAP response " + response);
|
||||
}
|
||||
responses.add(response);
|
||||
} while (response.mTag == null);
|
||||
if (response.size() < 1 || !response.get(0).equals("OK")) {
|
||||
@ -1282,6 +1389,40 @@ public class ImapStore extends Store {
|
||||
super.setFlag(flag, set);
|
||||
mFolder.setFlags(new Message[] { this }, new Flag[] { flag }, set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String trashFolderName) throws MessagingException
|
||||
{
|
||||
ImapFolder iFolder = (ImapFolder)getFolder();
|
||||
Folder remoteTrashFolder = iFolder.getStore().getFolder(trashFolderName);
|
||||
/*
|
||||
* Attempt to copy the remote message to the remote trash folder.
|
||||
*/
|
||||
if (!remoteTrashFolder.exists()) {
|
||||
/*
|
||||
* If the remote trash folder doesn't exist we try to create it.
|
||||
*/
|
||||
Log.i(Email.LOG_TAG, "IMAPMessage.delete: attempting to create remote " + trashFolderName + " folder");
|
||||
remoteTrashFolder.create(FolderType.HOLDS_MESSAGES);
|
||||
}
|
||||
|
||||
if (remoteTrashFolder.exists()) {
|
||||
if (Config.LOGD)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "IMAPMessage.delete: copying remote message to " + trashFolderName);
|
||||
}
|
||||
iFolder.copyMessages(new Message[] { this }, remoteTrashFolder);
|
||||
setFlag(Flag.DELETED, true);
|
||||
iFolder.expunge();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Toast.makeText(context, R.string.message_delete_failed, Toast.LENGTH_SHORT).show();
|
||||
|
||||
Log.e(Email.LOG_TAG, "IMAPMessage.delete: remote Trash folder " + trashFolderName + " does not exist and could not be created");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ImapBodyPart extends MimeBodyPart {
|
||||
|
@ -8,12 +8,14 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
@ -26,6 +28,7 @@ import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.Utility;
|
||||
import com.android.email.codec.binary.Base64OutputStream;
|
||||
import com.android.email.mail.Address;
|
||||
@ -38,6 +41,7 @@ import com.android.email.mail.MessageRetrievalListener;
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.Part;
|
||||
import com.android.email.mail.Store;
|
||||
import com.android.email.mail.Folder.FolderClass;
|
||||
import com.android.email.mail.Message.RecipientType;
|
||||
import com.android.email.mail.internet.MimeBodyPart;
|
||||
import com.android.email.mail.internet.MimeHeader;
|
||||
@ -52,14 +56,15 @@ import com.android.email.provider.AttachmentProvider;
|
||||
* Implements a SQLite database backed local store for Messages.
|
||||
* </pre>
|
||||
*/
|
||||
public class LocalStore extends Store {
|
||||
private static final int DB_VERSION = 18;
|
||||
public class LocalStore extends Store implements Serializable {
|
||||
private static final int DB_VERSION = 22;
|
||||
private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN };
|
||||
|
||||
private String mPath;
|
||||
private SQLiteDatabase mDb;
|
||||
private File mAttachmentsDir;
|
||||
private Application mApplication;
|
||||
private String uUid = null;
|
||||
|
||||
/**
|
||||
* @param uri local://localhost/path/to/database/uuid.db
|
||||
@ -77,6 +82,14 @@ public class LocalStore extends Store {
|
||||
}
|
||||
mPath = uri.getPath();
|
||||
|
||||
|
||||
// We need to associate the localstore with the account. Since we don't have the account
|
||||
// handy here, we'll take the filename from the DB and use the basename of the filename
|
||||
// Folders probably should have references to their containing accounts
|
||||
File dbFile = new File(mPath);
|
||||
String[] tokens = dbFile.getName().split("\\.");
|
||||
uUid = tokens[0];
|
||||
|
||||
File parentDir = new File(mPath).getParentFile();
|
||||
if (!parentDir.exists()) {
|
||||
parentDir.mkdirs();
|
||||
@ -95,58 +108,58 @@ public class LocalStore extends Store {
|
||||
|
||||
|
||||
private void doDbUpgrade ( SQLiteDatabase mDb) {
|
||||
|
||||
if (mDb.getVersion() < 18) {
|
||||
if (Config.LOGV) {
|
||||
Log.v(Email.LOG_TAG, String.format("Upgrading database from %d to %d", mDb
|
||||
.getVersion(), 18));
|
||||
}
|
||||
mDb.execSQL("DROP TABLE IF EXISTS folders");
|
||||
mDb.execSQL("CREATE TABLE folders (id INTEGER PRIMARY KEY, name TEXT, "
|
||||
+ "last_updated INTEGER, unread_count INTEGER, visible_limit INTEGER)");
|
||||
|
||||
mDb.execSQL("DROP TABLE IF EXISTS messages");
|
||||
mDb.execSQL("CREATE TABLE messages (id INTEGER PRIMARY KEY, folder_id INTEGER, uid TEXT, subject TEXT, "
|
||||
+ "date INTEGER, flags TEXT, sender_list TEXT, to_list TEXT, cc_list TEXT, bcc_list TEXT, reply_to_list TEXT, "
|
||||
+ "html_content TEXT, text_content TEXT, attachment_count INTEGER, internal_date INTEGER)");
|
||||
|
||||
mDb.execSQL("DROP TABLE IF EXISTS attachments");
|
||||
mDb.execSQL("CREATE TABLE attachments (id INTEGER PRIMARY KEY, message_id INTEGER,"
|
||||
+ "store_data TEXT, content_uri TEXT, size INTEGER, name TEXT,"
|
||||
+ "mime_type TEXT)");
|
||||
|
||||
mDb.execSQL("DROP TABLE IF EXISTS pending_commands");
|
||||
mDb.execSQL("CREATE TABLE pending_commands " +
|
||||
"(id INTEGER PRIMARY KEY, command TEXT, arguments TEXT)");
|
||||
|
||||
mDb.execSQL("DROP TRIGGER IF EXISTS delete_folder");
|
||||
mDb.execSQL("CREATE TRIGGER delete_folder BEFORE DELETE ON folders BEGIN DELETE FROM messages WHERE old.id = folder_id; END;");
|
||||
|
||||
mDb.execSQL("DROP TRIGGER IF EXISTS delete_message");
|
||||
mDb.execSQL("CREATE TRIGGER delete_message BEFORE DELETE ON messages BEGIN DELETE FROM attachments WHERE old.id = message_id; END;");
|
||||
mDb.setVersion(18);
|
||||
if (Config.LOGV) {
|
||||
Log.v(Email.LOG_TAG, String.format("Upgrading database from %d to %d", mDb
|
||||
.getVersion(), DB_VERSION));
|
||||
}
|
||||
mDb.execSQL("DROP TABLE IF EXISTS folders");
|
||||
mDb.execSQL("CREATE TABLE folders (id INTEGER PRIMARY KEY, name TEXT, "
|
||||
+ "last_updated INTEGER, unread_count INTEGER, visible_limit INTEGER, status TEXT)");
|
||||
|
||||
mDb.execSQL("DROP TABLE IF EXISTS messages");
|
||||
mDb.execSQL("CREATE TABLE messages (id INTEGER PRIMARY KEY, folder_id INTEGER, uid TEXT, subject TEXT, "
|
||||
+ "date INTEGER, flags TEXT, sender_list TEXT, to_list TEXT, cc_list TEXT, bcc_list TEXT, reply_to_list TEXT, "
|
||||
+ "html_content TEXT, text_content TEXT, attachment_count INTEGER, internal_date INTEGER, message_id TEXT)");
|
||||
|
||||
mDb.execSQL("DROP TABLE IF EXISTS attachments");
|
||||
mDb.execSQL("CREATE TABLE attachments (id INTEGER PRIMARY KEY, message_id INTEGER,"
|
||||
+ "store_data TEXT, content_uri TEXT, size INTEGER, name TEXT,"
|
||||
+ "mime_type TEXT)");
|
||||
|
||||
mDb.execSQL("DROP TABLE IF EXISTS pending_commands");
|
||||
mDb.execSQL("CREATE TABLE pending_commands " +
|
||||
"(id INTEGER PRIMARY KEY, command TEXT, arguments TEXT)");
|
||||
|
||||
mDb.execSQL("DROP TRIGGER IF EXISTS delete_folder");
|
||||
mDb.execSQL("CREATE TRIGGER delete_folder BEFORE DELETE ON folders BEGIN DELETE FROM messages WHERE old.id = folder_id; END;");
|
||||
|
||||
mDb.execSQL("DROP TRIGGER IF EXISTS delete_message");
|
||||
mDb.execSQL("CREATE TRIGGER delete_message BEFORE DELETE ON messages BEGIN DELETE FROM attachments WHERE old.id = message_id; END;");
|
||||
mDb.setVersion(DB_VERSION);
|
||||
if (mDb.getVersion() != DB_VERSION) {
|
||||
throw new Error("Database upgrade failed!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Folder getFolder(String name) throws MessagingException {
|
||||
public LocalFolder getFolder(String name) throws MessagingException {
|
||||
return new LocalFolder(name);
|
||||
}
|
||||
|
||||
// TODO this takes about 260-300ms, seems slow.
|
||||
@Override
|
||||
public Folder[] getPersonalNamespaces() throws MessagingException {
|
||||
ArrayList<Folder> folders = new ArrayList<Folder>();
|
||||
public LocalFolder[] getPersonalNamespaces() throws MessagingException {
|
||||
ArrayList<LocalFolder> folders = new ArrayList<LocalFolder>();
|
||||
Cursor cursor = null;
|
||||
|
||||
|
||||
try {
|
||||
cursor = mDb.rawQuery("SELECT name FROM folders", null);
|
||||
cursor = mDb.rawQuery("SELECT name, id, unread_count, visible_limit, last_updated, status FROM folders", null);
|
||||
while (cursor.moveToNext()) {
|
||||
folders.add(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));
|
||||
|
||||
folders.add(folder);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@ -154,7 +167,7 @@ public class LocalStore extends Store {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return folders.toArray(new Folder[] {});
|
||||
return folders.toArray(new LocalFolder[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -300,6 +313,10 @@ public class LocalStore extends Store {
|
||||
public void removePendingCommand(PendingCommand command) {
|
||||
mDb.delete("pending_commands", "id = ?", new String[] { Long.toString(command.mId) });
|
||||
}
|
||||
|
||||
public void removePendingCommands() {
|
||||
mDb.delete("pending_commands", null, null);
|
||||
}
|
||||
|
||||
public static class PendingCommand {
|
||||
private long mId;
|
||||
@ -310,21 +327,24 @@ public class LocalStore extends Store {
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(command);
|
||||
sb.append("\n");
|
||||
sb.append(": ");
|
||||
for (String argument : arguments) {
|
||||
sb.append(" ");
|
||||
sb.append(argument);
|
||||
sb.append("\n");
|
||||
//sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public class LocalFolder extends Folder {
|
||||
public class LocalFolder extends Folder implements Serializable {
|
||||
private String mName;
|
||||
private long mFolderId = -1;
|
||||
private int mUnreadMessageCount = -1;
|
||||
private int mVisibleLimit = -1;
|
||||
private FolderClass displayClass = FolderClass.NONE;
|
||||
private FolderClass syncClass = FolderClass.NONE;
|
||||
private String prefId = null;
|
||||
|
||||
public LocalFolder(String name) {
|
||||
this.mName = name;
|
||||
@ -341,26 +361,32 @@ public class LocalStore extends Store {
|
||||
}
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = mDb.rawQuery(
|
||||
"SELECT id, unread_count, visible_limit FROM folders "
|
||||
+ "where folders.name = ?",
|
||||
new String[] { mName });
|
||||
if (cursor.moveToFirst()) {
|
||||
mFolderId = cursor.getInt(0);
|
||||
mUnreadMessageCount = cursor.getInt(1);
|
||||
mVisibleLimit = cursor.getInt(2);
|
||||
} else {
|
||||
// Calling exists on open is a little expensive. Instead,
|
||||
// just handle it when we don't find it.
|
||||
create(FolderType.HOLDS_MESSAGES);
|
||||
open(mode);
|
||||
}
|
||||
} finally {
|
||||
cursor = mDb.rawQuery("SELECT id, unread_count, visible_limit, last_updated, status FROM folders "
|
||||
+ "where folders.name = ?",
|
||||
new String[] {
|
||||
mName
|
||||
});
|
||||
cursor.moveToFirst();
|
||||
open(cursor.getInt(0), cursor.getInt(1), cursor.getInt(2), cursor.getLong(3), cursor.getString(4));
|
||||
|
||||
}
|
||||
finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void open(int id, int unreadCount, int visibleLimit, long lastChecked, String status) throws MessagingException
|
||||
{
|
||||
mFolderId = id;
|
||||
mUnreadMessageCount = unreadCount;
|
||||
mVisibleLimit = visibleLimit;
|
||||
super.setStatus(status);
|
||||
// Only want to set the local variable stored in the super class. This class
|
||||
// does a DB update on setLastChecked
|
||||
super.setLastChecked(lastChecked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
@ -461,6 +487,13 @@ public class LocalStore extends Store {
|
||||
mDb.execSQL("UPDATE folders SET unread_count = ? WHERE id = ?",
|
||||
new Object[] { mUnreadMessageCount, mFolderId });
|
||||
}
|
||||
|
||||
public void setLastChecked(long lastChecked) throws MessagingException {
|
||||
open(OpenMode.READ_WRITE);
|
||||
super.setLastChecked(lastChecked);
|
||||
mDb.execSQL("UPDATE folders SET last_updated = ? WHERE id = ?",
|
||||
new Object[] { lastChecked, mFolderId });
|
||||
}
|
||||
|
||||
public int getVisibleLimit() throws MessagingException {
|
||||
open(OpenMode.READ_WRITE);
|
||||
@ -474,8 +507,128 @@ public class LocalStore extends Store {
|
||||
mDb.execSQL("UPDATE folders SET visible_limit = ? WHERE id = ?",
|
||||
new Object[] { mVisibleLimit, mFolderId });
|
||||
}
|
||||
|
||||
public void setStatus(String status) throws MessagingException
|
||||
{
|
||||
open(OpenMode.READ_WRITE);
|
||||
super.setStatus(status);
|
||||
mDb.execSQL("UPDATE folders SET status = ? WHERE id = ?",
|
||||
new Object[] { status, mFolderId });
|
||||
}
|
||||
@Override
|
||||
public FolderClass getDisplayClass()
|
||||
{
|
||||
return displayClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FolderClass getSyncClass()
|
||||
{
|
||||
if (FolderClass.NONE == syncClass)
|
||||
{
|
||||
return displayClass;
|
||||
}
|
||||
else
|
||||
{
|
||||
return syncClass;
|
||||
}
|
||||
}
|
||||
|
||||
public FolderClass getRawSyncClass()
|
||||
{
|
||||
|
||||
return syncClass;
|
||||
|
||||
}
|
||||
|
||||
public void setDisplayClass(FolderClass displayClass)
|
||||
{
|
||||
this.displayClass = displayClass;
|
||||
}
|
||||
|
||||
public void setSyncClass(FolderClass syncClass)
|
||||
{
|
||||
this.syncClass = syncClass;
|
||||
}
|
||||
|
||||
private String getPrefId() throws MessagingException
|
||||
{
|
||||
open(OpenMode.READ_WRITE);
|
||||
|
||||
if (prefId == null)
|
||||
{
|
||||
prefId = uUid + "." + mName;
|
||||
}
|
||||
|
||||
return prefId;
|
||||
}
|
||||
|
||||
public void delete(Preferences preferences) throws MessagingException {
|
||||
String id = getPrefId();
|
||||
|
||||
SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
||||
|
||||
editor.remove(id + ".displayMode");
|
||||
editor.remove(id + ".syncMode");
|
||||
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public void save(Preferences preferences) throws MessagingException {
|
||||
String id = getPrefId();
|
||||
|
||||
SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
||||
// there can be a lot of folders. For the defaults, let's not save prefs, saving space
|
||||
if (displayClass == FolderClass.NONE)
|
||||
{
|
||||
editor.remove(id + ".displayMode");
|
||||
}
|
||||
else
|
||||
{
|
||||
editor.putString(id + ".displayMode", displayClass.name());
|
||||
}
|
||||
|
||||
if (syncClass == FolderClass.NONE)
|
||||
{
|
||||
editor.remove(id + ".syncMode");
|
||||
}
|
||||
else
|
||||
{
|
||||
editor.putString(id + ".syncMode", syncClass.name());
|
||||
}
|
||||
|
||||
editor.commit();
|
||||
}
|
||||
public void refresh(Preferences preferences) throws MessagingException {
|
||||
|
||||
String id = getPrefId();
|
||||
|
||||
try
|
||||
{
|
||||
displayClass = FolderClass.valueOf(preferences.mSharedPreferences.getString(id + ".displayMode",
|
||||
FolderClass.NONE.name()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e(Email.LOG_TAG, "Unable to load displayMode for " + getName(), e);
|
||||
|
||||
displayClass = FolderClass.NONE;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
syncClass = FolderClass.valueOf(preferences.mSharedPreferences.getString(id + ".syncMode",
|
||||
FolderClass.NONE.name()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e(Email.LOG_TAG, "Unable to load syncMode for " + getName(), e);
|
||||
|
||||
syncClass = FolderClass.NONE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener listener)
|
||||
throws MessagingException {
|
||||
@ -596,6 +749,7 @@ public class LocalStore extends Store {
|
||||
message.setReplyTo(Address.unpack(cursor.getString(9)));
|
||||
message.mAttachmentCount = cursor.getInt(10);
|
||||
message.setInternalDate(new Date(cursor.getLong(11)));
|
||||
message.setHeader("Message-ID", cursor.getString(12));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -614,7 +768,7 @@ public class LocalStore extends Store {
|
||||
try {
|
||||
cursor = mDb.rawQuery(
|
||||
"SELECT subject, sender_list, date, uid, flags, id, to_list, cc_list, "
|
||||
+ "bcc_list, reply_to_list, attachment_count, internal_date "
|
||||
+ "bcc_list, reply_to_list, attachment_count, internal_date, message_id "
|
||||
+ "FROM messages " + "WHERE uid = ? " + "AND folder_id = ?",
|
||||
new String[] {
|
||||
message.getUid(), Long.toString(mFolderId)
|
||||
@ -640,7 +794,7 @@ public class LocalStore extends Store {
|
||||
try {
|
||||
cursor = mDb.rawQuery(
|
||||
"SELECT subject, sender_list, date, uid, flags, id, to_list, cc_list, "
|
||||
+ "bcc_list, reply_to_list, attachment_count, internal_date "
|
||||
+ "bcc_list, reply_to_list, attachment_count, internal_date, message_id "
|
||||
+ "FROM messages " + "WHERE folder_id = ?", new String[] {
|
||||
Long.toString(mFolderId)
|
||||
});
|
||||
@ -761,6 +915,11 @@ public class LocalStore extends Store {
|
||||
cv.put("attachment_count", attachments.size());
|
||||
cv.put("internal_date", message.getInternalDate() == null
|
||||
? System.currentTimeMillis() : message.getInternalDate().getTime());
|
||||
String[] mHeaders = message.getHeader("Message-ID");
|
||||
if (mHeaders != null && mHeaders.length > 0)
|
||||
{
|
||||
cv.put("message_id", mHeaders[0]);
|
||||
}
|
||||
long messageId = mDb.insert("messages", "uid", cv);
|
||||
for (Part attachment : attachments) {
|
||||
saveAttachment(messageId, attachment, copy);
|
||||
@ -968,7 +1127,21 @@ public class LocalStore extends Store {
|
||||
message.setFlags(flags, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlags(Flag[] flags, boolean value)
|
||||
throws MessagingException {
|
||||
open(OpenMode.READ_WRITE);
|
||||
for (Message message : getMessages(null)) {
|
||||
message.setFlags(flags, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUidFromMessageId(Message message) throws MessagingException
|
||||
{
|
||||
throw new MessagingException("Cannot call getUidFromMessageId on LocalFolder");
|
||||
}
|
||||
@Override
|
||||
public Message[] expunge() throws MessagingException {
|
||||
open(OpenMode.READ_WRITE);
|
||||
@ -979,6 +1152,13 @@ public class LocalStore extends Store {
|
||||
*/
|
||||
return expungedMessages.toArray(new Message[] {});
|
||||
}
|
||||
|
||||
public void deleteMessagesOlderThan(long cutoff) throws MessagingException
|
||||
{
|
||||
open(OpenMode.READ_ONLY);
|
||||
mDb.execSQL("DELETE FROM messages WHERE folder_id = ? and date < ?", new Object[] {
|
||||
Long.toString(mFolderId), new Long(cutoff) } );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(boolean recurse) throws MessagingException {
|
||||
@ -1066,7 +1246,7 @@ public class LocalStore extends Store {
|
||||
this.mUid = uid;
|
||||
this.mFolder = folder;
|
||||
}
|
||||
|
||||
|
||||
public int getAttachmentCount() {
|
||||
return mAttachmentCount;
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ public class Pop3Store extends Store {
|
||||
|
||||
@Override
|
||||
public OpenMode getMode() throws MessagingException {
|
||||
return OpenMode.READ_ONLY;
|
||||
return OpenMode.READ_WRITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -487,13 +487,13 @@ public class Pop3Store extends Store {
|
||||
|
||||
@Override
|
||||
public Message[] getMessages(MessageRetrievalListener listener) throws MessagingException {
|
||||
throw new UnsupportedOperationException("Pop3Folder.getMessage(MessageRetrievalListener)");
|
||||
throw new UnsupportedOperationException("Pop3: No getMessages");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message[] getMessages(String[] uids, MessageRetrievalListener listener)
|
||||
throws MessagingException {
|
||||
throw new UnsupportedOperationException("Pop3Folder.getMessage(MessageRetrievalListener)");
|
||||
throw new UnsupportedOperationException("Pop3: No getMessages by uids");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -560,7 +560,7 @@ public class Pop3Store extends Store {
|
||||
*/
|
||||
pop3Message.setBody(null);
|
||||
}
|
||||
if (listener != null && !fp.contains(FetchProfile.Item.ENVELOPE)) {
|
||||
if (listener != null && !(fp.contains(FetchProfile.Item.ENVELOPE) && fp.size() == 1)) {
|
||||
listener.messageFinished(message, i, count);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
@ -683,11 +683,24 @@ public class Pop3Store extends Store {
|
||||
|
||||
public void delete(boolean recurse) throws MessagingException {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getUidFromMessageId(Message message) throws MessagingException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Message[] expunge() throws MessagingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlags(Flag[] flags, boolean value)
|
||||
throws MessagingException {
|
||||
Message[] messages = getMessages(null);
|
||||
setFlags(messages, flags, value);
|
||||
}
|
||||
|
||||
public void setFlags(Message[] messages, Flag[] flags, boolean value)
|
||||
throws MessagingException {
|
||||
if (!value || !Utility.arrayContains(flags, Flag.DELETED)) {
|
||||
@ -696,6 +709,20 @@ public class Pop3Store extends Store {
|
||||
*/
|
||||
return;
|
||||
}
|
||||
ArrayList<String> uids = new ArrayList<String>();
|
||||
try
|
||||
{
|
||||
for (Message message : messages)
|
||||
{
|
||||
uids.add(message.getUid());
|
||||
}
|
||||
|
||||
indexUids(uids);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new MessagingException("Could not get message number for uid " + uids, ioe);
|
||||
}
|
||||
try {
|
||||
for (Message message : messages) {
|
||||
executeSimpleCommand(String.format("DELE %s",
|
||||
@ -792,13 +819,20 @@ public class Pop3Store extends Store {
|
||||
private String executeSimpleCommand(String command) throws IOException, MessagingException {
|
||||
try {
|
||||
open(OpenMode.READ_WRITE);
|
||||
|
||||
if (Config.LOGV)
|
||||
{
|
||||
Log.v(Email.LOG_TAG, "POP3: command '" + command + "'");
|
||||
}
|
||||
if (command != null) {
|
||||
writeLine(command);
|
||||
}
|
||||
|
||||
String response = readLine();
|
||||
|
||||
if (Config.LOGV)
|
||||
{
|
||||
Log.v(Email.LOG_TAG, "POP3: response '" + command + "'");
|
||||
}
|
||||
|
||||
if (response.length() > 1 && response.charAt(0) == '-') {
|
||||
throw new MessagingException(response);
|
||||
}
|
||||
@ -831,6 +865,7 @@ public class Pop3Store extends Store {
|
||||
mUid = uid;
|
||||
mFolder = folder;
|
||||
mSize = -1;
|
||||
mFlags.add(Flag.X_NO_SEEN_INFO);
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
@ -846,6 +881,20 @@ public class Pop3Store extends Store {
|
||||
super.setFlag(flag, set);
|
||||
mFolder.setFlags(new Message[] { this }, new Flag[] { flag }, set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String trashFolderName) throws MessagingException
|
||||
{
|
||||
// try
|
||||
// {
|
||||
// Poor POP3 users, we can't copy the message to the Trash folder, but they still want a delete
|
||||
setFlag(Flag.DELETED, true);
|
||||
// }
|
||||
// catch (MessagingException me)
|
||||
// {
|
||||
// Log.w(Email.LOG_TAG, "Could not delete non-existant message", me);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
class Pop3Capabilities {
|
||||
|
@ -246,6 +246,10 @@ public class SmtpTransport extends Transport {
|
||||
} catch (IOException ioe) {
|
||||
throw new MessagingException("Unable to send message", ioe);
|
||||
}
|
||||
finally
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
@ -1,6 +1,8 @@
|
||||
|
||||
package com.android.email.service;
|
||||
|
||||
import com.android.email.Email;
|
||||
import android.util.Log;
|
||||
import com.android.email.MessagingController;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
@ -9,8 +11,10 @@ import android.content.Intent;
|
||||
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.v(Email.LOG_TAG, "BootReceiver.onReceive" + intent);
|
||||
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
|
||||
MailService.actionReschedule(context);
|
||||
Email.setServicesEnabled(context);
|
||||
}
|
||||
else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(intent.getAction())) {
|
||||
MailService.actionCancel(context);
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
package com.android.email.service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
@ -27,6 +28,9 @@ import com.android.email.Preferences;
|
||||
import com.android.email.R;
|
||||
import com.android.email.activity.Accounts;
|
||||
import com.android.email.activity.FolderMessageList;
|
||||
import com.android.email.mail.Folder;
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.Store;
|
||||
|
||||
/**
|
||||
*/
|
||||
@ -34,7 +38,7 @@ public class MailService extends Service {
|
||||
private static final String ACTION_CHECK_MAIL = "com.android.email.intent.action.MAIL_SERVICE_WAKEUP";
|
||||
private static final String ACTION_RESCHEDULE = "com.android.email.intent.action.MAIL_SERVICE_RESCHEDULE";
|
||||
private static final String ACTION_CANCEL = "com.android.email.intent.action.MAIL_SERVICE_CANCEL";
|
||||
|
||||
|
||||
private Listener mListener = new Listener();
|
||||
|
||||
private int mStartId;
|
||||
@ -52,17 +56,26 @@ public class MailService extends Service {
|
||||
i.setAction(MailService.ACTION_CANCEL);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Log.v(Email.LOG_TAG, "***** MailService *****: onCreate");
|
||||
}
|
||||
|
||||
@Override
|
||||
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 + ")");
|
||||
super.onStart(intent, startId);
|
||||
this.mStartId = startId;
|
||||
|
||||
MessagingController.getInstance(getApplication()).addListener(mListener);
|
||||
if (ACTION_CHECK_MAIL.equals(intent.getAction())) {
|
||||
if (Config.LOGV) {
|
||||
//if (Config.LOGV) {
|
||||
MessagingController.getInstance(getApplication()).log("***** MailService *****: checking mail");
|
||||
Log.v(Email.LOG_TAG, "***** MailService *****: checking mail");
|
||||
}
|
||||
//}
|
||||
mListener.wakeLockAcquire();
|
||||
MessagingController.getInstance(getApplication()).checkMail(this, null, mListener);
|
||||
}
|
||||
@ -70,6 +83,8 @@ public class MailService extends Service {
|
||||
if (Config.LOGV) {
|
||||
Log.v(Email.LOG_TAG, "***** MailService *****: cancel");
|
||||
}
|
||||
MessagingController.getInstance(getApplication()).log("***** MailService *****: cancel");
|
||||
|
||||
cancel();
|
||||
stopSelf(startId);
|
||||
}
|
||||
@ -77,6 +92,7 @@ public class MailService extends Service {
|
||||
if (Config.LOGV) {
|
||||
Log.v(Email.LOG_TAG, "***** MailService *****: reschedule");
|
||||
}
|
||||
MessagingController.getInstance(getApplication()).log("***** MailService *****: reschedule");
|
||||
reschedule();
|
||||
stopSelf(startId);
|
||||
}
|
||||
@ -84,6 +100,7 @@ public class MailService extends Service {
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Log.v(Email.LOG_TAG, "***** MailService *****: onDestroy()");
|
||||
super.onDestroy();
|
||||
MessagingController.getInstance(getApplication()).removeListener(mListener);
|
||||
}
|
||||
@ -103,22 +120,31 @@ public class MailService extends Service {
|
||||
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
|
||||
i.setAction(ACTION_CHECK_MAIL);
|
||||
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
|
||||
|
||||
|
||||
int shortestInterval = -1;
|
||||
|
||||
for (Account account : Preferences.getPreferences(this).getAccounts()) {
|
||||
if (account.getAutomaticCheckIntervalMinutes() != -1
|
||||
&& (account.getAutomaticCheckIntervalMinutes() < shortestInterval || shortestInterval == -1)) {
|
||||
shortestInterval = account.getAutomaticCheckIntervalMinutes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (shortestInterval == -1) {
|
||||
Log.v(Email.LOG_TAG, "No next check scheduled for package " + getApplication().getPackageName());
|
||||
alarmMgr.cancel(pi);
|
||||
}
|
||||
else {
|
||||
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
|
||||
+ (shortestInterval * (60 * 1000)), pi);
|
||||
else
|
||||
{
|
||||
long delay = (shortestInterval * (60 * 1000));
|
||||
|
||||
long nextTime = System.currentTimeMillis() + delay;
|
||||
String checkString = "Next check for package " + getApplication().getPackageName() + " scheduled for " + new Date(nextTime);
|
||||
Log.v(Email.LOG_TAG, checkString);
|
||||
MessagingController.getInstance(getApplication()).log(checkString);
|
||||
alarmMgr.set(AlarmManager.RTC_WAKEUP, nextTime, pi);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public IBinder onBind(Intent intent) {
|
||||
@ -131,22 +157,24 @@ public class MailService extends Service {
|
||||
|
||||
// wakelock strategy is to be very conservative. If there is any reason to release, then release
|
||||
// don't want to take the chance of running wild
|
||||
public synchronized void wakeLockAcquire() {
|
||||
if (wakeLock == null) {
|
||||
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email");
|
||||
wakeLock.setReferenceCounted(false);
|
||||
wakeLock.acquire(Email.WAKE_LOCK_TIMEOUT);
|
||||
public synchronized void wakeLockAcquire()
|
||||
{
|
||||
if (wakeLock == null)
|
||||
{
|
||||
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email");
|
||||
wakeLock.setReferenceCounted(false);
|
||||
wakeLock.acquire(Email.WAKE_LOCK_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void wakeLockRelease() {
|
||||
if (wakeLock != null) {
|
||||
public synchronized void wakeLockRelease()
|
||||
{
|
||||
if (wakeLock != null)
|
||||
{
|
||||
wakeLock.release();
|
||||
wakeLock = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMailStarted(Context context, Account account) {
|
||||
accountsWithNewMail.clear();
|
||||
@ -154,8 +182,14 @@ public class MailService extends Service {
|
||||
|
||||
@Override
|
||||
public void checkMailFailed(Context context, Account account, String reason) {
|
||||
try
|
||||
{
|
||||
reschedule();
|
||||
}
|
||||
finally
|
||||
{
|
||||
wakeLockRelease();
|
||||
}
|
||||
stopSelf(mStartId);
|
||||
}
|
||||
|
||||
@ -169,54 +203,105 @@ public class MailService extends Service {
|
||||
accountsWithNewMail.put(account, numNewMessages);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMailDone(Context context, Account doNotUseaccount)
|
||||
{
|
||||
if (accountsWithNewMail.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
StringBuffer notice = new StringBuffer();
|
||||
int accountNumber = Email.FETCHING_EMAIL_NOTIFICATION_NO_ACCOUNT;
|
||||
|
||||
boolean vibrate = false;
|
||||
String ringtone = null;
|
||||
for (Account thisAccount : Preferences.getPreferences(context).getAccounts()) {
|
||||
if (thisAccount.isNotifyNewMail())
|
||||
{
|
||||
int unreadMessageCount = 0;
|
||||
try
|
||||
{
|
||||
unreadMessageCount = thisAccount.getUnreadMessageCount(context, getApplication());
|
||||
if (unreadMessageCount > 0)
|
||||
{
|
||||
notice.append(getString(R.string.notification_new_one_account_fmt, unreadMessageCount,
|
||||
thisAccount.getDescription()) + "\n");
|
||||
if (accountNumber != Email.FETCHING_EMAIL_NOTIFICATION_MULTI_ACCOUNT_ID) // if already set to Multi, nothing to do
|
||||
{
|
||||
if (accountNumber == Email.FETCHING_EMAIL_NOTIFICATION_NO_ACCOUNT) // Haven't set to anything, yet, set to this account number
|
||||
{
|
||||
accountNumber = thisAccount.getAccountNumber();
|
||||
}
|
||||
else // Another account was already set, so there is more than one with new mail
|
||||
{
|
||||
accountNumber = Email.FETCHING_EMAIL_NOTIFICATION_MULTI_ACCOUNT_ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (MessagingException me)
|
||||
{
|
||||
Log.e(Email.LOG_TAG, "***** MailService *****: couldn't get unread count for account " +
|
||||
thisAccount.getDescription(), me);
|
||||
}
|
||||
if (ringtone == null)
|
||||
{
|
||||
ringtone = thisAccount.getRingtone();
|
||||
}
|
||||
vibrate |= thisAccount.isVibrate();
|
||||
}
|
||||
}
|
||||
if (notice.length() > 0)
|
||||
{
|
||||
NotificationManager notifMgr =
|
||||
(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
Notification notif = new Notification(R.drawable.stat_notify_email_generic,
|
||||
getString(R.string.notification_new_title), System.currentTimeMillis());
|
||||
|
||||
// If only one account has mail, maybe go back to the old way of targetting the account.
|
||||
Intent i = new Intent(context, Accounts.class);
|
||||
PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);
|
||||
|
||||
notif.setLatestEventInfo(context, getString(R.string.notification_new_title),
|
||||
notice, pi);
|
||||
|
||||
// notif.defaults = Notification.DEFAULT_LIGHTS;
|
||||
notif.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone);
|
||||
if (vibrate) {
|
||||
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(accountNumber, notif);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMailFinished(Context context, Account account) {
|
||||
NotificationManager notifMgr = (NotificationManager)context
|
||||
.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
if (accountsWithNewMail.size() > 0) {
|
||||
Notification notif = new Notification(R.drawable.stat_notify_email_generic,
|
||||
getString(R.string.notification_new_title), System.currentTimeMillis());
|
||||
boolean vibrate = false;
|
||||
String ringtone = null;
|
||||
if (accountsWithNewMail.size() > 1) {
|
||||
for (Account account1 : accountsWithNewMail.keySet()) {
|
||||
if (account1.isVibrate()) vibrate = true;
|
||||
if (account1.isNotifyRingtone()) ringtone = account1.getRingtone();
|
||||
}
|
||||
Intent i = new Intent(context, Accounts.class);
|
||||
PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);
|
||||
notif.setLatestEventInfo(context, getString(R.string.notification_new_title),
|
||||
getString(R.string.notification_new_multi_account_fmt,
|
||||
accountsWithNewMail.size()), pi);
|
||||
} else {
|
||||
Account account1 = accountsWithNewMail.keySet().iterator().next();
|
||||
int totalNewMails = accountsWithNewMail.get(account1);
|
||||
Intent i = FolderMessageList.actionHandleAccountIntent(context, account1, Email.INBOX);
|
||||
PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);
|
||||
notif.setLatestEventInfo(context, getString(R.string.notification_new_title),
|
||||
getString(R.string.notification_new_one_account_fmt, totalNewMails,
|
||||
account1.getDescription()), pi);
|
||||
vibrate = account1.isVibrate();
|
||||
if (account1.isNotifyRingtone()) ringtone = account1.getRingtone();
|
||||
}
|
||||
|
||||
notif.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone);
|
||||
if (vibrate) {
|
||||
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(Email.NEW_EMAIL_NOTIFICATION_ID, notif);
|
||||
Log.v(Email.LOG_TAG, "***** MailService *****: checkMailFinished");
|
||||
try
|
||||
{
|
||||
checkMailDone(context, account);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
reschedule();
|
||||
}
|
||||
finally
|
||||
{
|
||||
wakeLockRelease();
|
||||
}
|
||||
|
||||
reschedule();
|
||||
wakeLockRelease();
|
||||
stopSelf(mStartId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user