1
0
mirror of https://github.com/moparisthebest/k-9 synced 2025-02-15 06:30:17 -05:00

Merge remote branch 'origin/master' into ms-eas

This commit is contained in:
wongk 2012-01-09 13:05:32 -05:00
commit 6c06fb2071
23 changed files with 375 additions and 135 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest <manifest
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="15003" android:versionCode="15004"
android:versionName="4.103" package="com.fsck.k9" android:versionName="4.104" package="com.fsck.k9"
> >
<uses-sdk <uses-sdk
android:minSdkVersion="7" android:minSdkVersion="7"

View File

@ -19,6 +19,7 @@
<option name="LIBRARY_PROJECT" value="false" /> <option name="LIBRARY_PROJECT" value="false" />
<option name="RUN_PROCESS_RESOURCES_MAVEN_TASK" value="true" /> <option name="RUN_PROCESS_RESOURCES_MAVEN_TASK" value="true" />
<option name="GENERATE_UNSIGNED_APK" value="false" /> <option name="GENERATE_UNSIGNED_APK" value="false" />
<option name="CUSTOM_DEBUG_KEYSTORE_PATH" value="" />
</configuration> </configuration>
</facet> </facet>
</component> </component>

View File

@ -40,8 +40,8 @@
<string name="status_processing_account">\u0020(Behandler <xliff:g id="account">%s</xliff:g>:<xliff:g id="command">%s</xliff:g><xliff:g id="progress">%s</xliff:g>)</string> <string name="status_processing_account">\u0020(Behandler <xliff:g id="account">%s</xliff:g>:<xliff:g id="command">%s</xliff:g><xliff:g id="progress">%s</xliff:g>)</string>
<string name="folder_progress">\u0020<xliff:g id="completed">%s</xliff:g>/<xliff:g id="total">%s</xliff:g></string> <string name="folder_progress">\u0020<xliff:g id="completed">%s</xliff:g>/<xliff:g id="total">%s</xliff:g></string>
<string name="status_next_poll">\u0020(Næste synk @ <xliff:g id="nexttime">%s</xliff:g>)</string> <string name="status_next_poll">\u0020(Næste synkronisering @ <xliff:g id="nexttime">%s</xliff:g>)</string>
<string name="status_syncing_off">\u0020(Synk deaktiveret)</string> <string name="status_syncing_off">\u0020(synkronisering deaktiveret)</string>
<!-- Actions will be used as buttons and in menu items --> <!-- Actions will be used as buttons and in menu items -->
<string name="next_action">Næste</string> <!-- Used as part of a multi-step process --> <string name="next_action">Næste</string> <!-- Used as part of a multi-step process -->
@ -118,7 +118,7 @@
<string name="dump_settings_action">Dump indstillinger</string> <string name="dump_settings_action">Dump indstillinger</string>
<string name="empty_trash_action">Tøm papirkurv</string> <string name="empty_trash_action">Tøm papirkurv</string>
<string name="expunge_action">Ryd helt</string> <string name="expunge_action">Ryd helt</string>
<string name="clear_local_folder_action">Fjern lokalt lagrede meddelelser</string> <string name="clear_local_folder_action">Fjern lokalt lagrede mails</string>
<string name="set_sort_action">Vælg sortering</string> <string name="set_sort_action">Vælg sortering</string>
<string name="reverse_sort_action">Omvendt sortering</string> <string name="reverse_sort_action">Omvendt sortering</string>
<string name="about_action">Om</string> <string name="about_action">Om</string>
@ -321,10 +321,10 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="global_settings_checkbox_label">Checkbokse for multible valg</string> <string name="global_settings_checkbox_label">Checkbokse for multible valg</string>
<string name="global_settings_checkbox_summary">Vis altid checkbokse for multible valg</string> <string name="global_settings_checkbox_summary">Vis altid checkbokse for multible valg</string>
<string name="global_settings_touchable_label">Touch venlig visning</string> <string name="global_settings_touchable_label">Touch venlig visning</string>
<string name="global_settings_touchable_summary">Rummeligere listning med forhåndsvisning</string> <string name="global_settings_touchable_summary">Rummeligere listning i forhåndsvisning</string>
<string name="global_settings_preview_lines_label">Linier med forhåndsvisning</string> <string name="global_settings_preview_lines_label">Linier i forhåndsvisning</string>
<string name="global_settings_show_correspondent_names_label">Vis afsenders navne</string> <string name="global_settings_show_correspondent_names_label">Vis afsenders navne</string>
<string name="global_settings_show_correspondent_names_summary">Vis afsenders navne fremfor deres mailaddresser</string> <string name="global_settings_show_correspondent_names_summary">Vis afsendernavn fremfor deres mailaddresse</string>
<string name="global_settings_show_contact_name_label">Vis kontaktnavne</string> <string name="global_settings_show_contact_name_label">Vis kontaktnavne</string>
<string name="global_settings_show_contact_name_summary">Benyt afsendernavne fra eksisterende kontakter</string> <string name="global_settings_show_contact_name_summary">Benyt afsendernavne fra eksisterende kontakter</string>
<string name="global_settings_registered_name_color_label">Farvelæg kontakter</string> <string name="global_settings_registered_name_color_label">Farvelæg kontakter</string>
@ -333,7 +333,7 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="global_settings_messageview_fixedwidth_label">Tegnsæt med fast bredde</string> <string name="global_settings_messageview_fixedwidth_label">Tegnsæt med fast bredde</string>
<string name="global_settings_messageview_fixedwidth_summary">Benyt tegnsæt med fast bredde til visning af mails med ren tekst</string> <string name="global_settings_messageview_fixedwidth_summary">Benyt tegnsæt med fast bredde til visning af mails med ren tekst</string>
<string name="global_settings_messageview_return_to_list_label">Returner til liste efter sletning</string> <string name="global_settings_messageview_return_to_list_label">Retur til liste efter sletning</string>
<string name="global_settings_messageview_return_to_list_summary">Returner til mailliste efter sletning af mail</string> <string name="global_settings_messageview_return_to_list_summary">Returner til mailliste efter sletning af mail</string>
<string name="global_settings_messageview_show_next_label">Vis næste mail efter sletning</string> <string name="global_settings_messageview_show_next_label">Vis næste mail efter sletning</string>
<string name="global_settings_messageview_show_next_summary">Vis som standard næste mail efter sletning af mail</string> <string name="global_settings_messageview_show_next_summary">Vis som standard næste mail efter sletning af mail</string>
@ -370,7 +370,7 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="account_setup_check_settings_check_incoming_msg">Kontrollerer indstillinger for indgående server\u2026</string> <string name="account_setup_check_settings_check_incoming_msg">Kontrollerer indstillinger for indgående server\u2026</string>
<string name="account_setup_check_settings_check_outgoing_msg">Kontrollerer indstillinger for udgående server\u2026</string> <string name="account_setup_check_settings_check_outgoing_msg">Kontrollerer indstillinger for udgående server\u2026</string>
<string name="account_setup_check_settings_authenticate">Autentiserer\u2026</string> <string name="account_setup_check_settings_authenticate">Autentiserer\u2026</string>
<string name="account_setup_check_settings_fetch">Henter konto indstillinger\u2026</string> <string name="account_setup_check_settings_fetch">Henter kontoindstillinger\u2026</string>
<string name="account_setup_check_settings_finishing_msg">Afslutter\u2026</string> <string name="account_setup_check_settings_finishing_msg">Afslutter\u2026</string>
<string name="account_setup_check_settings_canceling_msg">Afbryder\u2026</string> <string name="account_setup_check_settings_canceling_msg">Afbryder\u2026</string>
@ -472,7 +472,7 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="compact_action">Komprimer</string> <string name="compact_action">Komprimer</string>
<string name="clear_action">Ryd mails (farligt!)</string> <string name="clear_action">Ryd mails (farligt!)</string>
<string name="recreate_action">Genskab data (Sidste udvej!)</string> <string name="recreate_action">Genskab data (sidste udvej!)</string>
<string name="account_setup_options_mail_check_frequency_label">Frekvens for hentning af mail</string> <string name="account_setup_options_mail_check_frequency_label">Frekvens for hentning af mail</string>
<!-- Frequency also used in account_settings_* --> <!-- Frequency also used in account_settings_* -->
@ -542,7 +542,7 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="account_settings_notify_self_summary">Vis besked for mails sendt af mig</string> <string name="account_settings_notify_self_summary">Vis besked for mails sendt af mig</string>
<string name="account_settings_notification_opens_unread_label">Klik på besked, viser ulæste mails</string> <string name="account_settings_notification_opens_unread_label">Klik på besked, viser ulæste mails</string>
<string name="account_settings_notification_opens_unread_summary">Søger efter ulæste mails når besked vises</string> <string name="account_settings_notification_opens_unread_summary">Søger efter ulæste mails når besked vises</string>
<string name="account_settings_notification_unread_count_label">Vis antallet af ulæste mails</string> <string name="account_settings_notification_unread_count_label">Vis antal ulæste mails</string>
<string name="account_settings_notification_unread_count_summary">Vis antallet af ulæste mails i statusbar.</string> <string name="account_settings_notification_unread_count_summary">Vis antallet af ulæste mails i statusbar.</string>
<string name="account_settings_hide_buttons_label">Scroll navigations knapper</string> <string name="account_settings_hide_buttons_label">Scroll navigations knapper</string>
@ -554,7 +554,7 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="account_settings_enable_move_buttons_summary">Vis Arkiver, Flyt og Spam knapper.</string> <string name="account_settings_enable_move_buttons_summary">Vis Arkiver, Flyt og Spam knapper.</string>
<string name="account_settings_hide_move_buttons_label">Scroll Flyt knapper</string> <string name="account_settings_hide_move_buttons_label">Scroll Flyt knapper</string>
<string name="account_settings_show_pictures_label">Vis altid billeder automatisk</string> <string name="account_settings_show_pictures_label">Vis altid billeder</string>
<string name="account_settings_show_pictures_never">Aldrig</string> <string name="account_settings_show_pictures_never">Aldrig</string>
<string name="account_settings_show_pictures_only_from_contacts">Kun når afsender findes i Kontakter</string> <string name="account_settings_show_pictures_only_from_contacts">Kun når afsender findes i Kontakter</string>
<string name="account_settings_show_pictures_always">Fra alle</string> <string name="account_settings_show_pictures_always">Fra alle</string>
@ -562,10 +562,10 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="account_settings_composition">Skriv mail</string> <string name="account_settings_composition">Skriv mail</string>
<string name="account_settings_default_quoted_text_shown_label">Medtag den originale meddelelse i svar</string> <string name="account_settings_default_quoted_text_shown_label">Medtag den originale meddelelse i svar</string>
<string name="account_settings_default_quoted_text_shown_summary">Når du sender svar på mail, vil den oprindelige tekst blive medtaget.</string> <string name="account_settings_default_quoted_text_shown_summary">Når du sender svar på mail, vil den oprindelige tekst blive medtaget</string>
<string name="account_settings_reply_after_quote_label">Svar placeres efter citeret tekst</string> <string name="account_settings_reply_after_quote_label">Svar placeres efter citeret tekst</string>
<string name="account_settings_reply_after_quote_summary">Når du sender svar på mail, vil den oprindelige tekst blive placeret oven over dit svar.</string> <string name="account_settings_reply_after_quote_summary">Når du sender svar på mail, vil den oprindelige tekst blive placeret oven over dit svar</string>
<string name="account_settings_strip_signature_label">Fjern signatur fra citeret svar</string> <string name="account_settings_strip_signature_label">Fjern signatur fra citeret svar</string>
<string name="account_settings_strip_signature_summary">Når du sender svar på mail, vil evt. signatur i citeret tekst blive fjernet</string> <string name="account_settings_strip_signature_summary">Når du sender svar på mail, vil evt. signatur i citeret tekst blive fjernet</string>
@ -721,7 +721,7 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="account_settings_composition_summary">Standardindstilling for afsender, Bcc og signatur</string> <string name="account_settings_composition_summary">Standardindstilling for afsender, Bcc og signatur</string>
<string name="account_settings_identities_label">Håndter identiteter</string> <string name="account_settings_identities_label">Håndter identiteter</string>
<string name="account_settings_identities_summary">Opsæt alternativ \'Fra\' addresse og signatur</string> <string name="account_settings_identities_summary">Opsæt alternativ afsender-addresse og signatur</string>
<string name="manage_identities_title">Håndter identiteter</string> <string name="manage_identities_title">Håndter identiteter</string>
@ -792,10 +792,10 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="account_delete_dlg_instructions_fmt">Kontoen \"<xliff:g id="account">%s</xliff:g>\" vil blive fjernet fra K-9 Mail.</string> <string name="account_delete_dlg_instructions_fmt">Kontoen \"<xliff:g id="account">%s</xliff:g>\" vil blive fjernet fra K-9 Mail.</string>
<string name="account_recreate_dlg_title">Nulstil konto</string> <string name="account_recreate_dlg_title">Nulstil konto</string>
<string name="account_recreate_dlg_instructions_fmt">Alle mails, vedhæftede filer, mapper og mappe-indstillinger for \"<xliff:g id="account">%s</xliff:g>\" vil blive fjernet fra K-9 Mail, men konto indstillinger vil blive husket.</string> <string name="account_recreate_dlg_instructions_fmt">Alle mails, vedhæftede filer, mapper og mappe-indstillinger for \"<xliff:g id="account">%s</xliff:g>\" vil blive fjernet fra K-9 Mail, men kontoindstillinger vil blive husket.</string>
<string name="account_clear_dlg_title">Rens konto</string> <string name="account_clear_dlg_title">Rens konto</string>
<string name="account_clear_dlg_instructions_fmt">Alle mails i \"<xliff:g id="account">%s</xliff:g>\" vil blive fjernet, men konto indstillinger vil blive husket.</string> <string name="account_clear_dlg_instructions_fmt">Alle mails i \"<xliff:g id="account">%s</xliff:g>\" vil blive fjernet, men kontoindstillinger vil blive husket.</string>
<string name="provider_note_live">Kun visse \"Plus\" konti tillader adgang via POP <string name="provider_note_live">Kun visse \"Plus\" konti tillader adgang via POP
som er nødvendig for at kunne tilgå konto. Hvis du ikke kan logge ind på trods af som er nødvendig for at kunne tilgå konto. Hvis du ikke kan logge ind på trods af
@ -827,7 +827,7 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
3 - Vis alle pånær sekundære mapper\u000A 3 - Vis alle pånær sekundære mapper\u000A
4 - Vis alle mapper\u000A 4 - Vis alle mapper\u000A
Q - Returner til Konti\u000A Q - Returner til Konti\u000A
S - Rediger konto indstillinger</string> S - Rediger kontoindstillinger</string>
<string name="folder_list_display_mode_label">Mapper</string> <string name="folder_list_display_mode_label">Mapper</string>
<string name="folder_list_display_mode_all">Vis alle mapper</string> <string name="folder_list_display_mode_all">Vis alle mapper</string>
@ -862,8 +862,8 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="background_ops_label">Baggrundssynkronisering</string> <string name="background_ops_label">Baggrundssynkronisering</string>
<string name="background_ops_never">Aldrig</string> <string name="background_ops_never">Aldrig</string>
<string name="background_ops_always">Altid</string> <string name="background_ops_always">Altid</string>
<string name="background_ops_enabled">Når \'Baggrundsdata\' er aktiveret</string> <string name="background_ops_enabled">Når \"Baggrundsdata\" er aktiveret</string>
<string name="background_ops_auto_sync">Når \'Baggrundsdata\' &amp; \'Auto-sync\' er aktiveret</string> <string name="background_ops_auto_sync">Når \"Baggrundsdata\" &amp; \"Auto-sync\" er aktiveret</string>
<string name="no_message_seletected_toast">Ingen mail valgt</string> <string name="no_message_seletected_toast">Ingen mail valgt</string>
@ -908,14 +908,14 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="gestures_summary">Benyt gesture kontrol</string> <string name="gestures_summary">Benyt gesture kontrol</string>
<string name="compact_layouts_title">Kompakt layout</string> <string name="compact_layouts_title">Kompakt layout</string>
<string name="compact_layouts_summary">Juster layouts så der vises mere på hver side</string> <string name="compact_layouts_summary">Juster layout så der vises mere på hver side</string>
<string name="volume_navigation_title">Volume-knap navigation</string> <string name="volume_navigation_title">Volume-knap navigation</string>
<string name="volume_navigation_summary">Skift mellem valg vha. volume-knapper</string> <string name="volume_navigation_summary">Skift mellem valg vha. volume-knapper</string>
<string name="volume_navigation_message">Mail-visning</string> <string name="volume_navigation_message">Mail-visning</string>
<string name="volume_navigation_list">Diverse listevisninger</string> <string name="volume_navigation_list">Diverse listevisninger</string>
<string name="manage_back_title">Håndter \"Tilbageknappen\"</string> <string name="manage_back_title">Håndter \"Tilbageknap\"</string>
<string name="manage_back_summary">\"Tilbageknap\" går altid et niveau op</string> <string name="manage_back_summary">\"Tilbageknap\" går altid et niveau op</string>
<string name="start_integrated_inbox_title">Start i fælles indbakke</string> <string name="start_integrated_inbox_title">Start i fælles indbakke</string>
@ -928,7 +928,7 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="count_search_summary">Deaktiver for hurtigere visning</string> <string name="count_search_summary">Deaktiver for hurtigere visning</string>
<string name="hide_special_accounts_title">Skjul specialkonti</string> <string name="hide_special_accounts_title">Skjul specialkonti</string>
<string name="hide_special_accounts_summary">Skjul fælles indbakke og alle mailkonti</string> <string name="hide_special_accounts_summary">Skjul fælles indbakke og fælles mailkonti</string>
<string name="search_title"><xliff:g id="search_name">%s</xliff:g> <xliff:g id="modifier">%s</xliff:g></string> <string name="search_title"><xliff:g id="search_name">%s</xliff:g> <xliff:g id="modifier">%s</xliff:g></string>
<string name="flagged_modifier"> - Stjernemarkerede</string> <string name="flagged_modifier"> - Stjernemarkerede</string>
@ -972,7 +972,7 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="font_size_message_view">Meddelelse</string> <string name="font_size_message_view">Meddelelse</string>
<string name="font_size_message_view_sender">Afsender</string> <string name="font_size_message_view_sender">Afsender</string>
<string name="font_size_message_view_to">Modtagere(Til)</string> <string name="font_size_message_view_to">Modtagere (Til)</string>
<string name="font_size_message_view_cc">Modtagere (Cc)</string> <string name="font_size_message_view_cc">Modtagere (Cc)</string>
<string name="font_size_message_view_additional_headers">Yderligere headers</string> <string name="font_size_message_view_additional_headers">Yderligere headers</string>
<string name="font_size_message_view_subject">Emne</string> <string name="font_size_message_view_subject">Emne</string>
@ -1058,8 +1058,8 @@ Velkommen til K-9 Mail opsætning. K-9 er en open source mail klient for Androi
<string name="error_unable_to_connect">Kunne ikke opnå forbindelse.</string> <string name="error_unable_to_connect">Kunne ikke opnå forbindelse.</string>
<string name="import_export_action">Import &amp; eksport af indstillinger</string> <string name="import_export_action">Import &amp; eksport af indstillinger</string>
<string name="settings_export_account">Eksport konto indstillinger</string> <string name="settings_export_account">Eksporter kontoindstillinger</string>
<string name="settings_export_all">Eksport indstillinger og konti</string> <string name="settings_export_all">Eksporter indstillinger og konti</string>
<string name="settings_import_dialog_title">Importer</string> <string name="settings_import_dialog_title">Importer</string>
<string name="settings_export_dialog_title">Eksporter</string> <string name="settings_export_dialog_title">Eksporter</string>
<string name="settings_import">Importer indstillinger</string> <string name="settings_import">Importer indstillinger</string>

