Merge "More use of EmailAsyncTask"
diff --git a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java
index 19f86db..1bc7715 100644
--- a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java
+++ b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java
@@ -16,7 +16,7 @@
package com.android.emailcommon.provider;
-import com.android.emailcommon.mail.Snippet;
+import com.android.emailcommon.utility.TextUtilities;
import com.android.emailcommon.utility.Utility;
import android.content.ContentProviderOperation;
@@ -839,9 +839,9 @@
ContentProviderOperation.Builder b = ContentProviderOperation.newInsert(mBaseUri);
// Generate the snippet here, before we create the CPO for Message
if (mText != null) {
- mSnippet = Snippet.fromPlainText(mText);
+ mSnippet = TextUtilities.makeSnippetFromPlainText(mText);
} else if (mHtml != null) {
- mSnippet = Snippet.fromHtmlText(mHtml);
+ mSnippet = TextUtilities.makeSnippetFromHtmlText(mHtml);
}
ops.add(b.withValues(toContentValues()).build());
diff --git a/emailcommon/src/com/android/emailcommon/utility/ConversionUtilities.java b/emailcommon/src/com/android/emailcommon/utility/ConversionUtilities.java
index dca31d6..41ba12d 100644
--- a/emailcommon/src/com/android/emailcommon/utility/ConversionUtilities.java
+++ b/emailcommon/src/com/android/emailcommon/utility/ConversionUtilities.java
@@ -20,7 +20,6 @@
import com.android.emailcommon.internet.MimeUtility;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.mail.Part;
-import com.android.emailcommon.mail.Snippet;
import com.android.emailcommon.provider.EmailContent;
import android.text.TextUtils;
@@ -116,13 +115,13 @@
if (!TextUtils.isEmpty(sbText)) {
String text = sbText.toString();
body.mTextContent = text;
- localMessage.mSnippet = Snippet.fromPlainText(text);
+ localMessage.mSnippet = TextUtilities.makeSnippetFromPlainText(text);
}
if (!TextUtils.isEmpty(sbHtml)) {
String text = sbHtml.toString();
body.mHtmlContent = text;
if (localMessage.mSnippet == null) {
- localMessage.mSnippet = Snippet.fromHtmlText(text);
+ localMessage.mSnippet = TextUtilities.makeSnippetFromHtmlText(text);
}
}
if (sbHtmlReply != null && sbHtmlReply.length() != 0) {
diff --git a/emailcommon/src/com/android/emailcommon/mail/Snippet.java b/emailcommon/src/com/android/emailcommon/utility/TextUtilities.java
similarity index 62%
rename from emailcommon/src/com/android/emailcommon/mail/Snippet.java
rename to emailcommon/src/com/android/emailcommon/utility/TextUtilities.java
index 38f982e..1e0abd9 100644
--- a/emailcommon/src/com/android/emailcommon/mail/Snippet.java
+++ b/emailcommon/src/com/android/emailcommon/utility/TextUtilities.java
@@ -14,38 +14,39 @@
* limitations under the License.
*/
-package com.android.emailcommon.mail;
+package com.android.emailcommon.utility;
+import android.graphics.Color;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
import android.text.TextUtils;
+import android.text.style.BackgroundColorSpan;
+import java.io.IOException;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
+import java.util.StringTokenizer;
-/**
- * Class to generate a short 'snippet' from either plain text or html text
- *
- * If the sync protocol can get plain text, that's great, but we'll still strip out extraneous
- * whitespace. If it's HTML, we'll 1) strip out tags, 2) turn entities into the appropriate
- * characters, and 3) strip out extraneous whitespace, all in one pass
- *
- * Why not use an existing class? The best answer is performance; yet another answer is
- * correctness (e.g. Html.textFromHtml simply doesn't generate well-stripped text). But performance
- * is key; we frequently sync text that is 10K or (much) longer, yet we really only care about a
- * small amount of text for the snippet. So it's critically important that we just stop when we've
- * gotten enough; existing methods that exist will go through the entire incoming string, at great
- * (and useless) expense.
- */
-public class Snippet {
+public class TextUtilities {
+ // Highlight color is yellow, as in other apps.
+ // TODO Push for this to be a global (style-related?) constant
+ private static final int HIGHLIGHT_COLOR_INT = Color.YELLOW;
+ /*package*/ static final String HIGHLIGHT_COLOR_STRING =
+ '#' + Integer.toHexString(HIGHLIGHT_COLOR_INT);
+
// This is how many chars we'll allow in a snippet
- private static final int MAX_PLAIN_TEXT_SCAN_LENGTH = 200;
+ private static final int MAX_SNIPPET_LENGTH = 200;
// For some reason, isWhitespace() returns false with the following...
/*package*/ static final char NON_BREAKING_SPACE_CHARACTER = (char)160;
// Tags whose content must be stripped as well
static final String[] STRIP_TAGS =
new String[] {"title", "script", "style", "applet", "head"};
- // The number of characters we peel off for testing against STRIP_TAGS
- static final int STRIP_TAG_LENGTH = 6;
+ // The number of characters we peel off for testing against STRIP_TAGS; this should be the
+ // maximum size of the strings in STRIP_TAGS
+ static final int MAX_STRIP_TAG_LENGTH = 6;
static final Map<String, Character> ESCAPE_STRINGS;
static {
@@ -307,12 +308,27 @@
ESCAPE_STRINGS.put("&euro", '\u20AC');
}
- public static String fromHtmlText(String text) {
- return fromText(text, true);
+ /**
+ * Code to generate a short 'snippet' from either plain text or html text
+ *
+ * If the sync protocol can get plain text, that's great, but we'll still strip out extraneous
+ * whitespace. If it's HTML, we'll 1) strip out tags, 2) turn entities into the appropriate
+ * characters, and 3) strip out extraneous whitespace, all in one pass
+ *
+ * Why not use an existing class? The best answer is performance; yet another answer is
+ * correctness (e.g. Html.textFromHtml simply doesn't generate well-stripped text). But
+ * performance is key; we frequently sync text that is 10K or (much) longer, yet we really only
+ * care about a small amount of text for the snippet. So it's critically important that we just
+ * stop when we've gotten enough; existing methods that exist will go through the entire
+ * incoming string, at great (and useless, in this case) expense.
+ */
+
+ public static String makeSnippetFromHtmlText(String text) {
+ return makeSnippetFromText(text, true);
}
- public static String fromPlainText(String text) {
- return fromText(text, false);
+ public static String makeSnippetFromPlainText(String text) {
+ return makeSnippetFromText(text, false);
}
/**
@@ -342,13 +358,13 @@
return htmlText.indexOf("/" + tag, startPos);
}
- public static String fromText(String text, boolean stripHtml) {
+ public static String makeSnippetFromText(String text, boolean stripHtml) {
// Handle null and empty string
if (TextUtils.isEmpty(text)) return "";
final int length = text.length();
// Use char[] instead of StringBuilder purely for performance; fewer method calls, etc.
- char[] buffer = new char[MAX_PLAIN_TEXT_SCAN_LENGTH];
+ char[] buffer = new char[MAX_SNIPPET_LENGTH];
// skipCount is an array of a single int; that int is set inside stripHtmlEntity and is
// used to determine how many characters can be "skipped" due to the transformation of the
// entity to a single character. When Java allows multiple return values, we can make this
@@ -361,7 +377,7 @@
boolean inTag = false;
// Walk through the text until we're done with the input OR we've got a large enough snippet
- for (int i = 0; i < length && bufferCount < MAX_PLAIN_TEXT_SCAN_LENGTH; i++) {
+ for (int i = 0; i < length && bufferCount < MAX_SNIPPET_LENGTH; i++) {
char c = text.charAt(i);
if (stripHtml && !inTag && (c == '<')) {
// Find tags to strip; they will begin with <! or !- or </ or <letter
@@ -370,8 +386,8 @@
if (peek == '!' || peek == '-' || peek == '/' || Character.isLetter(peek)) {
inTag = true;
// Strip content of title, script, style and applet tags
- if (i < (length - (STRIP_TAG_LENGTH + 2))) {
- String tag = text.substring(i + 1, i + STRIP_TAG_LENGTH + 1);
+ if (i < (length - (MAX_STRIP_TAG_LENGTH + 2))) {
+ String tag = text.substring(i + 1, i + MAX_STRIP_TAG_LENGTH + 1);
String tagLowerCase = tag.toLowerCase();
boolean stripContent = false;
for (String stripTag: STRIP_TAGS) {
@@ -484,4 +500,214 @@
return '&';
}
+ /**
+ * Given a string of HTML text and a query containing any number of search terms, returns
+ * an HTML string in which those search terms are highlighted (intended for use in a WebView)
+ *
+ * @param text the HTML text to process
+ * @param query the search terms
+ * @return HTML text with the search terms highlighted
+ */
+ public static String highlightTermsInHtml(String text, String query) {
+ try {
+ return highlightTerms(text, query, true).toString();
+ } catch (IOException e) {
+ // Can't happen, but we must catch this
+ return text;
+ }
+ }
+
+ /**
+ * Given a string of plain text and a query containing any number of search terms, returns
+ * a CharSequence in which those search terms are highlighted (intended for use in a TextView)
+ *
+ * @param text the text to process
+ * @param query the search terms
+ * @return a CharSequence with the search terms highlighted
+ */
+ public static CharSequence highlightTermsInText(String text, String query) {
+ try {
+ return highlightTerms(text, query, false);
+ } catch (IOException e) {
+ // Can't happen, but we must catch this
+ return text;
+ }
+ }
+
+ static class SearchTerm {
+ final String mTerm;
+ final String mTermLowerCase;
+ final int mLength;
+ int mMatchLength = 0;
+ int mMatchStart = -1;
+
+ SearchTerm(String term, boolean html) {
+ mTerm = term;
+ mTermLowerCase = term.toLowerCase();
+ mLength = term.length();
+ }
+ }
+
+ /**
+ * Generate a version of the incoming text in which all search terms in a query are highlighted.
+ * If the input is HTML, we return a StringBuilder with additional markup as required
+ * If the input is text, we return a SpannableStringBuilder with additional spans as required
+ *
+ * @param text the text to be processed
+ * @param query the query, which can contain multiple terms separated by whitespace
+ * @param html whether or not the text to be processed is HTML
+ * @return highlighted text
+ *
+ * @throws IOException as Appendable requires this
+ */
+ public static CharSequence highlightTerms(String text, String query, boolean html)
+ throws IOException {
+ // Handle null and empty string
+ if (TextUtils.isEmpty(text)) return "";
+ final int length = text.length();
+
+ // Break up the query into search terms
+ ArrayList<SearchTerm> terms = new ArrayList<SearchTerm>();
+ if (query != null) {
+ StringTokenizer st = new StringTokenizer(query);
+ while (st.hasMoreTokens()) {
+ terms.add(new SearchTerm(st.nextToken(), html));
+ }
+ }
+
+ // Our appendable depends on whether we're building HTML text (for webview) or spannable
+ // text (for UI)
+ final Appendable sb = html ? new StringBuilder() : new SpannableStringBuilder();
+ // Indicates whether we're in the middle of an HTML tag
+ boolean inTag = false;
+ // The position of the last input character copied to output
+ int lastOut = -1;
+
+ // Walk through the text until we're done with the input
+ // Just copy any HTML tags directly into the output; search for terms in the remaining text
+ for (int i = 0; i < length; i++) {
+ char chr = text.charAt(i);
+ if (html) {
+ if (!inTag && (chr == '<')) {
+ // Find tags; they will begin with <! or !- or </ or <letter
+ if (i < (length - 1)) {
+ char peek = text.charAt(i + 1);
+ if (peek == '!' || peek == '-' || peek == '/' || Character.isLetter(peek)) {
+ inTag = true;
+ // Skip content of title, script, style and applet tags
+ if (i < (length - (MAX_STRIP_TAG_LENGTH + 2))) {
+ String tag = text.substring(i + 1, i + MAX_STRIP_TAG_LENGTH + 1);
+ String tagLowerCase = tag.toLowerCase();
+ boolean stripContent = false;
+ for (String stripTag: STRIP_TAGS) {
+ if (tagLowerCase.startsWith(stripTag)) {
+ stripContent = true;
+ tag = tag.substring(0, stripTag.length());
+ break;
+ }
+ }
+ if (stripContent) {
+ // Look for the end of this tag
+ int endTagPosition = findTagEnd(text, tag, i);
+ if (endTagPosition < 0) {
+ sb.append(text.substring(i));
+ break;
+ } else {
+ sb.append(text.substring(i, endTagPosition - 1));
+ i = endTagPosition - 1;
+ chr = text.charAt(i);
+ }
+ }
+ }
+ }
+ }
+ } else if (inTag && (chr == '>')) {
+ inTag = false;
+ }
+
+ if (inTag) {
+ sb.append(chr);
+ continue;
+ }
+ }
+
+ // After all that, we've got some "body" text
+ char chrLowerCase = Character.toLowerCase(chr);
+ // Whether or not the current character should be appended to the output; we inhibit
+ // this while any search terms match
+ boolean appendNow = true;
+ // Look through search terms for matches
+ for (SearchTerm t: terms) {
+ if (chrLowerCase == t.mTermLowerCase.charAt(t.mMatchLength)) {
+ if (t.mMatchLength++ == 0) {
+ // New match start
+ t.mMatchStart = i;
+ }
+ if (t.mMatchLength == t.mLength) {
+ String matchText = text.substring(t.mMatchStart, t.mMatchStart + t.mLength);
+ // Completed match; add highlight and reset term
+ if (t.mMatchStart <= lastOut) {
+ matchText = text.substring(lastOut + 1, i + 1);
+ }
+ /*else*/
+ if (matchText.length() == 0) {} else
+ if (html) {
+ sb.append("<span style=\"background-color: " + HIGHLIGHT_COLOR_STRING +
+ "\">");
+ sb.append(matchText);
+ sb.append("</span>");
+ } else {
+ SpannableString highlightSpan = new SpannableString(matchText);
+ highlightSpan.setSpan(new BackgroundColorSpan(HIGHLIGHT_COLOR_INT), 0,
+ highlightSpan.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ sb.append(highlightSpan);
+ }
+ lastOut = t.mMatchStart + t.mLength - 1;
+ t.mMatchLength = 0;
+ t.mMatchStart = -1;
+ }
+ appendNow = false;
+ } else {
+ if (t.mMatchStart >= 0) {
+ // We're no longer matching; check for other matches in progress
+ int leastOtherStart = -1;
+ for (SearchTerm ot: terms) {
+ // Save away the lowest match start for other search terms
+ if ((ot != t) && (ot.mMatchStart >= 0) && ((leastOtherStart < 0) ||
+ (ot.mMatchStart <= leastOtherStart))) {
+ leastOtherStart = ot.mMatchStart;
+ }
+ }
+ int matchEnd = t.mMatchStart + t.mMatchLength;
+ if (leastOtherStart < 0 || leastOtherStart > matchEnd) {
+ // Append the whole thing
+ if (t.mMatchStart > lastOut) {
+ sb.append(text.substring(t.mMatchStart, matchEnd));
+ lastOut = matchEnd;
+ }
+ } else if (leastOtherStart == t.mMatchStart) {
+ // Ok to append the current char
+ } else if (leastOtherStart < t.mMatchStart) {
+ // We're already covered by another search term, so don't append
+ appendNow = false;
+ } else if (t.mMatchStart > lastOut) {
+ // Append the piece of our term that's not already covered
+ sb.append(text.substring(t.mMatchStart, leastOtherStart));
+ lastOut = leastOtherStart;
+ }
+ }
+ // Reset this term
+ t.mMatchLength = 0;
+ t.mMatchStart = -1;
+ }
+ }
+
+ if (appendNow) {
+ sb.append(chr);
+ lastOut = i;
+ }
+ }
+
+ return (CharSequence)sb;
+ }
}
diff --git a/res/drawable-hdpi/ab_fade.png b/res/drawable-hdpi/ab_fade.png
deleted file mode 100644
index 51fdf44..0000000
--- a/res/drawable-hdpi/ab_fade.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/bg_email_widget_holo.9.png b/res/drawable-hdpi/bg_email_widget_holo.9.png
deleted file mode 100644
index e78f1b0..0000000
--- a/res/drawable-hdpi/bg_email_widget_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/forward.png b/res/drawable-hdpi/forward.png
new file mode 100644
index 0000000..869ae55
--- /dev/null
+++ b/res/drawable-hdpi/forward.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_add_attachment_holo_light.png b/res/drawable-hdpi/ic_add_attachment_holo_light.png
deleted file mode 100644
index d57da50..0000000
--- a/res/drawable-hdpi/ic_add_attachment_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_cc_holo_light.png b/res/drawable-hdpi/ic_cc_holo_light.png
deleted file mode 100644
index 0d2a99b..0000000
--- a/res/drawable-hdpi/ic_cc_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_drafts_holo_light.png b/res/drawable-hdpi/ic_drafts_holo_light.png
deleted file mode 100644
index c568b3c..0000000
--- a/res/drawable-hdpi/ic_drafts_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_accounts_holo_light.png b/res/drawable-hdpi/ic_menu_accounts_holo_light.png
deleted file mode 100644
index 14dfd60..0000000
--- a/res/drawable-hdpi/ic_menu_accounts_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_add_star_holo_light.png b/res/drawable-hdpi/ic_menu_add_star_holo_light.png
deleted file mode 100644
index 9cdfef8..0000000
--- a/res/drawable-hdpi/ic_menu_add_star_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_edit_holo_light.png b/res/drawable-hdpi/ic_menu_edit_holo_light.png
deleted file mode 100644
index 6ffbd6f..0000000
--- a/res/drawable-hdpi/ic_menu_edit_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_help_holo_light.png b/res/drawable-hdpi/ic_menu_help_holo_light.png
deleted file mode 100644
index 7e9412e..0000000
--- a/res/drawable-hdpi/ic_menu_help_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_mark.png b/res/drawable-hdpi/ic_menu_mark.png
deleted file mode 100644
index 724d787..0000000
--- a/res/drawable-hdpi/ic_menu_mark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_save_draft_holo_light.png b/res/drawable-hdpi/ic_menu_save_draft_holo_light.png
deleted file mode 100644
index 67fb21e..0000000
--- a/res/drawable-hdpi/ic_menu_save_draft_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_settings_holo_light.png b/res/drawable-hdpi/ic_menu_settings_holo_light.png
deleted file mode 100644
index b43e6bb..0000000
--- a/res/drawable-hdpi/ic_menu_settings_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_newer_arrow_holo_light.png b/res/drawable-hdpi/ic_newer_arrow_holo_light.png
deleted file mode 100644
index 682b970..0000000
--- a/res/drawable-hdpi/ic_newer_arrow_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_older_arrow_holo_light.png b/res/drawable-hdpi/ic_older_arrow_holo_light.png
deleted file mode 100644
index 85518a4..0000000
--- a/res/drawable-hdpi/ic_older_arrow_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_star_none_holo_light.png b/res/drawable-hdpi/ic_star_none_holo_light.png
deleted file mode 100644
index 9a30962..0000000
--- a/res/drawable-hdpi/ic_star_none_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/list_message_view_topstroke.9.png b/res/drawable-hdpi/list_message_view_topstroke.9.png
deleted file mode 100644
index 5418286..0000000
--- a/res/drawable-hdpi/list_message_view_topstroke.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/list_message_wide_divider.9.png b/res/drawable-hdpi/list_message_wide_divider.9.png
deleted file mode 100644
index a3ebee6..0000000
--- a/res/drawable-hdpi/list_message_wide_divider.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/list_message_wide_read_pressed_holo.9.png b/res/drawable-hdpi/list_message_wide_read_pressed_holo.9.png
deleted file mode 100644
index 828af6c..0000000
--- a/res/drawable-hdpi/list_message_wide_read_pressed_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/message_header_collapsed.png b/res/drawable-hdpi/message_header_collapsed.png
deleted file mode 100644
index b6dceb6..0000000
--- a/res/drawable-hdpi/message_header_collapsed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/panel_message_view.9.png b/res/drawable-hdpi/panel_message_view.9.png
deleted file mode 100644
index ebdf5b0..0000000
--- a/res/drawable-hdpi/panel_message_view.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/panel_message_view_leftstroke.9.png b/res/drawable-hdpi/panel_message_view_leftstroke.9.png
deleted file mode 100644
index 1d5637f..0000000
--- a/res/drawable-hdpi/panel_message_view_leftstroke.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/reply.png b/res/drawable-hdpi/reply.png
new file mode 100644
index 0000000..7381610
--- /dev/null
+++ b/res/drawable-hdpi/reply.png
Binary files differ
diff --git a/res/drawable-hdpi/reply_all.png b/res/drawable-hdpi/reply_all.png
new file mode 100644
index 0000000..3d81a3c
--- /dev/null
+++ b/res/drawable-hdpi/reply_all.png
Binary files differ
diff --git a/res/drawable-hdpi/scroll_fade_btm_email_widget_holo.png b/res/drawable-hdpi/scroll_fade_btm_email_widget_holo.png
deleted file mode 100644
index ae2c4b4..0000000
--- a/res/drawable-hdpi/scroll_fade_btm_email_widget_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/stat_notify_calendar.png b/res/drawable-hdpi/stat_notify_calendar.png
deleted file mode 100644
index c0b5567..0000000
--- a/res/drawable-hdpi/stat_notify_calendar.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/title_bar_medium.9.png b/res/drawable-hdpi/title_bar_medium.9.png
deleted file mode 100644
index 311a54a..0000000
--- a/res/drawable-hdpi/title_bar_medium.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ab_fade.png b/res/drawable-mdpi/ab_fade.png
deleted file mode 100644
index 6b2c105..0000000
--- a/res/drawable-mdpi/ab_fade.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/bg_email_widget_holo.9.png b/res/drawable-mdpi/bg_email_widget_holo.9.png
deleted file mode 100644
index 15aa4b0..0000000
--- a/res/drawable-mdpi/bg_email_widget_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/forward.png b/res/drawable-mdpi/forward.png
similarity index 100%
rename from res/drawable/forward.png
rename to res/drawable-mdpi/forward.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_add_attachment_holo_light.png b/res/drawable-mdpi/ic_add_attachment_holo_light.png
deleted file mode 100644
index 9d257ff..0000000
--- a/res/drawable-mdpi/ic_add_attachment_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_cc_holo_light.png b/res/drawable-mdpi/ic_cc_holo_light.png
deleted file mode 100644
index 7392f1b..0000000
--- a/res/drawable-mdpi/ic_cc_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_drafts_holo_light.png b/res/drawable-mdpi/ic_drafts_holo_light.png
deleted file mode 100644
index 6de8514..0000000
--- a/res/drawable-mdpi/ic_drafts_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_accounts_holo_light.png b/res/drawable-mdpi/ic_menu_accounts_holo_light.png
deleted file mode 100644
index 365b85d..0000000
--- a/res/drawable-mdpi/ic_menu_accounts_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_add_star_holo_light.png b/res/drawable-mdpi/ic_menu_add_star_holo_light.png
deleted file mode 100644
index f9db677..0000000
--- a/res/drawable-mdpi/ic_menu_add_star_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_edit_holo_light.png b/res/drawable-mdpi/ic_menu_edit_holo_light.png
deleted file mode 100644
index 74f7856..0000000
--- a/res/drawable-mdpi/ic_menu_edit_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_help_holo_light.png b/res/drawable-mdpi/ic_menu_help_holo_light.png
deleted file mode 100644
index 1cdbe28..0000000
--- a/res/drawable-mdpi/ic_menu_help_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_mark.png b/res/drawable-mdpi/ic_menu_mark.png
deleted file mode 100644
index 5e95da7..0000000
--- a/res/drawable-mdpi/ic_menu_mark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_save_draft_holo_light.png b/res/drawable-mdpi/ic_menu_save_draft_holo_light.png
deleted file mode 100644
index 3c4d648..0000000
--- a/res/drawable-mdpi/ic_menu_save_draft_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_settings_holo_light.png b/res/drawable-mdpi/ic_menu_settings_holo_light.png
deleted file mode 100644
index 5b1d70d..0000000
--- a/res/drawable-mdpi/ic_menu_settings_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_newer_arrow_holo_light.png b/res/drawable-mdpi/ic_newer_arrow_holo_light.png
deleted file mode 100644
index 2304847..0000000
--- a/res/drawable-mdpi/ic_newer_arrow_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_older_arrow_holo_light.png b/res/drawable-mdpi/ic_older_arrow_holo_light.png
deleted file mode 100644
index faa0922..0000000
--- a/res/drawable-mdpi/ic_older_arrow_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_star_none_holo_light.png b/res/drawable-mdpi/ic_star_none_holo_light.png
deleted file mode 100644
index 1657b28..0000000
--- a/res/drawable-mdpi/ic_star_none_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/list_message_view_topstroke.9.png b/res/drawable-mdpi/list_message_view_topstroke.9.png
deleted file mode 100644
index 7594eae..0000000
--- a/res/drawable-mdpi/list_message_view_topstroke.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/list_message_wide_divider.9.png b/res/drawable-mdpi/list_message_wide_divider.9.png
deleted file mode 100644
index 5e368b1..0000000
--- a/res/drawable-mdpi/list_message_wide_divider.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/list_message_wide_read_pressed_holo.9.png b/res/drawable-mdpi/list_message_wide_read_pressed_holo.9.png
deleted file mode 100644
index 786eb09..0000000
--- a/res/drawable-mdpi/list_message_wide_read_pressed_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/message_header_collapsed.png b/res/drawable-mdpi/message_header_collapsed.png
deleted file mode 100644
index a3f651a..0000000
--- a/res/drawable-mdpi/message_header_collapsed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/panel_message_view.9.png b/res/drawable-mdpi/panel_message_view.9.png
deleted file mode 100644
index d8e5817..0000000
--- a/res/drawable-mdpi/panel_message_view.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/panel_message_view_leftstroke.9.png b/res/drawable-mdpi/panel_message_view_leftstroke.9.png
deleted file mode 100644
index ae0b3b0..0000000
--- a/res/drawable-mdpi/panel_message_view_leftstroke.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/reply.png b/res/drawable-mdpi/reply.png
similarity index 100%
rename from res/drawable/reply.png
rename to res/drawable-mdpi/reply.png
Binary files differ
diff --git a/res/drawable/reply_all.png b/res/drawable-mdpi/reply_all.png
similarity index 100%
rename from res/drawable/reply_all.png
rename to res/drawable-mdpi/reply_all.png
Binary files differ
diff --git a/res/drawable-mdpi/scroll_fade_btm_email_widget_holo.png b/res/drawable-mdpi/scroll_fade_btm_email_widget_holo.png
deleted file mode 100644
index fe1e839..0000000
--- a/res/drawable-mdpi/scroll_fade_btm_email_widget_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/stat_notify_calendar.png b/res/drawable-mdpi/stat_notify_calendar.png
deleted file mode 100644
index e43db35..0000000
--- a/res/drawable-mdpi/stat_notify_calendar.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/title_bar_medium.9.png b/res/drawable-mdpi/title_bar_medium.9.png
deleted file mode 100644
index 2d41d02..0000000
--- a/res/drawable-mdpi/title_bar_medium.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/email_widget_preview.png b/res/drawable/email_widget_preview.png
deleted file mode 100644
index f9d6342..0000000
--- a/res/drawable/email_widget_preview.png
+++ /dev/null
Binary files differ
diff --git a/res/layout/account_setup_account_type.xml b/res/layout/account_setup_account_type.xml
index e09bc2f..8305b45 100644
--- a/res/layout/account_setup_account_type.xml
+++ b/res/layout/account_setup_account_type.xml
@@ -4,9 +4,9 @@
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.
@@ -14,13 +14,15 @@
limitations under the License.
-->
+<!-- small -->
+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="match_parent"
android:orientation="vertical"
- >
- <TextView
- android:text="@string/account_setup_account_type_instructions"
+ >
+ <TextView
+ android:text="@string/account_setup_account_type_instructions"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceMedium"
diff --git a/res/layout/list_title.xml b/res/layout/list_title.xml
deleted file mode 100644
index 8dfb39a..0000000
--- a/res/layout/list_title.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/screen"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:background="@android:drawable/title_bar">
-
- <TextView android:id="@+id/title_left_text"
- android:gravity="center_vertical|left"
- android:ellipsize="end"
- android:singleLine="true"
- style="?android:attr/windowTitleStyle"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_weight="1" />
-
- <TextView android:id="@+id/title_right_text"
- android:gravity="center_vertical|right"
- android:ellipsize="end"
- android:singleLine="true"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textColor="#ffffffff"
- android:shadowRadius="0.1"
- android:shadowDy="1"
- android:shadowColor="#ff000000"
- android:layout_weight="1" />
-
- <Button android:id="@+id/account_title_button"
- android:gravity="center_vertical|right"
- android:visibility="gone"
- android:layout_width="wrap_content"
- android:layout_height="26dip"
- android:textColor="#ffffffff"
- android:layout_margin="3dip"
- android:paddingTop="0dip"
- android:paddingBottom="0dip"
- android:paddingLeft="10dip"
- android:paddingRight="10dip"
- android:background="@drawable/one_pixel_border_button" />
-
- <ProgressBar android:id="@+id/title_progress_icon"
- style="?android:attr/progressBarStyleSmallTitle"
- android:visibility="gone"
- android:minWidth="10dip"
- android:paddingRight="1dip"
- android:layout_marginLeft="4dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
-</LinearLayout>
diff --git a/res/layout/message_list.xml b/res/layout/message_list.xml
index 4bbcf2f..3a67c65 100644
--- a/res/layout/message_list.xml
+++ b/res/layout/message_list.xml
@@ -20,7 +20,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <include layout="@layout/list_title" />
<include layout="@layout/connection_error_banner" />
<fragment
@@ -29,38 +28,4 @@
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" />
-
- <!-- Footer in Multi-select mode -->
- <LinearLayout android:id="@+id/footer_organize"
- android:orientation="horizontal"
- android:visibility="gone"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="5dip"
- android:paddingLeft="4dip"
- android:paddingRight="4dip"
- android:paddingBottom="1dip"
- android:background="@android:drawable/bottom_bar">
-
- <Button
- android:id="@+id/btn_read_unread"
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:text="@string/read_unread_action" />
-
- <Button
- android:id="@+id/btn_multi_favorite"
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:text="@string/favorite_action" />
-
- <Button android:id="@+id/btn_multi_delete"
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:text="@string/delete_action" />
-
- </LinearLayout>
</LinearLayout>
diff --git a/res/menu/message_list_option.xml b/res/menu/message_list_option.xml
index 7d05cb6..f8635f4 100644
--- a/res/menu/message_list_option.xml
+++ b/res/menu/message_list_option.xml
@@ -4,9 +4,9 @@
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.
@@ -14,35 +14,32 @@
limitations under the License.
-->
-<!-- This menu is shown when MessageList is viewing a regular mailbox. -->
-
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/refresh"
android:alphabeticShortcut="r"
android:title="@string/refresh_action"
- android:icon="@drawable/ic_menu_refresh"
+ android:icon="@drawable/ic_menu_refresh_holo_light"
+ android:showAsAction="ifRoom"
/>
<item android:id="@+id/compose"
android:alphabeticShortcut="c"
android:title="@string/compose_action"
- android:icon="@drawable/ic_menu_compose"
+ android:icon="@drawable/ic_menu_compose_holo_light"
+ android:showAsAction="ifRoom"
/>
- <group android:id="@+id/deselect_all_group">
- <item android:id="@+id/deselect_all"
- android:title="@string/deselect_all_action"
- android:icon="@drawable/ic_menu_email_deselect_mail"
- />
- </group>
<item android:id="@+id/folders"
android:title="@string/folders_action"
android:icon="@drawable/ic_menu_folder"
+ android:showAsAction="ifRoom"
/>
<item android:id="@+id/accounts"
android:title="@string/accounts_action"
android:icon="@drawable/ic_menu_account_list"
+ android:showAsAction="ifRoom"
/>
<item android:id="@+id/account_settings"
android:title="@string/account_settings_action"
android:icon="@android:drawable/ic_menu_preferences"
+ android:showAsAction="ifRoom"
/>
</menu>
diff --git a/res/menu/message_list_option_smart_folder.xml b/res/menu/message_list_option_smart_folder.xml
deleted file mode 100644
index cafc4fe..0000000
--- a/res/menu/message_list_option_smart_folder.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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 menu is shown when MessageList is viewing a smart-folder mailbox. -->
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/refresh"
- android:alphabeticShortcut="r"
- android:title="@string/refresh_action"
- android:icon="@drawable/ic_menu_refresh"
- />
- <item android:id="@+id/compose"
- android:alphabeticShortcut="c"
- android:title="@string/compose_action"
- android:icon="@drawable/ic_menu_compose"
- />
- <item android:id="@+id/accounts"
- android:title="@string/accounts_action"
- android:icon="@drawable/ic_menu_account_list"
- />
- <group android:id="@+id/deselect_all_group">
- <item android:id="@+id/deselect_all"
- android:title="@string/deselect_all_action"
- android:icon="@drawable/ic_menu_email_deselect_mail"
- />
- </group>
-</menu>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 83f0341..98f94f0 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -787,6 +787,9 @@
being supported [CHAR LIMIT=none] -->
<string name="account_setup_failed_security_policies_unsupported">
This server requires security features that your Android device does not support.</string>
+ <!-- The user name can only be changed during initial account setup. [CHAR LIMIT=none] -->
+ <string name="account_setup_username_uneditable_error">You can\'t change an account\'s username.
+ To add an account with a different username, touch Add account.</string>
<!-- Warning given to users when they request disabling device administration (i.e. that their
administered accounts will be deleted) [CHAR LIMIT=none] -->
<string name="disable_admin_warning">WARNING: Deactivating the Email application\'s authority
diff --git a/res/xml/providers.xml b/res/xml/providers.xml
index 8a92f0b..4d607d7 100644
--- a/res/xml/providers.xml
+++ b/res/xml/providers.xml
@@ -4,9 +4,9 @@
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.
@@ -16,20 +16,20 @@
<!--
This file contains configuration data for commonly-used email providers.
-
+
==== CONTENT GUIDELINES ====
-
+
This file should only be used for email providers that are considered "universal"
and are appropriate for *all* android platform devices. These entries must be accessible
from all networks. It should be reasonable for any user to obtain an account on these
networks, and test accounts must be easily obtainable. No entries should be added
that are device, product, or carrier-specific.
-
- Entries that are device, product or carrier-specific should be added as overlays
+
+ Entries that are device, product or carrier-specific should be added as overlays
in the appropriate providers_product.xml file.
-
+
==== FORMAT OF ENTRIES ====
-
+
This file is used to specify providers that we know default settings for
so that the user can set up their account by simply entering their email
address and password.
@@ -37,7 +37,7 @@
When a user starts this process, the email address is parsed, the domain
broken out and used to search this file for a provider. If one is found the
provider's settings are used to attempt to connect to the account.
-
+
At this time, the id and label attributes are not used. However, please include them
if you make edits to this file. id must also be completely unique. label will be shown
to the user when there are multiple options provided for a single domain (not currently
@@ -75,26 +75,49 @@
"smtp+tls+trustallcerts". This should only used when necessary, as it
could allow a spoofed server to intercept password and mail.
- The URIs should be full templates for connection, including a port if
- the service uses a non-default port. The default ports are as follows:
+ The URIs must contain all of the information to make a connection,
+ including a port if the service uses a non-default port. The default
+ ports are as follows:
imap 143 pop3 110 smtp 587
imap+tls+ 143 pop3+tls+ 110 smtp+tls+ 587
imap+ssl+ 993 pop3+ssl+ 995 smtp+ssl+ 465
+ ==== DOMAIN PATTERNS ====
+
+ Often times a hosting company will have multiple mail server addresses. Often
+ times used for load balancing or based upon geographical boundaries. In these
+ cases, it would be unwieldy to maintain a list of 2-dozen providers that all
+ point the essentially the same mail server. To alleviate this, domains may
+ contain pattern matching characters that can be used to match user entered
+ domains without knowing the exact domain.
+
+ The domain attribute may specify a most one global character - a '*'. The
+ global character matches zero or more characters. This is a very greedy wild
+ card and may lead to unexpected matches.
+
+ The alternate is the wild card character - a '?'. The wide card character
+ matches any single character. This is very useful when the number of characters
+ is know (such as the country code in the domain).
+
+ ==== TEMPLATES ====
+
+ Both the username and uri attributes (for both incoming and outgoing elements)
+ are templates.
+
The username attribute is used to supply a template for the username
that will be presented to the server. This username is built from a
- set of variables that are substituted with parts of the user
- specified email address.
+ set of variables that are substituted with parts of the user specified
+ email address.
- Valid substitution values for the username attribute are:
+ Valid substitution values for all templates are:
$email - the email address the user entered
- $user - the value before the @ sign in the email address the user entered
- $domain - the value after the @ signin the email address the user entered
-
+ $user - the string before the @ sign in the email address the user entered
+ $domain - the string after the @ sign in the email address the user entered
+
The username attribute MUST be specified for the incoming element, so the POP3 or IMAP
server can identify the mailbox to be opened.
-
- The username attribute MAY be the empty string for the outgoing element, but only if the
+
+ The username attribute MAY be the empty string for the outgoing element, but only if the
SMTP server supports anonymous transmission (most don't).
-->
@@ -233,220 +256,8 @@
<incoming uri="pop3://pop-server.roadrunner.com" username="$email" />
<outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
</provider>
- <provider id="rr-austin" label="RoadRunner" domain="austin.rr.com">
- <incoming uri="pop3://pop-server.austin.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-bak" label="RoadRunner" domain="bak.rr.com">
- <incoming uri="pop3://pop-server.bak.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-berkshire" label="RoadRunner" domain="berkshire.rr.com">
- <incoming uri="pop3://pop-server.berkshire.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-bham" label="RoadRunner" domain="bham.rr.com">
- <incoming uri="pop3://pop-server.bham.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-ca" label="RoadRunner" domain="ca.rr.com">
- <incoming uri="pop3://pop-server.ca.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-carolina" label="RoadRunner" domain="carolina.rr.com">
- <incoming uri="pop3://pop-server.carolina.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-cfl" label="RoadRunner" domain="cfl.rr.com">
- <incoming uri="pop3://pop-server.cfl.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-cinci" label="RoadRunner" domain="cinci.rr.com">
- <incoming uri="pop3://pop-server.cinci.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-columbus" label="RoadRunner" domain="columbus.rr.com">
- <incoming uri="pop3://pop-server.columbus.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-dc" label="RoadRunner" domain="dc.rr.com">
- <incoming uri="pop3://pop-server.dc.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-ec" label="RoadRunner" domain="ec.rr.com">
- <incoming uri="pop3://pop-server.ec.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-elmore" label="RoadRunner" domain="elmore.rr.com">
- <incoming uri="pop3://pop-server.elmore.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-elp" label="RoadRunner" domain="elp.rr.com">
- <incoming uri="pop3://pop-server.elp.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-eufaula" label="RoadRunner" domain="eufaula.rr.com">
- <incoming uri="pop3://pop-server.eufaula.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-gt" label="RoadRunner" domain="gt.rr.com">
- <incoming uri="pop3://pop-server.gt.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-hawaii" label="RoadRunner" domain="hawaii.rr.com">
- <incoming uri="pop3://pop-server.hawaii.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-hot" label="RoadRunner" domain="hot.rr.com">
- <incoming uri="pop3://pop-server.hot.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-hvc" label="RoadRunner" domain="hvc.rr.com">
- <incoming uri="pop3://pop-server.hvc.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-indy" label="RoadRunner" domain="indy.rr.com">
- <incoming uri="pop3://pop-server.indy.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-insight" label="RoadRunner" domain="insight.rr.com">
- <incoming uri="pop3://pop-server.insight.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-kc" label="RoadRunner" domain="kc.rr.com">
- <incoming uri="pop3://pop-server.kc.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-ma" label="RoadRunner" domain="ma.rr.com">
- <incoming uri="pop3://pop-server.ma.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-maine" label="RoadRunner" domain="maine.rr.com">
- <incoming uri="pop3://pop-server.maine.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-mass" label="RoadRunner" domain="mass.rr.com">
- <incoming uri="pop3://pop-server.mass.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-mi" label="RoadRunner" domain="mi.rr.com">
- <incoming uri="pop3://pop-server.mi.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-nc" label="RoadRunner" domain="nc.rr.com">
- <incoming uri="pop3://pop-server.nc.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-ne" label="RoadRunner" domain="ne.rr.com">
- <incoming uri="pop3://pop-server.ne.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-neb" label="RoadRunner" domain="neb.rr.com">
- <incoming uri="pop3://pop-server.neb.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-neo" label="RoadRunner" domain="neo.rr.com">
- <incoming uri="pop3://pop-server.neo.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-new" label="RoadRunner" domain="new.rr.com">
- <incoming uri="pop3://pop-server.new.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-nj" label="RoadRunner" domain="nj.rr.com">
- <incoming uri="pop3://pop-server.nj.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-nyc" label="RoadRunner" domain="nyc.rr.com">
- <incoming uri="pop3://pop-server.nyc.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-nycap" label="RoadRunner" domain="nycap.rr.com">
- <incoming uri="pop3://pop-server.nycap.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-oh" label="RoadRunner" domain="oh.rr.com">
- <incoming uri="pop3://pop-server.oh.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-pa" label="RoadRunner" domain="pa.rr.com">
- <incoming uri="pop3://pop-server.pa.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-panhandle" label="RoadRunner" domain="panhandle.rr.com">
- <incoming uri="pop3://pop-server.panhandle.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-rgv" label="RoadRunner" domain="rgv.rr.com">
- <incoming uri="pop3://pop-server.rgv.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-rochester" label="RoadRunner" domain="rochester.rr.com">
- <incoming uri="pop3://pop-server.rochester.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-san" label="RoadRunner" domain="san.rr.com">
- <incoming uri="pop3://pop-server.san.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-satx" label="RoadRunner" domain="satx.rr.com">
- <incoming uri="pop3://pop-server.satx.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-sc" label="RoadRunner" domain="sc.rr.com">
- <incoming uri="pop3://pop-server.sc.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-si" label="RoadRunner" domain="si.rr.com">
- <incoming uri="pop3://pop-server.si.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-socal" label="RoadRunner" domain="socal.rr.com">
- <incoming uri="pop3://pop-server.socal.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-stny" label="RoadRunner" domain="stny.rr.com">
- <incoming uri="pop3://pop-server.stny.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-stx" label="RoadRunner" domain="stx.rr.com">
- <incoming uri="pop3://pop-server.stx.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-sw" label="RoadRunner" domain="sw.rr.com">
- <incoming uri="pop3://pop-server.sw.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-tampabay" label="RoadRunner" domain="tampabay.rr.com">
- <incoming uri="pop3://pop-server.tampabay.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-triad" label="RoadRunner" domain="triad.rr.com">
- <incoming uri="pop3://pop-server.triad.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-twcny" label="RoadRunner" domain="twcny.rr.com">
- <incoming uri="pop3://pop-server.twcny.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-twmi" label="RoadRunner" domain="twmi.rr.com">
- <incoming uri="pop3://pop-server.twmi.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-tx" label="RoadRunner" domain="tx.rr.com">
- <incoming uri="pop3://pop-server.tx.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-we" label="RoadRunner" domain="we.rr.com">
- <incoming uri="pop3://pop-server.we.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-wi" label="RoadRunner" domain="wi.rr.com">
- <incoming uri="pop3://pop-server.wi.rr.com" username="$email" />
- <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
- </provider>
- <provider id="rr-woh" label="RoadRunner" domain="woh.rr.com">
- <incoming uri="pop3://pop-server.woh.rr.com" username="$email" />
+ <provider id="rr-global" label="RoadRunner" domain="*.rr.com">
+ <incoming uri="pop3://pop-server.$domain" username="$email" />
<outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
</provider>
@@ -481,13 +292,13 @@
<incoming uri="pop3://incoming.verizon.net" username="$user" />
<outgoing uri="smtp://outgoing.verizon.net" username="$user" />
</provider>
-
+
<!-- UK -->
<provider id="aol-uk" label="AOL" domain="aol.co.uk">
<incoming uri="imap+ssl+://imap.uk.aol.com" label="IMAP" username="$user" />
<outgoing uri="smtp+ssl+://smtp.uk.aol.com" username="$user" />
</provider>
-
+
<!-- Germany -->
<provider id="freenet" label="Freenet" domain="freenet.de">
<incoming uri="pop3://mx.freenet.de" username="$user" />
@@ -497,7 +308,7 @@
<incoming uri="pop3://pop.gmx.net" username="$email" />
<outgoing uri="smtp://mail.gmx.net" username="$email" />
</provider>
- <provider id="T-Online" label="T-Online" domain="t-online.de"
+ <provider id="T-Online" label="T-Online" domain="t-online.de"
note="@string/provider_note_t_online">
<incoming uri="pop3://popmail.t-online.de" username="$email" />
<outgoing uri="smtp://smtpmail.t-online.de" username="$email" />
@@ -569,99 +380,11 @@
</provider>
<!-- Yahoo! country-specific email domains -->
- <provider id="yahoo-ar" label="Yahoo! Argentina" domain="yahoo.com.ar">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
<provider id="yahoo-y7" label="Yahoo!7" domain="y7mail.com">
<incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
</provider>
- <provider id="yahoo-au" label="Yahoo! Australia" domain="yahoo.com.au">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-bg" label="Yahoo! Bulgaria" domain="yahoo.bg">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-br" label="Yahoo! Brazil" domain="yahoo.com.br">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-ca" label="Yahoo! Canada" domain="yahoo.ca">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-cl" label="Yahoo! Cote d'Ivoire" domain="yahoo.cl">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-com-cn" label="Yahoo! China" domain="yahoo.com.cn">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-cn" label="Yahoo! China" domain="yahoo.cn">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-co" label="Yahoo! Colombia" domain="yahoo.com.co">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-cz" label="Yahoo! Czech Republic" domain="yahoo.cz">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-de" label="Yahoo! Germany" domain="yahoo.de">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-dk" label="Yahoo! Denmark" domain="yahoo.dk">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-ec" label="Yahoo! Ecuador" domain="yahoo.com.ec">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-ee" label="Yahoo! Estonia" domain="yahoo.ee">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-es" label="Yahoo! Spain" domain="yahoo.es">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-fr" label="Yahoo! France" domain="yahoo.fr">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-gr" label="Yahoo! Greece" domain="yahoo.gr">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-hk" label="Yahoo! Hong Kong" domain="yahoo.com.hk">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-hu" label="Yahoo! Hungary" domain="yahoo.hu">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-id" label="Yahoo! Indonesia" domain="yahoo.co.id">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-ie" label="Yahoo! Ireland" domain="yahoo.ie">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-in" label="Yahoo! India" domain="yahoo.in">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-it" label="Yahoo! Italy" domain="yahoo.it">
+ <provider id="kimo" label="Yahoo! Taiwan" domain="kimo.com">
<incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
</provider>
@@ -675,107 +398,15 @@
<incoming uri="pop3+ssl+://android.pop.mail.yahoo.co.jp" username="$user" />
<outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.co.jp" username="$user" />
</provider>
- <provider id="yahoo-kr" label="Yahoo! Republic of Korea" domain="yahoo.co.kr">
+ <provider id="yahoo-com-XX" label="Country specific Yahoo!" domain="yahoo.com.??">
<incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
</provider>
- <provider id="yahoo-lt" label="Yahoo! Lithuania" domain="yahoo.lt">
+ <provider id="yahoo-co-XX" label="Country specific Yahoo!" domain="yahoo.co.??">
<incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
</provider>
- <provider id="yahoo-lv" label="Yahoo! Latvia" domain="yahoo.lv">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-mx" label="Yahoo! Mexico" domain="yahoo.com.mx">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-my" label="Yahoo! Malaysia" domain="yahoo.com.my">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-ng" label="Yahoo! Nigeria" domain="yahoo.com.ng">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-no" label="Yahoo! Norway" domain="yahoo.no">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-nz" label="Yahoo! New Zealand" domain="yahoo.co.nz">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-pe" label="Yahoo! Peru" domain="yahoo.com.pe">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-ph" label="Yahoo! Philippines" domain="yahoo.com.ph">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-pk" label="Yahoo! Pakistan" domain="yahoo.com.pk">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-pl" label="Yahoo! Poland" domain="yahoo.pl">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-ru" label="Yahoo! Russia" domain="yahoo.ru">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-ro" label="Yahoo! Romania" domain="yahoo.ro">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-se" label="Yahoo! Sweden" domain="yahoo.se">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-sg" label="Yahoo! Singapore" domain="yahoo.com.sg">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-th" label="Yahoo! Thailand" domain="yahoo.co.th">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-tr" label="Yahoo! Turkey" domain="yahoo.com.tr">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="kimo" label="Yahoo! Taiwan" domain="kimo.com">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-tw" label="Yahoo! Taiwan" domain="yahoo.com.tw">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-ua" label="Yahoo! Ukraine" domain="yahoo.ua">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-uk" label="Yahoo! UK" domain="yahoo.co.uk">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-ve" label="Yahoo! Venezuela" domain="yahoo.com.ve">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-vn" label="Yahoo! Vietnam" domain="yahoo.com.vn">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="yahoo-za" label="Yahoo! South Africa" domain="yahoo.co.za">
- <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
- <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
- </provider>
- <provider id="xtra" label="Yahoo! Xtra" domain="xtra.co.nz">
+ <provider id="yahoo-XX" label="Country specific Yahoo!" domain="yahoo.??">
<incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
</provider>
diff --git a/src/com/android/email/UiUtilities.java b/src/com/android/email/UiUtilities.java
deleted file mode 100644
index 79ac4bb..0000000
--- a/src/com/android/email/UiUtilities.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.email;
-
-import android.content.Context;
-import android.content.res.Resources;
-
-public class UiUtilities {
-
- /**
- * Formats the given size as a String in bytes, kB, MB or GB. Ex: 12,315,000 = 11 MB
- */
- public static String formatSize(Context context, long size) {
- final Resources res = context.getResources();
- final long KB = 1024;
- final long MB = (KB * 1024);
- final long GB = (MB * 1024);
-
- int resId;
- int value;
-
- if (size < KB) {
- resId = R.plurals.message_view_attachment_bytes;
- value = (int) size;
- } else if (size < MB) {
- resId = R.plurals.message_view_attachment_kilobytes;
- value = (int) (size / KB);
- } else if (size < GB) {
- resId = R.plurals.message_view_attachment_megabytes;
- value = (int) (size / MB);
- } else {
- resId = R.plurals.message_view_attachment_gigabytes;
- value = (int) (size / GB);
- }
- return res.getQuantityString(resId, value, value);
- }
-
- public static String getMessageCountForUi(Context context, int count,
- boolean replaceZeroWithBlank) {
- if (replaceZeroWithBlank && (count == 0)) {
- return "";
- } else if (count > 999) {
- return context.getString(R.string.more_than_999);
- } else {
- return Integer.toString(count);
- }
- }
-}
diff --git a/src/com/android/email/activity/AccountSelectorAdapter.java b/src/com/android/email/activity/AccountSelectorAdapter.java
index b58e8c2..abf99f4 100644
--- a/src/com/android/email/activity/AccountSelectorAdapter.java
+++ b/src/com/android/email/activity/AccountSelectorAdapter.java
@@ -17,7 +17,6 @@
package com.android.email.activity;
import com.android.email.R;
-import com.android.email.UiUtilities;
import com.android.email.data.ClosingMatrixCursor;
import com.android.email.data.ThrottlingCursorLoader;
import com.android.emailcommon.provider.EmailContent;
diff --git a/src/com/android/email/activity/MessageCompose.java b/src/com/android/email/activity/MessageCompose.java
index 2c9c615..dc09fa5 100644
--- a/src/com/android/email/activity/MessageCompose.java
+++ b/src/com/android/email/activity/MessageCompose.java
@@ -20,7 +20,6 @@
import com.android.email.Email;
import com.android.email.EmailAddressAdapter;
import com.android.email.EmailAddressValidator;
-import com.android.email.UiUtilities;
import com.android.email.R;
import com.android.email.mail.internet.EmailHtmlUtil;
import com.android.emailcommon.Logging;
diff --git a/src/com/android/email/activity/MessageList.java b/src/com/android/email/activity/MessageList.java
index 9d6cdec..fe5cd64 100644
--- a/src/com/android/email/activity/MessageList.java
+++ b/src/com/android/email/activity/MessageList.java
@@ -20,43 +20,26 @@
import com.android.email.ControllerResultUiThreadWrapper;
import com.android.email.Email;
import com.android.email.MessagingExceptionStrings;
-import com.android.email.FolderProperties;
import com.android.email.R;
import com.android.email.activity.setup.AccountSecurity;
import com.android.email.activity.setup.AccountSettingsXL;
import com.android.emailcommon.mail.MessagingException;
-import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Account;
-import com.android.emailcommon.provider.EmailContent.AccountColumns;
import com.android.emailcommon.provider.EmailContent.Mailbox;
-import com.android.emailcommon.provider.EmailContent.MailboxColumns;
-import com.android.emailcommon.utility.Utility;
import android.app.Activity;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.database.Cursor;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.animation.Animation;
-import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
-import android.widget.Button;
-import android.widget.ProgressBar;
import android.widget.TextView;
-// TODO Rework the menu for the phone UI
-// Menu won't show up on the phone UI -- not sure if it's a framework issue or our bug.
-
-public class MessageList extends Activity implements OnClickListener,
- AnimationListener, MessageListFragment.Callback {
+public class MessageList extends Activity implements MessageListFragment.Callback {
// Intent extras (internal to this activity)
private static final String EXTRA_ACCOUNT_ID = "com.android.email.activity._ACCOUNT_ID";
private static final String EXTRA_MAILBOX_TYPE = "com.android.email.activity.MAILBOX_TYPE";
@@ -66,37 +49,13 @@
// UI support
private MessageListFragment mListFragment;
- private View mMultiSelectPanel;
- private Button mReadUnreadButton;
- private Button mFavoriteButton;
- private Button mDeleteButton;
private TextView mErrorBanner;
private final Controller mController = Controller.getInstance(getApplication());
private ControllerResultUiThreadWrapper<ControllerResults> mControllerCallback;
- private TextView mLeftTitle;
- private ProgressBar mProgressIcon;
-
- // DB access
- private ContentResolver mResolver;
- private SetTitleTask mSetTitleTask;
-
private MailboxFinder mMailboxFinder;
- private MailboxFinderCallback mMailboxFinderCallback = new MailboxFinderCallback();
-
- private static final int MAILBOX_NAME_COLUMN_ID = 0;
- private static final int MAILBOX_NAME_COLUMN_ACCOUNT_KEY = 1;
- private static final int MAILBOX_NAME_COLUMN_TYPE = 2;
- private static final String[] MAILBOX_NAME_PROJECTION = new String[] {
- MailboxColumns.DISPLAY_NAME, MailboxColumns.ACCOUNT_KEY,
- MailboxColumns.TYPE};
-
- private static final int ACCOUNT_DISPLAY_NAME_COLUMN_ID = 0;
- private static final String[] ACCOUNT_NAME_PROJECTION = new String[] {
- AccountColumns.DISPLAY_NAME };
-
- private static final String ID_SELECTION = EmailContent.RECORD_ID + "=?";
+ private final MailboxFinderCallback mMailboxFinderCallback = new MailboxFinderCallback();
/* package */ MessageListFragment getListFragmentForTest() {
return mListFragment;
@@ -179,23 +138,10 @@
new Handler(), new ControllerResults());
mListFragment = (MessageListFragment) getFragmentManager()
.findFragmentById(R.id.message_list_fragment);
- mMultiSelectPanel = findViewById(R.id.footer_organize);
- mReadUnreadButton = (Button) findViewById(R.id.btn_read_unread);
- mFavoriteButton = (Button) findViewById(R.id.btn_multi_favorite);
- mDeleteButton = (Button) findViewById(R.id.btn_multi_delete);
- mLeftTitle = (TextView) findViewById(R.id.title_left_text);
- mProgressIcon = (ProgressBar) findViewById(R.id.title_progress_icon);
mErrorBanner = (TextView) findViewById(R.id.connection_error_text);
- mReadUnreadButton.setOnClickListener(this);
- mFavoriteButton.setOnClickListener(this);
- mDeleteButton.setOnClickListener(this);
- ((Button) findViewById(R.id.account_title_button)).setOnClickListener(this);
-
mListFragment.setCallback(this);
- mResolver = getContentResolver();
-
// Show the appropriate account/mailbox specified by an {@link Intent}.
selectAccountAndMailbox(getIntent());
}
@@ -206,9 +152,6 @@
private void selectAccountAndMailbox(Intent intent) {
long mailboxId = intent.getLongExtra(EXTRA_MAILBOX_ID, -1);
if (mailboxId != -1) {
- // Specific mailbox ID was provided - go directly to it
- mSetTitleTask = new SetTitleTask(mailboxId);
- mSetTitleTask.execute();
mListFragment.openMailbox(mailboxId);
} else {
int mailboxType = intent.getIntExtra(EXTRA_MAILBOX_TYPE, Mailbox.TYPE_INBOX);
@@ -227,7 +170,6 @@
mMailboxFinderCallback);
mMailboxFinder.startLookup();
}
- // TODO set title to "account > mailbox (#unread)"
}
@Override
@@ -257,8 +199,6 @@
mMailboxFinder.cancel();
mMailboxFinder = null;
}
- Utility.cancelTaskInterrupt(mSetTitleTask);
- mSetTitleTask = null;
}
@@ -291,60 +231,15 @@
public void onEnterSelectionMode(boolean enter) {
}
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.btn_read_unread:
- mListFragment.onMultiToggleRead();
- break;
- case R.id.btn_multi_favorite:
- mListFragment.onMultiToggleFavorite();
- break;
- case R.id.btn_multi_delete:
- mListFragment.onMultiDelete();
- break;
- case R.id.account_title_button:
- onAccounts();
- break;
- }
- }
-
- public void onAnimationEnd(Animation animation) {
- // TODO: If the button panel hides the only selected item, scroll the list to make it
- // visible again.
- }
-
- public void onAnimationRepeat(Animation animation) {
- }
-
- public void onAnimationStart(Animation animation) {
- }
-
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- return true; // Tell the framework it has the menu
+ getMenuInflater().inflate(R.menu.message_list_option, menu);
+ return true;
}
- private boolean mMenuCreated;
-
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
- if (mListFragment == null) {
- // Activity not initialized.
- // This method indirectly gets called from MessageListFragment.onCreate()
- // due to the setHasOptionsMenu() call, at which point this.onCreate() hasn't been
- // called -- thus mListFragment == null.
- return false;
- }
- if (!mMenuCreated) {
- mMenuCreated = true;
- if (mListFragment.isMagicMailbox()) {
- getMenuInflater().inflate(R.menu.message_list_option_smart_folder, menu);
- } else {
- getMenuInflater().inflate(R.menu.message_list_option, menu);
- }
- }
- boolean showDeselect = mListFragment.getSelectedCount() > 0;
- menu.setGroupVisible(R.id.deselect_all_group, showDeselect);
+ // TODO Disable "refresh" for combined mailboxes
return true;
}
@@ -366,9 +261,6 @@
case R.id.account_settings:
onEditAccount();
return true;
- case R.id.deselect_all:
- mListFragment.onDeselectAll();
- return true;
default:
return super.onOptionsItemSelected(item);
}
@@ -399,56 +291,6 @@
}
/**
- * Show multi-selection panel, if one or more messages are selected. Button labels will be
- * updated too.
- *
- * @deprecated not used any longer. remove them.
- */
- public void onSelectionChanged() {
- showMultiPanel(mListFragment.getSelectedCount() > 0);
- }
-
- /**
- * @deprecated not used any longer. remove them. (with associated resources, strings,
- * members, etc)
- */
- private void updateFooterButtonNames () {
- // Show "unread_action" when one or more read messages are selected.
- if (mListFragment.doesSelectionContainReadMessage()) {
- mReadUnreadButton.setText(R.string.unread_action);
- } else {
- mReadUnreadButton.setText(R.string.read_action);
- }
- // Show "set_star_action" when one or more un-starred messages are selected.
- if (mListFragment.doesSelectionContainNonStarredMessage()) {
- mFavoriteButton.setText(R.string.set_star_action);
- } else {
- mFavoriteButton.setText(R.string.remove_star_action);
- }
- }
-
- /**
- * Show or hide the panel of multi-select options
- *
- * @deprecated not used any longer. remove them.
- */
- private void showMultiPanel(boolean show) {
- if (show && mMultiSelectPanel.getVisibility() != View.VISIBLE) {
- mMultiSelectPanel.setVisibility(View.VISIBLE);
- Animation animation = AnimationUtils.loadAnimation(this, R.anim.footer_appear);
- animation.setAnimationListener(this);
- mMultiSelectPanel.startAnimation(animation);
- } else if (!show && mMultiSelectPanel.getVisibility() != View.GONE) {
- mMultiSelectPanel.setVisibility(View.GONE);
- mMultiSelectPanel.startAnimation(
- AnimationUtils.loadAnimation(this, R.anim.footer_disappear));
- }
- if (show) {
- updateFooterButtonNames();
- }
- }
-
- /**
* Handle the eventual result from the security update activity
*
* Note, this is extremely coarse, and it simply returns the user to the Accounts list.
@@ -463,99 +305,8 @@
super.onActivityResult(requestCode, resultCode, data);
}
- private class SetTitleTask extends AsyncTask<Void, Void, Object[]> {
-
- private long mMailboxKey;
-
- public SetTitleTask(long mailboxKey) {
- mMailboxKey = mailboxKey;
- }
-
- @Override
- protected Object[] doInBackground(Void... params) {
- // Check special Mailboxes
- int resIdSpecialMailbox = 0;
- if (mMailboxKey == Mailbox.QUERY_ALL_INBOXES) {
- resIdSpecialMailbox = R.string.account_folder_list_summary_inbox;
- } else if (mMailboxKey == Mailbox.QUERY_ALL_FAVORITES) {
- resIdSpecialMailbox = R.string.account_folder_list_summary_starred;
- } else if (mMailboxKey == Mailbox.QUERY_ALL_DRAFTS) {
- resIdSpecialMailbox = R.string.account_folder_list_summary_drafts;
- } else if (mMailboxKey == Mailbox.QUERY_ALL_OUTBOX) {
- resIdSpecialMailbox = R.string.account_folder_list_summary_outbox;
- }
- if (resIdSpecialMailbox != 0) {
- return new Object[] {null, getString(resIdSpecialMailbox), 0};
- }
-
- String accountName = null;
- String mailboxName = null;
- String accountKey = null;
- Cursor c = MessageList.this.mResolver.query(Mailbox.CONTENT_URI,
- MAILBOX_NAME_PROJECTION, ID_SELECTION,
- new String[] { Long.toString(mMailboxKey) }, null);
- try {
- if (c.moveToFirst()) {
- mailboxName = FolderProperties.getInstance(MessageList.this)
- .getDisplayName(c.getInt(MAILBOX_NAME_COLUMN_TYPE));
- if (mailboxName == null) {
- mailboxName = c.getString(MAILBOX_NAME_COLUMN_ID);
- }
- accountKey = c.getString(MAILBOX_NAME_COLUMN_ACCOUNT_KEY);
- }
- } finally {
- c.close();
- }
- if (accountKey != null) {
- c = MessageList.this.mResolver.query(Account.CONTENT_URI,
- ACCOUNT_NAME_PROJECTION, ID_SELECTION, new String[] { accountKey },
- null);
- try {
- if (c.moveToFirst()) {
- accountName = c.getString(ACCOUNT_DISPLAY_NAME_COLUMN_ID);
- }
- } finally {
- c.close();
- }
- }
- int nAccounts = EmailContent.count(MessageList.this, Account.CONTENT_URI, null, null);
- return new Object[] {accountName, mailboxName, nAccounts};
- }
-
- @Override
- protected void onPostExecute(Object[] result) {
- if (result == null) {
- return;
- }
-
- final int nAccounts = (Integer) result[2];
- if (result[0] != null) {
- setTitleAccountName((String) result[0], nAccounts > 1);
- }
-
- if (result[1] != null) {
- mLeftTitle.setText((String) result[1]);
- }
- }
- }
-
- private void setTitleAccountName(String accountName, boolean showAccountsButton) {
- TextView accountsButton = (TextView) findViewById(R.id.account_title_button);
- TextView textPlain = (TextView) findViewById(R.id.title_right_text);
- if (showAccountsButton) {
- accountsButton.setVisibility(View.VISIBLE);
- textPlain.setVisibility(View.GONE);
- accountsButton.setText(accountName);
- } else {
- accountsButton.setVisibility(View.GONE);
- textPlain.setVisibility(View.VISIBLE);
- textPlain.setText(accountName);
- }
- }
-
private void showProgressIcon(boolean show) {
- int visibility = show ? View.VISIBLE : View.GONE;
- mProgressIcon.setVisibility(visibility);
+ // TODO Show "refreshing" icon somewhere. (It's on the action bar on xlarge.)
}
private void showErrorBanner(String message) {
@@ -579,6 +330,9 @@
}
/**
+ * TODO This should probably be removed -- use RefreshManager instead to update the progress
+ * icon and the error banner.
+ *
* Controller results listener. We wrap it with {@link ControllerResultUiThreadWrapper},
* so all methods are called on the UI thread.
*/
@@ -653,8 +407,6 @@
private class MailboxFinderCallback implements MailboxFinder.Callback {
@Override
public void onMailboxFound(long accountId, long mailboxId) {
- mSetTitleTask = new SetTitleTask(mailboxId);
- mSetTitleTask.execute();
mListFragment.openMailbox(mailboxId);
}
diff --git a/src/com/android/email/activity/MessageListXLFragmentManager.java b/src/com/android/email/activity/MessageListXLFragmentManager.java
index 383e044..5ad23c4 100644
--- a/src/com/android/email/activity/MessageListXLFragmentManager.java
+++ b/src/com/android/email/activity/MessageListXLFragmentManager.java
@@ -18,7 +18,6 @@
import com.android.email.Email;
import com.android.email.R;
-import com.android.email.UiUtilities;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.Mailbox;
diff --git a/src/com/android/email/activity/MessageViewFragmentBase.java b/src/com/android/email/activity/MessageViewFragmentBase.java
index a74778c..a843d1d 100644
--- a/src/com/android/email/activity/MessageViewFragmentBase.java
+++ b/src/com/android/email/activity/MessageViewFragmentBase.java
@@ -20,7 +20,6 @@
import com.android.email.Controller;
import com.android.email.ControllerResultUiThreadWrapper;
import com.android.email.Email;
-import com.android.email.UiUtilities;
import com.android.email.Preferences;
import com.android.email.R;
import com.android.email.Throttle;
diff --git a/src/com/android/email/activity/UiUtilities.java b/src/com/android/email/activity/UiUtilities.java
new file mode 100644
index 0000000..9512460
--- /dev/null
+++ b/src/com/android/email/activity/UiUtilities.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.email.activity;
+
+import com.android.email.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.View;
+
+public class UiUtilities {
+ private UiUtilities() {
+ }
+
+ /**
+ * Formats the given size as a String in bytes, kB, MB or GB. Ex: 12,315,000 = 11 MB
+ */
+ public static String formatSize(Context context, long size) {
+ final Resources res = context.getResources();
+ final long KB = 1024;
+ final long MB = (KB * 1024);
+ final long GB = (MB * 1024);
+
+ int resId;
+ int value;
+
+ if (size < KB) {
+ resId = R.plurals.message_view_attachment_bytes;
+ value = (int) size;
+ } else if (size < MB) {
+ resId = R.plurals.message_view_attachment_kilobytes;
+ value = (int) (size / KB);
+ } else if (size < GB) {
+ resId = R.plurals.message_view_attachment_megabytes;
+ value = (int) (size / MB);
+ } else {
+ resId = R.plurals.message_view_attachment_gigabytes;
+ value = (int) (size / GB);
+ }
+ return res.getQuantityString(resId, value, value);
+ }
+
+ public static String getMessageCountForUi(Context context, int count,
+ boolean replaceZeroWithBlank) {
+ if (replaceZeroWithBlank && (count == 0)) {
+ return "";
+ } else if (count > 999) {
+ return context.getString(R.string.more_than_999);
+ } else {
+ return Integer.toString(count);
+ }
+ }
+
+ /**
+ * Same as {@link Activity#findViewById}, but crashes if there's no view.
+ */
+ public static View getView(Activity parent, int viewId) {
+ return checkView(parent.findViewById(viewId));
+ }
+
+ /**
+ * Same as {@link View#findViewById}, but crashes if there's no view.
+ */
+ public static View getView(View parent, int viewId) {
+ return checkView(parent.findViewById(viewId));
+ }
+
+ private static View checkView(View v) {
+ if (v == null) {
+ throw new IllegalArgumentException("View doesn't exist");
+ }
+ return v;
+ }
+
+ /**
+ * Same as {@link View#setVisibility(int)}, but doesn't crash even if {@code view} is null.
+ */
+ public static void setVisibilitySafe(View v, int visibility) {
+ if (v != null) {
+ v.setVisibility(visibility);
+ }
+ }
+
+ /**
+ * Same as {@link View#setVisibility(int)}, but doesn't crash even if {@code view} is null.
+ */
+ public static void setVisibilitySafe(Activity parent, int viewId, int visibility) {
+ setVisibilitySafe(parent.findViewById(viewId), visibility);
+ }
+
+ /**
+ * Same as {@link View#setVisibility(int)}, but doesn't crash even if {@code view} is null.
+ */
+ public static void setVisibilitySafe(View parent, int viewId, int visibility) {
+ setVisibilitySafe(parent.findViewById(viewId), visibility);
+ }
+}
diff --git a/src/com/android/email/activity/setup/AccountServerBaseFragment.java b/src/com/android/email/activity/setup/AccountServerBaseFragment.java
index f84a48d..0c389ec 100644
--- a/src/com/android/email/activity/setup/AccountServerBaseFragment.java
+++ b/src/com/android/email/activity/setup/AccountServerBaseFragment.java
@@ -17,6 +17,7 @@
package com.android.email.activity.setup;
import com.android.email.R;
+import com.android.email.activity.UiUtilities;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.HostAuth;
@@ -29,7 +30,10 @@
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
+import android.widget.TextView;
import java.net.URI;
import java.net.URISyntaxException;
@@ -52,12 +56,18 @@
protected Context mContext;
protected Callback mCallback = EmptyCallback.INSTANCE;
+ /**
+ * Whether or not we are in "settings mode". We re-use the same screens for both the initial
+ * account creation as well as subsequent account modification. If <code>mSettingsMode</code>
+ * if <code>false</code>, we are in account creation mode. Otherwise, we are in account
+ * modification mode.
+ */
protected boolean mSettingsMode;
/*package*/ HostAuth mLoadedSendAuth;
/*package*/ HostAuth mLoadedRecvAuth;
// This is null in the setup wizard screens, and non-null in AccountSettings mode
- public Button mProceedButton;
+ private Button mProceedButton;
// This is used to debounce multiple clicks on the proceed button (which does async work)
private boolean mProceedButtonPressed;
/*package*/ String mBaseScheme = "protocol";
@@ -136,8 +146,8 @@
*/
protected void onCreateViewSettingsMode(View view) {
if (mSettingsMode) {
- view.findViewById(R.id.cancel).setOnClickListener(this);
- mProceedButton = (Button) view.findViewById(R.id.done);
+ UiUtilities.getView(view, R.id.cancel).setOnClickListener(this);
+ mProceedButton = (Button) UiUtilities.getView(view, R.id.done);
mProceedButton.setOnClickListener(this);
mProceedButton.setEnabled(false);
}
@@ -158,6 +168,15 @@
}
}
+ @Override
+ public void onPause() {
+ // Hide the soft keyboard if we lose focus
+ InputMethodManager imm =
+ (InputMethodManager)mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
+ super.onPause();
+ }
+
/**
* Implements OnClickListener
*/
@@ -213,6 +232,42 @@
}
/**
+ * Make the given text view uneditable. If the text view is ever focused, the specified
+ * error message will be displayed.
+ */
+ protected void makeTextViewUneditable(final TextView view, final String errorMessage) {
+ // We're editing an existing account; don't allow modification of the user name
+ if (mSettingsMode) {
+ view.setKeyListener(null);
+ view.setFocusable(true);
+ view.setOnFocusChangeListener(new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ // Framework will not auto-hide IME; do it ourselves
+ InputMethodManager imm = (InputMethodManager)mContext.
+ getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
+ view.setError(errorMessage);
+ } else {
+ view.setError(null);
+ }
+ }
+ });
+ view.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (view.getError() == null) {
+ view.setError(errorMessage);
+ } else {
+ view.setError(null);
+ }
+ }
+ });
+ }
+ }
+
+ /**
* Clears the "next" button de-bounce flags and allows the "next" button to activate.
*/
private void clearButtonBounce() {
diff --git a/src/com/android/email/activity/setup/AccountSettingsUtils.java b/src/com/android/email/activity/setup/AccountSettingsUtils.java
index 0634fd2..3cadc45 100644
--- a/src/com/android/email/activity/setup/AccountSettingsUtils.java
+++ b/src/com/android/email/activity/setup/AccountSettingsUtils.java
@@ -31,10 +31,15 @@
import android.widget.EditText;
import java.io.Serializable;
-import java.net.URI;
+import java.util.regex.Pattern;
public class AccountSettingsUtils {
+ /** Pattern to match globals in the domain */
+ private final static Pattern DOMAIN_GLOB_PATTERN = Pattern.compile("\\*");
+ /** Will match any, single character */
+ private final static char WILD_CHARACTER = '?';
+
/**
* Commits the UI-related settings of an account to the provider. This is static so that it
* can be used by the various account activities. If the account has never been saved, this
@@ -101,20 +106,28 @@
* @param resourceId Id of the provider resource to scan
* @return suitable Provider definition, or null if no match found
*/
- private static Provider findProviderForDomain(Context context, String domain, int resourceId) {
+ /*package*/ static Provider findProviderForDomain(
+ Context context, String domain, int resourceId) {
try {
XmlResourceParser xml = context.getResources().getXml(resourceId);
int xmlEventType;
Provider provider = null;
while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
if (xmlEventType == XmlResourceParser.START_TAG
- && "provider".equals(xml.getName())
- && domain.equalsIgnoreCase(getXmlAttribute(context, xml, "domain"))) {
- provider = new Provider();
- provider.id = getXmlAttribute(context, xml, "id");
- provider.label = getXmlAttribute(context, xml, "label");
- provider.domain = getXmlAttribute(context, xml, "domain");
- provider.note = getXmlAttribute(context, xml, "note");
+ && "provider".equals(xml.getName())) {
+ String providerDomain = getXmlAttribute(context, xml, "domain");
+ try {
+ if (globMatchIgnoreCase(domain, providerDomain)) {
+ provider = new Provider();
+ provider.id = getXmlAttribute(context, xml, "id");
+ provider.label = getXmlAttribute(context, xml, "label");
+ provider.domain = domain.toLowerCase();
+ provider.note = getXmlAttribute(context, xml, "note");
+ }
+ } catch (IllegalArgumentException e) {
+ Log.w(Logging.LOG_TAG, "providers line: " + xml.getLineNumber() +
+ "; Domain contains multiple globals");
+ }
}
else if (xmlEventType == XmlResourceParser.START_TAG
&& "incoming".equals(xml.getName())
@@ -142,6 +155,100 @@
}
/**
+ * Returns if the string <code>s1</code> matches the string <code>s2</code>. The string
+ * <code>s2</code> may contain any number of wildcards -- a '?' character -- and/or a
+ * single global character -- a '*' character. Wildcards match any, single character
+ * while a global character matches zero or more characters.
+ * @throws IllegalArgumentException if either string is null or <code>s2</code> has
+ * multiple globals.
+ */
+ /*package*/ static boolean globMatchIgnoreCase(String s1, String s2)
+ throws IllegalArgumentException {
+ if (s1 == null || s2 == null) {
+ throw new IllegalArgumentException("one or both strings are null");
+ }
+
+ // Handle the possible global in the domain name
+ String[] globParts = DOMAIN_GLOB_PATTERN.split(s2);
+ switch (globParts.length) {
+ case 1:
+ // No globals; test for simple equality
+ if (!wildEqualsIgnoreCase(s1, globParts[0])) {
+ return false;
+ }
+ break;
+ case 2:
+ // Global; test the front & end parts of the domain
+ String d1 = globParts[0];
+ String d2 = globParts[1];
+ if (!wildStartsWithIgnoreCase(s1, d1) ||
+ !wildEndsWithIgnoreCase(s1.substring(d1.length()), d2)) {
+ return false;
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Multiple globals");
+ }
+ return true;
+ }
+
+ /**
+ * Returns if the string <code>s1</code> equals the string <code>s2</code>. The string
+ * <code>s2</code> may contain zero or more wildcards -- a '?' character.
+ * @throws IllegalArgumentException if the strings are null.
+ */
+ /*package*/ static boolean wildEqualsIgnoreCase(String s1, String s2)
+ throws IllegalArgumentException {
+ if (s1 == null || s2 == null) {
+ throw new IllegalArgumentException("one or both strings are null");
+ }
+ if (s1.length() != s2.length()) {
+ return false;
+ }
+ char[] charArray1 = s1.toLowerCase().toCharArray();
+ char[] charArray2 = s2.toLowerCase().toCharArray();
+ for (int i = 0; i < charArray2.length; i++) {
+ if (charArray2[i] == WILD_CHARACTER || charArray1[i] == charArray2[i]) continue;
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns if the string <code>s1</code> starts with the string <code>s2</code>. The string
+ * <code>s2</code> may contain zero or more wildcards -- a '?' character.
+ * @throws IllegalArgumentException if the strings are null.
+ */
+ /*package*/ static boolean wildStartsWithIgnoreCase(String s1, String s2)
+ throws IllegalArgumentException {
+ if (s1 == null || s2 == null) {
+ throw new IllegalArgumentException("one or both strings are null");
+ }
+ if (s1.length() < s2.length()) {
+ return false;
+ }
+ s1 = s1.substring(0, s2.length());
+ return wildEqualsIgnoreCase(s1, s2);
+ }
+
+ /**
+ * Returns if the string <code>s1</code> ends with the string <code>s2</code>. The string
+ * <code>s2</code> may contain zero or more wildcards -- a '?' character.
+ * @throws IllegalArgumentException if the strings are null.
+ */
+ /*package*/ static boolean wildEndsWithIgnoreCase(String s1, String s2)
+ throws IllegalArgumentException {
+ if (s1 == null || s2 == null) {
+ throw new IllegalArgumentException("one or both strings are null");
+ }
+ if (s1.length() < s2.length()) {
+ return false;
+ }
+ s1 = s1.substring(s1.length() - s2.length(), s1.length());
+ return wildEqualsIgnoreCase(s1, s2);
+ }
+
+ /**
* Attempts to get the given attribute as a String resource first, and if it fails
* returns the attribute as a simple String value.
* @param xml
@@ -168,7 +275,38 @@
public String incomingUsernameTemplate;
public String outgoingUriTemplate;
public String outgoingUsernameTemplate;
+ public String incomingUri;
+ public String incomingUsername;
+ public String outgoingUri;
+ public String outgoingUsername;
public String note;
+
+ /**
+ * Expands templates in all of the provider fields that support them. Currently,
+ * templates are used in 4 fields -- incoming and outgoing URI and user name.
+ * @param email user-specified data used to replace template values
+ */
+ public void expandTemplates(String email) {
+ String[] emailParts = email.split("@");
+ String user = emailParts[0];
+
+ incomingUri = expandTemplate(incomingUriTemplate, email, user);
+ incomingUsername = expandTemplate(incomingUsernameTemplate, email, user);
+ outgoingUri = expandTemplate(outgoingUriTemplate, email, user);
+ outgoingUsername = expandTemplate(outgoingUsernameTemplate, email, user);
+ }
+
+ /**
+ * Replaces all parameterized values in the given template. The values replaced are
+ * $domain, $user and $email.
+ */
+ private String expandTemplate(String template, String email, String user) {
+ String returnString = template;
+ returnString = returnString.replaceAll("\\$email", email);
+ returnString = returnString.replaceAll("\\$user", user);
+ returnString = returnString.replaceAll("\\$domain", domain);
+ return returnString;
+ }
}
/**
diff --git a/src/com/android/email/activity/setup/AccountSetupAccountType.java b/src/com/android/email/activity/setup/AccountSetupAccountType.java
index 288dcec..6bd6706 100644
--- a/src/com/android/email/activity/setup/AccountSetupAccountType.java
+++ b/src/com/android/email/activity/setup/AccountSetupAccountType.java
@@ -20,6 +20,7 @@
import com.android.email.R;
import com.android.email.VendorPolicyLoader;
import com.android.email.activity.ActivityHelper;
+import com.android.email.activity.UiUtilities;
import com.android.email.mail.Store;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Account;
@@ -33,9 +34,6 @@
import android.view.View.OnClickListener;
import android.widget.Button;
-import java.net.URI;
-import java.net.URISyntaxException;
-
/**
* Prompts the user to select an account type. The account type, along with the
* passed in email address, password and makeDefault are then passed on to the
@@ -61,11 +59,11 @@
// Otherwise proceed into this screen
setContentView(R.layout.account_setup_account_type);
- ((Button)findViewById(R.id.pop)).setOnClickListener(this);
- ((Button)findViewById(R.id.imap)).setOnClickListener(this);
- final Button exchangeButton = (Button) findViewById(R.id.exchange);
+ UiUtilities.getView(this, R.id.pop).setOnClickListener(this);
+ UiUtilities.getView(this, R.id.imap).setOnClickListener(this);
+ final Button exchangeButton = (Button) UiUtilities.getView(this, R.id.exchange);
exchangeButton.setVisibility(View.INVISIBLE);
- final Button previousButton = (Button) findViewById(R.id.previous);
+ final Button previousButton = (Button) findViewById(R.id.previous); // xlarge only
if (previousButton != null) previousButton.setOnClickListener(this);
// TODO If we decide to exclude the Exchange option in POP_IMAP mode, use the following line
diff --git a/src/com/android/email/activity/setup/AccountSetupBasics.java b/src/com/android/email/activity/setup/AccountSetupBasics.java
index 01bf180..cbaf00a 100644
--- a/src/com/android/email/activity/setup/AccountSetupBasics.java
+++ b/src/com/android/email/activity/setup/AccountSetupBasics.java
@@ -20,6 +20,7 @@
import com.android.email.R;
import com.android.email.VendorPolicyLoader;
import com.android.email.activity.ActivityHelper;
+import com.android.email.activity.UiUtilities;
import com.android.email.activity.Welcome;
import com.android.email.activity.setup.AccountSettingsUtils.Provider;
import com.android.email.mail.Store;
@@ -198,10 +199,10 @@
setContentView(R.layout.account_setup_basics);
- mWelcomeView = (TextView) findViewById(R.id.instructions);
- mEmailView = (EditText) findViewById(R.id.account_email);
- mPasswordView = (EditText) findViewById(R.id.account_password);
- mDefaultView = (CheckBox) findViewById(R.id.account_default);
+ mWelcomeView = (TextView) UiUtilities.getView(this, R.id.instructions);
+ mEmailView = (EditText) UiUtilities.getView(this, R.id.account_email);
+ mPasswordView = (EditText) UiUtilities.getView(this, R.id.account_password);
+ mDefaultView = (CheckBox) UiUtilities.getView(this, R.id.account_default);
mEmailView.addTextChangedListener(this);
mPasswordView.addTextChangedListener(this);
@@ -226,8 +227,8 @@
}
// Configure buttons
- mManualButton = (Button) findViewById(R.id.manual_setup);
- mNextButton = (Button) findViewById(R.id.next);
+ mManualButton = (Button) UiUtilities.getView(this, R.id.manual_setup);
+ mNextButton = (Button) UiUtilities.getView(this, R.id.next);
mManualButton.setVisibility(manualButtonDisplayed ? View.VISIBLE : View.INVISIBLE);
mManualButton.setOnClickListener(this);
mNextButton.setOnClickListener(this);
@@ -418,36 +419,25 @@
private void finishAutoSetup() {
String email = mEmailView.getText().toString().trim();
String password = mPasswordView.getText().toString();
- String[] emailParts = email.split("@");
- String user = emailParts[0];
- String domain = emailParts[1];
try {
- String incomingUsername = mProvider.incomingUsernameTemplate;
- incomingUsername = incomingUsername.replaceAll("\\$email", email);
- incomingUsername = incomingUsername.replaceAll("\\$user", user);
- incomingUsername = incomingUsername.replaceAll("\\$domain", domain);
+ mProvider.expandTemplates(email);
Account account = SetupData.getAccount();
HostAuth recvAuth = account.getOrCreateHostAuthRecv(this);
- Utility.setHostAuthFromString(recvAuth, mProvider.incomingUriTemplate);
- recvAuth.setLogin(incomingUsername, password);
-
- String outgoingUsername = mProvider.outgoingUsernameTemplate;
- outgoingUsername = outgoingUsername.replaceAll("\\$email", email);
- outgoingUsername = outgoingUsername.replaceAll("\\$user", user);
- outgoingUsername = outgoingUsername.replaceAll("\\$domain", domain);
+ Utility.setHostAuthFromString(recvAuth, mProvider.incomingUri);
+ recvAuth.setLogin(mProvider.incomingUsername, password);
HostAuth sendAuth = account.getOrCreateHostAuthSend(this);
- Utility.setHostAuthFromString(sendAuth, mProvider.outgoingUriTemplate);
- sendAuth.setLogin(outgoingUsername, password);
+ Utility.setHostAuthFromString(sendAuth, mProvider.outgoingUri);
+ sendAuth.setLogin(mProvider.outgoingUsername, password);
// Populate the setup data, assuming that the duplicate account check will succeed
populateSetupData(getOwnerName(), email, mDefaultView.isChecked());
// Stop here if the login credentials duplicate an existing account
// Launch an Async task to do the work
- new DuplicateCheckTask(this, recvAuth.mAddress, incomingUsername).execute();
+ new DuplicateCheckTask(this, recvAuth.mAddress, mProvider.incomingUsername).execute();
} catch (URISyntaxException e) {
/*
* If there is some problem with the URI we give up and go on to manual setup.
@@ -665,10 +655,10 @@
@Override
protected void onPostExecute(Integer numAccounts) {
if (numAccounts > 0) {
- Activity activity = AccountSetupBasics.this;
- activity.findViewById(R.id.account_default_divider_1).setVisibility(View.VISIBLE);
- mDefaultView.setVisibility(View.VISIBLE);
- activity.findViewById(R.id.account_default_divider_2).setVisibility(View.VISIBLE);
+ Activity a = AccountSetupBasics.this;
+ UiUtilities.setVisibilitySafe(mDefaultView, View.VISIBLE);
+ UiUtilities.setVisibilitySafe(a, R.id.account_default_divider_1, View.VISIBLE);
+ UiUtilities.setVisibilitySafe(a, R.id.account_default_divider_2, View.VISIBLE);
}
}
}
diff --git a/src/com/android/email/activity/setup/AccountSetupExchange.java b/src/com/android/email/activity/setup/AccountSetupExchange.java
index b3da835..c5d5c83 100644
--- a/src/com/android/email/activity/setup/AccountSetupExchange.java
+++ b/src/com/android/email/activity/setup/AccountSetupExchange.java
@@ -18,6 +18,7 @@
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
+import com.android.email.activity.UiUtilities;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.HostAuth;
@@ -91,9 +92,9 @@
getFragmentManager().findFragmentById(R.id.setup_fragment);
mFragment.setCallback(this);
- mNextButton = (Button) findViewById(R.id.next);
+ mNextButton = (Button) UiUtilities.getView(this, R.id.next);
mNextButton.setOnClickListener(this);
- findViewById(R.id.previous).setOnClickListener(this);
+ UiUtilities.getView(this, R.id.previous).setOnClickListener(this);
// One-shot to launch autodiscovery at the entry to this activity (but not if it restarts)
mStartedAutoDiscovery = false;
diff --git a/src/com/android/email/activity/setup/AccountSetupExchangeFragment.java b/src/com/android/email/activity/setup/AccountSetupExchangeFragment.java
index 86c71b5..08265ed 100644
--- a/src/com/android/email/activity/setup/AccountSetupExchangeFragment.java
+++ b/src/com/android/email/activity/setup/AccountSetupExchangeFragment.java
@@ -20,6 +20,7 @@
import com.android.email.Email;
import com.android.email.ExchangeUtils;
import com.android.email.R;
+import com.android.email.activity.UiUtilities;
import com.android.email.mail.Store;
import com.android.emailcommon.Device;
import com.android.emailcommon.Logging;
@@ -65,7 +66,6 @@
private EditText mServerView;
private CheckBox mSslSecurityView;
private CheckBox mTrustCertificatesView;
- private View mTrustCertificatesDivider;
// Support for lifecycle
private boolean mStarted;
@@ -103,13 +103,13 @@
View view = inflater.inflate(layoutId, container, false);
Context context = getActivity();
- mUsernameView = (EditText) view.findViewById(R.id.account_username);
- mPasswordView = (EditText) view.findViewById(R.id.account_password);
- mServerView = (EditText) view.findViewById(R.id.account_server);
- mSslSecurityView = (CheckBox) view.findViewById(R.id.account_ssl);
+ mUsernameView = (EditText) UiUtilities.getView(view, R.id.account_username);
+ mPasswordView = (EditText) UiUtilities.getView(view, R.id.account_password);
+ mServerView = (EditText) UiUtilities.getView(view, R.id.account_server);
+ mSslSecurityView = (CheckBox) UiUtilities.getView(view, R.id.account_ssl);
mSslSecurityView.setOnCheckedChangeListener(this);
- mTrustCertificatesView = (CheckBox) view.findViewById(R.id.account_trust_certificates);
- mTrustCertificatesDivider = view.findViewById(R.id.account_trust_certificates_divider);
+ mTrustCertificatesView = (CheckBox) UiUtilities.getView(view,
+ R.id.account_trust_certificates);
// Calls validateFields() which enables or disables the Next button
// based on the fields' validity.
@@ -121,16 +121,21 @@
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
public void onTextChanged(CharSequence s, int start, int before, int count) { }
};
+ // We're editing an existing account; don't allow modification of the user name
+ if (mSettingsMode) {
+ makeTextViewUneditable(mUsernameView,
+ getString(R.string.account_setup_username_uneditable_error));
+ }
mUsernameView.addTextChangedListener(validationTextWatcher);
mPasswordView.addTextChangedListener(validationTextWatcher);
mServerView.addTextChangedListener(validationTextWatcher);
-
+ String deviceId = "";
try {
- String deviceId = Device.getDeviceId(context);
- ((TextView) view.findViewById(R.id.device_id)).setText(deviceId);
+ deviceId = Device.getDeviceId(context);
} catch (IOException e) {
// Not required
}
+ ((TextView) UiUtilities.getView(view, R.id.device_id)).setText(deviceId);
// Additional setup only used while in "settings" mode
onCreateViewSettingsMode(view);
@@ -318,10 +323,7 @@
public void showTrustCertificates(boolean visible) {
int mode = visible ? View.VISIBLE : View.GONE;
mTrustCertificatesView.setVisibility(mode);
- // Divider is optional (only on XL layouts)
- if (mTrustCertificatesDivider != null) {
- mTrustCertificatesDivider.setVisibility(mode);
- }
+ UiUtilities.setVisibilitySafe(getView(), R.id.account_trust_certificates_divider, mode);
}
/**
diff --git a/src/com/android/email/activity/setup/AccountSetupIncoming.java b/src/com/android/email/activity/setup/AccountSetupIncoming.java
index f3573a0..080cbdc 100644
--- a/src/com/android/email/activity/setup/AccountSetupIncoming.java
+++ b/src/com/android/email/activity/setup/AccountSetupIncoming.java
@@ -18,6 +18,7 @@
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
+import com.android.email.activity.UiUtilities;
import com.android.emailcommon.provider.EmailContent.Account;
import android.app.Activity;
@@ -59,9 +60,9 @@
// Configure fragment
mFragment.setCallback(this);
- mNextButton = (Button) findViewById(R.id.next);
+ mNextButton = (Button) UiUtilities.getView(this, R.id.next);
mNextButton.setOnClickListener(this);
- findViewById(R.id.previous).setOnClickListener(this);
+ UiUtilities.getView(this, R.id.previous).setOnClickListener(this);
}
/**
diff --git a/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java b/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java
index 0f31085..26c83fa 100644
--- a/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java
+++ b/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java
@@ -19,6 +19,7 @@
import com.android.email.AccountBackupRestore;
import com.android.email.Email;
import com.android.email.R;
+import com.android.email.activity.UiUtilities;
import com.android.email.mail.Store;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.EmailContent.Account;
@@ -110,16 +111,17 @@
View view = inflater.inflate(layoutId, container, false);
Context context = getActivity();
- mUsernameView = (EditText) view.findViewById(R.id.account_username);
- mPasswordView = (EditText) view.findViewById(R.id.account_password);
- mServerLabelView = (TextView) view.findViewById(R.id.account_server_label);
- mServerView = (EditText) view.findViewById(R.id.account_server);
- mPortView = (EditText) view.findViewById(R.id.account_port);
- mSecurityTypeView = (Spinner) view.findViewById(R.id.account_security_type);
- mDeletePolicyLabelView = (TextView) view.findViewById(R.id.account_delete_policy_label);
- mDeletePolicyView = (Spinner) view.findViewById(R.id.account_delete_policy);
- mImapPathPrefixSectionView = view.findViewById(R.id.imap_path_prefix_section);
- mImapPathPrefixView = (EditText) view.findViewById(R.id.imap_path_prefix);
+ mUsernameView = (EditText) UiUtilities.getView(view, R.id.account_username);
+ mPasswordView = (EditText) UiUtilities.getView(view, R.id.account_password);
+ mServerLabelView = (TextView) UiUtilities.getView(view, R.id.account_server_label);
+ mServerView = (EditText) UiUtilities.getView(view, R.id.account_server);
+ mPortView = (EditText) UiUtilities.getView(view, R.id.account_port);
+ mSecurityTypeView = (Spinner) UiUtilities.getView(view, R.id.account_security_type);
+ mDeletePolicyLabelView = (TextView) UiUtilities.getView(view,
+ R.id.account_delete_policy_label);
+ mDeletePolicyView = (Spinner) UiUtilities.getView(view, R.id.account_delete_policy);
+ mImapPathPrefixSectionView = UiUtilities.getView(view, R.id.imap_path_prefix_section);
+ mImapPathPrefixView = (EditText) UiUtilities.getView(view, R.id.imap_path_prefix);
// Set up spinners
SpinnerOption securityTypes[] = {
@@ -172,6 +174,11 @@
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
public void onTextChanged(CharSequence s, int start, int before, int count) { }
};
+ // We're editing an existing account; don't allow modification of the user name
+ if (mSettingsMode) {
+ makeTextViewUneditable(mUsernameView,
+ getString(R.string.account_setup_username_uneditable_error));
+ }
mUsernameView.addTextChangedListener(validationTextWatcher);
mPasswordView.addTextChangedListener(validationTextWatcher);
mServerView.addTextChangedListener(validationTextWatcher);
diff --git a/src/com/android/email/activity/setup/AccountSetupNames.java b/src/com/android/email/activity/setup/AccountSetupNames.java
index f5a25bf..33baad5 100644
--- a/src/com/android/email/activity/setup/AccountSetupNames.java
+++ b/src/com/android/email/activity/setup/AccountSetupNames.java
@@ -19,6 +19,7 @@
import com.android.email.AccountBackupRestore;
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
+import com.android.email.activity.UiUtilities;
import com.android.email.activity.Welcome;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.AccountColumns;
@@ -47,6 +48,7 @@
private EditText mDescription;
private EditText mName;
+ private View mAccountNameLabel;
private Button mNextButton;
private boolean mNextPressed = false;
private boolean mEasAccount = false;
@@ -60,9 +62,10 @@
super.onCreate(savedInstanceState);
ActivityHelper.debugSetWindowFlags(this);
setContentView(R.layout.account_setup_names);
- mDescription = (EditText) findViewById(R.id.account_description);
- mName = (EditText) findViewById(R.id.account_name);
- mNextButton = (Button) findViewById(R.id.next);
+ mDescription = (EditText) UiUtilities.getView(this, R.id.account_description);
+ mName = (EditText) UiUtilities.getView(this, R.id.account_name);
+ mAccountNameLabel = UiUtilities.getView(this, R.id.account_name_label);
+ mNextButton = (Button) UiUtilities.getView(this, R.id.next);
mNextButton.setOnClickListener(this);
TextWatcher validationTextWatcher = new TextWatcher() {
@@ -91,7 +94,7 @@
mEasAccount = "eas".equals(account.mHostAuthRecv.mProtocol);
if (mEasAccount) {
mName.setVisibility(View.GONE);
- findViewById(R.id.account_name_label).setVisibility(View.GONE);
+ mAccountNameLabel.setVisibility(View.GONE);
}
/*
* Since this field is considered optional, we don't set this here. If
diff --git a/src/com/android/email/activity/setup/AccountSetupOptions.java b/src/com/android/email/activity/setup/AccountSetupOptions.java
index 046bdb8..8009856 100644
--- a/src/com/android/email/activity/setup/AccountSetupOptions.java
+++ b/src/com/android/email/activity/setup/AccountSetupOptions.java
@@ -20,6 +20,7 @@
import com.android.email.ExchangeUtils;
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
+import com.android.email.activity.UiUtilities;
import com.android.email.mail.Store;
import com.android.email.service.MailService;
import com.android.emailcommon.Logging;
@@ -63,6 +64,7 @@
private CheckBox mSyncCalendarView;
private CheckBox mSyncEmailView;
private CheckBox mBackgroundAttachmentsView;
+ private View mAccountSyncWindowRow;
private boolean mDonePressed = false;
public static final int REQUEST_CODE_ACCEPT_POLICIES = 1;
@@ -80,18 +82,20 @@
ActivityHelper.debugSetWindowFlags(this);
setContentView(R.layout.account_setup_options);
- mCheckFrequencyView = (Spinner)findViewById(R.id.account_check_frequency);
- mSyncWindowView = (Spinner) findViewById(R.id.account_sync_window);
- mDefaultView = (CheckBox)findViewById(R.id.account_default);
- mNotifyView = (CheckBox)findViewById(R.id.account_notify);
- mSyncContactsView = (CheckBox) findViewById(R.id.account_sync_contacts);
- mSyncCalendarView = (CheckBox) findViewById(R.id.account_sync_calendar);
- mSyncEmailView = (CheckBox) findViewById(R.id.account_sync_email);
+ mCheckFrequencyView = (Spinner) UiUtilities.getView(this, R.id.account_check_frequency);
+ mSyncWindowView = (Spinner) UiUtilities.getView(this, R.id.account_sync_window);
+ mDefaultView = (CheckBox) UiUtilities.getView(this, R.id.account_default);
+ mNotifyView = (CheckBox) UiUtilities.getView(this, R.id.account_notify);
+ mSyncContactsView = (CheckBox) UiUtilities.getView(this, R.id.account_sync_contacts);
+ mSyncCalendarView = (CheckBox) UiUtilities.getView(this, R.id.account_sync_calendar);
+ mSyncEmailView = (CheckBox) UiUtilities.getView(this, R.id.account_sync_email);
mSyncEmailView.setChecked(true);
- mBackgroundAttachmentsView = (CheckBox) findViewById(R.id.account_background_attachments);
+ mBackgroundAttachmentsView = (CheckBox) UiUtilities.getView(this,
+ R.id.account_background_attachments);
mBackgroundAttachmentsView.setChecked(true);
- findViewById(R.id.previous).setOnClickListener(this);
- findViewById(R.id.next).setOnClickListener(this);
+ UiUtilities.getView(this, R.id.previous).setOnClickListener(this);
+ UiUtilities.getView(this, R.id.next).setOnClickListener(this);
+ mAccountSyncWindowRow = UiUtilities.getView(this, R.id.account_sync_window_row);
// Generate spinner entries using XML arrays used by the preferences
int frequencyValuesId;
@@ -142,14 +146,15 @@
mSyncCalendarView.setVisibility(View.VISIBLE);
mSyncCalendarView.setChecked(true);
// Show the associated dividers
- findViewById(R.id.account_sync_contacts_divider).setVisibility(View.VISIBLE);
- findViewById(R.id.account_sync_calendar_divider).setVisibility(View.VISIBLE);
+ UiUtilities.setVisibilitySafe(this, R.id.account_sync_contacts_divider, View.VISIBLE);
+ UiUtilities.setVisibilitySafe(this, R.id.account_sync_calendar_divider, View.VISIBLE);
}
// If we are in POP3, hide the "Background Attachments" mode
if ("pop3".equals(info.mScheme)) {
mBackgroundAttachmentsView.setVisibility(View.GONE);
- findViewById(R.id.account_background_attachments_divider).setVisibility(View.GONE);
+ UiUtilities.setVisibilitySafe(this, R.id.account_background_attachments_divider,
+ View.GONE);
}
// If we are just visiting here to fill in details, exit immediately
@@ -213,7 +218,7 @@
account.setFlags(newFlags);
account.setSyncInterval((Integer)((SpinnerOption)mCheckFrequencyView
.getSelectedItem()).value);
- if (findViewById(R.id.account_sync_window_row).getVisibility() == View.VISIBLE) {
+ if (mAccountSyncWindowRow.getVisibility() == View.VISIBLE) {
int window = (Integer)((SpinnerOption)mSyncWindowView.getSelectedItem()).value;
account.setSyncLookback(window);
}
@@ -373,7 +378,7 @@
*/
private void enableEASSyncWindowSpinner() {
// Show everything
- findViewById(R.id.account_sync_window_row).setVisibility(View.VISIBLE);
+ mAccountSyncWindowRow.setVisibility(View.VISIBLE);
// Generate spinner entries using XML arrays used by the preferences
CharSequence[] windowValues = getResources().getTextArray(
diff --git a/src/com/android/email/activity/setup/AccountSetupOutgoing.java b/src/com/android/email/activity/setup/AccountSetupOutgoing.java
index d28a7cc..e542c18 100644
--- a/src/com/android/email/activity/setup/AccountSetupOutgoing.java
+++ b/src/com/android/email/activity/setup/AccountSetupOutgoing.java
@@ -18,6 +18,7 @@
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
+import com.android.email.activity.UiUtilities;
import com.android.emailcommon.provider.EmailContent.Account;
import android.app.Activity;
@@ -59,9 +60,9 @@
// Configure fragment
mFragment.setCallback(this);
- mNextButton = (Button) findViewById(R.id.next);
+ mNextButton = (Button) UiUtilities.getView(this, R.id.next);
mNextButton.setOnClickListener(this);
- findViewById(R.id.previous).setOnClickListener(this);
+ UiUtilities.getView(this, R.id.previous).setOnClickListener(this);
}
/**
diff --git a/src/com/android/email/activity/setup/AccountSetupOutgoingFragment.java b/src/com/android/email/activity/setup/AccountSetupOutgoingFragment.java
index 65e3888..d01e100 100644
--- a/src/com/android/email/activity/setup/AccountSetupOutgoingFragment.java
+++ b/src/com/android/email/activity/setup/AccountSetupOutgoingFragment.java
@@ -19,6 +19,7 @@
import com.android.email.AccountBackupRestore;
import com.android.email.Email;
import com.android.email.R;
+import com.android.email.activity.UiUtilities;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Account;
@@ -65,8 +66,6 @@
private EditText mServerView;
private EditText mPortView;
private CheckBox mRequireLoginView;
- private View mRequireLoginSettingsView;
- private View mRequireLoginSettingsView2;
private Spinner mSecurityTypeView;
// Support for lifecycle
@@ -103,14 +102,12 @@
View view = inflater.inflate(layoutId, container, false);
Context context = getActivity();
- mUsernameView = (EditText) view.findViewById(R.id.account_username);
- mPasswordView = (EditText) view.findViewById(R.id.account_password);
- mServerView = (EditText) view.findViewById(R.id.account_server);
- mPortView = (EditText) view.findViewById(R.id.account_port);
- mRequireLoginView = (CheckBox) view.findViewById(R.id.account_require_login);
- mRequireLoginSettingsView = view.findViewById(R.id.account_require_login_settings);
- mRequireLoginSettingsView2 = view.findViewById(R.id.account_require_login_settings_2);
- mSecurityTypeView = (Spinner) view.findViewById(R.id.account_security_type);
+ mUsernameView = (EditText) UiUtilities.getView(view, R.id.account_username);
+ mPasswordView = (EditText) UiUtilities.getView(view, R.id.account_password);
+ mServerView = (EditText) UiUtilities.getView(view, R.id.account_server);
+ mPortView = (EditText) UiUtilities.getView(view, R.id.account_port);
+ mRequireLoginView = (CheckBox) UiUtilities.getView(view, R.id.account_require_login);
+ mSecurityTypeView = (Spinner) UiUtilities.getView(view, R.id.account_security_type);
mRequireLoginView.setOnCheckedChangeListener(this);
// Note: Strings are shared with AccountSetupIncomingFragment
@@ -321,10 +318,9 @@
*/
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- mRequireLoginSettingsView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
- if (mRequireLoginSettingsView2 != null) {
- mRequireLoginSettingsView2.setVisibility(isChecked ? View.VISIBLE : View.GONE);
- }
+ final int visibility = isChecked ? View.VISIBLE : View.GONE;
+ UiUtilities.setVisibilitySafe(getView(), R.id.account_require_login_settings, visibility);
+ UiUtilities.setVisibilitySafe(getView(), R.id.account_require_login_settings_2, visibility);
validateFields();
}
diff --git a/src/com/android/email/activity/setup/DebugFragment.java b/src/com/android/email/activity/setup/DebugFragment.java
index 44bde9b..ab6f3f0 100644
--- a/src/com/android/email/activity/setup/DebugFragment.java
+++ b/src/com/android/email/activity/setup/DebugFragment.java
@@ -20,6 +20,7 @@
import com.android.email.ExchangeUtils;
import com.android.email.Preferences;
import com.android.email.R;
+import com.android.email.activity.UiUtilities;
import com.android.email.service.MailService;
import com.android.emailcommon.Logging;
@@ -59,16 +60,16 @@
Context context = getActivity();
mPreferences = Preferences.getPreferences(context);
- mVersionView = (TextView) view.findViewById(R.id.version);
+ mVersionView = (TextView) UiUtilities.getView(view, R.id.version);
mVersionView.setText(String.format(context.getString(R.string.debug_version_fmt).toString(),
context.getString(R.string.build_number)));
- mEnableDebugLoggingView = (CheckBox) view.findViewById(R.id.debug_logging);
+ mEnableDebugLoggingView = (CheckBox) UiUtilities.getView(view, R.id.debug_logging);
mEnableDebugLoggingView.setChecked(Email.DEBUG);
- mEnableExchangeLoggingView = (CheckBox) view.findViewById(R.id.exchange_logging);
+ mEnableExchangeLoggingView = (CheckBox) UiUtilities.getView(view, R.id.exchange_logging);
mEnableExchangeFileLoggingView =
- (CheckBox) view.findViewById(R.id.exchange_file_logging);
+ (CheckBox) UiUtilities.getView(view, R.id.exchange_file_logging);
// Note: To prevent recursion while presetting checkboxes, assign all listeners last
mEnableDebugLoggingView.setOnCheckedChangeListener(this);
@@ -84,20 +85,20 @@
mEnableExchangeFileLoggingView.setVisibility(View.GONE);
}
- view.findViewById(R.id.clear_webview_cache).setOnClickListener(this);
+ UiUtilities.getView(view, R.id.clear_webview_cache).setOnClickListener(this);
mInhibitGraphicsAccelerationView = (CheckBox)
- view.findViewById(R.id.debug_disable_graphics_acceleration);
+ UiUtilities.getView(view, R.id.debug_disable_graphics_acceleration);
mInhibitGraphicsAccelerationView.setChecked(Email.sDebugInhibitGraphicsAcceleration);
mInhibitGraphicsAccelerationView.setOnCheckedChangeListener(this);
mForceOneMinuteRefreshView = (CheckBox)
- view.findViewById(R.id.debug_force_one_minute_refresh);
+ UiUtilities.getView(view, R.id.debug_force_one_minute_refresh);
mForceOneMinuteRefreshView.setChecked(mPreferences.getForceOneMinuteRefresh());
mForceOneMinuteRefreshView.setOnCheckedChangeListener(this);
mEnableStrictModeView = (CheckBox)
- view.findViewById(R.id.debug_enable_strict_mode);
+ UiUtilities.getView(view, R.id.debug_enable_strict_mode);
mEnableStrictModeView.setChecked(mPreferences.getEnableStrictMode());
mEnableStrictModeView.setOnCheckedChangeListener(this);
diff --git a/src/com/android/email/widget/EmailWidget.java b/src/com/android/email/widget/EmailWidget.java
index 11d1034..874367b 100644
--- a/src/com/android/email/widget/EmailWidget.java
+++ b/src/com/android/email/widget/EmailWidget.java
@@ -19,8 +19,8 @@
import com.android.email.Email;
import com.android.email.R;
import com.android.email.ResourceHelper;
-import com.android.email.UiUtilities;
import com.android.email.activity.MessageCompose;
+import com.android.email.activity.UiUtilities;
import com.android.email.activity.Welcome;
import com.android.email.provider.WidgetProvider.WidgetService;
import com.android.emailcommon.provider.EmailContent.Mailbox;
@@ -575,4 +575,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/res/xml/test_providers.xml b/tests/res/xml/test_providers.xml
new file mode 100644
index 0000000..2ed04ff
--- /dev/null
+++ b/tests/res/xml/test_providers.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+ <!--
+ This file contains email provider configuration for testing purposes. The complete
+ format specification for this file can be found in res/xml/providers.xml.
+ -->
+
+<providers>
+
+ <!-- Gmail variants -->
+ <provider id="gmail" label="Gmail" domain="gmail.com">
+ <incoming uri="imap+ssl+://imap.gmail.com" username="$email" />
+ <outgoing uri="smtp+ssl+://smtp.gmail.com" username="$email" />
+ </provider>
+
+ <!-- Yahoo! Mail variants -->
+ <provider id="generic" label="Generic Y!" domain="mail*yahoo.com">
+ <incoming uri="pop3://pop-server.$domain" username="$email" />
+ <outgoing uri="smtp://smtp-server.foo.com" username="$email" />
+ </provider>
+ <provider id="yahoo" label="Yahoo!" domain="yahoo.com">
+ <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
+ <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
+ </provider>
+ <provider id="yahoo" label="Yahoo!" domain="yahoo.com.yahoo.com">
+ <incoming uri="imap+ssl+://android.imap.mail.yahoo.com" username="$email" />
+ <outgoing uri="smtp+ssl+://android.smtp.mail.yahoo.com" username="$email" />
+ </provider>
+
+ <!-- Roadrunner variants -->
+ <provider id="rr-roadrunner" label="RoadRunner" domain="roadrunner.com">
+ <incoming uri="pop3://pop-server.roadrunner.com" username="$email" />
+ <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
+ </provider>
+ <provider id="rr-global" label="RoadRunner" domain="leonard.rr.com">
+ <incoming uri="pop3://pop-server.firstonewins.com" username="$email" />
+ <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
+ </provider>
+ <provider id="rr-global" label="RoadRunner" domain="*.rr.???">
+ <incoming uri="pop3://pop-server.$domain" username="$email" />
+ <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
+ </provider>
+
+ <!-- USA (other)-->
+ <provider id="tuffmail" label="Tuffmail" domain="tuffmail.com">
+ <incoming uri="imap+ssl+://mail.mxes.net" username="$user_$domain" />
+ <outgoing uri="smtp+ssl+://smtp.mxes.net" username="$user_$domain" />
+ </provider>
+
+</providers>
diff --git a/tests/src/com/android/email/activity/UiUtilitiesTests.java b/tests/src/com/android/email/activity/UiUtilitiesTests.java
new file mode 100644
index 0000000..00737cc
--- /dev/null
+++ b/tests/src/com/android/email/activity/UiUtilitiesTests.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.email.activity;
+
+import com.android.email.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.view.View;
+
+import java.util.Locale;
+
+public class UiUtilitiesTests extends AndroidTestCase {
+ public void testFormatSize() {
+ if (!"en".equalsIgnoreCase(Locale.getDefault().getLanguage())) {
+ return; // Only works on the EN locale.
+ }
+ assertEquals("0B", UiUtilities.formatSize(getContext(), 0));
+ assertEquals("1B", UiUtilities.formatSize(getContext(), 1));
+ assertEquals("1023B", UiUtilities.formatSize(getContext(), 1023));
+ assertEquals("1KB", UiUtilities.formatSize(getContext(), 1024));
+ assertEquals("1023KB", UiUtilities.formatSize(getContext(), 1024 * 1024 - 1));
+ assertEquals("1MB", UiUtilities.formatSize(getContext(), 1024 * 1024));
+ assertEquals("1023MB", UiUtilities.formatSize(getContext(), 1024 * 1024 * 1024 - 1));
+ assertEquals("1GB", UiUtilities.formatSize(getContext(), 1024 * 1024 * 1024));
+ assertEquals("5GB", UiUtilities.formatSize(getContext(), 5L * 1024 * 1024 * 1024));
+ }
+
+ public void testGetMessageCountForUi() {
+ final Context c = getContext();
+
+ // Negavive valeus not really expected, but at least shouldn't crash.
+ assertEquals("-1", UiUtilities.getMessageCountForUi(c, -1, true));
+ assertEquals("-1", UiUtilities.getMessageCountForUi(c, -1, false));
+
+ assertEquals("", UiUtilities.getMessageCountForUi(c, 0, true));
+ assertEquals("0", UiUtilities.getMessageCountForUi(c, 0, false));
+
+ assertEquals("1", UiUtilities.getMessageCountForUi(c, 1, true));
+ assertEquals("1", UiUtilities.getMessageCountForUi(c, 1, false));
+
+ assertEquals("999", UiUtilities.getMessageCountForUi(c, 999, true));
+ assertEquals("999", UiUtilities.getMessageCountForUi(c, 999, false));
+
+ final String moreThan999 = c.getString(R.string.more_than_999);
+
+ assertEquals(moreThan999, UiUtilities.getMessageCountForUi(c, 1000, true));
+ assertEquals(moreThan999, UiUtilities.getMessageCountForUi(c, 1000, false));
+
+ assertEquals(moreThan999, UiUtilities.getMessageCountForUi(c, 1001, true));
+ assertEquals(moreThan999, UiUtilities.getMessageCountForUi(c, 1001, false));
+ }
+
+ public void testGetView() {
+ // Test for getView(Activity, int)
+ DummyActivity a = new DummyActivity();
+ DummyView v = new DummyView(getContext());
+
+ a.mDummyViewId = 10;
+ a.mDummyView = v;
+ assertEquals(v, UiUtilities.getView(a, 10));
+
+ try {
+ assertEquals(v, UiUtilities.getView(a, 11));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // TODO Test for getView(View, int)?
+ // Unfortunately View.findViewById is final, so can't use the same approach.
+ // Also it's a huge pain to set up an actual, nested views in unit tests, so let's leave
+ // it for now.
+ }
+
+ public void testSetVisibilitySafe() {
+ {
+ DummyView v = new DummyView(getContext());
+ UiUtilities.setVisibilitySafe(v, View.VISIBLE);
+ assertEquals(View.VISIBLE, v.mVisibility);
+
+ // Shouldn't crash
+ UiUtilities.setVisibilitySafe(null, View.VISIBLE);
+ }
+
+ {
+ DummyActivity a = new DummyActivity();
+ DummyView v = new DummyView(getContext());
+ a.mDummyViewId = 3;
+ a.mDummyView = v;
+
+ UiUtilities.setVisibilitySafe(a, 3, View.VISIBLE);
+ assertEquals(View.VISIBLE, v.mVisibility);
+
+ // shouldn't crash
+ UiUtilities.setVisibilitySafe(a, 5, View.VISIBLE);
+ }
+ // No test for setVisibilitySafe(View, int, int) -- see testGetView().
+ }
+
+ private static class DummyActivity extends Activity {
+ public int mDummyViewId;
+ public View mDummyView;
+
+ @Override
+ public View findViewById(int id) {
+ return (id == mDummyViewId) ? mDummyView : null;
+ }
+ }
+
+ private static class DummyView extends View {
+ public int mVisibility = View.GONE;
+
+ public DummyView(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ mVisibility = visibility;
+ }
+ }
+}
diff --git a/tests/src/com/android/email/activity/setup/AccountSettingsUtilsTests.java b/tests/src/com/android/email/activity/setup/AccountSettingsUtilsTests.java
index 90282b3..583ec78 100644
--- a/tests/src/com/android/email/activity/setup/AccountSettingsUtilsTests.java
+++ b/tests/src/com/android/email/activity/setup/AccountSettingsUtilsTests.java
@@ -16,6 +16,10 @@
package com.android.email.activity.setup;
+import com.android.email.tests.R;
+import com.android.email.activity.setup.AccountSettingsUtils.Provider;
+
+import android.content.Context;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -28,6 +32,14 @@
@SmallTest
public class AccountSettingsUtilsTests extends AndroidTestCase {
+ private Context mTestContext;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mTestContext = getTestContext();
+ }
+
/**
* Test server name inferences
*
@@ -51,4 +63,185 @@
assertEquals("MaiL.y.z", AccountSettingsUtils.inferServerName("MaiL.y.z", null, "bar"));
}
+ public void testFindProviderForDomain() {
+ Provider testProvider;
+ // <provider id="gmail" label="Gmail" domain="gmail.com">
+ // <incoming uri="imap+ssl+://imap.gmail.com" username="$email" />
+ // <outgoing uri="smtp+ssl+://smtp.gmail.com" username="$email" />
+ // </provider>
+ testProvider = AccountSettingsUtils.findProviderForDomain(
+ mTestContext, "gmail.com", R.xml.test_providers);
+ assertNotNull(testProvider);
+ assertEquals("imap+ssl+://imap.gmail.com", testProvider.incomingUriTemplate);
+ assertEquals("smtp+ssl+://smtp.gmail.com", testProvider.outgoingUriTemplate);
+ assertEquals("gmail.com", testProvider.domain);
+
+ // <provider id="rr-generic" label="RoadRunner" domain="*.rr.com">
+ // <incoming uri="pop3://pop-server.$domain" username="$email" />
+ // <outgoing uri="smtp://mobile-smtp.roadrunner.com" username="$email" />
+ // </provider>
+ testProvider = AccountSettingsUtils.findProviderForDomain(
+ mTestContext, "elmore.rr.com", R.xml.test_providers);
+ assertNotNull(testProvider);
+ assertEquals("pop3://pop-server.$domain", testProvider.incomingUriTemplate);
+ assertEquals("smtp://mobile-smtp.roadrunner.com", testProvider.outgoingUriTemplate);
+ assertEquals("elmore.rr.com", testProvider.domain);
+
+ // Domain matches 2 providers; first one wins
+ testProvider = AccountSettingsUtils.findProviderForDomain(
+ mTestContext, "leonard.rr.com", R.xml.test_providers);
+ assertNotNull(testProvider);
+ assertEquals("pop3://pop-server.firstonewins.com", testProvider.incomingUriTemplate);
+
+ // Domains that don't exist
+ testProvider = AccountSettingsUtils.findProviderForDomain(
+ mTestContext, "nonexist.com", R.xml.test_providers);
+ assertNull(testProvider);
+ }
+
+ public void testGlobEndsWithIgnoreCase() {
+ assertTrue(AccountSettingsUtils.wildEndsWithIgnoreCase(
+ "yahoo.com.tw", ".??"));
+ assertTrue(AccountSettingsUtils.wildEndsWithIgnoreCase(
+ "abcd", "a??d"));
+ assertFalse(AccountSettingsUtils.wildEndsWithIgnoreCase(
+ "yahoo.com.tw.foo.com", ".??"));
+ assertFalse(AccountSettingsUtils.wildEndsWithIgnoreCase(
+ "abc", "a??d"));
+ }
+
+ public void testGlobStartsWithIgnoreCase() {
+ assertTrue(AccountSettingsUtils.wildStartsWithIgnoreCase(
+ "tw.yahoo.com", "??."));
+ assertTrue(AccountSettingsUtils.wildStartsWithIgnoreCase(
+ "abcdxyz", "a??d"));
+ assertFalse(AccountSettingsUtils.wildStartsWithIgnoreCase(
+ "abc", "a??d"));
+ }
+
+ public void testGlobEqualsIgnoreCase() {
+ assertTrue(AccountSettingsUtils.wildEqualsIgnoreCase(
+ "tw.yahoo.com", "??.yahoo.com"));
+ assertTrue(AccountSettingsUtils.wildEqualsIgnoreCase(
+ "yahoo.com.tw", "yahoo.com.??"));
+ assertTrue(AccountSettingsUtils.wildEqualsIgnoreCase(
+ "abcdxyz", "a??dxyz"));
+ assertFalse(AccountSettingsUtils.wildEqualsIgnoreCase(
+ "abc", "a??d"));
+ assertFalse(AccountSettingsUtils.wildEqualsIgnoreCase(
+ "abccxyz", "a??d"));
+ }
+
+ public void testGlobMatchIgnoreCase() {
+ assertTrue(AccountSettingsUtils.globMatchIgnoreCase(
+ "mail.yahoo.com", "mail*yahoo.com"));
+ assertTrue(AccountSettingsUtils.globMatchIgnoreCase(
+ "mail.foo.bar.yahoo.com", "mail*yahoo.com"));
+ assertTrue(AccountSettingsUtils.globMatchIgnoreCase(
+ "mail.notwhatyouwant.myyahoo.com", "mail*yahoo.com"));
+
+ // Test other combinations
+ assertTrue(AccountSettingsUtils.globMatchIgnoreCase(
+ "yahoo.com", "yahoo.com"));
+ assertFalse(AccountSettingsUtils.globMatchIgnoreCase(
+ "yahoo.com.au", "yahoo.com"));
+ assertFalse(AccountSettingsUtils.globMatchIgnoreCase(
+ "yahoo.com", "yahoo.com.au"));
+
+ // Try mixed case in the domain name
+ assertTrue(AccountSettingsUtils.globMatchIgnoreCase(
+ "GmAiL.cOm", "gMaIl.CoM"));
+
+ assertFalse(AccountSettingsUtils.globMatchIgnoreCase(
+ "nonexist.frr.com", "*.rr.com"));
+ assertFalse(AccountSettingsUtils.globMatchIgnoreCase(
+ "rr.com", "*.rr.com"));
+ assertTrue(AccountSettingsUtils.globMatchIgnoreCase(
+ "abbc.com", "ab*bc.com"));
+ assertFalse(AccountSettingsUtils.globMatchIgnoreCase(
+ "abc.com", "ab*bc.com"));
+
+ try {
+ AccountSettingsUtils.globMatchIgnoreCase(
+ "abc.com", "ab*bc*.com");
+ fail("Should have thrown an IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ AccountSettingsUtils.globMatchIgnoreCase(
+ null, "ab*bc*.com");
+ fail("Should have thrown an IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ AccountSettingsUtils.globMatchIgnoreCase(
+ "abc.com", null);
+ fail("Should have thrown an IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ public void testExpandTemplates() {
+ Provider testProvider;
+ // <provider id="cox" label="Cox" domain="cox.net">
+ // <incoming uri="pop3+ssl+://pop.east.cox.net" username="$user" />
+ // <outgoing uri="smtp+ssl+://smtp.east.cox.net" username="$user" />
+ // </provider>
+ testProvider = new Provider();
+ testProvider.domain = "cox.net";
+ testProvider.incomingUriTemplate = "pop3+ssl+://pop.east.$domain";
+ testProvider.outgoingUriTemplate = "smtp+ssl+://smtp.east.$domain";
+ testProvider.incomingUsernameTemplate = "$user";
+ testProvider.outgoingUsernameTemplate = "$user";
+ testProvider.expandTemplates("replUser@cox.net");
+ assertEquals("replUser", testProvider.incomingUsername);
+ assertEquals("replUser", testProvider.outgoingUsername);
+ assertEquals("pop3+ssl+://pop.east.cox.net", testProvider.incomingUri);
+ assertEquals("smtp+ssl+://smtp.east.cox.net", testProvider.outgoingUri);
+
+ // <provider id="earthlink" label="Earthlink" domain="earthlink.net">
+ // <incoming uri="pop3://pop.earthlink.net" username="$email" />
+ // <outgoing uri="smtp://smtpauth.earthlink.net:587" username="$email" />
+ // </provider>
+ testProvider = new Provider();
+ testProvider.domain = "earthlink.net";
+ testProvider.incomingUriTemplate = "pop3://pop.earthlink.net";
+ testProvider.outgoingUriTemplate = "smtp://smtpauth.earthlink.net:587";
+ testProvider.incomingUsernameTemplate = "$email";
+ testProvider.outgoingUsernameTemplate = "$email";
+ testProvider.expandTemplates("replUser@earthlink.net");
+ assertEquals("replUser@earthlink.net", testProvider.incomingUsername);
+ assertEquals("replUser@earthlink.net", testProvider.outgoingUsername);
+ assertEquals("pop3://pop.earthlink.net", testProvider.incomingUri);
+ assertEquals("smtp://smtpauth.earthlink.net:587", testProvider.outgoingUri);
+
+ // <provider id="tuffmail" label="Tuffmail" domain="tuffmail.com">
+ // <incoming uri="imap+ssl+://mail.mxes.net" username="$user_$domain" />
+ // <outgoing uri="smtp+ssl+://smtp.mxes.net" username="$user_$domain" />
+ // </provider>
+ testProvider = new Provider();
+ testProvider.domain = "tuffmail.com";
+ testProvider.incomingUriTemplate = "imap+ssl+://mail.mxes.net";
+ testProvider.outgoingUriTemplate = "smtp+ssl+://smtp.mxes.net";
+ testProvider.incomingUsernameTemplate = "$user_$domain";
+ testProvider.outgoingUsernameTemplate = "$user_$domain";
+ testProvider.expandTemplates("replUser@tuffmail.com");
+ assertEquals("replUser_tuffmail.com", testProvider.incomingUsername);
+ assertEquals("replUser_tuffmail.com", testProvider.outgoingUsername);
+ assertEquals("imap+ssl+://mail.mxes.net", testProvider.incomingUri);
+ assertEquals("smtp+ssl+://smtp.mxes.net", testProvider.outgoingUri);
+
+ // Everything hardcoded; not effective in the wild
+ testProvider = new Provider();
+ testProvider.domain = "yahoo.com";
+ testProvider.incomingUriTemplate = "imap+ssl+://pop.yahoo.com";
+ testProvider.outgoingUriTemplate = "smtp+ssl+://smtp.yahoo.com";
+ testProvider.incomingUsernameTemplate = "joe_smith";
+ testProvider.outgoingUsernameTemplate = "joe_smith";
+ testProvider.expandTemplates("replUser@yahoo.com");
+ assertEquals("joe_smith", testProvider.incomingUsername);
+ assertEquals("joe_smith", testProvider.outgoingUsername);
+ assertEquals("imap+ssl+://pop.yahoo.com", testProvider.incomingUri);
+ assertEquals("smtp+ssl+://smtp.yahoo.com", testProvider.outgoingUri);
+ }
}
diff --git a/tests/src/com/android/email/provider/ProviderTests.java b/tests/src/com/android/email/provider/ProviderTests.java
index 048d840..4b91d7f 100644
--- a/tests/src/com/android/email/provider/ProviderTests.java
+++ b/tests/src/com/android/email/provider/ProviderTests.java
@@ -16,7 +16,6 @@
package com.android.email.provider;
-import com.android.emailcommon.mail.Snippet;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.AccountColumns;
@@ -29,6 +28,7 @@
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
import com.android.emailcommon.provider.EmailContent.Message;
import com.android.emailcommon.provider.EmailContent.MessageColumns;
+import com.android.emailcommon.utility.TextUtilities;
import com.android.emailcommon.utility.Utility;
import android.content.ContentResolver;
@@ -46,7 +46,6 @@
import java.io.File;
import java.io.IOException;
-import java.net.URISyntaxException;
import java.util.ArrayList;
/**
@@ -504,7 +503,8 @@
message.save(mMockContext);
Message restoredMessage = Message.restoreMessageWithId(mMockContext, message.mId);
// We should have the plain text as the snippet
- assertEquals(restoredMessage.mSnippet, Snippet.fromPlainText(message.mText));
+ assertEquals(restoredMessage.mSnippet,
+ TextUtilities.makeSnippetFromPlainText(message.mText));
// Start again
message = ProviderTestUtils.setupMessage("message", account.mId, box.mId, false,
@@ -514,7 +514,8 @@
message.save(mMockContext);
restoredMessage = Message.restoreMessageWithId(mMockContext, message.mId);
// We should have the plain text as the snippet
- assertEquals(restoredMessage.mSnippet, Snippet.fromHtmlText(message.mHtml));
+ assertEquals(restoredMessage.mSnippet,
+ TextUtilities.makeSnippetFromHtmlText(message.mHtml));
}
/**
diff --git a/tests/src/com/android/emailcommon/mail/SnippetTests.java b/tests/src/com/android/emailcommon/mail/SnippetTests.java
deleted file mode 100644
index 8cee45b..0000000
--- a/tests/src/com/android/emailcommon/mail/SnippetTests.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2010 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 series of unit tests for snippet creation
- *
- * You can run this entire test case with:
- * runtest -c com.android.email.SnippetTests email
- */
-package com.android.emailcommon.mail;
-
-import com.android.emailcommon.mail.Snippet;
-
-import android.test.AndroidTestCase;
-
-/**
- * Tests of Snippet
- *
- * You can run this entire test case with:
- * runtest -c com.android.email.SnippetTests email
- */
-public class SnippetTests extends AndroidTestCase {
-
- public void testPlainSnippet() {
- // Test the simplest cases
- assertEquals("", Snippet.fromPlainText(null));
- assertEquals("", Snippet.fromPlainText(""));
-
- // Test handling leading, trailing, and duplicated whitespace
- // Just test common whitespace characters; we calls Character.isWhitespace() internally, so
- // other whitespace should be fine as well
- assertEquals("", Snippet.fromPlainText(" \n\r\t\r\t\n"));
- char c = Snippet.NON_BREAKING_SPACE_CHARACTER;
- assertEquals("foo", Snippet.fromPlainText(c + "\r\n\tfoo \n\t\r" + c));
- assertEquals("foo bar", Snippet.fromPlainText(c + "\r\n\tfoo \r\n bar\n\t\r" + c));
-
- // Handle duplicated - and =
- assertEquals("Foo-Bar=Bletch", Snippet.fromPlainText("Foo-----Bar=======Bletch"));
-
- // We shouldn't muck with HTML entities
- assertEquals(" >", Snippet.fromPlainText(" >"));
- }
-
- public void testHtmlSnippet() {
- // Test the simplest cases
- assertEquals("", Snippet.fromHtmlText(null));
- assertEquals("", Snippet.fromHtmlText(""));
-
- // Test handling leading, trailing, and duplicated whitespace
- // Just test common whitespace characters; we calls Character.isWhitespace() internally, so
- // other whitespace should be fine as well
- assertEquals("", Snippet.fromHtmlText(" \n\r\t\r\t\n"));
- char c = Snippet.NON_BREAKING_SPACE_CHARACTER;
- assertEquals("foo", Snippet.fromHtmlText(c + "\r\n\tfoo \n\t\r" + c));
- assertEquals("foo bar", Snippet.fromHtmlText(c + "\r\n\tfoo \r\n bar\n\t\r" + c));
-
- // Handle duplicated - and =
- assertEquals("Foo-Bar=Bletch", Snippet.fromPlainText("Foo-----Bar=======Bletch"));
-
- // We should catch HTML entities in these tests
- assertEquals(">", Snippet.fromHtmlText(" >"));
- assertEquals("&<> \"", Snippet.fromHtmlText("&<> ""));
- // Test for decimal and hex entities
- assertEquals("ABC", Snippet.fromHtmlText("ABC"));
- assertEquals("ABC", Snippet.fromHtmlText("ABC"));
-
- // Test for stripping simple tags
- assertEquals("Hi there", Snippet.fromHtmlText("<html>Hi there</html>"));
- // TODO: Add tests here if/when we find problematic HTML
- }
-
- public void testStripHtmlEntityEdgeCases() {
- int[] skipCount = new int[1];
- // Bare & isn't an entity
- char c = Snippet.stripHtmlEntity("&", 0, skipCount);
- assertEquals(c, '&');
- assertEquals(0, skipCount[0]);
- // Also not legal
- c = Snippet.stripHtmlEntity("&;", 0, skipCount);
- assertEquals(c, '&');
- assertEquals(0, skipCount[0]);
- // This is an entity, but shouldn't be found
- c = Snippet.stripHtmlEntity("&nosuch;", 0, skipCount);
- assertEquals(c, '&');
- assertEquals(0, skipCount[0]);
- // This is too long for an entity, even though it starts like a valid one
- c = Snippet.stripHtmlEntity(" andmore;", 0, skipCount);
- assertEquals(c, '&');
- assertEquals(0, skipCount[0]);
- // Illegal decimal entities
- c = Snippet.stripHtmlEntity("&#ABC", 0, skipCount);
- assertEquals(c, '&');
- assertEquals(0, skipCount[0]);
- c = Snippet.stripHtmlEntity("B", 0, skipCount);
- assertEquals(c, '&');
- assertEquals(0, skipCount[0]);
- // Illegal hex entities
- c = Snippet.stripHtmlEntity("઼", 0, skipCount);
- assertEquals(c, '&');
- assertEquals(0, skipCount[0]);
- // Illegal hex entities
- c = Snippet.stripHtmlEntity("G", 0, skipCount);
- assertEquals(c, '&');
- assertEquals(0, skipCount[0]);
- }
-
- public void testStripContent() {
- assertEquals("Visible", Snippet.fromHtmlText(
- "<html><style foo=\"bar\">Not</style>Visible</html>"));
- assertEquals("Visible", Snippet.fromHtmlText(
- "<html><STYLE foo=\"bar\">Not</STYLE>Visible</html>"));
- assertEquals("IsVisible", Snippet.fromHtmlText(
- "<html><nostrip foo=\"bar\">Is</nostrip>Visible</html>"));
- assertEquals("Visible", Snippet.fromHtmlText(
- "<html>Visible<style foo=\"bar\">Not"));
- assertEquals("VisibleAgainVisible", Snippet.fromHtmlText(
- "<html>Visible<style foo=\"bar\">Not</style>AgainVisible"));
- assertEquals("VisibleAgainVisible", Snippet.fromHtmlText(
- "<html>Visible<style foo=\"bar\"/>AgainVisible"));
- assertEquals("VisibleAgainVisible", Snippet.fromHtmlText(
- "<html>Visible<style foo=\"bar\"/><head><//blah<style>Not</head>AgainVisible"));
- }
-
- /**
- * We pass in HTML text in which an ampersand (@) is two chars ahead of the correct end position
- * for the tag named 'tag' and then check whether the calculated end position matches the known
- * correct position. HTML text not containing an ampersand should generate a calculated end of
- * -1
- * @param text the HTML text to test
- */
- private void findTagEnd(String text, String tag) {
- int calculatedEnd = Snippet.findTagEnd(text , tag, 0);
- int knownEnd = text.indexOf('@') + 2;
- if (knownEnd == 1) {
- // indexOf will return -1, so we'll get 1 as knownEnd
- assertEquals(-1, calculatedEnd);
- } else {
- assertEquals(calculatedEnd, knownEnd);
- }
- }
-
- public void testFindTagEnd() {
- // Test with <tag ... />
- findTagEnd("<tag foo=\"bar\"@ /> <blah blah>", "tag");
- // Test with <tag ...> ... </tag>
- findTagEnd("<tag foo=\"bar\">some text@</tag>some more text", "tag");
- // Test with incomplete tag
- findTagEnd("<tag foo=\"bar\">some more text but no end tag", "tag");
- // Test with space at end of tag
- findTagEnd("<tag foo=\"bar\">some more text but no end tag", "tag ");
- }
-
- // For debugging large HTML samples
-
-// private String readLargeSnippet(String fn) {
-// File file = mContext.getFileStreamPath(fn);
-// StringBuffer sb = new StringBuffer();
-// BufferedReader reader = null;
-// try {
-// String text;
-// reader = new BufferedReader(new FileReader(file));
-// while ((text = reader.readLine()) != null) {
-// sb.append(text);
-// sb.append(" ");
-// }
-// } catch (IOException e) {
-// }
-// return sb.toString();
-// }
- }
diff --git a/tests/src/com/android/emailcommon/utility/TextUtilitiesTests.java b/tests/src/com/android/emailcommon/utility/TextUtilitiesTests.java
new file mode 100644
index 0000000..3e1bd9d
--- /dev/null
+++ b/tests/src/com/android/emailcommon/utility/TextUtilitiesTests.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2010 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 series of unit tests for snippet creation and highlighting
+ *
+ * You can run this entire test case with:
+ * runtest -c com.android.emailcommon.utility.TextUtilitiesTests email
+ */
+package com.android.emailcommon.utility;
+
+import android.test.AndroidTestCase;
+import android.text.SpannableStringBuilder;
+import android.text.style.BackgroundColorSpan;
+
+public class TextUtilitiesTests extends AndroidTestCase {
+
+ public void testPlainSnippet() {
+ // Test the simplest cases
+ assertEquals("", TextUtilities.makeSnippetFromPlainText(null));
+ assertEquals("", TextUtilities.makeSnippetFromPlainText(""));
+
+ // Test handling leading, trailing, and duplicated whitespace
+ // Just test common whitespace characters; we calls Character.isWhitespace() internally, so
+ // other whitespace should be fine as well
+ assertEquals("", TextUtilities.makeSnippetFromPlainText(" \n\r\t\r\t\n"));
+ char c = TextUtilities.NON_BREAKING_SPACE_CHARACTER;
+ assertEquals("foo", TextUtilities.makeSnippetFromPlainText(c + "\r\n\tfoo \n\t\r" + c));
+ assertEquals("foo bar",
+ TextUtilities.makeSnippetFromPlainText(c + "\r\n\tfoo \r\n bar\n\t\r" + c));
+
+ // Handle duplicated - and =
+ assertEquals("Foo-Bar=Bletch",
+ TextUtilities.makeSnippetFromPlainText("Foo-----Bar=======Bletch"));
+
+ // We shouldn't muck with HTML entities
+ assertEquals(" >", TextUtilities.makeSnippetFromPlainText(" >"));
+ }
+
+ public void testHtmlSnippet() {
+ // Test the simplest cases
+ assertEquals("", TextUtilities.makeSnippetFromHtmlText(null));
+ assertEquals("", TextUtilities.makeSnippetFromHtmlText(""));
+
+ // Test handling leading, trailing, and duplicated whitespace
+ // Just test common whitespace characters; we calls Character.isWhitespace() internally, so
+ // other whitespace should be fine as well
+ assertEquals("", TextUtilities.makeSnippetFromHtmlText(" \n\r\t\r\t\n"));
+ char c = TextUtilities.NON_BREAKING_SPACE_CHARACTER;
+ assertEquals("foo", TextUtilities.makeSnippetFromHtmlText(c + "\r\n\tfoo \n\t\r" + c));
+ assertEquals("foo bar",
+ TextUtilities.makeSnippetFromHtmlText(c + "\r\n\tfoo \r\n bar\n\t\r" + c));
+
+ // Handle duplicated - and =
+ assertEquals("Foo-Bar=Bletch",
+ TextUtilities.makeSnippetFromPlainText("Foo-----Bar=======Bletch"));
+
+ // We should catch HTML entities in these tests
+ assertEquals(">", TextUtilities.makeSnippetFromHtmlText(" >"));
+ assertEquals("&<> \"", TextUtilities.makeSnippetFromHtmlText("&<> ""));
+ // Test for decimal and hex entities
+ assertEquals("ABC", TextUtilities.makeSnippetFromHtmlText("ABC"));
+ assertEquals("ABC", TextUtilities.makeSnippetFromHtmlText("ABC"));
+
+ // Test for stripping simple tags
+ assertEquals("Hi there", TextUtilities.makeSnippetFromHtmlText("<html>Hi there</html>"));
+ // TODO: Add tests here if/when we find problematic HTML
+ }
+
+ public void testStripHtmlEntityEdgeCases() {
+ int[] skipCount = new int[1];
+ // Bare & isn't an entity
+ char c = TextUtilities.stripHtmlEntity("&", 0, skipCount);
+ assertEquals(c, '&');
+ assertEquals(0, skipCount[0]);
+ // Also not legal
+ c = TextUtilities.stripHtmlEntity("&;", 0, skipCount);
+ assertEquals(c, '&');
+ assertEquals(0, skipCount[0]);
+ // This is an entity, but shouldn't be found
+ c = TextUtilities.stripHtmlEntity("&nosuch;", 0, skipCount);
+ assertEquals(c, '&');
+ assertEquals(0, skipCount[0]);
+ // This is too long for an entity, even though it starts like a valid one
+ c = TextUtilities.stripHtmlEntity(" andmore;", 0, skipCount);
+ assertEquals(c, '&');
+ assertEquals(0, skipCount[0]);
+ // Illegal decimal entities
+ c = TextUtilities.stripHtmlEntity("&#ABC", 0, skipCount);
+ assertEquals(c, '&');
+ assertEquals(0, skipCount[0]);
+ c = TextUtilities.stripHtmlEntity("B", 0, skipCount);
+ assertEquals(c, '&');
+ assertEquals(0, skipCount[0]);
+ // Illegal hex entities
+ c = TextUtilities.stripHtmlEntity("઼", 0, skipCount);
+ assertEquals(c, '&');
+ assertEquals(0, skipCount[0]);
+ // Illegal hex entities
+ c = TextUtilities.stripHtmlEntity("G", 0, skipCount);
+ assertEquals(c, '&');
+ assertEquals(0, skipCount[0]);
+ }
+
+ public void testStripContent() {
+ assertEquals("Visible", TextUtilities.makeSnippetFromHtmlText(
+ "<html><style foo=\"bar\">Not</style>Visible</html>"));
+ assertEquals("Visible", TextUtilities.makeSnippetFromHtmlText(
+ "<html><STYLE foo=\"bar\">Not</STYLE>Visible</html>"));
+ assertEquals("IsVisible", TextUtilities.makeSnippetFromHtmlText(
+ "<html><nostrip foo=\"bar\">Is</nostrip>Visible</html>"));
+ assertEquals("Visible", TextUtilities.makeSnippetFromHtmlText(
+ "<html>Visible<style foo=\"bar\">Not"));
+ assertEquals("VisibleAgainVisible", TextUtilities.makeSnippetFromHtmlText(
+ "<html>Visible<style foo=\"bar\">Not</style>AgainVisible"));
+ assertEquals("VisibleAgainVisible", TextUtilities.makeSnippetFromHtmlText(
+ "<html>Visible<style foo=\"bar\"/>AgainVisible"));
+ assertEquals("VisibleAgainVisible", TextUtilities.makeSnippetFromHtmlText(
+ "<html>Visible<style foo=\"bar\"/><head><//blah<style>Not</head>AgainVisible"));
+ }
+
+ /**
+ * We pass in HTML text in which an ampersand (@) is two chars ahead of the correct end position
+ * for the tag named 'tag' and then check whether the calculated end position matches the known
+ * correct position. HTML text not containing an ampersand should generate a calculated end of
+ * -1
+ * @param text the HTML text to test
+ */
+ private void findTagEnd(String text, String tag) {
+ int calculatedEnd = TextUtilities.findTagEnd(text , tag, 0);
+ int knownEnd = text.indexOf('@') + 2;
+ if (knownEnd == 1) {
+ // indexOf will return -1, so we'll get 1 as knownEnd
+ assertEquals(-1, calculatedEnd);
+ } else {
+ assertEquals(calculatedEnd, knownEnd);
+ }
+ }
+
+ public void testFindTagEnd() {
+ // Test with <tag ... />
+ findTagEnd("<tag foo=\"bar\"@ /> <blah blah>", "tag");
+ // Test with <tag ...> ... </tag>
+ findTagEnd("<tag foo=\"bar\">some text@</tag>some more text", "tag");
+ // Test with incomplete tag
+ findTagEnd("<tag foo=\"bar\">some more text but no end tag", "tag");
+ // Test with space at end of tag
+ findTagEnd("<tag foo=\"bar\">some more text but no end tag", "tag ");
+ }
+
+ private void assertHighlightUnchanged(String str) {
+ assertEquals(str, TextUtilities.highlightTermsInHtml(str, null));
+ }
+
+ public void testHighlightNoTerm() {
+ // With no search terms, the html should be unchanged
+ assertHighlightUnchanged("<html><style foo=\"bar\">Not</style>Visible</html>");
+ assertHighlightUnchanged("<html><nostrip foo=\"bar\">Is</nostrip>Visible</html>");
+ assertHighlightUnchanged("<html>Visible<style foo=\"bar\">Not");
+ assertHighlightUnchanged("<html>Visible<style foo=\"bar\">Not</style>AgainVisible");
+ assertHighlightUnchanged("<html>Visible<style foo=\"bar\"/>AgainVisible");
+ assertHighlightUnchanged(
+ "<html>Visible<style foo=\"bar\"/><head><//blah<style>Not</head>AgainVisible");
+ }
+
+ public void testHighlightSingleTermHtml() {
+ String str = "<html><style foo=\"bar\">Not</style>Visible</html>";
+ // Test that tags aren't highlighted
+ assertEquals(str, TextUtilities.highlightTermsInHtml(
+ "<html><style foo=\"bar\">Not</style>Visible</html>", "style"));
+ // Test that non-tags are
+ assertEquals("<html><style foo=\"bar\">Not</style><span " +
+ "style=\"background-color: " + TextUtilities.HIGHLIGHT_COLOR_STRING +
+ "\">Visi</span>ble</html>",
+ TextUtilities.highlightTermsInHtml(str, "Visi"));
+ assertEquals("<html>Visible<style foo=\"bar\">Not</style>A<span" +
+ " style=\"background-color: " + TextUtilities.HIGHLIGHT_COLOR_STRING +
+ "\">gain</span>Visible",
+ TextUtilities.highlightTermsInHtml(
+ "<html>Visible<style foo=\"bar\">Not</style>AgainVisible", "gain"));
+ }
+
+ public void testHighlightSingleTermText() {
+ // Sprinkle text with a few HTML characters to make sure they're ignored
+ String text = "This< should be visibl>e";
+ // We should find this, because search terms are case insensitive
+ SpannableStringBuilder ssb =
+ (SpannableStringBuilder)TextUtilities.highlightTermsInText(text, "Visi");
+ BackgroundColorSpan[] spans = ssb.getSpans(0, ssb.length(), BackgroundColorSpan.class);
+ assertEquals(1, spans.length);
+ BackgroundColorSpan span = spans[0];
+ assertEquals(text.indexOf("visi"), ssb.getSpanStart(span));
+ assertEquals(text.indexOf("bl>e"), ssb.getSpanEnd(span));
+ // Heh; this next test fails.. we use the search term!
+ assertEquals(text, ssb.toString());
+
+ // Multiple instances of the term
+ text = "The research word should be a search result";
+ ssb = (SpannableStringBuilder)TextUtilities.highlightTermsInText(text, "Search");
+ spans = ssb.getSpans(0, ssb.length(), BackgroundColorSpan.class);
+ assertEquals(2, spans.length);
+ span = spans[0];
+ assertEquals(text.indexOf("search word"), ssb.getSpanStart(span));
+ assertEquals(text.indexOf(" word"), ssb.getSpanEnd(span));
+ span = spans[1];
+ assertEquals(text.indexOf("search result"), ssb.getSpanStart(span));
+ assertEquals(text.indexOf(" result"), ssb.getSpanEnd(span));
+ assertEquals(text, ssb.toString());
+ }
+
+ public void testHighlightTwoTermText() {
+ String text = "This should be visible";
+ // We should find this, because search terms are case insensitive
+ SpannableStringBuilder ssb =
+ (SpannableStringBuilder)TextUtilities.highlightTermsInText(text, "visi should");
+ BackgroundColorSpan[] spans = ssb.getSpans(0, ssb.length(), BackgroundColorSpan.class);
+ assertEquals(2, spans.length);
+ BackgroundColorSpan span = spans[0];
+ assertEquals(text.indexOf("should"), ssb.getSpanStart(span));
+ assertEquals(text.indexOf(" be"), ssb.getSpanEnd(span));
+ span = spans[1];
+ assertEquals(text.indexOf("visi"), ssb.getSpanStart(span));
+ assertEquals(text.indexOf("ble"), ssb.getSpanEnd(span));
+ assertEquals(text, ssb.toString());
+ }
+
+ public void testHighlightDuplicateTermText() {
+ String text = "This should be visible";
+ // We should find this, because search terms are case insensitive
+ SpannableStringBuilder ssb =
+ (SpannableStringBuilder)TextUtilities.highlightTermsInText(text, "should should");
+ BackgroundColorSpan[] spans = ssb.getSpans(0, ssb.length(), BackgroundColorSpan.class);
+ assertEquals(1, spans.length);
+ BackgroundColorSpan span = spans[0];
+ assertEquals(text.indexOf("should"), ssb.getSpanStart(span));
+ assertEquals(text.indexOf(" be"), ssb.getSpanEnd(span));
+ }
+
+ public void testHighlightOverlapTermText() {
+ String text = "This shoulder is visible";
+ // We should find this, because search terms are case insensitive
+ SpannableStringBuilder ssb =
+ (SpannableStringBuilder)TextUtilities.highlightTermsInText(text, "should ould");
+ BackgroundColorSpan[] spans = ssb.getSpans(0, ssb.length(), BackgroundColorSpan.class);
+ assertEquals(1, spans.length);
+ BackgroundColorSpan span = spans[0];
+ assertEquals(text.indexOf("should"), ssb.getSpanStart(span));
+ assertEquals(text.indexOf("er is"), ssb.getSpanEnd(span));
+ }
+
+
+ public void testHighlightOverlapTermText2() {
+ String text = "The shoulders are visible";
+ // We should find this, because search terms are case insensitive
+ SpannableStringBuilder ssb =
+ (SpannableStringBuilder)TextUtilities.highlightTermsInText(text, "shoulder shoulders");
+ BackgroundColorSpan[] spans = ssb.getSpans(0, ssb.length(), BackgroundColorSpan.class);
+ assertEquals(2, spans.length);
+ BackgroundColorSpan span = spans[0];
+ assertEquals(text.indexOf("shoulder"), ssb.getSpanStart(span));
+ assertEquals(text.indexOf("s are visible"), ssb.getSpanEnd(span));
+ span = spans[1];
+ // Just the 's' should be caught in the 2nd span
+ assertEquals(text.indexOf("s are visible"), ssb.getSpanStart(span));
+ assertEquals(text.indexOf(" are visible"), ssb.getSpanEnd(span));
+ assertEquals(text, ssb.toString());
+ }
+ // For debugging large HTML samples
+
+// private String readLargeSnippet(String fn) {
+// File file = mContext.getFileStreamPath(fn);
+// StringBuffer sb = new StringBuffer();
+// BufferedReader reader = null;
+// try {
+// String text;
+// reader = new BufferedReader(new FileReader(file));
+// while ((text = reader.readLine()) != null) {
+// sb.append(text);
+// sb.append(" ");
+// }
+// } catch (IOException e) {
+// }
+// return sb.toString();
+// }
+ }
diff --git a/tests/src/com/android/emailcommon/utility/UtilityUnitTests.java b/tests/src/com/android/emailcommon/utility/UtilityUnitTests.java
index a5aa6b3..5daf049 100644
--- a/tests/src/com/android/emailcommon/utility/UtilityUnitTests.java
+++ b/tests/src/com/android/emailcommon/utility/UtilityUnitTests.java
@@ -20,7 +20,6 @@
import com.android.email.FolderProperties;
import com.android.email.R;
import com.android.email.TestUtils;
-import com.android.email.UiUtilities;
import com.android.email.provider.ProviderTestUtils;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.Attachment;
@@ -53,11 +52,8 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
-import java.util.Locale;
import java.util.Set;
-import libcore.util.EmptyArray;
-
/**
* This is a series of unit tests for the Utility class. These tests must be locally
* complete - no server(s) required.
@@ -231,21 +227,6 @@
Utility.cleanUpMimeDate("Thu, 10 Dec 09 15:08:08 -0700"));
}
- public void testFormatSize() {
- if (!"en".equalsIgnoreCase(Locale.getDefault().getLanguage())) {
- return; // Only works on the EN locale.
- }
- assertEquals("0B", UiUtilities.formatSize(getContext(), 0));
- assertEquals("1B", UiUtilities.formatSize(getContext(), 1));
- assertEquals("1023B", UiUtilities.formatSize(getContext(), 1023));
- assertEquals("1KB", UiUtilities.formatSize(getContext(), 1024));
- assertEquals("1023KB", UiUtilities.formatSize(getContext(), 1024 * 1024 - 1));
- assertEquals("1MB", UiUtilities.formatSize(getContext(), 1024 * 1024));
- assertEquals("1023MB", UiUtilities.formatSize(getContext(), 1024 * 1024 * 1024 - 1));
- assertEquals("1GB", UiUtilities.formatSize(getContext(), 1024 * 1024 * 1024));
- assertEquals("5GB", UiUtilities.formatSize(getContext(), 5L * 1024 * 1024 * 1024));
- }
-
private static class MyNewFileCreator implements NewFileCreator {
private final HashSet<String> mExistingFileNames;
@@ -463,31 +444,6 @@
// TODO check style -- but how?
}
- public void testGetMessageCountForUi() {
- final Context c = getContext();
-
- // Negavive valeus not really expected, but at least shouldn't crash.
- assertEquals("-1", UiUtilities.getMessageCountForUi(c, -1, true));
- assertEquals("-1", UiUtilities.getMessageCountForUi(c, -1, false));
-
- assertEquals("", UiUtilities.getMessageCountForUi(c, 0, true));
- assertEquals("0", UiUtilities.getMessageCountForUi(c, 0, false));
-
- assertEquals("1", UiUtilities.getMessageCountForUi(c, 1, true));
- assertEquals("1", UiUtilities.getMessageCountForUi(c, 1, false));
-
- assertEquals("999", UiUtilities.getMessageCountForUi(c, 999, true));
- assertEquals("999", UiUtilities.getMessageCountForUi(c, 999, false));
-
- final String moreThan999 = c.getString(R.string.more_than_999);
-
- assertEquals(moreThan999, UiUtilities.getMessageCountForUi(c, 1000, true));
- assertEquals(moreThan999, UiUtilities.getMessageCountForUi(c, 1000, false));
-
- assertEquals(moreThan999, UiUtilities.getMessageCountForUi(c, 1001, true));
- assertEquals(moreThan999, UiUtilities.getMessageCountForUi(c, 1001, false));
- }
-
public void testAreStringsEqual() {
String s1;
String s2;