Utils.java revision 161f50d0fabdaa384a63ce69f595861c5e69795f
17b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira/**
27b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * Copyright (c) 2011, Google Inc.
37b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira *
47b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
57b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * you may not use this file except in compliance with the License.
67b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * You may obtain a copy of the License at
77b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira *
87b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira *     http://www.apache.org/licenses/LICENSE-2.0
97b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira *
107b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * Unless required by applicable law or agreed to in writing, software
117b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
127b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * See the License for the specific language governing permissions and
147b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * limitations under the License.
157b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira */
162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.utils;
187b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
19f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport com.google.common.collect.Maps;
20f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
216f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.content.Context;
228a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport android.content.Intent;
2394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrookimport android.content.pm.PackageManager.NameNotFoundException;
246f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.content.res.Resources;
256f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Typeface;
268a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport android.net.Uri;
2794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrookimport android.provider.Browser;
283e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.Html;
293e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.Spannable;
306f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.SpannableString;
316f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.SpannableStringBuilder;
323e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.Spanned;
333e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.TextUtils;
343e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.TextUtils.SimpleStringSplitter;
356f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.CharacterStyle;
366f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.ForegroundColorSpan;
376f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.StyleSpan;
38326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.View;
39326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.View.MeasureSpec;
40f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport android.view.ViewGroup;
418b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereiraimport android.webkit.WebSettings;
428b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereiraimport android.webkit.WebView;
438b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira
4430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.R;
458a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport com.android.mail.providers.Account;
469ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereiraimport com.android.mail.providers.Conversation;
478a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport com.android.mail.providers.Folder;
488a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport com.android.mail.providers.UIProvider;
493e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira
5094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrookimport java.util.Locale;
513e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport java.util.Map;
527b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
536f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereirapublic class Utils {
546f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    /**
556f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     * longest extension we recognize is 4 characters (e.g. "html", "docx")
566f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     */
576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final int FILE_EXTENSION_MAX_CHARS = 4;
583e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    private static final Map<Integer, Integer> sPriorityToLength = Maps.newHashMap();
593e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_ELIDED = "e";
603e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_NUM_MESSAGES = "n";
613e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_NUM_DRAFTS = "d";
623e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_LITERAL = "l";
633e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_SENDING = "s";
643e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_SEND_FAILED = "f";
653e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final Character SENDER_LIST_SEPARATOR = '\n';
663e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final SimpleStringSplitter sSenderListSplitter = new SimpleStringSplitter(
673e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            SENDER_LIST_SEPARATOR);
683e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static String[] sSenderFragments = new String[8];
698b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira
706349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    public static final String EXTRA_ACCOUNT = "account";
717418e4b9942f291b8de8bc7b1b72a7ef7130a8b6Mindy Pereira    public static final String EXTRA_COMPOSE_URI = "composeUri";
72963cdedf714e6e37c7447413cff767b3f2826b28Mindy Pereira    public static final String EXTRA_CONVERSATION = "conversationUri";
73963cdedf714e6e37c7447413cff767b3f2826b28Mindy Pereira    public static final String EXTRA_FOLDER = "folder";
748a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira    /*
758a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira     * Notifies that changes happened. Certain UI components, e.g., widgets, can
768a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira     * register for this {@link Intent} and update accordingly. However, this
778a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira     * can be very broad and is NOT the preferred way of getting notification.
788a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira     */
798a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira    // TODO: UI Provider has this notification URI?
8094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    public static final String ACTION_NOTIFY_DATASET_CHANGED =
8194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            "com.android.mail.ACTION_NOTIFY_DATASET_CHANGED";
8294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
8394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    /** Parameter keys for context-aware help. */
8494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static final String SMART_HELP_LINK_PARAMETER_NAME = "p";
8594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
8694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static final String SMART_LINK_APP_VERSION = "version";
8794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static String sVersionCode = null;
8894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
8994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static final String LOG_TAG = new LogUtils().getLogTag();
906349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
922c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Sets WebView in a restricted mode suitable for email use.
932c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *
942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @param webView The WebView to restrict
952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static void restrictWebView(WebView webView) {
978b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira        WebSettings webSettings = webView.getSettings();
988b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira        webSettings.setSavePassword(false);
998b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira        webSettings.setSaveFormData(false);
1008b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira        webSettings.setJavaScriptEnabled(true);
1018b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira        webSettings.setSupportZoom(false);
1022c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
1032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
1052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Format a plural string.
1062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *
1072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @param resource The identity of the resource, which must be a R.plurals
1082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @param count The number of items.
1092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
1102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static String formatPlural(Context context, int resource, int count) {
1112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        CharSequence formatString = context.getResources().getQuantityText(resource, count);
1122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return String.format(formatString.toString(), count);
1132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
1142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1152c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
1162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @return an ellipsized String that's at most maxCharacters long. If the
1172c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *         text passed is longer, it will be abbreviated. If it contains a
1182c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *         suffix, the ellipses will be inserted in the middle and the
1192c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *         suffix will be preserved.
1202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
1212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static String ellipsize(String text, int maxCharacters) {
1222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int length = text.length();
1232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (length < maxCharacters)
1242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            return text;
1252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int realMax = Math.min(maxCharacters, length);
1272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        // Preserve the suffix if any
1282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int index = text.lastIndexOf(".");
1292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        String extension = "\u2026"; // "...";
1302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (index >= 0) {
1312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            // Limit the suffix to dot + four characters
1322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (length - index <= FILE_EXTENSION_MAX_CHARS + 1) {
1332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                extension = extension + text.substring(index + 1);
1342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
1352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
1362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        realMax -= extension.length();
1372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (realMax < 0)
1382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            realMax = 0;
1392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return text.substring(0, realMax) + extension;
1402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
1412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
1434ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * Ensures that the given string starts and ends with the double quote
1444ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * character. The string is not modified in any way except to add the double
1454ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * quote character to start and end if it's not already there. sample ->
1464ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * "sample" "sample" -> "sample" ""sample"" -> "sample"
1474ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * "sample"" -> "sample" sa"mp"le -> "sa"mp"le" "sa"mp"le" -> "sa"mp"le"
1484ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * (empty string) -> "" " -> ""
1494ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     */
1502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static String ensureQuotedString(String s) {
1512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (s == null) {
1522c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            return null;
1532c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
1542c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (!s.matches("^\".*\"$")) {
1552c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            return "\"" + s + "\"";
1562c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        } else {
1572c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            return s;
1582c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
1592c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
1602c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1612c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    // TODO: Move this to the UI Provider.
1622c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharacterStyle sUnreadStyleSpan = null;
1632c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharacterStyle sReadStyleSpan;
1642c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharacterStyle sDraftsStyleSpan;
1652c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharSequence sMeString;
1662c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharSequence sDraftSingularString;
1672c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharSequence sDraftPluralString;
1682c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharSequence sSendingString;
1692c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharSequence sSendFailedString;
1702c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1712c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static int sMaxUnreadCount = -1;
1722c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static String sUnreadText;
1732c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1742c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static void getStyledSenderSnippet(Context context, String senderInstructions,
1752c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            SpannableStringBuilder senderBuilder, SpannableStringBuilder statusBuilder,
1762c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            int maxChars, boolean forceAllUnread, boolean forceAllRead, boolean allowDraft) {
1772c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        Resources res = context.getResources();
1782c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (sUnreadStyleSpan == null) {
1792c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sUnreadStyleSpan = new StyleSpan(Typeface.BOLD);
1802c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sReadStyleSpan = new StyleSpan(Typeface.NORMAL);
1812c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sDraftsStyleSpan = new ForegroundColorSpan(res.getColor(R.color.drafts));
1822c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1832c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sMeString = context.getText(R.string.me);
1842c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sDraftSingularString = res.getQuantityText(R.plurals.draft, 1);
1852c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sDraftPluralString = res.getQuantityText(R.plurals.draft, 2);
1862c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            SpannableString sendingString = new SpannableString(context.getText(R.string.sending));
1872c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sendingString.setSpan(CharacterStyle.wrap(sDraftsStyleSpan), 0, sendingString.length(),
1882c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    0);
1892c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sSendingString = sendingString;
1902c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sSendFailedString = context.getText(R.string.send_failed);
1912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
1922c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1932c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        getSenderSnippet(senderInstructions, senderBuilder, statusBuilder, maxChars,
1942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sUnreadStyleSpan, sReadStyleSpan, sDraftsStyleSpan, sMeString,
1952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sDraftSingularString, sDraftPluralString, sSendingString, sSendFailedString,
1962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                forceAllUnread, forceAllRead, allowDraft);
1972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
1982c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
2003e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * Uses sender instructions to build a formatted string.
2013e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <p>
2023e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * Sender list instructions contain compact information about the sender
2033e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * list. Most work that can be done without knowing how much room will be
2043e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * availble for the sender list is done when creating the instructions.
2053e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <p>
2063e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * The instructions string consists of tokens separated by
2073e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * SENDER_LIST_SEPARATOR. Here are the tokens, one per line:
2083e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <ul>
2093e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>n</tt></li>
2103e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>int</em>, the number of non-draft messages in the conversation</li>
2113e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>d</tt</li>
2123e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>int</em>, the number of drafts in the conversation</li>
2133e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>l</tt></li>
2143e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>literal html to be included in the output</em></li>
2153e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>s</tt> indicates that the message is sending (in the outbox
2163e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * without errors)</li>
2173e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>f</tt> indicates that the message failed to send (in the outbox
2183e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * with errors)</li>
2193e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>for each message</em>
2203e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <ul>
2213e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>int</em>, 0 for read, 1 for unread</li>
2223e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>int</em>, the priority of the message. Zero is the most important
2233e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * </li>
2243e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>text</em>, the sender text or blank for messages from 'me'</li>
2253e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * </ul>
2263e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * </li>
2273e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>e</tt> to indicate that one or more messages have been elided</li>
2283e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <p>
2293e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * The instructions indicate how many messages and drafts are in the
2303e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * conversation and then describe the most important messages in order,
2313e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * indicating the priority of each message and whether the message is
2323e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * unread.
233f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     *
2343e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param instructions instructions as described above
2353e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param senderBuilder the SpannableStringBuilder to append to for sender
2363e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     *            information
2373e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param statusBuilder the SpannableStringBuilder to append to for status
2383e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param maxChars the number of characters available to display the text
2393e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param unreadStyle the CharacterStyle for unread messages, or null
2403e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param draftsStyle the CharacterStyle for draft messages, or null
2413e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param sendingString the string to use when there are messages scheduled
2423e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     *            to be sent
2433e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param sendFailedString the string to use when there are messages that
2443e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     *            mailed to send
2453e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param meString the string to use for messages sent by this user
2463e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param draftString the string to use for "Draft"
2473e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param draftPluralString the string to use for "Drafts"
2483e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     */
2492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static synchronized void getSenderSnippet(String instructions,
2502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            SpannableStringBuilder senderBuilder, SpannableStringBuilder statusBuilder,
2512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            int maxChars, CharacterStyle unreadStyle, CharacterStyle readStyle,
2522c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            CharacterStyle draftsStyle, CharSequence meString, CharSequence draftString,
2532c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            CharSequence draftPluralString, CharSequence sendingString,
2542c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            CharSequence sendFailedString, boolean forceAllUnread, boolean forceAllRead,
2552c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            boolean allowDraft) {
2562c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        assert !(forceAllUnread && forceAllRead);
2572c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        boolean unreadStatusIsForced = forceAllUnread || forceAllRead;
2582c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        boolean forcedUnreadStatus = forceAllUnread;
2592c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
2602c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        // Measure each fragment. It's ok to iterate over the entire set of
2612c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        // fragments because it is
2622c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        // never a long list, even if there are many senders.
2632c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        final Map<Integer, Integer> priorityToLength = sPriorityToLength;
2642c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        priorityToLength.clear();
2652c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
2662c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int maxFoundPriority = Integer.MIN_VALUE;
2672c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numMessages = 0;
2682c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numDrafts = 0;
2692c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        CharSequence draftsFragment = "";
2702c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        CharSequence sendingFragment = "";
2712c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        CharSequence sendFailedFragment = "";
2722c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
2732c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        sSenderListSplitter.setString(instructions);
2742c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numFragments = 0;
2752c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        String[] fragments = sSenderFragments;
2762c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int currentSize = fragments.length;
2772c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        while (sSenderListSplitter.hasNext()) {
2782c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            fragments[numFragments++] = sSenderListSplitter.next();
2792c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (numFragments == currentSize) {
2802c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sSenderFragments = new String[2 * currentSize];
2812c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                System.arraycopy(fragments, 0, sSenderFragments, 0, currentSize);
2822c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                currentSize *= 2;
2832c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fragments = sSenderFragments;
2842c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
2852c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
2862c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
2872c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        for (int i = 0; i < numFragments;) {
2882c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            String fragment0 = fragments[i++];
2892c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if ("".equals(fragment0)) {
2902c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // This should be the final fragment.
2912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_ELIDED.equals(fragment0)) {
2922c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // ignore
2932c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_NUM_MESSAGES.equals(fragment0)) {
2942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                numMessages = Integer.valueOf(fragments[i++]);
2952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_NUM_DRAFTS.equals(fragment0)) {
2962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                String numDraftsString = fragments[i++];
2972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                numDrafts = Integer.parseInt(numDraftsString);
2982c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                draftsFragment = numDrafts == 1 ? draftString : draftPluralString + " ("
2992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        + numDraftsString + ")";
3002c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_LITERAL.equals(fragment0)) {
3012c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                senderBuilder.append(Html.fromHtml(fragments[i++]));
3022c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                return;
3032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_SENDING.equals(fragment0)) {
3042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sendingFragment = sendingString;
3052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_SEND_FAILED.equals(fragment0)) {
3062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sendFailedFragment = sendFailedString;
3072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else {
3082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                String priorityString = fragments[i++];
3092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                CharSequence nameString = fragments[i++];
3102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (nameString.length() == 0)
3112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    nameString = meString;
3122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                int priority = Integer.parseInt(priorityString);
3132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                priorityToLength.put(priority, nameString.length());
3142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                maxFoundPriority = Math.max(maxFoundPriority, priority);
3152c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3172c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        String numMessagesFragment = (numMessages != 0) ? " \u00A0"
3182c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                + Integer.toString(numMessages + numDrafts) : "";
3192c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        // Don't allocate fixedFragment unless we need it
3212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        SpannableStringBuilder fixedFragment = null;
3222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int fixedFragmentLength = 0;
3232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (draftsFragment.length() != 0 && allowDraft) {
3242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (fixedFragment == null) {
3252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment = new SpannableStringBuilder();
3262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            fixedFragment.append(draftsFragment);
3282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (draftsStyle != null) {
3292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment.setSpan(CharacterStyle.wrap(draftsStyle), 0, fixedFragment.length(),
3302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
3312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (sendingFragment.length() != 0) {
3342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (fixedFragment == null) {
3352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment = new SpannableStringBuilder();
3362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (fixedFragment.length() != 0)
3382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment.append(", ");
3392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            fixedFragment.append(sendingFragment);
3402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (sendFailedFragment.length() != 0) {
3422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (fixedFragment == null) {
3432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment = new SpannableStringBuilder();
3442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (fixedFragment.length() != 0)
3462c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment.append(", ");
3472c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            fixedFragment.append(sendFailedFragment);
3482c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (fixedFragment != null) {
3512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            fixedFragmentLength = fixedFragment.length();
3522c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3532c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        maxChars -= fixedFragmentLength;
3542c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3552c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int maxPriorityToInclude = -1; // inclusive
3562c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numCharsUsed = numMessagesFragment.length();
3572c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numSendersUsed = 0;
3582c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        while (maxPriorityToInclude < maxFoundPriority) {
3592c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (priorityToLength.containsKey(maxPriorityToInclude + 1)) {
3602c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                int length = numCharsUsed + priorityToLength.get(maxPriorityToInclude + 1);
3612c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (numCharsUsed > 0)
3622c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    length += 2;
3632c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // We must show at least two senders if they exist. If we don't
3642c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // have space for both
3652c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // then we will truncate names.
3662c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (length > maxChars && numSendersUsed >= 2) {
3672c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    break;
3682c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                }
3692c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                numCharsUsed = length;
3702c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                numSendersUsed++;
3712c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3722c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            maxPriorityToInclude++;
3732c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3742c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3752c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numCharsToRemovePerWord = 0;
3762c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (numCharsUsed > maxChars) {
3772c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            numCharsToRemovePerWord = (numCharsUsed - maxChars) / numSendersUsed;
3782c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3792c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3802c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        String lastFragment = null;
3812c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        CharacterStyle lastStyle = null;
3822c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        for (int i = 0; i < numFragments;) {
3832c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            String fragment0 = fragments[i++];
3842c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if ("".equals(fragment0)) {
3852c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // This should be the final fragment.
3862c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_ELIDED.equals(fragment0)) {
3872c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (lastFragment != null) {
3882c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    addStyledFragment(senderBuilder, lastFragment, lastStyle, false);
3892c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    senderBuilder.append(" ");
3902c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    addStyledFragment(senderBuilder, "..", lastStyle, true);
3912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    senderBuilder.append(" ");
3922c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                }
3932c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                lastFragment = null;
3942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_NUM_MESSAGES.equals(fragment0)) {
3952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                i++;
3962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_NUM_DRAFTS.equals(fragment0)) {
3972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                i++;
3982c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_SENDING.equals(fragment0)) {
3992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_SEND_FAILED.equals(fragment0)) {
4002c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else {
4012c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                final String unreadString = fragment0;
4022c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                final String priorityString = fragments[i++];
4032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                String nameString = fragments[i++];
4042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (nameString.length() == 0) {
4052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    nameString = meString.toString();
4062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                } else {
4072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    nameString = Html.fromHtml(nameString).toString();
4082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                }
4092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (numCharsToRemovePerWord != 0) {
4102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    nameString = nameString.substring(0,
4112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                            Math.max(nameString.length() - numCharsToRemovePerWord, 0));
4122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                }
4132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                final boolean unread = unreadStatusIsForced ? forcedUnreadStatus : Integer
4142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        .parseInt(unreadString) != 0;
4152c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                final int priority = Integer.parseInt(priorityString);
4162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (priority <= maxPriorityToInclude) {
4172c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    if (lastFragment != null && !lastFragment.equals(nameString)) {
4182c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        addStyledFragment(senderBuilder, lastFragment.concat(","), lastStyle,
4192c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                                false);
4202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        senderBuilder.append(" ");
4212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    }
4222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    lastFragment = nameString;
4232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    lastStyle = unread ? unreadStyle : readStyle;
4242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                } else {
4252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    if (lastFragment != null) {
4262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        addStyledFragment(senderBuilder, lastFragment, lastStyle, false);
4272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        // Adjacent spans can cause the TextView in Gmail widget
4282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        // confused and leads to weird behavior on scrolling.
4292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        // Our workaround here is to separate the spans by
4302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        // spaces.
4312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        senderBuilder.append(" ");
4322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        addStyledFragment(senderBuilder, "..", lastStyle, true);
4332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        senderBuilder.append(" ");
4342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    }
4352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    lastFragment = null;
4362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                }
4372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
4382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
4392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (lastFragment != null) {
4402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            addStyledFragment(senderBuilder, lastFragment, lastStyle, false);
4412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
4422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        senderBuilder.append(numMessagesFragment);
4432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (fixedFragmentLength != 0) {
4442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            statusBuilder.append(fixedFragment);
4452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
4462c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
4476f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4483e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    /**
4493e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * Adds a fragment with given style to a string builder.
450f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     *
4513e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param builder the current string builder
4523e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param fragment the fragment to be added
4533e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param style the style of the fragment
4543e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param withSpaces whether to add the whole fragment or to divide it into
4553e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     *            smaller ones
4563e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     */
4573e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    private static void addStyledFragment(SpannableStringBuilder builder, String fragment,
4583e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            CharacterStyle style, boolean withSpaces) {
4593e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira        if (withSpaces) {
4603e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            int pos = builder.length();
4613e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            builder.append(fragment);
4623e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            builder.setSpan(CharacterStyle.wrap(style), pos, builder.length(),
4633e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
4643e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira        } else {
4653e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            int start = 0;
4663e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            while (true) {
4673e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                int pos = fragment.substring(start).indexOf(' ');
4683e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                if (pos == -1) {
4693e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    addStyledFragment(builder, fragment.substring(start), style, true);
4703e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    break;
4713e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                } else {
4723e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    pos += start;
4733e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    if (start < pos) {
4743e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                        addStyledFragment(builder, fragment.substring(start, pos), style, true);
4753e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                        builder.append(' ');
4763e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    }
4773e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    start = pos + 1;
4783e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    if (start >= fragment.length()) {
4793e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                        break;
4803e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    }
4813e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                }
4823e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            }
4833e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira        }
4843e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    }
4853e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira
4862c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
4872c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Returns a boolean indicating whether the table UI should be shown.
4882c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
4892c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static boolean useTabletUI(Context context) {
4902c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return context.getResources().getInteger(R.integer.use_tablet_ui) != 0;
4912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
4922c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
4932c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
4942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Perform a simulated measure pass on the given child view, assuming the
4952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * child has a ViewGroup parent and that it should be laid out within that
4962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * parent with a matching width but variable height. Code largely lifted
4972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * from AnimatedAdapter.measureChildHeight().
498f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     *
4992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @param child a child view that has already been placed within its parent
5002c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *            ViewGroup
5012c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @param parent the parent ViewGroup of child
5022c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @return measured height of the child in px
5032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
5042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static int measureViewHeight(View child, ViewGroup parent) {
5052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int parentWSpec = MeasureSpec.makeMeasureSpec(parent.getWidth(), MeasureSpec.EXACTLY);
5062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int wSpec = ViewGroup.getChildMeasureSpec(parentWSpec,
5072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                parent.getPaddingLeft() + parent.getPaddingRight(),
5082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                ViewGroup.LayoutParams.MATCH_PARENT);
5092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int hSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
5102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        child.measure(wSpec, hSpec);
5112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return child.getMeasuredHeight();
5122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
513326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
51446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
51546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Encode the string in HTML.
51646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
51746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param removeEmptyDoubleQuotes If true, also remove any occurrence of ""
51846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *            found in the string
51946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
5202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static Object cleanUpString(String string, boolean removeEmptyDoubleQuotes) {
5212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return !TextUtils.isEmpty(string) ? TextUtils.htmlEncode(removeEmptyDoubleQuotes ? string
5222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                .replace("\"\"", "") : string) : "";
5232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
5242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
5252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
5262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Returns comma seperated strings as an array.
5272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
5282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static String[] splitCommaSeparatedString(String str) {
5292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return TextUtils.isEmpty(str) ? new String[0] : TextUtils.split(str, ",");
5302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
5312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
5322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
5332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Get the correct display string for the unread count of a folder.
5342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
5352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static String getUnreadCountString(Context context, int unreadCount) {
5362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        String unreadCountString;
5372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        Resources resources = context.getResources();
5382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (sMaxUnreadCount == -1) {
5392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sMaxUnreadCount = resources.getInteger(R.integer.maxUnreadCount);
5402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
5412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (unreadCount > sMaxUnreadCount) {
5422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (sUnreadText == null) {
5432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sUnreadText = resources.getString(R.string.widget_large_unread_count);
5442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
5452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            unreadCountString = String.format(sUnreadText, sMaxUnreadCount);
5462c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        } else if (unreadCount <= 0) {
5472c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            unreadCountString = "";
5482c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        } else {
5492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            unreadCountString = String.valueOf(unreadCount);
5502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
5512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return unreadCountString;
5522c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
55328beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira
55428beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira    /**
55528beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira     * Get text matching the last sync status.
55628beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira     */
55728beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira    public static CharSequence getSyncStatusText(Context context, int status) {
55828beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira        String[] errors = context.getResources().getStringArray(R.array.sync_status);
55928beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira        if (status >= errors.length) {
56028beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira            return "";
56128beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira        }
56228beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira        return errors[status];
56328beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira    }
5648a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira
5658a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira    /**
5669ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     * Create an intent to show a conversation.
5679ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     * @param conversation Conversation to open.
568161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira     * @param folder
569161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira     * @param account
5709ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     * @return
5719ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     */
572161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira    public static Intent createViewConversationIntent(Conversation conversation, Folder folder,
573161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira            Account account) {
5749ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        final Intent intent = new Intent(Intent.ACTION_VIEW);
5759ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
5769ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        intent.setDataAndType(conversation.uri, "application/mail-ls");
577161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
578161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira        intent.putExtra(Utils.EXTRA_FOLDER, folder);
579963cdedf714e6e37c7447413cff767b3f2826b28Mindy Pereira        intent.putExtra(Utils.EXTRA_CONVERSATION, conversation);
5809ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        return intent;
5819ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira    }
5829ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira
5839ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira    /**
5849ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     * Create an intent to open a folder.
5859ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     * @param folder Folder to open.
586161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira     * @param account
5879ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     * @return
5889ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     */
589161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira    public static Intent createViewFolderIntent(Folder folder, Account account) {
5909ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        final Intent intent = new Intent(Intent.ACTION_VIEW);
5919ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
592cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira        intent.setDataAndType(folder.uri, "application/mail-ls");
593161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
594963cdedf714e6e37c7447413cff767b3f2826b28Mindy Pereira        intent.putExtra(Utils.EXTRA_FOLDER, folder);
5959ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        return intent;
5969ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira    }
5979ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira
5989ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira    /**
5998a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira     * @return an intent which, if launched, will display the corresponding conversation
6008a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira     */
6018a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira    public static Intent createViewConversationIntent(Context context,
6028a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira            Account account, Folder folder, long conversationId) {
6038a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        final Intent intent = new Intent(Intent.ACTION_VIEW);
6048a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
6058a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        Uri.Builder builder = new Uri.Builder();
6068a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        builder.scheme("content");
6078a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        builder.authority(UIProvider.AUTHORITY);
6088a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        builder.appendEncodedPath("account/" + account);
6098a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        final String intentLabel = folder.name != null ? folder.name
6108a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira                : account.getAccountInbox().name;
6118a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        builder.appendPath("label");
6128a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        builder.appendPath(intentLabel);
6138a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira
6148a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        if (conversationId != UIProvider.INVALID_CONVERSATION_ID) {
6158a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira            builder.appendEncodedPath("conversationId/" + conversationId);
6168a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        }
6178a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        intent.setDataAndType(builder.build(), "application/" + UIProvider.AUTHORITY);
6188a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira
6198a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira        return intent;
6208a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira    }
62194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
62294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    /**
62394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * Helper method to show context-aware Gmail help.
62494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     *
62594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @param context Context to be used to open the help.
62694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @param fromWhere Information about the activity the user was in
62794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * when they requested help.
62894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     */
629cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira    public static void showHelp(Context context, Uri accountHelpUrl, String fromWhere) {
630cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira        final Uri uri = addParamsToUrl(context, accountHelpUrl.toString());
63194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        Uri.Builder builder = uri.buildUpon();
63294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        // Add the activity specific information parameter.
63394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        if (fromWhere != null) {
63494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            builder = builder.appendQueryParameter(SMART_HELP_LINK_PARAMETER_NAME, fromWhere);
63594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        }
63694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
63794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        openUrl(context, builder.build());
63894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    }
63994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
64094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    /**
64194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * Helper method to open a link in a browser.
64294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     *
64394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @param context Context
64494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @param uri Uri to open.
64594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     */
64694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static void openUrl(Context context, Uri uri) {
64794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        if(uri == null || TextUtils.isEmpty(uri.toString())) {
64894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            LogUtils.wtf(LOG_TAG, "invalid url in Utils.openUrl(): %s", uri);
64994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            return;
65094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        }
65194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
65294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
65394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        context.startActivity(intent);
65494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    }
65594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
65694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
65794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static Uri addParamsToUrl(Context context, String url) {
65894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        url = replaceLocale(url);
65994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        Uri.Builder builder = Uri.parse(url).buildUpon();
66094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        final String versionCode = getVersionCode(context);
66194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        if (versionCode != null) {
66294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            builder = builder.appendQueryParameter(SMART_LINK_APP_VERSION, versionCode);
66394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        }
66494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
66594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        return builder.build();
66694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    }
66794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
66894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    /**
66994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * Replaces the language/country of the device into the given string.  The pattern "%locale%"
67094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * will be replaced with the <language_code>_<country_code> value.
67194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     *
67294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @param str the string to replace the language/country within
67394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     *
67494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @return the string with replacement
67594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     */
67694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static String replaceLocale(String str) {
67794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        // Substitute locale if present in string
67894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        if (str.contains("%locale%")) {
67994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            Locale locale = Locale.getDefault();
68094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            String tmp = locale.getLanguage() + "_" + locale.getCountry().toLowerCase();
68194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            str = str.replace("%locale%", tmp);
68294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        }
68394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        return str;
68494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    }
68594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
68694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    /**
68794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * Returns the version code for the package, or null if it cannot be retrieved.
68894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     */
68994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    public static String getVersionCode(Context context) {
69094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        if (sVersionCode == null) {
69194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            try {
69294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook                sVersionCode = String.valueOf(context.getPackageManager()
69394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook                        .getPackageInfo(context.getPackageName(), 0 /* flags */)
69494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook                        .versionCode);
69594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            } catch (NameNotFoundException e) {
69694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook                LogUtils.e(Utils.LOG_TAG, "Error finding package %s",
69794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook                        context.getApplicationInfo().packageName);
69894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            }
69994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        }
70094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        return sVersionCode;
70194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    }
7027b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira}
703