Utils.java revision 91d0b86db3287f1702913177d347dd42b7d13764
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 1968f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereiraimport android.app.SearchManager; 206f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.content.Context; 218a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport android.content.Intent; 2294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrookimport android.content.pm.PackageManager.NameNotFoundException; 236f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.content.res.Resources; 24ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huangimport android.database.Cursor; 256f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Typeface; 268a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport android.net.Uri; 279f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrookimport android.os.AsyncTask; 28e4fc81ef363a072480edaced9c89457b8ef019d1Paul Westbrookimport android.os.Build; 29ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huangimport android.os.Bundle; 3094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrookimport android.provider.Browser; 313e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.Html; 323e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.Spannable; 336f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.SpannableString; 346f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.SpannableStringBuilder; 353e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.Spanned; 363e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.TextUtils; 373e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.TextUtils.SimpleStringSplitter; 386f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.CharacterStyle; 396f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.ForegroundColorSpan; 406f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.StyleSpan; 41863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereiraimport android.view.Menu; 42863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereiraimport android.view.MenuItem; 43326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.View; 44326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.View.MeasureSpec; 45f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport android.view.ViewGroup; 468b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereiraimport android.webkit.WebSettings; 478b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereiraimport android.webkit.WebView; 488b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 4930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.R; 508a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport com.android.mail.providers.Account; 519ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereiraimport com.android.mail.providers.Conversation; 528a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport com.android.mail.providers.Folder; 53ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huangimport com.android.mail.providers.UIProvider; 54e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrookimport com.android.mail.providers.UIProvider.EditSettingsExtras; 5510ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blankimport com.google.common.collect.Maps; 563e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira 5792551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport org.json.JSONObject; 5892551d057965689f1952faeb06763f0762bc717fMindy Pereira 5994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrookimport java.util.Locale; 603e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport java.util.Map; 617b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira 626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereirapublic class Utils { 636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira /** 646f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira * longest extension we recognize is 4 characters (e.g. "html", "docx") 656f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira */ 666f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira private static final int FILE_EXTENSION_MAX_CHARS = 4; 673e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira private static final Map<Integer, Integer> sPriorityToLength = Maps.newHashMap(); 683e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira public static final String SENDER_LIST_TOKEN_ELIDED = "e"; 693e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira public static final String SENDER_LIST_TOKEN_NUM_MESSAGES = "n"; 703e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira public static final String SENDER_LIST_TOKEN_NUM_DRAFTS = "d"; 713e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira public static final String SENDER_LIST_TOKEN_LITERAL = "l"; 723e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira public static final String SENDER_LIST_TOKEN_SENDING = "s"; 733e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira public static final String SENDER_LIST_TOKEN_SEND_FAILED = "f"; 743e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira public static final Character SENDER_LIST_SEPARATOR = '\n'; 753e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira public static final SimpleStringSplitter sSenderListSplitter = new SimpleStringSplitter( 763e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira SENDER_LIST_SEPARATOR); 773e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira public static String[] sSenderFragments = new String[8]; 788b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira public static final String EXTRA_ACCOUNT = "account"; 80c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira public static final String EXTRA_ACCOUNT_STRING = "accountString"; 81e144980ef9c8828401922373ef0dc203281bff6ePaul Westbrook public static final String EXTRA_ACCOUNT_URI = "accountUri"; 8291d0b86db3287f1702913177d347dd42b7d13764Marc Blank public static final String EXTRA_FOLDER_URI = "folderUri"; 837418e4b9942f291b8de8bc7b1b72a7ef7130a8b6Mindy Pereira public static final String EXTRA_COMPOSE_URI = "composeUri"; 84963cdedf714e6e37c7447413cff767b3f2826b28Mindy Pereira public static final String EXTRA_CONVERSATION = "conversationUri"; 85963cdedf714e6e37c7447413cff767b3f2826b28Mindy Pereira public static final String EXTRA_FOLDER = "folder"; 86c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira public static final String EXTRA_FOLDER_STRING = "folderString"; 878a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira /* 888a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira * Notifies that changes happened. Certain UI components, e.g., widgets, can 898a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira * register for this {@link Intent} and update accordingly. However, this 908a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira * can be very broad and is NOT the preferred way of getting notification. 918a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira */ 928a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira // TODO: UI Provider has this notification URI? 9394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook public static final String ACTION_NOTIFY_DATASET_CHANGED = 9494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook "com.android.mail.ACTION_NOTIFY_DATASET_CHANGED"; 9594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 9694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook /** Parameter keys for context-aware help. */ 9794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook private static final String SMART_HELP_LINK_PARAMETER_NAME = "p"; 9894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 9994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook private static final String SMART_LINK_APP_VERSION = "version"; 10094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook private static String sVersionCode = null; 10194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 10294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook private static final String LOG_TAG = new LogUtils().getLogTag(); 1036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 104e4fc81ef363a072480edaced9c89457b8ef019d1Paul Westbrook public static boolean isRunningJellybeanOrLater() { 105e4fc81ef363a072480edaced9c89457b8ef019d1Paul Westbrook return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; 106e4fc81ef363a072480edaced9c89457b8ef019d1Paul Westbrook } 107e4fc81ef363a072480edaced9c89457b8ef019d1Paul Westbrook 1082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira /** 1092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * Sets WebView in a restricted mode suitable for email use. 1102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * 1112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * @param webView The WebView to restrict 1122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira */ 1132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static void restrictWebView(WebView webView) { 1148b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira WebSettings webSettings = webView.getSettings(); 1158b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira webSettings.setSavePassword(false); 1168b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira webSettings.setSaveFormData(false); 1178b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira webSettings.setJavaScriptEnabled(true); 1188b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira webSettings.setSupportZoom(false); 1192c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 1202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 1212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira /** 1222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * Format a plural string. 1232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * 1242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * @param resource The identity of the resource, which must be a R.plurals 1252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * @param count The number of items. 1262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira */ 1272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static String formatPlural(Context context, int resource, int count) { 1282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira CharSequence formatString = context.getResources().getQuantityText(resource, count); 1292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return String.format(formatString.toString(), count); 1302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 1312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 1322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira /** 1332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * @return an ellipsized String that's at most maxCharacters long. If the 1342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * text passed is longer, it will be abbreviated. If it contains a 1352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * suffix, the ellipses will be inserted in the middle and the 1362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * suffix will be preserved. 1372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira */ 1382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static String ellipsize(String text, int maxCharacters) { 1392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int length = text.length(); 1402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (length < maxCharacters) 1412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return text; 1422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 1432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int realMax = Math.min(maxCharacters, length); 1442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // Preserve the suffix if any 1452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int index = text.lastIndexOf("."); 1462c47a117415bc4461150f190837e0e94389b7597Mindy Pereira String extension = "\u2026"; // "..."; 1472c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (index >= 0) { 1482c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // Limit the suffix to dot + four characters 1492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (length - index <= FILE_EXTENSION_MAX_CHARS + 1) { 1502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira extension = extension + text.substring(index + 1); 1512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 1522c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 1532c47a117415bc4461150f190837e0e94389b7597Mindy Pereira realMax -= extension.length(); 1542c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (realMax < 0) 1552c47a117415bc4461150f190837e0e94389b7597Mindy Pereira realMax = 0; 1562c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return text.substring(0, realMax) + extension; 1572c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 1582c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 1592c47a117415bc4461150f190837e0e94389b7597Mindy Pereira /** 1604ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * Ensures that the given string starts and ends with the double quote 1614ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * character. The string is not modified in any way except to add the double 1624ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * quote character to start and end if it's not already there. sample -> 1634ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * "sample" "sample" -> "sample" ""sample"" -> "sample" 1644ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * "sample"" -> "sample" sa"mp"le -> "sa"mp"le" "sa"mp"le" -> "sa"mp"le" 1654ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * (empty string) -> "" " -> "" 1664ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira */ 1672c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static String ensureQuotedString(String s) { 1682c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (s == null) { 1692c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return null; 1702c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 1712c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (!s.matches("^\".*\"$")) { 1722c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return "\"" + s + "\""; 1732c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else { 1742c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return s; 1752c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 1762c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 1772c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 1782c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // TODO: Move this to the UI Provider. 1792c47a117415bc4461150f190837e0e94389b7597Mindy Pereira private static CharacterStyle sUnreadStyleSpan = null; 1802c47a117415bc4461150f190837e0e94389b7597Mindy Pereira private static CharacterStyle sReadStyleSpan; 1812c47a117415bc4461150f190837e0e94389b7597Mindy Pereira private static CharacterStyle sDraftsStyleSpan; 1822c47a117415bc4461150f190837e0e94389b7597Mindy Pereira private static CharSequence sMeString; 1832c47a117415bc4461150f190837e0e94389b7597Mindy Pereira private static CharSequence sDraftSingularString; 1842c47a117415bc4461150f190837e0e94389b7597Mindy Pereira private static CharSequence sDraftPluralString; 1852c47a117415bc4461150f190837e0e94389b7597Mindy Pereira private static CharSequence sSendingString; 1862c47a117415bc4461150f190837e0e94389b7597Mindy Pereira private static CharSequence sSendFailedString; 1872c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 1882c47a117415bc4461150f190837e0e94389b7597Mindy Pereira private static int sMaxUnreadCount = -1; 1892c47a117415bc4461150f190837e0e94389b7597Mindy Pereira private static String sUnreadText; 1902c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 1912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static void getStyledSenderSnippet(Context context, String senderInstructions, 1922c47a117415bc4461150f190837e0e94389b7597Mindy Pereira SpannableStringBuilder senderBuilder, SpannableStringBuilder statusBuilder, 1932c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int maxChars, boolean forceAllUnread, boolean forceAllRead, boolean allowDraft) { 1942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira Resources res = context.getResources(); 1952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (sUnreadStyleSpan == null) { 1962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sUnreadStyleSpan = new StyleSpan(Typeface.BOLD); 1972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sReadStyleSpan = new StyleSpan(Typeface.NORMAL); 1982c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sDraftsStyleSpan = new ForegroundColorSpan(res.getColor(R.color.drafts)); 1992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 2002c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sMeString = context.getText(R.string.me); 2012c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sDraftSingularString = res.getQuantityText(R.plurals.draft, 1); 2022c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sDraftPluralString = res.getQuantityText(R.plurals.draft, 2); 2032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira SpannableString sendingString = new SpannableString(context.getText(R.string.sending)); 2042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sendingString.setSpan(CharacterStyle.wrap(sDraftsStyleSpan), 0, sendingString.length(), 2052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 0); 2062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sSendingString = sendingString; 2072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sSendFailedString = context.getText(R.string.send_failed); 2082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 2092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 2102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira getSenderSnippet(senderInstructions, senderBuilder, statusBuilder, maxChars, 2112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sUnreadStyleSpan, sReadStyleSpan, sDraftsStyleSpan, sMeString, 2122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sDraftSingularString, sDraftPluralString, sSendingString, sSendFailedString, 2132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira forceAllUnread, forceAllRead, allowDraft); 2142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 2152c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 2162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira /** 2173e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * Uses sender instructions to build a formatted string. 2183e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <p> 2193e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * Sender list instructions contain compact information about the sender 2203e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * list. Most work that can be done without knowing how much room will be 2213e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * availble for the sender list is done when creating the instructions. 2223e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <p> 2233e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * The instructions string consists of tokens separated by 2243e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * SENDER_LIST_SEPARATOR. Here are the tokens, one per line: 2253e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <ul> 2263e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><tt>n</tt></li> 2273e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><em>int</em>, the number of non-draft messages in the conversation</li> 2283e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><tt>d</tt</li> 2293e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><em>int</em>, the number of drafts in the conversation</li> 2303e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><tt>l</tt></li> 2313e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><em>literal html to be included in the output</em></li> 2323e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><tt>s</tt> indicates that the message is sending (in the outbox 2333e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * without errors)</li> 2343e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><tt>f</tt> indicates that the message failed to send (in the outbox 2353e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * with errors)</li> 2363e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><em>for each message</em> 2373e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <ul> 2383e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><em>int</em>, 0 for read, 1 for unread</li> 2393e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><em>int</em>, the priority of the message. Zero is the most important 2403e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * </li> 2413e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><em>text</em>, the sender text or blank for messages from 'me'</li> 2423e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * </ul> 2433e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * </li> 2443e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <li><tt>e</tt> to indicate that one or more messages have been elided</li> 2453e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * <p> 2463e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * The instructions indicate how many messages and drafts are in the 2473e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * conversation and then describe the most important messages in order, 2483e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * indicating the priority of each message and whether the message is 2493e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * unread. 250f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * 2513e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param instructions instructions as described above 2523e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param senderBuilder the SpannableStringBuilder to append to for sender 2533e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * information 2543e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param statusBuilder the SpannableStringBuilder to append to for status 2553e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param maxChars the number of characters available to display the text 2563e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param unreadStyle the CharacterStyle for unread messages, or null 2573e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param draftsStyle the CharacterStyle for draft messages, or null 2583e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param sendingString the string to use when there are messages scheduled 2593e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * to be sent 2603e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param sendFailedString the string to use when there are messages that 2613e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * mailed to send 2623e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param meString the string to use for messages sent by this user 2633e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param draftString the string to use for "Draft" 2643e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param draftPluralString the string to use for "Drafts" 2653e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira */ 2662c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static synchronized void getSenderSnippet(String instructions, 2672c47a117415bc4461150f190837e0e94389b7597Mindy Pereira SpannableStringBuilder senderBuilder, SpannableStringBuilder statusBuilder, 2682c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int maxChars, CharacterStyle unreadStyle, CharacterStyle readStyle, 2692c47a117415bc4461150f190837e0e94389b7597Mindy Pereira CharacterStyle draftsStyle, CharSequence meString, CharSequence draftString, 2702c47a117415bc4461150f190837e0e94389b7597Mindy Pereira CharSequence draftPluralString, CharSequence sendingString, 2712c47a117415bc4461150f190837e0e94389b7597Mindy Pereira CharSequence sendFailedString, boolean forceAllUnread, boolean forceAllRead, 2722c47a117415bc4461150f190837e0e94389b7597Mindy Pereira boolean allowDraft) { 2732c47a117415bc4461150f190837e0e94389b7597Mindy Pereira assert !(forceAllUnread && forceAllRead); 2742c47a117415bc4461150f190837e0e94389b7597Mindy Pereira boolean unreadStatusIsForced = forceAllUnread || forceAllRead; 2752c47a117415bc4461150f190837e0e94389b7597Mindy Pereira boolean forcedUnreadStatus = forceAllUnread; 2762c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 2772c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // Measure each fragment. It's ok to iterate over the entire set of 2782c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // fragments because it is 2792c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // never a long list, even if there are many senders. 2802c47a117415bc4461150f190837e0e94389b7597Mindy Pereira final Map<Integer, Integer> priorityToLength = sPriorityToLength; 2812c47a117415bc4461150f190837e0e94389b7597Mindy Pereira priorityToLength.clear(); 2822c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 2832c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int maxFoundPriority = Integer.MIN_VALUE; 2842c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int numMessages = 0; 2852c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int numDrafts = 0; 2862c47a117415bc4461150f190837e0e94389b7597Mindy Pereira CharSequence draftsFragment = ""; 2872c47a117415bc4461150f190837e0e94389b7597Mindy Pereira CharSequence sendingFragment = ""; 2882c47a117415bc4461150f190837e0e94389b7597Mindy Pereira CharSequence sendFailedFragment = ""; 2892c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 2902c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sSenderListSplitter.setString(instructions); 2912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int numFragments = 0; 2922c47a117415bc4461150f190837e0e94389b7597Mindy Pereira String[] fragments = sSenderFragments; 2932c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int currentSize = fragments.length; 2942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira while (sSenderListSplitter.hasNext()) { 2952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fragments[numFragments++] = sSenderListSplitter.next(); 2962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (numFragments == currentSize) { 2972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sSenderFragments = new String[2 * currentSize]; 2982c47a117415bc4461150f190837e0e94389b7597Mindy Pereira System.arraycopy(fragments, 0, sSenderFragments, 0, currentSize); 2992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira currentSize *= 2; 3002c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fragments = sSenderFragments; 3012c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3022c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 3042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira for (int i = 0; i < numFragments;) { 3052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira String fragment0 = fragments[i++]; 3062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if ("".equals(fragment0)) { 3072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // This should be the final fragment. 3082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_ELIDED.equals(fragment0)) { 3092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // ignore 3102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_NUM_MESSAGES.equals(fragment0)) { 3112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira numMessages = Integer.valueOf(fragments[i++]); 3122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_NUM_DRAFTS.equals(fragment0)) { 3132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira String numDraftsString = fragments[i++]; 3142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira numDrafts = Integer.parseInt(numDraftsString); 3152c47a117415bc4461150f190837e0e94389b7597Mindy Pereira draftsFragment = numDrafts == 1 ? draftString : draftPluralString + " (" 3162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira + numDraftsString + ")"; 3172c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_LITERAL.equals(fragment0)) { 3182c47a117415bc4461150f190837e0e94389b7597Mindy Pereira senderBuilder.append(Html.fromHtml(fragments[i++])); 3192c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return; 3202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_SENDING.equals(fragment0)) { 3212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sendingFragment = sendingString; 3222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_SEND_FAILED.equals(fragment0)) { 3232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sendFailedFragment = sendFailedString; 3242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else { 3252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira String priorityString = fragments[i++]; 3262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira CharSequence nameString = fragments[i++]; 3272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (nameString.length() == 0) 3282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira nameString = meString; 3292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int priority = Integer.parseInt(priorityString); 3302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira priorityToLength.put(priority, nameString.length()); 3312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira maxFoundPriority = Math.max(maxFoundPriority, priority); 3322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira String numMessagesFragment = (numMessages != 0) ? " \u00A0" 3352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira + Integer.toString(numMessages + numDrafts) : ""; 3362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 3372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // Don't allocate fixedFragment unless we need it 3382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira SpannableStringBuilder fixedFragment = null; 3392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int fixedFragmentLength = 0; 3402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (draftsFragment.length() != 0 && allowDraft) { 3412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (fixedFragment == null) { 3422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fixedFragment = new SpannableStringBuilder(); 3432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fixedFragment.append(draftsFragment); 3452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (draftsStyle != null) { 3462c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fixedFragment.setSpan(CharacterStyle.wrap(draftsStyle), 0, fixedFragment.length(), 3472c47a117415bc4461150f190837e0e94389b7597Mindy Pereira Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 3482c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (sendingFragment.length() != 0) { 3512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (fixedFragment == null) { 3522c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fixedFragment = new SpannableStringBuilder(); 3532c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3542c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (fixedFragment.length() != 0) 3552c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fixedFragment.append(", "); 3562c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fixedFragment.append(sendingFragment); 3572c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3582c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (sendFailedFragment.length() != 0) { 3592c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (fixedFragment == null) { 3602c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fixedFragment = new SpannableStringBuilder(); 3612c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3622c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (fixedFragment.length() != 0) 3632c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fixedFragment.append(", "); 3642c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fixedFragment.append(sendFailedFragment); 3652c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3662c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 3672c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (fixedFragment != null) { 3682c47a117415bc4461150f190837e0e94389b7597Mindy Pereira fixedFragmentLength = fixedFragment.length(); 3692c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3702c47a117415bc4461150f190837e0e94389b7597Mindy Pereira maxChars -= fixedFragmentLength; 3712c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 3722c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int maxPriorityToInclude = -1; // inclusive 3732c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int numCharsUsed = numMessagesFragment.length(); 3742c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int numSendersUsed = 0; 3752c47a117415bc4461150f190837e0e94389b7597Mindy Pereira while (maxPriorityToInclude < maxFoundPriority) { 3762c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (priorityToLength.containsKey(maxPriorityToInclude + 1)) { 3772c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int length = numCharsUsed + priorityToLength.get(maxPriorityToInclude + 1); 3782c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (numCharsUsed > 0) 3792c47a117415bc4461150f190837e0e94389b7597Mindy Pereira length += 2; 3802c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // We must show at least two senders if they exist. If we don't 3812c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // have space for both 3822c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // then we will truncate names. 3832c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (length > maxChars && numSendersUsed >= 2) { 3842c47a117415bc4461150f190837e0e94389b7597Mindy Pereira break; 3852c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3862c47a117415bc4461150f190837e0e94389b7597Mindy Pereira numCharsUsed = length; 3872c47a117415bc4461150f190837e0e94389b7597Mindy Pereira numSendersUsed++; 3882c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3892c47a117415bc4461150f190837e0e94389b7597Mindy Pereira maxPriorityToInclude++; 3902c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 3922c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int numCharsToRemovePerWord = 0; 3932c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (numCharsUsed > maxChars) { 3942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira numCharsToRemovePerWord = (numCharsUsed - maxChars) / numSendersUsed; 3952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 3962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 3972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira String lastFragment = null; 3982c47a117415bc4461150f190837e0e94389b7597Mindy Pereira CharacterStyle lastStyle = null; 3992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira for (int i = 0; i < numFragments;) { 4002c47a117415bc4461150f190837e0e94389b7597Mindy Pereira String fragment0 = fragments[i++]; 4012c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if ("".equals(fragment0)) { 4022c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // This should be the final fragment. 4032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_ELIDED.equals(fragment0)) { 4042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (lastFragment != null) { 4052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira addStyledFragment(senderBuilder, lastFragment, lastStyle, false); 4062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira senderBuilder.append(" "); 4072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira addStyledFragment(senderBuilder, "..", lastStyle, true); 4082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira senderBuilder.append(" "); 4092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira lastFragment = null; 4112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_NUM_MESSAGES.equals(fragment0)) { 4122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira i++; 4132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_NUM_DRAFTS.equals(fragment0)) { 4142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira i++; 4152c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_SENDING.equals(fragment0)) { 4162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (SENDER_LIST_TOKEN_SEND_FAILED.equals(fragment0)) { 4172c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else { 4182c47a117415bc4461150f190837e0e94389b7597Mindy Pereira final String unreadString = fragment0; 4192c47a117415bc4461150f190837e0e94389b7597Mindy Pereira final String priorityString = fragments[i++]; 4202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira String nameString = fragments[i++]; 4212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (nameString.length() == 0) { 4222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira nameString = meString.toString(); 4232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else { 4242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira nameString = Html.fromHtml(nameString).toString(); 4252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (numCharsToRemovePerWord != 0) { 4272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira nameString = nameString.substring(0, 4282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira Math.max(nameString.length() - numCharsToRemovePerWord, 0)); 4292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira final boolean unread = unreadStatusIsForced ? forcedUnreadStatus : Integer 4312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira .parseInt(unreadString) != 0; 4322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira final int priority = Integer.parseInt(priorityString); 4332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (priority <= maxPriorityToInclude) { 4342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (lastFragment != null && !lastFragment.equals(nameString)) { 4352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira addStyledFragment(senderBuilder, lastFragment.concat(","), lastStyle, 4362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira false); 4372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira senderBuilder.append(" "); 4382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira lastFragment = nameString; 4402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira lastStyle = unread ? unreadStyle : readStyle; 4412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else { 4422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (lastFragment != null) { 4432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira addStyledFragment(senderBuilder, lastFragment, lastStyle, false); 4442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // Adjacent spans can cause the TextView in Gmail widget 4452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // confused and leads to weird behavior on scrolling. 4462c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // Our workaround here is to separate the spans by 4472c47a117415bc4461150f190837e0e94389b7597Mindy Pereira // spaces. 4482c47a117415bc4461150f190837e0e94389b7597Mindy Pereira senderBuilder.append(" "); 4492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira addStyledFragment(senderBuilder, "..", lastStyle, true); 4502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira senderBuilder.append(" "); 4512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4522c47a117415bc4461150f190837e0e94389b7597Mindy Pereira lastFragment = null; 4532c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4542c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4552c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4562c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (lastFragment != null) { 4572c47a117415bc4461150f190837e0e94389b7597Mindy Pereira addStyledFragment(senderBuilder, lastFragment, lastStyle, false); 4582c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4592c47a117415bc4461150f190837e0e94389b7597Mindy Pereira senderBuilder.append(numMessagesFragment); 4602c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (fixedFragmentLength != 0) { 4612c47a117415bc4461150f190837e0e94389b7597Mindy Pereira statusBuilder.append(fixedFragment); 4622c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4632c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 4646f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira 4653e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira /** 4663e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * Adds a fragment with given style to a string builder. 467f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * 4683e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param builder the current string builder 4693e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param fragment the fragment to be added 4703e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param style the style of the fragment 4713e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * @param withSpaces whether to add the whole fragment or to divide it into 4723e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira * smaller ones 4733e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira */ 4743e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira private static void addStyledFragment(SpannableStringBuilder builder, String fragment, 4753e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira CharacterStyle style, boolean withSpaces) { 4763e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira if (withSpaces) { 4773e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira int pos = builder.length(); 4783e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira builder.append(fragment); 4793e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira builder.setSpan(CharacterStyle.wrap(style), pos, builder.length(), 4803e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 4813e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira } else { 4823e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira int start = 0; 4833e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira while (true) { 4843e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira int pos = fragment.substring(start).indexOf(' '); 4853e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira if (pos == -1) { 4863e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira addStyledFragment(builder, fragment.substring(start), style, true); 4873e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira break; 4883e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira } else { 4893e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira pos += start; 4903e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira if (start < pos) { 4913e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira addStyledFragment(builder, fragment.substring(start, pos), style, true); 4923e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira builder.append(' '); 4933e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira } 4943e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira start = pos + 1; 4953e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira if (start >= fragment.length()) { 4963e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira break; 4973e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira } 4983e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira } 4993e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira } 5003e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira } 5013e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira } 5023e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira 5032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira /** 5042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * Returns a boolean indicating whether the table UI should be shown. 5052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira */ 5062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static boolean useTabletUI(Context context) { 5072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return context.getResources().getInteger(R.integer.use_tablet_ui) != 0; 5082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 5092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 5102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira /** 5112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * Perform a simulated measure pass on the given child view, assuming the 5122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * child has a ViewGroup parent and that it should be laid out within that 5132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * parent with a matching width but variable height. Code largely lifted 5142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * from AnimatedAdapter.measureChildHeight(). 515f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * 5162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * @param child a child view that has already been placed within its parent 5172c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * ViewGroup 5182c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * @param parent the parent ViewGroup of child 5192c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * @return measured height of the child in px 5202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira */ 5212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static int measureViewHeight(View child, ViewGroup parent) { 5222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int parentWSpec = MeasureSpec.makeMeasureSpec(parent.getWidth(), MeasureSpec.EXACTLY); 5232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int wSpec = ViewGroup.getChildMeasureSpec(parentWSpec, 5242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira parent.getPaddingLeft() + parent.getPaddingRight(), 5252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira ViewGroup.LayoutParams.MATCH_PARENT); 5262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira int hSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 5272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira child.measure(wSpec, hSpec); 5282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return child.getMeasuredHeight(); 5292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 530326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 53146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 53246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Encode the string in HTML. 53346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * 53446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param removeEmptyDoubleQuotes If true, also remove any occurrence of "" 53546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * found in the string 53646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 5372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static Object cleanUpString(String string, boolean removeEmptyDoubleQuotes) { 5382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return !TextUtils.isEmpty(string) ? TextUtils.htmlEncode(removeEmptyDoubleQuotes ? string 5392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira .replace("\"\"", "") : string) : ""; 5402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 5412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 5422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira /** 5432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * Returns comma seperated strings as an array. 5442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira */ 5452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static String[] splitCommaSeparatedString(String str) { 5462c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return TextUtils.isEmpty(str) ? new String[0] : TextUtils.split(str, ","); 5472c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 5482c47a117415bc4461150f190837e0e94389b7597Mindy Pereira 5492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira /** 5502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira * Get the correct display string for the unread count of a folder. 5512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira */ 5522c47a117415bc4461150f190837e0e94389b7597Mindy Pereira public static String getUnreadCountString(Context context, int unreadCount) { 5532c47a117415bc4461150f190837e0e94389b7597Mindy Pereira String unreadCountString; 5542c47a117415bc4461150f190837e0e94389b7597Mindy Pereira Resources resources = context.getResources(); 5552c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (sMaxUnreadCount == -1) { 5562c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sMaxUnreadCount = resources.getInteger(R.integer.maxUnreadCount); 5572c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 5582c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (unreadCount > sMaxUnreadCount) { 5592c47a117415bc4461150f190837e0e94389b7597Mindy Pereira if (sUnreadText == null) { 5602c47a117415bc4461150f190837e0e94389b7597Mindy Pereira sUnreadText = resources.getString(R.string.widget_large_unread_count); 5612c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 5622c47a117415bc4461150f190837e0e94389b7597Mindy Pereira unreadCountString = String.format(sUnreadText, sMaxUnreadCount); 5632c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else if (unreadCount <= 0) { 5642c47a117415bc4461150f190837e0e94389b7597Mindy Pereira unreadCountString = ""; 5652c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } else { 5662c47a117415bc4461150f190837e0e94389b7597Mindy Pereira unreadCountString = String.valueOf(unreadCount); 5672c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 5682c47a117415bc4461150f190837e0e94389b7597Mindy Pereira return unreadCountString; 5692c47a117415bc4461150f190837e0e94389b7597Mindy Pereira } 57028beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira 57128beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira /** 57228beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira * Get text matching the last sync status. 57328beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira */ 57428beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira public static CharSequence getSyncStatusText(Context context, int status) { 57528beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira String[] errors = context.getResources().getStringArray(R.array.sync_status); 57628beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira if (status >= errors.length) { 57728beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira return ""; 57828beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira } 57928beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira return errors[status]; 58028beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira } 5818a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira 5828a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira /** 5839ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira * Create an intent to show a conversation. 5849ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira * @param conversation Conversation to open. 585161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * @param folder 586161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * @param account 5879ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira * @return 5889ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira */ 589161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira public static Intent createViewConversationIntent(Conversation conversation, Folder folder, 590161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira Account account) { 5919ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira final Intent intent = new Intent(Intent.ACTION_VIEW); 5927425d482040c5c2badb466ce840b67396c73f118Paul Westbrook intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | 5937425d482040c5c2badb466ce840b67396c73f118Paul Westbrook Intent.FLAG_ACTIVITY_TASK_ON_HOME); 594898cd38018ff4331e79262451f464efa9dc5d43eMindy Pereira intent.setDataAndType(conversation.uri, account.mimeType); 595161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, account); 596161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira intent.putExtra(Utils.EXTRA_FOLDER, folder); 597963cdedf714e6e37c7447413cff767b3f2826b28Mindy Pereira intent.putExtra(Utils.EXTRA_CONVERSATION, conversation); 5989ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira return intent; 5999ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira } 6009ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira 6019ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira /** 6029ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira * Create an intent to open a folder. 603c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira * 6049ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira * @param folder Folder to open. 605161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * @param account 606c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira * @param pendingIntent If this will be used as a pending intent we need to 607c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira * send strings not parcelables. 6089ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira * @return 6099ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira */ 610c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira public static Intent createViewFolderIntent(Folder folder, Account account, 611c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira boolean pendingIntent) { 6129ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira final Intent intent = new Intent(Intent.ACTION_VIEW); 6137425d482040c5c2badb466ce840b67396c73f118Paul Westbrook intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | 6147425d482040c5c2badb466ce840b67396c73f118Paul Westbrook Intent.FLAG_ACTIVITY_TASK_ON_HOME); 615898cd38018ff4331e79262451f464efa9dc5d43eMindy Pereira intent.setDataAndType(folder.uri, account.mimeType); 616c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira if (pendingIntent) { 617c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT_STRING, account.serialize()); 618c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira intent.putExtra(Utils.EXTRA_FOLDER_STRING, folder.serialize()); 619c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira } else { 620c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, account); 621c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira intent.putExtra(Utils.EXTRA_FOLDER, folder); 622c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira } 6239ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira return intent; 6249ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira } 6259ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira 6269ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira /** 62794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * Helper method to show context-aware Gmail help. 62894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * 62994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * @param context Context to be used to open the help. 63094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * @param fromWhere Information about the activity the user was in 63194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * when they requested help. 63294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook */ 633498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook public static void showHelp(Context context, Account account, String fromWhere) { 634498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook if (account == null || account.helpIntentUri == null) { 635498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook LogUtils.e(LOG_TAG, "unable to show help for account: %s", account); 636498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook return; 637498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook } 638498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook final Uri uri = addParamsToUrl(context, account.helpIntentUri.toString()); 63994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook Uri.Builder builder = uri.buildUpon(); 64094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook // Add the activity specific information parameter. 64194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook if (fromWhere != null) { 64294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook builder = builder.appendQueryParameter(SMART_HELP_LINK_PARAMETER_NAME, fromWhere); 64394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 64494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 64594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook openUrl(context, builder.build()); 64694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 64794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 64894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook /** 64994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * Helper method to open a link in a browser. 65094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * 65194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * @param context Context 65294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * @param uri Uri to open. 65394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook */ 65494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook private static void openUrl(Context context, Uri uri) { 65594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook if(uri == null || TextUtils.isEmpty(uri.toString())) { 65694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook LogUtils.wtf(LOG_TAG, "invalid url in Utils.openUrl(): %s", uri); 65794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook return; 65894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 65994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook Intent intent = new Intent(Intent.ACTION_VIEW, uri); 66094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); 66194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook context.startActivity(intent); 66294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 66394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 66494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 66594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook private static Uri addParamsToUrl(Context context, String url) { 66694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook url = replaceLocale(url); 66794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook Uri.Builder builder = Uri.parse(url).buildUpon(); 66894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook final String versionCode = getVersionCode(context); 66994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook if (versionCode != null) { 67094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook builder = builder.appendQueryParameter(SMART_LINK_APP_VERSION, versionCode); 67194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 67294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 67394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook return builder.build(); 67494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 67594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 67694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook /** 67794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * Replaces the language/country of the device into the given string. The pattern "%locale%" 67894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * will be replaced with the <language_code>_<country_code> value. 67994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * 68094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * @param str the string to replace the language/country within 68194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * 68294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * @return the string with replacement 68394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook */ 68494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook private static String replaceLocale(String str) { 68594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook // Substitute locale if present in string 68694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook if (str.contains("%locale%")) { 68794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook Locale locale = Locale.getDefault(); 68894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook String tmp = locale.getLanguage() + "_" + locale.getCountry().toLowerCase(); 68994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook str = str.replace("%locale%", tmp); 69094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 69194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook return str; 69294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 69394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 69494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook /** 69594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook * Returns the version code for the package, or null if it cannot be retrieved. 69694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook */ 69794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook public static String getVersionCode(Context context) { 69894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook if (sVersionCode == null) { 69994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook try { 70094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook sVersionCode = String.valueOf(context.getPackageManager() 70194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook .getPackageInfo(context.getPackageName(), 0 /* flags */) 70294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook .versionCode); 70394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } catch (NameNotFoundException e) { 70494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook LogUtils.e(Utils.LOG_TAG, "Error finding package %s", 70594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook context.getApplicationInfo().packageName); 70694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 70794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 70894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook return sVersionCode; 70994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 7101f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira 7111f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira /** 7121f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira * Show the settings screen for the supplied account. 7131f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira */ 7141f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira public static void showSettings(Context context, Account account) { 7151f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira final Intent settingsIntent = new Intent(Intent.ACTION_EDIT, account.settingsIntentUri); 7161f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira context.startActivity(settingsIntent); 7171f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira } 71868f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira 71968f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira /** 720e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook * Show the settings screen for the supplied account. 721e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook */ 722e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook public static void showFolderSettings(Context context, Account account, Folder folder) { 7233580f1c5d39bd2131511bdd7ab6d1e2c6246e53ePaul Westbrook if (account == null || folder == null) { 7243580f1c5d39bd2131511bdd7ab6d1e2c6246e53ePaul Westbrook LogUtils.e(LOG_TAG, "Invalid attempt to show folder settings. account: %s folder: %s", 7253580f1c5d39bd2131511bdd7ab6d1e2c6246e53ePaul Westbrook account, folder); 7263580f1c5d39bd2131511bdd7ab6d1e2c6246e53ePaul Westbrook return; 7273580f1c5d39bd2131511bdd7ab6d1e2c6246e53ePaul Westbrook } 7283580f1c5d39bd2131511bdd7ab6d1e2c6246e53ePaul Westbrook final Intent settingsIntent = new Intent(Intent.ACTION_EDIT, account.settingsIntentUri); 729e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook 7303580f1c5d39bd2131511bdd7ab6d1e2c6246e53ePaul Westbrook settingsIntent.putExtra(EditSettingsExtras.EXTRA_ACCOUNT, account); 7313580f1c5d39bd2131511bdd7ab6d1e2c6246e53ePaul Westbrook settingsIntent.putExtra(EditSettingsExtras.EXTRA_FOLDER, folder); 732e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook 7333580f1c5d39bd2131511bdd7ab6d1e2c6246e53ePaul Westbrook context.startActivity(settingsIntent); 734e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook } 735e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook 736e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook /** 73718babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook * Show the settings screen for managing all folders. 73818babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook */ 73918babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook public static void showManageFolder(Context context, Account account) { 74018babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook if (account == null) { 74118babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook LogUtils.e(LOG_TAG, "Invalid attempt to the manage folders screen with null account"); 74218babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook return; 74318babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook } 74418babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook final Intent settingsIntent = new Intent(Intent.ACTION_EDIT, account.settingsIntentUri); 74518babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook 74618babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook settingsIntent.putExtra(EditSettingsExtras.EXTRA_ACCOUNT, account); 74718babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook settingsIntent.putExtra(EditSettingsExtras.EXTRA_MANAGE_FOLDERS, true); 74818babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook 74918babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook context.startActivity(settingsIntent); 75018babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook } 75118babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook 75218babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook /** 753fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira * Show the feedback screen for the supplied account. 754fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira */ 755fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira public static void sendFeedback(Context context, Account account) { 7563ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (account.sendFeedbackIntentUri != null) { 7573ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira openUrl(context, account.sendFeedbackIntentUri); 7583ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 759fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 760fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira 761fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira /** 76268f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira * Retrieves the mailbox search query associated with an intent (or null if not available), 76368f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira * doing proper sanitizing (e.g. trims whitespace). 76468f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira */ 76568f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira public static String mailSearchQueryForIntent(Intent intent) { 76668f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira String query = intent.getStringExtra(SearchManager.QUERY); 76768f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira return TextUtils.isEmpty(query) ? null : query.trim(); 76868f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira } 76988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang 77088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang /** 77188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * Split out a filename's extension and return it. 77288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * @param filename a file name 77388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * @return the file extension (max of 5 chars including period, like ".docx"), or null 77488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang */ 77596f6bed5c71d3cec9725ee3efc6465176c3023a8Mindy Pereira public static String getFileExtension(String filename) { 77688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang String extension = null; 77796f6bed5c71d3cec9725ee3efc6465176c3023a8Mindy Pereira int index = !TextUtils.isEmpty(filename) ? filename.lastIndexOf('.') : -1; 77888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang // Limit the suffix to dot + four characters 77988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang if (index >= 0 && filename.length() - index <= FILE_EXTENSION_MAX_CHARS + 1) { 78088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang extension = filename.substring(index); 78188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang } 78288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang return extension; 78388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang } 78488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang 78588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang /** 78688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * (copied from {@link Intent#normalizeMimeType(String)} for pre-J) 78788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 78888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * Normalize a MIME data type. 78988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 79088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * <p>A normalized MIME type has white-space trimmed, 79188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * content-type parameters removed, and is lower-case. 79288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * This aligns the type with Android best practices for 79388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * intent filtering. 79488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 79588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * <p>For example, "text/plain; charset=utf-8" becomes "text/plain". 79688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * "text/x-vCard" becomes "text/x-vcard". 79788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 79888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * <p>All MIME types received from outside Android (such as user input, 79988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * or external sources like Bluetooth, NFC, or the Internet) should 80088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * be normalized before they are used to create an Intent. 80188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 80288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * @param type MIME data type to normalize 80388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * @return normalized MIME data type, or null if the input was null 80488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * @see {@link #setType} 80588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * @see {@link #setTypeAndNormalize} 80688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang */ 80788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang public static String normalizeMimeType(String type) { 80888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang if (type == null) { 80988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang return null; 81088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang } 81188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang 81288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang type = type.trim().toLowerCase(Locale.US); 81388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang 81488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang final int semicolonIndex = type.indexOf(';'); 81588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang if (semicolonIndex != -1) { 81688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang type = type.substring(0, semicolonIndex); 81788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang } 81888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang return type; 81988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang } 82088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang 82188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang /** 82288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * (copied from {@link Uri#normalize()} for pre-J) 82388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 82488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * Return a normalized representation of this Uri. 82588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 82688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * <p>A normalized Uri has a lowercase scheme component. 82788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * This aligns the Uri with Android best practices for 82888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * intent filtering. 82988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 83088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * <p>For example, "HTTP://www.android.com" becomes 83188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * "http://www.android.com" 83288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 83388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * <p>All URIs received from outside Android (such as user input, 83488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * or external sources like Bluetooth, NFC, or the Internet) should 83588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * be normalized before they are used to create an Intent. 83688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 83788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * <p class="note">This method does <em>not</em> validate bad URI's, 83888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * or 'fix' poorly formatted URI's - so do not use it for input validation. 83988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * A Uri will always be returned, even if the Uri is badly formatted to 84088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * begin with and a scheme component cannot be found. 84188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * 84288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * @return normalized Uri (never null) 84388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * @see {@link android.content.Intent#setData} 84488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang * @see {@link #setNormalizedData} 84588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang */ 84688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang public static Uri normalizeUri(Uri uri) { 84788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang String scheme = uri.getScheme(); 84888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang if (scheme == null) return uri; // give up 84988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang String lowerScheme = scheme.toLowerCase(Locale.US); 85088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang if (scheme.equals(lowerScheme)) return uri; // no change 85188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang 85288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang return uri.buildUpon().scheme(lowerScheme).build(); 85388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang } 85488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang 85588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang public static Intent setIntentTypeAndNormalize(Intent intent, String type) { 85688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang return intent.setType(normalizeMimeType(type)); 85788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang } 85888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang 85988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang public static Intent setIntentDataAndTypeAndNormalize(Intent intent, Uri data, String type) { 86088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang return intent.setDataAndType(normalizeUri(data), normalizeMimeType(type)); 86188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang } 86288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang 863b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira public static int getTransparentColor(int color) { 864b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira return 0x00ffffff & color; 865b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira } 866863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira 867863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira public static void setMenuItemVisibility(Menu menu, int itemId, boolean shouldShow) { 868863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira final MenuItem item = menu.findItem(itemId); 869863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira if (item == null) { 870863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira return; 871863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira } 872863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira item.setVisible(shouldShow); 873863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira } 87492551d057965689f1952faeb06763f0762bc717fMindy Pereira 87592551d057965689f1952faeb06763f0762bc717fMindy Pereira /** 87692551d057965689f1952faeb06763f0762bc717fMindy Pereira * Parse a string (possibly null or empty) into a URI. If the string is null 87792551d057965689f1952faeb06763f0762bc717fMindy Pereira * or empty, null is returned back. Otherwise an empty URI is returned. 87892551d057965689f1952faeb06763f0762bc717fMindy Pereira * 87992551d057965689f1952faeb06763f0762bc717fMindy Pereira * @param uri 88092551d057965689f1952faeb06763f0762bc717fMindy Pereira * @return a valid URI, possibly {@link android.net.Uri#EMPTY} 88192551d057965689f1952faeb06763f0762bc717fMindy Pereira */ 88292551d057965689f1952faeb06763f0762bc717fMindy Pereira public static Uri getValidUri(String uri) { 883df886e7ba9eefd9a261e7cc95a5999fe0fde5351Marc Blank if (uri == null || uri == JSONObject.NULL) 88492551d057965689f1952faeb06763f0762bc717fMindy Pereira return Uri.EMPTY; 88592551d057965689f1952faeb06763f0762bc717fMindy Pereira return Uri.parse(uri); 88692551d057965689f1952faeb06763f0762bc717fMindy Pereira } 88710ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blank 88810ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blank public static boolean isEmpty(Uri uri) { 88910ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blank return uri == null || uri.equals(Uri.EMPTY); 89010ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blank } 891ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang 892ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang public static boolean executeConversationCursorCommand(Cursor cursor, String commandKey, 893ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang boolean value) { 894ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang final Bundle params = new Bundle(); 895ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang params.putBoolean(commandKey, value); 896ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang final Bundle response = cursor.respond(params); 897ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang final String result = response.getString(commandKey, 898ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang UIProvider.ConversationCursorCommand.COMMAND_RESPONSE_FAILED); 899ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang 900ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang return UIProvider.ConversationCursorCommand.COMMAND_RESPONSE_OK.equals(result); 901ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang } 902ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang 903ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang /** 904ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang * Commands a cursor representing a set of conversations to disable any network requests it may 905ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang * do as clients move through the cursor. 906ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang * 907ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang * @param cursor a conversation cursor 908ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang * @return true iff the provider supports network requests and they were previously enabled 909ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang */ 910ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang public static boolean disableConversationCursorNetworkAccess(Cursor cursor) { 911ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang return executeConversationCursorCommand(cursor, 912ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang UIProvider.ConversationCursorCommand.COMMAND_KEY_ALLOW_NETWORK_ACCESS, false); 913ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang } 914ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang 915ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang /** 916ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang * Commands a cursor representing a set of conversations to [re-]enable any network requests it 917ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang * may do as clients move through the cursor. 918ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang * 919ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang * @param cursor a conversation cursor 920ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang * @return true iff the provider supports network requests and they are successfully enabled 921ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang */ 922ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang public static boolean enableConversationCursorNetworkAccess(Cursor cursor) { 923ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang return executeConversationCursorCommand(cursor, 924ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang UIProvider.ConversationCursorCommand.COMMAND_KEY_ALLOW_NETWORK_ACCESS, true); 925ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang } 9269f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook 9279f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook /** 9289f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook * Commands a cursor representing a set of conversations to set its visibility state. 9299f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook * 9309f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook * @param cursor a conversation cursor 9319f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook */ 9329f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook public static void setConversationCursorVisibility(Cursor cursor, boolean visible) { 9339f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook new MarkConversationCursorVisibleTask(cursor, visible).execute(); 9349f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 9359f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook 9369f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook /** 9379f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook * Async task for marking conversations "seen" 9389f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook */ 9399f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook private static class MarkConversationCursorVisibleTask extends AsyncTask<Void, Void, Void> { 9409f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook private final Cursor mCursor; 9419f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook private final boolean mVisible; 9429f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook 9439f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook public MarkConversationCursorVisibleTask(Cursor cursor, boolean visible) { 9449f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook mCursor = cursor; 9459f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook mVisible = visible; 9469f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 9479f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook 9489f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook @Override 9499f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook protected Void doInBackground(Void... params) { 9509f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook if (mCursor != null) { 9519f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook executeConversationCursorCommand(mCursor, 9529f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook UIProvider.ConversationCursorCommand.COMMAND_KEY_SET_VISIBILITY, mVisible); 9539f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 9549f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook return null; 9559f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 9569f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 9579fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira 9589fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira /** 9599fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira * @return whether to show two pane or single pane search results. 9609fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira */ 9619fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira public static boolean showTwoPaneSearchResults(Context context) { 9629fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira return context.getResources().getBoolean(R.bool.show_two_pane_search_results); 9639fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira } 9647b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira} 965