Merge "Fix bug where constructing message attachment uri with null/empty partId will remove the trailing backslash, causing the uri to not match the expected pattern." into jb-ub-mail-ur9
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ff40c23..24fa2b2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -143,12 +143,6 @@
<provider android:name="com.android.mail.providers.SuggestionsProvider"
android:authorities="com.android.mail.suggestionsprovider" />
- <receiver android:name=".providers.protos.boot.AccountReceiver">
- <intent-filter>
- <action android:name="com.android.mail.providers.protos.boot.intent.ACTION_PROVIDER_CREATED" />
- </intent-filter>
- </receiver>
-
<service android:name=".compose.EmptyService"/>
<!-- Widget -->
diff --git a/assets/script.js b/assets/script.js
index c4f3ae6..51a9d69 100644
--- a/assets/script.js
+++ b/assets/script.js
@@ -28,7 +28,9 @@
* to shrink by this much. Expressed as a ratio of:
* (original width difference : width difference after transforms);
*/
-TRANSFORM_MINIMUM_EFFECTIVE_RATIO = 0.75;
+TRANSFORM_MINIMUM_EFFECTIVE_RATIO = 0.7;
+
+var gTransformText = {};
/**
* Returns the page offset of an element.
@@ -182,9 +184,7 @@
el.style.zoom = 1;
}
newZoom = documentWidth / el.scrollWidth;
- if (ENABLE_MUNGE_TABLES) {
- mungeTables(el, documentWidth, el.scrollWidth);
- }
+ transformContent(el, documentWidth, el.scrollWidth);
newZoom = documentWidth / el.scrollWidth;
if (NORMALIZE_MESSAGE_WIDTHS) {
el.style.zoom = newZoom;
@@ -192,97 +192,141 @@
}
}
-function mungeTables(el, docWidth, elWidth) {
+function transformContent(el, docWidth, elWidth) {
var nodes;
var i, len;
+ var index;
var newWidth = elWidth;
var wStr;
var touched;
+ // the format of entries in this array is:
+ // entry := [ undoFunction, undoFunctionThis, undoFunctionParamArray ]
var actionLog = [];
var node;
+ var done = false;
+ var msgId;
+ var transformText;
+ var existingText;
+ var textElement;
var start;
if (elWidth <= docWidth) {
return;
}
start = Date.now();
- // Try munging all divs with inline styles where the width
+
+ if (el.parentElement.classList.contains("mail-message")) {
+ msgId = el.parentElement.id;
+ transformText = "[origW=" + elWidth + "/" + docWidth;
+ }
+
+ // Try munging all divs or textareas with inline styles where the width
// is wider than docWidth, and change it to be a max-width.
touched = false;
- nodes = el.querySelectorAll("div[style]");
- for (i = 0, len = nodes.length; i < len; i++) {
- node = nodes[i];
- wStr = node.style.width;
- if (wStr && wStr.slice(0, -2) > docWidth) {
- node.style.width = "";
- node.style.maxWidth = wStr;
- touched = true;
- }
- }
+ nodes = ENABLE_MUNGE_TABLES ? el.querySelectorAll("div[style], textarea[style]") : [];
+ touched = transformBlockElements(nodes, docWidth, actionLog);
if (touched) {
newWidth = el.scrollWidth;
console.log("ran div-width munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth
+ " docW=" + docWidth);
+ if (msgId) {
+ transformText += " DIV:newW=" + newWidth;
+ }
if (newWidth <= docWidth) {
- console.log("munger succeeded, elapsed time=" + (Date.now() - start));
- return;
+ done = true;
}
}
- // OK, that wasn't enough. Find tables with widths and override their widths.
- touched = addClassToElements(el.querySelectorAll("table"), shouldMungeTable, "munged",
- actionLog);
- if (touched) {
- newWidth = el.scrollWidth;
- console.log("ran table munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth
- + " docW=" + docWidth);
- if (newWidth <= docWidth) {
- console.log("munger succeeded, elapsed time=" + (Date.now() - start));
- return;
+ if (!done) {
+ // OK, that wasn't enough. Find images with widths and override their widths.
+ nodes = ENABLE_MUNGE_IMAGES ? el.querySelectorAll("img") : [];
+ touched = transformImages(nodes, docWidth, actionLog);
+ if (touched) {
+ newWidth = el.scrollWidth;
+ console.log("ran img munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth
+ + " docW=" + docWidth);
+ if (msgId) {
+ transformText += " IMG:newW=" + newWidth;
+ }
+ if (newWidth <= docWidth) {
+ done = true;
+ }
}
}
- // OK, that wasn't enough. Try munging all <td> to override any width and nowrap set.
- touched = addClassToElements(el.querySelectorAll("td"), null /* mungeAll */, "munged",
- actionLog);
- if (touched) {
- newWidth = el.scrollWidth;
- console.log("ran td munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth
- + " docW=" + docWidth);
- if (newWidth <= docWidth) {
- console.log("munger succeeded, elapsed time=" + (Date.now() - start));
- return;
+ if (!done) {
+ // OK, that wasn't enough. Find tables with widths and override their widths.
+ nodes = ENABLE_MUNGE_TABLES ? el.querySelectorAll("table") : [];
+ touched = addClassToElements(nodes, shouldMungeTable, "munged",
+ actionLog);
+ if (touched) {
+ newWidth = el.scrollWidth;
+ console.log("ran table munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth
+ + " docW=" + docWidth);
+ if (msgId) {
+ transformText += " TABLE:newW=" + newWidth;
+ }
+ if (newWidth <= docWidth) {
+ done = true;
+ }
}
}
- // OK, that wasn't enough. Try further munging all <td> to override text wrapping.
- touched = addClassToElements(el.querySelectorAll("td"), null /* mungeAll */, "munged2",
- actionLog);
- if (touched) {
- newWidth = el.scrollWidth;
- console.log("ran td munger2 on el=" + el + " oldW=" + elWidth + " newW=" + newWidth
- + " docW=" + docWidth);
- if (newWidth <= docWidth) {
- console.log("munger succeeded, elapsed time=" + (Date.now() - start));
- return;
+ if (!done) {
+ // OK, that wasn't enough. Try munging all <td> to override any width and nowrap set.
+ nodes = ENABLE_MUNGE_TABLES ? el.querySelectorAll("td") : [];
+ touched = addClassToElements(nodes, null /* mungeAll */, "munged",
+ actionLog);
+ if (touched) {
+ newWidth = el.scrollWidth;
+ console.log("ran td munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth
+ + " docW=" + docWidth);
+ if (msgId) {
+ transformText += " TD:newW=" + newWidth;
+ }
+ if (newWidth <= docWidth) {
+ done = true;
+ }
}
}
// If the transformations shrank the width significantly enough, leave them in place.
// We figure that in those cases, the benefits outweight the risk of rendering artifacts.
- //
- // TODO: this is a risky transform that should not be attempted on sufficiently complex mail.
- // (TBD how to measure that)
- if ((elWidth - newWidth) / (elWidth - docWidth) > TRANSFORM_MINIMUM_EFFECTIVE_RATIO) {
- console.log("transform(s) deemed effective enough. elapsed time="
- + (Date.now() - start));
+ if (!done && (elWidth - newWidth) / (elWidth - docWidth) >
+ TRANSFORM_MINIMUM_EFFECTIVE_RATIO) {
+ console.log("transform(s) deemed effective enough");
+ done = true;
+ }
+
+ if (done) {
+ if (msgId) {
+ transformText += "]";
+ existingText = gTransformText[msgId];
+ if (!existingText) {
+ transformText = "Message transforms: " + transformText;
+ } else {
+ transformText = existingText + " " + transformText;
+ }
+ gTransformText[msgId] = transformText;
+ window.mail.onMessageTransform(msgId, transformText);
+ textElement = el.firstChild;
+ if (!textElement.classList || !textElement.classList.contains("transform-text")) {
+ textElement = document.createElement("div");
+ textElement.classList.add("transform-text");
+ textElement.style.fontSize = "10px";
+ textElement.style.color = "#ccc";
+ el.insertBefore(textElement, el.firstChild);
+ }
+ textElement.innerHTML = transformText + "<br>";
+ }
+ console.log("munger(s) succeeded, elapsed time=" + (Date.now() - start));
return;
}
// reverse all changes if the width is STILL not narrow enough
// (except the width->maxWidth change, which is not particularly destructive)
for (i = 0, len = actionLog.length; i < len; i++) {
- actionLog[i][0].classList.remove(actionLog[i][1]);
+ actionLog[i][0].apply(actionLog[i][1], actionLog[i][2]);
}
if (actionLog.length > 0) {
console.log("all mungers failed, changes reversed. elapsed time=" + (Date.now() - start));
@@ -296,14 +340,75 @@
for (i = 0, len = nodes.length; i < len; i++) {
node = nodes[i];
if (!conditionFn || conditionFn(node)) {
+ if (node.classList.contains(classToAdd)) {
+ continue;
+ }
node.classList.add(classToAdd);
added = true;
- actionLog.push([node, classToAdd]);
+ actionLog.push([node.classList.remove, node.classList, [classToAdd]]);
}
}
return added;
}
+function transformBlockElements(nodes, docWidth, actionLog) {
+ var i, len;
+ var node;
+ var wStr;
+ var index;
+ var touched = false;
+
+ for (i = 0, len = nodes.length; i < len; i++) {
+ node = nodes[i];
+ wStr = node.style.width || node.style.minWidth;
+ index = wStr ? wStr.indexOf("px") : -1;
+ if (index >= 0 && wStr.slice(0, index) > docWidth) {
+ saveStyleProperty(node, "width", actionLog);
+ saveStyleProperty(node, "minWidth", actionLog);
+ saveStyleProperty(node, "maxWidth", actionLog);
+ node.style.width = "100%";
+ node.style.minWidth = "";
+ node.style.maxWidth = wStr;
+ touched = true;
+ }
+ }
+ return touched;
+}
+
+function transformImages(nodes, docWidth, actionLog) {
+ var i, len;
+ var node;
+ var w, h;
+ var touched = false;
+
+ for (i = 0, len = nodes.length; i < len; i++) {
+ node = nodes[i];
+ w = node.offsetWidth;
+ h = node.offsetHeight;
+ // shrink w/h proportionally if the img is wider than available width
+ if (w > docWidth) {
+ saveStyleProperty(node, "maxWidth", actionLog);
+ saveStyleProperty(node, "width", actionLog);
+ saveStyleProperty(node, "height", actionLog);
+ node.style.maxWidth = docWidth + "px";
+ node.style.width = "100%";
+ node.style.height = "auto";
+ touched = true;
+ }
+ }
+ return touched;
+}
+
+function saveStyleProperty(node, property, actionLog) {
+ var savedName = "data-" + property;
+ node.setAttribute(savedName, node.style[property]);
+ actionLog.push([undoSetProperty, node, [property, savedName]]);
+}
+
+function undoSetProperty(property, savedProperty) {
+ this.style[property] = savedProperty ? this.getAttribute(savedProperty) : "";
+}
+
function shouldMungeTable(table) {
return table.hasAttribute("width") || table.style.width;
}
diff --git a/res/layout-sw600dp/account_switch_spinner_item.xml b/res/layout-sw600dp/account_switch_spinner_item.xml
deleted file mode 100644
index c6ee7c1..0000000
--- a/res/layout-sw600dp/account_switch_spinner_item.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2011 Google Inc.
- Licensed to 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.
--->
-
-<!-- View shown in the navigation spinner in the actionbar. -->
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="match_parent"
- android:paddingLeft="0dip"
- android:layout_marginLeft="0dip"
- android:layout_width="match_parent">
-
- <LinearLayout
- android:layout_height="match_parent"
- android:id="@+id/account_spinner_container"
- android:orientation="vertical"
- android:gravity="center_vertical"
- android:background="@drawable/spinner_ab_holo_light"
- android:duplicateParentState="false"
- android:layout_alignParentLeft="true"
- android:focusable="true"
- android:focusableInTouchMode="false"
- style="@style/AccountSpinnerStyle">
- <TextView
- android:id="@+id/account_first"
- style="@style/AccountSpinnerAnchorTextPrimary"
- android:singleLine="true"
- android:ellipsize="end"
- android:includeFontPadding="false"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <TextView
- android:id="@+id/account_second"
- style="@style/AccountSpinnerAnchorTextSecondary"
- android:singleLine="true"
- android:ellipsize="end"
- android:includeFontPadding="false"
- android:layout_marginRight="4dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- </LinearLayout>
-
- <TextView
- android:id="@+id/account_unread"
- android:layout_toRightOf="@id/account_spinner_container"
- style="@style/unreadCountActionBarTablet"/>
-</RelativeLayout>
diff --git a/res/layout/account_switch_spinner_item.xml b/res/layout/account_switch_spinner_item.xml
deleted file mode 100644
index 7681665..0000000
--- a/res/layout/account_switch_spinner_item.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2011 Google Inc.
- Licensed to 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.
--->
-
-<!-- View shown in the navigation spinner in the actionbar. -->
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="match_parent"
- android:paddingLeft="0dip"
- android:layout_marginLeft="0dip"
- android:layout_width="match_parent">
-
- <!-- Place the unread count first, taking all the space it needs
- to fit its content -->
- <TextView
- android:id="@+id/account_unread"
- android:layout_alignParentRight="true"
- android:layout_width="wrap_content"
- android:layout_marginLeft="4dp"
- style="@style/UnreadCountActionBar"/>
-
- <!-- Container to soak up space and ensure that the caret attaches
- to a short label name. This container should be anonymous because nothing
- should reference it.
- Phone only: On tablets, the width of the spinner is a constant for each
- orientation. -->
- <LinearLayout
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:gravity="center_vertical"
- android:clickable="false"
- android:focusable="false"
- android:layout_toLeftOf="@id/account_unread">
-
- <!-- In the container, the label name takes up as much space
- as it needs to show its content: this is to ensure that the
- dropdown caret is flush with the label name. -->
- <LinearLayout
- android:layout_height="match_parent"
- android:id="@+id/account_spinner_container"
- android:orientation="vertical"
- android:gravity="center_vertical"
- android:background="@drawable/spinner_ab_holo_light"
- android:focusable="true"
- android:focusableInTouchMode="false"
- style="@style/AccountSpinnerStyle">
- <TextView
- android:id="@+id/account_first"
- style="@style/AccountSpinnerAnchorTextPrimary"
- android:singleLine="true"
- android:ellipsize="end"
- android:includeFontPadding="false"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <TextView
- android:id="@+id/account_second"
- style="@style/AccountSpinnerAnchorTextSecondary"
- android:singleLine="true"
- android:ellipsize="end"
- android:includeFontPadding="false"
- android:layout_marginRight="4dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- </LinearLayout>
- </LinearLayout>
-</RelativeLayout>
diff --git a/res/layout/actionbar_view.xml b/res/layout/actionbar_view.xml
index ffb6c64..7d4b792 100644
--- a/res/layout/actionbar_view.xml
+++ b/res/layout/actionbar_view.xml
@@ -21,16 +21,10 @@
label, and subject).
-->
<com.android.mail.ui.MailActionBarView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
-
- <com.android.mail.ui.MailSpinner
- android:id="@+id/account_spinner"
- android:layout_height="match_parent"
- style="@style/AccountSwitchSpinnerItem"
- android:clickable="true"/>
-
+ <!-- Only used for displaying a subject view -->
<include layout="@layout/actionbar_subject" />
</com.android.mail.ui.MailActionBarView>
diff --git a/res/layout/folder_expand_item.xml b/res/layout/folder_expand_item.xml
new file mode 100644
index 0000000..5041582
--- /dev/null
+++ b/res/layout/folder_expand_item.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013 Google Inc.
+ Licensed to 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.
+-->
+
+<!-- This is a button for expanding/collapsing emails in FLF -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/folder_expand_item"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/message_details_header_bottom_border_height"
+ android:visibility="visible"
+ android:background="@color/conv_subject_border" />
+
+ <TextView
+ android:id="@+id/folder_expand_text"
+ android:layout_width="match_parent"
+ android:layout_height="48dip"
+ android:layout_marginLeft="@dimen/folder_list_item_left_margin"
+ android:gravity="center_vertical"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:textAllCaps="true"
+ android:textColor="@color/folder_list_heading_text_color"/>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/message_details_header_bottom_border_height"
+ android:visibility="visible"
+ android:background="@color/conv_subject_border" />
+
+ <ImageView
+ android:layout_gravity="top|right"
+ android:layout_marginTop="14dip"
+ android:layout_marginRight="14dip"
+ android:id="@+id/details_expander"
+ style="@style/MessageHeaderExpanderMinimizedStyle" />
+</FrameLayout>
diff --git a/res/layout/search_actionbar_view.xml b/res/layout/search_actionbar_view.xml
index 93d8de8..613d8c4 100644
--- a/res/layout/search_actionbar_view.xml
+++ b/res/layout/search_actionbar_view.xml
@@ -26,15 +26,6 @@
android:layout_height="match_parent"
android:orientation="horizontal" >
- <com.android.mail.ui.MailSpinner
- android:id="@+id/account_spinner"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- style="@style/PlainSpinnerDropdown"
- android:focusableInTouchMode="false"
- android:focusable="false"
- android:clickable="true"/>
-
<include layout="@layout/actionbar_subject" />
</com.android.mail.ui.SearchMailActionBarView>
\ No newline at end of file
diff --git a/res/layout/secure_conversation_view.xml b/res/layout/secure_conversation_view.xml
index 56679f2..da1dae3 100644
--- a/res/layout/secure_conversation_view.xml
+++ b/res/layout/secure_conversation_view.xml
@@ -26,21 +26,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <RelativeLayout android:id="@+id/header"
+ <include layout="@layout/conversation_view_header"
+ android:id="@+id/conv_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <include layout="@layout/conversation_message_header"
+ android:id="@+id/message_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@android:color/white">
- <include layout="@layout/conversation_view_header"
- android:id="@+id/conv_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <include layout="@layout/conversation_message_header"
- android:id="@+id/message_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/conv_header" />
- </RelativeLayout>
+ android:layout_below="@id/conv_header" />
<!-- base WebView layer -->
<WebView
android:id="@+id/webview"
@@ -54,12 +49,6 @@
android:visibility="gone" />
</LinearLayout>
</ScrollView>
- <FrameLayout
- android:id="@+id/conversation_topmost_overlay"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <!-- TODO: scroll indicators go HERE on top of all other layers -->
- </FrameLayout>
<include layout="@layout/conversation_load_spinner"/>
diff --git a/res/menu-sw600dp-port/conversation_list_search_results_actions.xml b/res/menu-sw600dp-port/conversation_list_search_results_actions.xml
index 357ba1b..ba722e6 100644
--- a/res/menu-sw600dp-port/conversation_list_search_results_actions.xml
+++ b/res/menu-sw600dp-port/conversation_list_search_results_actions.xml
@@ -35,11 +35,6 @@
android:icon="@drawable/ic_menu_refresh_holo_light"
android:alphabeticShortcut="@string/trigger_refresh_char" />
- <!-- Available for Folders with SUPPORTS_SETTINGS capability -->
- <item android:id="@+id/folder_options"
- android:title="@string/menu_folder_options"
- android:showAsAction="never" />
-
<item android:id="@+id/settings"
android:title="@string/menu_settings"
android:showAsAction="never" />
diff --git a/res/menu-sw600dp-port/conversation_search_results_actions.xml b/res/menu-sw600dp-port/conversation_search_results_actions.xml
index ca13500..e228059 100644
--- a/res/menu-sw600dp-port/conversation_search_results_actions.xml
+++ b/res/menu-sw600dp-port/conversation_search_results_actions.xml
@@ -51,11 +51,6 @@
android:title="@string/report_spam"
android:showAsAction="never"/>
- <!-- Available for Folders with SUPPORTS_SETTINGS capability -->
- <item android:id="@+id/folder_options"
- android:title="@string/menu_folder_options"
- android:showAsAction="never" />
-
<item android:id="@+id/settings"
android:title="@string/menu_settings"
android:showAsAction="never" />
@@ -72,4 +67,4 @@
android:icon="@android:drawable/ic_menu_help"
android:title="@string/help_and_info" />
-</menu>
\ No newline at end of file
+</menu>
diff --git a/res/menu/conversation_list_menu.xml b/res/menu/conversation_list_menu.xml
index 589097a..76ae716 100644
--- a/res/menu/conversation_list_menu.xml
+++ b/res/menu/conversation_list_menu.xml
@@ -34,7 +34,7 @@
<!-- Always available -->
<item android:id="@+id/show_all_folders"
android:title="@string/show_all_folders"
- android:showAsAction="ifRoom"
+ android:showAsAction="never"
android:icon="@drawable/ic_menu_folders_holo_light" />
<!-- Always available -->
diff --git a/res/menu/message_header_overflow_menu.xml b/res/menu/message_header_overflow_menu.xml
index e3e9f0b..035eca2 100644
--- a/res/menu/message_header_overflow_menu.xml
+++ b/res/menu/message_header_overflow_menu.xml
@@ -26,4 +26,10 @@
<item android:id="@+id/forward"
android:icon="@drawable/ic_forward_holo_dark"
android:title="@string/forward" />
+ <item android:id="@+id/report_rendering_problem"
+ android:icon="@drawable/ic_forward_holo_dark"
+ android:title="@string/report_rendering_problem" />
+ <item android:id="@+id/report_rendering_improvement"
+ android:icon="@drawable/ic_forward_holo_dark"
+ android:title="@string/report_rendering_improvement" />
</menu>
diff --git a/res/raw/template_conversation_lower.html b/res/raw/template_conversation_lower.html
index bbcbd4f..b128077 100644
--- a/res/raw/template_conversation_lower.html
+++ b/res/raw/template_conversation_lower.html
@@ -10,6 +10,7 @@
var ENABLE_CONTENT_READY = %s;
var NORMALIZE_MESSAGE_WIDTHS = %s;
var ENABLE_MUNGE_TABLES = %s;
+ var ENABLE_MUNGE_IMAGES = %s;
</script>
<script type="text/javascript" src="file:///android_asset/script.js"></script>
</html>
diff --git a/res/raw/template_conversation_upper.html b/res/raw/template_conversation_upper.html
index 1b3ecce..6222762 100644
--- a/res/raw/template_conversation_upper.html
+++ b/res/raw/template_conversation_upper.html
@@ -21,6 +21,12 @@
body {
font-size: 80%%;
}
+ blockquote {
+ margin-left: 0.8ex !important;
+ margin-right: 0 !important;
+ border-left:1px #ccc solid !important;
+ padding-left: 1ex !important;
+ }
table.munged {
width: auto !important;
}
@@ -28,10 +34,6 @@
width: auto !important;
white-space: normal !important;
}
- td.munged2 {
- word-break: break-all !important;
- word-wrap: break-word !important;
- }
.initial-load {
/* 0x0 and 1x1 may be short-circuited by WebView */
width: 2px;
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index fd7c593..e2e55c0 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Skuif na"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Vouerinstellings"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Vouers"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sinkroniseer en stel in kennis"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Vouerinstellings"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Rekeninginstellings"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Het vouer verander."</item>
<item quantity="other" msgid="8918589141287976985">"Het vouers verander."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Resultate"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Search word nie ondersteun op hierdie rekening nie."</string>
<string name="searchMode" msgid="3329807422114758583">"Soekmodus"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index aea32ca..5b832d4 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"አንቀሳቅስ ወደ"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"የአቃፊ ቅንብሮች"</string>
<string name="folder_list_title" msgid="4276644062440415214">"አቃፊዎች"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"አመሳስልና አሳውቅ"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"የአቃፊ ቅንብሮች"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"የመለያ ቅንብሮች"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"የተቀየረ አቃፊ። የተለወጠ አቃፊ።"</item>
<item quantity="other" msgid="8918589141287976985">"የተቀየሩ አቃፊዎች።"</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"ውጤቶች"</string>
<string name="search_unsupported" msgid="4654227193354052607">"ፍለጋ በዚህ መለያ አይደገፍም።"</string>
<string name="searchMode" msgid="3329807422114758583">"የፍለጋ ሁናቴ"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 9b38a60..cd7f37c 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"نقل إلى"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"إعدادات المجلدات"</string>
<string name="folder_list_title" msgid="4276644062440415214">"المجلدات"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"المزامنة والإشعارات"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"إعدادات المجلد"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"إعدادات الحساب"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"تم تغيير المجلد."</item>
<item quantity="other" msgid="8918589141287976985">"تم تغيير المجلدات."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"النتائج"</string>
<string name="search_unsupported" msgid="4654227193354052607">"لا يمكن استخدام البحث على هذا الحساب."</string>
<string name="searchMode" msgid="3329807422114758583">"وضع البحث"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 9b4a7cc..d119d6c 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Перанесці ў"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Налады тэчкi"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Тэчкі"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Сінхранізацыя і апавяшчэнне"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Налады тэчак"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Налады ўліковага запісу"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Змененая тэчка."</item>
<item quantity="other" msgid="8918589141287976985">"Змененыя тэчкі."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Вынікі"</string>
<string name="search_unsupported" msgid="4654227193354052607">"У гэтым уліковым запісе пошук не падтрымліваецца."</string>
<string name="searchMode" msgid="3329807422114758583">"Рэжым пошуку"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 9bfa480..f35f63d 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Преместване във:"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Настройки за папките"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Папки"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Синхронизиране и известяване"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Настройки за папката"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Настройки на профила"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Променихте папката."</item>
<item quantity="other" msgid="8918589141287976985">"Променихте папките."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Резултати"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Търсенето не се поддържа за този профил."</string>
<string name="searchMode" msgid="3329807422114758583">"Режим на търсене"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 216eaea..8b30f07 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Mou a"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Configuració de la carpeta"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Carpetes"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sincronitza i notifica"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Configuració de la carpeta"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Configuració del compte"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"S\'ha canviat la carpeta."</item>
<item quantity="other" msgid="8918589141287976985">"S\'han canviat les carpetes."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Resultats"</string>
<string name="search_unsupported" msgid="4654227193354052607">"La cerca no és compatible en aquest compte."</string>
<string name="searchMode" msgid="3329807422114758583">"Mode de cerca"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index dfc28cb..487aaad 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Přesunout do"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Nastavení složek"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Složky"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Synchronizace a upozornění"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Nastavení složek"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Nastavení účtu"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Složka změněna."</item>
<item quantity="other" msgid="8918589141287976985">"Složky změněny."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Výsledky"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Vyhledávání není v tomto účtu podporováno."</string>
<string name="searchMode" msgid="3329807422114758583">"Režim vyhledávání"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index b1d97d9..ae7c73a 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Flyt til"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Indstillinger for mapper"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Mapper"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Synkroniser og underret"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Indstillinger for mapper"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Kontoindstillinger"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Ændret mappe."</item>
<item quantity="other" msgid="8918589141287976985">"Ændrede mapper."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Resultater"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Søgningen understøttes ikke på denne konto."</string>
<string name="searchMode" msgid="3329807422114758583">"Søgetilstand"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 4008169..2ca30c3 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Verschieben nach"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Ordnereinstellungen"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Ordner"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Synchron. & benachrichtigen"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Ordnereinstellungen"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Kontoeinstellungen"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Ordner geändert"</item>
<item quantity="other" msgid="8918589141287976985">"Ordner geändert"</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Ergebnisse"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Die Suche wird für dieses Konto nicht unterstützt."</string>
<string name="searchMode" msgid="3329807422114758583">"Suchmodus"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 24550d9..59f1748 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Μετακίνηση σε"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Ρυθμίσεις φακέλων"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Φάκελοι"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Συγχρονισμός και ειδοποίηση"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Ρυθμίσεις φακέλου..."</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Ρυθμίσεις Λογαριασμού"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Αλλαγή φακέλου."</item>
<item quantity="other" msgid="8918589141287976985">"Αλλαγή φακέλων."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Αποτελέσματα"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Η αναζήτηση δεν υποστηρίζεται σε αυτόν τον λογαριασμό."</string>
<string name="searchMode" msgid="3329807422114758583">"Λειτουργία αναζήτησης"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 8a81e56..b3e54f6 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Move to"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Folder settings"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Folders"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sync & notify"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Folder settings"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Account settings"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Changed folder."</item>
<item quantity="other" msgid="8918589141287976985">"Changed folders."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Results"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Search is not supported on this account."</string>
<string name="searchMode" msgid="3329807422114758583">"Search Mode"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 41f0092..3a845c4 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Mover a"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Configuración de carpetas"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Carpetas"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sincronizar y notificar"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Configuración de la carpeta"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Configuración de la cuenta"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Carpeta modificada"</item>
<item quantity="other" msgid="8918589141287976985">"Carpetas modificadas"</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Resultados"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Esta cuenta no admite la función de búsqueda."</string>
<string name="searchMode" msgid="3329807422114758583">"Buscar modo"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index cdc4a42..f6f692c 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Mover a"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Ajustes de carpeta"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Carpetas"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sincronizar y notificar"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Ajustes de carpeta"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Ajustes de cuenta"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Carpeta cambiada"</item>
<item quantity="other" msgid="8918589141287976985">"Carpetas cambiadas"</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Resultados"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Esta cuenta no admite la función de búsqueda."</string>
<string name="searchMode" msgid="3329807422114758583">"Modo de búsqueda"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 250d094..857e31f 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Teisalda asukohta"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Kausta seaded"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Kaustad"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sünkroonimine ja teavitamine"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Kausta seaded"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Konto seaded"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Muudetud kaust."</item>
<item quantity="other" msgid="8918589141287976985">"Muudetud kaustad."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Tulemused"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Sellel kontol ei toetata otsingut."</string>
<string name="searchMode" msgid="3329807422114758583">"Otsimisrežiim"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 83b8a52..444a3c4 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"انتقال به"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"تنظیمات پوشه"</string>
<string name="folder_list_title" msgid="4276644062440415214">"پوشهها"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"همگامسازی و اعلان"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"تنظیمات پوشه"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"تنظیمات حساب"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"پوشه تغییر کرد."</item>
<item quantity="other" msgid="8918589141287976985">"پوشهها تغییر کردند."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"نتایج"</string>
<string name="search_unsupported" msgid="4654227193354052607">"جستجو در این حساب پشتیبانی نمیشود."</string>
<string name="searchMode" msgid="3329807422114758583">"حالت جستجو"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index b8bc436..994a196 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Siirrä kansioon"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Kansion asetukset"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Kansiot"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Synkronoi ja ilmoita"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Kansion asetukset..."</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Tilin asetukset"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Kansiota muutettu."</item>
<item quantity="other" msgid="8918589141287976985">"Kansioita muutettu."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Tulokset"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Hakua ei voi käyttää tällä tilillä."</string>
<string name="searchMode" msgid="3329807422114758583">"Hakutapa"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 684cfa5..f1a7e0f 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Déplacer vers"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Paramètres des dossiers"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Dossiers"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Synchroniser et signaler"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Paramètres du dossier"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Paramètres de compte"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Dossier modifié."</item>
<item quantity="other" msgid="8918589141287976985">"Dossiers modifiés."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Résultats"</string>
<string name="search_unsupported" msgid="4654227193354052607">"La fonctionnalité de recherche n\'est pas compatible avec ce compte."</string>
<string name="searchMode" msgid="3329807422114758583">"Mode Recherche"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 23f6cc3..b1f8f3d 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"इसमें ले जाएं"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"फ़ोल्डर सेटिंग"</string>
<string name="folder_list_title" msgid="4276644062440415214">"फ़ोल्डर"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"समन्वयित करें और सूचित करें"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"फ़ोल्डर सेटिंग"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"खाता सेटिंग"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"फ़ोल्डर बदला गया."</item>
<item quantity="other" msgid="8918589141287976985">"फ़ोल्डर बदले गए."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"परिणाम"</string>
<string name="search_unsupported" msgid="4654227193354052607">"इस खाते पर खोज समर्थित नहीं है."</string>
<string name="searchMode" msgid="3329807422114758583">"खोज मोड"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 403c498..ea7f309 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Premjesti u/na"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Postavke mapa"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Mape"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sinkroniziraj i obavijesti"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Postavke mape"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Postavke računa"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Promijenjena mapa."</item>
<item quantity="other" msgid="8918589141287976985">"Promijenjene mape."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Rezultati"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Pretraživanje nije podržano na ovom računu."</string>
<string name="searchMode" msgid="3329807422114758583">"Način pretraživanja"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 81223dc..e1f12a9 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Áthelyezés ide:"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Mappabeállítások"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Mappák"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Szinkronizálás és értesítés"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Mappabeállítások"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Fiókbeállítások"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"A mappa módosult."</item>
<item quantity="other" msgid="8918589141287976985">"A mappák módosultak."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Találatok"</string>
<string name="search_unsupported" msgid="4654227193354052607">"A keresés nem támogatott ebben a fiókban."</string>
<string name="searchMode" msgid="3329807422114758583">"Keresési mód"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 12497f5..50d0352 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Pindahkan ke"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Setelan folder"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Folder"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sinkronkan & beri tahu"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Setelan folder"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Pengaturan akun"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Folder diubah."</item>
<item quantity="other" msgid="8918589141287976985">"Folder diubah."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Hasil"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Penelusuran tidak didukung pada akun ini."</string>
<string name="searchMode" msgid="3329807422114758583">"Mode Penelusuran"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index f3281b0..2e17b51 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Sposta in"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Impostazioni cartella"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Cartelle"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sincronizza e notifica"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Impostazioni cartella"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Impostazioni account"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Cartella cambiata."</item>
<item quantity="other" msgid="8918589141287976985">"Cartelle cambiate."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Risultati"</string>
<string name="search_unsupported" msgid="4654227193354052607">"La ricerca non è supportata per l\'account in uso."</string>
<string name="searchMode" msgid="3329807422114758583">"Modalità di ricerca"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index a2ad658..dd9dd84 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"העבר אל"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"הגדרות תיקיה"</string>
<string name="folder_list_title" msgid="4276644062440415214">"תיקיות"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"סנכרן ושלח התראה"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"הגדרות תיקיה"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"הגדרות חשבון"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"התיקיה שונתה."</item>
<item quantity="other" msgid="8918589141287976985">"התיקיות שונו."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"תוצאות"</string>
<string name="search_unsupported" msgid="4654227193354052607">"חיפוש אינו נתמך בחשבון זה."</string>
<string name="searchMode" msgid="3329807422114758583">"מצב חיפוש"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index f7faa86..6bb7191 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"移動"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"フォルダの設定"</string>
<string name="folder_list_title" msgid="4276644062440415214">"フォルダ"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"同期と通知"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"フォルダの設定"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"アカウント設定"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"フォルダを変更しました。"</item>
<item quantity="other" msgid="8918589141287976985">"フォルダを変更しました。"</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"検索結果"</string>
<string name="search_unsupported" msgid="4654227193354052607">"このアカウントでは検索をご利用いただけません。"</string>
<string name="searchMode" msgid="3329807422114758583">"検索モード"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 29c93ac..842dbb1 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"이동"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"폴더 설정"</string>
<string name="folder_list_title" msgid="4276644062440415214">"폴더"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"동기화 및 알림"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"폴더 설정"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"계정 설정"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"폴더가 변경되었습니다."</item>
<item quantity="other" msgid="8918589141287976985">"폴더가 변경되었습니다."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"검색결과"</string>
<string name="search_unsupported" msgid="4654227193354052607">"이 계정에서는 검색이 지원되지 않습니다."</string>
<string name="searchMode" msgid="3329807422114758583">"검색 모드"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index b3cfd02..23944b8 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Perkelti į"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Aplankų nustatymai"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Aplankai"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sinchronizuoti ir pranešti"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Aplankų nustatymai"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Paskyros nustatymai"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Aplankas pakeistas."</item>
<item quantity="other" msgid="8918589141287976985">"Aplankai pakeisti."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Rezultatai"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Šioje paskyroje paieška nepalaikoma."</string>
<string name="searchMode" msgid="3329807422114758583">"Paieškos režimas"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 7503708..bef8502 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Pārvietot uz:"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Mapju iestatījumi"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Mapes"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sinhronizācija un paziņojumi"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Mapes iestatījumi"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Konta iestatījumi"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Mape ir mainīta."</item>
<item quantity="other" msgid="8918589141287976985">"Mapes ir mainītas."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Rezultāti"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Šajā kontā netiek atbalstīta meklēšana."</string>
<string name="searchMode" msgid="3329807422114758583">"Meklēšanas režīms"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 150a4cc..0c364af 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Alih ke"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Tetapan folder"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Folder"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Segerakkan & beritahu"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Tetapan folder"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Tetapan akaun"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Folder yang diubah."</item>
<item quantity="other" msgid="8918589141287976985">"Folder yang diubah."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Hasil"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Carian tidak disokong pada akaun ini."</string>
<string name="searchMode" msgid="3329807422114758583">"Cari dalam Mod"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 48da52c..656ebd4 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Flytt til"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Mappeinnstillinger"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Mapper"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Synkronisering og varsler"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Mappeinnstillinger"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Kontoinnstillinger"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Endret mappe."</item>
<item quantity="other" msgid="8918589141287976985">"Endret mapper."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Resultater"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Søk støttes ikke på denne kontoen."</string>
<string name="searchMode" msgid="3329807422114758583">"Søkemodus"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 9f2e54c..cc91bda 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Verplaatsen naar"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Mapinstellingen"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Mappen"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Synchroniseren en melden"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Mapinstellingen"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Accountinstellingen"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Map gewijzigd."</item>
<item quantity="other" msgid="8918589141287976985">"Mappen gewijzigd."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Resultaten"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Zoeken wordt niet ondersteund in dit account."</string>
<string name="searchMode" msgid="3329807422114758583">"Zoekmodus"</string>
@@ -277,7 +283,7 @@
<string-array name="sync_status">
<item msgid="2446076619901049026">"Geslaagd"</item>
<item msgid="7109065688039971961">"Geen verbinding."</item>
- <item msgid="8437496123716232060">"Kan niet aanmelden."</item>
+ <item msgid="8437496123716232060">"Kan niet inloggen."</item>
<item msgid="1651266301325684887">"Beveiligingsfout."</item>
<item msgid="1461520171154288533">"Kan niet synchroniseren."</item>
<item msgid="4779810016424303449">"Interne fout"</item>
@@ -323,7 +329,7 @@
<item msgid="6593672292311851204">"Veelgebruikt"</item>
<item msgid="3584541772344786752">"Alle mappen"</item>
</string-array>
- <string name="signin" msgid="8958889809095796177">"Aanmelden"</string>
+ <string name="signin" msgid="8958889809095796177">"Inloggen"</string>
<string name="info" msgid="6009817562073541204">"Info"</string>
<string name="report" msgid="5417082746232614958">"Rapporteren"</string>
<string name="sync_error" msgid="7368819509040597851">"Kan niet synchroniseren."</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 1ee0c72..45efbaf 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Przenieś do"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Ustawienia folderów"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Foldery"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Synchronizuj i powiadamiaj"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Ustawienia folderu"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Ustawienia konta"</string>
@@ -219,6 +223,8 @@
<item quantity="one" msgid="4930161390461457462">"Zmieniono folder."</item>
<item quantity="other" msgid="8918589141287976985">"Zmieniono foldery."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Wyniki"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Wyszukiwanie nie jest obsługiwane na tym koncie."</string>
<string name="searchMode" msgid="3329807422114758583">"Tryb wyszukiwania"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 6f7f31f..b33baa4 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Mover para"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Definições da pasta"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Pastas"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sincronizar e notificar"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Definições da pasta"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Definições da conta"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Pasta alterada."</item>
<item quantity="other" msgid="8918589141287976985">"Pastas alteradas."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Resultados"</string>
<string name="search_unsupported" msgid="4654227193354052607">"A pesquisa não é suportada nesta conta."</string>
<string name="searchMode" msgid="3329807422114758583">"Modo de Pesquisa"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 4e8bea7..ee01f8d 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Mover para"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Configurações de pastas"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Pastas"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sincronizar e notificar"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Configurações da pasta"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Configurações da conta"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Pasta alterada."</item>
<item quantity="other" msgid="8918589141287976985">"Pastas alteradas."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Resultados"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Não há suporte para pesquisa nesta conta."</string>
<string name="searchMode" msgid="3329807422114758583">"Modo de pesquisa"</string>
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
index 0c579ff..a47b6ce 100644
--- a/res/values-rm/strings.xml
+++ b/res/values-rm/strings.xml
@@ -129,6 +129,10 @@
<skip />
<!-- no translation found for folder_list_title (4276644062440415214) -->
<skip />
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<!-- no translation found for manage_folders_subtitle (7702199674083260433) -->
<skip />
<!-- no translation found for menu_folder_options (8897520487430647932) -->
@@ -321,6 +325,8 @@
<skip />
<!-- no translation found for conversation_folder_changed:one (4930161390461457462) -->
<!-- no translation found for conversation_folder_changed:other (8918589141287976985) -->
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<!-- no translation found for search_results_header (4669917471897026269) -->
<skip />
<!-- no translation found for search_unsupported (4654227193354052607) -->
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 2b38507..f537450 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -63,8 +63,8 @@
<string name="report_spam" msgid="6467567747975393907">"Raportaţi ca spam"</string>
<string name="mark_not_spam" msgid="694891665407228160">"Nu este spam"</string>
<string name="report_phishing" msgid="5714205737453138338">"Raportaţi phishing"</string>
- <string name="delete" msgid="844871204175957681">"Ştergeţi"</string>
- <string name="discard_drafts" msgid="6862272443470085375">"Ştergeţi mesajele nefinalizate"</string>
+ <string name="delete" msgid="844871204175957681">"Ștergeţi"</string>
+ <string name="discard_drafts" msgid="6862272443470085375">"Ștergeţi mesajele nefinalizate"</string>
<string name="next" msgid="4674401197968248302">"Mai vechi"</string>
<string name="previous" msgid="309943944831349924">"Mai noi"</string>
<string name="refresh" msgid="490989798005710951">"Actualizaţi"</string>
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Mutați în"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Setări pentru dosare"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Dosare"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sincronizare şi notificare"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Setări pentru dosar"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Setările contului"</string>
@@ -167,16 +171,16 @@
<string name="me" msgid="6480762904022198669">"eu"</string>
<string name="show_all_folders" msgid="3281420732307737553">"Afişaţi toate dosarele"</string>
<plurals name="confirm_delete_conversation">
- <item quantity="one" msgid="3731948757247905508">"Ştergeţi această conversaţie?"</item>
- <item quantity="other" msgid="930334208937121234">"Ştergeţi aceste <xliff:g id="COUNT">%1$d</xliff:g> (de) conversaţii?"</item>
+ <item quantity="one" msgid="3731948757247905508">"Ștergeţi această conversaţie?"</item>
+ <item quantity="other" msgid="930334208937121234">"Ștergeţi aceste <xliff:g id="COUNT">%1$d</xliff:g> (de) conversaţii?"</item>
</plurals>
<plurals name="confirm_archive_conversation">
<item quantity="one" msgid="2990537295519552069">"Arhivaţi această conversaţie?"</item>
<item quantity="other" msgid="4713469868399246772">"Arhivaţi aceste <xliff:g id="COUNT">%1$d</xliff:g> (de) conversaţii?"</item>
</plurals>
<plurals name="confirm_discard_drafts_conversation">
- <item quantity="one" msgid="5974090449454432874">"Ştergeţi mesajele nefinalizate din conversaţie?"</item>
- <item quantity="other" msgid="4173815457177336569">"Ştergeţi mesajele nefinalizate din <xliff:g id="COUNT">%1$d</xliff:g> conversaţii?"</item>
+ <item quantity="one" msgid="5974090449454432874">"Ștergeţi mesajele nefinalizate din conversaţie?"</item>
+ <item quantity="other" msgid="4173815457177336569">"Ștergeţi mesajele nefinalizate din <xliff:g id="COUNT">%1$d</xliff:g> conversaţii?"</item>
</plurals>
<string name="confirm_discard_text" msgid="1149834186404614612">"Renunţaţi la acest mesaj?"</string>
<string name="loading_conversations" msgid="2649440958602369555">"Se încarcă…"</string>
@@ -214,13 +218,15 @@
<item quantity="one" msgid="4398693029405479323">"<b><xliff:g id="COUNT">%1$d</xliff:g></b> a fost ştearsă."</item>
<item quantity="other" msgid="8630099095360065837">"<b><xliff:g id="COUNT">%1$d</xliff:g></b> au fost şterse."</item>
</plurals>
- <string name="deleted" msgid="2757349161107268029">"Ştearsă"</string>
+ <string name="deleted" msgid="2757349161107268029">"Ștearsă"</string>
<string name="archived" msgid="7533995360704366325">"Arhivată"</string>
<string name="folder_removed" msgid="1047474677580149436">"Eliminat din <xliff:g id="FOLDERNAME">%1$s</xliff:g>"</string>
<plurals name="conversation_folder_changed">
<item quantity="one" msgid="4930161390461457462">"Dosar modificat."</item>
<item quantity="other" msgid="8918589141287976985">"Dosare modificate."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Rezultate"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Căutarea nu este acceptată pentru acest cont."</string>
<string name="searchMode" msgid="3329807422114758583">"Modul Căutare"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index c78e3b8..47726e7 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Переместить в"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Настройки папок"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Папки"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Синхронизация и уведомления"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Настройки папки"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Настройки аккаунта"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Папка изменена."</item>
<item quantity="other" msgid="8918589141287976985">"Папки изменены."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Результаты"</string>
<string name="search_unsupported" msgid="4654227193354052607">"В этом аккаунте не поддерживается поиск."</string>
<string name="searchMode" msgid="3329807422114758583">"Режим поиска"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index eb2addd..534430b 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Presunúť do"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Nastavenia priečinka"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Priečinky"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Synchronizovať a upozorniť"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Nastavenia priečinka"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Nastavenia účtu"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Zmenený priečinok."</item>
<item quantity="other" msgid="8918589141287976985">"Zmenené priečinky."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Výsledky"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Hľadanie nie je v tomto účte podporované."</string>
<string name="searchMode" msgid="3329807422114758583">"Režim vyhľadávania"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 52649a9..d406dc9 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Premakni v"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Nastavitve mape"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Mape"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sinhronizacija in obveščanje"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Nastavitve mape"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Nastavitve računa"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Spremenjena mapa."</item>
<item quantity="other" msgid="8918589141287976985">"Spremenjene mape."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Rezultati"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Iskanje ni podprto za ta račun."</string>
<string name="searchMode" msgid="3329807422114758583">"Način iskanja"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 45018d9..77bb3f2 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Премести у"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Подешавања директоријума"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Директоријуми"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Синхронизовање и обавештавање"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Подешавања директоријума"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Подешавања налога"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Директоријум је промењен."</item>
<item quantity="other" msgid="8918589141287976985">"Директоријуми су промењени."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Резултати"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Претрага није подржана на овом налогу."</string>
<string name="searchMode" msgid="3329807422114758583">"Режим претраге"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 0dd55de7..021a3e8 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Flytta till"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Mappinställningar"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Mappar"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Synka och meddela"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Mappinställningar"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Kontoinställningar"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Mappen har ändrats."</item>
<item quantity="other" msgid="8918589141287976985">"Mapparna har ändrats."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Resultat"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Det går inte att söka i det här kontot."</string>
<string name="searchMode" msgid="3329807422114758583">"Sökläge"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 50ed7c8..1ddf455 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Hamisha hadi"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Mipangilio ya folda"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Folda"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Sawazisha na uarifu"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Mipangilio ya folda"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Mipangilio ya akaunti"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Folda iliyobadilishwa."</item>
<item quantity="other" msgid="8918589141287976985">"Folda zilizobadilishwa."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Matokeo"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Utafutaji hauauniwi kwenye akaunti hii."</string>
<string name="searchMode" msgid="3329807422114758583">"Hali ya Utafutaji"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 3f5c5d5..a638516 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"ย้ายไปที่"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"การตั้งค่าโฟลเดอร์"</string>
<string name="folder_list_title" msgid="4276644062440415214">"โฟลเดอร์"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"ซิงค์และแจ้งเตือน"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"การตั้งค่าโฟลเดอร์"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"การตั้งค่าบัญชี"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"เปลี่ยนโฟลเดอร์แล้ว"</item>
<item quantity="other" msgid="8918589141287976985">"เปลี่ยนโฟลเดอร์แล้ว"</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"ผลการค้นหา"</string>
<string name="search_unsupported" msgid="4654227193354052607">"บัญชีนี้ไม่สนับสนุนการค้นหา"</string>
<string name="searchMode" msgid="3329807422114758583">"โหมดการค้นหา"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index e98da52..5c00f6f 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Ilipat sa"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Mga setting ng folder"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Mga Folder"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"I-sync at i-notify"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Mga setting ng folder"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Mga setting ng account"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Binagong folder."</item>
<item quantity="other" msgid="8918589141287976985">"Mga binagong folder."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Mga resulta"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Hindi sinusuportahan ang paghahanap sa account na ito."</string>
<string name="searchMode" msgid="3329807422114758583">"Mode ng Paghahanap"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index b6afb41..27233f2 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Taşı"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Klasör ayarları"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Klasörler"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Senkronize et ve bildir"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Klasör ayarları"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Hesap ayarları"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Klasör değişti."</item>
<item quantity="other" msgid="8918589141287976985">"Klasörler değişti."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Sonuçlar"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Bu hesapta arama desteklenmiyor"</string>
<string name="searchMode" msgid="3329807422114758583">"Arama Modu"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index deaab0b..7986e2e 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Перемістити в"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Налаштування папки"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Папки"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Синхронізація та сповіщення"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Налаштування папки"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Налаштування облікового запису"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Змінено папку."</item>
<item quantity="other" msgid="8918589141287976985">"Змінено папки."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Результати"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Функція пошуку в цьому обліковому записі не підтримується."</string>
<string name="searchMode" msgid="3329807422114758583">"Режим пошуку"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 8d490ec..6aa6ac7 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Di chuyển tới"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Cài đặt thư mục"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Thư mục"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Đồng bộ hóa và thông báo"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Cài đặt thư mục"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Cài đặt tài khoản"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Đã thay đổi thư mục."</item>
<item quantity="other" msgid="8918589141287976985">"Đã thay đổi thư mục."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Kết quả"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Không hỗ trợ tính năng tìm kiếm trên tài khoản này."</string>
<string name="searchMode" msgid="3329807422114758583">"Chế độ tìm kiếm"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 79a9237..a3ffadb 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"移至"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"文件夹设置"</string>
<string name="folder_list_title" msgid="4276644062440415214">"文件夹"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"同步与通知"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"文件夹设置"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"帐户设置"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"已更改文件夹。"</item>
<item quantity="other" msgid="8918589141287976985">"已更改文件夹。"</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"结果"</string>
<string name="search_unsupported" msgid="4654227193354052607">"此帐户不支持搜索。"</string>
<string name="searchMode" msgid="3329807422114758583">"搜索模式"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 2385432..ee35ca4 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"移至"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"資料夾設定"</string>
<string name="folder_list_title" msgid="4276644062440415214">"資料夾"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"同步處理並通知"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"資料夾設定"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"帳戶設定"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"已變更資料夾。"</item>
<item quantity="other" msgid="8918589141287976985">"已變更資料夾。"</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"搜尋結果"</string>
<string name="search_unsupported" msgid="4654227193354052607">"這個帳戶不支援搜尋功能。"</string>
<string name="searchMode" msgid="3329807422114758583">"搜尋模式"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index efd7aea..ed52d66 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -77,6 +77,10 @@
<string name="menu_move_to" msgid="9138296669516358542">"Hambisa ku-"</string>
<string name="menu_manage_folders" msgid="6755623004628177492">"Izilungiselelo zefolda"</string>
<string name="folder_list_title" msgid="4276644062440415214">"Amafolda"</string>
+ <!-- no translation found for folder_list_more (537172187223133825) -->
+ <skip />
+ <!-- no translation found for folder_list_show_all_accounts (8054807182336991835) -->
+ <skip />
<string name="manage_folders_subtitle" msgid="7702199674083260433">"Ukuvumelanisa & ukuqaphelisa"</string>
<string name="menu_folder_options" msgid="8897520487430647932">"Izilungiselelo zefolda"</string>
<string name="menu_account_settings" msgid="8230989362863431918">"Izilungiselelo ze-akhawunti"</string>
@@ -221,6 +225,8 @@
<item quantity="one" msgid="4930161390461457462">"Ifolda eshintshiwe."</item>
<item quantity="other" msgid="8918589141287976985">"Amafolda ashintshiwe."</item>
</plurals>
+ <!-- no translation found for conversation_folder_moved (297469098857964678) -->
+ <skip />
<string name="search_results_header" msgid="4669917471897026269">"Imiphumela"</string>
<string name="search_unsupported" msgid="4654227193354052607">"Usesho alusekelwe kule akhawunti."</string>
<string name="searchMode" msgid="3329807422114758583">"Imodi yokusesha"</string>
diff --git a/res/values/accountprovider.xml b/res/values/accountprovider.xml
new file mode 100644
index 0000000..742a7e5
--- /dev/null
+++ b/res/values/accountprovider.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013 Google Inc.
+ Licensed to 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.
+-->
+<resources>
+ <!-- List of content provider uris for -->
+ <string-array name="account_providers" translatable="false">
+ <!-- mock account list -->
+ <item>content://com.android.mail.mockprovider/accounts</item>
+ </string-array>
+
+</resources>
\ No newline at end of file
diff --git a/res/values/ids.xml b/res/values/ids.xml
index 84042ce..0039aab 100644
--- a/res/values/ids.xml
+++ b/res/values/ids.xml
@@ -21,4 +21,5 @@
<item type="id" name="reply_state" />
<item type="id" name="manage_folders_item"/>
<item type="id" name="contact_image" />
+ <item type="id" name="move_folder" />
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 10d58df..dee3df6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -153,8 +153,24 @@
<string name="menu_move_to">Move to</string>
<!-- Menu item: manages the folders for this account. [CHAR LIMIT = 30] -->
<string name="menu_manage_folders">Folder settings</string>
+ <!-- Menu item: report an email was not readable or poorly rendered -->
+ <string name="report_rendering_problem" translatable="false">Looks bad</string>
+ <!-- Menu item: report an email's readability has improved -->
+ <string name="report_rendering_improvement" translatable="false">Looks good</string>
+ <!-- Temporary text used for reporting rendering issues Googlers see in testing -->
+ <string name="report_rendering_problem_desc" translatable="false">
+ This message looks bad.
+ </string>
+ <!-- Temporary text used for reporting rendering improvements Googlers see in testing -->
+ <string name="report_rendering_improvement_desc" translatable="false">
+ This message looks good.
+ </string>
<!-- Title for the Folder list screen. [CHAR LIMIT = 30] -->
<string name="folder_list_title">Folders</string>
+ <!-- Folder list item: show more folders. [CHAR LIMIT = 30] -->
+ <string name="folder_list_more">More</string>
+ <!-- Folder list item: show all accounts. [CHAR LIMIT = 30] -->
+ <string name="folder_list_show_all_accounts">More accounts</string>
<!-- action bar sub title for manage folder mode. [CHAR LIMIT = 30] -->
<string name="manage_folders_subtitle">Sync & notify</string>
<!-- Menu item: options for this folder. When source text cannot be translated within the char limit, please translate the shorter "Folder options" instead. [CHAR LIMIT = 30] -->
@@ -440,6 +456,9 @@
<item quantity="other">Changed folders.</item>
</plurals>
+ <!-- Displayed after moving a conversation to a different folder. [CHAR LIMIT=100] -->
+ <string name="conversation_folder_moved">Moved to <xliff:g id="folderName">%1$s</xliff:g></string>
+
<!-- Search Results: Text for header that is shown above search results [CHAR LIMIT=30] -->
<string name="search_results_header">Results</string>
<!-- Toast shown when the user taps the search hard key when viewing an account that does not support search [CHAR LIMIT=100] -->
diff --git a/src/com/android/mail/adapter/DrawerItem.java b/src/com/android/mail/adapter/DrawerItem.java
new file mode 100644
index 0000000..84b6540
--- /dev/null
+++ b/src/com/android/mail/adapter/DrawerItem.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2013 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.android.mail.adapter;
+
+import com.android.mail.R;
+import com.android.mail.providers.Account;
+import com.android.mail.providers.Folder;
+import com.android.mail.ui.ControllableActivity;
+import com.android.mail.ui.FolderItemView;
+import com.android.mail.utils.LogTag;
+import com.android.mail.utils.LogUtils;
+
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/** An account, a system folder, a recent folder, or a header (a resource string) */
+public class DrawerItem {
+
+ private static final String LOG_TAG = LogTag.getLogTag();
+ public int mPosition;
+ public final Folder mFolder;
+ public final Account mAccount;
+ public final int mResource;
+ /** True if expand item view for expanding accounts. False otherwise */
+ public final boolean mIsExpandForAccount;
+ /** Either {@link #VIEW_ACCOUNT}, {@link #VIEW_FOLDER} or {@link #VIEW_HEADER} */
+ public final int mType;
+ /** A normal folder, also a child, if a parent is specified. */
+ public static final int VIEW_FOLDER = 0;
+ /** A text-label which serves as a header in sectioned lists. */
+ public static final int VIEW_HEADER = 1;
+ /** An account object, which allows switching accounts rather than folders. */
+ public static final int VIEW_ACCOUNT = 2;
+ /** An expandable object for expanding/collapsing more of the list */
+ public static final int VIEW_MORE = 3;
+ /** TODO: On adding another type, be sure to change getViewTypes() */
+
+ /** The parent activity */
+ private final ControllableActivity mActivity;
+ private final LayoutInflater mInflater;
+
+ /**
+ * Either {@link #FOLDER_SYSTEM}, {@link #FOLDER_RECENT} or {@link #FOLDER_USER} when
+ * {@link #mType} is {@link #VIEW_FOLDER}, or an {@link #ACCOUNT} in the case of
+ * accounts, {@link #EXPAND} for expand blocks, and {@link #INERT_HEADER} otherwise.
+ */
+ public final int mFolderType;
+ /** An unclickable text-header visually separating the different types. */
+ public static final int INERT_HEADER = 0;
+ /** A system-defined folder: Inbox/Drafts, ...*/
+ public static final int FOLDER_SYSTEM = 1;
+ /** A folder from whom a conversation was recently viewed */
+ public static final int FOLDER_RECENT = 2;
+ /** A user created folder */
+ public static final int FOLDER_USER = 3;
+ /** An entry for the accounts the user has on the device. */
+ public static final int ACCOUNT = 4;
+ /** A clickable block to expand list as requested */
+ public static final int EXPAND = 5;
+
+ /** True if this view is enabled, false otherwise. */
+ private boolean isEnabled = false;
+
+ /**
+ * Create a folder item with the given type.
+ * @param folder a folder that this item represents
+ * @param folderType one of {@link #FOLDER_SYSTEM}, {@link #FOLDER_RECENT} or
+ * {@link #FOLDER_USER}
+ */
+ public DrawerItem(ControllableActivity activity, Folder folder, int folderType,
+ int cursorPosition) {
+ mActivity = activity;
+ mInflater = LayoutInflater.from(mActivity.getActivityContext());
+ mFolder = folder;
+ mAccount = null;
+ mResource = -1;
+ mType = VIEW_FOLDER;
+ mFolderType = folderType;
+ mPosition = cursorPosition;
+ mIsExpandForAccount = false;
+ }
+
+ /**
+ * Creates an item from an account.
+ * @param account an account that this item represents.
+ */
+ public DrawerItem(ControllableActivity activity, Account account, int count) {
+ mActivity = activity;
+ mInflater = LayoutInflater.from(mActivity.getActivityContext());
+ mFolder = null;
+ mType = VIEW_ACCOUNT;
+ mResource = count;
+ mFolderType = ACCOUNT;
+ mAccount = account;
+ mIsExpandForAccount = false;
+ }
+
+ /**
+ * Create a header item with a string resource.
+ * @param resource the string resource: R.string.all_folders_heading
+ */
+ public DrawerItem(ControllableActivity activity, int resource) {
+ mActivity = activity;
+ mInflater = LayoutInflater.from(mActivity.getActivityContext());
+ mFolder = null;
+ mResource = resource;
+ mType = VIEW_HEADER;
+ mFolderType = INERT_HEADER;
+ mAccount = null;
+ mIsExpandForAccount = false;
+ }
+
+ /**
+ * Creates an item for expanding or contracting for emails/items
+ * @param resource the string resource: R.string.folder_list_*
+ * @param isExpand true if "more" and false if "less"
+ */
+ public DrawerItem(ControllableActivity activity, int resource, boolean isExpandForAccount) {
+ mActivity = activity;
+ mInflater = LayoutInflater.from(mActivity.getActivityContext());
+ mFolder = null;
+ mType = VIEW_MORE;
+ mResource = resource;
+ mFolderType = EXPAND;
+ mAccount = null;
+ mIsExpandForAccount = isExpandForAccount;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final View result;
+ switch (mType) {
+ case VIEW_FOLDER:
+ result = getFolderView(position, convertView, parent);
+ break;
+ case VIEW_HEADER:
+ result = getHeaderView(position, convertView, parent);
+ break;
+ case VIEW_ACCOUNT:
+ result = getAccountView(position, convertView, parent);
+ break;
+ case VIEW_MORE:
+ result = getExpandView(position, convertView, parent);
+ break;
+ default:
+ LogUtils.wtf(LOG_TAG, "DrawerItem.getView(%d) for an invalid type!", mType);
+ result = null;
+ }
+ return result;
+ }
+
+ /**
+ * Book-keeping for how many different view types there are. Be sure to
+ * increment this appropriately once adding more types as drawer items
+ * @return number of different types of view items
+ */
+ public static int getViewTypes() {
+ return VIEW_MORE + 1;
+ }
+
+ /**
+ * Returns whether this view is enabled or not.
+ * @return
+ */
+ public boolean isItemEnabled(Uri currentAccountUri) {
+ switch (mType) {
+ case VIEW_HEADER :
+ // Headers are never enabled.
+ return false;
+ case VIEW_FOLDER :
+ // Folders are always enabled.
+ return true;
+ case VIEW_ACCOUNT:
+ // Accounts are only enabled if they are not the current account.
+ return !currentAccountUri.equals(mAccount.uri);
+ case VIEW_MORE:
+ // 'Expand/Collapse' items are always enabled.
+ return true;
+ default:
+ LogUtils.wtf(LOG_TAG, "DrawerItem.isItemEnabled() for invalid type %d", mType);
+ return false;
+ }
+ }
+
+ /**
+ * Returns whether this view is highlighted or not.
+ *
+ * @param currentFolder
+ * @param currentType
+ * @return
+ */
+ public boolean isHighlighted(Folder currentFolder, int currentType){
+ switch (mType) {
+ case VIEW_HEADER :
+ // Headers are never highlighted
+ return false;
+ case VIEW_FOLDER :
+ return (mFolderType == currentType) && mFolder.uri.equals(currentFolder.uri);
+ case VIEW_ACCOUNT:
+ // Accounts are never highlighted
+ return false;
+ case VIEW_MORE:
+ // Expand/Collapse items are never highlighted
+ return false;
+ default:
+ LogUtils.wtf(LOG_TAG, "DrawerItem.isHighlighted() for invalid type %d", mType);
+ return false;
+ }
+ }
+
+ /**
+ * Return a view for an account object.
+ * @param position a zero indexed position in to the list.
+ * @param convertView a view, possibly null, to be recycled.
+ * @param parent the parent viewgroup to attach to.
+ * @return a view to display at this position.
+ */
+ private View getAccountView(int position, View convertView, ViewGroup parent) {
+ // Shoe-horn an account object into a Folder DrawerItem for now.
+ // TODO(viki): Stop this ugly shoe-horning and use a real layout.
+ final FolderItemView folderItemView;
+ if (convertView != null) {
+ folderItemView = (FolderItemView) convertView;
+ } else {
+ folderItemView =
+ (FolderItemView) mInflater.inflate(R.layout.folder_item, null, false);
+ }
+ // Temporary. Ideally we want a totally different item.
+ folderItemView.bind(mAccount, mActivity, mResource);
+ View v = folderItemView.findViewById(R.id.color_block);
+ v.setBackgroundColor(mAccount.color);
+ v = folderItemView.findViewById(R.id.folder_icon);
+ v.setVisibility(View.GONE);
+ return folderItemView;
+ }
+
+ /**
+ * Returns a text divider between sections.
+ * @param convertView a previous view, perhaps null
+ * @param parent the parent of this view
+ * @return a text header at the given position.
+ */
+ private View getHeaderView(int position, View convertView, ViewGroup parent) {
+ final TextView headerView;
+ if (convertView != null) {
+ headerView = (TextView) convertView;
+ } else {
+ headerView = (TextView) mInflater.inflate(
+ R.layout.folder_list_header, parent, false);
+ }
+ headerView.setText(mResource);
+ return headerView;
+ }
+
+ /**
+ * Return a folder: either a parent folder or a normal (child or flat)
+ * folder.
+ * @param position a zero indexed position into the top level list.
+ * @param convertView a view, possibly null, to be recycled.
+ * @param parent the parent hosting this view.
+ * @return a view showing a folder at the given position.
+ */
+ private View getFolderView(int position, View convertView, ViewGroup parent) {
+ final FolderItemView folderItemView;
+ if (convertView != null) {
+ folderItemView = (FolderItemView) convertView;
+ } else {
+ folderItemView =
+ (FolderItemView) mInflater.inflate(R.layout.folder_item, null, false);
+ }
+ folderItemView.bind(mFolder, mActivity);
+ Folder.setFolderBlockColor(mFolder, folderItemView.findViewById(R.id.color_block));
+ Folder.setIcon(mFolder, (ImageView) folderItemView.findViewById(R.id.folder_icon));
+ return folderItemView;
+ }
+
+ /**
+ * Return a view for the 'Expand/Collapse' item.
+ * @param position a zero indexed position into the top level list.
+ * @param convertView a view, possibly null, to be recycled.
+ * @param parent the parent hosting this view.
+ * @return a view showing an item for folder/account expansion at given position.
+ */
+ private View getExpandView(int position, View convertView, ViewGroup parent) {
+ final ViewGroup headerView;
+ if (convertView != null) {
+ headerView = (ViewGroup) convertView;
+ } else {
+ headerView = (ViewGroup) mInflater.inflate(
+ R.layout.folder_expand_item, parent, false);
+ }
+ TextView direction =
+ (TextView)headerView.findViewById(R.id.folder_expand_text);
+ if(direction != null) {
+ direction.setText(mResource);
+ }
+ return headerView;
+ }
+}
+
diff --git a/src/com/android/mail/browse/ConversationCursor.java b/src/com/android/mail/browse/ConversationCursor.java
index f47f7fd..b3c9f79 100644
--- a/src/com/android/mail/browse/ConversationCursor.java
+++ b/src/com/android/mail/browse/ConversationCursor.java
@@ -74,7 +74,7 @@
* caching for quick UI response. This is effectively a singleton class, as the cache is
* implemented as a static HashMap.
*/
-public final class ConversationCursor implements Cursor {
+public final class ConversationCursor implements Cursor, ConversationCursorMarkSeenListener {
private static final boolean ENABLE_CONVERSATION_PRECACHING = true;
@@ -2101,4 +2101,12 @@
});
}
}
+
+ /**
+ * Marks all contents of this cursor as seen. This may have no effect with certain providers.
+ */
+ @Override
+ public void markContentsSeen() {
+ ConversationCursorMarkSeenListener.MarkSeenHelper.markContentsSeen(mUnderlyingCursor);
+ }
}
diff --git a/src/com/android/mail/browse/ConversationCursorMarkSeenListener.java b/src/com/android/mail/browse/ConversationCursorMarkSeenListener.java
new file mode 100644
index 0000000..0956859
--- /dev/null
+++ b/src/com/android/mail/browse/ConversationCursorMarkSeenListener.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (C) 2013 Google Inc.
+ * Licensed to 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.android.mail.browse;
+
+import android.database.Cursor;
+import android.database.CursorWrapper;
+
+public interface ConversationCursorMarkSeenListener {
+ /**
+ * Marks all contents of this cursor as seen.
+ */
+ void markContentsSeen();
+
+ public class MarkSeenHelper {
+ /**
+ * Invokes {@link ConversationCursorMarkSeenListener#markContentsSeen(Cursor)} on the
+ * specified {@link Cursor}, recursively calls {@link #markContentsSeen(Cursor)} on a
+ * wrapped cursor, or returns.
+ */
+ public static void markContentsSeen(final Cursor cursor) {
+ if (cursor == null) {
+ return;
+ }
+
+ if (cursor instanceof ConversationCursorMarkSeenListener) {
+ ((ConversationCursorMarkSeenListener) cursor).markContentsSeen();
+ } else if (cursor instanceof CursorWrapper) {
+ markContentsSeen(((CursorWrapper) cursor).getWrappedCursor());
+ }
+ }
+ }
+}
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 9ef50cd..5165610 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -72,7 +72,6 @@
import com.android.mail.ui.AnimatedAdapter;
import com.android.mail.ui.ControllableActivity;
import com.android.mail.ui.ConversationSelectionSet;
-
import com.android.mail.ui.DividedImageCanvas;
import com.android.mail.ui.DividedImageCanvas.InvalidateCallback;
import com.android.mail.ui.EllipsizedMultilineTextView;
@@ -1220,6 +1219,7 @@
* Toggle the check mark on this view and update the conversation or begin
* drag, if drag is enabled.
*/
+ @Override
public void toggleCheckMarkOrBeginDrag() {
ViewMode mode = mActivity.getViewMode();
if (!mTabletDevice || !mode.isListMode()) {
@@ -1267,9 +1267,11 @@
postInvalidate(mCoordinates.starX, mCoordinates.starY, mCoordinates.starX
+ starBitmap.getWidth(),
mCoordinates.starY + starBitmap.getHeight());
- ConversationCursor cursor = (ConversationCursor)mAdapter.getCursor();
- cursor.updateBoolean(mContext, mHeader.conversation, ConversationColumns.STARRED,
- mHeader.conversation.starred);
+ ConversationCursor cursor = (ConversationCursor) mAdapter.getCursor();
+ if (cursor != null) {
+ cursor.updateBoolean(mContext, mHeader.conversation, ConversationColumns.STARRED,
+ mHeader.conversation.starred);
+ }
}
private boolean isTouchInCheckmark(float x, float y) {
diff --git a/src/com/android/mail/browse/ConversationPagerAdapter.java b/src/com/android/mail/browse/ConversationPagerAdapter.java
index c542733..239d6dc 100644
--- a/src/com/android/mail/browse/ConversationPagerAdapter.java
+++ b/src/com/android/mail/browse/ConversationPagerAdapter.java
@@ -31,6 +31,7 @@
import com.android.mail.providers.Account;
import com.android.mail.providers.Conversation;
import com.android.mail.providers.Folder;
+import com.android.mail.providers.FolderObserver;
import com.android.mail.providers.UIProvider;
import com.android.mail.ui.AbstractConversationViewFragment;
import com.android.mail.ui.ActivityController;
@@ -44,7 +45,12 @@
implements ViewPager.OnPageChangeListener {
private final DataSetObserver mListObserver = new ListObserver();
- private final DataSetObserver mFolderObserver = new FolderObserver();
+ private final FolderObserver mFolderObserver = new FolderObserver() {
+ @Override
+ public void onChanged(Folder newFolder) {
+ notifyDataSetChanged();
+ }
+ };
private ActivityController mController;
private final Bundle mCommonFragmentArgs;
private final Conversation mInitialConversation;
@@ -427,7 +433,7 @@
mController = controller;
if (mController != null && !mStopListeningMode) {
mController.registerConversationListObserver(mListObserver);
- mController.registerFolderObserver(mFolderObserver);
+ mFolderObserver.initialize(mController);
notifyDataSetChanged();
} else {
@@ -451,7 +457,7 @@
if (mController != null) {
mController.unregisterConversationListObserver(mListObserver);
- mController.unregisterFolderObserver(mFolderObserver);
+ mFolderObserver.unregisterAndDestroy();
}
mLastKnownCount = getCount();
mStopListeningMode = true;
@@ -484,14 +490,6 @@
// no-op
}
- // update the pager title strip as the Folder's conversation count changes
- private class FolderObserver extends DataSetObserver {
- @Override
- public void onChanged() {
- notifyDataSetChanged();
- }
- }
-
// update the pager dataset as the Controller's cursor changes
private class ListObserver extends DataSetObserver {
@Override
diff --git a/src/com/android/mail/browse/MessageHeaderView.java b/src/com/android/mail/browse/MessageHeaderView.java
index be8baad..8bd6981 100644
--- a/src/com/android/mail/browse/MessageHeaderView.java
+++ b/src/com/android/mail/browse/MessageHeaderView.java
@@ -16,13 +16,12 @@
package com.android.mail.browse;
-import android.app.Dialog;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.AsyncQueryHandler;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.res.Resources;
import android.database.DataSetObserver;
import android.graphics.Typeface;
@@ -33,12 +32,11 @@
import android.text.style.StyleSpan;
import android.util.AttributeSet;
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.OnLongClickListener;
import android.view.ViewGroup;
-import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
@@ -55,6 +53,7 @@
import com.android.mail.browse.MessageCursor.ConversationMessage;
import com.android.mail.compose.ComposeActivity;
import com.android.mail.perf.Timer;
+import com.android.mail.preferences.MailPrefs;
import com.android.mail.providers.Account;
import com.android.mail.providers.Address;
import com.android.mail.providers.Folder;
@@ -64,7 +63,6 @@
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.Utils;
import com.android.mail.utils.VeiledAddressMatcher;
-
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
@@ -99,6 +97,10 @@
public static final int POPUP_MODE = 1;
+ // This is a debug only feature
+ public static final boolean ENABLE_REPORT_RENDERING_PROBLEM =
+ MailPrefs.SHOW_EXPERIMENTAL_PREFS;
+
private MessageHeaderViewCallbacks mCallbacks;
private ViewGroup mUpperHeaderView;
@@ -227,6 +229,9 @@
void showExternalResources(Message msg);
void showExternalResources(String senderRawAddress);
+
+ boolean supportsMessageTransforms();
+ String getMessageTransforms(Message msg);
}
public MessageHeaderView(Context context) {
@@ -930,6 +935,16 @@
case R.id.forward:
ComposeActivity.forward(getContext(), getAccount(), mMessage);
break;
+ case R.id.report_rendering_problem:
+ String text = getContext().getString(R.string.report_rendering_problem_desc);
+ ComposeActivity.reportRenderingFeedback(getContext(), getAccount(), mMessage,
+ text + "\n\n" + mCallbacks.getMessageTransforms(mMessage));
+ break;
+ case R.id.report_rendering_improvement:
+ text = getContext().getString(R.string.report_rendering_improvement_desc);
+ ComposeActivity.reportRenderingFeedback(getContext(), getAccount(), mMessage,
+ text + "\n\n" + mCallbacks.getMessageTransforms(mMessage));
+ break;
case R.id.star: {
final boolean newValue = !v.isSelected();
v.setSelected(newValue);
@@ -948,8 +963,14 @@
}
final boolean defaultReplyAll = getAccount().settings.replyBehavior
== UIProvider.DefaultReplyBehavior.REPLY_ALL;
- mPopup.getMenu().findItem(R.id.reply).setVisible(defaultReplyAll);
- mPopup.getMenu().findItem(R.id.reply_all).setVisible(!defaultReplyAll);
+ final Menu m = mPopup.getMenu();
+ m.findItem(R.id.reply).setVisible(defaultReplyAll);
+ m.findItem(R.id.reply_all).setVisible(!defaultReplyAll);
+
+ final boolean reportRendering = ENABLE_REPORT_RENDERING_PROBLEM
+ && mCallbacks.supportsMessageTransforms();
+ m.findItem(R.id.report_rendering_improvement).setVisible(reportRendering);
+ m.findItem(R.id.report_rendering_problem).setVisible(reportRendering);
mPopup.show();
break;
diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java
index 31f4973..77c29d7 100644
--- a/src/com/android/mail/compose/ComposeActivity.java
+++ b/src/com/android/mail/compose/ComposeActivity.java
@@ -38,8 +38,8 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import android.provider.BaseColumns;
import android.text.Editable;
import android.text.Html;
@@ -70,6 +70,7 @@
import com.android.ex.chips.RecipientEditTextView;
import com.android.mail.MailIntentService;
import com.android.mail.R;
+import com.android.mail.browse.MessageHeaderView;
import com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener;
import com.android.mail.compose.AttachmentsView.AttachmentFailureException;
import com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
@@ -86,10 +87,10 @@
import com.android.mail.providers.UIProvider;
import com.android.mail.providers.UIProvider.AccountCapabilities;
import com.android.mail.providers.UIProvider.DraftType;
+import com.android.mail.ui.AttachmentTile.AttachmentPreview;
import com.android.mail.ui.FeedbackEnabledActivity;
import com.android.mail.ui.MailActivity;
import com.android.mail.ui.WaitFragment;
-import com.android.mail.ui.AttachmentTile.AttachmentPreview;
import com.android.mail.utils.AccountUtils;
import com.android.mail.utils.AttachmentUtils;
import com.android.mail.utils.ContentProviderTask;
@@ -116,8 +117,9 @@
public class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
RespondInlineListener, DialogInterface.OnClickListener, TextWatcher,
- AttachmentAddedOrDeletedListener, OnAccountChangedListener, LoaderManager.LoaderCallbacks<Cursor>,
- TextView.OnEditorActionListener, FeedbackEnabledActivity {
+ AttachmentAddedOrDeletedListener, OnAccountChangedListener,
+ LoaderManager.LoaderCallbacks<Cursor>, TextView.OnEditorActionListener,
+ FeedbackEnabledActivity {
// Identifiers for which type of composition this is
protected static final int COMPOSE = -1;
protected static final int REPLY = 0;
@@ -205,6 +207,7 @@
private static final String EXTRA_MESSAGE = "extraMessage";
private static final int REFERENCE_MESSAGE_LOADER = 0;
private static final int LOADER_ACCOUNT_CURSOR = 1;
+ private static final int INIT_DRAFT_USING_REFERENCE_MESSAGE = 2;
private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
private static final String TAG_WAIT = "wait-fragment";
private static final String MIME_TYPE_PHOTO = "image/*";
@@ -262,6 +265,7 @@
private RecipientTextWatcher mCcListener;
private RecipientTextWatcher mBccListener;
private Uri mRefMessageUri;
+ private boolean mShowQuotedText = false;
private Bundle mSavedInstanceState;
@@ -280,14 +284,14 @@
* Can be called from a non-UI thread.
*/
public static void editDraft(Context launcher, Account account, Message message) {
- launch(launcher, account, message, EDIT_DRAFT);
+ launch(launcher, account, message, EDIT_DRAFT, null, null);
}
/**
* Can be called from a non-UI thread.
*/
public static void compose(Context launcher, Account account) {
- launch(launcher, account, null, COMPOSE);
+ launch(launcher, account, null, COMPOSE, null, null);
}
/**
@@ -322,24 +326,30 @@
* Can be called from a non-UI thread.
*/
public static void reply(Context launcher, Account account, Message message) {
- launch(launcher, account, message, REPLY);
+ launch(launcher, account, message, REPLY, null, null);
}
/**
* Can be called from a non-UI thread.
*/
public static void replyAll(Context launcher, Account account, Message message) {
- launch(launcher, account, message, REPLY_ALL);
+ launch(launcher, account, message, REPLY_ALL, null, null);
}
/**
* Can be called from a non-UI thread.
*/
public static void forward(Context launcher, Account account, Message message) {
- launch(launcher, account, message, FORWARD);
+ launch(launcher, account, message, FORWARD, null, null);
}
- private static void launch(Context launcher, Account account, Message message, int action) {
+ public static void reportRenderingFeedback(Context launcher, Account account, Message message,
+ String body) {
+ launch(launcher, account, message, FORWARD, "android-gmail-readability@google.com", body);
+ }
+
+ private static void launch(Context launcher, Account account, Message message, int action,
+ String toAddress, String body) {
Intent intent = new Intent(launcher, ComposeActivity.class);
intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
intent.putExtra(EXTRA_ACTION, action);
@@ -349,6 +359,12 @@
} else {
intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
}
+ if (toAddress != null) {
+ intent.putExtra(EXTRA_TO, toAddress);
+ }
+ if (body != null) {
+ intent.putExtra(EXTRA_BODY, body);
+ }
launcher.startActivity(intent);
}
@@ -366,7 +382,7 @@
Intent intent = getIntent();
Message message;
ArrayList<AttachmentPreview> previews;
- boolean showQuotedText = false;
+ mShowQuotedText = false;
int action;
// Check for any of the possibly supplied accounts.;
Account account = null;
@@ -418,14 +434,15 @@
}
if (mRefMessageUri != null) {
- // We have a referenced message that we must look up.
- getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
+ mShowQuotedText = true;
+ mComposeMode = action;
+ getLoaderManager().initLoader(INIT_DRAFT_USING_REFERENCE_MESSAGE, null, this);
return;
} else if (message != null && action != EDIT_DRAFT) {
initFromDraftMessage(message);
initQuotedTextFromRefMessage(mRefMessage, action);
showCcBcc(savedInstanceState);
- showQuotedText = message.appendRefMessageContent;
+ mShowQuotedText = message.appendRefMessageContent;
} else if (action == EDIT_DRAFT) {
initFromDraftMessage(message);
boolean showBcc = !TextUtils.isEmpty(message.getBcc());
@@ -447,17 +464,29 @@
action = COMPOSE;
break;
}
- initQuotedTextFromRefMessage(mRefMessage, action);
- showQuotedText = message.appendRefMessageContent;
+ LogUtils.d(LOG_TAG, "Previous draft had action type: %d", action);
+
+ mShowQuotedText = message.appendRefMessageContent;
+ if (message.refMessageUri != null) {
+ // If we're editing an existing draft that was in reference to an existing message,
+ // still need to load that original message since we might need to refer to the
+ // original sender and recipients if user switches "reply <-> reply-all".
+ mRefMessageUri = message.refMessageUri;
+ mComposeMode = action;
+ getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
+ return;
+ }
} else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
if (mRefMessage != null) {
initFromRefMessage(action);
- showQuotedText = true;
+ mShowQuotedText = true;
}
} else {
initFromExtras(intent);
}
- finishSetup(action, intent, savedInstanceState, showQuotedText);
+
+ mComposeMode = action;
+ finishSetup(action, intent, savedInstanceState);
}
private void checkValidAccounts() {
@@ -541,8 +570,7 @@
return account;
}
- private void finishSetup(int action, Intent intent, Bundle savedInstanceState,
- boolean showQuotedText) {
+ private void finishSetup(int action, Intent intent, Bundle savedInstanceState) {
setFocus(action);
if (action == COMPOSE) {
mQuotedTextView.setVisibility(View.GONE);
@@ -553,7 +581,7 @@
if (!hadSavedInstanceStateMessage(savedInstanceState)) {
initAttachmentsFromIntent(intent);
}
- initActionBar(action);
+ initActionBar();
initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
action);
@@ -565,7 +593,7 @@
initChangeListeners();
updateHideOrShowCcBcc();
- updateHideOrShowQuotedText(showQuotedText);
+ updateHideOrShowQuotedText(mShowQuotedText);
mRespondedInline = mSavedInstanceState != null ?
mSavedInstanceState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
@@ -664,7 +692,7 @@
addAttachmentAndUpdateView(data);
mAddingAttachment = false;
} else if (request == RESULT_CREATE_ACCOUNT) {
- // We were waiting for the user to create an account
+ // We were waiting for the user to create an account
if (result != RESULT_OK) {
finish();
} else {
@@ -784,7 +812,7 @@
message.bodyHtml = fullBody.toString();
message.bodyText = mBodyView.getText().toString();
message.embedsExternalResources = false;
- message.refMessageId = mRefMessage != null ? mRefMessage.uri.toString() : null;
+ message.refMessageUri = mRefMessage != null ? mRefMessage.uri : null;
message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
message.hasAttachments = attachments != null && attachments.size() > 0;
@@ -1054,13 +1082,13 @@
mAttachmentsView.setAttachmentChangesListener(this);
}
- private void initActionBar(int action) {
- mComposeMode = action;
+ private void initActionBar() {
+ LogUtils.d(LOG_TAG, "initializing action bar in ComposeActivity");
ActionBar actionBar = getActionBar();
if (actionBar == null) {
return;
}
- if (action == ComposeActivity.COMPOSE) {
+ if (mComposeMode == ComposeActivity.COMPOSE) {
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setTitle(R.string.compose);
} else {
@@ -1070,7 +1098,7 @@
}
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
- switch (action) {
+ switch (mComposeMode) {
case ComposeActivity.REPLY:
actionBar.setSelectedNavigationItem(0);
break;
@@ -1089,6 +1117,23 @@
private void initFromRefMessage(int action) {
setFieldsFromRefMessage(action);
+
+ // Check if To: address and email body needs to be prefilled based on extras.
+ // This is used for reporting rendering feedback.
+ if (MessageHeaderView.ENABLE_REPORT_RENDERING_PROBLEM) {
+ Intent intent = getIntent();
+ if (intent.getExtras() != null) {
+ String toAddresses = intent.getStringExtra(EXTRA_TO);
+ if (toAddresses != null) {
+ addToAddresses(Arrays.asList(TextUtils.split(toAddresses, ",")));
+ }
+ String body = intent.getStringExtra(EXTRA_BODY);
+ if (body != null) {
+ setBody(body, false /* withSignature */);
+ }
+ }
+ }
+
if (mRefMessage != null) {
// CC field only gets populated when doing REPLY_ALL.
// BCC never gets auto-populated, unless the user is editing
@@ -3078,6 +3123,9 @@
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
+ case INIT_DRAFT_USING_REFERENCE_MESSAGE:
+ return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
+ null, null);
case REFERENCE_MESSAGE_LOADER:
return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
null, null);
@@ -3092,14 +3140,13 @@
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
int id = loader.getId();
switch (id) {
- case REFERENCE_MESSAGE_LOADER:
+ case INIT_DRAFT_USING_REFERENCE_MESSAGE:
if (data != null && data.moveToFirst()) {
mRefMessage = new Message(data);
Intent intent = getIntent();
- int action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
- initFromRefMessage(action);
- finishSetup(action, intent, null, true);
- if (action != FORWARD) {
+ initFromRefMessage(mComposeMode);
+ finishSetup(mComposeMode, intent, null);
+ if (mComposeMode != FORWARD) {
String to = intent.getStringExtra(EXTRA_TO);
if (!TextUtils.isEmpty(to)) {
mRefMessage.setTo(null);
@@ -3113,6 +3160,13 @@
finish();
}
break;
+ case REFERENCE_MESSAGE_LOADER:
+ // Only populate mRefMessage and leave other fields untouched.
+ if (data != null && data.moveToFirst()) {
+ mRefMessage = new Message(data);
+ }
+ finishSetup(mComposeMode, getIntent(), mSavedInstanceState);
+ break;
case LOADER_ACCOUNT_CURSOR:
if (data != null && data.moveToFirst()) {
// there are accounts now!
diff --git a/src/com/android/mail/content/ObjectCursorLoader.java b/src/com/android/mail/content/ObjectCursorLoader.java
index 227162f..a9a930f 100644
--- a/src/com/android/mail/content/ObjectCursorLoader.java
+++ b/src/com/android/mail/content/ObjectCursorLoader.java
@@ -20,7 +20,6 @@
import android.content.AsyncTaskLoader;
import android.content.Context;
-import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
@@ -54,6 +53,18 @@
public ObjectCursorLoader(Context context, Uri uri, String[] projection,
CursorCreator<T> factory) {
super(context);
+
+ /*
+ * If these are null, it's going to crash anyway in loadInBackground(), but this stack trace
+ * is much more useful.
+ */
+ if (uri == null) {
+ throw new NullPointerException("The uri cannot be null");
+ }
+ if (factory == null) {
+ throw new NullPointerException("The factory cannot be null");
+ }
+
mObserver = new ForceLoadContentObserver();
mUri = uri;
mProjection = projection;
@@ -68,7 +79,7 @@
if (inner != null) {
// Ensure the cursor window is filled
inner.getCount();
- registerContentObserver(inner, mObserver);
+ inner.registerContentObserver(mObserver);
}
// Modifications to the ObjectCursor, create an Object Cursor and fill the cache.
final ObjectCursor<T> cursor = new ObjectCursor<T>(inner, mFactory);
@@ -76,14 +87,6 @@
return cursor;
}
- /**
- * Registers an observer to get notifications from the content provider
- * when the cursor needs to be refreshed.
- */
- void registerContentObserver(Cursor cursor, ContentObserver observer) {
- cursor.registerContentObserver(mObserver);
- }
-
/* Runs on the UI thread */
@Override
public void deliverResult(ObjectCursor<T> cursor) {
@@ -133,11 +136,10 @@
}
@Override
- public boolean cancelLoad() {
- if (mCursor != null && !mCursor.isClosed()) {
- mCursor.close();
+ public void onCanceled(ObjectCursor<T> cursor) {
+ if (cursor != null && !cursor.isClosed()) {
+ cursor.close();
}
- return super.cancelLoad();
}
@Override
diff --git a/src/com/android/mail/preferences/MailPrefs.java b/src/com/android/mail/preferences/MailPrefs.java
index 88392ed..5a0b0d7 100644
--- a/src/com/android/mail/preferences/MailPrefs.java
+++ b/src/com/android/mail/preferences/MailPrefs.java
@@ -67,11 +67,11 @@
.add(CONVERSATION_LIST_SWIPE_ACTION)
.build();
- private static final String ENABLE_FTS = "enable-fts";
private static final String ENABLE_CHIP_DRAG_AND_DROP = "enable-chip-drag-and-drop";
public static final String ENABLE_CONVLIST_PHOTOS = "enable-convlist-photos";
public static final String ENABLE_WHOOSH_ZOOM = "enable-whoosh-zoom";
public static final String ENABLE_MUNGE_TABLES = "enable-munge-tables";
+ public static final String ENABLE_MUNGE_IMAGES = "enable-munge-images";
public static final String ENABLE_SECTIONED_INBOX_EXPERIMENT = "enable-sectioned-inbox";
}
@@ -134,13 +134,6 @@
}
@SuppressWarnings("unused")
- public boolean fullTextSearchEnabled() {
- // If experimental preferences are not enabled, return true.
- return !SHOW_EXPERIMENTAL_PREFS || getSharedPreferences().getBoolean(
- PreferenceKeys.ENABLE_FTS, true);
- }
-
- @SuppressWarnings("unused")
public boolean chipDragAndDropEnabled() {
// If experimental preferences are not enabled, return false.
return SHOW_EXPERIMENTAL_PREFS && getSharedPreferences().getBoolean(
@@ -176,6 +169,13 @@
PreferenceKeys.ENABLE_MUNGE_TABLES, true);
}
+ @SuppressWarnings("unused")
+ public boolean shouldMungeImages() {
+ // If experimental preferences are not enabled, return false.
+ return SHOW_EXPERIMENTAL_PREFS && getSharedPreferences().getBoolean(
+ PreferenceKeys.ENABLE_MUNGE_IMAGES, true);
+ }
+
private static String createWidgetPreferenceValue(Account account, String folderUri) {
return account.uri.toString() + BaseWidgetProvider.ACCOUNT_FOLDER_PREFERENCE_SEPARATOR
+ folderUri;
diff --git a/src/com/android/mail/providers/Account.java b/src/com/android/mail/providers/Account.java
index a33c8fa..5b8522f 100644
--- a/src/com/android/mail/providers/Account.java
+++ b/src/com/android/mail/providers/Account.java
@@ -726,7 +726,7 @@
map.put(AccountColumns.SettingsColumns.SNAP_HEADERS, settings.snapHeaders);
map.put(AccountColumns.SettingsColumns.REPLY_BEHAVIOR, settings.replyBehavior);
map.put(
- AccountColumns.SettingsColumns.SHOW_CHECKBOXES, settings.showCheckboxes ? 1 : 0);
+ AccountColumns.SettingsColumns.HIDE_CHECKBOXES, settings.hideCheckboxes ? 1 : 0);
map.put(AccountColumns.SettingsColumns.CONFIRM_DELETE, settings.confirmDelete ? 1 : 0);
map.put(
AccountColumns.SettingsColumns.CONFIRM_ARCHIVE, settings.confirmArchive ? 1 : 0);
diff --git a/src/com/android/mail/providers/AllAccountObserver.java b/src/com/android/mail/providers/AllAccountObserver.java
new file mode 100644
index 0000000..50ce259
--- /dev/null
+++ b/src/com/android/mail/providers/AllAccountObserver.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 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.android.mail.providers;
+
+import com.android.mail.ui.AccountController;
+import com.android.mail.utils.LogTag;
+import com.android.mail.utils.LogUtils;
+
+import android.database.DataSetObserver;
+
+/**
+ * A simple extension of {@link android.database.DataSetObserver} to provide all Accounts in
+ * {@link #onChanged(Account[])} when the list of Accounts changes. Initializing the object
+ * registers with the observer with the {@link com.android.mail.ui.AccountController} provided.
+ * The object will then begin to receive {@link #onChanged(Account[])} till {@link
+ * #unregisterAndDestroy()} is called. <p> To implement an {@link com.android.mail.providers
+ * .AllAccountObserver}, you need to implement the {@link #onChanged(Account[])} method.
+ */
+public abstract class AllAccountObserver extends DataSetObserver {
+ /**
+ * The AccountController that the observer is registered with.
+ */
+ private AccountController mController;
+
+ private static final String LOG_TAG = LogTag.getLogTag();
+
+ /**
+ * The no-argument constructor leaves the object unusable till
+ * {@link #initialize(com.android.mail.ui.AccountController)} is called.
+ */
+ public AllAccountObserver() {
+ }
+
+ /**
+ * Initializes an {@link com.android.mail.providers.AllAccountObserver} object that receives
+ * a call to {@link #onChanged(Account[])} when the controller changes the list of accounts.
+ *
+ * @param controller
+ */
+ public Account[] initialize(AccountController controller) {
+ if (controller == null) {
+ LogUtils.wtf(LOG_TAG, "AllAccountObserver initialized with null controller!");
+ }
+ mController = controller;
+ mController.registerAllAccountObserver(this);
+ return mController.getAllAccounts();
+ }
+
+ @Override
+ public final void onChanged() {
+ if (mController == null) {
+ return;
+ }
+ onChanged(mController.getAllAccounts());
+ }
+
+ /**
+ * Callback invoked when the list of Accounts changes.
+ * The updated list is passed as the argument.
+ * @param allAccounts the array of all accounts in the current application.
+ */
+ public abstract void onChanged(Account[] allAccounts);
+
+ /**
+ * Return the array of existing accounts.
+ * @return the array of existing accounts.
+ */
+ public final Account[] getAllAccounts() {
+ if (mController == null) {
+ return null;
+ }
+ return mController.getAllAccounts();
+ }
+
+ /**
+ * Unregisters for list of Account changes and makes the object unusable.
+ */
+ public void unregisterAndDestroy() {
+ if (mController == null) {
+ return;
+ }
+ mController.unregisterAllAccountObserver(this);
+ }
+}
diff --git a/src/com/android/mail/providers/Folder.java b/src/com/android/mail/providers/Folder.java
index a34786d..928d6bb 100644
--- a/src/com/android/mail/providers/Folder.java
+++ b/src/com/android/mail/providers/Folder.java
@@ -18,7 +18,6 @@
package com.android.mail.providers;
import android.content.Context;
-import android.content.CursorLoader;
import android.database.Cursor;
import android.graphics.drawable.PaintDrawable;
import android.net.Uri;
@@ -176,6 +175,11 @@
*/
public Folder parent;
+ /**
+ * The time at which the last message was received.
+ */
+ public long lastMessageTimestamp;
+
/** An immutable, empty conversation list */
public static final Collection<Folder> EMPTY = Collections.emptyList();
@@ -184,7 +188,8 @@
boolean hasChildren, int syncWindow, Uri conversationListUri, Uri childFoldersListUri,
int unseenCount, int unreadCount, int totalCount, Uri refreshUri, int syncStatus,
int lastSyncResult, int type, int iconResId, int notificationIconResId, String bgColor,
- String fgColor, Uri loadMoreUri, String hierarchicalDesc, Folder parent) {
+ String fgColor, Uri loadMoreUri, String hierarchicalDesc, Folder parent,
+ final long lastMessageTimestamp) {
this.id = id;
this.persistentId = persistentId;
this.uri = uri;
@@ -208,6 +213,7 @@
this.loadMoreUri = loadMoreUri;
this.hierarchicalDesc = hierarchicalDesc;
this.parent = parent;
+ this.lastMessageTimestamp = lastMessageTimestamp;
}
public Folder(Cursor cursor) {
@@ -240,6 +246,7 @@
loadMoreUri = !TextUtils.isEmpty(loadMore) ? Uri.parse(loadMore) : null;
hierarchicalDesc = cursor.getString(UIProvider.FOLDER_HIERARCHICAL_DESC_COLUMN);
parent = null;
+ lastMessageTimestamp = cursor.getLong(UIProvider.FOLDER_LAST_MESSAGE_TIMESTAMP_COLUMN);
}
/**
@@ -282,6 +289,7 @@
loadMoreUri = in.readParcelable(loader);
hierarchicalDesc = in.readString();
parent = in.readParcelable(loader);
+ lastMessageTimestamp = in.readLong();
}
@Override
@@ -310,6 +318,7 @@
dest.writeParcelable(loadMoreUri, 0);
dest.writeString(hierarchicalDesc);
dest.writeParcelable(parent, 0);
+ dest.writeLong(lastMessageTimestamp);
}
/**
@@ -625,6 +634,7 @@
f.name = cursor.getString(UIProvider.FOLDER_NAME_COLUMN);
f.iconResId = cursor.getInt(UIProvider.FOLDER_ICON_RES_ID_COLUMN);
f.notificationIconResId = cursor.getInt(UIProvider.FOLDER_NOTIFICATION_ICON_RES_ID_COLUMN);
+ f.lastMessageTimestamp = cursor.getLong(UIProvider.FOLDER_LAST_MESSAGE_TIMESTAMP_COLUMN);
return f;
}
}
diff --git a/src/com/android/mail/providers/FolderObserver.java b/src/com/android/mail/providers/FolderObserver.java
new file mode 100644
index 0000000..03c1ac8
--- /dev/null
+++ b/src/com/android/mail/providers/FolderObserver.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013 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.android.mail.providers;
+
+import com.android.mail.ui.FolderController;
+import com.android.mail.utils.LogTag;
+import com.android.mail.utils.LogUtils;
+
+import android.database.DataSetObserver;
+
+/**
+ * A simple extension of {@link android.database.DataSetObserver} to provide the updated Folder in
+ * {@link #onChanged(Folder)} when the Folder changes. Initializing the object registers with
+ * the observer with the {@link com.android.mail.ui.FolderController} provided. The object will then begin to
+ * receive {@link #onChanged(Folder)} till {@link #unregisterAndDestroy()} is called.
+ * <p>
+ * To implement an {@link FolderObserver}, you need to implement the {@link #onChanged(Folder)}
+ * method.
+ */
+public abstract class FolderObserver extends DataSetObserver {
+ /**
+ * The FolderController that the observer is registered with.
+ */
+ private FolderController mController;
+
+ private static final String LOG_TAG = LogTag.getLogTag();
+
+ /**
+ * The no-argument constructor leaves the object unusable till
+ * {@link #initialize(FolderController)} is called.
+ */
+ public FolderObserver () {
+ }
+
+ /**
+ * Initializes an {@link FolderObserver} object that receives a call to
+ * {@link #onChanged(Folder)} when the controller changes the Folder.
+ *
+ * @param controller
+ */
+ public Folder initialize(FolderController controller) {
+ if (controller == null) {
+ LogUtils.wtf(LOG_TAG, "FolderObserver initialized with null controller!");
+ }
+ mController = controller;
+ mController.registerFolderObserver(this);
+ return mController.getFolder();
+ }
+
+ @Override
+ public final void onChanged() {
+ if (mController == null) {
+ return;
+ }
+ onChanged(mController.getFolder());
+ }
+
+ /**
+ * Callback invoked when the Folder object is changed. Since {@link Folder} objects are
+ * immutable, updates can be received on changes to individual settings (sync on/off)
+ * in addition to changes of Folders: alice@example.com -> bob@example.com.
+ * The updated Folder is passed as the argument.
+ * @param newFolder
+ */
+ public abstract void onChanged(Folder newFolder);
+
+ /**
+ * Return the current folder.
+ * @return
+ */
+ public final Folder getFolder() {
+ if (mController == null) {
+ return null;
+ }
+ return mController.getFolder();
+ }
+
+ /**
+ * Unregisters for Folder changes and makes the object unusable.
+ */
+ public void unregisterAndDestroy() {
+ if (mController == null) {
+ return;
+ }
+ mController.unregisterFolderObserver(this);
+ }
+}
diff --git a/src/com/android/mail/providers/MailAppProvider.java b/src/com/android/mail/providers/MailAppProvider.java
index 92360c3..23c8965 100644
--- a/src/com/android/mail/providers/MailAppProvider.java
+++ b/src/com/android/mail/providers/MailAppProvider.java
@@ -27,18 +27,18 @@
import android.content.Loader;
import android.content.Loader.OnLoadCompleteListener;
import android.content.SharedPreferences;
+import android.content.res.Resources;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.Bundle;
+import com.android.mail.R;
import com.android.mail.providers.UIProvider.AccountCursorExtraKeys;
-import com.android.mail.providers.protos.boot.AccountReceiver;
import com.android.mail.utils.LogTag;
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.MatrixCursorWithExtra;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -86,7 +86,6 @@
private ContentResolver mResolver;
private static String sAuthority;
private static MailAppProvider sInstance;
- private final static Set<Uri> PENDING_ACCOUNT_URIS = Sets.newHashSet();
private volatile boolean mAccountsFullyLoaded = false;
@@ -141,24 +140,19 @@
@Override
public boolean onCreate() {
sAuthority = getAuthority();
+ sInstance = this;
mResolver = getContext().getContentResolver();
- final Intent intent = new Intent(AccountReceiver.ACTION_PROVIDER_CREATED);
- getContext().sendBroadcast(intent);
-
// Load the previously saved account list
loadCachedAccountList();
- synchronized (PENDING_ACCOUNT_URIS) {
- sInstance = this;
+ final Resources res = getContext().getResources();
+ // Load the uris for the account list
+ final String[] accountQueryUris = res.getStringArray(R.array.account_providers);
- // Handle the case where addAccountsForUriAsync was called before
- // this Provider instance was created
- final Set<Uri> urisToQery = ImmutableSet.copyOf(PENDING_ACCOUNT_URIS);
- PENDING_ACCOUNT_URIS.clear();
- for (Uri accountQueryUri : urisToQery) {
- addAccountsForUriAsync(accountQueryUri);
- }
+ for (String accountQueryUri : accountQueryUris) {
+ final Uri uri = Uri.parse(accountQueryUri);
+ addAccountsForUriAsync(uri);
}
return true;
@@ -166,9 +160,7 @@
@Override
public void shutdown() {
- synchronized (PENDING_ACCOUNT_URIS) {
- sInstance = null;
- }
+ sInstance = null;
for (CursorLoader loader : mCursorLoaderMap.values()) {
loader.stopLoading();
@@ -243,15 +235,8 @@
* @param resolver
* @param accountsQueryUri
*/
- public static void addAccountsForUriAsync(Uri accountsQueryUri) {
- synchronized (PENDING_ACCOUNT_URIS) {
- final MailAppProvider instance = getInstance();
- if (instance != null) {
- instance.startAccountsLoader(accountsQueryUri);
- } else {
- PENDING_ACCOUNT_URIS.add(accountsQueryUri);
- }
- }
+ private void addAccountsForUriAsync(Uri accountsQueryUri) {
+ startAccountsLoader(accountsQueryUri);
}
/**
diff --git a/src/com/android/mail/providers/Message.java b/src/com/android/mail/providers/Message.java
index 750d17d..ff007eb 100644
--- a/src/com/android/mail/providers/Message.java
+++ b/src/com/android/mail/providers/Message.java
@@ -110,7 +110,7 @@
/**
* @see UIProvider.MessageColumns#REF_MESSAGE_ID
*/
- public String refMessageId;
+ public Uri refMessageUri;
/**
* @see UIProvider.MessageColumns#DRAFT_TYPE
*/
@@ -227,7 +227,7 @@
dest.writeString(bodyHtml);
dest.writeString(bodyText);
dest.writeInt(embedsExternalResources ? 1 : 0);
- dest.writeString(refMessageId);
+ dest.writeParcelable(refMessageUri, 0);
dest.writeInt(draftType);
dest.writeInt(appendRefMessageContent ? 1 : 0);
dest.writeInt(hasAttachments ? 1 : 0);
@@ -261,7 +261,7 @@
bodyHtml = in.readString();
bodyText = in.readString();
embedsExternalResources = in.readInt() != 0;
- refMessageId = in.readString();
+ refMessageUri = in.readParcelable(null);
draftType = in.readInt();
appendRefMessageContent = in.readInt() != 0;
hasAttachments = in.readInt() != 0;
@@ -322,7 +322,10 @@
bodyText = cursor.getString(UIProvider.MESSAGE_BODY_TEXT_COLUMN);
embedsExternalResources = cursor
.getInt(UIProvider.MESSAGE_EMBEDS_EXTERNAL_RESOURCES_COLUMN) != 0;
- refMessageId = cursor.getString(UIProvider.MESSAGE_REF_MESSAGE_ID_COLUMN);
+ final String refMessageUriStr =
+ cursor.getString(UIProvider.MESSAGE_REF_MESSAGE_URI_COLUMN);
+ refMessageUri = !TextUtils.isEmpty(refMessageUriStr) ?
+ Uri.parse(refMessageUriStr) : null;
draftType = cursor.getInt(UIProvider.MESSAGE_DRAFT_TYPE_COLUMN);
appendRefMessageContent = cursor
.getInt(UIProvider.MESSAGE_APPEND_REF_MESSAGE_CONTENT_COLUMN) != 0;
diff --git a/src/com/android/mail/providers/Settings.java b/src/com/android/mail/providers/Settings.java
index a7519f2..6cb7c3a 100644
--- a/src/com/android/mail/providers/Settings.java
+++ b/src/com/android/mail/providers/Settings.java
@@ -66,7 +66,7 @@
public final int messageTextSize;
public final int snapHeaders;
public final int replyBehavior;
- public final boolean showCheckboxes;
+ public final boolean hideCheckboxes;
public final boolean confirmDelete;
public final boolean confirmArchive;
public final boolean confirmSend;
@@ -101,7 +101,7 @@
messageTextSize = MessageTextSize.NORMAL;
snapHeaders = SnapHeaderValue.ALWAYS;
replyBehavior = DefaultReplyBehavior.REPLY;
- showCheckboxes = false;
+ hideCheckboxes = false;
confirmDelete = false;
confirmArchive = false;
confirmSend = false;
@@ -122,7 +122,7 @@
messageTextSize = inParcel.readInt();
snapHeaders = inParcel.readInt();
replyBehavior = inParcel.readInt();
- showCheckboxes = inParcel.readInt() != 0;
+ hideCheckboxes = inParcel.readInt() != 0;
confirmDelete = inParcel.readInt() != 0;
confirmArchive = inParcel.readInt() != 0;
confirmSend = inParcel.readInt() != 0;
@@ -148,8 +148,8 @@
cursor.getColumnIndex(UIProvider.AccountColumns.SettingsColumns.SNAP_HEADERS));
replyBehavior = cursor.getInt(
cursor.getColumnIndex(UIProvider.AccountColumns.SettingsColumns.REPLY_BEHAVIOR));
- showCheckboxes = cursor.getInt(cursor.getColumnIndex(
- UIProvider.AccountColumns.SettingsColumns.SHOW_CHECKBOXES)) != 0;
+ hideCheckboxes = cursor.getInt(cursor.getColumnIndex(
+ UIProvider.AccountColumns.SettingsColumns.HIDE_CHECKBOXES)) != 0;
confirmDelete = cursor.getInt(cursor.getColumnIndex(
UIProvider.AccountColumns.SettingsColumns.CONFIRM_DELETE)) != 0;
confirmArchive = cursor.getInt(cursor.getColumnIndex(
@@ -186,8 +186,8 @@
sDefault.snapHeaders);
replyBehavior = json.optInt(AccountColumns.SettingsColumns.REPLY_BEHAVIOR,
sDefault.replyBehavior);
- showCheckboxes = json.optBoolean(AccountColumns.SettingsColumns.SHOW_CHECKBOXES,
- sDefault.showCheckboxes);
+ hideCheckboxes = json.optBoolean(AccountColumns.SettingsColumns.HIDE_CHECKBOXES,
+ sDefault.hideCheckboxes);
confirmDelete = json.optBoolean(AccountColumns.SettingsColumns.CONFIRM_DELETE,
sDefault.confirmDelete);
confirmArchive = json.optBoolean(AccountColumns.SettingsColumns.CONFIRM_ARCHIVE,
@@ -241,7 +241,7 @@
json.put(AccountColumns.SettingsColumns.MESSAGE_TEXT_SIZE, messageTextSize);
json.put(AccountColumns.SettingsColumns.SNAP_HEADERS, snapHeaders);
json.put(AccountColumns.SettingsColumns.REPLY_BEHAVIOR, replyBehavior);
- json.put(AccountColumns.SettingsColumns.SHOW_CHECKBOXES, showCheckboxes);
+ json.put(AccountColumns.SettingsColumns.HIDE_CHECKBOXES, hideCheckboxes);
json.put(AccountColumns.SettingsColumns.CONFIRM_DELETE, confirmDelete);
json.put(AccountColumns.SettingsColumns.CONFIRM_ARCHIVE, confirmArchive);
json.put(AccountColumns.SettingsColumns.CONFIRM_SEND, confirmSend);
@@ -311,7 +311,7 @@
dest.writeInt(messageTextSize);
dest.writeInt(snapHeaders);
dest.writeInt(replyBehavior);
- dest.writeInt(showCheckboxes ? 1 : 0);
+ dest.writeInt(hideCheckboxes ? 1 : 0);
dest.writeInt(confirmDelete ? 1 : 0);
dest.writeInt(confirmArchive? 1 : 0);
dest.writeInt(confirmSend? 1 : 0);
@@ -360,6 +360,19 @@
}
/**
+ * @return true if {@link UIProvider.ConversationViewMode.OVERVIEW} mode is set. In the event
+ * that the setting is not yet set, fall back to
+ * {@link UIProvider.ConversationViewMode.DEFAULT}.
+ */
+ public boolean isOverviewMode() {
+ final boolean isDefined = (conversationViewMode
+ != UIProvider.ConversationViewMode.UNDEFINED);
+ final int val = (conversationViewMode != UIProvider.ConversationViewMode.UNDEFINED) ?
+ conversationViewMode : UIProvider.ConversationViewMode.DEFAULT;
+ return (val == UIProvider.ConversationViewMode.OVERVIEW);
+ }
+
+ /**
* Return the swipe setting for the settings provided. It is safe to pass this method
* a null object. It always returns a valid {@link Swipe} setting.
* @return the auto advance setting, a constant from {@link Swipe}
@@ -404,7 +417,7 @@
&& messageTextSize == that.messageTextSize
&& snapHeaders == that.snapHeaders
&& replyBehavior == that.replyBehavior
- && showCheckboxes == that.showCheckboxes
+ && hideCheckboxes == that.hideCheckboxes
&& confirmDelete == that.confirmDelete
&& confirmArchive == that.confirmArchive
&& confirmSend == that.confirmSend
@@ -433,7 +446,7 @@
private final int calculateHashCode() {
return super.hashCode()
^ Objects.hashCode(signature, mAutoAdvance, mTransientAutoAdvance, messageTextSize,
- snapHeaders, replyBehavior, showCheckboxes, confirmDelete, confirmArchive,
+ snapHeaders, replyBehavior, hideCheckboxes, confirmDelete, confirmArchive,
confirmSend, defaultInbox, forceReplyFromDefault, maxAttachmentSize, swipe,
priorityArrowsEnabled, setupIntentUri, conversationViewMode,
veiledAddressPattern);
diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java
index 3316bb1..86ab8aa 100644
--- a/src/com/android/mail/providers/UIProvider.java
+++ b/src/com/android/mail/providers/UIProvider.java
@@ -149,7 +149,7 @@
.put(AccountColumns.SettingsColumns.MESSAGE_TEXT_SIZE, Integer.class)
.put(AccountColumns.SettingsColumns.SNAP_HEADERS, Integer.class)
.put(AccountColumns.SettingsColumns.REPLY_BEHAVIOR, Integer.class)
- .put(AccountColumns.SettingsColumns.SHOW_CHECKBOXES, Integer.class)
+ .put(AccountColumns.SettingsColumns.HIDE_CHECKBOXES, Integer.class)
.put(AccountColumns.SettingsColumns.CONFIRM_DELETE, Integer.class)
.put(AccountColumns.SettingsColumns.CONFIRM_ARCHIVE, Integer.class)
.put(AccountColumns.SettingsColumns.CONFIRM_SEND, Integer.class)
@@ -472,9 +472,9 @@
/**
* Integer column containing the user's specified checkbox preference. A
- * non zero value means to show checkboxes.
+ * non zero value means to hide checkboxes.
*/
- public static final String SHOW_CHECKBOXES = "show_checkboxes";
+ public static final String HIDE_CHECKBOXES = "hide_checkboxes";
/**
* Integer column containing the user's specified confirm delete preference value.
@@ -614,7 +614,8 @@
FolderColumns.BG_COLOR,
FolderColumns.FG_COLOR,
FolderColumns.LOAD_MORE_URI,
- FolderColumns.HIERARCHICAL_DESC
+ FolderColumns.HIERARCHICAL_DESC,
+ FolderColumns.LAST_MESSAGE_TIMESTAMP
};
public static final int FOLDER_ID_COLUMN = 0;
@@ -639,6 +640,7 @@
public static final int FOLDER_FG_COLOR_COLUMN = 19;
public static final int FOLDER_LOAD_MORE_URI_COLUMN = 20;
public static final int FOLDER_HIERARCHICAL_DESC_COLUMN = 21;
+ public static final int FOLDER_LAST_MESSAGE_TIMESTAMP_COLUMN = 22;
public static final class FolderType {
/** A user defined label. */
@@ -828,6 +830,11 @@
*/
public static final String HIERARCHICAL_DESC = "hierarchicalDesc";
+ /**
+ * The timestamp of the last message received in this folder.
+ */
+ public static final String LAST_MESSAGE_TIMESTAMP = "lastMessageTimestamp";
+
public FolderColumns() {}
}
@@ -1335,7 +1342,7 @@
public static final int MESSAGE_BODY_HTML_COLUMN = 12;
public static final int MESSAGE_BODY_TEXT_COLUMN = 13;
public static final int MESSAGE_EMBEDS_EXTERNAL_RESOURCES_COLUMN = 14;
- public static final int MESSAGE_REF_MESSAGE_ID_COLUMN = 15;
+ public static final int MESSAGE_REF_MESSAGE_URI_COLUMN = 15;
public static final int MESSAGE_DRAFT_TYPE_COLUMN = 16;
public static final int MESSAGE_APPEND_REF_MESSAGE_CONTENT_COLUMN = 17;
public static final int MESSAGE_HAS_ATTACHMENTS_COLUMN = 18;
@@ -1927,6 +1934,7 @@
* require panning
*/
public static final int READING = 1;
+ public static final int DEFAULT = OVERVIEW;
}
public static final class SnapHeaderValue {
diff --git a/src/com/android/mail/providers/protos/mock/MockUiProvider.java b/src/com/android/mail/providers/protos/mock/MockUiProvider.java
index 3cf0f0f..1055b42 100644
--- a/src/com/android/mail/providers/protos/mock/MockUiProvider.java
+++ b/src/com/android/mail/providers/protos/mock/MockUiProvider.java
@@ -387,6 +387,7 @@
@Override
public boolean onCreate() {
+ MockUiProvider.initializeMockProvider();
return true;
}
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 8d2ec4c..0f07ef0 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -36,7 +36,6 @@
import android.content.Intent;
import android.content.Loader;
import android.content.res.Resources;
-import android.database.Cursor;
import android.database.DataSetObservable;
import android.database.DataSetObserver;
import android.net.Uri;
@@ -90,6 +89,7 @@
import com.android.mail.utils.LogTag;
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.NotificationActionUtils;
+import com.android.mail.utils.Observable;
import com.android.mail.utils.Utils;
import com.android.mail.utils.VeiledAddressMatcher;
@@ -204,25 +204,12 @@
private final Set<Uri> mCurrentAccountUris = Sets.newHashSet();
protected ConversationCursor mConversationListCursor;
- private final DataSetObservable mConversationListObservable = new DataSetObservable() {
- @Override
- public void registerObserver(DataSetObserver observer) {
- final int count = mObservers.size();
- super.registerObserver(observer);
- LogUtils.d(LOG_TAG, "IN AAC.register(List)Observer: %s before=%d after=%d", observer,
- count, mObservers.size());
- }
- @Override
- public void unregisterObserver(DataSetObserver observer) {
- final int count = mObservers.size();
- super.unregisterObserver(observer);
- LogUtils.d(LOG_TAG, "IN AAC.unregister(List)Observer: %s before=%d after=%d", observer,
- count, mObservers.size());
- }
- };
+ private final DataSetObservable mConversationListObservable = new Observable("List");
/** Runnable that checks the logging level to enable/disable the logging service. */
private Runnable mLogServiceChecker = null;
+ /** List of all accounts currently known to the controller. */
+ private Account[] mAllAccounts;
/**
* Interface for actions that are deferred until after a load completes. This is for handling
@@ -240,40 +227,13 @@
private RefreshTimerTask mConversationListRefreshTask;
/** Listeners that are interested in changes to the current account. */
- private final DataSetObservable mAccountObservers = new DataSetObservable() {
- @Override
- public void registerObserver(DataSetObserver observer) {
- final int count = mObservers.size();
- super.registerObserver(observer);
- LogUtils.d(LOG_TAG, "IN AAC.register(Account)Observer: %s before=%d after=%d",
- observer, count, mObservers.size());
- }
- @Override
- public void unregisterObserver(DataSetObserver observer) {
- final int count = mObservers.size();
- super.unregisterObserver(observer);
- LogUtils.d(LOG_TAG, "IN AAC.unregister(Account)Observer: %s before=%d after=%d",
- observer, count, mObservers.size());
- }
- };
-
+ private final DataSetObservable mAccountObservers = new Observable("Account");
/** Listeners that are interested in changes to the recent folders. */
- private final DataSetObservable mRecentFolderObservers = new DataSetObservable() {
- @Override
- public void registerObserver(DataSetObserver observer) {
- final int count = mObservers.size();
- super.registerObserver(observer);
- LogUtils.d(LOG_TAG, "IN AAC.register(RecentFolder)Observer: %s before=%d after=%d",
- observer, count, mObservers.size());
- }
- @Override
- public void unregisterObserver(DataSetObserver observer) {
- final int count = mObservers.size();
- super.unregisterObserver(observer);
- LogUtils.d(LOG_TAG, "IN AAC.unregister(RecentFolder)Observer: %s before=%d after=%d",
- observer, count, mObservers.size());
- }
- };
+ private final DataSetObservable mRecentFolderObservers = new Observable("RecentFolder");
+ /** Listeners that are interested in changes to the list of all accounts. */
+ private final DataSetObservable mAllAccountObservers = new Observable("AllAccounts");
+ /** Listeners that are interested in changes to the current folder. */
+ private final DataSetObservable mFolderObservable = new Observable("CurrentFolder");
/**
* Selected conversations, if any.
@@ -302,8 +262,6 @@
/** Object that listens to all LoaderCallbacks that result in {@link Account} creation. */
private final AccountLoads mAccountCallbacks = new AccountLoads();
- private final DataSetObservable mFolderObservable = new DataSetObservable();
-
/**
* Matched addresses that must be shielded from users because they are temporary. Even though
* this is instantiated from settings, this matcher is valid for all accounts, and is expected
@@ -333,6 +291,13 @@
* perhaps.
*/
public static final int LAST_LOADER_ID = 100;
+ /**
+ * Guaranteed to be the last loader ID used by the Fragment. Loaders are owned by Activity or
+ * fragments, and within an activity, loader IDs need to be unique. Currently,
+ * {@link SectionedInboxTeaserView} is the only class that uses the
+ * {@link ConversationListFragment}'s LoaderManager.
+ */
+ public static final int LAST_FRAGMENT_LOADER_ID = 1000;
private static final int ADD_ACCOUNT_REQUEST_CODE = 1;
private static final int REAUTHENTICATE_REQUEST_CODE = 2;
@@ -500,11 +465,10 @@
if (actionBar != null && mActionBarView != null) {
actionBar.setCustomView(mActionBarView, new ActionBar.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- // Show a custom view and home icon, but remove the title
+ // Show a custom view and home icon, keep the title and subttitle
final int mask = ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_TITLE
| ActionBar.DISPLAY_SHOW_HOME;
- final int enabled = ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME;
- actionBar.setDisplayOptions(enabled, mask);
+ actionBar.setDisplayOptions(mask, mask);
mActionBarView.attach();
}
mViewMode.addListener(mActionBarView);
@@ -546,7 +510,7 @@
}
@Override
- public void onAccountChanged(Account account) {
+ public void changeAccount(Account account) {
// Is the account or account settings different from the existing account?
final boolean firstLoad = mAccount == null;
final boolean accountChanged = firstLoad || !account.uri.equals(mAccount.uri);
@@ -556,7 +520,7 @@
}
// We also don't want to do anything if the new account is null
if (account == null) {
- LogUtils.e(LOG_TAG, "AAC.onAccountChanged(null) called.");
+ LogUtils.e(LOG_TAG, "AAC.changeAccount(null) called.");
return;
}
final String accountName = account.name;
@@ -605,6 +569,21 @@
}
@Override
+ public void registerAllAccountObserver(DataSetObserver observer) {
+ mAllAccountObservers.registerObserver(observer);
+ }
+
+ @Override
+ public void unregisterAllAccountObserver(DataSetObserver observer) {
+ mAllAccountObservers.unregisterObserver(observer);
+ }
+
+ @Override
+ public Account[] getAllAccounts() {
+ return mAllAccounts;
+ }
+
+ @Override
public Account getAccount() {
return mAccount;
}
@@ -1779,8 +1758,10 @@
}
// Put the folder and conversation, and ask the loader to create this folder.
final Bundle args = new Bundle();
- args.putParcelable(Utils.EXTRA_FOLDER_URI,
- intent.getParcelableExtra(Utils.EXTRA_FOLDER_URI));
+ final Uri folderUri = intent.hasExtra(Utils.EXTRA_FOLDER_URI)
+ ? (Uri) intent.getParcelableExtra(Utils.EXTRA_FOLDER_URI)
+ : mAccount.settings.defaultInbox;
+ args.putParcelable(Utils.EXTRA_FOLDER_URI, folderUri);
args.putParcelable(Utils.EXTRA_CONVERSATION,
intent.getParcelableExtra(Utils.EXTRA_CONVERSATION));
restartOptionalLoader(LOADER_FIRST_FOLDER, mFolderCallbacks, args);
@@ -1860,8 +1841,7 @@
Utils.sConvLoadTimer.start();
}
- MailLogService.log("AbstractActivityController", "showConversation(" + conversation + " )"
- + "");
+ MailLogService.log("AbstractActivityController", "showConversation(%s)", conversation);
// Set the current conversation just in case it wasn't already set.
setCurrentConversation(conversation);
// Add the folder that we were viewing to the recent folders list.
@@ -2143,11 +2123,13 @@
}
}
if (accountChanged) {
- onAccountChanged(newAccount);
+ changeAccount(newAccount);
}
+
// Whether we have updated the current account or not, we need to update the list of
// accounts in the ActionBar.
- mActionBarView.setAccounts(allAccounts);
+ mAllAccounts = allAccounts;
+ mAllAccountObservers.notifyChanged();
return (allAccounts.length > 0);
}
@@ -2295,7 +2277,7 @@
@Override
public void run() {
onUndoAvailable(new ToastBarOperation(mTarget.size(), mAction,
- ToastBarOperation.UNDO, mIsSelectedSet));
+ ToastBarOperation.UNDO, mIsSelectedSet, mFolder));
}
}, mShowUndoBarDelay);
}
@@ -2322,7 +2304,8 @@
// conversations to.
@Override
public final void assignFolder(Collection<FolderOperation> folderOps,
- Collection<Conversation> target, boolean batch, boolean showUndo) {
+ Collection<Conversation> target, boolean batch, boolean showUndo,
+ final boolean isMoveTo) {
// Actions are destructive only when the current folder can be assigned
// to (which is the same as being able to un-assign a conversation from the folder) and
// when the list of folders contains the current folder.
@@ -2339,12 +2322,40 @@
// Update the UI elements depending no their visibility and availability
// TODO(viki): Consolidate this into a single method requestDelete.
if (isDestructive) {
+ /*
+ * If this is a MOVE operation, we want the action folder to be the destination folder.
+ * Otherwise, we want it to be the current folder.
+ *
+ * A set of folder operations is a move if there are exactly two operations: an add and
+ * a remove.
+ */
+ final Folder actionFolder;
+ if (folderOps.size() != 2) {
+ actionFolder = mFolder;
+ } else {
+ Folder addedFolder = null;
+ boolean hasRemove = false;
+ for (final FolderOperation folderOperation : folderOps) {
+ if (folderOperation.mAdd) {
+ addedFolder = folderOperation.mFolder;
+ } else {
+ hasRemove = true;
+ }
+ }
+
+ if (hasRemove && addedFolder != null) {
+ actionFolder = addedFolder;
+ } else {
+ actionFolder = mFolder;
+ }
+ }
+
folderChange = getDeferredFolderChange(target, folderOps, isDestructive,
- batch, showUndo);
+ batch, showUndo, isMoveTo, actionFolder);
delete(0, target, folderChange);
} else {
folderChange = getFolderChange(target, folderOps, isDestructive,
- batch, showUndo);
+ batch, showUndo, false /* isMoveTo */, mFolder);
requestUpdate(folderChange);
}
}
@@ -2620,8 +2631,9 @@
}
// Drag and drop is destructive: we remove conversations from the
// current folder.
- final DestructiveAction action = getFolderChange(conversations, dragDropOperations,
- isDestructive, true, true);
+ final DestructiveAction action =
+ getFolderChange(conversations, dragDropOperations, isDestructive,
+ true /* isBatch */, true /* showUndo */, true /* isMoveTo */, folder);
if (isDestructive) {
delete(0, conversations, action);
} else {
@@ -2689,7 +2701,7 @@
@Override
public void performAction() {
ToastBarOperation undoOp = new ToastBarOperation(mConversations.size(),
- R.id.change_folder, ToastBarOperation.UNDO, true);
+ R.id.change_folder, ToastBarOperation.UNDO, true /* batch */, mInitialFolder);
onUndoAvailable(undoOp);
ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>();
ContentValues values = new ContentValues();
@@ -2818,7 +2830,8 @@
return loader;
case LOADER_RECENT_FOLDERS:
LogUtils.d(LOG_TAG, "LOADER_RECENT_FOLDERS created");
- if (mAccount != null && mAccount.recentFolderListUri != null) {
+ if (mAccount != null && mAccount.recentFolderListUri != null
+ && !mAccount.recentFolderListUri.equals(Uri.EMPTY)) {
return new ObjectCursorLoader<Folder>(mContext,
mAccount.recentFolderListUri, everything, Folder.FACTORY);
}
@@ -3149,20 +3162,23 @@
private boolean mIsSelectedSet;
private boolean mShowUndo;
private int mAction;
+ private final Folder mActionFolder;
/**
* Create a new folder destruction object to act on the given conversations.
* @param target conversations to act upon.
+ * @param actionFolder the {@link Folder} being acted upon, used for displaying the undo bar
*/
private FolderDestruction(final Collection<Conversation> target,
final Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch,
- boolean showUndo, int action) {
+ boolean showUndo, int action, final Folder actionFolder) {
mTarget = ImmutableList.copyOf(target);
mFolderOps.addAll(folders);
mIsDestructive = isDestructive;
mIsSelectedSet = isBatch;
mShowUndo = showUndo;
mAction = action;
+ mActionFolder = actionFolder;
}
@Override
@@ -3172,7 +3188,7 @@
}
if (mIsDestructive && mShowUndo) {
ToastBarOperation undoOp = new ToastBarOperation(mTarget.size(), mAction,
- ToastBarOperation.UNDO, mIsSelectedSet);
+ ToastBarOperation.UNDO, mIsSelectedSet, mActionFolder);
onUndoAvailable(undoOp);
}
// For each conversation, for each operation, add/ remove the
@@ -3224,18 +3240,18 @@
public final DestructiveAction getFolderChange(Collection<Conversation> target,
Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch,
- boolean showUndo) {
+ boolean showUndo, final boolean isMoveTo, final Folder actionFolder) {
final DestructiveAction da = getDeferredFolderChange(target, folders, isDestructive,
- isBatch, showUndo);
+ isBatch, showUndo, isMoveTo, actionFolder);
registerDestructiveAction(da);
return da;
}
public final DestructiveAction getDeferredFolderChange(Collection<Conversation> target,
Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch,
- boolean showUndo) {
- return new FolderDestruction(target, folders, isDestructive, isBatch,
- showUndo, R.id.change_folder);
+ boolean showUndo, final boolean isMoveTo, final Folder actionFolder) {
+ return new FolderDestruction(target, folders, isDestructive, isBatch, showUndo,
+ isMoveTo ? R.id.move_folder : R.id.change_folder, actionFolder);
}
@Override
@@ -3245,7 +3261,7 @@
Collection<FolderOperation> folderOps = new ArrayList<FolderOperation>();
folderOps.add(new FolderOperation(toRemove, false));
return new FolderDestruction(target, folderOps, isDestructive, isBatch,
- showUndo, R.id.remove_folder);
+ showUndo, R.id.remove_folder, mFolder);
}
@Override
@@ -3332,7 +3348,7 @@
false, /* showActionIcon */
actionTextResourceId,
replaceVisibleToast,
- new ToastBarOperation(1, 0, ToastBarOperation.ERROR, false));
+ new ToastBarOperation(1, 0, ToastBarOperation.ERROR, false, folder));
}
private ActionClickedListener getRetryClickedListener(final Folder folder) {
diff --git a/src/com/android/mail/ui/AbstractConversationViewFragment.java b/src/com/android/mail/ui/AbstractConversationViewFragment.java
index 65718cb..ba63588 100644
--- a/src/com/android/mail/ui/AbstractConversationViewFragment.java
+++ b/src/com/android/mail/ui/AbstractConversationViewFragment.java
@@ -98,7 +98,6 @@
protected String mBaseUri;
protected Account mAccount;
protected final Map<String, Address> mAddressCache = Maps.newHashMap();
- protected boolean mEnableContentReadySignal;
private MessageCursor mCursor;
private Context mContext;
/**
@@ -203,17 +202,6 @@
// base uri that us guaranteed to be unique for this conversation.
mBaseUri = "x-thread://" + mAccount.name + "/" + mConversation.id;
- // On JB or newer, we use the 'webkitAnimationStart' DOM event to signal load complete
- // Below JB, try to speed up initial render by having the webview do supplemental draws to
- // custom a software canvas.
- // TODO(mindyp):
- //PAGE READINESS SIGNAL FOR JELLYBEAN AND NEWER
- // Notify the app on 'webkitAnimationStart' of a simple dummy element with a simple no-op
- // animation that immediately runs on page load. The app uses this as a signal that the
- // content is loaded and ready to draw, since WebView delays firing this event until the
- // layers are composited and everything is ready to draw.
- // This signal does not seem to be reliable, so just use the old method for now.
- mEnableContentReadySignal = false; //Utils.isRunningJellybeanOrLater();
LogUtils.d(LOG_TAG, "onCreate in ConversationViewFragment (this=%s)", this);
// Not really, we just want to get a crack to store a reference to the change_folder item
setHasOptionsMenu(true);
diff --git a/src/com/android/mail/ui/AccountChangeListener.java b/src/com/android/mail/ui/AccountChangeListener.java
deleted file mode 100644
index 7690799..0000000
--- a/src/com/android/mail/ui/AccountChangeListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2012 Google Inc.
- * Licensed to 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.android.mail.ui;
-
-import com.android.mail.providers.Account;
-
-/**
- * The callback interface for when a list item has been selected.
- */
-public interface AccountChangeListener {
- /**
- * Handles selecting a folder from within the {@link FolderListFragment}.
- *
- * @param folder the selected folder
- */
- void onAccountChanged(Account account);
-}
diff --git a/src/com/android/mail/ui/AccountController.java b/src/com/android/mail/ui/AccountController.java
index e13b2eb..1d7745c 100644
--- a/src/com/android/mail/ui/AccountController.java
+++ b/src/com/android/mail/ui/AccountController.java
@@ -45,9 +45,31 @@
*/
Account getAccount();
+
+ /**
+ * Registers to receive changes to the list of accounts, and obtain the current list.
+ */
+ void registerAllAccountObserver(DataSetObserver observer);
+
+ /**
+ * Removes a listener from receiving account list changes.
+ */
+ void unregisterAllAccountObserver(DataSetObserver observer);
+
+ /** Returns a list of all accounts currently known. */
+ Account[] getAllAccounts();
+
/**
* Returns an object that can check veiled addresses.
* @return
*/
VeiledAddressMatcher getVeiledAddressMatcher();
+
+ /**
+ * Handles selecting an account from within the {@link FolderListFragment}.
+ *
+ * @param account the account to change to.
+ */
+ void changeAccount(Account account);
+
}
diff --git a/src/com/android/mail/ui/ActivityController.java b/src/com/android/mail/ui/ActivityController.java
index 5e80e65..d1a1740 100644
--- a/src/com/android/mail/ui/ActivityController.java
+++ b/src/com/android/mail/ui/ActivityController.java
@@ -42,8 +42,7 @@
*/
public interface ActivityController extends LayoutListener,
ModeChangeListener, ConversationListCallbacks,
- FolderChangeListener, AccountChangeListener,
- ConversationSetObserver, ConversationListener,
+ FolderChangeListener, ConversationSetObserver, ConversationListener,
FolderListFragment.FolderListSelectionListener, HelpCallback, UndoListener,
ConversationUpdater, ErrorListener, FolderController, AccountController,
ConversationPositionTracker.Callbacks, ConversationListFooterView.FooterViewClickListener,
diff --git a/src/com/android/mail/ui/AddableFolderSelectorAdapter.java b/src/com/android/mail/ui/AddableFolderSelectorAdapter.java
index fcf79b0..0888369 100644
--- a/src/com/android/mail/ui/AddableFolderSelectorAdapter.java
+++ b/src/com/android/mail/ui/AddableFolderSelectorAdapter.java
@@ -84,6 +84,8 @@
.getString(UIProvider.FOLDER_LOAD_MORE_URI_COLUMN);
folder[UIProvider.FOLDER_HIERARCHICAL_DESC_COLUMN] = folderCursor
.getString(UIProvider.FOLDER_HIERARCHICAL_DESC_COLUMN);
+ folder[UIProvider.FOLDER_LAST_MESSAGE_TIMESTAMP_COLUMN] = folderCursor
+ .getLong(UIProvider.FOLDER_LAST_MESSAGE_TIMESTAMP_COLUMN);
cursor.addRow(folder);
}
} while (folderCursor.moveToNext());
diff --git a/src/com/android/mail/ui/AnimatedAdapter.java b/src/com/android/mail/ui/AnimatedAdapter.java
index 8524c29..0a75711 100644
--- a/src/com/android/mail/ui/AnimatedAdapter.java
+++ b/src/com/android/mail/ui/AnimatedAdapter.java
@@ -24,6 +24,7 @@
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
+import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -49,6 +50,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map.Entry;
public class AnimatedAdapter extends SimpleCursorAdapter implements
@@ -115,6 +117,9 @@
}
};
+ private final List<ConversationSpecialItemView> mSpecialViews;
+ private final SparseArray<ConversationSpecialItemView> mSpecialViewPositions;
+
private final void setAccount(Account newAccount) {
mAccount = newAccount;
mPriorityMarkersEnabled = mAccount.settings.priorityArrowsEnabled;
@@ -130,6 +135,12 @@
public AnimatedAdapter(Context context, ConversationCursor cursor,
ConversationSelectionSet batch, ControllableActivity activity,
SwipeableListView listView) {
+ this(context, cursor, batch, activity, listView, null);
+ }
+
+ public AnimatedAdapter(Context context, ConversationCursor cursor,
+ ConversationSelectionSet batch, ControllableActivity activity,
+ SwipeableListView listView, final List<ConversationSpecialItemView> specialViews) {
super(context, -1, cursor, UIProvider.CONVERSATION_PROJECTION, null, 0);
mContext = context;
mBatchConversations = batch;
@@ -146,6 +157,16 @@
context.getResources()
.getInteger(R.integer.dismiss_all_leavebehinds_long_delay);
}
+ mSpecialViews =
+ specialViews == null ? new ArrayList<ConversationSpecialItemView>(0)
+ : new ArrayList<ConversationSpecialItemView>(specialViews);
+ mSpecialViewPositions = new SparseArray<ConversationSpecialItemView>(mSpecialViews.size());
+
+ for (final ConversationSpecialItemView view : mSpecialViews) {
+ view.setAdapter(this);
+ }
+
+ updateSpecialViews();
}
public void cancelDismissCounter() {
@@ -169,7 +190,10 @@
@Override
public int getCount() {
- final int count = super.getCount();
+ // mSpecialViewPositions only contains the views that are currently being displayed
+ final int specialViewCount = mSpecialViewPositions.size();
+
+ final int count = super.getCount() + specialViewCount;
return mShowFooter ? count + 1 : count;
}
@@ -211,7 +235,7 @@
view = new SwipeableConversationItemView(context, mAccount.name);
}
view.bind(conv, mActivity, mBatchConversations, mFolder,
- mAccount != null ? !mAccount.settings.showCheckboxes : false, mSwipeEnabled,
+ mAccount != null ? mAccount.settings.hideCheckboxes : false, mSwipeEnabled,
mPriorityMarkersEnabled, this);
return view;
}
@@ -231,7 +255,7 @@
@Override
public int getItemViewType(int position) {
// Try to recycle views.
- if (mShowFooter && position == super.getCount()) {
+ if (mShowFooter && position == getCount() - 1) {
return TYPE_VIEW_FOOTER;
} else if (hasLeaveBehinds() || isAnimating()) {
// Setting as type -1 means the recycler won't take this view and
@@ -241,6 +265,9 @@
// types. In a future release, use position/id map to try to make
// this cleaner / faster to determine if the view is animating.
return TYPE_VIEW_DONT_RECYCLE;
+ } else if (mSpecialViewPositions.get(position) != null) {
+ // Don't recycle the special views
+ return TYPE_VIEW_DONT_RECYCLE;
}
return TYPE_VIEW_CONVERSATION;
}
@@ -306,9 +333,16 @@
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- if (mShowFooter && position == super.getCount()) {
+ if (mShowFooter && position == getCount() - 1) {
return mFooter;
}
+
+ // Check if this is a special view
+ final View specialView = (View) mSpecialViewPositions.get(position);
+ if (specialView != null) {
+ return specialView;
+ }
+
ConversationCursor cursor = (ConversationCursor) getItem(position);
final Conversation conv = cursor.getConversation();
if (isPositionUndoing(conv.id)) {
@@ -347,6 +381,7 @@
return fadeIn;
}
}
+
if (convertView != null && !(convertView instanceof SwipeableConversationItemView)) {
LogUtils.w(LOG_TAG, "Incorrect convert view received; nulling it out");
convertView = newView(mContext, cursor, parent);
@@ -497,10 +532,11 @@
@Override
public long getItemId(int position) {
- if (mShowFooter && position == super.getCount()) {
+ if (mShowFooter && position == getCount() - 1
+ || mSpecialViewPositions.get(position) != null) {
return -1;
}
- return super.getItemId(position);
+ return super.getItemId(position - getPositionOffset(position));
}
private View getDeletingView(int position, Conversation conversation, ViewGroup parent,
@@ -541,7 +577,7 @@
return;
}
((SwipeableConversationItemView) view).bind(cursor, mActivity, mBatchConversations, mFolder,
- mAccount != null ? !mAccount.settings.showCheckboxes : false,
+ mAccount != null ? mAccount.settings.hideCheckboxes : false,
mSwipeEnabled, mPriorityMarkersEnabled, this);
}
@@ -551,7 +587,7 @@
position, null, parent);
view.reset();
view.bind(conversation, mActivity, mBatchConversations, mFolder,
- mAccount != null ? !mAccount.settings.showCheckboxes : false, mSwipeEnabled,
+ mAccount != null ? mAccount.settings.hideCheckboxes : false, mSwipeEnabled,
mPriorityMarkersEnabled, this);
mAnimatingViews.put(conversation.id, view);
return view;
@@ -559,10 +595,12 @@
@Override
public Object getItem(int position) {
- if (mShowFooter && position == super.getCount()) {
+ if (mShowFooter && position == getCount() - 1) {
return mFooter;
+ } else if (mSpecialViewPositions.get(position) != null) {
+ return mSpecialViewPositions.get(position);
}
- return super.getItem(position);
+ return super.getItem(position - getPositionOffset(position));
}
private boolean isPositionDeleting(long id) {
@@ -797,4 +835,67 @@
item.cancelFadeOutText();
}
}
+
+ private void updateSpecialViews() {
+ mSpecialViewPositions.clear();
+
+ for (int i = 0; i < mSpecialViews.size(); i++) {
+ final ConversationSpecialItemView specialView = mSpecialViews.get(i);
+ specialView.onUpdate(mAccount.name, mFolder, getConversationCursor());
+
+ if (specialView.getShouldDisplayInList()) {
+ mSpecialViewPositions.put(specialView.getPosition(), specialView);
+ }
+ }
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ updateSpecialViews();
+ super.notifyDataSetChanged();
+ }
+
+ @Override
+ public void changeCursor(final Cursor cursor) {
+ super.changeCursor(cursor);
+ updateSpecialViews();
+ }
+
+ @Override
+ public void changeCursorAndColumns(final Cursor c, final String[] from, final int[] to) {
+ super.changeCursorAndColumns(c, from, to);
+ updateSpecialViews();
+ }
+
+ @Override
+ public Cursor swapCursor(final Cursor c) {
+ final Cursor oldCursor = super.swapCursor(c);
+ updateSpecialViews();
+
+ return oldCursor;
+ }
+
+ /**
+ * Gets the offset for the given position in the underlying cursor, based on any special views
+ * that may be above it.
+ */
+ public int getPositionOffset(final int position) {
+ int offset = 0;
+
+ for (int i = 0; i < mSpecialViewPositions.size(); i++) {
+ final int key = mSpecialViewPositions.keyAt(i);
+ final ConversationSpecialItemView specialView = mSpecialViewPositions.get(key);
+ if (specialView.getPosition() <= position) {
+ offset++;
+ }
+ }
+
+ return offset;
+ }
+
+ public void cleanup() {
+ for (final ConversationSpecialItemView view : mSpecialViews) {
+ view.cleanup();
+ }
+ }
}
diff --git a/src/com/android/mail/ui/ControllableActivity.java b/src/com/android/mail/ui/ControllableActivity.java
index 37e70f5..f4a1d87 100644
--- a/src/com/android/mail/ui/ControllableActivity.java
+++ b/src/com/android/mail/ui/ControllableActivity.java
@@ -116,4 +116,9 @@
void stopDragMode();
boolean isAccessibilityEnabled();
+
+ /**
+ * Gets a helper to provide addition features in the conversation list. This may be null.
+ */
+ ConversationListHelper getConversationListHelper();
}
diff --git a/src/com/android/mail/ui/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java
index d1d1153..12d2087 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -43,6 +43,7 @@
import com.android.mail.providers.AccountObserver;
import com.android.mail.providers.Conversation;
import com.android.mail.providers.Folder;
+import com.android.mail.providers.FolderObserver;
import com.android.mail.providers.Settings;
import com.android.mail.providers.UIProvider;
import com.android.mail.providers.UIProvider.AccountCapabilities;
@@ -57,6 +58,7 @@
import com.android.mail.utils.Utils;
import java.util.Collection;
+import java.util.List;
/**
* The conversation list UI component.
@@ -117,7 +119,7 @@
private ConversationListFooterView mFooterView;
private View mEmptyView;
private ErrorListener mErrorListener;
- private DataSetObserver mFolderObserver;
+ private FolderObserver mFolderObserver;
private DataSetObserver mConversationCursorObserver;
private ConversationSelectionSet mSelectedSet;
@@ -140,21 +142,6 @@
super();
}
- // update the pager title strip as the Folder's conversation count changes
- private class FolderObserver extends DataSetObserver {
- @Override
- public void onChanged() {
- if (mActivity == null) {
- return;
- }
- final FolderController controller = mActivity.getFolderController();
- if (controller == null) {
- return;
- }
- onFolderUpdated(controller.getFolder());
- }
- }
-
private class ConversationCursorObserver extends DataSetObserver {
@Override
public void onChanged() {
@@ -264,15 +251,32 @@
null);
mFooterView.setClickListener(mActivity);
final ConversationCursor conversationCursor = getConversationListCursor();
- mListAdapter = new AnimatedAdapter(mActivity.getApplicationContext(),
- conversationCursor, mActivity.getSelectedSet(), mActivity, mListView);
+
+ final ConversationListHelper helper = mActivity.getConversationListHelper();
+ final List<ConversationSpecialItemView> specialItemViews =
+ helper != null ? helper.makeConversationListSpecialViews(getActivity(), mAccount,
+ mActivity.getFolderListSelectionListener()) : null;
+ if (specialItemViews != null) {
+ // Attach to the LoaderManager
+ for (final ConversationSpecialItemView view : specialItemViews) {
+ view.bindLoaderManager(getLoaderManager());
+ }
+ }
+
+ mListAdapter = new AnimatedAdapter(mActivity.getApplicationContext(), conversationCursor,
+ mActivity.getSelectedSet(), mActivity, mListView, specialItemViews);
mListAdapter.addFooter(mFooterView);
mListView.setAdapter(mListAdapter);
mSelectedSet = mActivity.getSelectedSet();
mListView.setSelectionSet(mSelectedSet);
mListAdapter.hideFooter();
- mFolderObserver = new FolderObserver();
- mActivity.getFolderController().registerFolderObserver(mFolderObserver);
+ mFolderObserver = new FolderObserver(){
+ @Override
+ public void onChanged(Folder newFolder) {
+ onFolderUpdated(newFolder);
+ }
+ };
+ mFolderObserver.initialize(mActivity.getFolderController());
mConversationCursorObserver = new ConversationCursorObserver();
mUpdater = mActivity.getConversationUpdater();
mUpdater.registerConversationListObserver(mConversationCursorObserver);
@@ -438,7 +442,7 @@
mActivity.unsetViewModeListener(this);
if (mFolderObserver != null) {
- mActivity.getFolderController().unregisterFolderObserver(mFolderObserver);
+ mFolderObserver.unregisterAndDestroy();
mFolderObserver = null;
}
if (mConversationCursorObserver != null) {
@@ -446,6 +450,7 @@
mConversationCursorObserver = null;
}
mAccountObserver.unregisterAndDestroy();
+ getAnimatedAdapter().cleanup();
super.onDestroyView();
}
@@ -475,7 +480,7 @@
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
// Ignore anything that is not a conversation item. Could be a footer.
if (!(view instanceof ConversationItemView)) {
- return true;
+ return false;
}
((ConversationItemView) view).toggleCheckMarkOrBeginDrag();
return true;
@@ -506,7 +511,7 @@
if (!(view instanceof ToggleableItem)) {
return;
}
- if (!mAccount.settings.showCheckboxes && !mSelectedSet.isEmpty()) {
+ if (mAccount.settings.hideCheckboxes && !mSelectedSet.isEmpty()) {
ToggleableItem v = (ToggleableItem) view;
v.toggleCheckMarkOrBeginDrag();
} else {
@@ -584,30 +589,40 @@
/**
* View the message at the given position.
- * @param position
+ *
+ * @param position The position of the conversation in the list (as opposed to its position in
+ * the cursor)
*/
- protected void viewConversation(int position) {
+ protected void viewConversation(final int position) {
LogUtils.d(LOG_TAG, "ConversationListFragment.viewConversation(%d)", position);
- setSelected(position, true);
- final ConversationCursor cursor = getConversationListCursor();
- if (cursor != null && cursor.moveToPosition(position)) {
- final Conversation conv = new Conversation(cursor);
- conv.position = position;
- mCallbacks.onConversationSelected(conv, false /* inLoaderCallbacks */);
- }
+
+ final ConversationCursor cursor =
+ (ConversationCursor) getAnimatedAdapter().getItem(position);
+ final Conversation conv = cursor.getConversation();
+ /*
+ * The cursor position may be different than the position method parameter because of
+ * special views in the list.
+ */
+ conv.position = cursor.getPosition();
+ setSelected(conv.position, true);
+ mCallbacks.onConversationSelected(conv, false /* inLoaderCallbacks */);
}
/**
* Sets the selected conversation to the position given here.
- * @param position
+ * @param position The position of the conversation in the cursor (as opposed to in the list)
* @param different if the currently selected conversation is different from the one provided
* here. This is a difference in conversations, not a difference in positions. For example, a
* conversation at position 2 can move to position 4 as a result of new mail.
*/
- public void setSelected(int position, boolean different) {
+ public void setSelected(final int cursorPosition, boolean different) {
if (mListView.getChoiceMode() == ListView.CHOICE_MODE_NONE) {
return;
}
+
+ final int position =
+ cursorPosition + getAnimatedAdapter().getPositionOffset(cursorPosition);
+
if (different) {
mListView.smoothScrollToPosition(position);
}
@@ -775,6 +790,11 @@
mListAdapter.notifyDataSetChanged();
}
mConversationCursorHash = newCursorHash;
+
+ if (newCursor != null) {
+ newCursor.markContentsSeen();
+ }
+
// If a current conversation is available, and none is selected in the list, then ask
// the list to select the current conversation.
final Conversation conv = mCallbacks.getCurrentConversation();
diff --git a/src/com/android/mail/ui/ConversationListHelper.java b/src/com/android/mail/ui/ConversationListHelper.java
new file mode 100644
index 0000000..8470be1
--- /dev/null
+++ b/src/com/android/mail/ui/ConversationListHelper.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 Google Inc.
+ * Licensed to 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.android.mail.ui;
+
+import android.content.Context;
+
+import com.android.mail.providers.Account;
+import com.android.mail.ui.FolderListFragment.FolderListSelectionListener;
+
+import java.util.List;
+
+public interface ConversationListHelper {
+ /**
+ * Creates a list of newly created special views.
+ */
+ List<ConversationSpecialItemView> makeConversationListSpecialViews(Context context,
+ Account account, FolderListSelectionListener listener);
+}
diff --git a/src/com/android/mail/ui/ConversationSpecialItemView.java b/src/com/android/mail/ui/ConversationSpecialItemView.java
new file mode 100644
index 0000000..8488162
--- /dev/null
+++ b/src/com/android/mail/ui/ConversationSpecialItemView.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Google Inc.
+ * Licensed to 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.android.mail.ui;
+
+import android.app.LoaderManager;
+import android.widget.BaseAdapter;
+
+import com.android.mail.browse.ConversationCursor;
+import com.android.mail.providers.Folder;
+
+/**
+ * An interface for a view that can be inserted into an {@link AnimatedAdapter} at an arbitrary
+ * point. The methods described here control whether the view gets displayed, and what it displays.
+ */
+public interface ConversationSpecialItemView {
+ /**
+ * Called when there as an update to the information being displayed.
+ *
+ * @param cursor The {@link ConversationCursor}. May be <code>null</code>
+ */
+ void onUpdate(String account, Folder folder, ConversationCursor cursor);
+
+ boolean getShouldDisplayInList();
+
+ int getPosition();
+
+ void setAdapter(BaseAdapter adapter);
+
+ void bindLoaderManager(LoaderManager loaderManager);
+
+ /**
+ * Called when the view is being destroyed.
+ */
+ void cleanup();
+}
diff --git a/src/com/android/mail/ui/ConversationUpdater.java b/src/com/android/mail/ui/ConversationUpdater.java
index fe7f621..55511ac 100644
--- a/src/com/android/mail/ui/ConversationUpdater.java
+++ b/src/com/android/mail/ui/ConversationUpdater.java
@@ -23,7 +23,6 @@
import com.android.mail.browse.ConfirmDialogFragment;
import com.android.mail.browse.ConversationCursor;
-import com.android.mail.browse.ConversationItemView;
import com.android.mail.browse.MessageCursor.ConversationMessage;
import com.android.mail.providers.Conversation;
import com.android.mail.providers.ConversationInfo;
@@ -142,15 +141,17 @@
boolean showUndo);
/**
- * Assign the target conversations to the given folders, and remove them from all other
- * folders that they might be assigned to.
+ * Assign the target conversations to the given folders, and remove them from all other folders
+ * that they might be assigned to.
* @param folders the folders to assign the conversations to.
* @param target the conversations to act upon.
* @param batch whether this is a batch operation
* @param showUndo whether to show the undo bar
+ * @param isMoveTo <code>true</code> if this is a move operation, <code>false</code> if it is
+ * some other type of folder change operation
*/
public void assignFolder(Collection<FolderOperation> folders, Collection<Conversation> target,
- boolean batch, boolean showUndo);
+ boolean batch, boolean showUndo, boolean isMoveTo);
/**
* Refreshes the conversation list, if one exists.
diff --git a/src/com/android/mail/ui/ConversationViewFragment.java b/src/com/android/mail/ui/ConversationViewFragment.java
index e73c380..8aae3f3 100644
--- a/src/com/android/mail/ui/ConversationViewFragment.java
+++ b/src/com/android/mail/ui/ConversationViewFragment.java
@@ -83,10 +83,12 @@
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.Utils;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
@@ -193,6 +195,8 @@
private long mWebViewLoadStartMs;
+ private final Map<String, String> mMessageTransforms = Maps.newHashMap();
+
private final DataSetObserver mLoadedObserver = new DataSetObserver() {
@Override
public void onChanged() {
@@ -785,10 +789,11 @@
mWebView.getSettings().setBlockNetworkImage(!allowNetworkImages);
+ final MailPrefs prefs = MailPrefs.get(getContext());
// If the conversation has specified a base uri, use it here, otherwise use mBaseUri
return mTemplates.endConversation(mBaseUri, mConversation.getBaseUri(mBaseUri), 320,
mWebView.getViewportWidth(), enableContentReadySignal, isOverviewMode(mAccount),
- MailPrefs.get(getContext()).shouldMungeTables());
+ prefs.shouldMungeTables(), prefs.shouldMungeImages());
}
private void renderSuperCollapsedBlock(int start, int end) {
@@ -960,6 +965,18 @@
"javascript:unblockImages(['%s']);", TextUtils.join("','", messageDomIds));
mWebView.loadUrl(url);
}
+
+ @Override
+ public boolean supportsMessageTransforms() {
+ return true;
+ }
+
+ @Override
+ public String getMessageTransforms(final Message msg) {
+ final String domId = mTemplates.getMessageDomId(msg);
+ return (domId == null) ? null : mMessageTransforms.get(domId);
+ }
+
// END message header callbacks
@Override
@@ -1025,7 +1042,7 @@
}
private static boolean isOverviewMode(Account acct) {
- return acct.settings.conversationViewMode == UIProvider.ConversationViewMode.OVERVIEW;
+ return acct.settings.isOverviewMode();
}
private void setupOverviewMode() {
@@ -1216,6 +1233,13 @@
return 0f;
}
}
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ public void onMessageTransform(String messageDomId, String transformText) {
+ LogUtils.i(LOG_TAG, "TRANSFORM: (%s) %s", messageDomId, transformText);
+ mMessageTransforms.put(messageDomId, transformText);
+ }
}
/**
@@ -1648,7 +1672,7 @@
mTemplates.appendMessageHtml(msgItem.getMessage(), true /* expanded */,
safeForImages, 0, 0);
final String html = mTemplates.endConversation(mBaseUri,
- mConversation.getBaseUri(mBaseUri), 0, 0, false, false, false);
+ mConversation.getBaseUri(mBaseUri), 0, 0, false, false, false, false);
mMessageView.loadDataWithBaseURL(mBaseUri, html, "text/html", "utf-8", null);
mMessageViewLoadStartMs = SystemClock.uptimeMillis();
diff --git a/src/com/android/mail/ui/FolderItemView.java b/src/com/android/mail/ui/FolderItemView.java
index 6281339..8235602 100644
--- a/src/com/android/mail/ui/FolderItemView.java
+++ b/src/com/android/mail/ui/FolderItemView.java
@@ -20,6 +20,7 @@
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.mail.providers.Account;
import com.android.mail.providers.Folder;
import com.android.mail.providers.UIProvider.FolderType;
import com.android.mail.utils.LogTag;
@@ -131,10 +132,20 @@
}
}
+ public void bind(Account account, DropHandler dropHandler, int count) {
+ mFolder = null;
+ mDropHandler = dropHandler;
+ mFolderTextView.setText(account.name);
+ mFolderParentIcon.setVisibility(View.GONE);
+ mUnreadCountTextView.setVisibility(View.GONE);
+ setUnseenCount(Color.BLACK, 0);
+ setUnreadCount(count);
+ }
+
/**
* Sets the unread count, taking care to hide/show the textview if the count is zero/non-zero.
*/
- private final void setUnreadCount(int count) {
+ private void setUnreadCount(int count) {
mUnreadCountTextView.setVisibility(count > 0 ? View.VISIBLE : View.GONE);
if (count > 0) {
mUnreadCountTextView.setText(Utils.getUnreadCountString(getContext(), count));
@@ -144,7 +155,7 @@
/**
* Sets the unseen count, taking care to hide/show the textview if the count is zero/non-zero.
*/
- private final void setUnseenCount(final int color, final int count) {
+ private void setUnseenCount(final int color, final int count) {
mUnseenCountTextView.setVisibility(count > 0 ? View.VISIBLE : View.GONE);
if (count > 0) {
mUnseenCountTextView.setBackgroundColor(color);
diff --git a/src/com/android/mail/ui/FolderListFragment.java b/src/com/android/mail/ui/FolderListFragment.java
index ca80106..fed9da4 100644
--- a/src/com/android/mail/ui/FolderListFragment.java
+++ b/src/com/android/mail/ui/FolderListFragment.java
@@ -34,12 +34,10 @@
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
-import android.widget.TextView;
import com.android.mail.R;
-import com.android.mail.providers.Folder;
-import com.android.mail.providers.RecentFolderObserver;
-import com.android.mail.providers.UIProvider;
+import com.android.mail.adapter.DrawerItem;
+import com.android.mail.providers.*;
import com.android.mail.providers.UIProvider.FolderType;
import com.android.mail.utils.LogTag;
import com.android.mail.utils.LogUtils;
@@ -61,10 +59,14 @@
private Uri mFolderListUri;
/** True if you want a sectioned FolderList, false otherwise. */
private boolean mIsSectioned;
+ /** Is the current device using tablet UI (true if 2-pane, false if 1-pane) */
+ private boolean mIsTabletUI;
/** An {@link ArrayList} of {@link FolderType}s to exclude from displaying. */
private ArrayList<Integer> mExcludedFolderTypes;
- /** Callback into the parent */
- private FolderListSelectionListener mListener;
+ /** Object that changes folders on our behalf. */
+ private FolderListSelectionListener mFolderChanger;
+ /** Object that changes accounts on our behalf */
+ private AccountController mAccountChanger;
/** The currently selected folder (the folder being viewed). This is never null. */
private Uri mSelectedFolderUri = Uri.EMPTY;
@@ -77,16 +79,18 @@
private Folder mParentFolder;
private static final int FOLDER_LOADER_ID = 0;
- public static final int MODE_DEFAULT = 0;
- public static final int MODE_PICK = 1;
/** Key to store {@link #mParentFolder}. */
private static final String ARG_PARENT_FOLDER = "arg-parent-folder";
/** Key to store {@link #mFolderListUri}. */
private static final String ARG_FOLDER_URI = "arg-folder-list-uri";
/** Key to store {@link #mIsSectioned} */
private static final String ARG_IS_SECTIONED = "arg-is-sectioned";
+ /** Key to store {@link #mIsTabletUI} */
+ private static final String ARG_IS_TABLET_UI = "arg-is-tablet-ui";
/** Key to store {@link #mExcludedFolderTypes} */
private static final String ARG_EXCLUDED_FOLDER_TYPES = "arg-excluded-folder-types";
+ /** Should the {@link FolderListFragment} show less labels to begin with? */
+ private static final boolean ARE_ITEMS_COLLAPSED = true;
private static final String BUNDLE_LIST_STATE = "flf-list-state";
private static final String BUNDLE_SELECTED_FOLDER = "flf-selected-folder";
@@ -97,31 +101,24 @@
private View mEmptyView;
/** Observer to wait for changes to the current folder so we can change the selected folder */
private FolderObserver mFolderObserver = null;
+ /** Listen for account changes. */
+ private AccountObserver mAccountObserver = null;
+
+ /** Listen to changes to list of all accounts */
+ private AllAccountObserver mAllAccountObserver = null;
/**
- * Type of currently selected folder: {@link FolderListAdapter.Item#FOLDER_SYSTEM},
- * {@link FolderListAdapter.Item#FOLDER_RECENT} or {@link FolderListAdapter.Item#FOLDER_USER}.
+ * Type of currently selected folder: {@link DrawerItem#FOLDER_SYSTEM},
+ * {@link DrawerItem#FOLDER_RECENT} or {@link DrawerItem#FOLDER_USER}.
*/
- // Setting to NOT_A_FOLDER = leaving uninitialized.
- private int mSelectedFolderType = FolderListAdapter.Item.NOT_A_FOLDER;
+ // Setting to INERT_HEADER = leaving uninitialized.
+ private int mSelectedFolderType = DrawerItem.INERT_HEADER;
private Cursor mFutureData;
private ConversationListCallbacks mConversationListCallback;
+ /** The current account according to the controller */
+ private Account mCurrentAccount;
- /**
- * Listens to folder changes from the controller and updates state accordingly.
- */
- private final class FolderObserver extends DataSetObserver {
- @Override
- public void onChanged() {
- if (mActivity == null) {
- return;
- }
- final FolderController controller = mActivity.getFolderController();
- if (controller == null) {
- return;
- }
- setSelectedFolder(controller.getFolder());
- }
- }
+ /** List of all accounts currently known */
+ private Account[] mAllAccounts;
/**
* Constructor needs to be public to handle orientation changes and activity lifecycle events.
@@ -133,21 +130,24 @@
/**
* Creates a new instance of {@link ConversationListFragment}, initialized
* to display conversation list context.
- * @param isSectioned TODO(viki):
+ * @param isSectioned True if sections should be shown for folder list
+ * @param isTabletUI True if two-pane layout, false if not
*/
public static FolderListFragment newInstance(Folder parentFolder, Uri folderUri,
- boolean isSectioned) {
- return newInstance(parentFolder, folderUri, isSectioned, null);
+ boolean isSectioned, boolean isTabletUI) {
+ return newInstance(parentFolder, folderUri, isSectioned, null, isTabletUI);
}
/**
* Creates a new instance of {@link ConversationListFragment}, initialized
* to display conversation list context.
- * @param isSectioned TODO(viki):
+ * @param isSectioned True if sections should be shown for folder list
* @param excludedFolderTypes A list of {@link FolderType}s to exclude from displaying
+ * @param isTabletUI True if two-pane layout, false if not
*/
public static FolderListFragment newInstance(Folder parentFolder, Uri folderUri,
- boolean isSectioned, final ArrayList<Integer> excludedFolderTypes) {
+ boolean isSectioned, final ArrayList<Integer> excludedFolderTypes,
+ boolean isTabletUI) {
final FolderListFragment fragment = new FolderListFragment();
final Bundle args = new Bundle();
if (parentFolder != null) {
@@ -155,6 +155,7 @@
}
args.putString(ARG_FOLDER_URI, folderUri.toString());
args.putBoolean(ARG_IS_SECTIONED, isSectioned);
+ args.putBoolean(ARG_IS_TABLET_UI, isTabletUI);
if (excludedFolderTypes != null) {
args.putIntegerArrayList(ARG_EXCLUDED_FOLDER_TYPES, excludedFolderTypes);
}
@@ -179,14 +180,38 @@
mConversationListCallback = mActivity.getListHandler();
final FolderController controller = mActivity.getFolderController();
// Listen to folder changes in the future
- mFolderObserver = new FolderObserver();
+ mFolderObserver = new FolderObserver() {
+ @Override
+ public void onChanged(Folder newFolder) {
+ setSelectedFolder(newFolder);
+ }
+ };
if (controller != null) {
// Only register for selected folder updates if we have a controller.
- controller.registerFolderObserver(mFolderObserver);
- mCurrentFolderForUnreadCheck = controller.getFolder();
+ mCurrentFolderForUnreadCheck = mFolderObserver.initialize(controller);
+ }
+ final AccountController accountController = mActivity.getAccountController();
+ mAccountObserver = new AccountObserver() {
+ @Override
+ public void onChanged(Account newAccount) {
+ setSelectedAccount(newAccount);
+ }
+ };
+ if (accountController != null) {
+ // Current account and its observer.
+ mCurrentAccount = mAccountObserver.initialize(accountController);
+ // List of all accounts and its observer.
+ mAllAccountObserver = new AllAccountObserver(){
+ @Override
+ public void onChanged(Account[] allAccounts) {
+ mAllAccounts = allAccounts;
+ }
+ };
+ mAllAccounts = mAllAccountObserver.initialize(accountController);
+ mAccountChanger = accountController;
}
- mListener = mActivity.getFolderListSelectionListener();
+ mFolderChanger = mActivity.getFolderListSelectionListener();
if (mActivity.isFinishing()) {
// Activity is finishing, just bail.
return;
@@ -197,7 +222,12 @@
mCursorAdapter = new HierarchicalFolderListAdapter(null, mParentFolder);
selectedFolder = mActivity.getHierarchyFolder();
} else {
- mCursorAdapter = new FolderListAdapter(R.layout.folder_item, mIsSectioned);
+ // Initiate FLA with accounts and folders collapsed in the list
+ // The second param is for whether folders should be collapsed
+ // The third param is for whether accounts should be collapsed
+ mCursorAdapter = new FolderListAdapter(mIsSectioned,
+ !mIsTabletUI && ARE_ITEMS_COLLAPSED,
+ !mIsTabletUI && ARE_ITEMS_COLLAPSED);
selectedFolder = controller == null ? null : controller.getFolder();
}
// Is the selected folder fresher than the one we have restored from a bundle?
@@ -216,6 +246,7 @@
mFolderListUri = Uri.parse(args.getString(ARG_FOLDER_URI));
mParentFolder = (Folder) args.getParcelable(ARG_PARENT_FOLDER);
mIsSectioned = args.getBoolean(ARG_IS_SECTIONED);
+ mIsTabletUI = args.getBoolean(ARG_IS_TABLET_UI);
mExcludedFolderTypes = args.getIntegerArrayList(ARG_EXCLUDED_FOLDER_TYPES);
final View rootView = inflater.inflate(R.layout.folder_list, null);
mListView = (ListView) rootView.findViewById(android.R.id.list);
@@ -272,31 +303,54 @@
// Clear the adapter.
setListAdapter(null);
if (mFolderObserver != null) {
- FolderController controller = mActivity.getFolderController();
- if (controller != null) {
- controller.unregisterFolderObserver(mFolderObserver);
- mFolderObserver = null;
- }
+ mFolderObserver.unregisterAndDestroy();
+ mFolderObserver = null;
+ }
+ if (mAccountObserver != null) {
+ mAccountObserver.unregisterAndDestroy();
+ mAccountObserver = null;
+ }
+ if (mAllAccountObserver != null) {
+ mAllAccountObserver.unregisterAndDestroy();
+ mAllAccountObserver = null;
}
super.onDestroyView();
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
- viewFolder(position);
+ viewFolderOrChangeAccount(position);
}
/**
* Display the conversation list from the folder at the position given.
- * @param position
+ * @param position a zero indexed position into the list.
*/
- private void viewFolder(int position) {
+ private void viewFolderOrChangeAccount(int position) {
final Object item = getListAdapter().getItem(position);
final Folder folder;
- if (item instanceof FolderListAdapter.Item) {
- final FolderListAdapter.Item folderItem = (FolderListAdapter.Item) item;
- folder = mCursorAdapter.getFullFolder(folderItem);
- mSelectedFolderType = folderItem.mFolderType;
+ if (item instanceof DrawerItem) {
+ final DrawerItem folderItem = (DrawerItem) item;
+ // Could be a folder, account, or expand block.
+ final int itemType = mCursorAdapter.getItemType(folderItem);
+ if (itemType == DrawerItem.VIEW_ACCOUNT) {
+ // Account, so switch.
+ folder = null;
+ final Account account = mCursorAdapter.getFullAccount(folderItem);
+ mAccountChanger.changeAccount(account);
+ } else if (itemType == DrawerItem.VIEW_FOLDER) {
+ // Folder type, so change folders only.
+ folder = mCursorAdapter.getFullFolder(folderItem);
+ mSelectedFolderType = folderItem.mFolderType;
+ } else {
+ // Block for expanding/contracting labels/accounts
+ folder = null;
+ if(!folderItem.mIsExpandForAccount) {
+ mCursorAdapter.toggleShowLessFolders();
+ } else {
+ mCursorAdapter.toggleShowLessAccounts();
+ }
+ }
} else if (item instanceof Folder) {
folder = (Folder) item;
} else {
@@ -309,10 +363,7 @@
// update its parent!
folder.parent = folder.equals(mParentFolder) ? null : mParentFolder;
// Go to the conversation list for this folder.
- mListener.onFolderSelected(folder);
- } else {
- LogUtils.d(LOG_TAG, "FolderListFragment unable to get a full fledged folder" +
- " to hand to the listener for position %d", position);
+ mFolderChanger.onFolderSelected(folder);
}
}
@@ -360,8 +411,21 @@
private interface FolderListFragmentCursorAdapter extends ListAdapter {
/** Update the folder list cursor with the cursor given here. */
void setCursor(Cursor cursor);
- /** Get the cursor associated with this adapter **/
- Folder getFullFolder(FolderListAdapter.Item item);
+ /** Toggles showing more accounts or less accounts. */
+ boolean toggleShowLessAccounts();
+ /** Toggles showing more folders or less. */
+ boolean toggleShowLessFolders();
+ /**
+ * Given an item, find the type of the item, which is {@link
+ * DrawerItem#VIEW_FOLDER}, {@link DrawerItem#VIEW_ACCOUNT} or
+ * {@link DrawerItem#VIEW_MORE}
+ * @return the type of the item.
+ */
+ int getItemType(DrawerItem item);
+ /** Get the folder associated with this item. **/
+ Folder getFullFolder(DrawerItem item);
+ /** Get the account associated with this item. **/
+ Account getFullAccount(DrawerItem item);
/** Remove all observers and destroy the object. */
void destroy();
/** Notifies the adapter that the data has changed. */
@@ -380,131 +444,30 @@
}
};
+ /** After given number of accounts, show "more" until expanded. */
+ private static final int MAX_ACCOUNTS = 2;
+ /** After the given number of labels, show "more" until expanded. */
+ private static final int MAX_FOLDERS = 7;
+
private final RecentFolderList mRecentFolders;
/** True if the list is sectioned, false otherwise */
private final boolean mIsSectioned;
- private final LayoutInflater mInflater;
/** All the items */
- private final List<Item> mItemList = new ArrayList<Item>();
+ private final List<DrawerItem> mItemList = new ArrayList<DrawerItem>();
/** Cursor into the folder list. This might be null. */
private Cursor mCursor = null;
-
- /** A union of either a folder or a resource string */
- private class Item {
- public int mPosition;
- public final Folder mFolder;
- public final int mResource;
- /** Either {@link #VIEW_FOLDER} or {@link #VIEW_HEADER} */
- public final int mType;
- /** A normal folder, also a child, if a parent is specified. */
- private static final int VIEW_FOLDER = 0;
- /** A text-label which serves as a header in sectioned lists. */
- private static final int VIEW_HEADER = 1;
-
- /**
- * Either {@link #FOLDER_SYSTEM}, {@link #FOLDER_RECENT} or {@link #FOLDER_USER} when
- * {@link #mType} is {@link #VIEW_FOLDER}, and {@link #NOT_A_FOLDER} otherwise.
- */
- public final int mFolderType;
- private static final int NOT_A_FOLDER = 0;
- private static final int FOLDER_SYSTEM = 1;
- private static final int FOLDER_RECENT = 2;
- private static final int FOLDER_USER = 3;
-
- /**
- * Create a folder item with the given type.
- * @param folder
- * @param folderType one of {@link #FOLDER_SYSTEM}, {@link #FOLDER_RECENT} or
- * {@link #FOLDER_USER}
- */
- private Item(Folder folder, int folderType, int cursorPosition) {
- mFolder = folder;
- mResource = -1;
- mType = VIEW_FOLDER;
- mFolderType = folderType;
- mPosition = cursorPosition;
- }
- /**
- * Create a header item with a string resource.
- * @param resource the string resource: R.string.all_folders_heading
- */
- private Item(int resource) {
- mFolder = null;
- mResource = resource;
- mType = VIEW_HEADER;
- mFolderType = NOT_A_FOLDER;
- }
-
- private final View getView(int position, View convertView, ViewGroup parent) {
- if (mType == VIEW_FOLDER) {
- return getFolderView(position, convertView, parent);
- } else {
- return getHeaderView(position, convertView, parent);
- }
- }
-
- /**
- * Returns a text divider between sections.
- * @param convertView
- * @param parent
- * @return a text header at the given position.
- */
- private final View getHeaderView(int position, View convertView, ViewGroup parent) {
- final TextView headerView;
- if (convertView != null) {
- headerView = (TextView) convertView;
- } else {
- headerView = (TextView) mInflater.inflate(
- R.layout.folder_list_header, parent, false);
- }
- headerView.setText(mResource);
- return headerView;
- }
-
- /**
- * Return a folder: either a parent folder or a normal (child or flat)
- * folder.
- * @param position
- * @param convertView
- * @param parent
- * @return a view showing a folder at the given position.
- */
- private final View getFolderView(int position, View convertView, ViewGroup parent) {
- final FolderItemView folderItemView;
- if (convertView != null) {
- folderItemView = (FolderItemView) convertView;
- } else {
- folderItemView =
- (FolderItemView) mInflater.inflate(R.layout.folder_item, null, false);
- }
- folderItemView.bind(mFolder, mActivity);
- if (mListView != null) {
- final boolean isSelected = (mFolderType == mSelectedFolderType)
- && mFolder.uri.equals(mSelectedFolderUri);
- mListView.setItemChecked(position, isSelected);
- // If this is the current folder, also check to verify that the unread count
- // matches what the action bar shows.
- if (isSelected && (mCurrentFolderForUnreadCheck != null)
- && mFolder.unreadCount != mCurrentFolderForUnreadCheck.unreadCount) {
- folderItemView.overrideUnreadCount(
- mCurrentFolderForUnreadCheck.unreadCount);
- }
- }
- Folder.setFolderBlockColor(mFolder, folderItemView.findViewById(R.id.color_block));
- Folder.setIcon(mFolder, (ImageView) folderItemView.findViewById(R.id.folder_icon));
- return folderItemView;
- }
- }
+ /** Watcher for tracking and receiving unread counts for mail */
+ private FolderWatcher mFolderWatcher = null;
+ private boolean mShowLessFolders;
+ private boolean mShowLessAccounts;
/**
* Creates a {@link FolderListAdapter}.This is a flat folder list of all the folders for the
* given account.
- * @param layout
* @param isSectioned TODO(viki):
*/
- public FolderListAdapter(int layout, boolean isSectioned) {
+ public FolderListAdapter(boolean isSectioned, boolean showLess, boolean showLessAccounts) {
super();
- mInflater = LayoutInflater.from(mActivity.getActivityContext());
mIsSectioned = isSectioned;
final RecentFolderController controller = mActivity.getRecentFolderController();
if (controller != null && mIsSectioned) {
@@ -512,22 +475,48 @@
} else {
mRecentFolders = null;
}
+ mFolderWatcher = new FolderWatcher(mActivity, this);
+ mShowLessFolders = showLess;
+ mShowLessAccounts = showLessAccounts;
+ for (int i=0; i < mAllAccounts.length; i++) {
+ final Uri uri = mAllAccounts[i].settings.defaultInbox;
+ mFolderWatcher.startWatching(uri);
+ }
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- return ((Item) getItem(position)).getView(position, convertView, parent);
+ final DrawerItem item = (DrawerItem) getItem(position);
+ final View view = item.getView(position, convertView, parent);
+ final int type = item.mType;
+ if (mListView!= null) {
+ final boolean isSelected =
+ item.isHighlighted(mCurrentFolderForUnreadCheck, mSelectedFolderType);
+ if (type == DrawerItem.VIEW_FOLDER) {
+ mListView.setItemChecked(position, isSelected);
+ }
+ // If this is the current folder, also check to verify that the unread count
+ // matches what the action bar shows.
+ if (type == DrawerItem.VIEW_FOLDER
+ && isSelected
+ && (mCurrentFolderForUnreadCheck != null)
+ && item.mFolder.unreadCount != mCurrentFolderForUnreadCheck.unreadCount) {
+ ((FolderItemView) view).overrideUnreadCount(
+ mCurrentFolderForUnreadCheck.unreadCount);
+ }
+ }
+ return view;
}
@Override
public int getViewTypeCount() {
- // Headers and folders
- return 2;
+ // Accounts, headers and folders
+ return DrawerItem.getViewTypes();
}
@Override
public int getItemViewType(int position) {
- return ((Item) getItem(position)).mType;
+ return ((DrawerItem) getItem(position)).mType;
}
@Override
@@ -537,22 +526,27 @@
@Override
public boolean isEnabled(int position) {
- // We disallow taps on headers
- return ((Item) getItem(position)).mType != Item.VIEW_HEADER;
+ final DrawerItem item = (DrawerItem) getItem(position);
+ return item.isItemEnabled(getCurrentAccountUri());
+
+ }
+
+ private Uri getCurrentAccountUri() {
+ return mCurrentAccount == null ? Uri.EMPTY : mCurrentAccount.uri;
}
@Override
public boolean areAllItemsEnabled() {
- // The headers are not enabled.
+ // The headers and current accounts are not enabled.
return false;
}
/**
* Returns all the recent folders from the list given here. Safe to call with a null list.
- * @param recentList
+ * @param recentList a list of all recently accessed folders.
* @return a valid list of folders, which are all recent folders.
*/
- private final List<Folder> getRecentFolders(RecentFolderList recentList) {
+ private List<Folder> getRecentFolders(RecentFolderList recentList) {
final List<Folder> folderList = new ArrayList<Folder>();
if (recentList == null) {
return folderList;
@@ -567,21 +561,84 @@
}
/**
- * Recalculates the system, recent and user label lists. Notifies that the data has changed.
- * This method modifies all the three lists on every single invocation.
+ * Toggle boolean for what folders are shown and which ones are
+ * hidden. Redraws list after toggling to show changes.
+ * @return true if folders are hidden, false if all are shown
+ */
+ @Override
+ public boolean toggleShowLessFolders() {
+ mShowLessFolders = !mShowLessFolders;
+ recalculateList();
+ return mShowLessFolders;
+ }
+
+ /**
+ * Toggle boolean for what accounts are shown and which ones are
+ * hidden. Redraws list after toggling to show changes.
+ * @return true if accounts are hidden, false if all are shown
+ */
+ @Override
+ public boolean toggleShowLessAccounts() {
+ mShowLessAccounts = !mShowLessAccounts;
+ recalculateList();
+ return mShowLessAccounts;
+ }
+
+ /**
+ * Responsible for verifying mCursor, adding collapsed view items
+ * when necessary, and notifying the data set has changed.
*/
private void recalculateList() {
if (mCursor == null || mCursor.isClosed() || mCursor.getCount() <= 0
|| !mCursor.moveToFirst()) {
return;
}
+ recalculateListFolders();
+ if(mShowLessFolders) {
+ mItemList.add(new DrawerItem(mActivity, R.string.folder_list_more, false));
+ }
+ // Ask the list to invalidate its views.
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Recalculates the system, recent and user label lists.
+ * This method modifies all the three lists on every single invocation.
+ */
+ private void recalculateListFolders() {
mItemList.clear();
+ if (mAllAccounts != null) {
+ // Add the accounts at the top.
+ // TODO(shahrk): The logic here is messy and will be changed
+ // to properly add/reflect on LRU/MRU account
+ // changes similar to RecentFoldersList
+ if (mShowLessAccounts && mAllAccounts.length > MAX_ACCOUNTS) {
+ mItemList.add(new DrawerItem(
+ mActivity, R.string.folder_list_show_all_accounts, true));
+ final int unreadCount =
+ getFolderUnreadCount(mCurrentAccount.settings.defaultInbox);
+ mItemList.add(new DrawerItem(mActivity, mCurrentAccount, unreadCount));
+ } else {
+ Uri currentAccountUri = getCurrentAccountUri();
+ for (final Account c : mAllAccounts) {
+ if (!currentAccountUri.equals(c.uri)) {
+ final int otherAccountUnreadCount =
+ getFolderUnreadCount(c.settings.defaultInbox);
+ mItemList.add(new DrawerItem(mActivity, c, otherAccountUnreadCount));
+ }
+ }
+ final int accountUnreadCount =
+ getFolderUnreadCount(mCurrentAccount.settings.defaultInbox);
+ mItemList.add(new DrawerItem(mActivity, mCurrentAccount, accountUnreadCount));
+ }
+ }
if (!mIsSectioned) {
// Adapter for a flat list. Everything is a FOLDER_USER, and there are no headers.
do {
final Folder f = Folder.getDeficientDisplayOnlyFolder(mCursor);
if (mExcludedFolderTypes == null || !mExcludedFolderTypes.contains(f.type)) {
- mItemList.add(new Item(f, Item.FOLDER_USER, mCursor.getPosition()));
+ mItemList.add(new DrawerItem(mActivity, f, DrawerItem.FOLDER_USER,
+ mCursor.getPosition()));
}
} while (mCursor.moveToNext());
// Ask the list to invalidate its views.
@@ -589,16 +646,25 @@
return;
}
+ // Tracks how many folders have been added through the rest of the function
+ int folderCount = 0;
// Otherwise, this is an adapter for a sectioned list.
// First add all the system folders.
- final List<Item> userFolderList = new ArrayList<Item>();
+ final List<DrawerItem> userFolderList = new ArrayList<DrawerItem>();
do {
final Folder f = Folder.getDeficientDisplayOnlyFolder(mCursor);
if (mExcludedFolderTypes == null || !mExcludedFolderTypes.contains(f.type)) {
if (f.isProviderFolder()) {
- mItemList.add(new Item(f, Item.FOLDER_SYSTEM, mCursor.getPosition()));
+ mItemList.add(new DrawerItem(mActivity, f, DrawerItem.FOLDER_SYSTEM,
+ mCursor.getPosition()));
+ // Check if show less is enabled and we've passed max folders
+ folderCount++;
+ if(mShowLessFolders && folderCount >= MAX_FOLDERS) {
+ return;
+ }
} else {
- userFolderList.add(new Item(f, Item.FOLDER_USER, mCursor.getPosition()));
+ userFolderList.add(new DrawerItem(
+ mActivity, f, DrawerItem.FOLDER_USER, mCursor.getPosition()));
}
}
} while (mCursor.moveToNext());
@@ -616,20 +682,33 @@
}
if (recentFolderList.size() > 0) {
- mItemList.add(new Item(R.string.recent_folders_heading));
+ mItemList.add(new DrawerItem(mActivity, R.string.recent_folders_heading));
for (Folder f : recentFolderList) {
- mItemList.add(new Item(f, Item.FOLDER_RECENT, -1));
+ mItemList.add(new DrawerItem(mActivity, f, DrawerItem.FOLDER_RECENT, -1));
+ // Check if show less is enabled and we've passed max folders
+ folderCount++;
+ if(mShowLessFolders && folderCount >= MAX_FOLDERS) {
+ return;
+ }
}
}
// If there are user folders, add them and a header.
if (userFolderList.size() > 0) {
- mItemList.add(new Item(R.string.all_folders_heading));
- for (final Item i : userFolderList) {
+ mItemList.add(new DrawerItem(mActivity, R.string.all_folders_heading));
+ for (final DrawerItem i : userFolderList) {
mItemList.add(i);
+ // Check if show less is enabled and we've passed max folders
+ folderCount++;
+ if(mShowLessFolders && folderCount >= MAX_FOLDERS) {
+ return;
+ }
}
}
- // Ask the list to invalidate its views.
- notifyDataSetChanged();
+ }
+
+ private int getFolderUnreadCount(Uri folderUri) {
+ final Folder folder = mFolderWatcher.get(folderUri);
+ return folder != null ? folder.unreadCount : 0;
}
@Override
@@ -654,8 +733,13 @@
}
@Override
- public Folder getFullFolder(Item folderItem) {
- if (folderItem.mFolderType == Item.FOLDER_RECENT) {
+ public int getItemType(DrawerItem item) {
+ return item.mType;
+ }
+
+ @Override
+ public Folder getFullFolder(DrawerItem folderItem) {
+ if (folderItem.mFolderType == DrawerItem.FOLDER_RECENT) {
return folderItem.mFolder;
} else {
int pos = folderItem.mPosition;
@@ -671,6 +755,11 @@
}
}
}
+
+ @Override
+ public Account getFullAccount(DrawerItem item) {
+ return item.mAccount;
+ }
}
private class HierarchicalFolderListAdapter extends ArrayAdapter<Folder>
@@ -699,14 +788,14 @@
@Override
public int getItemViewType(int position) {
- Folder f = getItem(position);
+ final Folder f = getItem(position);
return f.uri.equals(mParentUri) ? PARENT : CHILD;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- FolderItemView folderItemView;
- Folder folder = getItem(position);
+ final FolderItemView folderItemView;
+ final Folder folder = getItem(position);
boolean isParent = folder.uri.equals(mParentUri);
if (convertView != null) {
folderItemView = (FolderItemView) convertView;
@@ -754,7 +843,13 @@
}
@Override
- public Folder getFullFolder(FolderListAdapter.Item folderItem) {
+ public int getItemType(DrawerItem item) {
+ // Always returns folders for now.
+ return DrawerItem.VIEW_FOLDER;
+ }
+
+ @Override
+ public Folder getFullFolder(DrawerItem folderItem) {
int pos = folderItem.mPosition;
if (mCursor == null || mCursor.isClosed()) {
// See if we have a cursor hanging out we can use
@@ -768,6 +863,21 @@
return null;
}
}
+
+ @Override
+ public Account getFullAccount(DrawerItem item) {
+ return null;
+ }
+
+ @Override
+ public boolean toggleShowLessFolders() {
+ return false;
+ }
+
+ @Override
+ public boolean toggleShowLessAccounts() {
+ return false;
+ }
}
/**
@@ -782,7 +892,7 @@
}
// If the current folder changed, we don't have a selected folder type anymore.
if (!folder.uri.equals(mSelectedFolderUri)) {
- mSelectedFolderType = FolderListAdapter.Item.NOT_A_FOLDER;
+ mSelectedFolderType = DrawerItem.INERT_HEADER;
}
mCurrentFolderForUnreadCheck = folder;
mSelectedFolderUri = folder.uri;
@@ -794,15 +904,23 @@
/**
* Sets the selected folder type safely.
- * @param folder
+ * @param folder folder to set to.
*/
private void setSelectedFolderType(Folder folder) {
// If it is set already, assume it is correct.
- if (mSelectedFolderType != FolderListAdapter.Item.NOT_A_FOLDER) {
+ if (mSelectedFolderType != DrawerItem.INERT_HEADER) {
return;
}
- mSelectedFolderType = folder.isProviderFolder() ? FolderListAdapter.Item.FOLDER_SYSTEM
- : FolderListAdapter.Item.FOLDER_USER;
+ mSelectedFolderType = folder.isProviderFolder() ? DrawerItem.FOLDER_SYSTEM
+ : DrawerItem.FOLDER_USER;
+ }
+
+ /**
+ * Sets the current account to the one provided here.
+ * @param account the current account to set to.
+ */
+ private void setSelectedAccount(Account account){
+ mCurrentAccount = account;
}
public interface FolderListSelectionListener {
diff --git a/src/com/android/mail/ui/FolderSelectionActivity.java b/src/com/android/mail/ui/FolderSelectionActivity.java
index c336ff3..3bee9b0 100644
--- a/src/com/android/mail/ui/FolderSelectionActivity.java
+++ b/src/com/android/mail/ui/FolderSelectionActivity.java
@@ -110,7 +110,7 @@
private void createFolderListFragment(Folder parent, Uri uri) {
final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
final Fragment fragment = FolderListFragment.newInstance(parent, uri, false,
- getExcludedFolderTypes());
+ getExcludedFolderTypes(), true);
fragmentTransaction.replace(R.id.content_pane, fragment);
fragmentTransaction.commitAllowingStateLoss();
}
@@ -371,4 +371,10 @@
// Unsupported
return true;
}
+
+ @Override
+ public ConversationListHelper getConversationListHelper() {
+ // Unsupported
+ return null;
+ }
}
diff --git a/src/com/android/mail/ui/FolderSelectorAdapter.java b/src/com/android/mail/ui/FolderSelectorAdapter.java
index c9f7718..d5d85af 100644
--- a/src/com/android/mail/ui/FolderSelectorAdapter.java
+++ b/src/com/android/mail/ui/FolderSelectorAdapter.java
@@ -211,9 +211,9 @@
if (view == null) {
view = mInflater.inflate(mLayout, parent, false);
}
- FolderRow row = (FolderRow) getItem(position);
- Folder folder = row.getFolder();
- String folderDisplay = !TextUtils.isEmpty(folder.hierarchicalDesc) ?
+ final FolderRow row = (FolderRow) getItem(position);
+ final Folder folder = row.getFolder();
+ final String folderDisplay = !TextUtils.isEmpty(folder.hierarchicalDesc) ?
folder.hierarchicalDesc : folder.name;
checkBox = (CompoundButton) view.findViewById(R.id.checkbox);
display = (TextView) view.findViewById(R.id.folder_name);
diff --git a/src/com/android/mail/ui/HtmlConversationTemplates.java b/src/com/android/mail/ui/HtmlConversationTemplates.java
index 5eeeb3e..92340b3 100644
--- a/src/com/android/mail/ui/HtmlConversationTemplates.java
+++ b/src/com/android/mail/ui/HtmlConversationTemplates.java
@@ -182,7 +182,7 @@
public String endConversation(String docBaseUri, String conversationBaseUri, int viewWidth,
int viewportWidth, boolean enableContentReadySignal, boolean normalizeMessageWidths,
- boolean enableMungeTables) {
+ boolean enableMungeTables, boolean enableMungeImages) {
if (!mInProgress) {
throw new IllegalStateException("must call startConversation first");
}
@@ -192,7 +192,7 @@
append(sConversationLower, contentReadyClass, mContext.getString(R.string.hide_elided),
mContext.getString(R.string.show_elided), docBaseUri, conversationBaseUri,
viewWidth, viewportWidth, enableContentReadySignal, normalizeMessageWidths,
- enableMungeTables);
+ enableMungeTables, enableMungeImages);
mInProgress = false;
diff --git a/src/com/android/mail/ui/MailActionBarView.java b/src/com/android/mail/ui/MailActionBarView.java
index 9202569..9e94d33 100644
--- a/src/com/android/mail/ui/MailActionBarView.java
+++ b/src/com/android/mail/ui/MailActionBarView.java
@@ -17,6 +17,23 @@
package com.android.mail.ui;
+import com.android.mail.ConversationListContext;
+import com.android.mail.R;
+import com.android.mail.browse.SnippetTextView;
+import com.android.mail.providers.Account;
+import com.android.mail.providers.AccountObserver;
+import com.android.mail.providers.AllAccountObserver;
+import com.android.mail.providers.Conversation;
+import com.android.mail.providers.Folder;
+import com.android.mail.providers.FolderObserver;
+import com.android.mail.providers.SearchRecentSuggestionsProvider;
+import com.android.mail.providers.UIProvider;
+import com.android.mail.providers.UIProvider.AccountCapabilities;
+import com.android.mail.providers.UIProvider.FolderCapabilities;
+import com.android.mail.utils.LogTag;
+import com.android.mail.utils.LogUtils;
+import com.android.mail.utils.Utils;
+
import android.app.ActionBar;
import android.app.SearchManager;
import android.app.SearchableInfo;
@@ -24,7 +41,6 @@
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
-import android.database.DataSetObserver;
import android.os.Bundle;
import android.os.Handler;
import android.text.SpannableString;
@@ -40,22 +56,6 @@
import android.widget.SearchView.OnQueryTextListener;
import android.widget.SearchView.OnSuggestionListener;
-import com.android.mail.AccountSpinnerAdapter;
-import com.android.mail.ConversationListContext;
-import com.android.mail.R;
-import com.android.mail.browse.SnippetTextView;
-import com.android.mail.providers.Account;
-import com.android.mail.providers.AccountObserver;
-import com.android.mail.providers.Conversation;
-import com.android.mail.providers.Folder;
-import com.android.mail.providers.SearchRecentSuggestionsProvider;
-import com.android.mail.providers.UIProvider;
-import com.android.mail.providers.UIProvider.AccountCapabilities;
-import com.android.mail.providers.UIProvider.FolderCapabilities;
-import com.android.mail.utils.LogTag;
-import com.android.mail.utils.LogUtils;
-import com.android.mail.utils.Utils;
-
/**
* View to manage the various states of the Mail Action Bar.
* <p>
@@ -78,8 +78,6 @@
private int mMode = ViewMode.UNKNOWN;
private MenuItem mSearch;
- private AccountSpinnerAdapter mSpinnerAdapter;
- private MailSpinner mSpinner;
/**
* The account currently being shown
*/
@@ -96,12 +94,12 @@
private MenuItem mRefreshItem;
private MenuItem mFolderSettingsItem;
private View mRefreshActionView;
+ /** True if the current device is a tablet, false otherwise. */
+ private boolean mIsOnTablet;
private boolean mRefreshInProgress;
private Conversation mCurrentConversation;
- /**
- * True if we are running on tablet.
- */
- private final boolean mIsOnTablet;
+ private AllAccountObserver mAllAccountObserver;
+ private boolean mHaveMultipleAccounts = false;
public static final String LOG_TAG = LogTag.getLogTag();
@@ -113,13 +111,12 @@
}
};
private final boolean mShowConversationSubject;
- private DataSetObserver mFolderObserver;
+ private FolderObserver mFolderObserver;
private final AccountObserver mAccountObserver = new AccountObserver() {
@Override
public void onChanged(Account newAccount) {
updateAccount(newAccount);
- mSpinner.setAccount(mAccount);
}
};
@@ -165,9 +162,6 @@
return reports;
}
- /** True if the application has more than one account. */
- private boolean mHasManyAccounts;
-
// Created via view inflation.
@SuppressWarnings("unused")
public MailActionBarView(Context context) {
@@ -185,18 +179,9 @@
mIsOnTablet = Utils.useTabletUI(r);
}
- // update the pager title strip as the Folder's conversation count changes
- private class FolderObserver extends DataSetObserver {
- @Override
- public void onChanged() {
- onFolderUpdated(mController.getFolder());
- }
- }
-
@Override
protected void onFinishInflate() {
super.onFinishInflate();
-
mSubjectView = (SnippetTextView) findViewById(R.id.conversation_subject);
}
@@ -281,26 +266,32 @@
mActionBar = actionBar;
mController = callback;
mActivity = activity;
- mFolderObserver = new FolderObserver();
- mController.registerFolderObserver(mFolderObserver);
- // We don't want to include the "Show all folders" menu item on tablet devices
- final Context context = getContext();
- final boolean showAllFolders = !Utils.useTabletUI(context.getResources());
- mSpinnerAdapter = new AccountSpinnerAdapter(activity, context, showAllFolders);
- mSpinner = (MailSpinner) findViewById(R.id.account_spinner);
- mSpinner.setAdapter(mSpinnerAdapter);
- mSpinner.setController(mController);
+ mFolderObserver = new FolderObserver() {
+ @Override
+ public void onChanged(Folder newFolder) {
+ onFolderUpdated(newFolder);
+ }
+ };
+ mFolderObserver.initialize(mController);
+ mAllAccountObserver = new AllAccountObserver() {
+ @Override
+ public void onChanged(Account[] allAccounts) {
+ mHaveMultipleAccounts = (allAccounts.length > 1);
+ }
+ };
+ mAllAccountObserver.initialize(mController);
updateAccount(mAccountObserver.initialize(activity.getAccountController()));
}
private void updateAccount(Account account) {
mAccount = account;
if (mAccount != null) {
- ContentResolver resolver = mActivity.getActivityContext().getContentResolver();
- Bundle bundle = new Bundle(1);
+ final ContentResolver resolver = mActivity.getActivityContext().getContentResolver();
+ final Bundle bundle = new Bundle(1);
bundle.putParcelable(UIProvider.SetCurrentAccountColumns.ACCOUNT, account);
resolver.call(mAccount.uri, UIProvider.AccountCallMethods.SET_CURRENT_ACCOUNT,
mAccount.uri.toString(), bundle);
+ setFolderAndAccount();
}
}
@@ -312,72 +303,34 @@
}
/**
- * Sets the array of accounts to the value provided here.
- * @param accounts array of all accounts on the device.
- */
- public void setAccounts(Account[] accounts) {
- mSpinnerAdapter.setAccountArray(accounts);
- mHasManyAccounts = accounts.length > 1;
- enableDisableSpinnner();
- }
-
- /**
- * Changes the spinner state according to the following logic. On phone we always show recent
- * labels: pre-populating if necessary. So on phone we always want to enable the spinner.
- * On tablet, we enable the spinner when the Folder list is NOT visible: In conversation view,
- * and search conversation view.
- */
- private void enableDisableSpinnner() {
- // Spinner is always shown on phone, and it is enabled by default, so don't mess with it.
- // By default the drawable is set in the XML layout, and the view is enabled.
- if (!mIsOnTablet) {
- return;
- }
- // We do not populate default recent folders on tablet, so we need to check that in the
- // conversation mode we have some recent folders. If we don't have any, then we should
- // disable the spinner.
- final boolean hasRecentsInConvView = ViewMode.isConversationMode(mMode)
- && mSpinnerAdapter.hasRecentFolders();
- // More than one account, OR has recent folders in conversation view.
- final boolean enabled = mHasManyAccounts || hasRecentsInConvView;
- mSpinner.changeEnabledState(enabled);
- }
-
- /**
* Called by the owner of the ActionBar to set the
* folder that is currently being displayed.
*/
public void setFolder(Folder folder) {
setRefreshInProgress(false);
mFolder = folder;
- mSpinner.setFolder(folder);
+ setFolderAndAccount();
mActivity.invalidateOptionsMenu();
}
public void onDestroy() {
if (mFolderObserver != null) {
- mController.unregisterFolderObserver(mFolderObserver);
+ mFolderObserver.unregisterAndDestroy();
mFolderObserver = null;
}
- mSpinnerAdapter.destroy();
+ if (mAllAccountObserver != null) {
+ mAllAccountObserver.unregisterAndDestroy();
+ mAllAccountObserver = null;
+ }
mAccountObserver.unregisterAndDestroy();
}
@Override
public void onViewModeChanged(int newMode) {
mMode = newMode;
- // Always update the options menu and redraw. This will read the new mode and redraw
- // the options menu.
- enableDisableSpinnner();
mActivity.invalidateOptionsMenu();
// Check if we are either on a phone, or in Conversation mode on tablet. For these, the
// recent folders is enabled.
- if (!mIsOnTablet || mMode == ViewMode.CONVERSATION) {
- mSpinnerAdapter.enableRecentFolders();
- } else {
- mSpinnerAdapter.disableRecentFolders();
- }
-
switch (mMode) {
case ViewMode.UNKNOWN:
closeSearchField();
@@ -480,9 +433,9 @@
* Put the ActionBar in List navigation mode. This starts the spinner up if it is missing.
*/
private void showNavList() {
- setTitleModeFlags(ActionBar.DISPLAY_SHOW_CUSTOM);
- mSpinner.setVisibility(View.VISIBLE);
+ setTitleModeFlags(ActionBar.DISPLAY_SHOW_TITLE);
mSubjectView.setVisibility(View.GONE);
+ setFolderAndAccount();
}
/**
@@ -492,24 +445,23 @@
*/
protected void setSnippetMode() {
setTitleModeFlags(ActionBar.DISPLAY_SHOW_CUSTOM);
- mSpinner.setVisibility(View.GONE);
mSubjectView.setVisibility(View.VISIBLE);
-
mSubjectView.addOnLayoutChangeListener(mSnippetLayoutListener);
}
private void setFoldersMode() {
setTitleModeFlags(ActionBar.DISPLAY_SHOW_TITLE);
mActionBar.setTitle(R.string.folders);
- mActionBar.setSubtitle(mAccount.name);
+ if (mHaveMultipleAccounts) {
+ mActionBar.setSubtitle(mAccount.name);
+ }
}
/**
* Set the actionbar mode to empty: no title, no custom content.
*/
protected void setEmptyMode() {
- setTitleModeFlags(ActionBar.DISPLAY_SHOW_CUSTOM);
- mSpinner.setVisibility(View.GONE);
+ setTitleModeFlags(ActionBar.DISPLAY_SHOW_TITLE);
mSubjectView.setVisibility(View.GONE);
}
@@ -618,10 +570,30 @@
}
/**
+ * Uses the current state to update the current folder {@link #mFolder} and the current
+ * account {@link #mAccount} shown in the actionbar.
+ */
+ private void setFolderAndAccount() {
+ // Check if we should be changing the actionbar at all, and back off if not.
+ final boolean isShowingFolderAndAccount =
+ (mActionBar != null && (mIsOnTablet || ViewMode.isListMode(mMode)));
+ if (!isShowingFolderAndAccount) {
+ return;
+ }
+ if (mFolder != null) {
+ mActionBar.setTitle(mFolder.name);
+ }
+ if (mAccount != null && mHaveMultipleAccounts) {
+ mActionBar.setSubtitle(mAccount.name);
+ }
+ // TODO(viki): Show unread count.
+ }
+
+ /**
* Notify that the folder has changed.
*/
public void onFolderUpdated(Folder folder) {
- mSpinner.onFolderUpdated(folder);
+ setFolderAndAccount();
if (folder.isSyncInProgress()) {
onRefreshStarted();
} else {
@@ -660,7 +632,6 @@
private void setTitleModeFlags(int enabledFlags) {
final int mask = ActionBar.DISPLAY_SHOW_TITLE
| ActionBar.DISPLAY_SHOW_CUSTOM | DISPLAY_TITLE_MULTIPLE_LINES;
-
mActionBar.setDisplayOptions(enabledFlags, mask);
}
@@ -736,7 +707,7 @@
Utils.setMenuItemVisibility(menu, R.id.move_to, mFolder != null
&& mFolder.supportsCapability(FolderCapabilities.ALLOWS_REMOVE_CONVERSATION));
final MenuItem removeFolder = menu.findItem(R.id.remove_folder);
- if (removeFolder != null) {
+ if (mFolder != null && removeFolder != null) {
removeFolder.setTitle(mActivity.getApplicationContext().getString(
R.string.remove_folder, mFolder.name));
}
diff --git a/src/com/android/mail/ui/MailActivity.java b/src/com/android/mail/ui/MailActivity.java
index 73a4db3..0bc75da 100644
--- a/src/com/android/mail/ui/MailActivity.java
+++ b/src/com/android/mail/ui/MailActivity.java
@@ -67,7 +67,7 @@
* to be static since the {@link ComposeActivity} needs to statically change the account name
* and have the NFC message changed accordingly.
*/
- private static String sAccountName = null;
+ protected static String sAccountName = null;
/**
* Create an NFC message (in the NDEF: Nfc Data Exchange Format) to instruct the recepient to
@@ -404,4 +404,10 @@
mAccessibilityEnabled = enabled;
mController.onAccessibilityStateChanged();
}
+
+ @Override
+ public ConversationListHelper getConversationListHelper() {
+ // Unsupported
+ return null;
+ }
}
diff --git a/src/com/android/mail/ui/MailSpinner.java b/src/com/android/mail/ui/MailSpinner.java
deleted file mode 100644
index 854eeac..0000000
--- a/src/com/android/mail/ui/MailSpinner.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/**
- * Copyright (c) 2012, Google Inc.
- *
- * 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.android.mail.ui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.ListPopupWindow;
-import android.widget.TextView;
-
-import com.android.mail.AccountSpinnerAdapter;
-import com.android.mail.R;
-import com.android.mail.providers.Account;
-import com.android.mail.providers.Folder;
-import com.android.mail.utils.LogTag;
-import com.android.mail.utils.LogUtils;
-import com.android.mail.utils.Utils;
-
-public class MailSpinner extends FrameLayout implements OnItemClickListener, OnClickListener {
- private static final String LOG_TAG = LogTag.getLogTag();
- private final ListPopupWindow mListPopupWindow;
- private AccountSpinnerAdapter mSpinnerAdapter;
- private Account mAccount;
- private ActivityController mController;
- private final TextView mAccountName;
- private final TextView mFolderName;
- private final TextView mFolderCount;
- private final LinearLayout mContainer;
-
- // Created through view inflation.
- @SuppressWarnings("unused")
- public MailSpinner(Context context) {
- this(context, null);
- }
-
- public MailSpinner(Context context, AttributeSet attrs) {
- this(context, attrs, -1);
- }
-
- public MailSpinner(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mListPopupWindow = new ListPopupWindow(context);
- mListPopupWindow.setOnItemClickListener(this);
- mListPopupWindow.setAnchorView(this);
- final int dropDownWidth = context.getResources().getDimensionPixelSize(
- R.dimen.account_dropdown_dropdownwidth);
- mListPopupWindow.setWidth(dropDownWidth);
- mListPopupWindow.setModal(true);
- addView(LayoutInflater.from(context).inflate(R.layout.account_switch_spinner_item, null));
- mAccountName = (TextView) findViewById(R.id.account_second);
- mFolderName = (TextView) findViewById(R.id.account_first);
- mFolderCount = (TextView) findViewById(R.id.account_unread);
- mContainer = (LinearLayout) findViewById(R.id.account_spinner_container);
- mContainer.setOnClickListener(this);
- }
-
- public void setAdapter(AccountSpinnerAdapter adapter) {
- mSpinnerAdapter = adapter;
- mListPopupWindow.setAdapter(mSpinnerAdapter);
- }
-
- /**
- * Changes the enabled state of the spinner. Not called {@link #setEnabled(boolean)} because
- * that is an existing method on views.
- *
- * @param enabled true if the spinner allows touch events, and shows a little triangle on the
- * bottom right indicating that it is a spinner. False if it is just a view
- * showing the account name.
- */
- public final void changeEnabledState(boolean enabled) {
- setEnabled(enabled);
- if (enabled) {
- mContainer.setBackgroundResource(R.drawable.spinner_ab_holo_light);
- } else {
- mContainer.setBackgroundDrawable(null);
- }
- }
-
- public void setAccount(Account account) {
- mAccount = account;
- if (mAccount != null) {
- mAccountName.setText(mAccount.name);
- }
- }
-
- public void setFolder(Folder folder) {
- if (folder != null) {
- mFolderName.setText(folder.name);
- final int unreadCount = Utils.getFolderUnreadDisplayCount(folder);
- mFolderCount.setText(Utils.getUnreadCountString(getContext(), unreadCount));
- mFolderCount.setContentDescription(Utils.formatPlural(getContext(),
- R.plurals.unread_mail_count, unreadCount));
-
- if (mSpinnerAdapter != null) {
- // Update the spinner with this current folder, as it could change the recent items
- // that are shown.
- mSpinnerAdapter.setCurrentFolder(folder);
- }
- }
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- LogUtils.d(LOG_TAG, "onNavigationItemSelected(%d, %d) called", position, id);
- final int type = mSpinnerAdapter.getItemViewType(position);
- boolean dismiss = false;
- switch (type) {
- case AccountSpinnerAdapter.TYPE_ACCOUNT:
- // Get the capabilities associated with this account.
- final Account account = (Account) mSpinnerAdapter.getItem(position);
- LogUtils.d(LOG_TAG, "onNavigationItemSelected: Selecting account: %s",
- account.name);
- if (mAccount.uri.equals(account.uri)) {
- // The selected account is the same, let's load the default inbox.
- mController.loadAccountInbox();
- } else {
- // Switching accounts.
- mController.onAccountChanged(account);
- }
- dismiss = true;
- break;
- case AccountSpinnerAdapter.TYPE_FOLDER:
- final Object folder = mSpinnerAdapter.getItem(position);
- assert (folder instanceof Folder);
- LogUtils.d(LOG_TAG, "onNavigationItemSelected: Selecting folder: %s",
- ((Folder)folder).name);
- mController.onFolderChanged((Folder) folder);
- dismiss = true;
- break;
- case AccountSpinnerAdapter.TYPE_ALL_FOLDERS:
- mController.loadFolderList();
- dismiss = true;
- break;
- case AccountSpinnerAdapter.TYPE_HEADER:
- LogUtils.e(LOG_TAG, "MailSpinner.onItemClick(): Got unexpected click on header.");
- break;
- default:
- LogUtils.e(LOG_TAG, "MailSpinner.onItemClick(%d): Strange click ignored: type %d.",
- position, type);
- break;
- }
- if (dismiss) {
- mListPopupWindow.dismiss();
- }
- }
-
- public void setController(ActivityController controller) {
- mController = controller;
- }
-
- @Override
- public void onClick(View arg0) {
- if (isEnabled() && !mListPopupWindow.isShowing()) {
- mListPopupWindow.show();
- // Commit any leave behind items.
- mController.commitDestructiveActions(false);
- }
- }
-
- public void dismiss() {
- mListPopupWindow.dismiss();
- }
-
- public void onFolderUpdated(Folder folder) {
- mSpinnerAdapter.onFolderUpdated(folder);
- setFolder(folder);
- }
-}
diff --git a/src/com/android/mail/ui/MultiFoldersSelectionDialog.java b/src/com/android/mail/ui/MultiFoldersSelectionDialog.java
index 41b0778..cc95a48 100644
--- a/src/com/android/mail/ui/MultiFoldersSelectionDialog.java
+++ b/src/com/android/mail/ui/MultiFoldersSelectionDialog.java
@@ -30,7 +30,6 @@
import com.android.mail.ui.FolderSelectorAdapter.FolderRow;
import com.android.mail.utils.Utils;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -152,7 +151,8 @@
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
if (mUpdater != null) {
- mUpdater.assignFolder(mOperations.values(), mTarget, mBatch, true);
+ mUpdater.assignFolder(mOperations.values(), mTarget, mBatch,
+ true /* showUndo */, false /* isMoveTo */);
}
break;
case DialogInterface.BUTTON_NEGATIVE:
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index be7193c..fc33b8d 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -24,8 +24,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
-import android.support.v4.widget.DrawerLayout.LayoutParams;
-import android.util.Log;
+import android.view.View;
import android.view.ViewGroup;
import com.android.mail.ConversationListContext;
@@ -59,6 +58,8 @@
private static final String CONVERSATION_LIST_NEVER_SHOWN_KEY = "conversation-list-never-shown";
/** Key to store {@link #mInbox}. */
private final static String SAVED_INBOX_KEY = "m-inbox";
+ /** Set to true to show sections/recent inbox in drawer, false otherwise*/
+ private final static boolean SECTIONS_AND_RECENT_FOLDERS_ENABLED = true;
private static final int INVALID_ID = -1;
private boolean mConversationListVisible = false;
@@ -146,10 +147,10 @@
* into drawer (to avoid repetitive calls to replaceFragment).
*/
@Override
- public void onAccountChanged(Account account) {
- super.onAccountChanged(account);
+ public void changeAccount(Account account) {
+ super.changeAccount(account);
mConversationListNeverShown = true;
- loadFolderList();
+ resetAndLoadDrawer();
}
@Override
@@ -166,10 +167,34 @@
return mConversationListVisible;
}
+ /**
+ * If drawer is open/visible (even partially), close it and replace the
+ * folder fragment upon closing the drawer. Otherwise, the drawer is closed
+ * and we can replace the folder list fragment without concern.
+ */
+ private void resetAndLoadDrawer() {
+ if(mDrawerContainer.isDrawerVisible(mDrawerPullout)) {
+ mDrawerContainer.setDrawerListener(new DrawerLayout.SimpleDrawerListener() {
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ loadFolderList();
+ mDrawerContainer.setDrawerListener(null);
+ }
+ });
+ mDrawerContainer.closeDrawers();
+ } else {
+ loadFolderList();
+ }
+ }
+
@Override
public void onViewModeChanged(int newMode) {
super.onViewModeChanged(newMode);
- mDrawerContainer.closeDrawers();
+
+ // When view mode changes, we should wait for drawer to close and
+ // repopulate folders.
+ resetAndLoadDrawer();
+
// When entering conversation list mode, hide and clean up any currently visible
// conversation.
if (ViewMode.isListMode(newMode)) {
@@ -311,8 +336,10 @@
* Adding this will enable back stack to labels: mLastFolderListTransactionId =
*/
replaceFragment(
- FolderListFragment.newInstance(null, mAccount.folderListUri, false),
- FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_FOLDER_LIST, R.id.drawer_pullout);
+ FolderListFragment.newInstance(null, mAccount.folderListUri,
+ SECTIONS_AND_RECENT_FOLDERS_ENABLED, false),
+ FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_FOLDER_LIST,
+ R.id.drawer_pullout);
/*
* TODO(shahrk): Move or remove this
@@ -428,8 +455,9 @@
// showing this folder's children if we are not already
// looking at the child view for this folder.
mLastFolderListTransactionId = replaceFragment(FolderListFragment.newInstance(
- top, top.childFoldersListUri, false),
- FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_FOLDER_LIST, R.id.content_pane);
+ top, top.childFoldersListUri, SECTIONS_AND_RECENT_FOLDERS_ENABLED, false),
+ FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_FOLDER_LIST,
+ R.id.content_pane);
// Show the up affordance when digging into child folders.
mActionBarView.setBackButton();
} else {
@@ -468,7 +496,8 @@
// showing this folder's children if we are not already
// looking at the child view for this folder.
mLastFolderListTransactionId = replaceFragment(
- FolderListFragment.newInstance(folder, folder.childFoldersListUri, false),
+ FolderListFragment.newInstance(folder, folder.childFoldersListUri,
+ SECTIONS_AND_RECENT_FOLDERS_ENABLED, false),
FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_FOLDER_LIST, R.id.content_pane);
// Show the up affordance when digging into child folders.
mActionBarView.setBackButton();
@@ -579,7 +608,7 @@
convList != null ? convList.getAnimatedAdapter() : null),
0,
Utils.convertHtmlToPlainText
- (op.getDescription(mActivity.getActivityContext(), mFolder)),
+ (op.getDescription(mActivity.getActivityContext())),
true, /* showActionIcon */
R.string.undo,
true, /* replaceVisibleToast */
@@ -593,7 +622,7 @@
getUndoClickedListener(convList.getAnimatedAdapter()),
0,
Utils.convertHtmlToPlainText
- (op.getDescription(mActivity.getActivityContext(), mFolder)),
+ (op.getDescription(mActivity.getActivityContext())),
true, /* showActionIcon */
R.string.undo,
true, /* replaceVisibleToast */
diff --git a/src/com/android/mail/ui/RecentFolderList.java b/src/com/android/mail/ui/RecentFolderList.java
index 223ac60..d05530e 100644
--- a/src/com/android/mail/ui/RecentFolderList.java
+++ b/src/com/android/mail/ui/RecentFolderList.java
@@ -18,7 +18,6 @@
import android.content.ContentValues;
import android.content.Context;
-import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
@@ -97,8 +96,8 @@
/**
* Create a new asynchronous task to store the recent folder list. Both the account
* and the folder should be non-null.
- * @param account
- * @param folder
+ * @param account the current account for this folder.
+ * @param folder the folder which is to be stored.
*/
public StoreRecent(Account account, Folder folder) {
assert (account != null && folder != null);
@@ -124,7 +123,7 @@
/**
* Create a Recent Folder List from the given account. This will query the UIProvider to
* retrieve the RecentFolderList from persistent storage (if any).
- * @param context
+ * @param context the context for the activity
*/
public RecentFolderList(Context context) {
mFolderCache = new LruCache<String, RecentFolderListEntry>(
@@ -134,7 +133,7 @@
/**
* Initialize the {@link RecentFolderList} with a controllable activity.
- * @param activity
+ * @param activity the underlying activity
*/
public void initialize(ControllableActivity activity){
setCurrentAccount(mAccountObserver.initialize(activity.getAccountController()));
diff --git a/src/com/android/mail/ui/SecureConversationViewFragment.java b/src/com/android/mail/ui/SecureConversationViewFragment.java
index 13ab84c..eebec55 100644
--- a/src/com/android/mail/ui/SecureConversationViewFragment.java
+++ b/src/com/android/mail/ui/SecureConversationViewFragment.java
@@ -21,9 +21,6 @@
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
-import android.text.Html;
-import android.text.SpannedString;
-import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -35,17 +32,16 @@
import com.android.mail.R;
import com.android.mail.browse.ConversationViewAdapter;
+import com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem;
import com.android.mail.browse.ConversationViewHeader;
import com.android.mail.browse.MessageCursor;
+import com.android.mail.browse.MessageCursor.ConversationMessage;
import com.android.mail.browse.MessageFooterView;
import com.android.mail.browse.MessageHeaderView;
-import com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem;
-import com.android.mail.browse.MessageCursor.ConversationMessage;
import com.android.mail.browse.MessageHeaderView.MessageHeaderViewCallbacks;
import com.android.mail.providers.Account;
import com.android.mail.providers.Conversation;
import com.android.mail.providers.Message;
-import com.android.mail.providers.UIProvider;
import com.android.mail.utils.LogTag;
import com.android.mail.utils.LogUtils;
@@ -61,7 +57,7 @@
private ConversationMessage mMessage;
private ScrollView mScrollView;
- private WebViewClient mWebViewClient = new AbstractConversationWebViewClient() {
+ private final WebViewClient mWebViewClient = new AbstractConversationWebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
if (isUserVisible()) {
@@ -100,12 +96,15 @@
mConversationHeaderView.setCallbacks(this, this);
mConversationHeaderView.setFoldersVisible(false);
mConversationHeaderView.setSubject(mConversation.subject);
+ mMessageHeaderView.initialize(mDateBuilder, this, mAddressCache);
+ mMessageHeaderView.setExpandMode(MessageHeaderView.POPUP_MODE);
mMessageHeaderView.setContactInfoSource(getContactInfoSource());
mMessageHeaderView.setCallbacks(this);
mMessageHeaderView.setExpandable(false);
mMessageHeaderView.setVeiledMatcher(
((ControllableActivity) getActivity()).getAccountController()
.getVeiledAddressMatcher());
+ mMessageFooterView.initialize(getLoaderManager(), getFragmentManager());
getLoaderManager().initLoader(MESSAGE_LOADER, null, getMessageLoaderCallbacks());
showLoadingStatus();
}
@@ -161,16 +160,6 @@
}
@Override
- public void setMessageSpacerHeight(MessageHeaderItem item, int newSpacerHeight) {
- // Do nothing.
- }
-
- @Override
- public void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight) {
- // Do nothing.
- }
-
- @Override
public void onConversationViewHeaderHeightChange(int newHeight) {
// Do nothing.
}
@@ -181,12 +170,26 @@
return;
}
if (isUserVisible()) {
- mScrollView.scrollTo(0, 0);
onConversationSeen();
}
}
@Override
+ public void setMessageSpacerHeight(MessageHeaderItem item, int newSpacerHeight) {
+ // Do nothing.
+ }
+
+ @Override
+ public void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight) {
+ // Do nothing.
+ }
+
+ @Override
+ public void setMessageDetailsExpanded(MessageHeaderItem i, boolean expanded, int heightbefore) {
+ // Do nothing.
+ }
+
+ @Override
public void showExternalResources(final Message msg) {
mWebView.getSettings().setBlockNetworkImage(false);
}
@@ -197,6 +200,16 @@
}
@Override
+ public boolean supportsMessageTransforms() {
+ return false;
+ }
+
+ @Override
+ public String getMessageTransforms(final Message msg) {
+ return null;
+ }
+
+ @Override
protected void onMessageCursorLoadFinished(Loader<Cursor> loader, MessageCursor newCursor,
MessageCursor oldCursor) {
// ignore cursors that are still loading results
@@ -208,7 +221,7 @@
// Activity is finishing, just bail.
return;
}
- renderMessageBodies(newCursor, mEnableContentReadySignal);
+ renderMessageBodies(newCursor);
}
/**
@@ -216,35 +229,23 @@
* blocks, a conversation header), and return an HTML document with spacer
* divs inserted for all overlays.
*/
- private void renderMessageBodies(MessageCursor messageCursor,
- boolean enableContentReadySignal) {
- final StringBuilder convHtml = new StringBuilder();
- String content;
- if (messageCursor.moveToFirst()) {
- content = messageCursor.getString(UIProvider.MESSAGE_BODY_HTML_COLUMN);
- if (TextUtils.isEmpty(content)) {
- content = messageCursor.getString(UIProvider.MESSAGE_BODY_TEXT_COLUMN);
- if (content != null) {
- content = Html.toHtml(new SpannedString(content));
- }
- }
- convHtml.append(content);
- mMessage = messageCursor.getMessage();
- mWebView.getSettings().setBlockNetworkImage(!mMessage.alwaysShowImages);
- mWebView.loadDataWithBaseURL(mBaseUri, convHtml.toString(), "text/html", "utf-8", null);
- ConversationViewAdapter mAdapter = new ConversationViewAdapter(mActivity, null, null,
- null, null, null, null, null, null);
- MessageHeaderItem item = mAdapter.newMessageHeaderItem(mMessage, true,
- mMessage.alwaysShowImages);
- mMessageHeaderView.initialize(mDateBuilder, this, mAddressCache);
- mMessageHeaderView.setExpandMode(MessageHeaderView.POPUP_MODE);
- mMessageHeaderView.bind(item, false);
- mMessageHeaderView.setMessageDetailsVisibility(View.VISIBLE);
- if (mMessage.hasAttachments) {
- mMessageFooterView.setVisibility(View.VISIBLE);
- mMessageFooterView.initialize(getLoaderManager(), getFragmentManager());
- mMessageFooterView.bind(item, false);
- }
+ private void renderMessageBodies(MessageCursor messageCursor) {
+ if (!messageCursor.moveToFirst()) {
+ LogUtils.e(LOG_TAG, "unable to open message cursor");
+ return;
+ }
+ final ConversationMessage m = messageCursor.getMessage();
+ mMessage = messageCursor.getMessage();
+ mWebView.getSettings().setBlockNetworkImage(!mMessage.alwaysShowImages);
+ mWebView.loadDataWithBaseURL(mBaseUri, m.getBodyAsHtml(), "text/html", "utf-8", null);
+ final ConversationViewAdapter adapter = new ConversationViewAdapter(mActivity, null, null,
+ null, null, null, null, null, null);
+ final MessageHeaderItem item = adapter.newMessageHeaderItem(mMessage, true,
+ mMessage.alwaysShowImages);
+ mMessageHeaderView.bind(item, false);
+ if (mMessage.hasAttachments) {
+ mMessageFooterView.setVisibility(View.VISIBLE);
+ mMessageFooterView.bind(item, false);
}
}
@@ -257,8 +258,4 @@
}
}
- @Override
- public void setMessageDetailsExpanded(MessageHeaderItem i, boolean expanded, int heightbefore) {
- // Do nothing.
- }
}
diff --git a/src/com/android/mail/ui/SingleFolderSelectionDialog.java b/src/com/android/mail/ui/SingleFolderSelectionDialog.java
index 7676732..f7c5771 100644
--- a/src/com/android/mail/ui/SingleFolderSelectionDialog.java
+++ b/src/com/android/mail/ui/SingleFolderSelectionDialog.java
@@ -71,11 +71,12 @@
// Currently, the number of adapters are assumed to match the
// number of headers in the string array.
mAdapter.addSection(new SystemFolderSelectorAdapter(context, foldersCursor,
- R.layout.single_folders_view, null, mCurrentFolder));
+ R.layout.single_folders_view, headers[0], mCurrentFolder));
// TODO(mindyp): we currently do not support frequently moved to
// folders, at headers[1]; need to define what that means.*/
- mAdapter.addSection(new HierarchicalFolderSelectorAdapter(context,
+ // TODO(pwestbro): determine if we need to call filterFolders
+ mAdapter.addSection(new UserFolderHierarchicalFolderSelectorAdapter(context,
AddableFolderSelectorAdapter.filterFolders(foldersCursor),
R.layout.single_folders_view, headers[2], mCurrentFolder));
mBuilder.setAdapter(mAdapter, SingleFolderSelectionDialog.this);
@@ -95,7 +96,7 @@
// Remove the current folder and add the new folder.
ops.add(new FolderOperation(mCurrentFolder, false));
ops.add(new FolderOperation(folder, true));
- mUpdater.assignFolder(ops, mTarget, mBatch, true);
+ mUpdater.assignFolder(ops, mTarget, mBatch, true /* showUndo */, true /* isMoveTo */);
mDialog.dismiss();
}
}
diff --git a/src/com/android/mail/ui/SwipeableListView.java b/src/com/android/mail/ui/SwipeableListView.java
index 4048119..82d4d33 100644
--- a/src/com/android/mail/ui/SwipeableListView.java
+++ b/src/com/android/mail/ui/SwipeableListView.java
@@ -196,7 +196,8 @@
final Context context = getContext();
final ToastBarOperation undoOp;
- undoOp = new ToastBarOperation(1, mSwipeAction, ToastBarOperation.UNDO, false);
+ undoOp = new ToastBarOperation(1, mSwipeAction, ToastBarOperation.UNDO, false /* batch */,
+ mFolder);
Conversation conv = target.getConversation();
target.getConversation().position = findConversation(target, conv);
final AnimatedAdapter adapter = getAnimatedAdapter();
diff --git a/src/com/android/mail/ui/ToastBarOperation.java b/src/com/android/mail/ui/ToastBarOperation.java
index b56a94d..b47879f 100644
--- a/src/com/android/mail/ui/ToastBarOperation.java
+++ b/src/com/android/mail/ui/ToastBarOperation.java
@@ -33,19 +33,25 @@
private final int mCount;
private final boolean mBatch;
private final int mType;
+ private final Folder mFolder;
/**
* Create a ToastBarOperation
*
* @param count Number of conversations this action would be applied to.
- * @param menuId res id identifying the menu item tapped; used to determine
- * what action was performed
+ * @param menuId res id identifying the menu item tapped; used to determine what action was
+ * performed
+ * @param operationFolder The {@link Folder} upon which the operation was run. This may be
+ * <code>null</code>, but is required in {@link #getDescription(Context)} for certain
+ * actions.
*/
- public ToastBarOperation(int count, int menuId, int type, boolean batch) {
+ public ToastBarOperation(int count, int menuId, int type, boolean batch,
+ final Folder operationFolder) {
mCount = count;
mAction = menuId;
mBatch = batch;
mType = type;
+ mFolder = operationFolder;
}
public int getType() {
@@ -56,11 +62,12 @@
return mBatch;
}
- public ToastBarOperation(Parcel in) {
+ public ToastBarOperation(final Parcel in, final ClassLoader loader) {
mCount = in.readInt();
mAction = in.readInt();
mBatch = in.readInt() != 0;
mType = in.readInt();
+ mFolder = in.readParcelable(loader);
}
@Override
@@ -69,35 +76,44 @@
dest.writeInt(mAction);
dest.writeInt(mBatch ? 1 : 0);
dest.writeInt(mType);
+ dest.writeParcelable(mFolder, 0);
}
- public static final Creator<ToastBarOperation> CREATOR = new Creator<ToastBarOperation>() {
+ public static final ClassLoaderCreator<ToastBarOperation> CREATOR =
+ new ClassLoaderCreator<ToastBarOperation>() {
@Override
- public ToastBarOperation createFromParcel(Parcel source) {
- return new ToastBarOperation(source);
+ public ToastBarOperation createFromParcel(final Parcel source) {
+ return createFromParcel(source, null);
}
@Override
- public ToastBarOperation[] newArray(int size) {
+ public ToastBarOperation[] newArray(final int size) {
return new ToastBarOperation[size];
}
+
+ @Override
+ public ToastBarOperation createFromParcel(final Parcel source, final ClassLoader loader) {
+ return new ToastBarOperation(source, loader);
+ }
};
/**
* Get a string description of the operation that will be performed
* when the user taps the undo bar.
*/
- public String getDescription(Context context, Folder folder) {
+ public String getDescription(Context context) {
int resId = -1;
switch (mAction) {
case R.id.delete:
resId = R.plurals.conversation_deleted;
break;
case R.id.remove_folder:
- return context.getString(R.string.folder_removed, folder.name);
+ return context.getString(R.string.folder_removed, mFolder.name);
case R.id.change_folder:
resId = R.plurals.conversation_folder_changed;
break;
+ case R.id.move_folder:
+ return context.getString(R.string.conversation_folder_moved, mFolder.name);
case R.id.archive:
resId = R.plurals.conversation_archived;
break;
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 418ee75..d022352 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -105,7 +105,8 @@
private void createFolderListFragment(Folder parent, Uri uri) {
setHierarchyFolder(parent);
// Create a sectioned FolderListFragment.
- FolderListFragment folderListFragment = FolderListFragment.newInstance(parent, uri, true);
+ FolderListFragment folderListFragment = FolderListFragment.newInstance(parent, uri, true,
+ true);
FragmentTransaction fragmentTransaction = mActivity.getFragmentManager().beginTransaction();
if (Utils.useFolderListFragmentTransition(mActivity.getActivityContext())) {
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
@@ -163,8 +164,8 @@
}
@Override
- public void onAccountChanged(Account account) {
- super.onAccountChanged(account);
+ public void changeAccount(Account account) {
+ super.changeAccount(account);
renderFolderList();
}
@@ -473,7 +474,7 @@
getUndoClickedListener(convList.getAnimatedAdapter()),
0,
Utils.convertHtmlToPlainText
- (op.getDescription(mActivity.getActivityContext(), mFolder)),
+ (op.getDescription(mActivity.getActivityContext())),
true, /* showActionIcon */
R.string.undo,
true, /* replaceVisibleToast */
@@ -485,7 +486,7 @@
if (convList != null) {
mToastBar.show(getUndoClickedListener(convList.getAnimatedAdapter()), 0,
Utils.convertHtmlToPlainText
- (op.getDescription(mActivity.getActivityContext(), mFolder)),
+ (op.getDescription(mActivity.getActivityContext())),
true, /* showActionIcon */
R.string.undo, true, /* replaceVisibleToast */
op);
diff --git a/src/com/android/mail/ui/UserFolderHierarchicalFolderSelectorAdapter.java b/src/com/android/mail/ui/UserFolderHierarchicalFolderSelectorAdapter.java
new file mode 100644
index 0000000..9a601cf
--- /dev/null
+++ b/src/com/android/mail/ui/UserFolderHierarchicalFolderSelectorAdapter.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (C) 2013 Google Inc.
+ * Licensed to 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.android.mail.ui;
+
+import android.content.Context;
+import android.database.Cursor;
+import com.android.mail.providers.Folder;
+
+import java.util.Set;
+
+public class UserFolderHierarchicalFolderSelectorAdapter extends HierarchicalFolderSelectorAdapter {
+ public UserFolderHierarchicalFolderSelectorAdapter(Context context, Cursor folders, int layout,
+ String header, Folder excludedFolder) {
+ super(context, folders, layout, header, excludedFolder);
+ }
+
+ /**
+ * Return whether the supplied folder meets the requirements to be displayed
+ * in the folder list.
+ */
+ @Override
+ protected boolean meetsRequirements(Folder folder) {
+ if (folder.isProviderFolder()) {
+ return false;
+ }
+ return super.meetsRequirements(folder);
+ }
+}
diff --git a/src/com/android/mail/utils/NotificationUtils.java b/src/com/android/mail/utils/NotificationUtils.java
index 2f72e44..dbc0113 100644
--- a/src/com/android/mail/utils/NotificationUtils.java
+++ b/src/com/android/mail/utils/NotificationUtils.java
@@ -708,11 +708,14 @@
UIProvider.MESSAGE_PROJECTION, null, null, null);
messageCursor = new MessageCursor(cursor);
- String from = null;
+ String from = "";
String fromAddress = "";
if (messageCursor.moveToPosition(messageCursor.getCount() - 1)) {
final Message message = messageCursor.getMessage();
fromAddress = message.getFrom();
+ if (fromAddress == null) {
+ fromAddress = "";
+ }
from = getDisplayableSender(fromAddress);
}
while (messageCursor.moveToPosition(messageCursor.getPosition() - 1)) {
diff --git a/src/com/android/mail/utils/Observable.java b/src/com/android/mail/utils/Observable.java
new file mode 100644
index 0000000..81e8d83
--- /dev/null
+++ b/src/com/android/mail/utils/Observable.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 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.android.mail.utils;
+
+import android.database.DataSetObservable;
+import android.database.DataSetObserver;
+
+/**
+ * A Utility class to register observers and return logging and counts for the number of registered
+ * observers.
+ */
+public class Observable extends DataSetObservable {
+ protected static final String LOG_TAG = LogTag.getLogTag();
+ private final String mName;
+
+ public Observable(String name) {
+ mName = name;
+ }
+
+ @Override
+ public void registerObserver(DataSetObserver observer) {
+ final int count = mObservers.size();
+ super.registerObserver(observer);
+ LogUtils.d(LOG_TAG, "IN register(%s)Observer: %s before=%d after=%d",
+ mName, observer, count, mObservers.size());
+ }
+
+ @Override
+ public void unregisterObserver(DataSetObserver observer) {
+ final int count = mObservers.size();
+ super.unregisterObserver(observer);
+ LogUtils.d(LOG_TAG, "IN unregister(%s)Observer: %s before=%d after=%d",
+ mName, observer, count, mObservers.size());
+ }
+}
diff --git a/unified_src/com/android/mail/providers/protos/boot/AccountReceiver.java b/unified_src/com/android/mail/providers/protos/boot/AccountReceiver.java
deleted file mode 100644
index 9e2412f..0000000
--- a/unified_src/com/android/mail/providers/protos/boot/AccountReceiver.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Copyright (c) 2011, Google Inc.
- *
- * 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.android.mail.providers.protos.boot;
-
-import com.android.mail.providers.protos.mock.MockUiProvider;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class AccountReceiver extends BroadcastReceiver {
- /**
- * Intent used to notify interested parties that the Mail provider has been created.
- */
- public static final String ACTION_PROVIDER_CREATED
- = "com.android.mail.providers.protos.boot.intent.ACTION_PROVIDER_CREATED";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- MockUiProvider.initializeMockProvider();
- }
-}