mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-16 22:45:04 -05:00
Merge commit '4.113' into issue-162-new
Conflicts: src/com/fsck/k9/activity/ChooseFolder.java src/com/fsck/k9/controller/MessagingController.java src/com/fsck/k9/mail/store/ImapStore.java src/com/fsck/k9/view/MessageHeader.java I hacked on src/com/fsck/k9/controller/MessagingController.java and perhaps broke uidplus support, but things run fine in my simple tests.
This commit is contained in:
commit
a5d0e44711
@ -9,5 +9,6 @@
|
||||
<classpathentry kind="lib" path="libs/jzlib-1.0.7.jar"/>
|
||||
<classpathentry kind="lib" path="libs/jutf7-1.0.1-SNAPSHOT.jar"/>
|
||||
<classpathentry kind="lib" path="libs/htmlcleaner-2.2.jar"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="15011"
|
||||
android:versionName="4.112" package="com.fsck.k9"
|
||||
android:versionCode="15012"
|
||||
android:versionName="4.113" package="com.fsck.k9"
|
||||
>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="7"
|
||||
|
@ -19,5 +19,5 @@
|
||||
split.density=false
|
||||
java.encoding=utf8
|
||||
# Project target.
|
||||
target=android-9
|
||||
target=android-15
|
||||
extensible.libs.classpath=compile-only-libs
|
||||
|
@ -11,5 +11,5 @@
|
||||
split.density=false
|
||||
java.encoding=utf8
|
||||
# Project target.
|
||||
target=android-9
|
||||
target=android-15
|
||||
extensible.libs.classpath=compile-only-libs
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 434 B After Width: | Height: | Size: 570 B |
Binary file not shown.
Before Width: | Height: | Size: 436 B After Width: | Height: | Size: 570 B |
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ExpandableListView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:divider="?android:attr/listDivider"
|
||||
android:childDivider="?android:attr/listDivider"
|
||||
android:indicatorLeft="14dip" />
|
@ -3,37 +3,25 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:paddingRight="6dip"
|
||||
android:paddingBottom="2dip"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:gravity="center_vertical" >
|
||||
|
||||
android:background="#cccccc"
|
||||
android:gravity="left|center_vertical">
|
||||
<View
|
||||
android:id="@+id/chip"
|
||||
android:layout_width="6dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentLeft="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft" >
|
||||
android:layout_width="6dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:id="@+id/name"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingLeft="18dp"
|
||||
android:paddingRight="4dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -4,26 +4,10 @@
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:paddingRight="6dip"
|
||||
android:paddingBottom="2dip"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:gravity="center_vertical" >
|
||||
|
||||
<View
|
||||
android:id="@+id/chip"
|
||||
android:layout_width="6dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentLeft="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft" >
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingRight="4dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
@ -32,7 +16,7 @@
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
@ -44,5 +28,3 @@
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -2,14 +2,13 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#ffffff" >
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
android:scrollbarStyle="outsideInset"
|
||||
android:scrollbarStyle="insideOverlay"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
@ -20,17 +19,19 @@
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:paddingTop="6dp"
|
||||
android:orientation="vertical"
|
||||
android:background="#ededed" >
|
||||
android:background="#45bcbcbc">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/from"
|
||||
<Button
|
||||
android:id="@+id/identity"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="left|center"
|
||||
android:layout_marginLeft="6dip"
|
||||
android:layout_marginRight="6dip"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
android:layout_marginRight="6dip"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/to_wrapper"
|
||||
android:layout_height="wrap_content"
|
||||
@ -38,27 +39,28 @@
|
||||
android:layout_marginLeft="6dip"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_width="fill_parent">
|
||||
|
||||
<MultiAutoCompleteTextView
|
||||
android:id="@+id/to"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textEmailAddress|textMultiLine"
|
||||
android:imeOptions="actionNext"
|
||||
android:hint="@string/message_compose_to_hint"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_weight="5"
|
||||
/>
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/add_to"
|
||||
android:contentDescription="@string/message_compose_description_add_to"
|
||||
android:src="@drawable/ic_button_contacts"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="60dip"
|
||||
android:layout_marginTop="1dip"
|
||||
/>
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginTop="1dip"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cc_wrapper"
|
||||
android:visibility="gone"
|
||||
@ -67,27 +69,28 @@
|
||||
android:layout_marginLeft="6dip"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_width="fill_parent">
|
||||
|
||||
<MultiAutoCompleteTextView
|
||||
android:id="@+id/cc"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="5"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginRight="6dip"
|
||||
android:inputType="textEmailAddress|textMultiLine"
|
||||
android:imeOptions="actionNext"
|
||||
android:hint="@string/message_compose_cc_hint"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/add_cc"
|
||||
android:contentDescription="@string/message_compose_description_add_cc"
|
||||
android:src="@drawable/ic_button_contacts"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="60dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_marginTop="1dip"
|
||||
/>
|
||||
android:layout_marginTop="1dip"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bcc_wrapper"
|
||||
android:visibility="gone"
|
||||
@ -99,24 +102,23 @@
|
||||
|
||||
<MultiAutoCompleteTextView
|
||||
android:id="@+id/bcc"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_weight="5"
|
||||
android:layout_weight="1"
|
||||
android:inputType="textEmailAddress|textMultiLine"
|
||||
android:imeOptions="actionNext"
|
||||
android:hint="@string/message_compose_bcc_hint"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/add_bcc"
|
||||
android:contentDescription="@string/message_compose_description_add_bcc"
|
||||
android:layout_marginTop="1dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:id="@+id/add_bcc"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="60dip"
|
||||
android:src="@drawable/ic_button_contacts"
|
||||
/>
|
||||
android:layout_width="wrap_content"
|
||||
android:src="@drawable/ic_button_contacts"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@ -138,7 +140,6 @@
|
||||
<CheckBox
|
||||
android:text="@string/btn_crypto_sign"
|
||||
android:id="@+id/cb_crypto_signature"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
@ -154,7 +155,6 @@
|
||||
android:id="@+id/userId"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
@ -162,7 +162,6 @@
|
||||
android:id="@+id/userIdRest"
|
||||
android:textSize="10sp"
|
||||
android:ellipsize="end"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
@ -173,7 +172,6 @@
|
||||
<CheckBox
|
||||
android:text="@string/btn_encrypt"
|
||||
android:id="@+id/cb_encrypt"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@ -191,7 +189,6 @@
|
||||
android:inputType="textEmailSubject|textAutoCorrect|textCapSentences|textImeMultiLine"
|
||||
android:imeOptions="actionNext"
|
||||
android:singleLine="true"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<!--
|
||||
@ -211,30 +208,31 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- We have to use "wrap_content" (not "0dip") for "layout_height", otherwise the
|
||||
EditText won't properly grow in height while the user is typing the message -->
|
||||
<EditText
|
||||
android:id="@+id/message_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:layout_weight="1"
|
||||
android:gravity="left|top"
|
||||
android:hint="@string/message_compose_content_hint"
|
||||
android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
|
||||
android:imeOptions="actionDone|flagNoEnterAction"
|
||||
android:minLines="3"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/upper_signature"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:gravity="left|top"
|
||||
android:editable="false"
|
||||
android:minLines="0"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:hint="@string/message_compose_signature_hint"
|
||||
android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<Button
|
||||
@ -244,9 +242,7 @@
|
||||
android:padding="0dip"
|
||||
android:layout_gravity="right"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true" />
|
||||
android:layout_width="match_parent"/>
|
||||
|
||||
<!-- Quoted text bar -->
|
||||
<RelativeLayout
|
||||
@ -258,12 +254,11 @@
|
||||
android:id="@+id/quoted_text"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:gravity="left|top"
|
||||
android:minLines="3"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<com.fsck.k9.view.MessageWebView
|
||||
@ -280,19 +275,17 @@
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/quoted_text_edit"
|
||||
android:contentDescription="@string/message_compose_description_edit_quoted_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginRight="8dip"
|
||||
android:background="@drawable/btn_edit" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/quoted_text_delete"
|
||||
android:contentDescription="@string/message_compose_description_delete_quoted_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="@drawable/btn_dialog" />
|
||||
|
||||
</LinearLayout>
|
||||
@ -303,13 +296,13 @@
|
||||
android:id="@+id/lower_signature"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:gravity="left|top"
|
||||
android:editable="false"
|
||||
android:minLines="0"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:hint="@string/message_compose_signature_hint"
|
||||
android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -122,16 +122,6 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/additional_headers_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="false"
|
||||
android:ellipsize="none"
|
||||
android:textSize="10sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@ -192,6 +182,31 @@
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:id="@+id/additional_headers_row">
|
||||
|
||||
<!-- Color chip 2 -->
|
||||
<View
|
||||
android:id="@+id/chip2"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_width="6dip"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
<!-- Additional headers -->
|
||||
<TextView
|
||||
android:layout_span="2"
|
||||
android:id="@+id/additional_headers_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="10dp"
|
||||
android:singleLine="false"
|
||||
android:ellipsize="none"
|
||||
android:textSize="10sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
|
||||
<!-- Separator -->
|
||||
@ -201,19 +216,19 @@
|
||||
android:id="@+id/show_additional_headers_area"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="21.5dp"
|
||||
android:layout_height="21dp"
|
||||
android:focusable="true"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/separator_area_background">
|
||||
android:background="@drawable/message_view_header_background">
|
||||
|
||||
<RelativeLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="20dp">
|
||||
|
||||
<!-- Color chip 2 -->
|
||||
<!-- Color chip 3 -->
|
||||
<View
|
||||
android:id="@+id/chip2"
|
||||
android:id="@+id/chip3"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_width="6dip"
|
||||
android:layout_height="fill_parent"
|
||||
@ -233,10 +248,9 @@
|
||||
</RelativeLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/separator"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1.5dp"
|
||||
android:background="#59000000"/>
|
||||
android:layout_height="1dip"
|
||||
android:background="@drawable/divider_horizontal_email" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -30,12 +30,6 @@
|
||||
android:title="@string/discard_action"
|
||||
android:icon="@drawable/ic_menu_close_clear_cancel"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/choose_identity"
|
||||
android:alphabeticShortcut="i"
|
||||
android:title="@string/send_as"
|
||||
android:icon="@drawable/ic_menu_identity"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/read_receipt"
|
||||
android:alphabeticShortcut="r"
|
||||
|
@ -15,6 +15,10 @@
|
||||
android:id="@+id/set_sort_date"
|
||||
android:title="@string/sort_by_date"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/set_sort_arrival"
|
||||
android:title="@string/sort_by_arrival"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/set_sort_subject"
|
||||
android:title="@string/sort_by_subject"
|
||||
|
@ -64,7 +64,7 @@
|
||||
<string name="done_action">Fertig</string> <!-- Used to complete a multi-step process -->
|
||||
<string name="remove_action">Entfernen</string>
|
||||
<string name="discard_action">Verwerfen</string>
|
||||
<string name="save_draft_action">Als Entwurf speichern</string>
|
||||
<string name="save_draft_action">Speichern</string>
|
||||
<string name="retry_action">Erneut versuchen</string>
|
||||
<string name="refresh_action">Aktualisieren</string>
|
||||
<string name="check_mail_action">Nachrichten abrufen</string>
|
||||
@ -218,7 +218,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
\n * Speichern von Anhängen auf SD-Karte
|
||||
\n * Papierkorb leeren
|
||||
\n * Sortieren der Nachrichten
|
||||
\n * ...und viele mehr
|
||||
\n * …und viele mehr
|
||||
\n
|
||||
\nBitte beachten Sie, dass K-9, wie viele andere E-Mail-Anwendungen auch, die meisten kostenlosen Hotmail-Accounts nicht unterstützt. Zudem gibt es einige Probleme mit Microsoft Exchange-Servern.
|
||||
\n
|
||||
@ -256,6 +256,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="message_compose_bcc_hint">BCC</string>
|
||||
<string name="message_compose_subject_hint">Betreff</string>
|
||||
<string name="message_compose_content_hint">Nachrichtentext</string>
|
||||
<string name="message_compose_signature_hint">Signatur</string>
|
||||
<string name="message_compose_quote_header_separator">-------- Original-Nachricht --------</string>
|
||||
<string name="message_compose_quote_header_subject">Betreff:</string>
|
||||
<string name="message_compose_quote_header_send_date">Gesendet:</string>
|
||||
@ -269,6 +270,11 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="message_compose_downloading_attachments_toast">Einige Anhänge wurden nicht heruntergeladen. Sie werden automatisch heruntergeladen, bevor diese Nachricht gesendet wird.</string>
|
||||
<string name="message_compose_attachments_skipped_toast">Einige Anhänge können nicht weitergeleitet werden, da diese nicht heruntergeladen wurden.</string>
|
||||
<string name="message_compose_show_quoted_text_action">Original-Nachricht zitieren</string>
|
||||
<string name="message_compose_description_add_to">Empfänger hinzufügen</string>
|
||||
<string name="message_compose_description_add_cc">Empfänger hinzufügen (CC)</string>
|
||||
<string name="message_compose_description_add_bcc">Empfänger hinzufügen (BCC)</string>
|
||||
<string name="message_compose_description_delete_quoted_text">Zitierten Text entfernen</string>
|
||||
<string name="message_compose_description_edit_quoted_text">Zitierten Text bearbeiten</string>
|
||||
|
||||
<string name="message_view_from_format">Von: <xliff:g id="name">%s</xliff:g> <<xliff:g id="email">%s</xliff:g>></string>
|
||||
<string name="message_to_label">An:</string>
|
||||
@ -285,6 +291,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="message_view_status_attachment_not_saved">Anhang konnte nicht auf SD-Karte gespeichert werden.</string>
|
||||
<string name="message_view_show_pictures_instructions">Wählen Sie \"Bilder anzeigen\", um eingebettete Bilder abzurufen.</string>
|
||||
<string name="message_view_show_pictures_action">Bilder anzeigen</string>
|
||||
<string name="message_view_show_message_action">Zeige Nachricht</string>
|
||||
<string name="message_view_show_attachments_action">Zeige Anhänge</string>
|
||||
<string name="message_view_show_more_attachments_action">Mehr…</string>
|
||||
<string name="message_view_fetching_attachment_toast">Lade Anhang.</string>
|
||||
@ -402,7 +409,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_setup_incoming_security_tls_optional_label">TLS (falls verfügbar)</string>
|
||||
<string name="account_setup_incoming_security_tls_label">TLS (immer)</string>
|
||||
|
||||
<string name="account_setup_incoming_delete_policy_label">Bei Löschen von Nachrichten:</string>
|
||||
<string name="account_setup_incoming_delete_policy_label">Beim Löschen von Nachrichten</string>
|
||||
<string name="account_setup_incoming_delete_policy_never_label">Nie von Server löschen</string>
|
||||
<string name="account_setup_incoming_delete_policy_7days_label">Nach 7 Tagen löschen</string>
|
||||
<string name="account_setup_incoming_delete_policy_delete_label">Auch auf Server löschen</string>
|
||||
@ -426,7 +433,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_setup_expunge_policy_on_poll">Bei jedem Abrufen</string>
|
||||
<string name="account_setup_expunge_policy_manual">Nur manuell</string>
|
||||
|
||||
<string name="account_setup_incoming_autodetect_namespace_label">IMAP Namensraum automatisch ermitteln</string>
|
||||
<string name="account_setup_incoming_autodetect_namespace_label">IMAP-Namensraum automatisch ermitteln</string>
|
||||
<string name="account_setup_incoming_imap_path_prefix_label">IMAP-Verzeichnispräfix</string>
|
||||
|
||||
<string name="drafts_folder_label">Ordner für Entwürfe</string>
|
||||
@ -457,7 +464,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_setup_outgoing_require_login_label">Anmeldung erforderlich.</string>
|
||||
<string name="account_setup_outgoing_username_label">Benutzername</string>
|
||||
<string name="account_setup_outgoing_password_label">Passwort</string>
|
||||
<string name="account_setup_outgoing_authentication_label">Authentifizierungstyp</string>
|
||||
<string name="account_setup_outgoing_authentication_label">Authentifizierungsmethode</string>
|
||||
<!-- The authentication strings below are for a planned (hopefully) change to the above username and password options -->
|
||||
<string name="account_setup_outgoing_authentication_basic_label">Benutzername & Passwort</string>
|
||||
<string name="account_setup_outgoing_authentication_basic_username_label">Benutzername</string>
|
||||
@ -492,7 +499,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="push_poll_on_connect_label">Abruf beim Start der Push-Verbindung</string>
|
||||
<string name="account_setup_options_enable_push_label">Push-Mail für dieses Konto aktivieren</string>
|
||||
<string name="account_setup_options_enable_push_summary">Neue Nachrichten werden nach dem Eintreffen umgehend abgerufen, falls Ihr Server dies unterstützt. Diese Einstellung kann zur Reduzierung der Laufzeit führen oder diese verbessern.</string>
|
||||
<string name="idle_refresh_period_label">IDLE Verbindung refreshen</string>
|
||||
<string name="idle_refresh_period_label">Push-Verbindung erneuern</string>
|
||||
<string name="idle_refresh_period_1min">Jede Minute</string>
|
||||
<string name="idle_refresh_period_2min">Alle 2 Minuten</string>
|
||||
<string name="idle_refresh_period_3min">Alle 3 Minuten</string>
|
||||
@ -544,6 +551,8 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_settings_notification_opens_unread_summary">Zeigt beim Öffnen einer Benachrichtigung Liste der ungelesenen Nachrichten an</string>
|
||||
<string name="account_settings_notification_unread_count_label">Anzahl ungelesener Nachrichten anzeigen</string>
|
||||
<string name="account_settings_notification_unread_count_summary">Zeigt die Anzahl der ungelesenen Nachrichten in der Statuszeile.</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_label">Nachricht beim Öffnen als gelesen markieren</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_summary">Markiert eine Nachricht als gelesen, sobald sie zum Betrachten geöffnet wird.</string>
|
||||
|
||||
<string name="account_settings_enable_move_buttons_label">Spam-Leiste</string>
|
||||
<string name="account_settings_enable_move_buttons_summary">Zeige Archivieren-, Verschieben- und Spam-Schaltfläche.</string>
|
||||
@ -582,16 +591,15 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_settings_folders">Ordner</string>
|
||||
<string name="account_settings_message_lists">Liste der Nachrichten</string>
|
||||
<string name="account_settings_message_view">Anzeige der Nachricht</string>
|
||||
<string name="account_settings_quote_prefix_label">Prefix beim Zitieren</string>
|
||||
<string name="account_settings_quote_prefix_label">Präfix beim Zitieren</string>
|
||||
<string name="account_settings_crypto">Kryptographie</string>
|
||||
<string name="account_settings_crypto_app">OpenPGP Provider</string>
|
||||
<string name="account_settings_crypto_app_none">Keiner</string>
|
||||
<string name="account_settings_crypto_app_not_available">Nicht verfügbar</string>
|
||||
<string name="account_settings_crypto_auto_signature">Auto-sign</string>
|
||||
<string name="account_settings_crypto_auto_signature_summary">Email Adresse des Kontos verwenden um Signaturschlüssel zu schätzen.</string>
|
||||
|
||||
<string name="account_settings_crypto_auto_encrypt">Automatische verschlüsselung</string>
|
||||
<string name="account_settings_crypto_auto_encrypt_summary">Verschlüsselung aktivieren falls für den Empfänger ein öffentlichen Schlüssel abgespeichert ist.</string>
|
||||
<string name="account_settings_crypto_auto_signature">Automatisches Signieren</string>
|
||||
<string name="account_settings_crypto_auto_signature_summary">Verwendet die E-Mail-Adresse des Kontos, um den Signaturschlüssel zu finden.</string>
|
||||
<string name="account_settings_crypto_auto_encrypt">Automatische Verschlüsselung</string>
|
||||
<string name="account_settings_crypto_auto_encrypt_summary">Verschlüsselt automatisch, falls für den Empfänger ein öffentlicher Schlüssel vorhanden ist.</string>
|
||||
|
||||
<string name="account_settings_mail_check_frequency_label">Häufigkeit der E-Mail-Abfrage</string>
|
||||
<string name="account_settings_second_class_check_frequency_label">Häufigkeit der Abfrage für Nebenordner</string>
|
||||
@ -664,7 +672,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_settings_folder_target_mode_not_second_class">Alle außer Nebenordner</string>
|
||||
|
||||
<string name="account_settings_sync_remote_deletetions_label">Übernehme Löschungen vom Server</string>
|
||||
<string name="account_settings_sync_remote_deletetions_summary">Lösche Nachrichten wenn sie am Server gelöscht werden</string>
|
||||
<string name="account_settings_sync_remote_deletetions_summary">Lösche Nachrichten, wenn sie vom Server gelöscht wurden</string>
|
||||
|
||||
<string name="folder_settings_title">Ordner-Einstellungen</string>
|
||||
|
||||
@ -776,8 +784,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="sort_attach_first">Nachrichten mit Anhängen zuerst</string>
|
||||
<string name="sort_unattached_first">Nachrichten ohne Anhänge zuerst</string>
|
||||
|
||||
<string name="sort_by">Sortieren nach...</string>
|
||||
<string name="sort_by">Sortieren nach…</string>
|
||||
<string name="sort_by_date">Datum</string>
|
||||
<string name="sort_by_arrival">Ankunftsdatum</string>
|
||||
<string name="sort_by_sender">Absender</string>
|
||||
<string name="sort_by_subject">Betreff</string>
|
||||
<string name="sort_by_flag">Wichtigkeit</string>
|
||||
@ -978,6 +987,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="font_size_message_view_date">Datum</string>
|
||||
<string name="font_size_message_view_content">Nachrichtentext</string>
|
||||
|
||||
<string name="font_size_message_compose">Nachricht verfassen</string>
|
||||
<string name="font_size_message_compose_input">Texteingabefelder</string>
|
||||
|
||||
<string name="font_size_tiniest">Winzig</string>
|
||||
<string name="font_size_tiny">Sehr klein</string>
|
||||
<string name="font_size_smaller">Kleiner</string>
|
||||
@ -1019,6 +1031,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="save_or_discard_draft_message_dlg_title">Entwurf speichern?</string>
|
||||
<string name="save_or_discard_draft_message_instructions_fmt">Entwurf speichern oder verwerfen?</string>
|
||||
|
||||
<string name="confirm_discard_draft_message_title">Nachricht verwerfen?</string>
|
||||
<string name="confirm_discard_draft_message">Sind Sie sicher, dass Sie die Nachricht verwerfen möchten?</string>
|
||||
|
||||
<string name="refuse_to_save_draft_marked_encrypted_dlg_title">Speichern des Entwurfs verweigern.</string>
|
||||
<string name="refuse_to_save_draft_marked_encrypted_instructions_fmt">Die Speicherung von als verschlüsselt markierten Entwürfen verweigern.</string>
|
||||
|
||||
@ -1058,9 +1073,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="settings_import">Einstellungen importieren</string>
|
||||
<string name="settings_import_selection">Auswahl importieren</string>
|
||||
<string name="settings_import_global_settings">Globale Einstellungen</string>
|
||||
<string name="settings_exporting">Einstellungen Exportieren...</string>
|
||||
<string name="settings_importing">Einstellungen Importieren...</string>
|
||||
<string name="settings_import_scanning_file">Datei lesen...</string>
|
||||
<string name="settings_exporting">Einstellungen exportieren…</string>
|
||||
<string name="settings_importing">Einstellungen importieren…</string>
|
||||
<string name="settings_import_scanning_file">Datei lesen…</string>
|
||||
<string name="settings_export_success">Exportiere Einstellungen erfolgreich in <xliff:g id="filename">%s</xliff:g> gespeichert</string>
|
||||
<string name="settings_import_global_settings_success">Globale Einstellungen erfolgreich von <xliff:g id="filename">%s</xliff:g> importiert</string>
|
||||
<string name="settings_import_success"><xliff:g id="accounts">%s</xliff:g> erfolgreich von <xliff:g id="filename">%s</xliff:g> importiert</string>
|
||||
@ -1069,21 +1084,21 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<item quantity="other"><xliff:g id="numAccounts">%s</xliff:g> Konten</item>
|
||||
</plurals>
|
||||
<string name="settings_export_failure">Exportieren der Einstellungen ist fehlgeschlagen</string>
|
||||
<string name="settings_import_failure">Importieren der Einstellungen von <xliff:g id="filename">%s</xliff:g> sind fehlgeschlagen</string>
|
||||
<string name="settings_import_failure">Importieren der Einstellungen von <xliff:g id="filename">%s</xliff:g> ist fehlgeschlagen</string>
|
||||
<string name="settings_export_success_header">Export erfolgreich</string>
|
||||
<string name="settings_export_failed_header">Export fehlgeschlagen</string>
|
||||
<string name="settings_import_success_header">Import erfolgreich</string>
|
||||
<string name="settings_import_failed_header">Import fehlgeschlagen</string>
|
||||
<string name="settings_import_activate_account_header">Konto aktivieren</string>
|
||||
<string name="settings_import_activate_account_intro">Um das Konto \"<xliff:g id="account">%s</xliff:g>\" zu benutzen müssen sie das <xliff:g id="server_passwords">%s</xliff:g> angeben.</string>
|
||||
<string name="settings_import_activate_account_intro">Um das Konto \"<xliff:g id="account">%s</xliff:g>\" benutzen zu können, müssen Sie <xliff:g id="server_passwords">%s</xliff:g> angeben.</string>
|
||||
<plurals name="settings_import_server_passwords">
|
||||
<item quantity="one">Server Passwort</item>
|
||||
<item quantity="other">Server Passwörter</item>
|
||||
<item quantity="one">das Server Passwort</item>
|
||||
<item quantity="other">die Server Passwörter</item>
|
||||
</plurals>
|
||||
<string name="settings_import_incoming_server">Posteingangsserver (<xliff:g id="hostname">%s</xliff:g>):</string>
|
||||
<string name="settings_import_outgoing_server">Postausgangsserver (<xliff:g id="hostname">%s</xliff:g>):</string>
|
||||
<plurals name="settings_import_setting_passwords">
|
||||
<item quantity="one">Passwort Setzen...</item>
|
||||
<item quantity="one">Passwort setzen...</item>
|
||||
<item quantity="other">Passwörter setzen...</item>
|
||||
</plurals>
|
||||
<string name="settings_import_use_incoming_server_password">Passwort des Posteingangsservers benutzen</string>
|
||||
@ -1093,12 +1108,44 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
|
||||
<string name="account_unavailable">Konto \"<xliff:g id="account">%s</xliff:g>\" ist nicht verfügbar; Bitte SD-Karte prüfen.</string>
|
||||
|
||||
<string name="settings_attachment_default_path">Anhang speichern unter...</string>
|
||||
<string name="settings_attachment_default_path">Anhang speichern unter…</string>
|
||||
<string name="attachment_save_title">Anhang speichern</string>
|
||||
<string name="attachment_save_desc">Es wurde kein Dateimanager gefunden. Wo soll der Anhang abgelegt werden?</string>
|
||||
|
||||
<string name="manage_accounts_move_up_action">Nach oben verschieben</string>
|
||||
<string name="manage_accounts_move_down_action">Nach unten verschieben</string>
|
||||
<string name="manage_accounts_moving_message">Konto verschieben...</string>
|
||||
<string name="manage_accounts_moving_message">Konto verschieben…</string>
|
||||
|
||||
<string name="unread_widget_label">K-9 Ungelesen</string>
|
||||
<string name="unread_widget_select_account">Zeige die Anzahl ungelesener Nachrichten für…</string>
|
||||
|
||||
<string name="import_dialog_error_title">Kein Dateimanager gefunden!</string>
|
||||
<string name="import_dialog_error_message">Es wurde keine geeignete Applikation gefunden, um den Import durchzuführen. Bitte installieren Sie einen Dateimanager aus dem Play Store.</string>
|
||||
<string name="open_market">Play Store öffnen</string>
|
||||
<string name="close">Abbrechen</string>
|
||||
|
||||
<string name="webview_contextmenu_link_view_action">Öffnen</string>
|
||||
<string name="webview_contextmenu_link_share_action">Link weitergeben</string>
|
||||
<string name="webview_contextmenu_link_copy_action">Link kopieren</string>
|
||||
<string name="webview_contextmenu_link_clipboard_label">Link</string>
|
||||
|
||||
<string name="webview_contextmenu_image_title">Bild</string>
|
||||
<string name="webview_contextmenu_image_view_action">Bild anzeigen</string>
|
||||
<string name="webview_contextmenu_image_save_action">Bild speichern</string>
|
||||
<string name="webview_contextmenu_image_download_action">Bild herunterladen</string>
|
||||
<string name="webview_contextmenu_image_copy_action">Bild-URL kopieren</string>
|
||||
<string name="webview_contextmenu_image_clipboard_label">Bild-URL</string>
|
||||
|
||||
<string name="webview_contextmenu_phone_call_action">Anrufen</string>
|
||||
<string name="webview_contextmenu_phone_save_action">Im Adressbuch speichern</string>
|
||||
<string name="webview_contextmenu_phone_copy_action">Telefonnummer kopieren</string>
|
||||
<string name="webview_contextmenu_phone_clipboard_label">Telefonnummer</string>
|
||||
|
||||
<string name="webview_contextmenu_email_send_action">E-Mail senden</string>
|
||||
<string name="webview_contextmenu_email_save_action">Im Adressbuch speichern</string>
|
||||
<string name="webview_contextmenu_email_copy_action">E-Mail-Adresse kopieren</string>
|
||||
<string name="webview_contextmenu_email_clipboard_label">E-Mail-Adresse</string>
|
||||
|
||||
<string name="image_saved_as">Das Bild wurde als \"<xliff:g id="filename">%s</xliff:g>\" gespeichert.</string>
|
||||
<string name="image_saving_failed">Speichern des Bildes fehlgeschlagen.</string>
|
||||
</resources>
|
||||
|
@ -258,6 +258,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="message_compose_bcc_hint">Bcc</string>
|
||||
<string name="message_compose_subject_hint">件名</string>
|
||||
<string name="message_compose_content_hint">本文</string>
|
||||
<string name="message_compose_signature_hint">署名</string>
|
||||
<string name="message_compose_quote_header_separator">-------- 元メール --------</string>
|
||||
<string name="message_compose_quote_header_subject">件名:</string>
|
||||
<string name="message_compose_quote_header_send_date">送信日:</string>
|
||||
@ -271,6 +272,11 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="message_compose_downloading_attachments_toast">一部の添付ファイルをダウンロードしていません。このメールが送信される前に自動的にダウンロードされます。</string>
|
||||
<string name="message_compose_attachments_skipped_toast">ダウンロードしていないため、一部の添付ファイルを転送することはできません。</string>
|
||||
<string name="message_compose_show_quoted_text_action">元のメッセージを引用する</string>
|
||||
<string name="message_compose_description_add_to">Toに宛先を追加します</string>
|
||||
<string name="message_compose_description_add_cc">CCに宛先を追加します</string>
|
||||
<string name="message_compose_description_add_bcc">BCCに宛先を追加します</string>
|
||||
<string name="message_compose_description_delete_quoted_text">引用文を削除します</string>
|
||||
<string name="message_compose_description_edit_quoted_text">引用文を編集します</string>
|
||||
|
||||
<string name="message_view_from_format">送信者: <xliff:g id="name">%s</xliff:g> <<xliff:g id="email">%s</xliff:g>></string>
|
||||
<string name="message_to_label">宛先:</string>
|
||||
@ -287,8 +293,11 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="message_view_status_attachment_not_saved">SDカードに添付ファイルを保存できません</string>
|
||||
<string name="message_view_show_pictures_instructions">\"画像表示\"ボタンを押下すると描画します</string>
|
||||
<string name="message_view_show_pictures_action">画像表示</string>
|
||||
<string name="message_view_fetching_attachment_toast">添付取込中</string>
|
||||
<string name="message_view_no_viewer">添付ファイルのビューワー見つけられません .<xliff:g id="mimetype">%s</xliff:g></string>
|
||||
<string name="message_view_show_message_action">メッセージ表示</string>
|
||||
<string name="message_view_show_attachments_action">添付ファイル表示</string>
|
||||
<string name="message_view_show_more_attachments_action">他…</string>
|
||||
<string name="message_view_fetching_attachment_toast">添付ファイル取得中</string>
|
||||
<string name="message_view_no_viewer"><xliff:g id="mimetype">%s</xliff:g>のビューワーが見つかりません</string>
|
||||
|
||||
<string name="message_view_download_remainder">すべてダウンロード</string>
|
||||
|
||||
@ -544,6 +553,8 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="account_settings_notification_opens_unread_summary">通知を開いた際に未読メールを検索する</string>
|
||||
<string name="account_settings_notification_unread_count_label">未読件数の表示</string>
|
||||
<string name="account_settings_notification_unread_count_summary">通知バーに未読メッセージの件数を表示する</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_label">開くと同時に既読にする</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_summary">メッセージを参照したときに既読にする</string>
|
||||
|
||||
<string name="account_settings_enable_move_buttons_label">メール整理ボタンを有効にする</string>
|
||||
<string name="account_settings_enable_move_buttons_summary">アーカイブ、移動、迷惑メールボタンを表示</string>
|
||||
@ -777,6 +788,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
|
||||
<string name="sort_by">並べ替え...</string>
|
||||
<string name="sort_by_date">日付</string>
|
||||
<string name="sort_by_arrival">受信順</string>
|
||||
<string name="sort_by_sender">送信者</string>
|
||||
<string name="sort_by_subject">件名</string>
|
||||
<string name="sort_by_flag">フラグ</string>
|
||||
@ -795,7 +807,9 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
|
||||
<string name="provider_note_live">このプログラムでPOPアクセスが許可されているのは一部の「Plus」アカウントだけです。有料の「Plus」アカウントがなければ、正しいメールアドレスとパスワードを入力してもログインできません。これらのアカウントにはブラウザからアクセスしてください。</string>
|
||||
|
||||
<string name="provider_note_yahoojp">Yahoo! JapanでPOP3アクセスを使う場合は、Yahoo!メールサイトの「メールの設定」にてPOPアクセスが許可されていることを確認してください。</string>
|
||||
<string name="provider_note_yahoojp">Yahoo! JapanでPOP3アクセスを行う場合は、Yahoo!メールサイトの「メールの設定」にてPOPアクセスが許可されていることを確認してください。</string>
|
||||
|
||||
<string name="provider_note_auonejp">au oneでIMAPアクセスを行う場合は、au oneポータルサイトの「メール」→「設定」ページにて「IMAPを有効にする」をチェックしてください。</string>
|
||||
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">証明書が無効です</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">許可</string>
|
||||
@ -1112,4 +1126,29 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="import_dialog_error_message">設定をインポートするためのアプリケーションがありません。Androidマーケットからファイルマネージャをインストールしてください。</string>
|
||||
<string name="open_market">マーケット</string>
|
||||
<string name="close">閉じる</string>
|
||||
|
||||
<string name="webview_contextmenu_link_view_action">開く</string>
|
||||
<string name="webview_contextmenu_link_share_action">リンクを共有</string>
|
||||
<string name="webview_contextmenu_link_copy_action">リンクをコピー</string>
|
||||
<string name="webview_contextmenu_link_clipboard_label">リンク</string>
|
||||
|
||||
<string name="webview_contextmenu_image_title">画像</string>
|
||||
<string name="webview_contextmenu_image_view_action">表示</string>
|
||||
<string name="webview_contextmenu_image_save_action">画像を保存</string>
|
||||
<string name="webview_contextmenu_image_download_action">画像をダウンロード</string>
|
||||
<string name="webview_contextmenu_image_copy_action">画像のURLをコピー</string>
|
||||
<string name="webview_contextmenu_image_clipboard_label">画像のURL</string>
|
||||
|
||||
<string name="webview_contextmenu_phone_call_action">発信</string>
|
||||
<string name="webview_contextmenu_phone_save_action">連絡先に保存</string>
|
||||
<string name="webview_contextmenu_phone_copy_action">電話番号をコピー</string>
|
||||
<string name="webview_contextmenu_phone_clipboard_label">電話番号</string>
|
||||
|
||||
<string name="webview_contextmenu_email_send_action">メール送信</string>
|
||||
<string name="webview_contextmenu_email_save_action">連絡先に保存</string>
|
||||
<string name="webview_contextmenu_email_copy_action">メールアドレスをコピー</string>
|
||||
<string name="webview_contextmenu_email_clipboard_label">メールアドレス</string>
|
||||
|
||||
<string name="image_saved_as">\"<xliff:g id="filename">%s</xliff:g>\"に保存しました</string>
|
||||
<string name="image_saving_failed">画像の保存に失敗しました</string>
|
||||
</resources>
|
||||
|
@ -2,5 +2,5 @@
|
||||
<resources>
|
||||
<color name="message_list_item_background">#ffffff</color>
|
||||
<color name="message_list_item_footer_background">#eeeeee</color>
|
||||
<color name="message_view_header_background">#1a080808</color>
|
||||
<color name="message_view_header_background">#45bcbcbc</color>
|
||||
</resources>
|
||||
|
@ -268,6 +268,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
<string name="message_compose_bcc_hint">Bcc</string>
|
||||
<string name="message_compose_subject_hint">Subject</string>
|
||||
<string name="message_compose_content_hint">Message text</string>
|
||||
<string name="message_compose_signature_hint">Signature</string>
|
||||
<string name="message_compose_quote_header_separator">-------- Original Message --------</string>
|
||||
<string name="message_compose_quote_header_subject">Subject:</string>
|
||||
<string name="message_compose_quote_header_send_date">Sent:</string>
|
||||
@ -281,6 +282,11 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
<string name="message_compose_downloading_attachments_toast">Some attachments were not downloaded. They will be downloaded automatically before this message is sent.</string>
|
||||
<string name="message_compose_attachments_skipped_toast">Some attachments cannot be forwarded because they have not been downloaded.</string>
|
||||
<string name="message_compose_show_quoted_text_action">Quote message</string>
|
||||
<string name="message_compose_description_add_to">Add recipient (To)</string>
|
||||
<string name="message_compose_description_add_cc">Add recipient (CC)</string>
|
||||
<string name="message_compose_description_add_bcc">Add recipient (BCC)</string>
|
||||
<string name="message_compose_description_delete_quoted_text">Remove quoted text</string>
|
||||
<string name="message_compose_description_edit_quoted_text">Edit quoted text</string>
|
||||
|
||||
<string name="message_view_from_format">From: <xliff:g id="name">%s</xliff:g> <<xliff:g id="email">%s</xliff:g>></string>
|
||||
<string name="message_to_label">To:</string>
|
||||
@ -561,6 +567,8 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
<string name="account_settings_notification_opens_unread_summary">Searches for unread messages when Notification is opened</string>
|
||||
<string name="account_settings_notification_unread_count_label">Show unread count</string>
|
||||
<string name="account_settings_notification_unread_count_summary">Show the number of unread messages in the notification bar.</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_label">Mark message as read when opening</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_summary">Mark a message as read when it is opened for viewing</string>
|
||||
|
||||
<string name="account_settings_enable_move_buttons_label">Enable refile buttons</string>
|
||||
<string name="account_settings_enable_move_buttons_summary">Show the Archive, Move, and Spam buttons.</string>
|
||||
@ -797,6 +805,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
|
||||
<string name="sort_by">Sort by...</string>
|
||||
<string name="sort_by_date">Date</string>
|
||||
<string name="sort_by_arrival">Arrival</string>
|
||||
<string name="sort_by_sender">Sender</string>
|
||||
<string name="sort_by_subject">Subject</string>
|
||||
<string name="sort_by_flag">Star</string>
|
||||
@ -819,6 +828,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
\"Plus\" account. Please launch the Web browser to gain access to
|
||||
these mail accounts.</string>
|
||||
<string name="provider_note_yahoojp">If you would like to use POP3 for this provider, You should permit to use POP3 on Yahoo mail settings page.</string>
|
||||
<string name="provider_note_auonejp">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on au one mail settings page.</string>
|
||||
<string name="provider_note_naver">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Naver mail settings page.</string>
|
||||
<string name="provider_note_hanmail">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Hanmail(Daum) mail settings page.</string>
|
||||
<string name="provider_note_paran">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Paran mail settings page.</string>
|
||||
@ -1150,4 +1160,29 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
the import operation. Please install a file manager application from Android Market</string>
|
||||
<string name="open_market">Open Market</string>
|
||||
<string name="close">Close</string>
|
||||
|
||||
<string name="webview_contextmenu_link_view_action">Open for viewing</string>
|
||||
<string name="webview_contextmenu_link_share_action">Share link</string>
|
||||
<string name="webview_contextmenu_link_copy_action">Copy link to clipboard</string>
|
||||
<string name="webview_contextmenu_link_clipboard_label">Link</string>
|
||||
|
||||
<string name="webview_contextmenu_image_title">Image</string>
|
||||
<string name="webview_contextmenu_image_view_action">View image</string>
|
||||
<string name="webview_contextmenu_image_save_action">Save image</string>
|
||||
<string name="webview_contextmenu_image_download_action">Download image</string>
|
||||
<string name="webview_contextmenu_image_copy_action">Copy image URL to clipboard</string>
|
||||
<string name="webview_contextmenu_image_clipboard_label">Image URL</string>
|
||||
|
||||
<string name="webview_contextmenu_phone_call_action">Call number</string>
|
||||
<string name="webview_contextmenu_phone_save_action">Save to Contacts</string>
|
||||
<string name="webview_contextmenu_phone_copy_action">Copy phone number to clipboard</string>
|
||||
<string name="webview_contextmenu_phone_clipboard_label">Phone number</string>
|
||||
|
||||
<string name="webview_contextmenu_email_send_action">Send mail</string>
|
||||
<string name="webview_contextmenu_email_save_action">Save to Contacts</string>
|
||||
<string name="webview_contextmenu_email_copy_action">Copy email address to clipboard</string>
|
||||
<string name="webview_contextmenu_email_clipboard_label">Email address</string>
|
||||
|
||||
<string name="image_saved_as">Saved image as \"<xliff:g id="filename">%s</xliff:g>\"</string>
|
||||
<string name="image_saving_failed">Saving the image failed.</string>
|
||||
</resources>
|
||||
|
@ -81,6 +81,17 @@
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
android:title="@string/interaction_preferences">
|
||||
|
||||
<CheckBoxPreference
|
||||
android:persistent="false"
|
||||
android:key="mark_message_as_read_on_view"
|
||||
android:title="@string/account_settings_mark_message_as_read_on_view_label"
|
||||
android:summary="@string/account_settings_mark_message_as_read_on_view_summary" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
android:title="@string/account_settings_sync"
|
||||
android:key="incoming_prefs">
|
||||
|
@ -283,6 +283,11 @@
|
||||
<incoming uri="pop3+ssl+://pop.mail.yahoo.co.jp" username="$user" />
|
||||
<outgoing uri="smtp://smtp.mail.yahoo.co.jp:587" username="$user" />
|
||||
</provider>
|
||||
<provider id="auone" label="au one" domain="auone.jp"
|
||||
note="@string/provider_note_auonejp">
|
||||
<incoming uri="imap+ssl+://imap.gmail.com" username="$email" />
|
||||
<outgoing uri="smtp+ssl+://smtp.gmail.com" username="$email" />
|
||||
</provider>
|
||||
|
||||
<!-- Korean -->
|
||||
<provider id="naver" label="Naver" domain="naver.com"
|
||||
|
@ -152,6 +152,7 @@ public class Account implements BaseAccount {
|
||||
private String mCryptoApp;
|
||||
private boolean mCryptoAutoSignature;
|
||||
private boolean mCryptoAutoEncrypt;
|
||||
private boolean mMarkMessageAsReadOnView;
|
||||
|
||||
private CryptoProvider mCryptoProvider = null;
|
||||
|
||||
@ -240,6 +241,7 @@ public class Account implements BaseAccount {
|
||||
mCryptoAutoSignature = false;
|
||||
mCryptoAutoEncrypt = false;
|
||||
mEnabled = true;
|
||||
mMarkMessageAsReadOnView = true;
|
||||
|
||||
searchableFolders = Searchable.ALL;
|
||||
|
||||
@ -396,6 +398,7 @@ public class Account implements BaseAccount {
|
||||
mCryptoAutoSignature = prefs.getBoolean(mUuid + ".cryptoAutoSignature", false);
|
||||
mCryptoAutoEncrypt = prefs.getBoolean(mUuid + ".cryptoAutoEncrypt", false);
|
||||
mEnabled = prefs.getBoolean(mUuid + ".enabled", true);
|
||||
mMarkMessageAsReadOnView = prefs.getBoolean(mUuid + ".markMessageAsReadOnView", true);
|
||||
}
|
||||
|
||||
protected synchronized void delete(Preferences preferences) {
|
||||
@ -478,6 +481,7 @@ public class Account implements BaseAccount {
|
||||
editor.remove(mUuid + ".enabled");
|
||||
editor.remove(mUuid + ".enableMoveButtons");
|
||||
editor.remove(mUuid + ".hideMoveButtonsEnum");
|
||||
editor.remove(mUuid + ".markMessageAsReadOnView");
|
||||
for (String type : networkTypes) {
|
||||
editor.remove(mUuid + ".useCompression." + type);
|
||||
}
|
||||
@ -639,6 +643,7 @@ public class Account implements BaseAccount {
|
||||
editor.putBoolean(mUuid + ".cryptoAutoSignature", mCryptoAutoSignature);
|
||||
editor.putBoolean(mUuid + ".cryptoAutoEncrypt", mCryptoAutoEncrypt);
|
||||
editor.putBoolean(mUuid + ".enabled", mEnabled);
|
||||
editor.putBoolean(mUuid + ".markMessageAsReadOnView", mMarkMessageAsReadOnView);
|
||||
|
||||
editor.putBoolean(mUuid + ".vibrate", mNotificationSetting.shouldVibrate());
|
||||
editor.putInt(mUuid + ".vibratePattern", mNotificationSetting.getVibratePattern());
|
||||
@ -1557,4 +1562,12 @@ Log.d("ASH", "setTrashFolderName() attempting change of folder.setLocalOnly()");
|
||||
public synchronized void setEnabled(boolean enabled) {
|
||||
mEnabled = enabled;
|
||||
}
|
||||
|
||||
public synchronized boolean isMarkMessageAsReadOnView() {
|
||||
return mMarkMessageAsReadOnView;
|
||||
}
|
||||
|
||||
public synchronized void setMarkMessageAsReadOnView(boolean value) {
|
||||
mMarkMessageAsReadOnView = value;
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,9 @@ import com.fsck.k9.service.ShutdownReceiver;
|
||||
import com.fsck.k9.service.StorageGoneReceiver;
|
||||
|
||||
public class K9 extends Application {
|
||||
public static final int THEME_LIGHT = 0;
|
||||
public static final int THEME_DARK = 1;
|
||||
|
||||
/**
|
||||
* Components that are interested in knowing when the K9 instance is
|
||||
* available and ready (Android invokes Application.onCreate() after other
|
||||
@ -72,7 +75,7 @@ public class K9 extends Application {
|
||||
}
|
||||
|
||||
private static String language = "";
|
||||
private static int theme = android.R.style.Theme_Light;
|
||||
private static int theme = THEME_LIGHT;
|
||||
|
||||
private static final FontSizes fontSizes = new FontSizes();
|
||||
|
||||
@ -606,7 +609,17 @@ public class K9 extends Application {
|
||||
}
|
||||
|
||||
K9.setK9Language(sprefs.getString("language", ""));
|
||||
K9.setK9Theme(sprefs.getInt("theme", android.R.style.Theme_Light));
|
||||
|
||||
int theme = sprefs.getInt("theme", THEME_LIGHT);
|
||||
|
||||
// We used to save the resource ID of the theme. So convert that to the new format if
|
||||
// necessary.
|
||||
if (theme == THEME_DARK || theme == android.R.style.Theme) {
|
||||
theme = THEME_DARK;
|
||||
} else {
|
||||
theme = THEME_LIGHT;
|
||||
}
|
||||
K9.setK9Theme(theme);
|
||||
}
|
||||
|
||||
private void maybeSetupStrictMode() {
|
||||
@ -665,6 +678,14 @@ public class K9 extends Application {
|
||||
language = nlanguage;
|
||||
}
|
||||
|
||||
public static int getK9ThemeResourceId(int theme) {
|
||||
return (theme == THEME_LIGHT) ? android.R.style.Theme_Light : android.R.style.Theme;
|
||||
}
|
||||
|
||||
public static int getK9ThemeResourceId() {
|
||||
return getK9ThemeResourceId(theme);
|
||||
}
|
||||
|
||||
public static int getK9Theme() {
|
||||
return theme;
|
||||
}
|
||||
|
@ -12,6 +12,39 @@ import com.fsck.k9.mail.Flag;
|
||||
* is defined by {@link com.fsck.k9.activity.SearchModifier}.
|
||||
*/
|
||||
public class SearchAccount implements BaseAccount, SearchSpecification, Serializable {
|
||||
/**
|
||||
* Create a {@code SearchAccount} instance for the Unified Inbox.
|
||||
*
|
||||
* @param context
|
||||
* A {@link Context} instance that will be used to get localized strings and will be
|
||||
* passed on to the {@code SearchAccount} instance.
|
||||
*
|
||||
* @return The {@link SearchAccount} instance for the Unified Inbox.
|
||||
*/
|
||||
public static SearchAccount createUnifiedInboxAccount(Context context) {
|
||||
SearchAccount unifiedInbox = new SearchAccount(context, true, null, null);
|
||||
unifiedInbox.setDescription(context.getString(R.string.integrated_inbox_title));
|
||||
unifiedInbox.setEmail(context.getString(R.string.integrated_inbox_detail));
|
||||
return unifiedInbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code SearchAccount} instance for the special account "All messages".
|
||||
*
|
||||
* @param context
|
||||
* A {@link Context} instance that will be used to get localized strings and will be
|
||||
* passed on to the {@code SearchAccount} instance.
|
||||
*
|
||||
* @return The {@link SearchAccount} instance for the Unified Inbox.
|
||||
*/
|
||||
public static SearchAccount createAllMessagesAccount(Context context) {
|
||||
SearchAccount allMessages = new SearchAccount(context, false, null, null);
|
||||
allMessages.setDescription(context.getString(R.string.search_all_messages_title));
|
||||
allMessages.setEmail(context.getString(R.string.search_all_messages_detail));
|
||||
return allMessages;
|
||||
}
|
||||
|
||||
|
||||
private static final long serialVersionUID = -4388420303235543976L;
|
||||
private Flag[] mRequiredFlags = null;
|
||||
private Flag[] mForbiddenFlags = null;
|
||||
|
@ -73,16 +73,11 @@ public abstract class AccountList extends K9ListActivity implements OnItemClickL
|
||||
List<BaseAccount> accounts = new ArrayList<BaseAccount>();
|
||||
|
||||
if (displaySpecialAccounts() && !K9.isHideSpecialAccounts()) {
|
||||
BaseAccount integratedInboxAccount = new SearchAccount(this, true, null, null);
|
||||
integratedInboxAccount.setDescription(getString(R.string.integrated_inbox_title));
|
||||
integratedInboxAccount.setEmail(getString(R.string.integrated_inbox_detail));
|
||||
BaseAccount unifiedInboxAccount = SearchAccount.createUnifiedInboxAccount(this);
|
||||
BaseAccount allMessagesAccount = SearchAccount.createAllMessagesAccount(this);
|
||||
|
||||
BaseAccount unreadAccount = new SearchAccount(this, false, null, null);
|
||||
unreadAccount.setDescription(getString(R.string.search_all_messages_title));
|
||||
unreadAccount.setEmail(getString(R.string.search_all_messages_detail));
|
||||
|
||||
accounts.add(integratedInboxAccount);
|
||||
accounts.add(unreadAccount);
|
||||
accounts.add(unifiedInboxAccount);
|
||||
accounts.add(allMessagesAccount);
|
||||
}
|
||||
|
||||
accounts.addAll(Arrays.asList(realAccounts));
|
||||
|
@ -23,6 +23,7 @@ import android.app.ProgressDialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnMultiChoiceClickListener;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -47,12 +48,10 @@ import android.webkit.WebView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CheckedTextView;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.ScrollView;
|
||||
@ -60,7 +59,6 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
@ -385,16 +383,11 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes the special accounts ('Integrated Inbox' and 'All Messages')
|
||||
* Creates and initializes the special accounts ('Unified Inbox' and 'All Messages')
|
||||
*/
|
||||
private void createSpecialAccounts() {
|
||||
unreadAccount = new SearchAccount(this, false, null, null);
|
||||
unreadAccount.setDescription(getString(R.string.search_all_messages_title));
|
||||
unreadAccount.setEmail(getString(R.string.search_all_messages_detail));
|
||||
|
||||
integratedInboxAccount = new SearchAccount(this, true, null, null);
|
||||
integratedInboxAccount.setDescription(getString(R.string.integrated_inbox_title));
|
||||
integratedInboxAccount.setEmail(getString(R.string.integrated_inbox_detail));
|
||||
integratedInboxAccount = SearchAccount.createUnifiedInboxAccount(this);
|
||||
unreadAccount = SearchAccount.createAllMessagesAccount(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -951,8 +944,14 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(int id) {
|
||||
// Android recreates our dialogs on configuration changes even when they have been
|
||||
// dismissed. Make sure we have all information necessary before creating a new dialog.
|
||||
switch (id) {
|
||||
case DIALOG_REMOVE_ACCOUNT:
|
||||
case DIALOG_REMOVE_ACCOUNT: {
|
||||
if (mSelectedContextAccount == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.account_delete_dlg_title,
|
||||
getString(R.string.account_delete_dlg_instructions_fmt,
|
||||
@ -967,19 +966,24 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
try {
|
||||
realAccount.getLocalStore().delete();
|
||||
} catch (Exception e) {
|
||||
// Ignore, this may lead to localStores on sd-cards that are
|
||||
// currently not inserted to be left
|
||||
// Ignore, this may lead to localStores on sd-cards that
|
||||
// are currently not inserted to be left
|
||||
}
|
||||
MessagingController.getInstance(getApplication())
|
||||
.notifyAccountCancel(Accounts.this, realAccount);
|
||||
Preferences.getPreferences(Accounts.this).deleteAccount(realAccount);
|
||||
Preferences.getPreferences(Accounts.this)
|
||||
.deleteAccount(realAccount);
|
||||
K9.setServicesEnabled(Accounts.this);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
case DIALOG_CLEAR_ACCOUNT: {
|
||||
if (mSelectedContextAccount == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
case DIALOG_CLEAR_ACCOUNT:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.account_clear_dlg_title,
|
||||
getString(R.string.account_clear_dlg_instructions_fmt,
|
||||
@ -991,13 +995,19 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account) mSelectedContextAccount;
|
||||
mHandler.workingAccount(realAccount, R.string.clearing_account);
|
||||
MessagingController.getInstance(getApplication()).clear(realAccount, null);
|
||||
mHandler.workingAccount(realAccount,
|
||||
R.string.clearing_account);
|
||||
MessagingController.getInstance(getApplication())
|
||||
.clear(realAccount, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
case DIALOG_RECREATE_ACCOUNT: {
|
||||
if (mSelectedContextAccount == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
case DIALOG_RECREATE_ACCOUNT:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.account_recreate_dlg_title,
|
||||
getString(R.string.account_recreate_dlg_instructions_fmt,
|
||||
@ -1009,12 +1019,15 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account) mSelectedContextAccount;
|
||||
mHandler.workingAccount(realAccount, R.string.recreating_account);
|
||||
MessagingController.getInstance(getApplication()).recreate(realAccount, null);
|
||||
mHandler.workingAccount(realAccount,
|
||||
R.string.recreating_account);
|
||||
MessagingController.getInstance(getApplication())
|
||||
.recreate(realAccount, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
case DIALOG_NO_FILE_MANAGER:
|
||||
}
|
||||
case DIALOG_NO_FILE_MANAGER: {
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.import_dialog_error_title,
|
||||
getString(R.string.import_dialog_error_message),
|
||||
@ -1029,29 +1042,30 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareDialog(int id, Dialog d) {
|
||||
|
||||
AlertDialog alert = (AlertDialog) d;
|
||||
switch (id) {
|
||||
case DIALOG_REMOVE_ACCOUNT:
|
||||
case DIALOG_REMOVE_ACCOUNT: {
|
||||
alert.setMessage(getString(R.string.account_delete_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()));
|
||||
break;
|
||||
case DIALOG_CLEAR_ACCOUNT:
|
||||
}
|
||||
case DIALOG_CLEAR_ACCOUNT: {
|
||||
alert.setMessage(getString(R.string.account_clear_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()));
|
||||
break;
|
||||
case DIALOG_RECREATE_ACCOUNT:
|
||||
}
|
||||
case DIALOG_RECREATE_ACCOUNT: {
|
||||
alert.setMessage(getString(R.string.account_recreate_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()));
|
||||
break;
|
||||
case DIALOG_NO_FILE_MANAGER:
|
||||
alert.setMessage(getString(R.string.import_dialog_error_message));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
super.onPrepareDialog(id, d);
|
||||
@ -1495,8 +1509,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
private static class ImportSelectionDialog implements NonConfigurationInstance {
|
||||
private ImportContents mImportContents;
|
||||
private Uri mUri;
|
||||
private Dialog mDialog;
|
||||
private ListView mImportSelectionView;
|
||||
private AlertDialog mDialog;
|
||||
private SparseBooleanArray mSelection;
|
||||
|
||||
|
||||
@ -1514,8 +1527,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
public boolean retain() {
|
||||
if (mDialog != null) {
|
||||
// Save the selection state of each list item
|
||||
mSelection = mImportSelectionView.getCheckedItemPositions();
|
||||
mImportSelectionView = null;
|
||||
mSelection = mDialog.getListView().getCheckedItemPositions();
|
||||
|
||||
mDialog.dismiss();
|
||||
mDialog = null;
|
||||
@ -1529,8 +1541,6 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
}
|
||||
|
||||
public void show(final Accounts activity, SparseBooleanArray selection) {
|
||||
final ListView importSelectionView = new ListView(activity);
|
||||
mImportSelectionView = importSelectionView;
|
||||
List<String> contents = new ArrayList<String>();
|
||||
|
||||
if (mImportContents.globalSettings) {
|
||||
@ -1541,23 +1551,15 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
contents.add(account.name);
|
||||
}
|
||||
|
||||
importSelectionView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||
importSelectionView.setAdapter(new ArrayAdapter<String>(activity,
|
||||
android.R.layout.simple_list_item_checked, contents));
|
||||
importSelectionView.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
|
||||
CheckedTextView ctv = (CheckedTextView)view;
|
||||
ctv.setChecked(!ctv.isChecked());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> arg0) { /* Do nothing */ }
|
||||
});
|
||||
|
||||
int count = contents.size();
|
||||
boolean[] checkedItems = new boolean[count];
|
||||
if (selection != null) {
|
||||
for (int i = 0, end = contents.size(); i < end; i++) {
|
||||
importSelectionView.setItemChecked(i, selection.get(i));
|
||||
for (int i = 0; i < count; i++) {
|
||||
checkedItems[i] = selection.get(i);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; i++) {
|
||||
checkedItems[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1565,23 +1567,29 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
//TODO: listview footer: "Select all" / "Select none" buttons?
|
||||
//TODO: listview footer: "Overwrite existing accounts?" checkbox
|
||||
|
||||
OnMultiChoiceClickListener listener = new OnMultiChoiceClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
|
||||
((AlertDialog) dialog).getListView().setItemChecked(which, isChecked);
|
||||
}
|
||||
};
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setMultiChoiceItems(contents.toArray(new String[0]), checkedItems, listener);
|
||||
builder.setTitle(activity.getString(R.string.settings_import_selection));
|
||||
builder.setView(importSelectionView);
|
||||
builder.setInverseBackgroundForced(true);
|
||||
builder.setPositiveButton(R.string.okay_action,
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
ListAdapter adapter = importSelectionView.getAdapter();
|
||||
int count = adapter.getCount();
|
||||
SparseBooleanArray pos = importSelectionView.getCheckedItemPositions();
|
||||
ListView listView = ((AlertDialog) dialog).getListView();
|
||||
SparseBooleanArray pos = listView.getCheckedItemPositions();
|
||||
|
||||
boolean includeGlobals = mImportContents.globalSettings ? pos.get(0) : false;
|
||||
List<String> accountUuids = new ArrayList<String>();
|
||||
int start = mImportContents.globalSettings ? 1 : 0;
|
||||
for (int i = start; i < count; i++) {
|
||||
for (int i = start, end = listView.getCount(); i < end; i++) {
|
||||
if (pos.get(i)) {
|
||||
accountUuids.add(mImportContents.accounts.get(i-start).uuid);
|
||||
}
|
||||
|
@ -1,243 +0,0 @@
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.ExpandableListAdapter;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.Identity;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Activity displaying list of accounts/identity for user choice
|
||||
*
|
||||
* @see K9ExpandableListActivity
|
||||
*/
|
||||
public class ChooseAccount extends K9ExpandableListActivity {
|
||||
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[0];
|
||||
|
||||
/**
|
||||
* {@link Intent} extended data name for storing {@link Account#getUuid()
|
||||
* account UUID}
|
||||
*/
|
||||
public static final String EXTRA_ACCOUNT = ChooseAccount.class.getName() + "_account";
|
||||
|
||||
/**
|
||||
* {@link Intent} extended data name for storing serialized {@link Identity}
|
||||
*/
|
||||
public static final String EXTRA_IDENTITY = ChooseAccount.class.getName() + "_identity";
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
setContentView(R.layout.choose_account);
|
||||
|
||||
final ExpandableListView expandableListView = getExpandableListView();
|
||||
expandableListView.setItemsCanFocus(false);
|
||||
|
||||
final IdentitiesAdapter adapter = createAdapter();
|
||||
setListAdapter(adapter);
|
||||
|
||||
expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
|
||||
@Override
|
||||
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
|
||||
int childPosition, long id) {
|
||||
final Identity identity = (Identity) adapter.getChild(groupPosition, childPosition);
|
||||
final Account account = (Account) adapter.getGroup(groupPosition);
|
||||
|
||||
if (!account.isAvailable(v.getContext())) {
|
||||
Log.i(K9.LOG_TAG, "Refusing selection of unavailable account");
|
||||
return true;
|
||||
}
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
||||
intent.putExtra(EXTRA_IDENTITY, identity);
|
||||
setResult(RESULT_OK, intent);
|
||||
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
final Bundle extras = getIntent().getExtras();
|
||||
final String uuid = extras.getString(EXTRA_ACCOUNT);
|
||||
if (uuid != null) {
|
||||
final Account[] accounts = adapter.getAccounts();
|
||||
final int length = accounts.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
final Account account = accounts[i];
|
||||
if (uuid.equals(account.getUuid())) {
|
||||
// setSelectedChild() doesn't seem to obey the
|
||||
// shouldExpandGroup parameter (2.1), manually expanding
|
||||
// group
|
||||
expandableListView.expandGroup(i);
|
||||
|
||||
final List<Identity> identities = account.getIdentities();
|
||||
final Identity identity = (Identity) extras.getSerializable(EXTRA_IDENTITY);
|
||||
if (identity == null) {
|
||||
expandableListView.setSelectedChild(i, 0, true);
|
||||
break;
|
||||
}
|
||||
for (int j = 0; j < identities.size(); j++) {
|
||||
final Identity loopIdentity = identities.get(j);
|
||||
if (identity.equals(loopIdentity)) {
|
||||
expandableListView.setSelectedChild(i, j, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IdentitiesAdapter createAdapter() {
|
||||
return new IdentitiesAdapter(this, getLayoutInflater());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically provides accounts/identities data for
|
||||
* {@link ExpandableListView#setAdapter(ExpandableListAdapter)}:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Groups represent {@link Account accounts}</li>
|
||||
* <li>Children represent {@link Identity identities} of the parent account</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static class IdentitiesAdapter extends BaseExpandableListAdapter {
|
||||
|
||||
private Context mContext;
|
||||
private LayoutInflater mLayoutInflater;
|
||||
private Account[] mAccounts;
|
||||
|
||||
public IdentitiesAdapter(final Context context, final LayoutInflater layoutInflater) {
|
||||
mContext = context;
|
||||
mLayoutInflater = layoutInflater;
|
||||
Preferences prefs = Preferences.getPreferences(mContext);
|
||||
mAccounts = prefs.getAvailableAccounts().toArray(EMPTY_ACCOUNT_ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getChild(int groupPosition, int childPosition) {
|
||||
return getAccounts()[groupPosition].getIdentity(childPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int groupPosition, int childPosition) {
|
||||
return Integer.valueOf(childPosition).longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount(int groupPosition) {
|
||||
return getAccounts()[groupPosition].getIdentities().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGroup(int groupPosition) {
|
||||
return getAccounts()[groupPosition];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
return getAccounts().length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGroupId(int groupPosition) {
|
||||
return Integer.valueOf(groupPosition).longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
|
||||
ViewGroup parent) {
|
||||
final View v;
|
||||
if (convertView == null) {
|
||||
v = mLayoutInflater.inflate(R.layout.choose_account_item, parent, false);
|
||||
} else {
|
||||
v = convertView;
|
||||
}
|
||||
|
||||
final TextView description = (TextView) v.findViewById(R.id.description);
|
||||
final Account account = getAccounts()[groupPosition];
|
||||
description.setText(account.getDescription());
|
||||
description.setTextSize(TypedValue.COMPLEX_UNIT_SP, K9.getFontSizes().getAccountName());
|
||||
|
||||
// display unavailable accounts translucent
|
||||
/*
|
||||
* 20101030/fiouzy: NullPointerException on null getBackground()
|
||||
*
|
||||
if (account.isAvailable(parent.getContext()))
|
||||
{
|
||||
description.getBackground().setAlpha(255);
|
||||
description.getBackground().setAlpha(255);
|
||||
}
|
||||
else
|
||||
{
|
||||
description.getBackground().setAlpha(127);
|
||||
description.getBackground().setAlpha(127);
|
||||
}
|
||||
*/
|
||||
|
||||
v.findViewById(R.id.chip).setBackgroundColor(account.getChipColor());
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
|
||||
View convertView, ViewGroup parent) {
|
||||
final Account account = getAccounts()[groupPosition];
|
||||
final Identity identity = account.getIdentity(childPosition);
|
||||
|
||||
final View v;
|
||||
if (convertView == null) {
|
||||
v = mLayoutInflater.inflate(R.layout.choose_identity_item, parent, false);
|
||||
} else {
|
||||
v = convertView;
|
||||
}
|
||||
|
||||
final TextView name = (TextView) v.findViewById(R.id.name);
|
||||
final TextView description = (TextView) v.findViewById(R.id.description);
|
||||
name.setTextSize(TypedValue.COMPLEX_UNIT_SP, K9.getFontSizes().getAccountName());
|
||||
description.setTextSize(TypedValue.COMPLEX_UNIT_SP, K9.getFontSizes().getAccountDescription());
|
||||
|
||||
name.setText(identity.getDescription());
|
||||
description.setText(String.format("%s <%s>", identity.getName(), identity.getEmail()));
|
||||
|
||||
v.findViewById(R.id.chip).setBackgroundColor(account.getChipColor());
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
// returning false since accounts/identities are mutable
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private Account[] getAccounts() {
|
||||
return mAccounts;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,13 @@
|
||||
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
@ -21,8 +28,13 @@ import android.widget.Filter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import com.fsck.k9.*;
|
||||
|
||||
//import com.fsck.k9.*;
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.Account.FolderMode;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.mail.Folder;
|
||||
@ -31,38 +43,8 @@ import com.fsck.k9.mail.Store;
|
||||
import com.fsck.k9.mail.store.ImapStore;
|
||||
import com.fsck.k9.mail.store.Pop3Store;
|
||||
import com.fsck.k9.mail.store.WebDavStore;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ChooseFolder extends K9ListActivity {
|
||||
String mFolder;
|
||||
String mSelectFolder;
|
||||
Account mAccount;
|
||||
MessageReference mMessageReference;
|
||||
ArrayAdapter<String> mAdapter;
|
||||
private ChooseFolderHandler mHandler = new ChooseFolderHandler();
|
||||
String heldInbox = null;
|
||||
boolean hideCurrentFolder = true;
|
||||
boolean showOptionNone = false;
|
||||
boolean showDisplayableOnly = false;
|
||||
|
||||
/**
|
||||
* What folders to display.<br/>
|
||||
* Initialized to whatever is configured
|
||||
* but can be overridden via {@link #onOptionsItemSelected(MenuItem)}
|
||||
* while this activity is showing.
|
||||
*/
|
||||
private Account.FolderMode mMode;
|
||||
/**
|
||||
* Current filter used by our ArrayAdapter.<br/>
|
||||
* Created on the fly and invalidated if a new
|
||||
* set of folders is chosen via {@link #onOptionsItemSelected(MenuItem)}
|
||||
*/
|
||||
private FolderListFilter<String> myFilter = null;
|
||||
|
||||
public static final String EXTRA_ACCOUNT = "com.fsck.k9.ChooseFolder_account";
|
||||
public static final String EXTRA_CUR_FOLDER = "com.fsck.k9.ChooseFolder_curfolder";
|
||||
public static final String EXTRA_SEL_FOLDER = "com.fsck.k9.ChooseFolder_selfolder";
|
||||
@ -72,6 +54,34 @@ public class ChooseFolder extends K9ListActivity {
|
||||
public static final String EXTRA_SHOW_FOLDER_NONE = "com.fsck.k9.ChooseFolder_showOptionNone";
|
||||
public static final String EXTRA_SHOW_DISPLAYABLE_ONLY = "com.fsck.k9.ChooseFolder_showDisplayableOnly";
|
||||
|
||||
|
||||
String mFolder;
|
||||
String mSelectFolder;
|
||||
Account mAccount;
|
||||
MessageReference mMessageReference;
|
||||
ArrayAdapter<String> mAdapter;
|
||||
private ChooseFolderHandler mHandler = new ChooseFolderHandler();
|
||||
String mHeldInbox = null;
|
||||
boolean mHideCurrentFolder = true;
|
||||
boolean mShowOptionNone = false;
|
||||
boolean mShowDisplayableOnly = false;
|
||||
|
||||
/**
|
||||
* What folders to display.<br/>
|
||||
* Initialized to whatever is configured
|
||||
* but can be overridden via {@link #onOptionsItemSelected(MenuItem)}
|
||||
* while this activity is showing.
|
||||
*/
|
||||
private Account.FolderMode mMode;
|
||||
|
||||
/**
|
||||
* Current filter used by our ArrayAdapter.<br/>
|
||||
* Created on the fly and invalidated if a new
|
||||
* set of folders is chosen via {@link #onOptionsItemSelected(MenuItem)}
|
||||
*/
|
||||
private FolderListFilter<String> mMyFilter = null;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -87,13 +97,13 @@ public class ChooseFolder extends K9ListActivity {
|
||||
mFolder = intent.getStringExtra(EXTRA_CUR_FOLDER);
|
||||
mSelectFolder = intent.getStringExtra(EXTRA_SEL_FOLDER);
|
||||
if (intent.getStringExtra(EXTRA_SHOW_CURRENT) != null) {
|
||||
hideCurrentFolder = false;
|
||||
mHideCurrentFolder = false;
|
||||
}
|
||||
if (intent.getStringExtra(EXTRA_SHOW_FOLDER_NONE) != null) {
|
||||
showOptionNone = true;
|
||||
mShowOptionNone = true;
|
||||
}
|
||||
if (intent.getStringExtra(EXTRA_SHOW_DISPLAYABLE_ONLY) != null) {
|
||||
showDisplayableOnly = true;
|
||||
mShowDisplayableOnly = true;
|
||||
}
|
||||
if (mFolder == null)
|
||||
mFolder = "";
|
||||
@ -112,57 +122,44 @@ public class ChooseFolder extends K9ListActivity {
|
||||
|
||||
setListAdapter(mAdapter);
|
||||
|
||||
|
||||
mMode = mAccount.getFolderTargetMode();
|
||||
onRefresh(false);
|
||||
|
||||
|
||||
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_ACCOUNT, mAccount.getUuid());
|
||||
intent.putExtra(EXTRA_CUR_FOLDER, mFolder);
|
||||
Intent result = new Intent();
|
||||
result.putExtra(EXTRA_ACCOUNT, mAccount.getUuid());
|
||||
result.putExtra(EXTRA_CUR_FOLDER, mFolder);
|
||||
String destFolderName = (String)((TextView)view).getText();
|
||||
if (heldInbox != null && getString(R.string.special_mailbox_name_inbox).equals(destFolderName)) {
|
||||
destFolderName = heldInbox;
|
||||
if (mHeldInbox != null && getString(R.string.special_mailbox_name_inbox).equals(destFolderName)) {
|
||||
destFolderName = mHeldInbox;
|
||||
}
|
||||
intent.putExtra(EXTRA_NEW_FOLDER, destFolderName);
|
||||
intent.putExtra(EXTRA_MESSAGE, mMessageReference);
|
||||
setResult(RESULT_OK, intent);
|
||||
result.putExtra(EXTRA_NEW_FOLDER, destFolderName);
|
||||
result.putExtra(EXTRA_MESSAGE, mMessageReference);
|
||||
setResult(RESULT_OK, result);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
class ChooseFolderHandler extends Handler {
|
||||
|
||||
private static final int MSG_PROGRESS = 2;
|
||||
|
||||
private static final int MSG_DATA_CHANGED = 3;
|
||||
private static final int MSG_SET_SELECTED_FOLDER = 4;
|
||||
private static final int MSG_PROGRESS = 1;
|
||||
private static final int MSG_SET_SELECTED_FOLDER = 2;
|
||||
|
||||
@Override
|
||||
public void handleMessage(android.os.Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_PROGRESS:
|
||||
case MSG_PROGRESS: {
|
||||
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
|
||||
break;
|
||||
case MSG_DATA_CHANGED:
|
||||
mAdapter.notifyDataSetChanged();
|
||||
|
||||
/*
|
||||
* Only enable the text filter after the list has been
|
||||
* populated to avoid possible race conditions because our
|
||||
* FolderListFilter isn't really thread-safe.
|
||||
*/
|
||||
getListView().setTextFilterEnabled(true);
|
||||
break;
|
||||
case MSG_SET_SELECTED_FOLDER:
|
||||
}
|
||||
case MSG_SET_SELECTED_FOLDER: {
|
||||
getListView().setSelection(msg.arg1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void progress(boolean progress) {
|
||||
android.os.Message msg = new android.os.Message();
|
||||
@ -177,13 +174,10 @@ public class ChooseFolder extends K9ListActivity {
|
||||
msg.arg1 = position;
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
public void dataChanged() {
|
||||
sendEmptyMessage(MSG_DATA_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean onCreateOptionsMenu(Menu menu) {
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.folder_select_option, menu);
|
||||
if (mAccount.getStoreUri().startsWith("webdav")) {
|
||||
@ -192,10 +186,9 @@ public class ChooseFolder extends K9ListActivity {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean onOptionsItemSelected(MenuItem item) {
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
|
||||
|
||||
case R.id.display_1st_class: {
|
||||
setDisplayMode(FolderMode.FIRST_CLASS);
|
||||
return true;
|
||||
@ -212,7 +205,6 @@ public class ChooseFolder extends K9ListActivity {
|
||||
setDisplayMode(FolderMode.ALL);
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.list_folders: {
|
||||
onRefresh();
|
||||
return true;
|
||||
@ -225,22 +217,18 @@ public class ChooseFolder extends K9ListActivity {
|
||||
onCreateFolder();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
default: {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void onRefresh() {
|
||||
|
||||
onRefresh(true);
|
||||
|
||||
}
|
||||
|
||||
private void onRefresh(final boolean forceRemote) {
|
||||
|
||||
MessagingController.getInstance(getApplication()).listFolders(mAccount, forceRemote, mListener);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -252,40 +240,39 @@ public class ChooseFolder extends K9ListActivity {
|
||||
|
||||
final EditText input = new EditText(this);
|
||||
input.addTextChangedListener(new TextWatcher() {
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
mAdapter.getFilter().filter(input.getText().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count,
|
||||
int after) {
|
||||
}
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
/* not used */ }
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
public void afterTextChanged(Editable s) { /* not used */ }
|
||||
});
|
||||
input.setHint(R.string.folder_list_filter_hint);
|
||||
filterAlert.setView(input);
|
||||
|
||||
filterAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
|
||||
String okay = getString(R.string.okay_action);
|
||||
filterAlert.setPositiveButton(okay, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
String value = input.getText().toString().trim();
|
||||
mAdapter.getFilter().filter(value);
|
||||
}
|
||||
});
|
||||
|
||||
filterAlert.setNegativeButton("Cancel",
|
||||
new DialogInterface.OnClickListener() {
|
||||
String cancel = getString(R.string.cancel_action);
|
||||
filterAlert.setNegativeButton(cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
mAdapter.getFilter().filter("");
|
||||
}
|
||||
});
|
||||
|
||||
filterAlert.show();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -350,8 +337,8 @@ public class ChooseFolder extends K9ListActivity {
|
||||
private void setDisplayMode(FolderMode aMode) {
|
||||
mMode = aMode;
|
||||
// invalidate the current filter as it is working on an inval
|
||||
if (myFilter != null) {
|
||||
myFilter.invalidate();
|
||||
if (mMyFilter != null) {
|
||||
mMyFilter.invalidate();
|
||||
}
|
||||
//re-populate the list
|
||||
onRefresh(false);
|
||||
@ -394,34 +381,39 @@ public class ChooseFolder extends K9ListActivity {
|
||||
String name = folder.getName();
|
||||
|
||||
// Inbox needs to be compared case-insensitively
|
||||
if (hideCurrentFolder && (name.equals(mFolder) ||
|
||||
(mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) && mAccount.getInboxFolderName().equalsIgnoreCase(name)))) {
|
||||
if (mHideCurrentFolder && (name.equals(mFolder) || (
|
||||
mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) &&
|
||||
mAccount.getInboxFolderName().equalsIgnoreCase(name)))) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
folder.refresh(prefs);
|
||||
Folder.FolderClass fMode = folder.getDisplayClass();
|
||||
|
||||
if ((aMode == Account.FolderMode.FIRST_CLASS && fMode != Folder.FolderClass.FIRST_CLASS)
|
||||
|| (aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS &&
|
||||
if ((aMode == Account.FolderMode.FIRST_CLASS &&
|
||||
fMode != Folder.FolderClass.FIRST_CLASS) || (
|
||||
aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS &&
|
||||
fMode != Folder.FolderClass.FIRST_CLASS &&
|
||||
fMode != Folder.FolderClass.SECOND_CLASS)
|
||||
|| (aMode == Account.FolderMode.NOT_SECOND_CLASS && fMode == Folder.FolderClass.SECOND_CLASS)) {
|
||||
fMode != Folder.FolderClass.SECOND_CLASS) || (
|
||||
aMode == Account.FolderMode.NOT_SECOND_CLASS &&
|
||||
fMode == Folder.FolderClass.SECOND_CLASS)) {
|
||||
continue;
|
||||
}
|
||||
} catch (MessagingException me) {
|
||||
Log.e(K9.LOG_TAG, "Couldn't get prefs to check for displayability of folder " + folder.getName(), me);
|
||||
Log.e(K9.LOG_TAG, "Couldn't get prefs to check for displayability of folder " +
|
||||
folder.getName(), me);
|
||||
}
|
||||
|
||||
localFolders.add(folder.getName());
|
||||
|
||||
}
|
||||
|
||||
if (showOptionNone) {
|
||||
if (mShowOptionNone) {
|
||||
localFolders.add(K9.FOLDER_NONE);
|
||||
}
|
||||
|
||||
Collections.sort(localFolders, new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String aName, String bName) {
|
||||
if (K9.FOLDER_NONE.equalsIgnoreCase(aName)) {
|
||||
return -1;
|
||||
@ -439,17 +431,22 @@ public class ChooseFolder extends K9ListActivity {
|
||||
return aName.compareToIgnoreCase(bName);
|
||||
}
|
||||
});
|
||||
mAdapter.setNotifyOnChange(false);
|
||||
int selectedFolder = -1;
|
||||
|
||||
/*
|
||||
* We're not allowed to change the adapter from a background thread, so we collect the
|
||||
* folder names and update the adapter in the UI thread (see finally block).
|
||||
*/
|
||||
final List<String> folderList = new ArrayList<String>();
|
||||
try {
|
||||
mAdapter.clear();
|
||||
int position = 0;
|
||||
for (String name : localFolders) {
|
||||
if (mAccount.getInboxFolderName().equalsIgnoreCase(name)) {
|
||||
mAdapter.add(getString(R.string.special_mailbox_name_inbox));
|
||||
heldInbox = name;
|
||||
} else if (!K9.ERROR_FOLDER_NAME.equals(name) && !account.getOutboxFolderName().equals(name)) {
|
||||
mAdapter.add(name);
|
||||
folderList.add(getString(R.string.special_mailbox_name_inbox));
|
||||
mHeldInbox = name;
|
||||
} else if (!K9.ERROR_FOLDER_NAME.equals(name) &&
|
||||
!account.getOutboxFolderName().equals(name)) {
|
||||
folderList.add(name);
|
||||
}
|
||||
|
||||
if (mSelectFolder != null) {
|
||||
@ -461,24 +458,35 @@ public class ChooseFolder extends K9ListActivity {
|
||||
if (name.equals(mSelectFolder)) {
|
||||
selectedFolder = position;
|
||||
}
|
||||
} else if (name.equals(mFolder) ||
|
||||
(mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) && mAccount.getInboxFolderName().equalsIgnoreCase(name))) {
|
||||
} else if (name.equals(mFolder) || (
|
||||
mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) &&
|
||||
mAccount.getInboxFolderName().equalsIgnoreCase(name))) {
|
||||
selectedFolder = position;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
} finally {
|
||||
mAdapter.setNotifyOnChange(true);
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// runOnUiThread(
|
||||
// Now we're in the UI-thread, we can safely change the contents of the adapter.
|
||||
mAdapter.clear();
|
||||
for (String folderName: folderList) {
|
||||
mAdapter.add(folderName);
|
||||
}
|
||||
|
||||
mAdapter.notifyDataSetChanged();
|
||||
|
||||
/*
|
||||
* Only enable the text filter after the list has been
|
||||
* populated to avoid possible race conditions because our
|
||||
* FolderListFilter isn't really thread-safe.
|
||||
*/
|
||||
getListView().setTextFilterEnabled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mHandler.dataChanged();
|
||||
|
||||
if (selectedFolder != -1) {
|
||||
mHandler.setSelectedFolder(selectedFolder);
|
||||
}
|
||||
|
@ -32,12 +32,21 @@ class InsertableHtmlContent implements Serializable {
|
||||
}
|
||||
|
||||
public void setHeaderInsertionPoint(int headerInsertionPoint) {
|
||||
if (headerInsertionPoint < 0 || headerInsertionPoint > quotedContent.length()) {
|
||||
this.headerInsertionPoint = 0;
|
||||
} else {
|
||||
this.headerInsertionPoint = headerInsertionPoint;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFooterInsertionPoint(int footerInsertionPoint) {
|
||||
int len = quotedContent.length();
|
||||
if (footerInsertionPoint < 0 || footerInsertionPoint > len) {
|
||||
this.footerInsertionPoint = len;
|
||||
} else {
|
||||
this.footerInsertionPoint = footerInsertionPoint;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the quoted content.
|
||||
|
@ -23,14 +23,8 @@ public class K9Activity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
onCreate(icicle, true);
|
||||
}
|
||||
|
||||
public void onCreate(Bundle icicle, boolean useTheme) {
|
||||
setLanguage(this, K9.getK9Language());
|
||||
if (useTheme) {
|
||||
setTheme(K9.getK9Theme());
|
||||
}
|
||||
setTheme(K9.getK9ThemeResourceId());
|
||||
super.onCreate(icicle);
|
||||
setupFormats();
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
import android.app.ExpandableListActivity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
|
||||
/**
|
||||
* @see ExpandableListActivity
|
||||
*/
|
||||
public class K9ExpandableListActivity extends ExpandableListActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(K9.getK9Theme());
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ public class K9ListActivity extends ListActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
K9Activity.setLanguage(this, K9.getK9Language());
|
||||
setTheme(K9.getK9Theme());
|
||||
setTheme(K9.getK9ThemeResourceId());
|
||||
super.onCreate(icicle);
|
||||
setupFormats();
|
||||
}
|
||||
|
@ -15,15 +15,18 @@ import com.fsck.k9.mail.*;
|
||||
import com.fsck.k9.view.MessageWebView;
|
||||
import org.apache.james.mime4j.codec.EncoderUtil;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Parcelable;
|
||||
@ -31,14 +34,17 @@ import android.provider.OpenableColumns;
|
||||
import android.text.util.Rfc822Tokenizer;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnFocusChangeListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.AutoCompleteTextView.Validator;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
@ -84,6 +90,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
private static final int DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED = 2;
|
||||
private static final int DIALOG_CONTINUE_WITHOUT_PUBLIC_KEY = 3;
|
||||
private static final int DIALOG_CONFIRM_DISCARD_ON_BACK = 4;
|
||||
private static final int DIALOG_CHOOSE_IDENTITY = 5;
|
||||
|
||||
private static final long INVALID_DRAFT_ID = MessagingController.INVALID_MESSAGE_ID;
|
||||
|
||||
@ -128,12 +135,11 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
private static final int MSG_DISCARDED_DRAFT = 6;
|
||||
|
||||
private static final int ACTIVITY_REQUEST_PICK_ATTACHMENT = 1;
|
||||
private static final int ACTIVITY_CHOOSE_IDENTITY = 2;
|
||||
private static final int ACTIVITY_CHOOSE_ACCOUNT = 3;
|
||||
private static final int CONTACT_PICKER_TO = 4;
|
||||
private static final int CONTACT_PICKER_CC = 5;
|
||||
private static final int CONTACT_PICKER_BCC = 6;
|
||||
private static final int CONTACT_PICKER_TO = 2;
|
||||
private static final int CONTACT_PICKER_CC = 3;
|
||||
private static final int CONTACT_PICKER_BCC = 4;
|
||||
|
||||
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[0];
|
||||
|
||||
/**
|
||||
* Regular expression to remove the first localized "Re:" prefix in subjects.
|
||||
@ -186,7 +192,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
|
||||
private QuotedTextMode mQuotedTextMode = QuotedTextMode.NONE;
|
||||
|
||||
private TextView mFromView;
|
||||
private Button mChooseIdentityButton;
|
||||
private LinearLayout mCcWrapper;
|
||||
private LinearLayout mBccWrapper;
|
||||
private MultiAutoCompleteTextView mToView;
|
||||
@ -410,7 +416,14 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
mAddressAdapter = EmailAddressAdapter.getInstance(this);
|
||||
mAddressValidator = new EmailAddressValidator();
|
||||
|
||||
mFromView = (TextView) findViewById(R.id.from);
|
||||
mChooseIdentityButton = (Button) findViewById(R.id.identity);
|
||||
mChooseIdentityButton.setOnClickListener(this);
|
||||
|
||||
if (mAccount.getIdentities().size() == 1 &&
|
||||
Preferences.getPreferences(this).getAvailableAccounts().size() == 1) {
|
||||
mChooseIdentityButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
mToView = (MultiAutoCompleteTextView) findViewById(R.id.to);
|
||||
mCcView = (MultiAutoCompleteTextView) findViewById(R.id.cc);
|
||||
mBccView = (MultiAutoCompleteTextView) findViewById(R.id.bcc);
|
||||
@ -548,8 +561,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
mQuotedTextEdit.setOnClickListener(this);
|
||||
mQuotedTextDelete.setOnClickListener(this);
|
||||
|
||||
mFromView.setVisibility(View.GONE);
|
||||
|
||||
mToView.setAdapter(mAddressAdapter);
|
||||
mToView.setTokenizer(new Rfc822Tokenizer());
|
||||
mToView.setValidator(mAddressValidator);
|
||||
@ -607,8 +618,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
mReadReceipt = mAccount.isMessageReadReceiptAlways();
|
||||
mQuoteStyle = mAccount.getQuoteStyle();
|
||||
|
||||
if (!mSourceMessageProcessed) {
|
||||
updateFrom();
|
||||
|
||||
if (!mSourceMessageProcessed) {
|
||||
updateSignature();
|
||||
|
||||
if (ACTION_REPLY.equals(action) ||
|
||||
@ -941,7 +953,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
if (mQuotedTextMode != QuotedTextMode.NONE && mMessageFormat == MessageFormat.HTML) {
|
||||
mQuotedHtmlContent = (InsertableHtmlContent) savedInstanceState.getSerializable(STATE_KEY_HTML_QUOTE);
|
||||
if (mQuotedHtmlContent != null && mQuotedHtmlContent.getQuotedContent() != null) {
|
||||
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
|
||||
mQuotedHTML.setText(mQuotedHtmlContent.getQuotedContent(), "text/html");
|
||||
}
|
||||
}
|
||||
mDraftId = savedInstanceState.getLong(STATE_KEY_DRAFT_ID);
|
||||
@ -1776,12 +1788,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
addAttachment(data.getData());
|
||||
mDraftNeedsSaving = true;
|
||||
break;
|
||||
case ACTIVITY_CHOOSE_IDENTITY:
|
||||
onIdentityChosen(data);
|
||||
break;
|
||||
case ACTIVITY_CHOOSE_ACCOUNT:
|
||||
onAccountChosen(data);
|
||||
break;
|
||||
case CONTACT_PICKER_TO:
|
||||
case CONTACT_PICKER_CC:
|
||||
case CONTACT_PICKER_BCC:
|
||||
@ -1811,15 +1817,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
startActivityForResult(mContacts.contactPickerIntent(), resultId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void onAccountChosen(final Intent intent) {
|
||||
final Bundle extras = intent.getExtras();
|
||||
final String uuid = extras.getString(ChooseAccount.EXTRA_ACCOUNT);
|
||||
final Identity identity = (Identity) extras.getSerializable(ChooseAccount.EXTRA_IDENTITY);
|
||||
|
||||
final Account account = Preferences.getPreferences(this).getAccount(uuid);
|
||||
|
||||
private void onAccountChosen(Account account, Identity identity) {
|
||||
if (!mAccount.equals(account)) {
|
||||
if (K9.DEBUG) {
|
||||
Log.v(K9.LOG_TAG, "Switching account from " + mAccount + " to " + account);
|
||||
@ -1863,11 +1861,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
switchToIdentity(identity);
|
||||
}
|
||||
|
||||
private void onIdentityChosen(Intent intent) {
|
||||
Bundle bundle = intent.getExtras();
|
||||
switchToIdentity((Identity) bundle.getSerializable(ChooseIdentity.EXTRA_IDENTITY));
|
||||
}
|
||||
|
||||
private void switchToIdentity(Identity identity) {
|
||||
mIdentity = identity;
|
||||
mIdentityChanged = true;
|
||||
@ -1877,10 +1870,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
|
||||
private void updateFrom() {
|
||||
if (mIdentityChanged) {
|
||||
mFromView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
mFromView.setText(getString(R.string.message_view_from_format, mIdentity.getName(), mIdentity.getEmail()));
|
||||
mChooseIdentityButton.setText(mIdentity.getEmail());
|
||||
}
|
||||
|
||||
private void updateSignature() {
|
||||
@ -1923,6 +1913,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
MessagingController.getInstance(getApplication()).loadMessageForView(account, folderName, sourceMessageUid, null);
|
||||
}
|
||||
break;
|
||||
case R.id.identity:
|
||||
showDialog(DIALOG_CHOOSE_IDENTITY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1989,9 +1982,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
case R.id.add_attachment_video:
|
||||
onAddAttachment2("video/*");
|
||||
break;
|
||||
case R.id.choose_identity:
|
||||
onChooseIdentity();
|
||||
break;
|
||||
case R.id.read_receipt:
|
||||
onReadReceipt();
|
||||
default:
|
||||
@ -2000,25 +1990,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
return true;
|
||||
}
|
||||
|
||||
private void onChooseIdentity() {
|
||||
// keep things simple: trigger account choice only if there are more
|
||||
// than 1 account
|
||||
mIgnoreOnPause = true;
|
||||
if (Preferences.getPreferences(this).getAvailableAccounts().size() > 1) {
|
||||
final Intent intent = new Intent(this, ChooseAccount.class);
|
||||
intent.putExtra(ChooseAccount.EXTRA_ACCOUNT, mAccount.getUuid());
|
||||
intent.putExtra(ChooseAccount.EXTRA_IDENTITY, mIdentity);
|
||||
startActivityForResult(intent, ACTIVITY_CHOOSE_ACCOUNT);
|
||||
} else if (mAccount.getIdentities().size() > 1) {
|
||||
Intent intent = new Intent(this, ChooseIdentity.class);
|
||||
intent.putExtra(ChooseIdentity.EXTRA_ACCOUNT, mAccount.getUuid());
|
||||
startActivityForResult(intent, ACTIVITY_CHOOSE_IDENTITY);
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.no_identities),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
@ -2148,6 +2119,21 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
})
|
||||
.create();
|
||||
case DIALOG_CHOOSE_IDENTITY:
|
||||
Context context = new ContextWrapper(this);
|
||||
context.setTheme(K9.getK9ThemeResourceId(K9.THEME_LIGHT));
|
||||
Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.send_as);
|
||||
final IdentityAdapter adapter = new IdentityAdapter(context, getLayoutInflater());
|
||||
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
IdentityContainer container = (IdentityContainer) adapter.getItem(which);
|
||||
onAccountChosen(container.account, container.identity);
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
@ -2289,10 +2275,17 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
|
||||
if (ACTION_REPLY_ALL.equals(action)) {
|
||||
for (Address address : message.getRecipients(RecipientType.TO)) {
|
||||
if (message.getReplyTo().length > 0) {
|
||||
for (Address address : message.getFrom()) {
|
||||
if (!mAccount.isAnIdentity(address)) {
|
||||
addAddress(mToView, address);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Address address : message.getRecipients(RecipientType.TO)) {
|
||||
if (!mAccount.isAnIdentity(address) && !Utility.arrayContains(replyToAddresses, address)) {
|
||||
addAddress(mToView, address);
|
||||
}
|
||||
|
||||
}
|
||||
if (message.getRecipients(RecipientType.CC).length > 0) {
|
||||
@ -2395,7 +2388,15 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
if (k9identity.containsKey(IdentityField.ORIGINAL_MESSAGE)) {
|
||||
mMessageReference = null;
|
||||
try {
|
||||
mMessageReference = new MessageReference(k9identity.get(IdentityField.ORIGINAL_MESSAGE));
|
||||
String originalMessage = k9identity.get(IdentityField.ORIGINAL_MESSAGE);
|
||||
MessageReference messageReference = new MessageReference(originalMessage);
|
||||
|
||||
// Check if this is a valid account in our database
|
||||
Preferences prefs = Preferences.getPreferences(getApplicationContext());
|
||||
Account account = prefs.getAccount(messageReference.accountUuid);
|
||||
if (account != null) {
|
||||
mMessageReference = messageReference;
|
||||
}
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "Could not decode message reference in identity.", e);
|
||||
}
|
||||
@ -2420,19 +2421,19 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
updateFrom();
|
||||
|
||||
Integer bodyLength = k9identity.get(IdentityField.LENGTH) != null
|
||||
? Integer.parseInt(k9identity.get(IdentityField.LENGTH))
|
||||
? Integer.valueOf(k9identity.get(IdentityField.LENGTH))
|
||||
: 0;
|
||||
Integer bodyOffset = k9identity.get(IdentityField.OFFSET) != null
|
||||
? Integer.parseInt(k9identity.get(IdentityField.OFFSET))
|
||||
? Integer.valueOf(k9identity.get(IdentityField.OFFSET))
|
||||
: 0;
|
||||
Integer bodyFooterOffset = k9identity.get(IdentityField.FOOTER_OFFSET) != null
|
||||
? Integer.parseInt(k9identity.get(IdentityField.FOOTER_OFFSET))
|
||||
? Integer.valueOf(k9identity.get(IdentityField.FOOTER_OFFSET))
|
||||
: null;
|
||||
Integer bodyPlainLength = k9identity.get(IdentityField.PLAIN_LENGTH) != null
|
||||
? Integer.parseInt(k9identity.get(IdentityField.PLAIN_LENGTH))
|
||||
? Integer.valueOf(k9identity.get(IdentityField.PLAIN_LENGTH))
|
||||
: null;
|
||||
Integer bodyPlainOffset = k9identity.get(IdentityField.PLAIN_OFFSET) != null
|
||||
? Integer.parseInt(k9identity.get(IdentityField.PLAIN_OFFSET))
|
||||
? Integer.valueOf(k9identity.get(IdentityField.PLAIN_OFFSET))
|
||||
: null;
|
||||
mQuoteStyle = k9identity.get(IdentityField.QUOTE_STYLE) != null
|
||||
? QuoteStyle.valueOf(k9identity.get(IdentityField.QUOTE_STYLE))
|
||||
@ -2482,7 +2483,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
} else {
|
||||
mQuotedHtmlContent.setFooterInsertionPoint(bodyOffset);
|
||||
}
|
||||
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
|
||||
mQuotedHTML.setText(mQuotedHtmlContent.getQuotedContent(), "text/html");
|
||||
}
|
||||
}
|
||||
if (bodyPlainOffset != null && bodyPlainLength != null) {
|
||||
@ -2665,7 +2666,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
// Add the HTML reply header to the top of the content.
|
||||
mQuotedHtmlContent = quoteOriginalHtmlMessage(mSourceMessage, content, mQuoteStyle);
|
||||
// Load the message with the reply header.
|
||||
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
|
||||
mQuotedHTML.setText(mQuotedHtmlContent.getQuotedContent(), "text/html");
|
||||
mQuotedText.setText(quoteOriginalTextMessage(mSourceMessage,
|
||||
getBodyTextFromMessage(mSourceMessage, MessageFormat.TEXT), mQuoteStyle));
|
||||
|
||||
@ -3177,4 +3178,139 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
|
||||
return insertable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to store an {@link Identity} instance together with the {@link Account} it belongs to.
|
||||
*
|
||||
* @see IdentityAdapter
|
||||
*/
|
||||
static class IdentityContainer {
|
||||
public final Identity identity;
|
||||
public final Account account;
|
||||
|
||||
IdentityContainer(Identity identity, Account account) {
|
||||
this.identity = identity;
|
||||
this.account = account;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter for the <em>Choose identity</em> list view.
|
||||
*
|
||||
* <p>
|
||||
* Account names are displayed as section headers, identities as selectable list items.
|
||||
* </p>
|
||||
*/
|
||||
static class IdentityAdapter extends BaseAdapter {
|
||||
private LayoutInflater mLayoutInflater;
|
||||
private List<Object> mItems;
|
||||
private FontSizes mFontSizes;
|
||||
|
||||
public IdentityAdapter(Context context, LayoutInflater layoutInflater) {
|
||||
mLayoutInflater = layoutInflater;
|
||||
mFontSizes = K9.getFontSizes();
|
||||
|
||||
List<Object> items = new ArrayList<Object>();
|
||||
Preferences prefs = Preferences.getPreferences(context.getApplicationContext());
|
||||
Account[] accounts = prefs.getAvailableAccounts().toArray(EMPTY_ACCOUNT_ARRAY);
|
||||
for (Account account : accounts) {
|
||||
items.add(account);
|
||||
List<Identity> identities = account.getIdentities();
|
||||
for (Identity identity : identities) {
|
||||
items.add(new IdentityContainer(identity, account));
|
||||
}
|
||||
}
|
||||
mItems = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return (mItems.get(position) instanceof Account) ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
return (mItems.get(position) instanceof IdentityContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mItems.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
Object item = mItems.get(position);
|
||||
|
||||
View view = null;
|
||||
if (item instanceof Account) {
|
||||
if (convertView != null && convertView.getTag() instanceof AccountHolder) {
|
||||
view = convertView;
|
||||
} else {
|
||||
view = mLayoutInflater.inflate(R.layout.choose_account_item, parent, false);
|
||||
AccountHolder holder = new AccountHolder();
|
||||
holder.name = (TextView) view.findViewById(R.id.name);
|
||||
holder.chip = view.findViewById(R.id.chip);
|
||||
view.setTag(holder);
|
||||
}
|
||||
|
||||
Account account = (Account) item;
|
||||
AccountHolder holder = (AccountHolder) view.getTag();
|
||||
holder.name.setText(account.getDescription());
|
||||
holder.chip.setBackgroundColor(account.getChipColor());
|
||||
} else if (item instanceof IdentityContainer) {
|
||||
if (convertView != null && convertView.getTag() instanceof IdentityHolder) {
|
||||
view = convertView;
|
||||
} else {
|
||||
view = mLayoutInflater.inflate(R.layout.choose_identity_item, parent, false);
|
||||
IdentityHolder holder = new IdentityHolder();
|
||||
holder.name = (TextView) view.findViewById(R.id.name);
|
||||
holder.description = (TextView) view.findViewById(R.id.description);
|
||||
view.setTag(holder);
|
||||
}
|
||||
|
||||
IdentityContainer identityContainer = (IdentityContainer) item;
|
||||
Identity identity = identityContainer.identity;
|
||||
IdentityHolder holder = (IdentityHolder) view.getTag();
|
||||
holder.name.setText(identity.getDescription());
|
||||
holder.description.setText(getIdentityDescription(identity));
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
static class AccountHolder {
|
||||
public TextView name;
|
||||
public View chip;
|
||||
}
|
||||
|
||||
static class IdentityHolder {
|
||||
public TextView name;
|
||||
public TextView description;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getIdentityDescription(Identity identity) {
|
||||
return String.format("%s <%s>", identity.getName(), identity.getEmail());
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import com.fsck.k9.mail.store.LocalStore.LocalMessage;
|
||||
public class MessageInfoHolder {
|
||||
public String date;
|
||||
public Date compareDate;
|
||||
public Date compareArrival;
|
||||
public String compareSubject;
|
||||
public CharSequence sender;
|
||||
public String senderAddress;
|
||||
|
@ -185,6 +185,15 @@ public class MessageList
|
||||
|
||||
}
|
||||
|
||||
public static class ArrivalComparator implements Comparator<MessageInfoHolder> {
|
||||
|
||||
@Override
|
||||
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
|
||||
return object1.compareArrival.compareTo(object2.compareArrival);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SubjectComparator implements Comparator<MessageInfoHolder> {
|
||||
|
||||
@Override
|
||||
@ -234,6 +243,7 @@ public class MessageList
|
||||
final Map<SORT_TYPE, Comparator<MessageInfoHolder>> map = new EnumMap<SORT_TYPE, Comparator<MessageInfoHolder>>(SORT_TYPE.class);
|
||||
map.put(SORT_TYPE.SORT_ATTACHMENT, new AttachmentComparator());
|
||||
map.put(SORT_TYPE.SORT_DATE, new DateComparator());
|
||||
map.put(SORT_TYPE.SORT_ARRIVAL, new ArrivalComparator());
|
||||
map.put(SORT_TYPE.SORT_FLAGGED, new FlaggedComparator());
|
||||
map.put(SORT_TYPE.SORT_SENDER, new SenderComparator());
|
||||
map.put(SORT_TYPE.SORT_SUBJECT, new SubjectComparator());
|
||||
@ -460,7 +470,7 @@ public class MessageList
|
||||
|
||||
{
|
||||
// add the date comparator if not already specified
|
||||
if (sortType != SORT_TYPE.SORT_DATE) {
|
||||
if (sortType != SORT_TYPE.SORT_DATE && sortType != SORT_TYPE.SORT_ARRIVAL) {
|
||||
final Comparator<MessageInfoHolder> comparator = SORT_COMPARATORS.get(SORT_TYPE.SORT_DATE);
|
||||
if (sortDateAscending) {
|
||||
chain.add(comparator);
|
||||
@ -1447,6 +1457,10 @@ public class MessageList
|
||||
changeSort(SORT_TYPE.SORT_DATE);
|
||||
return true;
|
||||
}
|
||||
case R.id.set_sort_arrival: {
|
||||
changeSort(SORT_TYPE.SORT_ARRIVAL);
|
||||
return true;
|
||||
}
|
||||
case R.id.set_sort_subject: {
|
||||
changeSort(SORT_TYPE.SORT_SUBJECT);
|
||||
return true;
|
||||
|
@ -287,7 +287,7 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle, false);
|
||||
super.onCreate(icicle);
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.message_view);
|
||||
@ -731,17 +731,16 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
mPrevious.requestFocus();
|
||||
}
|
||||
|
||||
private void onMarkAsUnread() {
|
||||
private void onToggleRead() {
|
||||
if (mMessage != null) {
|
||||
mController.setFlag(mAccount, mMessage.getFolder().getName(),
|
||||
new Message[] { mMessage }, Flag.SEEN, false);
|
||||
new Message[] { mMessage }, Flag.SEEN, !mMessage.isSet(Flag.SEEN));
|
||||
mMessageView.setHeaders(mMessage, mAccount);
|
||||
String subject = mMessage.getSubject();
|
||||
setTitle(subject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onDownloadRemainder() {
|
||||
if (mMessage.isSet(Flag.X_DOWNLOADED_FULL)) {
|
||||
return;
|
||||
@ -808,7 +807,7 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
onSendAlternate();
|
||||
break;
|
||||
case R.id.mark_as_unread:
|
||||
onMarkAsUnread();
|
||||
onToggleRead();
|
||||
break;
|
||||
case R.id.flag:
|
||||
onFlag();
|
||||
@ -923,6 +922,12 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
additionalHeadersItem.setTitle(mMessageView.additionalHeadersVisible() ?
|
||||
R.string.hide_full_header_action : R.string.show_full_header_action);
|
||||
}
|
||||
|
||||
if (mMessage != null) {
|
||||
int actionTitle = mMessage.isSet(Flag.SEEN) ?
|
||||
R.string.mark_as_unread_action : R.string.mark_as_read_action;
|
||||
menu.findItem(R.id.mark_as_unread).setTitle(actionTitle);
|
||||
}
|
||||
}
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private static final String PREFERENCE_SCREEN_PUSH_ADVANCED = "push_advanced";
|
||||
|
||||
private static final String PREFERENCE_DESCRIPTION = "account_description";
|
||||
private static final String PREFERENCE_MARK_MESSAGE_AS_READ_ON_VIEW = "mark_message_as_read_on_view";
|
||||
private static final String PREFERENCE_COMPOSITION = "composition";
|
||||
private static final String PREFERENCE_MANAGE_IDENTITIES = "manage_identities";
|
||||
private static final String PREFERENCE_FREQUENCY = "account_check_frequency";
|
||||
@ -95,9 +96,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private static final String PREFERENCE_CRYPTO_APP = "crypto_app";
|
||||
private static final String PREFERENCE_CRYPTO_AUTO_SIGNATURE = "crypto_auto_signature";
|
||||
private static final String PREFERENCE_CRYPTO_AUTO_ENCRYPT = "crypto_auto_encrypt";
|
||||
|
||||
private static final String PREFERENCE_LOCAL_STORAGE_PROVIDER = "local_storage_provider";
|
||||
|
||||
private static final String PREFERENCE_CATEGORY_FOLDERS = "folders";
|
||||
private static final String PREFERENCE_ARCHIVE_FOLDER = "archive_folder";
|
||||
private static final String PREFERENCE_DRAFTS_FOLDER = "drafts_folder";
|
||||
@ -116,6 +115,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private PreferenceScreen mComposingScreen;
|
||||
|
||||
private EditTextPreference mAccountDescription;
|
||||
private CheckBoxPreference mMarkMessageAsReadOnView;
|
||||
private ListPreference mCheckFrequency;
|
||||
private ListPreference mDisplayCount;
|
||||
private ListPreference mMessageAge;
|
||||
@ -160,10 +160,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private ListPreference mCryptoApp;
|
||||
private CheckBoxPreference mCryptoAutoSignature;
|
||||
private CheckBoxPreference mCryptoAutoEncrypt;
|
||||
|
||||
private ListPreference mLocalStorageProvider;
|
||||
|
||||
|
||||
private ListPreference mArchiveFolder;
|
||||
private ListPreference mDraftsFolder;
|
||||
private ListPreference mSentFolder;
|
||||
@ -207,6 +204,9 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
}
|
||||
});
|
||||
|
||||
mMarkMessageAsReadOnView = (CheckBoxPreference) findPreference(PREFERENCE_MARK_MESSAGE_AS_READ_ON_VIEW);
|
||||
mMarkMessageAsReadOnView.setChecked(mAccount.isMarkMessageAsReadOnView());
|
||||
|
||||
mMessageFormat = (ListPreference) findPreference(PREFERENCE_MESSAGE_FORMAT);
|
||||
mMessageFormat.setValue(mAccount.getMessageFormat().name());
|
||||
mMessageFormat.setSummary(mMessageFormat.getEntry());
|
||||
@ -681,6 +681,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
}
|
||||
|
||||
mAccount.setDescription(mAccountDescription.getText());
|
||||
mAccount.setMarkMessageAsReadOnView(mMarkMessageAsReadOnView.isChecked());
|
||||
mAccount.setNotifyNewMail(mAccountNotify.isChecked());
|
||||
mAccount.setNotifySelfNewMail(mAccountNotifySelf.isChecked());
|
||||
mAccount.setShowOngoing(mAccountNotifySync.isChecked());
|
||||
|
@ -150,7 +150,7 @@ public class Prefs extends K9PreferenceActivity {
|
||||
entryVector.toArray(EMPTY_CHAR_SEQUENCE_ARRAY),
|
||||
entryValueVector.toArray(EMPTY_CHAR_SEQUENCE_ARRAY));
|
||||
|
||||
final String theme = (K9.getK9Theme() == android.R.style.Theme) ? "dark" : "light";
|
||||
final String theme = (K9.getK9Theme() == K9.THEME_DARK) ? "dark" : "light";
|
||||
mTheme = setupListPreference(PREFERENCE_THEME, theme);
|
||||
|
||||
findPreference(PREFERENCE_FONT_SIZE).setOnPreferenceClickListener(
|
||||
@ -353,7 +353,7 @@ public class Prefs extends K9PreferenceActivity {
|
||||
SharedPreferences preferences = Preferences.getPreferences(this).getPreferences();
|
||||
|
||||
K9.setK9Language(mLanguage.getValue());
|
||||
K9.setK9Theme(mTheme.getValue().equals("dark") ? android.R.style.Theme : android.R.style.Theme_Light);
|
||||
K9.setK9Theme(mTheme.getValue().equals("dark") ? K9.THEME_DARK : K9.THEME_LIGHT);
|
||||
K9.setAnimations(mAnimations.isChecked());
|
||||
K9.setGesturesEnabled(mGestures.isChecked());
|
||||
K9.setCompactLayouts(compactLayouts.isChecked());
|
||||
|
@ -117,6 +117,7 @@ public class MessagingController implements Runnable {
|
||||
*/
|
||||
|
||||
private static final String PENDING_COMMAND_MOVE_OR_COPY_BULK = "com.fsck.k9.MessagingController.moveOrCopyBulk";
|
||||
private static final String PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW = "com.fsck.k9.MessagingController.moveOrCopyBulkNew";
|
||||
private static final String PENDING_COMMAND_EMPTY_TRASH = "com.fsck.k9.MessagingController.emptyTrash";
|
||||
private static final String PENDING_COMMAND_SET_FLAG_BULK = "com.fsck.k9.MessagingController.setFlagBulk";
|
||||
private static final String PENDING_COMMAND_APPEND = "com.fsck.k9.MessagingController.append";
|
||||
@ -144,6 +145,7 @@ public class MessagingController implements Runnable {
|
||||
|
||||
public enum SORT_TYPE {
|
||||
SORT_DATE(R.string.sort_earliest_first, R.string.sort_latest_first, false),
|
||||
SORT_ARRIVAL(R.string.sort_earliest_first, R.string.sort_latest_first, false),
|
||||
SORT_SUBJECT(R.string.sort_subject_alpha, R.string.sort_subject_re_alpha, true),
|
||||
SORT_SENDER(R.string.sort_sender_alpha, R.string.sort_sender_re_alpha, true),
|
||||
SORT_UNREAD(R.string.sort_unread_first, R.string.sort_unread_last, true),
|
||||
@ -446,7 +448,7 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private void doRefreshRemote(final Account account, MessagingListener listener) {
|
||||
private void doRefreshRemote(final Account account, final MessagingListener listener) {
|
||||
put("doRefreshRemote", listener, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -506,14 +508,14 @@ public class MessagingController implements Runnable {
|
||||
localFolders = localStore.getPersonalNamespaces(false);
|
||||
Folder[] folderArray = localFolders.toArray(EMPTY_FOLDER_ARRAY);
|
||||
|
||||
for (MessagingListener l : getListeners()) {
|
||||
for (MessagingListener l : getListeners(listener)) {
|
||||
l.listFolders(account, folderArray);
|
||||
}
|
||||
for (MessagingListener l : getListeners()) {
|
||||
for (MessagingListener l : getListeners(listener)) {
|
||||
l.listFoldersFinished(account);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
for (MessagingListener l : getListeners()) {
|
||||
for (MessagingListener l : getListeners(listener)) {
|
||||
l.listFoldersFailed(account, "");
|
||||
}
|
||||
addErrorMessage(account, null, e);
|
||||
@ -645,7 +647,7 @@ public class MessagingController implements Runnable {
|
||||
Log.i(K9.LOG_TAG, "searchLocalMessages ("
|
||||
+ "accountUuids=" + Utility.combine(accountUuids, ',')
|
||||
+ ", folderNames = " + Utility.combine(folderNames, ',')
|
||||
+ ", messages.size() = " + (messages != null ? messages.length : null)
|
||||
+ ", messages.size() = " + (messages != null ? messages.length : -1)
|
||||
+ ", query = " + query
|
||||
+ ", integrate = " + integrate
|
||||
+ ", requiredFlags = " + Utility.combine(requiredFlags, ',')
|
||||
@ -1934,6 +1936,8 @@ public class MessagingController implements Runnable {
|
||||
} else if (PENDING_COMMAND_MARK_ALL_AS_READ.equals(command.command)) {
|
||||
processPendingMarkAllAsRead(command, account);
|
||||
} else if (PENDING_COMMAND_MOVE_OR_COPY_BULK.equals(command.command)) {
|
||||
processPendingMoveOrCopyOld2(command, account);
|
||||
} else if (PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW.equals(command.command)) {
|
||||
processPendingMoveOrCopy(command, account);
|
||||
} else if (PENDING_COMMAND_EMPTY_TRASH.equals(command.command)) {
|
||||
processPendingEmptyTrash(command, account);
|
||||
@ -2118,10 +2122,30 @@ public class MessagingController implements Runnable {
|
||||
closeFolder(localFolder);
|
||||
}
|
||||
}
|
||||
private void queueMoveOrCopy(Account account, String srcFolder, String destFolder, boolean isCopy, String uids[]) {
|
||||
|
||||
// was:
|
||||
private void queueMoveOrCopyOld(Account account, String srcFolder, String destFolder, boolean isCopy, String uids[]) {
|
||||
if (account.getErrorFolderName().equals(srcFolder)) {
|
||||
return;
|
||||
}
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK;
|
||||
|
||||
int length = 3 + uids.length;
|
||||
command.arguments = new String[length];
|
||||
command.arguments[0] = srcFolder;
|
||||
command.arguments[1] = destFolder;
|
||||
command.arguments[2] = Boolean.toString(isCopy);
|
||||
System.arraycopy(uids, 0, command.arguments, 3, uids.length);
|
||||
queuePendingCommand(account, command);
|
||||
}
|
||||
|
||||
// ASH probably don't need this
|
||||
private void queueMoveOrCopyAsh(Account account, String srcFolder, String destFolder, boolean isCopy, String uids[]) {
|
||||
if (account.getErrorFolderName().equals(srcFolder)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ArrayList<String> remoteUids = new ArrayList<String>();
|
||||
for (String uid : uids) {
|
||||
// ignore unsynced messages
|
||||
@ -2132,8 +2156,9 @@ public class MessagingController implements Runnable {
|
||||
if (remoteUids.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK;
|
||||
command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
|
||||
|
||||
int length = 3 + remoteUids.size();
|
||||
command.arguments = new String[length];
|
||||
@ -2144,6 +2169,78 @@ public class MessagingController implements Runnable {
|
||||
remoteUids.size());
|
||||
queuePendingCommand(account, command);
|
||||
}
|
||||
|
||||
private void queueMoveOrCopy(Account account, String srcFolder, String destFolder, boolean isCopy, String uids[]) {
|
||||
if (account.getErrorFolderName().equals(srcFolder)) {
|
||||
return;
|
||||
}
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
|
||||
|
||||
int length = 4 + uids.length;
|
||||
command.arguments = new String[length];
|
||||
command.arguments[0] = srcFolder;
|
||||
command.arguments[1] = destFolder;
|
||||
command.arguments[2] = Boolean.toString(isCopy);
|
||||
command.arguments[3] = Boolean.toString(false);
|
||||
System.arraycopy(uids, 0, command.arguments, 4, uids.length);
|
||||
queuePendingCommand(account, command);
|
||||
}
|
||||
|
||||
private void queueMoveOrCopy(Account account, String srcFolder, String destFolder, boolean isCopy, String uids[], Map<String, String> uidMap) {
|
||||
if (uidMap == null || uidMap.isEmpty()) {
|
||||
queueMoveOrCopy(account, srcFolder, destFolder, isCopy, uids);
|
||||
} else {
|
||||
if (account.getErrorFolderName().equals(srcFolder)) {
|
||||
return;
|
||||
}
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
|
||||
|
||||
int length = 4 + uidMap.keySet().size() + uidMap.values().size();
|
||||
command.arguments = new String[length];
|
||||
command.arguments[0] = srcFolder;
|
||||
command.arguments[1] = destFolder;
|
||||
command.arguments[2] = Boolean.toString(isCopy);
|
||||
command.arguments[3] = Boolean.toString(true);
|
||||
System.arraycopy(uidMap.keySet().toArray(), 0, command.arguments, 4, uidMap.keySet().size());
|
||||
System.arraycopy(uidMap.values().toArray(), 0, command.arguments, 4 + uidMap.keySet().size(), uidMap.values().size());
|
||||
queuePendingCommand(account, command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pending command to new format and call
|
||||
* {@link #processPendingMoveOrCopy(PendingCommand, Account)}.
|
||||
*
|
||||
* <p>
|
||||
* TODO: This method is obsolete and is only for transition from K-9 4.0 to K-9 4.2
|
||||
* Eventually, it should be removed.
|
||||
* </p>
|
||||
*
|
||||
* @param command
|
||||
* Pending move/copy command in old format.
|
||||
* @param account
|
||||
* The account the pending command belongs to.
|
||||
*
|
||||
* @throws MessagingException
|
||||
* In case of an error.
|
||||
*/
|
||||
private void processPendingMoveOrCopyOld2(PendingCommand command, Account account)
|
||||
throws MessagingException {
|
||||
PendingCommand newCommand = new PendingCommand();
|
||||
int len = command.arguments.length;
|
||||
newCommand.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
|
||||
newCommand.arguments = new String[len + 1];
|
||||
newCommand.arguments[0] = command.arguments[0];
|
||||
newCommand.arguments[1] = command.arguments[1];
|
||||
newCommand.arguments[2] = command.arguments[2];
|
||||
newCommand.arguments[3] = Boolean.toString(false);
|
||||
System.arraycopy(command.arguments, 3, newCommand.arguments, 4, len - 3);
|
||||
|
||||
processPendingMoveOrCopy(newCommand, account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a pending move or copy message command.
|
||||
*
|
||||
@ -2155,6 +2252,7 @@ public class MessagingController implements Runnable {
|
||||
throws MessagingException {
|
||||
Folder remoteSrcFolder = null;
|
||||
Folder remoteDestFolder = null;
|
||||
LocalFolder localDestFolder = null;
|
||||
try {
|
||||
String srcFolder = command.arguments[0];
|
||||
if (account.getErrorFolderName().equals(srcFolder)) {
|
||||
@ -2162,17 +2260,45 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
String destFolder = command.arguments[1];
|
||||
String isCopyS = command.arguments[2];
|
||||
String hasNewUidsS = command.arguments[3];
|
||||
|
||||
boolean hasNewUids = false;
|
||||
if (hasNewUidsS != null) {
|
||||
hasNewUids = Boolean.parseBoolean(hasNewUidsS);
|
||||
}
|
||||
|
||||
Store remoteStore = account.getRemoteStore();
|
||||
remoteSrcFolder = remoteStore.getFolder(srcFolder);
|
||||
|
||||
Store localStore = account.getLocalStore();
|
||||
localDestFolder = (LocalFolder) localStore.getFolder(destFolder);
|
||||
List<Message> messages = new ArrayList<Message>();
|
||||
for (int i = 3; i < command.arguments.length; i++) {
|
||||
|
||||
/*
|
||||
* We split up the localUidMap into two parts while sending the command, here we assemble it back.
|
||||
*/
|
||||
Map<String, String> localUidMap = new HashMap<String, String>();
|
||||
if (hasNewUids) {
|
||||
int offset = (command.arguments.length - 4) / 2;
|
||||
|
||||
for (int i = 4; i < 4 + offset; i++) {
|
||||
localUidMap.put(command.arguments[i], command.arguments[i + offset]);
|
||||
|
||||
String uid = command.arguments[i];
|
||||
if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
|
||||
messages.add(remoteSrcFolder.getMessage(uid));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int i = 4; i < command.arguments.length; i++) {
|
||||
String uid = command.arguments[i];
|
||||
if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
|
||||
messages.add(remoteSrcFolder.getMessage(uid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isCopy = false;
|
||||
if (isCopyS != null) {
|
||||
isCopy = Boolean.parseBoolean(isCopyS);
|
||||
@ -2190,6 +2316,8 @@ public class MessagingController implements Runnable {
|
||||
Log.d(K9.LOG_TAG, "processingPendingMoveOrCopy: source folder = " + srcFolder
|
||||
+ ", " + messages.size() + " messages, destination folder = " + destFolder + ", isCopy = " + isCopy);
|
||||
|
||||
Map <String, String> remoteUidMap = null;
|
||||
|
||||
if (!isCopy && destFolder.equals(account.getTrashFolderName())) {
|
||||
if (K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "processingPendingMoveOrCopy doing special case for deleting message");
|
||||
@ -2206,9 +2334,9 @@ public class MessagingController implements Runnable {
|
||||
remoteDestFolder = remoteStore.getFolder(destFolder);
|
||||
|
||||
if (isCopy) {
|
||||
remoteSrcFolder.copyMessages(messages.toArray(EMPTY_MESSAGE_ARRAY), remoteDestFolder);
|
||||
remoteUidMap = remoteSrcFolder.copyMessages(messages.toArray(EMPTY_MESSAGE_ARRAY), remoteDestFolder);
|
||||
} else {
|
||||
remoteSrcFolder.moveMessages(messages.toArray(EMPTY_MESSAGE_ARRAY), remoteDestFolder);
|
||||
remoteUidMap = remoteSrcFolder.moveMessages(messages.toArray(EMPTY_MESSAGE_ARRAY), remoteDestFolder);
|
||||
}
|
||||
updateUids(account, destFolder);
|
||||
}
|
||||
@ -2219,12 +2347,34 @@ public class MessagingController implements Runnable {
|
||||
|
||||
remoteSrcFolder.expunge();
|
||||
}
|
||||
|
||||
/*
|
||||
* This next part is used to bring the local UIDs of the local destination folder
|
||||
* upto speed with the remote UIDs of remote destionation folder.
|
||||
*/
|
||||
if (!localUidMap.isEmpty() && remoteUidMap != null && !remoteUidMap.isEmpty()) {
|
||||
Set<String> remoteSrcUids = remoteUidMap.keySet();
|
||||
Iterator<String> remoteSrcUidsIterator = remoteSrcUids.iterator();
|
||||
|
||||
while (remoteSrcUidsIterator.hasNext()) {
|
||||
String remoteSrcUid = remoteSrcUidsIterator.next();
|
||||
String localDestUid = localUidMap.get(remoteSrcUid);
|
||||
String newUid = remoteUidMap.get(remoteSrcUid);
|
||||
|
||||
Message localDestMessage = localDestFolder.getMessage(localDestUid);
|
||||
if (localDestMessage != null) {
|
||||
localDestMessage.setUid(newUid);
|
||||
localDestFolder.changeUid((LocalMessage)localDestMessage);
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.messageUidChanged(account, destFolder, localDestUid, newUid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
closeFolder(remoteSrcFolder);
|
||||
closeFolder(remoteDestFolder);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2862,7 +3012,7 @@ public class MessagingController implements Runnable {
|
||||
|| message.getId() == 0) {
|
||||
throw new IllegalArgumentException("Message not found: folder=" + folder + ", uid=" + uid);
|
||||
}
|
||||
if (!message.isSet(Flag.SEEN)) {
|
||||
if (account.isMarkMessageAsReadOnView() && !message.isSet(Flag.SEEN)) {
|
||||
message.setFlag(Flag.SEEN, true);
|
||||
setFlag(new Message[] { message }, Flag.SEEN, true);
|
||||
}
|
||||
@ -3410,6 +3560,7 @@ public class MessagingController implements Runnable {
|
||||
private void moveOrCopyMessageSynchronous(final Account account, final String srcFolder, final Message[] inMessages,
|
||||
final String destFolder, final boolean isCopy, MessagingListener listener) {
|
||||
try {
|
||||
Map<String, String> uidMap = new HashMap<String, String>();
|
||||
LocalStore localStore = account.getLocalStore();
|
||||
Store remoteStore = account.getRemoteStore();
|
||||
LocalFolder localSrcFolder = localStore.getFolder(srcFolder);
|
||||
@ -3502,7 +3653,7 @@ public class MessagingController implements Runnable {
|
||||
fp.add(FetchProfile.Item.ENVELOPE);
|
||||
fp.add(FetchProfile.Item.BODY);
|
||||
localSrcFolder.fetch(messages, fp, null);
|
||||
localSrcFolder.copyMessages(messages, localDestFolder);
|
||||
uidMap = localSrcFolder.copyMessages(messages, localDestFolder);
|
||||
|
||||
if (unreadCountAffected) {
|
||||
// If this copy operation changes the unread count in the destination
|
||||
@ -3576,7 +3727,7 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
|
||||
if (!isCopy) {
|
||||
localSrcFolder.moveMessages(localMessages, localDestFolder);
|
||||
uidMap = localSrcFolder.moveMessages(localMessages, localDestFolder);
|
||||
for (Map.Entry<String, Message> entry : origUidMap.entrySet()) {
|
||||
String origUid = entry.getKey();
|
||||
Message message = entry.getValue();
|
||||
@ -3621,6 +3772,7 @@ public class MessagingController implements Runnable {
|
||||
l.folderStatusChanged(account, destFolder, unreadMessageCount);
|
||||
}
|
||||
}
|
||||
//ASH queueMoveOrCopy(account, srcFolder, destFolder, isCopy, origUidMap.keySet().toArray(EMPTY_STRING_ARRAY), uidMap);
|
||||
}
|
||||
|
||||
processPendingCommands(account);
|
||||
@ -3703,6 +3855,7 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
LocalStore localStore = account.getLocalStore();
|
||||
localFolder = localStore.getFolder(folder);
|
||||
Map<String, String> uidMap = null;
|
||||
if (folder.equals(account.getTrashFolderName()) || K9.FOLDER_NONE.equals(account.getTrashFolderName())) {
|
||||
if (K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "Deleting messages in trash folder or trash set to -None-, not copying");
|
||||
@ -3774,8 +3927,7 @@ public class MessagingController implements Runnable {
|
||||
return;
|
||||
}
|
||||
}
|
||||
localFolder.moveMessages(messages, localTrashFolder);
|
||||
|
||||
uidMap = localFolder.moveMessages(messages, localTrashFolder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3816,8 +3968,7 @@ public class MessagingController implements Runnable {
|
||||
queueSetFlag(account, folder, Boolean.toString(true), Flag.SEEN.toString(), uids);
|
||||
processPendingCommands(account);
|
||||
} else {
|
||||
if (K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "Delete policy " + account.getDeletePolicy() + " prevents delete from server");
|
||||
queueMoveOrCopy(account, folder, account.getTrashFolderName(), false, uids, uidMap);
|
||||
}
|
||||
}
|
||||
for (String uid : uids) {
|
||||
@ -4404,7 +4555,13 @@ public class MessagingController implements Runnable {
|
||||
|
||||
NotificationSetting n = account.getNotificationSetting();
|
||||
|
||||
configureNotification(notif, (n.shouldRing() ? n.getRingtone() : null), (n.shouldVibrate() ? n.getVibration() : null), (n.isLed() ? n.getLedColor() : null), K9.NOTIFICATION_LED_BLINK_SLOW, ringAndVibrate);
|
||||
configureNotification(
|
||||
notif,
|
||||
(n.shouldRing()) ? n.getRingtone() : null,
|
||||
(n.shouldVibrate()) ? n.getVibration() : null,
|
||||
(n.isLed()) ? Integer.valueOf(n.getLedColor()) : null,
|
||||
K9.NOTIFICATION_LED_BLINK_SLOW,
|
||||
ringAndVibrate);
|
||||
|
||||
notifMgr.notify(account.getAccountNumber(), notif);
|
||||
}
|
||||
|
63
src/com/fsck/k9/helper/ClipboardManager.java
Normal file
63
src/com/fsck/k9/helper/ClipboardManager.java
Normal file
@ -0,0 +1,63 @@
|
||||
package com.fsck.k9.helper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to access the system clipboard
|
||||
*
|
||||
* @see ClipboardManagerApi1
|
||||
* @see ClipboardManagerApi11
|
||||
*/
|
||||
public abstract class ClipboardManager {
|
||||
/**
|
||||
* Instance of the API-specific class that interfaces with the clipboard API.
|
||||
*/
|
||||
private static ClipboardManager sInstance = null;
|
||||
|
||||
/**
|
||||
* Get API-specific instance of the {@code ClipboardManager} class
|
||||
*
|
||||
* @param context
|
||||
* A {@link Context} instance.
|
||||
*
|
||||
* @return Appropriate {@link ClipboardManager} instance for this device.
|
||||
*/
|
||||
public static ClipboardManager getInstance(Context context) {
|
||||
Context appContext = context.getApplicationContext();
|
||||
|
||||
if (sInstance == null) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
sInstance = new ClipboardManagerApi1(appContext);
|
||||
} else {
|
||||
sInstance = new ClipboardManagerApi11(appContext);
|
||||
}
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
|
||||
protected Context mContext;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context
|
||||
* A {@link Context} instance.
|
||||
*/
|
||||
protected ClipboardManager(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a text string to the system clipboard
|
||||
*
|
||||
* @param label
|
||||
* User-visible label for the content.
|
||||
* @param text
|
||||
* The actual text to be copied to the clipboard.
|
||||
*/
|
||||
public abstract void setText(String label, String text);
|
||||
}
|
22
src/com/fsck/k9/helper/ClipboardManagerApi1.java
Normal file
22
src/com/fsck/k9/helper/ClipboardManagerApi1.java
Normal file
@ -0,0 +1,22 @@
|
||||
package com.fsck.k9.helper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.ClipboardManager;
|
||||
|
||||
/**
|
||||
* Access the system clipboard using the now deprecated {@link ClipboardManager}
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ClipboardManagerApi1 extends com.fsck.k9.helper.ClipboardManager {
|
||||
|
||||
public ClipboardManagerApi1(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(String label, String text) {
|
||||
ClipboardManager clipboardManager =
|
||||
(ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
clipboardManager.setText(text);
|
||||
}
|
||||
}
|
23
src/com/fsck/k9/helper/ClipboardManagerApi11.java
Normal file
23
src/com/fsck/k9/helper/ClipboardManagerApi11.java
Normal file
@ -0,0 +1,23 @@
|
||||
package com.fsck.k9.helper;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.content.ClipboardManager;
|
||||
|
||||
/**
|
||||
* Access the system clipboard using the new {@link ClipboardManager} introduced with API 11
|
||||
*/
|
||||
public class ClipboardManagerApi11 extends com.fsck.k9.helper.ClipboardManager {
|
||||
|
||||
public ClipboardManagerApi11(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(String label, String text) {
|
||||
ClipboardManager clipboardManager =
|
||||
(ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText(label, text);
|
||||
clipboardManager.setPrimaryClip(clip);
|
||||
}
|
||||
}
|
@ -104,6 +104,14 @@ public abstract class Contacts {
|
||||
*/
|
||||
public abstract void createContact(Address email);
|
||||
|
||||
/**
|
||||
* Start the activity to add a phone number to an existing contact or add a new one.
|
||||
*
|
||||
* @param phoneNumber
|
||||
* The phone number to add to a contact, or to use when creating a new contact.
|
||||
*/
|
||||
public abstract void addPhoneContact(String phoneNumber);
|
||||
|
||||
/**
|
||||
* Check whether the provided email address belongs to one of the contacts.
|
||||
*
|
||||
|
@ -9,6 +9,8 @@ import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.Intents;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Email;
|
||||
import android.provider.ContactsContract.Intents.Insert;
|
||||
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.K9;
|
||||
|
||||
@ -85,6 +87,15 @@ public class ContactsSdk5 extends com.fsck.k9.helper.Contacts {
|
||||
mContext.startActivity(contactIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPhoneContact(final String phoneNumber) {
|
||||
Intent addIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
||||
addIntent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
||||
addIntent.putExtra(Insert.PHONE, Uri.decode(phoneNumber));
|
||||
addIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(addIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInContacts(final String emailAddress) {
|
||||
boolean result = false;
|
||||
|
@ -49,6 +49,7 @@ public class MessageHelper {
|
||||
try {
|
||||
LocalMessage message = (LocalMessage) m;
|
||||
target.message = message;
|
||||
target.compareArrival = message.getInternalDate();
|
||||
target.compareDate = message.getSentDate();
|
||||
if (target.compareDate == null) {
|
||||
target.compareDate = message.getInternalDate();
|
||||
|
@ -19,6 +19,29 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Utility {
|
||||
/**
|
||||
* Regular expression that represents characters we won't allow in file names.
|
||||
*
|
||||
* <p>
|
||||
* Allowed are:
|
||||
* <ul>
|
||||
* <li>word characters (letters, digits, and underscores): {@code \w}</li>
|
||||
* <li>spaces: {@code " "}</li>
|
||||
* <li>special characters: {@code !}, {@code #}, {@code $}, {@code %}, {@code &}, {@code '},
|
||||
* {@code (}, {@code )}, {@code -}, {@code @}, {@code ^}, {@code `}, <code>{</code>,
|
||||
* <code>}</code>, {@code ~}, {@code .}, {@code ,}</li>
|
||||
* </ul></p>
|
||||
*
|
||||
* @see #sanitizeFilename(String)
|
||||
*/
|
||||
private static final String INVALID_CHARACTERS = "[^\\w !#$%&'()\\-@\\^`{}~.,]+";
|
||||
|
||||
/**
|
||||
* Invalid characters in a file name are replaced by this character.
|
||||
*
|
||||
* @see #sanitizeFilename(String)
|
||||
*/
|
||||
private static final String REPLACEMENT_CHARACTER = "_";
|
||||
|
||||
// \u00A0 (non-breaking space) happens to be used by French MUA
|
||||
|
||||
@ -605,4 +628,16 @@ public class Utility {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace characters we don't allow in file names with a replacement character.
|
||||
*
|
||||
* @param filename
|
||||
* The original file name.
|
||||
*
|
||||
* @return The sanitized file name containing only allowed characters.
|
||||
*/
|
||||
public static String sanitizeFilename(String filename) {
|
||||
return filename.replaceAll(INVALID_CHARACTERS, REPLACEMENT_CHARACTER);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.fsck.k9.mail;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import android.util.Log;
|
||||
import com.fsck.k9.Account;
|
||||
@ -98,11 +99,15 @@ public abstract class Folder {
|
||||
public abstract Message[] getMessages(String[] uids, MessageRetrievalListener listener)
|
||||
throws MessagingException;
|
||||
|
||||
public abstract void appendMessages(Message[] messages) throws MessagingException;
|
||||
public abstract Map<String, String> appendMessages(Message[] messages) throws MessagingException;
|
||||
|
||||
public void copyMessages(Message[] msgs, Folder folder) throws MessagingException {}
|
||||
public Map<String, String> copyMessages(Message[] msgs, Folder folder) throws MessagingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void moveMessages(Message[] msgs, Folder folder) throws MessagingException {}
|
||||
public Map<String, String> moveMessages(Message[] msgs, Folder folder) throws MessagingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void delete(Message[] msgs, String trashFolderName) throws MessagingException {}
|
||||
|
||||
|
@ -953,19 +953,23 @@ public class MimeUtility {
|
||||
}
|
||||
header = header.replaceAll("\r|\n", "");
|
||||
String[] parts = header.split(";");
|
||||
if (name == null) {
|
||||
if (name == null && parts.length > 0) {
|
||||
return parts[0];
|
||||
}
|
||||
for (String part : parts) {
|
||||
if (part.trim().toLowerCase(Locale.US).startsWith(name.toLowerCase(Locale.US))) {
|
||||
String parameter = part.split("=", 2)[1].trim();
|
||||
if (parameter.startsWith("\"") && parameter.endsWith("\"")) {
|
||||
return parameter.substring(1, parameter.length() - 1);
|
||||
String[] partParts = part.split("=", 2);
|
||||
if (partParts.length == 2) {
|
||||
String parameter = partParts[1].trim();
|
||||
int len = parameter.length();
|
||||
if (len >= 2 && parameter.startsWith("\"") && parameter.endsWith("\"")) {
|
||||
return parameter.substring(1, len - 1);
|
||||
} else {
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -2178,8 +2182,11 @@ public class MimeUtility {
|
||||
}
|
||||
|
||||
private static String getJisVariantFromAddress(String address) {
|
||||
if (address == null)
|
||||
return null;
|
||||
if (isInDomain(address, "docomo.ne.jp") || isInDomain(address, "dwmail.jp") ||
|
||||
isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com"))
|
||||
isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com") ||
|
||||
isInDomain(address, "emnet.ne.jp") || isInDomain(address, "emobile.ne.jp"))
|
||||
return "docomo";
|
||||
else if (isInDomain(address, "softbank.ne.jp") || isInDomain(address, "vodafone.ne.jp") ||
|
||||
isInDomain(address, "disney.ne.jp") || isInDomain(address, "vertuclub.ne.jp"))
|
||||
@ -3256,4 +3263,80 @@ public class MimeUtility {
|
||||
|
||||
return charset;
|
||||
}
|
||||
|
||||
public static ViewableContainer extractPartsFromDraft(Message message)
|
||||
throws MessagingException {
|
||||
|
||||
Body body = message.getBody();
|
||||
if (message.isMimeType("multipart/mixed") && body instanceof MimeMultipart) {
|
||||
MimeMultipart multipart = (MimeMultipart) body;
|
||||
|
||||
ViewableContainer container;
|
||||
int count = multipart.getCount();
|
||||
if (count >= 1) {
|
||||
// The first part is either a text/plain or a multipart/alternative
|
||||
BodyPart firstPart = multipart.getBodyPart(0);
|
||||
container = extractTextual(firstPart);
|
||||
|
||||
// The rest should be attachments
|
||||
for (int i = 1; i < count; i++) {
|
||||
BodyPart bodyPart = multipart.getBodyPart(i);
|
||||
container.attachments.add(bodyPart);
|
||||
}
|
||||
} else {
|
||||
container = new ViewableContainer("", "", new ArrayList<Part>());
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
return extractTextual(message);
|
||||
}
|
||||
|
||||
private static ViewableContainer extractTextual(Part part) throws MessagingException {
|
||||
String text = "";
|
||||
String html = "";
|
||||
List<Part> attachments = new ArrayList<Part>();
|
||||
|
||||
Body firstBody = part.getBody();
|
||||
if (part.isMimeType("text/plain")) {
|
||||
String bodyText = getTextFromPart(part);
|
||||
if (bodyText != null) {
|
||||
text = fixDraftTextBody(bodyText);
|
||||
}
|
||||
} else if (part.isMimeType("multipart/alternative") &&
|
||||
firstBody instanceof MimeMultipart) {
|
||||
MimeMultipart multipart = (MimeMultipart) firstBody;
|
||||
for (int i = 0, count = multipart.getCount(); i < count; i++) {
|
||||
BodyPart bodyPart = multipart.getBodyPart(i);
|
||||
String bodyText = getTextFromPart(bodyPart);
|
||||
if (bodyText != null) {
|
||||
if (text.length() == 0 && bodyPart.isMimeType("text/plain")) {
|
||||
text = fixDraftTextBody(bodyText);
|
||||
} else if (html.length() == 0 && bodyPart.isMimeType("text/html")) {
|
||||
html = fixDraftTextBody(bodyText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ViewableContainer(text, html, attachments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix line endings of text bodies in draft messages.
|
||||
*
|
||||
* <p>
|
||||
* We create drafts with LF line endings. The values in the identity header are based on that.
|
||||
* So we replace CRLF with LF when loading messages (from the server).
|
||||
* </p>
|
||||
*
|
||||
* @param text
|
||||
* The body text with CRLF line endings
|
||||
*
|
||||
* @return The text with LF line endings
|
||||
*/
|
||||
private static String fixDraftTextBody(String text) {
|
||||
return text.replace("\r\n", "\n");
|
||||
}
|
||||
}
|
||||
|
@ -409,7 +409,7 @@ public class ImapResponseParser {
|
||||
|
||||
|
||||
public Object getKeyedValue(Object key) {
|
||||
for (int i = 0, count = size(); i < count; i++) {
|
||||
for (int i = 0, count = size() - 1; i < count; i++) {
|
||||
if (equalsIgnoreCase(get(i), key)) {
|
||||
return get(i + 1);
|
||||
}
|
||||
@ -434,7 +434,7 @@ public class ImapResponseParser {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0, count = size(); i < count; i++) {
|
||||
for (int i = 0, count = size() - 1; i < count; i++) {
|
||||
if (equalsIgnoreCase(key, get(i))) {
|
||||
return true;
|
||||
}
|
||||
@ -443,7 +443,7 @@ public class ImapResponseParser {
|
||||
}
|
||||
|
||||
public int getKeyIndex(Object key) {
|
||||
for (int i = 0, count = size(); i < count; i++) {
|
||||
for (int i = 0, count = size() - 1; i < count; i++) {
|
||||
if (equalsIgnoreCase(key, get(i))) {
|
||||
return i;
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.controller.MessageRetrievalListener;
|
||||
import com.fsck.k9.helper.StringUtils;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.helper.power.TracingPowerManager;
|
||||
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
|
||||
@ -89,6 +90,7 @@ import com.fsck.k9.mail.internet.MimeMultipart;
|
||||
import com.fsck.k9.mail.internet.MimeUtility;
|
||||
import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
|
||||
import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse;
|
||||
import com.fsck.k9.mail.store.imap.ImapUtility;
|
||||
import com.fsck.k9.mail.transport.imap.ImapSettings;
|
||||
import com.jcraft.jzlib.JZlib;
|
||||
import com.jcraft.jzlib.ZOutputStream;
|
||||
@ -1153,24 +1155,57 @@ public class ImapStore extends Store {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the given messages to the specified folder.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Note:</strong>
|
||||
* Only the UIDs of the given {@link Message} instances are used. It is assumed that all
|
||||
* UIDs represent valid messages in this folder.
|
||||
* </p>
|
||||
*
|
||||
* @param messages
|
||||
* The messages to copy to the specfied folder.
|
||||
* @param folder
|
||||
* The name of the target folder.
|
||||
*
|
||||
* @return The mapping of original message UIDs to the new server UIDs.
|
||||
*/
|
||||
@Override
|
||||
public void copyMessages(Message[] messages, Folder folder) throws MessagingException {
|
||||
public Map<String, String> copyMessages(Message[] messages, Folder folder)
|
||||
throws MessagingException {
|
||||
if (!(folder instanceof ImapFolder)) {
|
||||
throw new MessagingException("ImapFolder.copyMessages passed non-ImapFolder");
|
||||
}
|
||||
|
||||
if (messages.length == 0)
|
||||
return;
|
||||
if (messages.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ImapFolder iFolder = (ImapFolder)folder;
|
||||
checkOpen();
|
||||
|
||||
String[] uids = new String[messages.length];
|
||||
for (int i = 0, count = messages.length; i < count; i++) {
|
||||
uids[i] = messages[i].getUid();
|
||||
}
|
||||
|
||||
try {
|
||||
String remoteDestName = encodeString(encodeFolderName(iFolder.getPrefixedName()));
|
||||
|
||||
//TODO: Split this into multiple commands if the command exceeds a certain length.
|
||||
mConnection.sendCommand(String.format("UID COPY %s %s",
|
||||
Utility.combine(uids, ','),
|
||||
remoteDestName), false);
|
||||
ImapResponse response;
|
||||
do {
|
||||
response = mConnection.readResponse();
|
||||
handleUntaggedResponse(response);
|
||||
} while (response.mTag == null);
|
||||
|
||||
Map<String, String> uidMap = null;
|
||||
|
||||
// ASH maybe this shouldn't be here at all.
|
||||
if (!exists(remoteDestName)) {
|
||||
/*
|
||||
* If the remote folder doesn't exist we try to create it.
|
||||
@ -1180,26 +1215,70 @@ public class ImapStore extends Store {
|
||||
iFolder.create();
|
||||
}
|
||||
|
||||
if (exists(remoteDestName)) {
|
||||
executeSimpleCommand(String.format("UID COPY %s %s",
|
||||
Utility.combine(uids, ','),
|
||||
remoteDestName));
|
||||
} else {
|
||||
throw new MessagingException("IMAPMessage.copyMessages: remote destination folder " + folder.getName()
|
||||
+ " does not exist and could not be created for " + getLogId()
|
||||
, true);
|
||||
|
||||
if (response.size() > 1) {
|
||||
/*
|
||||
* If the server supports UIDPLUS, then along with the COPY response it will
|
||||
* return an COPYUID response code, e.g.
|
||||
*
|
||||
* 24 OK [COPYUID 38505 304,319:320 3956:3958] Success
|
||||
*
|
||||
* COPYUID is followed by UIDVALIDITY, the set of UIDs of copied messages from
|
||||
* the source folder and the set of corresponding UIDs assigned to them in the
|
||||
* destination folder.
|
||||
*
|
||||
* We can use the new UIDs included in this response to update our records.
|
||||
*/
|
||||
Object responseList = response.get(1);
|
||||
|
||||
if (responseList instanceof ImapList) {
|
||||
final ImapList copyList = (ImapList) responseList;
|
||||
if (copyList.size() >= 4 && copyList.getString(0).equals("COPYUID")) {
|
||||
List<String> srcUids = ImapUtility.getImapSequenceValues(
|
||||
copyList.getString(2));
|
||||
List<String> destUids = ImapUtility.getImapSequenceValues(
|
||||
copyList.getString(3));
|
||||
|
||||
if (srcUids != null && destUids != null) {
|
||||
if (srcUids.size() == destUids.size()) {
|
||||
Iterator<String> srcUidsIterator = srcUids.iterator();
|
||||
Iterator<String> destUidsIterator = destUids.iterator();
|
||||
uidMap = new HashMap<String, String>();
|
||||
while (srcUidsIterator.hasNext() &&
|
||||
destUidsIterator.hasNext()) {
|
||||
String srcUid = srcUidsIterator.next();
|
||||
String destUid = destUidsIterator.next();
|
||||
uidMap.put(srcUid, destUid);
|
||||
}
|
||||
} else {
|
||||
if (K9.DEBUG) {
|
||||
Log.v(K9.LOG_TAG, "Parse error: size of source UIDs " +
|
||||
"list is not the same as size of destination " +
|
||||
"UIDs list.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (K9.DEBUG) {
|
||||
Log.v(K9.LOG_TAG, "Parsing of the sequence set failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uidMap;
|
||||
} catch (IOException ioe) {
|
||||
throw ioExceptionHandler(mConnection, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveMessages(Message[] messages, Folder folder) throws MessagingException {
|
||||
public Map<String, String> moveMessages(Message[] messages, Folder folder) throws MessagingException {
|
||||
if (messages.length == 0)
|
||||
return;
|
||||
copyMessages(messages, folder);
|
||||
return null;
|
||||
Map<String, String> uidMap = copyMessages(messages, folder);
|
||||
setFlags(messages, new Flag[] { Flag.DELETED }, true);
|
||||
return uidMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1675,16 +1754,19 @@ public class ImapStore extends Store {
|
||||
|
||||
if (fetchList.containsKey("BODY")) {
|
||||
int index = fetchList.getKeyIndex("BODY") + 2;
|
||||
int size = fetchList.size();
|
||||
if (index < size) {
|
||||
result = fetchList.getObject(index);
|
||||
|
||||
// Check if there's an origin octet
|
||||
if (result instanceof String) {
|
||||
String originOctet = (String) result;
|
||||
if (originOctet.startsWith("<")) {
|
||||
if (originOctet.startsWith("<") && (index + 1) < size) {
|
||||
result = fetchList.getObject(index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1938,20 +2020,30 @@ public class ImapStore extends Store {
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given messages to the selected folder. This implementation also determines
|
||||
* the new UID of the given message on the IMAP server and sets the Message's UID to the
|
||||
* new server UID.
|
||||
* Appends the given messages to the selected folder.
|
||||
*
|
||||
* <p>
|
||||
* This implementation also determines the new UIDs of the given messages on the IMAP
|
||||
* server and changes the messages' UIDs to the new server UIDs.
|
||||
* </p>
|
||||
*
|
||||
* @param messages
|
||||
* The messages to append to the folder.
|
||||
*
|
||||
* @return The mapping of original message UIDs to the new server UIDs.
|
||||
*/
|
||||
@Override
|
||||
public void appendMessages(Message[] messages) throws MessagingException {
|
||||
public Map<String, String> appendMessages(Message[] messages) throws MessagingException {
|
||||
checkOpen();
|
||||
try {
|
||||
Map<String, String> uidMap = new HashMap<String, String>();
|
||||
for (Message message : messages) {
|
||||
mConnection.sendCommand(
|
||||
String.format("APPEND %s (%s) {%d}",
|
||||
encodeString(encodeFolderName(getPrefixedName())),
|
||||
combineFlags(message.getFlags()),
|
||||
message.calculateSize()), false);
|
||||
|
||||
ImapResponse response;
|
||||
do {
|
||||
response = mConnection.readResponse();
|
||||
@ -1965,16 +2057,54 @@ public class ImapStore extends Store {
|
||||
}
|
||||
} while (response.mTag == null);
|
||||
|
||||
String newUid = getUidFromMessageId(message);
|
||||
if (K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "Got UID " + newUid + " for message for " + getLogId());
|
||||
if (response.size() > 1) {
|
||||
/*
|
||||
* If the server supports UIDPLUS, then along with the APPEND response it
|
||||
* will return an APPENDUID response code, e.g.
|
||||
*
|
||||
* 11 OK [APPENDUID 2 238268] APPEND completed
|
||||
*
|
||||
* We can use the UID included in this response to update our records.
|
||||
*/
|
||||
Object responseList = response.get(1);
|
||||
|
||||
if (newUid != null) {
|
||||
if (responseList instanceof ImapList) {
|
||||
ImapList appendList = (ImapList) responseList;
|
||||
if (appendList.size() >= 3 &&
|
||||
appendList.getString(0).equals("APPENDUID")) {
|
||||
|
||||
String newUid = appendList.getString(2);
|
||||
|
||||
if (!StringUtils.isNullOrEmpty(newUid)) {
|
||||
message.setUid(newUid);
|
||||
uidMap.put(message.getUid(), newUid);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This part is executed in case the server does not support UIDPLUS or does
|
||||
* not implement the APPENDUID response code.
|
||||
*/
|
||||
String newUid = getUidFromMessageId(message);
|
||||
if (K9.DEBUG) {
|
||||
Log.d(K9.LOG_TAG, "Got UID " + newUid + " for message for " + getLogId());
|
||||
}
|
||||
|
||||
if (!StringUtils.isNullOrEmpty(newUid)) {
|
||||
uidMap.put(message.getUid(), newUid);
|
||||
message.setUid(newUid);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* We need uidMap to be null if new UIDs are not available to maintain consistency
|
||||
* with the behavior of other similar methods (copyMessages, moveMessages) which
|
||||
* return null.
|
||||
*/
|
||||
return (uidMap.size() == 0) ? null : uidMap;
|
||||
} catch (IOException ioe) {
|
||||
throw ioExceptionHandler(mConnection, ioe);
|
||||
}
|
||||
@ -2693,13 +2823,8 @@ public class ImapStore extends Store {
|
||||
private static final long serialVersionUID = 3725007182205882394L;
|
||||
String mAlertText;
|
||||
|
||||
public ImapException(String message, String alertText, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
this.mAlertText = alertText;
|
||||
}
|
||||
|
||||
public ImapException(String message, String alertText) {
|
||||
super(message);
|
||||
super(message, true);
|
||||
this.mAlertText = alertText;
|
||||
}
|
||||
|
||||
|
@ -2109,21 +2109,23 @@ Log.v("ASH", mAccount.getDescription() + ":" + name + " is " + (localOnly == 1 ?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyMessages(Message[] msgs, Folder folder) throws MessagingException {
|
||||
public Map<String, String> copyMessages(Message[] msgs, Folder folder) throws MessagingException {
|
||||
if (!(folder instanceof LocalFolder)) {
|
||||
throw new MessagingException("copyMessages called with incorrect Folder");
|
||||
}
|
||||
((LocalFolder) folder).appendMessages(msgs, true);
|
||||
return ((LocalFolder) folder).appendMessages(msgs, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveMessages(final Message[] msgs, final Folder destFolder) throws MessagingException {
|
||||
public Map<String, String> moveMessages(final Message[] msgs, final Folder destFolder) throws MessagingException {
|
||||
if (!(destFolder instanceof LocalFolder)) {
|
||||
throw new MessagingException("moveMessages called with non-LocalFolder");
|
||||
}
|
||||
|
||||
final LocalFolder lDestFolder = (LocalFolder)destFolder;
|
||||
|
||||
final Map<String, String> uidMap = new HashMap<String, String>();
|
||||
|
||||
try {
|
||||
database.execute(false, new DbCallback<Void>() {
|
||||
@Override
|
||||
@ -2149,7 +2151,10 @@ Log.v("ASH", mAccount.getDescription() + ":" + name + " is " + (localOnly == 1 ?
|
||||
Log.d(K9.LOG_TAG, "Updating folder_id to " + lDestFolder.getId() + " for message with UID "
|
||||
+ message.getUid() + ", id " + lMessage.getId() + " currently in folder " + getName());
|
||||
|
||||
message.setUid(K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString());
|
||||
String newUid = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
|
||||
message.setUid(newUid);
|
||||
|
||||
uidMap.put(oldUID, newUid);
|
||||
|
||||
db.execSQL("UPDATE messages " + "SET folder_id = ?, uid = ? " + "WHERE id = ?", new Object[] {
|
||||
lDestFolder.getId(),
|
||||
@ -2157,6 +2162,11 @@ Log.v("ASH", mAccount.getDescription() + ":" + name + " is " + (localOnly == 1 ?
|
||||
lMessage.getId()
|
||||
});
|
||||
|
||||
/*
|
||||
* Add a placeholder message so we won't download the original
|
||||
* message again if we synchronize before the remote move is
|
||||
* complete.
|
||||
*/
|
||||
LocalMessage placeHolder = new LocalMessage(oldUID, LocalFolder.this);
|
||||
placeHolder.setFlagInternal(Flag.DELETED, true);
|
||||
placeHolder.setFlagInternal(Flag.SEEN, true);
|
||||
@ -2168,6 +2178,7 @@ Log.v("ASH", mAccount.getDescription() + ":" + name + " is " + (localOnly == 1 ?
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return uidMap;
|
||||
} catch (WrappedException e) {
|
||||
throw(MessagingException) e.getCause();
|
||||
}
|
||||
@ -2213,8 +2224,8 @@ Log.v("ASH", mAccount.getDescription() + ":" + name + " is " + (localOnly == 1 ?
|
||||
* message, retrieve the appropriate local message instance first (if it already exists).
|
||||
*/
|
||||
@Override
|
||||
public void appendMessages(Message[] messages) throws MessagingException {
|
||||
appendMessages(messages, false);
|
||||
public Map<String, String> appendMessages(Message[] messages) throws MessagingException {
|
||||
return appendMessages(messages, false);
|
||||
}
|
||||
|
||||
public void expunge() throws MessagingException {
|
||||
@ -2261,10 +2272,12 @@ Log.v("ASH", mAccount.getDescription() + ":" + name + " is " + (localOnly == 1 ?
|
||||
* message, retrieve the appropriate local message instance first (if it already exists).
|
||||
* @param messages
|
||||
* @param copy
|
||||
* @return Map<String, String> uidMap of srcUids -> destUids
|
||||
*/
|
||||
private void appendMessages(final Message[] messages, final boolean copy) throws MessagingException {
|
||||
private Map<String, String> appendMessages(final Message[] messages, final boolean copy) throws MessagingException {
|
||||
open(OpenMode.READ_WRITE);
|
||||
try {
|
||||
final Map<String, String> uidMap = new HashMap<String, String>();
|
||||
database.execute(true, new DbCallback<Void>() {
|
||||
@Override
|
||||
public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException {
|
||||
@ -2277,11 +2290,26 @@ Log.v("ASH", mAccount.getDescription() + ":" + name + " is " + (localOnly == 1 ?
|
||||
long oldMessageId = -1;
|
||||
String uid = message.getUid();
|
||||
if (uid == null || copy) {
|
||||
uid = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
|
||||
if (!copy) {
|
||||
message.setUid(uid);
|
||||
}
|
||||
/*
|
||||
* Create a new message in the database
|
||||
*/
|
||||
String randomLocalUid = K9.LOCAL_UID_PREFIX +
|
||||
UUID.randomUUID().toString();
|
||||
|
||||
if (copy) {
|
||||
// Save mapping: source UID -> target UID
|
||||
uidMap.put(uid, randomLocalUid);
|
||||
} else {
|
||||
// Modify the Message instance to reference the new UID
|
||||
message.setUid(randomLocalUid);
|
||||
}
|
||||
|
||||
// The message will be saved with the newly generated UID
|
||||
uid = randomLocalUid;
|
||||
} else {
|
||||
/*
|
||||
* Replace an existing message in the database
|
||||
*/
|
||||
LocalMessage oldMessage = (LocalMessage) getMessage(uid);
|
||||
|
||||
if (oldMessage != null) {
|
||||
@ -2298,12 +2326,29 @@ Log.v("ASH", mAccount.getDescription() + ":" + name + " is " + (localOnly == 1 ?
|
||||
deleteAttachments(message.getUid());
|
||||
}
|
||||
|
||||
boolean isDraft = (message.getHeader(K9.IDENTITY_HEADER) != null);
|
||||
|
||||
List<Part> attachments;
|
||||
String text;
|
||||
String html;
|
||||
if (isDraft) {
|
||||
// Don't modify the text/plain or text/html part of our own
|
||||
// draft messages because this will cause the values stored in
|
||||
// the identity header to be wrong.
|
||||
ViewableContainer container =
|
||||
MimeUtility.extractPartsFromDraft(message);
|
||||
|
||||
text = container.text;
|
||||
html = container.html;
|
||||
attachments = container.attachments;
|
||||
} else {
|
||||
ViewableContainer container =
|
||||
MimeUtility.extractTextAndAttachments(mApplication, message);
|
||||
|
||||
List<Part> attachments = container.attachments;
|
||||
String text = container.text;
|
||||
String html = HtmlConverter.convertEmoji2Img(container.html);
|
||||
attachments = container.attachments;
|
||||
text = container.text;
|
||||
html = HtmlConverter.convertEmoji2Img(container.html);
|
||||
}
|
||||
|
||||
String preview = calculateContentPreview(text);
|
||||
|
||||
@ -2361,6 +2406,7 @@ Log.v("ASH", mAccount.getDescription() + ":" + name + " is " + (localOnly == 1 ?
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return uidMap;
|
||||
} catch (WrappedException e) {
|
||||
throw(MessagingException) e.getCause();
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import java.util.LinkedList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Pop3Store extends Store {
|
||||
public static final String STORE_TYPE = "POP3";
|
||||
@ -889,7 +890,8 @@ public class Pop3Store extends Store {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendMessages(Message[] messages) throws MessagingException {
|
||||
public Map<String, String> appendMessages(Message[] messages) throws MessagingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1339,13 +1339,15 @@ public class WebDavStore extends Store {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyMessages(Message[] messages, Folder folder) throws MessagingException {
|
||||
public Map<String, String> copyMessages(Message[] messages, Folder folder) throws MessagingException {
|
||||
moveOrCopyMessages(messages, folder.getName(), false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveMessages(Message[] messages, Folder folder) throws MessagingException {
|
||||
public Map<String, String> moveMessages(Message[] messages, Folder folder) throws MessagingException {
|
||||
moveOrCopyMessages(messages, folder.getName(), true);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1920,8 +1922,9 @@ public class WebDavStore extends Store {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendMessages(Message[] messages) throws MessagingException {
|
||||
public Map<String, String> appendMessages(Message[] messages) throws MessagingException {
|
||||
appendWebDavMessages(messages);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Message[] appendWebDavMessages(Message[] messages) throws MessagingException {
|
||||
|
113
src/com/fsck/k9/mail/store/imap/ImapUtility.java
Normal file
113
src/com/fsck/k9/mail/store/imap/ImapUtility.java
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The K-9 Dog Walkers
|
||||
* Copyright (C) 2011 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.
|
||||
*/
|
||||
|
||||
package com.fsck.k9.mail.store.imap;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility methods for use with IMAP.
|
||||
*/
|
||||
public class ImapUtility {
|
||||
/**
|
||||
* Gets all of the values in a sequence set per RFC 3501.
|
||||
*
|
||||
* <p>
|
||||
* Any ranges are expanded into a list of individual numbers.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* sequence-number = nz-number / "*"
|
||||
* sequence-range = sequence-number ":" sequence-number
|
||||
* sequence-set = (sequence-number / sequence-range) *("," sequence-set)
|
||||
* </pre>
|
||||
*
|
||||
* @param set
|
||||
* The sequence set string as received by the server.
|
||||
*
|
||||
* @return The list of IDs as strings in this sequence set. If the set is invalid, an empty
|
||||
* list is returned.
|
||||
*/
|
||||
public static List<String> getImapSequenceValues(String set) {
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
if (set != null) {
|
||||
String[] setItems = set.split(",");
|
||||
for (String item : setItems) {
|
||||
if (item.indexOf(':') == -1) {
|
||||
// simple item
|
||||
try {
|
||||
Integer.parseInt(item); // Don't need the value; just ensure it's valid
|
||||
list.add(item);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.d(K9.LOG_TAG, "Invalid UID value", e);
|
||||
}
|
||||
} else {
|
||||
// range
|
||||
list.addAll(getImapRangeValues(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the given number range into a list of individual numbers.
|
||||
*
|
||||
* <pre>
|
||||
* sequence-number = nz-number / "*"
|
||||
* sequence-range = sequence-number ":" sequence-number
|
||||
* sequence-set = (sequence-number / sequence-range) *("," sequence-set)
|
||||
* </pre>
|
||||
*
|
||||
* @param range
|
||||
* The range string as received by the server.
|
||||
*
|
||||
* @return The list of IDs as strings in this range. If the range is not valid, an empty list
|
||||
* is returned.
|
||||
*/
|
||||
public static List<String> getImapRangeValues(String range) {
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
try {
|
||||
if (range != null) {
|
||||
int colonPos = range.indexOf(':');
|
||||
if (colonPos > 0) {
|
||||
int first = Integer.parseInt(range.substring(0, colonPos));
|
||||
int second = Integer.parseInt(range.substring(colonPos + 1));
|
||||
if (first < second) {
|
||||
for (int i = first; i <= second; i++) {
|
||||
list.add(Integer.toString(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = first; i >= second; i--) {
|
||||
list.add(Integer.toString(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Log.d(K9.LOG_TAG, "Invalid range value", e);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
@ -96,6 +96,9 @@ public class AccountSettings {
|
||||
s.put("localStorageProvider", Settings.versions(
|
||||
new V(1, new StorageProviderSetting())
|
||||
));
|
||||
s.put("markMessageAsReadOnView", Settings.versions(
|
||||
new V(7, new BooleanSetting(true))
|
||||
));
|
||||
s.put("maxPushFolders", Settings.versions(
|
||||
new V(1, new IntegerRangeSetting(0, 100, 10))
|
||||
));
|
||||
|
@ -7,6 +7,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class Editor implements android.content.SharedPreferences.Editor {
|
||||
private Storage storage;
|
||||
@ -138,4 +139,9 @@ public class Editor implements android.content.SharedPreferences.Editor {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public android.content.SharedPreferences.Editor putStringSet(String arg0, Set<String> arg1) {
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ public class GlobalSettings {
|
||||
new V(1, new BooleanSetting(false))
|
||||
));
|
||||
s.put("theme", Settings.versions(
|
||||
new V(1, new ThemeSetting(android.R.style.Theme_Light))
|
||||
new V(1, new ThemeSetting(K9.THEME_LIGHT))
|
||||
));
|
||||
s.put("useGalleryBugWorkaround", Settings.versions(
|
||||
new V(1, new GalleryBugWorkaroundSetting())
|
||||
@ -294,34 +294,47 @@ public class GlobalSettings {
|
||||
/**
|
||||
* The theme setting.
|
||||
*/
|
||||
public static class ThemeSetting extends PseudoEnumSetting<Integer> {
|
||||
private final Map<Integer, String> mMapping;
|
||||
public static class ThemeSetting extends SettingsDescription {
|
||||
private static final String THEME_LIGHT = "light";
|
||||
private static final String THEME_DARK = "dark";
|
||||
|
||||
public ThemeSetting(int defaultValue) {
|
||||
super(defaultValue);
|
||||
|
||||
Map<Integer, String> mapping = new HashMap<Integer, String>();
|
||||
mapping.put(android.R.style.Theme_Light, "light");
|
||||
mapping.put(android.R.style.Theme, "dark");
|
||||
mMapping = Collections.unmodifiableMap(mapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Integer, String> getMapping() {
|
||||
return mMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value) throws InvalidSettingValueException {
|
||||
try {
|
||||
Integer theme = Integer.parseInt(value);
|
||||
if (mMapping.containsKey(theme)) {
|
||||
return theme;
|
||||
if (theme == K9.THEME_LIGHT ||
|
||||
// We used to store the resource ID of the theme in the preference storage,
|
||||
// but don't use the database upgrade mechanism to update the values. So
|
||||
// we have to deal with the old format here.
|
||||
theme == android.R.style.Theme_Light) {
|
||||
return K9.THEME_LIGHT;
|
||||
} else if (theme == K9.THEME_DARK || theme == android.R.style.Theme) {
|
||||
return K9.THEME_DARK;
|
||||
}
|
||||
} catch (NumberFormatException e) { /* do nothing */ }
|
||||
|
||||
throw new InvalidSettingValueException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromPrettyString(String value) throws InvalidSettingValueException {
|
||||
if (THEME_LIGHT.equals(value)) {
|
||||
return K9.THEME_LIGHT;
|
||||
} else if (THEME_DARK.equals(value)) {
|
||||
return K9.THEME_DARK;
|
||||
}
|
||||
|
||||
throw new InvalidSettingValueException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toPrettyString(Object value) {
|
||||
return (((Integer)value).intValue() == K9.THEME_LIGHT) ? THEME_LIGHT : THEME_DARK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,7 +35,7 @@ public class Settings {
|
||||
*
|
||||
* @see SettingsExporter
|
||||
*/
|
||||
public static final int VERSION = 6;
|
||||
public static final int VERSION = 7;
|
||||
|
||||
public static Map<String, Object> validate(int version, Map<String,
|
||||
TreeMap<Integer, SettingsDescription>> settings,
|
||||
|
@ -15,6 +15,7 @@ import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
@ -399,4 +400,10 @@ public class Storage implements SharedPreferences {
|
||||
Log.e(K9.LOG_TAG, "Error writing key '" + key + "', value = '" + value + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<String> getStringSet(String arg0, Set<String> arg1) {
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,5 @@
|
||||
package com.fsck.k9.provider;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
@ -46,6 +33,19 @@ import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.store.LocalStore;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class MessageProvider extends ContentProvider {
|
||||
|
||||
public static interface MessageColumns extends BaseColumns {
|
||||
@ -245,7 +245,7 @@ public class MessageProvider extends ContentProvider {
|
||||
final BlockingQueue<List<MessageInfoHolder>> queue = new SynchronousQueue<List<MessageInfoHolder>>();
|
||||
|
||||
// new code for integrated inbox, only execute this once as it will be processed afterwards via the listener
|
||||
final SearchAccount integratedInboxAccount = new SearchAccount(getContext(), true, null, null);
|
||||
final SearchAccount integratedInboxAccount = SearchAccount.createUnifiedInboxAccount(getContext());
|
||||
final MessagingController msgController = MessagingController.getInstance(K9.app);
|
||||
|
||||
msgController.searchLocalMessages(integratedInboxAccount, null,
|
||||
@ -714,6 +714,12 @@ public class MessageProvider extends ContentProvider {
|
||||
checkClosed();
|
||||
mCursor.unregisterDataSetObserver(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType(int columnIndex) {
|
||||
checkClosed();
|
||||
return mCursor.getType(columnIndex);
|
||||
}
|
||||
}
|
||||
|
||||
protected class ThrottlingQueryHandler implements QueryHandler {
|
||||
|
@ -123,7 +123,7 @@ public class RemoteControlService extends CoreService {
|
||||
|
||||
String theme = intent.getStringExtra(K9_THEME);
|
||||
if (theme != null) {
|
||||
K9.setK9Theme(K9RemoteControl.K9_THEME_DARK.equals(theme) ? android.R.style.Theme : android.R.style.Theme_Light);
|
||||
K9.setK9Theme(K9RemoteControl.K9_THEME_DARK.equals(theme) ? K9.THEME_DARK : K9.THEME_LIGHT);
|
||||
}
|
||||
|
||||
SharedPreferences sPrefs = preferences.getPreferences();
|
||||
|
@ -43,27 +43,6 @@ import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBodyPart;
|
||||
import com.fsck.k9.provider.AttachmentProvider;
|
||||
|
||||
public class AttachmentView extends FrameLayout implements OnClickListener, OnLongClickListener {
|
||||
/**
|
||||
* Regular expression that represents characters we won't allow in file names.
|
||||
*
|
||||
* <p>
|
||||
* Allowed are:
|
||||
* <ul>
|
||||
* <li>word characters (letters, digits, and underscores): {@code \w}</li>
|
||||
* <li>spaces: {@code " "}</li>
|
||||
* <li>special characters: {@code !}, {@code #}, {@code $}, {@code %}, {@code &}, {@code '},
|
||||
* {@code (}, {@code )}, {@code -}, {@code @}, {@code ^}, {@code `}, <code>{</code>,
|
||||
* <code>}</code>, {@code ~}, {@code .}, {@code ,}</li>
|
||||
* </ul></p>
|
||||
*/
|
||||
private static final String INVALID_CHARACTERS = "[^\\w !#$%&'()\\-@\\^`{}~.,]+";
|
||||
|
||||
/**
|
||||
* Invalid characters in a file name are replaced by this character.
|
||||
*/
|
||||
private static final String REPLACEMENT_CHARACTER = "_";
|
||||
|
||||
|
||||
private Context mContext;
|
||||
public Button viewButton;
|
||||
public Button downloadButton;
|
||||
@ -259,7 +238,7 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
|
||||
*/
|
||||
public void writeFile(File directory) {
|
||||
try {
|
||||
String filename = sanitizeFilename(name);
|
||||
String filename = Utility.sanitizeFilename(name);
|
||||
File file = Utility.createUniqueFile(directory, filename);
|
||||
Uri uri = AttachmentProvider.getAttachmentUri(mAccount, part.getAttachmentId());
|
||||
InputStream in = mContext.getContentResolver().openInputStream(uri);
|
||||
@ -278,18 +257,6 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace characters we don't allow in file names with a replacement character.
|
||||
*
|
||||
* @param filename
|
||||
* The original file name.
|
||||
*
|
||||
* @return The sanitized file name containing only allowed characters.
|
||||
*/
|
||||
private String sanitizeFilename(String filename) {
|
||||
return filename.replaceAll(INVALID_CHARACTERS, REPLACEMENT_CHARACTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* saves the file to the defaultpath setting in the config, or if the config
|
||||
* is not set => to the Environment
|
||||
|
@ -50,6 +50,7 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
|
||||
private View mChip;
|
||||
private View mChip2;
|
||||
private View mChip3;
|
||||
private CheckBox mFlagged;
|
||||
private LinearLayout mToContainerView;
|
||||
private LinearLayout mCcContainerView;
|
||||
@ -62,6 +63,8 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
private ImageView mShowAdditionalHeadersIcon;
|
||||
private SavedState mSavedState;
|
||||
|
||||
private OnLayoutChangedListener mOnLayoutChangedListener;
|
||||
|
||||
/**
|
||||
* Pair class is only available since API Level 5, so we need
|
||||
* this helper class unfortunately
|
||||
@ -95,6 +98,7 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
mAdditionalHeadersView = (TextView) findViewById(R.id.additional_headers_view);
|
||||
mChip = findViewById(R.id.chip);
|
||||
mChip2 = findViewById(R.id.chip2);
|
||||
mChip3 = findViewById(R.id.chip3);
|
||||
mDateView = (TextView) findViewById(R.id.date);
|
||||
mTimeView = (TextView) findViewById(R.id.time);
|
||||
mFlagged = (CheckBox) findViewById(R.id.flagged);
|
||||
@ -115,12 +119,16 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
((TextView) findViewById(R.id.cc_label)).setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageViewCC());
|
||||
|
||||
findViewById(R.id.show_additional_headers_area).setOnClickListener(this);
|
||||
findViewById(R.id.additional_headers_row).setOnClickListener(this);
|
||||
mFromView.setOnClickListener(this);
|
||||
mToView.setOnClickListener(this);
|
||||
mCcView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.additional_headers_row:
|
||||
case R.id.show_additional_headers_area: {
|
||||
onShowAdditionalHeaders();
|
||||
break;
|
||||
@ -129,6 +137,11 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
onAddSenderToContacts();
|
||||
break;
|
||||
}
|
||||
case R.id.to:
|
||||
case R.id.cc: {
|
||||
expand((TextView)view, ((TextView)view).getEllipsize() != null);
|
||||
layoutChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,6 +267,8 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
mChip.getBackground().setAlpha(chipColorAlpha);
|
||||
mChip2.setBackgroundColor(chipColor);
|
||||
mChip2.getBackground().setAlpha(chipColorAlpha);
|
||||
mChip3.setBackgroundColor(chipColor);
|
||||
mChip3.getBackground().setAlpha(chipColorAlpha);
|
||||
|
||||
setVisibility(View.VISIBLE);
|
||||
|
||||
@ -271,8 +286,26 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
int currentVisibility = mAdditionalHeadersView.getVisibility();
|
||||
if (currentVisibility == View.VISIBLE) {
|
||||
hideAdditionalHeaders();
|
||||
expand(mToView, false);
|
||||
expand(mCcView, false);
|
||||
} else {
|
||||
showAdditionalHeaders();
|
||||
expand(mToView, true);
|
||||
expand(mCcView, true);
|
||||
}
|
||||
layoutChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand or collapse a TextView by removing or adding the 2 lines limitation
|
||||
*/
|
||||
private void expand(TextView v, boolean expand) {
|
||||
if (expand) {
|
||||
v.setMaxLines(Integer.MAX_VALUE);
|
||||
v.setEllipsize(null);
|
||||
} else {
|
||||
v.setMaxLines(2);
|
||||
v.setEllipsize(android.text.TextUtils.TruncateAt.END);
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,4 +413,18 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
out.writeInt((this.additionalHeadersVisible) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnLayoutChangedListener {
|
||||
void onLayoutChanged();
|
||||
}
|
||||
|
||||
public void setOnLayoutChangedListener(OnLayoutChangedListener listener) {
|
||||
mOnLayoutChangedListener = listener;
|
||||
}
|
||||
|
||||
private void layoutChanged() {
|
||||
if (mOnLayoutChangedListener != null) {
|
||||
mOnLayoutChangedListener.onLayoutChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,12 @@ public class MessageWebView extends WebView {
|
||||
this.setScrollBarStyle(SCROLLBARS_INSIDE_OVERLAY);
|
||||
this.setLongClickable(true);
|
||||
|
||||
if (K9.getK9Theme() == K9.THEME_DARK) {
|
||||
// Black theme should get a black webview background
|
||||
// we'll set the background of the messages on load
|
||||
this.setBackgroundColor(0xff000000);
|
||||
}
|
||||
|
||||
final WebSettings webSettings = this.getSettings();
|
||||
|
||||
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
|
||||
@ -104,6 +110,19 @@ public class MessageWebView extends WebView {
|
||||
|
||||
}
|
||||
|
||||
public void setText(String text, String contentType) {
|
||||
String content = text;
|
||||
if (K9.getK9Theme() == K9.THEME_DARK) {
|
||||
// It's a little wrong to just throw in the <style> before the opening <html>
|
||||
// but it's less wrong than trying to edit the html stream
|
||||
content = "<style>* { background: black ! important; color: white !important }" +
|
||||
":link, :link * { color: #CCFF33 !important }" +
|
||||
":visited, :visited * { color: #551A8B !important }</style> "
|
||||
+ content;
|
||||
}
|
||||
loadDataWithBaseURL("http://", content, contentType, "utf-8", null);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emulate the shift key being pressed to trigger the text selection mode
|
||||
* of a WebView.
|
||||
|
@ -7,16 +7,26 @@ import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MenuItem.OnMenuItemClickListener;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.*;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebView.HitTestResult;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.R;
|
||||
@ -25,15 +35,51 @@ import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.crypto.CryptoProvider;
|
||||
import com.fsck.k9.crypto.PgpData;
|
||||
import com.fsck.k9.helper.ClipboardManager;
|
||||
import com.fsck.k9.helper.Contacts;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.*;
|
||||
import com.fsck.k9.mail.internet.MimeUtility;
|
||||
import com.fsck.k9.mail.store.LocalStore;
|
||||
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
|
||||
import com.fsck.k9.provider.AttachmentProvider.AttachmentProviderColumns;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
MessageHeader.OnLayoutChangedListener, OnCreateContextMenuListener {
|
||||
private static final int MENU_ITEM_LINK_VIEW = Menu.FIRST;
|
||||
private static final int MENU_ITEM_LINK_SHARE = Menu.FIRST + 1;
|
||||
private static final int MENU_ITEM_LINK_COPY = Menu.FIRST + 2;
|
||||
|
||||
private static final int MENU_ITEM_IMAGE_VIEW = Menu.FIRST;
|
||||
private static final int MENU_ITEM_IMAGE_SAVE = Menu.FIRST + 1;
|
||||
private static final int MENU_ITEM_IMAGE_COPY = Menu.FIRST + 2;
|
||||
|
||||
private static final int MENU_ITEM_PHONE_CALL = Menu.FIRST;
|
||||
private static final int MENU_ITEM_PHONE_SAVE = Menu.FIRST + 1;
|
||||
private static final int MENU_ITEM_PHONE_COPY = Menu.FIRST + 2;
|
||||
|
||||
private static final int MENU_ITEM_EMAIL_SEND = Menu.FIRST;
|
||||
private static final int MENU_ITEM_EMAIL_SAVE = Menu.FIRST + 1;
|
||||
private static final int MENU_ITEM_EMAIL_COPY = Menu.FIRST + 2;
|
||||
|
||||
private static final String[] ATTACHMENT_PROJECTION = new String[] {
|
||||
AttachmentProviderColumns._ID,
|
||||
AttachmentProviderColumns.DISPLAY_NAME
|
||||
};
|
||||
private static final int DISPLAY_NAME_INDEX = 1;
|
||||
|
||||
|
||||
private boolean mScreenReaderEnabled;
|
||||
private MessageCryptoView mCryptoView;
|
||||
private MessageWebView mMessageContentView;
|
||||
@ -56,15 +102,20 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
private View mAttachmentsContainer;
|
||||
private LinearLayout mInsideAttachmentsContainer;
|
||||
private SavedState mSavedState;
|
||||
private ClipboardManager mClipboardManager;
|
||||
|
||||
|
||||
public void initialize(Activity activity) {
|
||||
mMessageContentView = (MessageWebView) findViewById(R.id.message_content);
|
||||
mAccessibleMessageContentView = (AccessibleWebView) findViewById(R.id.accessible_message_content);
|
||||
mMessageContentView.configure();
|
||||
activity.registerForContextMenu(mMessageContentView);
|
||||
mMessageContentView.setOnCreateContextMenuListener(this);
|
||||
|
||||
mHeaderPlaceHolder = (LinearLayout) findViewById(R.id.message_view_header_container);
|
||||
|
||||
mHeaderContainer = (MessageHeader) findViewById(R.id.header_container);
|
||||
mHeaderContainer.setOnLayoutChangedListener(this);
|
||||
|
||||
mAttachmentsContainer = findViewById(R.id.attachments_container);
|
||||
mInsideAttachmentsContainer = (LinearLayout) findViewById(R.id.inside_attachments_container);
|
||||
@ -112,6 +163,210 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
mShowMessageAction.setOnClickListener(this);
|
||||
mShowAttachmentsAction.setOnClickListener(this);
|
||||
mShowPicturesAction.setOnClickListener(this);
|
||||
|
||||
mClipboardManager = ClipboardManager.getInstance(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu);
|
||||
|
||||
WebView webview = (WebView) v;
|
||||
WebView.HitTestResult result = webview.getHitTestResult();
|
||||
int type = result.getType();
|
||||
Context context = getContext();
|
||||
|
||||
switch (type) {
|
||||
case HitTestResult.SRC_ANCHOR_TYPE: {
|
||||
final String url = result.getExtra();
|
||||
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ITEM_LINK_VIEW: {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
getContext().startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_LINK_SHARE: {
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(Intent.EXTRA_TEXT, url);
|
||||
getContext().startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_LINK_COPY: {
|
||||
String label = getContext().getString(
|
||||
R.string.webview_contextmenu_link_clipboard_label);
|
||||
mClipboardManager.setText(label, url);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
menu.setHeaderTitle(url);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_LINK_VIEW, 0,
|
||||
context.getString(R.string.webview_contextmenu_link_view_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_LINK_SHARE, 1,
|
||||
context.getString(R.string.webview_contextmenu_link_share_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_LINK_COPY, 2,
|
||||
context.getString(R.string.webview_contextmenu_link_copy_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
break;
|
||||
}
|
||||
case HitTestResult.IMAGE_TYPE:
|
||||
case HitTestResult.SRC_IMAGE_ANCHOR_TYPE: {
|
||||
final String url = result.getExtra();
|
||||
final boolean externalImage = url.startsWith("http");
|
||||
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ITEM_IMAGE_VIEW: {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
if (!externalImage) {
|
||||
// Grant read permission if this points to our
|
||||
// AttachmentProvider
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
}
|
||||
getContext().startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_IMAGE_SAVE: {
|
||||
new DownloadImageTask().execute(url);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_IMAGE_COPY: {
|
||||
String label = getContext().getString(
|
||||
R.string.webview_contextmenu_image_clipboard_label);
|
||||
mClipboardManager.setText(label, url);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
menu.setHeaderTitle((externalImage) ?
|
||||
url : context.getString(R.string.webview_contextmenu_image_title));
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_IMAGE_VIEW, 0,
|
||||
context.getString(R.string.webview_contextmenu_image_view_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_IMAGE_SAVE, 1,
|
||||
(externalImage) ?
|
||||
context.getString(R.string.webview_contextmenu_image_download_action) :
|
||||
context.getString(R.string.webview_contextmenu_image_save_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
if (externalImage) {
|
||||
menu.add(Menu.NONE, MENU_ITEM_IMAGE_COPY, 2,
|
||||
context.getString(R.string.webview_contextmenu_image_copy_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case HitTestResult.PHONE_TYPE: {
|
||||
final String phoneNumber = result.getExtra();
|
||||
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ITEM_PHONE_CALL: {
|
||||
Uri uri = Uri.parse(WebView.SCHEME_TEL + phoneNumber);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
getContext().startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_PHONE_SAVE: {
|
||||
Contacts contacts = Contacts.getInstance(getContext());
|
||||
contacts.addPhoneContact(phoneNumber);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_PHONE_COPY: {
|
||||
String label = getContext().getString(
|
||||
R.string.webview_contextmenu_phone_clipboard_label);
|
||||
mClipboardManager.setText(label, phoneNumber);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
menu.setHeaderTitle(phoneNumber);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_PHONE_CALL, 0,
|
||||
context.getString(R.string.webview_contextmenu_phone_call_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_PHONE_SAVE, 1,
|
||||
context.getString(R.string.webview_contextmenu_phone_save_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_PHONE_COPY, 2,
|
||||
context.getString(R.string.webview_contextmenu_phone_copy_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
break;
|
||||
}
|
||||
case WebView.HitTestResult.EMAIL_TYPE: {
|
||||
final String email = result.getExtra();
|
||||
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ITEM_EMAIL_SEND: {
|
||||
Uri uri = Uri.parse(WebView.SCHEME_MAILTO + email);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
getContext().startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_EMAIL_SAVE: {
|
||||
Contacts contacts = Contacts.getInstance(getContext());
|
||||
contacts.createContact(new Address(email));
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_EMAIL_COPY: {
|
||||
String label = getContext().getString(
|
||||
R.string.webview_contextmenu_email_clipboard_label);
|
||||
mClipboardManager.setText(label, email);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
menu.setHeaderTitle(email);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_EMAIL_SEND, 0,
|
||||
context.getString(R.string.webview_contextmenu_email_send_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_EMAIL_SAVE, 1,
|
||||
context.getString(R.string.webview_contextmenu_email_save_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_EMAIL_COPY, 2,
|
||||
context.getString(R.string.webview_contextmenu_email_copy_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -345,7 +600,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
if (mScreenReaderEnabled) {
|
||||
mAccessibleMessageContentView.loadDataWithBaseURL("http://", emailText, contentType, "utf-8", null);
|
||||
} else {
|
||||
mMessageContentView.loadDataWithBaseURL("http://", emailText, contentType, "utf-8", null);
|
||||
mMessageContentView.setText(emailText, contentType);
|
||||
mMessageContentView.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
@ -508,6 +763,12 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
mSavedState = savedState;
|
||||
}
|
||||
|
||||
public void onLayoutChanged() {
|
||||
if (mMessageContentView != null) {
|
||||
mMessageContentView.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
static class SavedState extends BaseSavedState {
|
||||
boolean attachmentViewVisible;
|
||||
boolean hiddenAttachmentsVisible;
|
||||
@ -547,4 +808,117 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
out.writeInt((this.showPictures) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
class DownloadImageTask extends AsyncTask<String, Void, String> {
|
||||
@Override
|
||||
protected String doInBackground(String... params) {
|
||||
String urlString = params[0];
|
||||
try {
|
||||
boolean externalImage = urlString.startsWith("http");
|
||||
|
||||
String filename = null;
|
||||
String mimeType = null;
|
||||
InputStream in = null;
|
||||
|
||||
try {
|
||||
if (externalImage) {
|
||||
URL url = new URL(urlString);
|
||||
URLConnection conn = url.openConnection();
|
||||
in = conn.getInputStream();
|
||||
|
||||
String path = url.getPath();
|
||||
|
||||
// Try to get the filename from the URL
|
||||
int start = path.lastIndexOf("/");
|
||||
if (start != -1 && start + 1 < path.length()) {
|
||||
filename = URLDecoder.decode(path.substring(start + 1), "UTF-8");
|
||||
} else {
|
||||
// Use a dummy filename if necessary
|
||||
filename = "saved_image";
|
||||
}
|
||||
|
||||
// Get the MIME type if we couldn't find a file extension
|
||||
if (filename.indexOf('.') == -1) {
|
||||
mimeType = conn.getContentType();
|
||||
}
|
||||
} else {
|
||||
ContentResolver contentResolver = getContext().getContentResolver();
|
||||
Uri uri = Uri.parse(urlString);
|
||||
|
||||
// Get the filename from AttachmentProvider
|
||||
Cursor cursor = contentResolver.query(uri, ATTACHMENT_PROJECTION, null, null, null);
|
||||
if (cursor != null) {
|
||||
try {
|
||||
if (cursor.moveToNext()) {
|
||||
filename = cursor.getString(DISPLAY_NAME_INDEX);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Use a dummy filename if necessary
|
||||
if (filename == null) {
|
||||
filename = "saved_image";
|
||||
}
|
||||
|
||||
// Get the MIME type if we couldn't find a file extension
|
||||
if (filename.indexOf('.') == -1) {
|
||||
mimeType = contentResolver.getType(uri);
|
||||
}
|
||||
|
||||
in = contentResolver.openInputStream(uri);
|
||||
}
|
||||
|
||||
// Do we still need an extension?
|
||||
if (filename.indexOf('.') == -1) {
|
||||
// Use JPEG as fallback
|
||||
String extension = "jpeg";
|
||||
if (mimeType != null) {
|
||||
// Try to find an extension for the given MIME type
|
||||
String ext = MimeUtility.getExtensionByMimeType(mimeType);
|
||||
if (ext != null) {
|
||||
extension = ext;
|
||||
}
|
||||
}
|
||||
filename += "." + extension;
|
||||
}
|
||||
|
||||
String sanitized = Utility.sanitizeFilename(filename);
|
||||
|
||||
File directory = new File(K9.getAttachmentDefaultPath());
|
||||
File file = Utility.createUniqueFile(directory, sanitized);
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
try {
|
||||
IOUtils.copy(in, out);
|
||||
out.flush();
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
|
||||
return file.getName();
|
||||
|
||||
} finally {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String filename) {
|
||||
String text;
|
||||
if (filename == null) {
|
||||
text = getContext().getString(R.string.image_saving_failed);
|
||||
} else {
|
||||
text = getContext().getString(R.string.image_saved_as, filename);
|
||||
}
|
||||
|
||||
Toast.makeText(getContext(), text, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
39
tests/src/com/fsck/k9/mail/internet/MimeUtilityTest.java
Normal file
39
tests/src/com/fsck/k9/mail/internet/MimeUtilityTest.java
Normal file
@ -0,0 +1,39 @@
|
||||
package com.fsck.k9.mail.internet;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
public class MimeUtilityTest extends AndroidTestCase {
|
||||
|
||||
public void testGetHeaderParameter() {
|
||||
String result;
|
||||
|
||||
/* Test edge cases */
|
||||
result = MimeUtility.getHeaderParameter(";", null);
|
||||
assertEquals(null, result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name", "name");
|
||||
assertEquals(null, result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name=", "name");
|
||||
assertEquals("", result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name=\"", "name");
|
||||
assertEquals("\"", result);
|
||||
|
||||
/* Test expected cases */
|
||||
result = MimeUtility.getHeaderParameter("name=value", "name");
|
||||
assertEquals("value", result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name = value", "name");
|
||||
assertEquals("value", result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name=\"value\"", "name");
|
||||
assertEquals("value", result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name = \"value\"" , "name");
|
||||
assertEquals("value", result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name=\"\"", "name");
|
||||
assertEquals("", result);
|
||||
}
|
||||
}
|
@ -59,6 +59,36 @@ public class ImapResponseParserTest extends TestCase {
|
||||
assertEquals("token2", respTextCode.get(1));
|
||||
}
|
||||
|
||||
public void testImapListMethods() throws IOException {
|
||||
ImapList list = new ImapList();
|
||||
list.add("ONE");
|
||||
list.add("TWO");
|
||||
list.add("THREE");
|
||||
|
||||
assertTrue(list.containsKey("ONE"));
|
||||
assertTrue(list.containsKey("TWO"));
|
||||
assertFalse(list.containsKey("THREE"));
|
||||
assertFalse(list.containsKey("nonexistent"));
|
||||
|
||||
assertEquals("TWO", list.getKeyedValue("ONE"));
|
||||
assertEquals("THREE", list.getKeyedValue("TWO"));
|
||||
assertNull(list.getKeyedValue("THREE"));
|
||||
assertNull(list.getKeyedValue("nonexistent"));
|
||||
|
||||
assertEquals(0, list.getKeyIndex("ONE"));
|
||||
assertEquals(1, list.getKeyIndex("TWO"));
|
||||
|
||||
try {
|
||||
list.getKeyIndex("THREE");
|
||||
fail("IllegalArgumentException should have been thrown");
|
||||
} catch (IllegalArgumentException e) { /* do nothing */ }
|
||||
|
||||
try {
|
||||
list.getKeyIndex("nonexistent");
|
||||
fail("IllegalArgumentException should have been thrown");
|
||||
} catch (IllegalArgumentException e) { /* do nothing */ }
|
||||
}
|
||||
|
||||
private ImapResponseParser createParser(String response) {
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(response.getBytes());
|
||||
PeekableInputStream pin = new PeekableInputStream(in);
|
||||
|
125
tests/src/com/fsck/k9/mail/store/imap/ImapUtilityTest.java
Normal file
125
tests/src/com/fsck/k9/mail/store/imap/ImapUtilityTest.java
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The K-9 Dog Walkers
|
||||
* Copyright (C) 2011 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.
|
||||
*/
|
||||
|
||||
package com.fsck.k9.mail.store.imap;
|
||||
|
||||
import java.util.List;
|
||||
import android.test.MoreAsserts;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class ImapUtilityTest extends TestCase {
|
||||
/**
|
||||
* Test getting elements of an IMAP sequence set.
|
||||
*/
|
||||
public void testGetImapSequenceValues() {
|
||||
String[] expected;
|
||||
List<String> actual;
|
||||
|
||||
// Test valid sets
|
||||
expected = new String[] {"1"};
|
||||
actual = ImapUtility.getImapSequenceValues("1");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[] {"1", "3", "2"};
|
||||
actual = ImapUtility.getImapSequenceValues("1,3,2");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[] {"4", "5", "6"};
|
||||
actual = ImapUtility.getImapSequenceValues("4:6");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[] {"9", "8", "7"};
|
||||
actual = ImapUtility.getImapSequenceValues("9:7");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[] {"1", "2", "3", "4", "9", "8", "7"};
|
||||
actual = ImapUtility.getImapSequenceValues("1,2:4,9:7");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
// Test partially invalid sets
|
||||
expected = new String[] { "1", "5" };
|
||||
actual = ImapUtility.getImapSequenceValues("1,x,5");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[] { "1", "2", "3" };
|
||||
actual = ImapUtility.getImapSequenceValues("a:d,1:3");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
// Test invalid sets
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapSequenceValues("");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapSequenceValues(null);
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapSequenceValues("a");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapSequenceValues("1:x");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting elements of an IMAP range.
|
||||
*/
|
||||
public void testGetImapRangeValues() {
|
||||
String[] expected;
|
||||
List<String> actual;
|
||||
|
||||
// Test valid ranges
|
||||
expected = new String[] {"1", "2", "3"};
|
||||
actual = ImapUtility.getImapRangeValues("1:3");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[] {"16", "15", "14"};
|
||||
actual = ImapUtility.getImapRangeValues("16:14");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
// Test in-valid ranges
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapRangeValues("");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapRangeValues(null);
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapRangeValues("a");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapRangeValues("6");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapRangeValues("1:3,6");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapRangeValues("1:x");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
|
||||
expected = new String[0];
|
||||
actual = ImapUtility.getImapRangeValues("1:*");
|
||||
MoreAsserts.assertEquals(expected, actual.toArray());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user