View File

@ -18,6 +18,7 @@ import com.fsck.k9.mail.store.StorageManager;
import com.fsck.k9.mail.store.StorageManager.StorageProvider; import com.fsck.k9.mail.store.StorageManager.StorageProvider;
import com.fsck.k9.view.ColorChip; import com.fsck.k9.view.ColorChip;
import java.lang.reflect.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;

View File

@ -509,7 +509,7 @@ public class K9 extends Application {
DEBUG = sprefs.getBoolean("enableDebugLogging", false); DEBUG = sprefs.getBoolean("enableDebugLogging", false);
DEBUG_SENSITIVE = sprefs.getBoolean("enableSensitiveLogging", false); DEBUG_SENSITIVE = sprefs.getBoolean("enableSensitiveLogging", false);
mAnimations = sprefs.getBoolean("animations", true); mAnimations = sprefs.getBoolean("animations", true);
mGesturesEnabled = sprefs.getBoolean("gesturesEnabled", true); mGesturesEnabled = sprefs.getBoolean("gesturesEnabled", false);
mUseVolumeKeysForNavigation = sprefs.getBoolean("useVolumeKeysForNavigation", false); mUseVolumeKeysForNavigation = sprefs.getBoolean("useVolumeKeysForNavigation", false);
mUseVolumeKeysForListNavigation = sprefs.getBoolean("useVolumeKeysForListNavigation", false); mUseVolumeKeysForListNavigation = sprefs.getBoolean("useVolumeKeysForListNavigation", false);
mManageBack = sprefs.getBoolean("manageBack", false); mManageBack = sprefs.getBoolean("manageBack", false);
@ -522,7 +522,7 @@ public class K9 extends Application {
mMessageListTouchable = sprefs.getBoolean("messageListTouchable", false); mMessageListTouchable = sprefs.getBoolean("messageListTouchable", false);
mMessageListPreviewLines = sprefs.getInt("messageListPreviewLines", 2); mMessageListPreviewLines = sprefs.getInt("messageListPreviewLines", 2);
mMobileOptimizedLayout = sprefs.getBoolean("mobileOptimizedLayout", false); mMobileOptimizedLayout = sprefs.getBoolean("mobileOptimizedLayout", false);
mZoomControlsEnabled = sprefs.getBoolean("zoomControlsEnabled", false); mZoomControlsEnabled = sprefs.getBoolean("zoomControlsEnabled", true);
mQuietTimeEnabled = sprefs.getBoolean("quietTimeEnabled", false); mQuietTimeEnabled = sprefs.getBoolean("quietTimeEnabled", false);
mQuietTimeStarts = sprefs.getString("quietTimeStarts", "21:00"); mQuietTimeStarts = sprefs.getString("quietTimeStarts", "21:00");
mQuietTimeEnds = sprefs.getString("quietTimeEnds", "7:00"); mQuietTimeEnds = sprefs.getString("quietTimeEnds", "7:00");

View File

@ -7,6 +7,7 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener; import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -15,7 +16,6 @@ import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.TranslateAnimation; import android.view.animation.TranslateAnimation;
import com.fsck.k9.K9; import com.fsck.k9.K9;
import com.fsck.k9.helper.DateFormatter;
import com.fsck.k9.view.ToggleScrollView; import com.fsck.k9.view.ToggleScrollView;
@ -70,12 +70,9 @@ public class K9Activity extends Activity {
setupFormats(); setupFormats();
} }
private java.text.DateFormat mDateFormat;
private java.text.DateFormat mTimeFormat; private java.text.DateFormat mTimeFormat;
private void setupFormats() { private void setupFormats() {
mDateFormat = DateFormatter.getDateFormat(this);
mTimeFormat = android.text.format.DateFormat.getTimeFormat(this); // 12/24 date format mTimeFormat = android.text.format.DateFormat.getTimeFormat(this); // 12/24 date format
} }
@ -83,10 +80,6 @@ public class K9Activity extends Activity {
return mTimeFormat; return mTimeFormat;
} }
public java.text.DateFormat getDateFormat() {
return mDateFormat;
}
/** /**
* Called when a swipe from right to left is handled by {@link MyGestureDetector}. See * Called when a swipe from right to left is handled by {@link MyGestureDetector}. See
* {@link android.view.GestureDetector.OnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float)} * {@link android.view.GestureDetector.OnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float)}
@ -148,7 +141,6 @@ public class K9Activity extends Activity {
this.gesturesEnabled = gesturesEnabled; this.gesturesEnabled = gesturesEnabled;
} }
private static final float SWIPE_MIN_DISTANCE_DIP = 130.0f;
private static final float SWIPE_MAX_OFF_PATH_DIP = 250f; private static final float SWIPE_MAX_OFF_PATH_DIP = 250f;
private static final float SWIPE_THRESHOLD_VELOCITY_DIP = 325f; private static final float SWIPE_THRESHOLD_VELOCITY_DIP = 325f;
@ -172,21 +164,50 @@ public class K9Activity extends Activity {
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// Do fling-detection if gestures are force-enabled or we have system-wide gestures enabled. // Do fling-detection if gestures are force-enabled or we have system-wide gestures enabled.
if (gesturesEnabled || K9.gesturesEnabled()) { if (gesturesEnabled || K9.gesturesEnabled()) {
// Convert the dips to pixels // Calculate the minimum distance required for this to count as a swipe.
// Convert the constant dips to pixels.
final float mGestureScale = getResources().getDisplayMetrics().density; final float mGestureScale = getResources().getDisplayMetrics().density;
int min_distance = (int)(SWIPE_MIN_DISTANCE_DIP * mGestureScale + 0.5f); final int minVelocity = (int)(SWIPE_THRESHOLD_VELOCITY_DIP * mGestureScale + 0.5f);
int min_velocity = (int)(SWIPE_THRESHOLD_VELOCITY_DIP * mGestureScale + 0.5f); final int maxOffPath = (int)(SWIPE_MAX_OFF_PATH_DIP * mGestureScale + 0.5f);
int max_off_path = (int)(SWIPE_MAX_OFF_PATH_DIP * mGestureScale + 0.5f);
// Calculate how much was actually swiped.
final float deltaX = e2.getX() - e1.getX();
final float deltaY = e2.getY() - e1.getY();
// Calculate the minimum distance required for this to be considered a swipe.
final int minDistance = (int)Math.abs(deltaY * 4);
if(K9.DEBUG) {
final boolean movedAcross = (Math.abs(deltaX) > Math.abs(deltaY * 4));
final boolean steadyHand = (Math.abs(deltaX / deltaY) > 2);
Log.d(K9.LOG_TAG, String.format("Old swipe algorithm: movedAcross=%s steadyHand=%s result=%s", movedAcross, steadyHand, movedAcross && steadyHand));
Log.d(K9.LOG_TAG, String.format("New swipe algorithm: deltaX=%.2f deltaY=%.2f minDistance=%d velocity=%.2f (min=%d)", deltaX, deltaY, minDistance, velocityX, minVelocity));
}
try { try {
if (Math.abs(e1.getY() - e2.getY()) > max_off_path) if (Math.abs(deltaY) > maxOffPath) {
if(K9.DEBUG)
Log.d(K9.LOG_TAG, "New swipe algorithm: Swipe too far off horizontal path.");
return false; return false;
}
if(Math.abs(velocityX) < minVelocity) {
if(K9.DEBUG)
Log.d(K9.LOG_TAG, "New swipe algorithm: Swipe too slow.");
return false;
}
// right to left swipe // right to left swipe
if (e1.getX() - e2.getX() > min_distance && Math.abs(velocityX) > min_velocity) { if (deltaX < (minDistance * -1)) {
onSwipeRightToLeft(e1, e2); onSwipeRightToLeft(e1, e2);
} else if (e2.getX() - e1.getX() > min_distance && Math.abs(velocityX) > min_velocity) { if(K9.DEBUG)
Log.d(K9.LOG_TAG, "New swipe algorithm: Right to Left swipe OK.");
} else if (deltaX > minDistance) {
onSwipeLeftToRight(e1, e2); onSwipeLeftToRight(e1, e2);
if(K9.DEBUG)
Log.d(K9.LOG_TAG, "New swipe algorithm: Left to Right swipe OK.");
} else {
if(K9.DEBUG)
Log.d(K9.LOG_TAG, "New swipe algorithm: Swipe did not meet minimum distance requirements.");
return false;
} }
} catch (Exception e) { } catch (Exception e) {
// nothing // nothing

View File

@ -733,6 +733,9 @@ public class MessageList
mCurrentFolder = mAdapter.getFolder(mFolderName, mAccount); mCurrentFolder = mAdapter.getFolder(mFolderName, mAccount);
} }
// Hide "Load up to x more" footer for search views
mFooterView.setVisibility((mQueryString != null) ? View.GONE : View.VISIBLE);
mController = MessagingController.getInstance(getApplication()); mController = MessagingController.getInstance(getApplication());
mListView.setAdapter(mAdapter); mListView.setAdapter(mAdapter);
} }
@ -2386,9 +2389,6 @@ public class MessageList
private View getFooterView(ViewGroup parent) { private View getFooterView(ViewGroup parent) {
if (mFooterView == null) { if (mFooterView == null) {
mFooterView = mInflater.inflate(R.layout.message_list_item_footer, parent, false); mFooterView = mInflater.inflate(R.layout.message_list_item_footer, parent, false);
if (mQueryString != null) {
mFooterView.setVisibility(View.GONE);
}
mFooterView.setId(R.layout.message_list_item_footer); mFooterView.setId(R.layout.message_list_item_footer);
FooterViewHolder holder = new FooterViewHolder(); FooterViewHolder holder = new FooterViewHolder();
holder.progress = (ProgressBar) mFooterView.findViewById(R.id.message_list_progress); holder.progress = (ProgressBar) mFooterView.findViewById(R.id.message_list_progress);

View File

@ -307,16 +307,6 @@ public class MessageView extends K9Activity implements OnClickListener {
public void fetchingAttachment() { public void fetchingAttachment() {
showToast(getString(R.string.message_view_fetching_attachment_toast), Toast.LENGTH_SHORT); showToast(getString(R.string.message_view_fetching_attachment_toast), Toast.LENGTH_SHORT);
} }
public void setHeaders(final Message message, final Account account) {
runOnUiThread(new Runnable() {
public void run() {
mMessageView.setHeaders(message, account);
}
});
}
} }
public static void actionView(Context context, MessageReference messRef, public static void actionView(Context context, MessageReference messRef,
@ -1125,12 +1115,28 @@ public class MessageView extends K9Activity implements OnClickListener {
return; return;
} }
MessageView.this.mMessage = message; MessageView.this.mMessage = message;
/*
* Clone the message object because the original could be modified by
* MessagingController later. This could lead to a ConcurrentModificationException
* when that same object is accessed by the UI thread (below).
*
* See issue 3953
*
* This is just an ugly hack to get rid of the most pressing problem. A proper way to
* fix this is to make Message thread-safe. Or, even better, rewriting the UI code to
* access messages via a ContentProvider.
*
*/
final Message clonedMessage = message.clone();
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
if (!message.isSet(Flag.X_DOWNLOADED_FULL) && !message.isSet(Flag.X_DOWNLOADED_PARTIAL)) { if (!clonedMessage.isSet(Flag.X_DOWNLOADED_FULL) &&
!clonedMessage.isSet(Flag.X_DOWNLOADED_PARTIAL)) {
mMessageView.loadBodyFromUrl("file:///android_asset/downloading.html"); mMessageView.loadBodyFromUrl("file:///android_asset/downloading.html");
} }
mMessageView.setHeaders(message, account); mMessageView.setHeaders(clonedMessage, account);
mMessageView.setOnFlagListener(new OnClickListener() { mMessageView.setOnFlagListener(new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {

View File

@ -784,24 +784,24 @@ public class AccountSettings extends K9PreferenceActivity {
mAccount.setScrollMessageViewButtons(Account.ScrollButtons.valueOf(mAccountScrollButtons.getValue())); mAccount.setScrollMessageViewButtons(Account.ScrollButtons.valueOf(mAccountScrollButtons.getValue()));
mAccount.setShowPictures(Account.ShowPictures.valueOf(mAccountShowPictures.getValue())); mAccount.setShowPictures(Account.ShowPictures.valueOf(mAccountShowPictures.getValue()));
mAccount.save(Preferences.getPreferences(this));
if (mIsPushCapable) { if (mIsPushCapable) {
boolean needsPushRestart = mAccount.setFolderPushMode(Account.FolderMode.valueOf(mPushMode.getValue())); boolean needsPushRestart = mAccount.setFolderPushMode(Account.FolderMode.valueOf(mPushMode.getValue()));
if (mAccount.getFolderPushMode() != FolderMode.NONE) { if (mAccount.getFolderPushMode() != FolderMode.NONE) {
needsPushRestart |= displayModeChanged; needsPushRestart |= displayModeChanged;
needsPushRestart |= mIncomingChanged; needsPushRestart |= mIncomingChanged;
} }
if (needsRefresh && needsPushRestart) { if (needsRefresh && needsPushRestart) {
MailService.actionReset(this, null); MailService.actionReset(this, null);
} else if (needsRefresh) { } else if (needsRefresh) {
MailService.actionReschedulePoll(this, null); MailService.actionReschedulePoll(this, null);
} else if (needsPushRestart) { } else if (needsPushRestart) {
MailService.actionRestartPushers(this, null); MailService.actionRestartPushers(this, null);
} }
} }
// TODO: refresh folder list here // TODO: refresh folder list here
mAccount.save(Preferences.getPreferences(this));
} }
@Override @Override
@ -817,9 +817,9 @@ public class AccountSettings extends K9PreferenceActivity {
} }
@Override @Override
public void onBackPressed() { protected void onPause() {
saveSettings(); saveSettings();
super.onBackPressed(); super.onPause();
} }
private void onCompositionSettings() { private void onCompositionSettings() {

View File

@ -144,13 +144,13 @@ public class FolderSettings extends K9PreferenceActivity {
} }
@Override @Override
public void onBackPressed() { public void onPause() {
try { try {
saveSettings(); saveSettings();
} catch (MessagingException e) { } catch (MessagingException e) {
Log.e(K9.LOG_TAG, "Saving folder settings failed", e); Log.e(K9.LOG_TAG, "Saving folder settings failed", e);
} }
super.onBackPressed(); super.onPause();
} }
} }

View File

@ -403,9 +403,13 @@ public class Prefs extends K9PreferenceActivity {
} }
@Override @Override
public void onBackPressed() { protected void onPause() {
saveSettings(); saveSettings();
super.onPause();
}
@Override
public void onBackPressed() {
if (K9.manageBack()) { if (K9.manageBack()) {
Accounts.listAccounts(this); Accounts.listAccounts(this);
finish(); finish();

View File

@ -186,6 +186,7 @@ public class Utility {
} }
} }
private static final long MILISECONDS_IN_18_HOURS = 18 * 60 * 60 * 1000;
/** /**
* Returns true if the specified date is within 18 hours of "now". Returns false otherwise. * Returns true if the specified date is within 18 hours of "now". Returns false otherwise.
* @param date * @param date
@ -193,7 +194,7 @@ public class Utility {
*/ */
public static boolean isDateToday(Date date) { public static boolean isDateToday(Date date) {
Date now = new Date(); Date now = new Date();
if (now.getTime() - 64800000 > date.getTime() || now.getTime() + 64800000 < date.getTime()) { if (now.getTime() - MILISECONDS_IN_18_HOURS > date.getTime() || now.getTime() + MILISECONDS_IN_18_HOURS < date.getTime()) {
return false; return false;
} else { } else {
return true; return true;
@ -500,14 +501,20 @@ public class Utility {
try { try {
FileInputStream in = new FileInputStream(from); FileInputStream in = new FileInputStream(from);
FileOutputStream out = new FileOutputStream(to); try {
byte[] buffer = new byte[1024]; FileOutputStream out = new FileOutputStream(to);
int count = -1; try {
while ((count = in.read(buffer)) > 0) { byte[] buffer = new byte[1024];
out.write(buffer, 0, count); int count = -1;
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
}
} finally {
out.close();
}
} finally {
try { in.close(); } catch (Throwable ignore) {}
} }
out.close();
in.close();
from.delete(); from.delete();
return true; return true;
} catch (Exception e) { } catch (Exception e) {

View File

@ -224,4 +224,32 @@ public abstract class Message implements Part, Body {
return 0; return 0;
} }
/**
* Copy the contents of this object into another {@code Message} object.
*
* @param destination
* The {@code Message} object to receive the contents of this instance.
*/
protected void copy(Message destination) {
destination.mUid = mUid;
destination.mInternalDate = mInternalDate;
destination.mFolder = mFolder;
destination.mReference = mReference;
// mFlags contents can change during the object lifetime, so copy the Set
destination.mFlags = new HashSet<Flag>(mFlags);
}
/**
* Creates a new {@code Message} object with the same content as this object.
*
* <p>
* <strong>Note:</strong>
* This method was introduced as a hack to prevent {@code ConcurrentModificationException}s. It
* shouldn't be used unless absolutely necessary. See the comment in
* {@link com.fsck.k9.activity.MessageView.Listener#loadMessageForViewHeadersAvailable(com.fsck.k9.Account, String, String, Message)}
* for more information.
* </p>
*/
public abstract Message clone();
} }

View File

@ -46,8 +46,11 @@ public class BinaryTempFileBody implements Body {
public void writeTo(OutputStream out) throws IOException, MessagingException { public void writeTo(OutputStream out) throws IOException, MessagingException {
InputStream in = getInputStream(); InputStream in = getInputStream();
Base64OutputStream base64Out = new Base64OutputStream(out); Base64OutputStream base64Out = new Base64OutputStream(out);
IOUtils.copy(in, base64Out); try {
base64Out.close(); IOUtils.copy(in, base64Out);
} finally {
base64Out.close();
}
mFile.delete(); mFile.delete();
} }

View File

@ -133,9 +133,9 @@ public class MimeHeader {
} }
static class Field { static class Field {
String name; final String name;
String value; final String value;
public Field(String name, String value) { public Field(String name, String value) {
this.name = name; this.name = name;
@ -153,4 +153,13 @@ public class MimeHeader {
public void setCharset(String charset) { public void setCharset(String charset) {
mCharset = charset; mCharset = charset;
} }
public MimeHeader clone() {
MimeHeader header = new MimeHeader();
header.mCharset = mCharset;
header.mFields = new ArrayList<Field>(mFields);
return header;
}
} }

View File

@ -553,4 +553,38 @@ public class MimeMessage extends Message {
throw new UnsupportedOperationException("Not supported"); throw new UnsupportedOperationException("Not supported");
} }
} }
/**
* Copy the contents of this object into another {@code MimeMessage} object.
*
* @param message
* The {@code MimeMessage} object to receive the contents of this instance.
*/
protected void copy(MimeMessage message) {
super.copy(message);
message.mHeader = mHeader.clone();
message.mBody = mBody;
message.mMessageId = mMessageId;
message.mSentDate = mSentDate;
message.mDateFormat = mDateFormat;
message.mSize = mSize;
// These arrays are not supposed to be modified, so it's okay to reuse the references
message.mFrom = mFrom;
message.mTo = mTo;
message.mCc = mCc;
message.mBcc = mBcc;
message.mReplyTo = mReplyTo;
message.mReferences = mReferences;
message.mInReplyTo = mInReplyTo;
}
@Override
public MimeMessage clone() {
MimeMessage message = new MimeMessage();
copy(message);
return message;
}
} }

View File

@ -1092,8 +1092,11 @@ public class MimeUtility {
BinaryTempFileBody tempBody = new BinaryTempFileBody(); BinaryTempFileBody tempBody = new BinaryTempFileBody();
OutputStream out = tempBody.getOutputStream(); OutputStream out = tempBody.getOutputStream();
IOUtils.copy(in, out); try {
out.close(); IOUtils.copy(in, out);
} finally {
out.close();
}
return tempBody; return tempBody;
} }

View File

@ -2380,11 +2380,17 @@ public class LocalStore extends Store implements Serializable {
* so we copy the data into a cached attachment file. * so we copy the data into a cached attachment file.
*/ */
InputStream in = attachment.getBody().getInputStream(); InputStream in = attachment.getBody().getInputStream();
tempAttachmentFile = File.createTempFile("att", null, attachmentDirectory); try {
FileOutputStream out = new FileOutputStream(tempAttachmentFile); tempAttachmentFile = File.createTempFile("att", null, attachmentDirectory);
size = IOUtils.copy(in, out); FileOutputStream out = new FileOutputStream(tempAttachmentFile);
in.close(); try {
out.close(); size = IOUtils.copy(in, out);
} finally {
out.close();
}
} finally {
try { in.close(); } catch (Throwable ignore) {}
}
} }
} }
@ -3302,6 +3308,25 @@ public class LocalStore extends Store implements Serializable {
loadHeaders(); loadHeaders();
return super.getHeaderNames(); return super.getHeaderNames();
} }
@Override
public LocalMessage clone() {
LocalMessage message = new LocalMessage();
super.copy(message);
message.mId = mId;
message.mAttachmentCount = mAttachmentCount;
message.mSubject = mSubject;
message.mPreview = mPreview;
message.mToMeCalculated = mToMeCalculated;
message.mCcMeCalculated = mCcMeCalculated;
message.mToMe = mToMe;
message.mCcMe = mCcMe;
message.mHeadersLoaded = mHeadersLoaded;
message.mMessageDirty = mMessageDirty;
return message;
}
} }
public static class LocalAttachmentBodyPart extends MimeBodyPart { public static class LocalAttachmentBodyPart extends MimeBodyPart {
@ -3355,8 +3380,11 @@ public class LocalStore extends Store implements Serializable {
public void writeTo(OutputStream out) throws IOException, MessagingException { public void writeTo(OutputStream out) throws IOException, MessagingException {
InputStream in = getInputStream(); InputStream in = getInputStream();
Base64OutputStream base64Out = new Base64OutputStream(out); Base64OutputStream base64Out = new Base64OutputStream(out);
IOUtils.copy(in, base64Out); try {
base64Out.close(); IOUtils.copy(in, base64Out);
} finally {
base64Out.close();
}
} }
public Uri getContentUri() { public Uri getContentUri() {

View File

@ -287,20 +287,11 @@ public class SmtpTransport extends Transport {
} }
} }
List<String> results = executeSimpleCommand("EHLO " + localHost); List<String> results = sendHello(localHost);
m8bitEncodingAllowed = results.contains("8BITMIME"); m8bitEncodingAllowed = results.contains("8BITMIME");
/*
* TODO may need to add code to fall back to HELO I switched it from
* using HELO on non STARTTLS connections because of AOL's mail
* server. It won't let you use AUTH without EHLO.
* We should really be paying more attention to the capabilities
* and only attempting auth if it's available, and warning the user
* if not.
*/
if (mConnectionSecurity == CONNECTION_SECURITY_TLS_OPTIONAL if (mConnectionSecurity == CONNECTION_SECURITY_TLS_OPTIONAL
|| mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) { || mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) {
if (results.contains("STARTTLS")) { if (results.contains("STARTTLS")) {
@ -321,7 +312,7 @@ public class SmtpTransport extends Transport {
* Now resend the EHLO. Required by RFC2487 Sec. 5.2, and more specifically, * Now resend the EHLO. Required by RFC2487 Sec. 5.2, and more specifically,
* Exim. * Exim.
*/ */
results = executeSimpleCommand("EHLO " + localHost); results = sendHello(localHost);
} else if (mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) { } else if (mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) {
throw new MessagingException("TLS not supported but required"); throw new MessagingException("TLS not supported but required");
} }
@ -407,6 +398,46 @@ public class SmtpTransport extends Transport {
} }
} }
/**
* Send the client "identity" using the EHLO or HELO command.
*
* <p>
* We first try the EHLO command. If the server sends a negative response, it probably doesn't
* support the EHLO command. So we try the older HELO command that all servers need to support.
* And if that fails, too, we pretend everything is fine and continue unimpressed.
* </p>
*
* @param host
* The EHLO/HELO parameter as defined by the RFC.
*
* @return The list of capabilities as returned by the EHLO command or an empty list.
*
* @throws IOException
* In case of a network error.
* @throws MessagingException
* In case of a malformed response.
*/
private List<String> sendHello(String host) throws IOException, MessagingException {
try {
//TODO: We currently assume the extension keywords returned by the server are always
// uppercased. But the RFC allows mixed-case keywords!
return executeSimpleCommand("EHLO " + host);
} catch (NegativeSmtpReplyException e) {
if (K9.DEBUG) {
Log.v(K9.LOG_TAG, "Server doesn't support the EHLO command. Trying HELO...");
}
try {
executeSimpleCommand("HELO " + host);
} catch (NegativeSmtpReplyException e2) {
Log.w(K9.LOG_TAG, "Server doesn't support the HELO command. Continuing anyway.");
}
}
return new ArrayList<String>(0);
}
@Override @Override
public void sendMessage(Message message) throws MessagingException { public void sendMessage(Message message) throws MessagingException {
ArrayList<Address> addresses = new ArrayList<Address>(); ArrayList<Address> addresses = new ArrayList<Address>();
@ -569,12 +600,28 @@ public class SmtpTransport extends Transport {
} }
private void checkLine(String line) throws MessagingException { private void checkLine(String line) throws MessagingException {
if (line.length() < 1) { int length = line.length();
if (length < 1) {
throw new MessagingException("SMTP response is 0 length"); throw new MessagingException("SMTP response is 0 length");
} }
char c = line.charAt(0); char c = line.charAt(0);
if ((c == '4') || (c == '5')) { if ((c == '4') || (c == '5')) {
throw new MessagingException(line); int replyCode = -1;
String message = line;
if (length >= 3) {
try {
replyCode = Integer.parseInt(line.substring(0, 3));
} catch (NumberFormatException e) { /* ignore */ }
if (length > 4) {
message = line.substring(4);
} else {
message = "";
}
}
throw new NegativeSmtpReplyException(replyCode, message);
} }
} }
@ -679,4 +726,28 @@ public class SmtpTransport extends Transport {
throw new AuthenticationFailedException("Unable to negotiate MD5 CRAM"); throw new AuthenticationFailedException("Unable to negotiate MD5 CRAM");
} }
} }
/**
* Exception that is thrown when the server sends a negative reply (reply codes 4xx or 5xx).
*/
static class NegativeSmtpReplyException extends MessagingException {
private static final long serialVersionUID = 8696043577357897135L;
private final int mReplyCode;
private final String mReplyText;
public NegativeSmtpReplyException(int replyCode, String replyText) {
super("Negative SMTP reply: " + replyCode + " " + replyText);
mReplyCode = replyCode;
mReplyText = replyText;
}
public int getReplyCode() {
return mReplyCode;
}
public String getReplyText() {
return mReplyText;
}
}
} }

