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