View File

@ -114,7 +114,8 @@ public class GlobalSettings {
new V(1, new FontSizeSetting(FontSizes.FONT_12DIP)) new V(1, new FontSizeSetting(FontSizes.FONT_12DIP))
)); ));
s.put("gesturesEnabled", Settings.versions( s.put("gesturesEnabled", Settings.versions(
new V(1, new BooleanSetting(true)) new V(1, new BooleanSetting(true)),
new V(4, new BooleanSetting(false))
)); ));
s.put("hideSpecialAccounts", Settings.versions( s.put("hideSpecialAccounts", Settings.versions(
new V(1, new BooleanSetting(false)) new V(1, new BooleanSetting(false))
@ -189,7 +190,8 @@ public class GlobalSettings {
new V(1, new BooleanSetting(false)) new V(1, new BooleanSetting(false))
)); ));
s.put("zoomControlsEnabled", Settings.versions( s.put("zoomControlsEnabled", Settings.versions(
new V(1, new BooleanSetting(false)) new V(1, new BooleanSetting(false)),
new V(4, new BooleanSetting(true))
)); ));
SETTINGS = Collections.unmodifiableMap(s); SETTINGS = Collections.unmodifiableMap(s);

View File

@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -34,7 +35,7 @@ public class Settings {
* *
* @see SettingsExporter * @see SettingsExporter
*/ */
public static final int VERSION = 3; public static final int VERSION = 4;
public static Map<String, Object> validate(int version, Map<String, public static Map<String, Object> validate(int version, Map<String,
TreeMap<Integer, SettingsDescription>> settings, TreeMap<Integer, SettingsDescription>> settings,
@ -44,15 +45,25 @@ public class Settings {
for (Map.Entry<String, TreeMap<Integer, SettingsDescription>> versionedSetting : for (Map.Entry<String, TreeMap<Integer, SettingsDescription>> versionedSetting :
settings.entrySet()) { settings.entrySet()) {
Entry<Integer, SettingsDescription> setting = // Get the setting description with the highest version lower than or equal to the
versionedSetting.getValue().floorEntry(version); // supplied content version.
TreeMap<Integer, SettingsDescription> versions = versionedSetting.getValue();
SortedMap<Integer, SettingsDescription> headMap = versions.headMap(version + 1);
if (setting == null) { // Skip this setting if it was introduced after 'version'
if (headMap.size() == 0) {
continue;
}
Integer settingVersion = headMap.lastKey();
SettingsDescription desc = versions.get(settingVersion);
// Skip this setting if it is no longer used in 'version'
if (desc == null) {
continue; continue;
} }
String key = versionedSetting.getKey(); String key = versionedSetting.getKey();
SettingsDescription desc = setting.getValue();
boolean useDefaultValue; boolean useDefaultValue;
if (!importedSettings.containsKey(key)) { if (!importedSettings.containsKey(key)) {
@ -127,7 +138,7 @@ public class Settings {
// Check if it was already added to upgradedSettings by the SettingsUpgrader // Check if it was already added to upgradedSettings by the SettingsUpgrader
if (!upgradedSettings.containsKey(settingName)) { if (!upgradedSettings.containsKey(settingName)) {
// Insert default value to upgradedSettings // Insert default value to upgradedSettings
SettingsDescription setting = versionedSettings.firstEntry().getValue(); SettingsDescription setting = versionedSettings.get(toVersion);
Object defaultValue = setting.getDefaultValue(); Object defaultValue = setting.getDefaultValue();
upgradedSettings.put(settingName, defaultValue); upgradedSettings.put(settingName, defaultValue);
@ -140,8 +151,9 @@ public class Settings {
} }
// Handle removed settings // Handle removed settings
Entry<Integer, SettingsDescription> lastEntry = versionedSettings.lastEntry(); Integer highestVersion = versionedSettings.lastKey();
if (lastEntry.getKey().intValue() == toVersion && lastEntry.getValue() == null) { if (highestVersion.intValue() == toVersion &&
versionedSettings.get(highestVersion) == null) {
upgradedSettings.remove(settingName); upgradedSettings.remove(settingName);
if (deletedSettings == null) { if (deletedSettings == null) {
deletedSettings = new HashSet<String>(); deletedSettings = new HashSet<String>();
@ -179,8 +191,10 @@ public class Settings {
String settingName = setting.getKey(); String settingName = setting.getKey();
Object internalValue = setting.getValue(); Object internalValue = setting.getValue();
SettingsDescription settingDesc = TreeMap<Integer, SettingsDescription> versionedSetting =
settingDescriptions.get(settingName).lastEntry().getValue(); settingDescriptions.get(settingName);
Integer highestVersion = versionedSetting.lastKey();
SettingsDescription settingDesc = versionedSetting.get(highestVersion);
if (settingDesc != null) { if (settingDesc != null) {
String stringValue = settingDesc.toString(internalValue); String stringValue = settingDesc.toString(internalValue);

View File

@ -171,7 +171,9 @@ public class SettingsExporter {
String key = versionedSetting.getKey(); String key = versionedSetting.getKey();
String valueString = (String) prefs.get(key); String valueString = (String) prefs.get(key);
SettingsDescription setting = versionedSetting.getValue().lastEntry().getValue(); TreeMap<Integer, SettingsDescription> versions = versionedSetting.getValue();
Integer highestVersion = versions.lastKey();
SettingsDescription setting = versions.get(highestVersion);
if (setting == null) { if (setting == null) {
// Setting was removed. // Setting was removed.
continue; continue;
@ -323,7 +325,8 @@ public class SettingsExporter {
AccountSettings.SETTINGS.get(keyPart); AccountSettings.SETTINGS.get(keyPart);
if (versionedSetting != null) { if (versionedSetting != null) {
SettingsDescription setting = versionedSetting.lastEntry().getValue(); Integer highestVersion = versionedSetting.lastKey();
SettingsDescription setting = versionedSetting.get(highestVersion);
if (setting != null) { if (setting != null) {
// Only export account settings that can be found in AccountSettings.SETTINGS // Only export account settings that can be found in AccountSettings.SETTINGS
@ -417,7 +420,8 @@ public class SettingsExporter {
IdentitySettings.SETTINGS.get(identityKey); IdentitySettings.SETTINGS.get(identityKey);
if (versionedSetting != null) { if (versionedSetting != null) {
SettingsDescription setting = versionedSetting.lastEntry().getValue(); Integer highestVersion = versionedSetting.lastKey();
SettingsDescription setting = versionedSetting.get(highestVersion);
if (setting != null) { if (setting != null) {
// Only write settings that have an entry in IdentitySettings.SETTINGS // Only write settings that have an entry in IdentitySettings.SETTINGS
@ -468,7 +472,8 @@ public class SettingsExporter {
FolderSettings.SETTINGS.get(folderKey); FolderSettings.SETTINGS.get(folderKey);
if (versionedSetting != null) { if (versionedSetting != null) {
SettingsDescription setting = versionedSetting.lastEntry().getValue(); Integer highestVersion = versionedSetting.lastKey();
SettingsDescription setting = versionedSetting.get(highestVersion);
if (setting != null) { if (setting != null) {
// Only write settings that have an entry in FolderSettings.SETTINGS // Only write settings that have an entry in FolderSettings.SETTINGS

View File

@ -180,11 +180,14 @@ public class AttachmentProvider extends ContentProvider {
if (thumbnail != null) { if (thumbnail != null) {
thumbnail = Bitmap.createScaledBitmap(thumbnail, width, height, true); thumbnail = Bitmap.createScaledBitmap(thumbnail, width, height, true);
FileOutputStream out = new FileOutputStream(file); FileOutputStream out = new FileOutputStream(file);
thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out); try {
out.close(); thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out);
} finally {
out.close();
}
} }
} finally { } finally {
in.close(); try { in.close(); } catch (Throwable ignore) {}
} }
} catch (IOException ioe) { } catch (IOException ioe) {
return null; return null;