Utils.java revision d878a84ca3e1046fe39c61cc5da501982f85885e
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
19f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedyimport com.google.android.common.html.parser.HtmlDocument;
20f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedyimport com.google.android.common.html.parser.HtmlParser;
21f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedyimport com.google.android.common.html.parser.HtmlTree;
22f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedyimport com.google.android.common.html.parser.HtmlTreeBuilder;
23f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedyimport com.google.common.collect.Maps;
24f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy
25bb9dd6b315c2b3a5816c8f52418a991c5c1b70fdAndy Huangimport android.app.Fragment;
2668f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereiraimport android.app.SearchManager;
276f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.content.Context;
288a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport android.content.Intent;
2909400efa442422299acf21abe20e3470f9d965abScott Kennedyimport android.content.pm.PackageInfo;
3094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrookimport android.content.pm.PackageManager.NameNotFoundException;
316f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.content.res.Resources;
32ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huangimport android.database.Cursor;
3383e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport android.graphics.Bitmap;
346f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Typeface;
358a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport android.net.Uri;
369f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrookimport android.os.AsyncTask;
37e4fc81ef363a072480edaced9c89457b8ef019d1Paul Westbrookimport android.os.Build;
38ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huangimport android.os.Bundle;
3994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrookimport android.provider.Browser;
403e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.Spannable;
416f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.SpannableString;
426f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.SpannableStringBuilder;
433e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.Spanned;
443e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.TextUtils;
453e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport android.text.TextUtils.SimpleStringSplitter;
466f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.CharacterStyle;
476f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.ForegroundColorSpan;
486f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.StyleSpan;
49863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereiraimport android.view.Menu;
50863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereiraimport android.view.MenuItem;
51326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.View;
52326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.View.MeasureSpec;
53f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport android.view.ViewGroup;
5418264b956bedb710e94e809a7fa30ad096021c10Andy Huangimport android.view.ViewGroup.MarginLayoutParams;
5583e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport android.view.Window;
568b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereiraimport android.webkit.WebSettings;
578b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereiraimport android.webkit.WebView;
588b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira
5930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.R;
60a13b3742522987f768ef9a1a1cddd32ff8105f0ePaul Westbrookimport com.android.mail.browse.ConversationCursor;
61f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedyimport com.android.mail.compose.ComposeActivity;
62243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huangimport com.android.mail.perf.SimpleTimer;
638a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport com.android.mail.providers.Account;
649ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereiraimport com.android.mail.providers.Conversation;
658a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereiraimport com.android.mail.providers.Folder;
66ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huangimport com.android.mail.providers.UIProvider;
67e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrookimport com.android.mail.providers.UIProvider.EditSettingsExtras;
6883e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport com.android.mail.ui.FeedbackEnabledActivity;
693e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira
7092551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport org.json.JSONObject;
7192551d057965689f1952faeb06763f0762bc717fMindy Pereira
72bb9dd6b315c2b3a5816c8f52418a991c5c1b70fdAndy Huangimport java.io.FileDescriptor;
73bb9dd6b315c2b3a5816c8f52418a991c5c1b70fdAndy Huangimport java.io.PrintWriter;
74bb9dd6b315c2b3a5816c8f52418a991c5c1b70fdAndy Huangimport java.io.StringWriter;
7594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrookimport java.util.Locale;
763e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereiraimport java.util.Map;
777b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
786f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereirapublic class Utils {
796f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    /**
806f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     * longest extension we recognize is 4 characters (e.g. "html", "docx")
816f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     */
826f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final int FILE_EXTENSION_MAX_CHARS = 4;
833e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    private static final Map<Integer, Integer> sPriorityToLength = Maps.newHashMap();
843e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_ELIDED = "e";
853e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_NUM_MESSAGES = "n";
863e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_NUM_DRAFTS = "d";
873e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_LITERAL = "l";
883e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_SENDING = "s";
893e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final String SENDER_LIST_TOKEN_SEND_FAILED = "f";
903e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final Character SENDER_LIST_SEPARATOR = '\n';
913e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static final SimpleStringSplitter sSenderListSplitter = new SimpleStringSplitter(
923e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            SENDER_LIST_SEPARATOR);
933e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    public static String[] sSenderFragments = new String[8];
948b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira
956349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    public static final String EXTRA_ACCOUNT = "account";
96e144980ef9c8828401922373ef0dc203281bff6ePaul Westbrook    public static final String EXTRA_ACCOUNT_URI = "accountUri";
9791d0b86db3287f1702913177d347dd42b7d13764Marc Blank    public static final String EXTRA_FOLDER_URI = "folderUri";
9848cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy    public static final String EXTRA_FOLDER = "folder";
997418e4b9942f291b8de8bc7b1b72a7ef7130a8b6Mindy Pereira    public static final String EXTRA_COMPOSE_URI = "composeUri";
100963cdedf714e6e37c7447413cff767b3f2826b28Mindy Pereira    public static final String EXTRA_CONVERSATION = "conversationUri";
1017517e3b61b898a57f19be0671f70d58a82224643Andy Huang
1027517e3b61b898a57f19be0671f70d58a82224643Andy Huang    /** Extra tag for debugging the blank fragment problem. */
1037517e3b61b898a57f19be0671f70d58a82224643Andy Huang    public static final String VIEW_DEBUGGING_TAG = "MailBlankFragment";
1047517e3b61b898a57f19be0671f70d58a82224643Andy Huang
1058a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira    /*
1068a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira     * Notifies that changes happened. Certain UI components, e.g., widgets, can
1078a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira     * register for this {@link Intent} and update accordingly. However, this
1088a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira     * can be very broad and is NOT the preferred way of getting notification.
1098a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira     */
1108a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira    // TODO: UI Provider has this notification URI?
11194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    public static final String ACTION_NOTIFY_DATASET_CHANGED =
11294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            "com.android.mail.ACTION_NOTIFY_DATASET_CHANGED";
11394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
11494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    /** Parameter keys for context-aware help. */
11594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static final String SMART_HELP_LINK_PARAMETER_NAME = "p";
11694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
11794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static final String SMART_LINK_APP_VERSION = "version";
118fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy    private static int sVersionCode = -1;
11994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
12083e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    private static final int SCALED_SCREENSHOT_MAX_HEIGHT_WIDTH = 600;
12183e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook
12209400efa442422299acf21abe20e3470f9d965abScott Kennedy    private static final String APP_VERSION_QUERY_PARAMETER = "appVersion";
12309400efa442422299acf21abe20e3470f9d965abScott Kennedy
124b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
1256349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
126243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang    public static final boolean ENABLE_CONV_LOAD_TIMER = false;
127243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang    public static final SimpleTimer sConvLoadTimer =
128243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang            new SimpleTimer(ENABLE_CONV_LOAD_TIMER).withSessionName("ConvLoadTimer");
129243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang
130e4fc81ef363a072480edaced9c89457b8ef019d1Paul Westbrook    public static boolean isRunningJellybeanOrLater() {
131e4fc81ef363a072480edaced9c89457b8ef019d1Paul Westbrook        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
132e4fc81ef363a072480edaced9c89457b8ef019d1Paul Westbrook    }
133e4fc81ef363a072480edaced9c89457b8ef019d1Paul Westbrook
1342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
1352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Sets WebView in a restricted mode suitable for email use.
1362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *
1372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @param webView The WebView to restrict
1382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
1392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static void restrictWebView(WebView webView) {
1408b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira        WebSettings webSettings = webView.getSettings();
1418b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira        webSettings.setSavePassword(false);
1428b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira        webSettings.setSaveFormData(false);
1438b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira        webSettings.setJavaScriptEnabled(true);
1448b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira        webSettings.setSupportZoom(false);
1452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
1462c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1472c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
1482c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Format a plural string.
1492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *
1502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @param resource The identity of the resource, which must be a R.plurals
1512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @param count The number of items.
1522c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
1532c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static String formatPlural(Context context, int resource, int count) {
1542c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        CharSequence formatString = context.getResources().getQuantityText(resource, count);
1552c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return String.format(formatString.toString(), count);
1562c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
1572c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1582c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
1592c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @return an ellipsized String that's at most maxCharacters long. If the
1602c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *         text passed is longer, it will be abbreviated. If it contains a
1612c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *         suffix, the ellipses will be inserted in the middle and the
1622c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *         suffix will be preserved.
1632c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
1642c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static String ellipsize(String text, int maxCharacters) {
1652c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int length = text.length();
1662c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (length < maxCharacters)
1672c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            return text;
1682c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1692c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int realMax = Math.min(maxCharacters, length);
1702c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        // Preserve the suffix if any
1712c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int index = text.lastIndexOf(".");
1722c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        String extension = "\u2026"; // "...";
1732c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (index >= 0) {
1742c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            // Limit the suffix to dot + four characters
1752c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (length - index <= FILE_EXTENSION_MAX_CHARS + 1) {
1762c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                extension = extension + text.substring(index + 1);
1772c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
1782c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
1792c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        realMax -= extension.length();
1802c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (realMax < 0)
1812c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            realMax = 0;
1822c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return text.substring(0, realMax) + extension;
1832c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
1842c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
1852c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
1864ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * Ensures that the given string starts and ends with the double quote
1874ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * character. The string is not modified in any way except to add the double
1884ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * quote character to start and end if it's not already there. sample ->
1894ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * "sample" "sample" -> "sample" ""sample"" -> "sample"
1904ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * "sample"" -> "sample" sa"mp"le -> "sa"mp"le" "sa"mp"le" -> "sa"mp"le"
1914ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * (empty string) -> "" " -> ""
1924ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     */
1932c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static String ensureQuotedString(String s) {
1942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (s == null) {
1952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            return null;
1962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
1972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (!s.matches("^\".*\"$")) {
1982c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            return "\"" + s + "\"";
1992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        } else {
2002c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            return s;
2012c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
2022c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
2032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
2042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    // TODO: Move this to the UI Provider.
2052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharacterStyle sUnreadStyleSpan = null;
2062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharacterStyle sReadStyleSpan;
2072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharacterStyle sDraftsStyleSpan;
2082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharSequence sMeString;
2092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharSequence sDraftSingularString;
2102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharSequence sDraftPluralString;
2112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharSequence sSendingString;
2122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static CharSequence sSendFailedString;
2132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
2142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static int sMaxUnreadCount = -1;
2152c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    private static String sUnreadText;
21655137b88f01521d15a0677b7105416bbc6528a49Mindy Pereira    private static int sDefaultFolderBackgroundColor = -1;
2174271bf0350442b594729d3074530bc0d8deac2a2mindyp    private static int sUseFolderListFragmentTransition = -1;
2182c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
2192c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static void getStyledSenderSnippet(Context context, String senderInstructions,
2202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            SpannableStringBuilder senderBuilder, SpannableStringBuilder statusBuilder,
2212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            int maxChars, boolean forceAllUnread, boolean forceAllRead, boolean allowDraft) {
2222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        Resources res = context.getResources();
2232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (sUnreadStyleSpan == null) {
2242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sUnreadStyleSpan = new StyleSpan(Typeface.BOLD);
2252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sReadStyleSpan = new StyleSpan(Typeface.NORMAL);
2262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sDraftsStyleSpan = new ForegroundColorSpan(res.getColor(R.color.drafts));
2272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
2282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sMeString = context.getText(R.string.me);
2292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sDraftSingularString = res.getQuantityText(R.plurals.draft, 1);
2302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sDraftPluralString = res.getQuantityText(R.plurals.draft, 2);
2312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            SpannableString sendingString = new SpannableString(context.getText(R.string.sending));
2322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sendingString.setSpan(CharacterStyle.wrap(sDraftsStyleSpan), 0, sendingString.length(),
2332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    0);
2342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sSendingString = sendingString;
2352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sSendFailedString = context.getText(R.string.send_failed);
2362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
2372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
2382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        getSenderSnippet(senderInstructions, senderBuilder, statusBuilder, maxChars,
2392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sUnreadStyleSpan, sReadStyleSpan, sDraftsStyleSpan, sMeString,
2402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sDraftSingularString, sDraftPluralString, sSendingString, sSendFailedString,
2412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                forceAllUnread, forceAllRead, allowDraft);
2422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
2432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
2442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
2453e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * Uses sender instructions to build a formatted string.
2463e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <p>
2473e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * Sender list instructions contain compact information about the sender
2483e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * list. Most work that can be done without knowing how much room will be
2493e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * availble for the sender list is done when creating the instructions.
2503e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <p>
2513e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * The instructions string consists of tokens separated by
2523e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * SENDER_LIST_SEPARATOR. Here are the tokens, one per line:
2533e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <ul>
2543e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>n</tt></li>
2553e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>int</em>, the number of non-draft messages in the conversation</li>
2563e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>d</tt</li>
2573e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>int</em>, the number of drafts in the conversation</li>
2583e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>l</tt></li>
2593e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>literal html to be included in the output</em></li>
2603e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>s</tt> indicates that the message is sending (in the outbox
2613e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * without errors)</li>
2623e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>f</tt> indicates that the message failed to send (in the outbox
2633e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * with errors)</li>
2643e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>for each message</em>
2653e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <ul>
2663e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>int</em>, 0 for read, 1 for unread</li>
2673e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>int</em>, the priority of the message. Zero is the most important
2683e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * </li>
2693e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><em>text</em>, the sender text or blank for messages from 'me'</li>
2703e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * </ul>
2713e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * </li>
2723e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <li><tt>e</tt> to indicate that one or more messages have been elided</li>
2733e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * <p>
2743e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * The instructions indicate how many messages and drafts are in the
2753e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * conversation and then describe the most important messages in order,
2763e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * indicating the priority of each message and whether the message is
2773e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * unread.
278f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     *
2793e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param instructions instructions as described above
2803e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param senderBuilder the SpannableStringBuilder to append to for sender
2813e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     *            information
2823e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param statusBuilder the SpannableStringBuilder to append to for status
2833e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param maxChars the number of characters available to display the text
2843e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param unreadStyle the CharacterStyle for unread messages, or null
2853e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param draftsStyle the CharacterStyle for draft messages, or null
2863e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param sendingString the string to use when there are messages scheduled
2873e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     *            to be sent
2883e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param sendFailedString the string to use when there are messages that
2893e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     *            mailed to send
2903e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param meString the string to use for messages sent by this user
2913e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param draftString the string to use for "Draft"
2923e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param draftPluralString the string to use for "Drafts"
2933e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     */
2942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static synchronized void getSenderSnippet(String instructions,
2952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            SpannableStringBuilder senderBuilder, SpannableStringBuilder statusBuilder,
2962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            int maxChars, CharacterStyle unreadStyle, CharacterStyle readStyle,
2972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            CharacterStyle draftsStyle, CharSequence meString, CharSequence draftString,
2982c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            CharSequence draftPluralString, CharSequence sendingString,
2992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            CharSequence sendFailedString, boolean forceAllUnread, boolean forceAllRead,
3002c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            boolean allowDraft) {
3012c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        assert !(forceAllUnread && forceAllRead);
3022c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        boolean unreadStatusIsForced = forceAllUnread || forceAllRead;
3032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        boolean forcedUnreadStatus = forceAllUnread;
3042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        // Measure each fragment. It's ok to iterate over the entire set of
3062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        // fragments because it is
3072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        // never a long list, even if there are many senders.
3082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        final Map<Integer, Integer> priorityToLength = sPriorityToLength;
3092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        priorityToLength.clear();
3102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int maxFoundPriority = Integer.MIN_VALUE;
3122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numMessages = 0;
3132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numDrafts = 0;
3142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        CharSequence draftsFragment = "";
3152c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        CharSequence sendingFragment = "";
3162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        CharSequence sendFailedFragment = "";
3172c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3182c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        sSenderListSplitter.setString(instructions);
3192c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numFragments = 0;
3202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        String[] fragments = sSenderFragments;
3212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int currentSize = fragments.length;
3222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        while (sSenderListSplitter.hasNext()) {
3232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            fragments[numFragments++] = sSenderListSplitter.next();
3242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (numFragments == currentSize) {
3252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sSenderFragments = new String[2 * currentSize];
3262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                System.arraycopy(fragments, 0, sSenderFragments, 0, currentSize);
3272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                currentSize *= 2;
3282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fragments = sSenderFragments;
3292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        for (int i = 0; i < numFragments;) {
3332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            String fragment0 = fragments[i++];
3342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if ("".equals(fragment0)) {
3352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // This should be the final fragment.
3362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_ELIDED.equals(fragment0)) {
3372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // ignore
3382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_NUM_MESSAGES.equals(fragment0)) {
3392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                numMessages = Integer.valueOf(fragments[i++]);
3402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_NUM_DRAFTS.equals(fragment0)) {
3412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                String numDraftsString = fragments[i++];
3422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                numDrafts = Integer.parseInt(numDraftsString);
3432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                draftsFragment = numDrafts == 1 ? draftString : draftPluralString + " ("
3442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        + numDraftsString + ")";
3452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_LITERAL.equals(fragment0)) {
346c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                senderBuilder.append(Utils.convertHtmlToPlainText(fragments[i++]));
3472c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                return;
3482c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_SENDING.equals(fragment0)) {
3492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sendingFragment = sendingString;
3502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_SEND_FAILED.equals(fragment0)) {
3512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sendFailedFragment = sendFailedString;
3522c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else {
3532c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                String priorityString = fragments[i++];
3542c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                CharSequence nameString = fragments[i++];
3552c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (nameString.length() == 0)
3562c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    nameString = meString;
3572c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                int priority = Integer.parseInt(priorityString);
3582c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                priorityToLength.put(priority, nameString.length());
3592c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                maxFoundPriority = Math.max(maxFoundPriority, priority);
3602c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3612c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3622c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        String numMessagesFragment = (numMessages != 0) ? " \u00A0"
3632c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                + Integer.toString(numMessages + numDrafts) : "";
3642c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3652c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        // Don't allocate fixedFragment unless we need it
3662c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        SpannableStringBuilder fixedFragment = null;
3672c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int fixedFragmentLength = 0;
3682c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (draftsFragment.length() != 0 && allowDraft) {
3692c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (fixedFragment == null) {
3702c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment = new SpannableStringBuilder();
3712c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3722c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            fixedFragment.append(draftsFragment);
3732c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (draftsStyle != null) {
3742c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment.setSpan(CharacterStyle.wrap(draftsStyle), 0, fixedFragment.length(),
3752c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
3762c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3772c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3782c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (sendingFragment.length() != 0) {
3792c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (fixedFragment == null) {
3802c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment = new SpannableStringBuilder();
3812c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3822c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (fixedFragment.length() != 0)
3832c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment.append(", ");
3842c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            fixedFragment.append(sendingFragment);
3852c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3862c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (sendFailedFragment.length() != 0) {
3872c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (fixedFragment == null) {
3882c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment = new SpannableStringBuilder();
3892c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
3902c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (fixedFragment.length() != 0)
3912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                fixedFragment.append(", ");
3922c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            fixedFragment.append(sendFailedFragment);
3932c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
3952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (fixedFragment != null) {
3962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            fixedFragmentLength = fixedFragment.length();
3972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
3982c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        maxChars -= fixedFragmentLength;
3992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
4002c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int maxPriorityToInclude = -1; // inclusive
4012c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numCharsUsed = numMessagesFragment.length();
4022c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numSendersUsed = 0;
4032c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        while (maxPriorityToInclude < maxFoundPriority) {
4042c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (priorityToLength.containsKey(maxPriorityToInclude + 1)) {
4052c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                int length = numCharsUsed + priorityToLength.get(maxPriorityToInclude + 1);
4062c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (numCharsUsed > 0)
4072c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    length += 2;
4082c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // We must show at least two senders if they exist. If we don't
4092c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // have space for both
4102c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // then we will truncate names.
4112c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (length > maxChars && numSendersUsed >= 2) {
4122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    break;
4132c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                }
4142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                numCharsUsed = length;
4152c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                numSendersUsed++;
4162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
4172c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            maxPriorityToInclude++;
4182c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
4192c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
4202c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        int numCharsToRemovePerWord = 0;
4212c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (numCharsUsed > maxChars) {
4222c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            numCharsToRemovePerWord = (numCharsUsed - maxChars) / numSendersUsed;
4232c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
4242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
4252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        String lastFragment = null;
4262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        CharacterStyle lastStyle = null;
4272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        for (int i = 0; i < numFragments;) {
4282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            String fragment0 = fragments[i++];
4292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if ("".equals(fragment0)) {
4302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                // This should be the final fragment.
4312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_ELIDED.equals(fragment0)) {
4322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (lastFragment != null) {
4332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    addStyledFragment(senderBuilder, lastFragment, lastStyle, false);
4342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    senderBuilder.append(" ");
4352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    addStyledFragment(senderBuilder, "..", lastStyle, true);
4362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    senderBuilder.append(" ");
4372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                }
4382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                lastFragment = null;
4392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_NUM_MESSAGES.equals(fragment0)) {
4402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                i++;
4412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_NUM_DRAFTS.equals(fragment0)) {
4422c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                i++;
4432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_SENDING.equals(fragment0)) {
4442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else if (SENDER_LIST_TOKEN_SEND_FAILED.equals(fragment0)) {
4452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            } else {
4462c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                final String unreadString = fragment0;
4472c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                final String priorityString = fragments[i++];
4482c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                String nameString = fragments[i++];
4492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (nameString.length() == 0) {
4502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    nameString = meString.toString();
4512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                } else {
452c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    nameString = Utils.convertHtmlToPlainText(nameString).toString();
4532c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                }
4542c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (numCharsToRemovePerWord != 0) {
4552c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    nameString = nameString.substring(0,
4562c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                            Math.max(nameString.length() - numCharsToRemovePerWord, 0));
4572c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                }
4582c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                final boolean unread = unreadStatusIsForced ? forcedUnreadStatus : Integer
4592c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        .parseInt(unreadString) != 0;
4602c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                final int priority = Integer.parseInt(priorityString);
4612c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                if (priority <= maxPriorityToInclude) {
4622c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    if (lastFragment != null && !lastFragment.equals(nameString)) {
4632c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        addStyledFragment(senderBuilder, lastFragment.concat(","), lastStyle,
4642c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                                false);
4652c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        senderBuilder.append(" ");
4662c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    }
4672c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    lastFragment = nameString;
4682c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    lastStyle = unread ? unreadStyle : readStyle;
4692c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                } else {
4702c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    if (lastFragment != null) {
4712c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        addStyledFragment(senderBuilder, lastFragment, lastStyle, false);
4722c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        // Adjacent spans can cause the TextView in Gmail widget
4732c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        // confused and leads to weird behavior on scrolling.
4742c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        // Our workaround here is to separate the spans by
4752c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        // spaces.
4762c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        senderBuilder.append(" ");
4772c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        addStyledFragment(senderBuilder, "..", lastStyle, true);
4782c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                        senderBuilder.append(" ");
4792c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    }
4802c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                    lastFragment = null;
4812c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                }
4822c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
4832c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
4842c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (lastFragment != null) {
4852c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            addStyledFragment(senderBuilder, lastFragment, lastStyle, false);
4862c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
4872c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        senderBuilder.append(numMessagesFragment);
4882c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (fixedFragmentLength != 0) {
4892c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            statusBuilder.append(fixedFragment);
4902c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
4912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
4926f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4933e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    /**
4943e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * Adds a fragment with given style to a string builder.
495f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     *
4963e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param builder the current string builder
4973e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param fragment the fragment to be added
4983e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param style the style of the fragment
4993e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     * @param withSpaces whether to add the whole fragment or to divide it into
5003e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     *            smaller ones
5013e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira     */
5023e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    private static void addStyledFragment(SpannableStringBuilder builder, String fragment,
5033e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            CharacterStyle style, boolean withSpaces) {
5043e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira        if (withSpaces) {
5053e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            int pos = builder.length();
5063e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            builder.append(fragment);
5073e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            builder.setSpan(CharacterStyle.wrap(style), pos, builder.length(),
5083e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
5093e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira        } else {
5103e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            int start = 0;
5113e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            while (true) {
5123e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                int pos = fragment.substring(start).indexOf(' ');
5133e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                if (pos == -1) {
5143e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    addStyledFragment(builder, fragment.substring(start), style, true);
5153e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    break;
5163e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                } else {
5173e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    pos += start;
5183e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    if (start < pos) {
5193e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                        addStyledFragment(builder, fragment.substring(start, pos), style, true);
5203e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                        builder.append(' ');
5213e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    }
5223e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    start = pos + 1;
5233e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    if (start >= fragment.length()) {
5243e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                        break;
5253e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                    }
5263e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira                }
5273e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira            }
5283e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira        }
5293e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira    }
5303e0426cceb884d13b5d39b56b2171686a1afdf03Mindy Pereira
5312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
5322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Returns a boolean indicating whether the table UI should be shown.
5332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
534bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal    public static boolean useTabletUI(Resources res) {
535bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal        return res.getInteger(R.integer.use_tablet_ui) != 0;
5362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
5372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
5384271bf0350442b594729d3074530bc0d8deac2a2mindyp    /**
5394271bf0350442b594729d3074530bc0d8deac2a2mindyp     * Returns a boolean indicating whether or not we should animate in the
5404271bf0350442b594729d3074530bc0d8deac2a2mindyp     * folder list fragment.
5414271bf0350442b594729d3074530bc0d8deac2a2mindyp     */
5424271bf0350442b594729d3074530bc0d8deac2a2mindyp    public static boolean useFolderListFragmentTransition(Context context) {
5434271bf0350442b594729d3074530bc0d8deac2a2mindyp        if (sUseFolderListFragmentTransition == -1) {
5444271bf0350442b594729d3074530bc0d8deac2a2mindyp            sUseFolderListFragmentTransition  = context.getResources().getInteger(
5454271bf0350442b594729d3074530bc0d8deac2a2mindyp                    R.integer.use_folder_list_fragment_transition);
5464271bf0350442b594729d3074530bc0d8deac2a2mindyp        }
5474271bf0350442b594729d3074530bc0d8deac2a2mindyp        return sUseFolderListFragmentTransition != 0;
5484271bf0350442b594729d3074530bc0d8deac2a2mindyp    }
5494271bf0350442b594729d3074530bc0d8deac2a2mindyp
5502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
55195141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook     * Returns displayable text from the provided HTML string.
55295141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook     * @param htmlText HTML string
55395141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook     * @return Plain text string representation of the specified Html string
55495141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook     */
55595141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook    public static String convertHtmlToPlainText(String htmlText) {
5569cd585662be55469d4aeae3e0d288b575f9d21faPaul Westbrook        if (TextUtils.isEmpty(htmlText)) {
5579cd585662be55469d4aeae3e0d288b575f9d21faPaul Westbrook            return "";
5589cd585662be55469d4aeae3e0d288b575f9d21faPaul Westbrook        }
559cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp        return getHtmlTree(htmlText, new HtmlParser(), new HtmlTreeBuilder()).getPlainText();
560cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp    }
561cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp
562cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp    public static String convertHtmlToPlainText(String htmlText, HtmlParser parser,
563cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp            HtmlTreeBuilder builder) {
5649cd585662be55469d4aeae3e0d288b575f9d21faPaul Westbrook        if (TextUtils.isEmpty(htmlText)) {
5659cd585662be55469d4aeae3e0d288b575f9d21faPaul Westbrook            return "";
5669cd585662be55469d4aeae3e0d288b575f9d21faPaul Westbrook        }
567cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp        return getHtmlTree(htmlText, parser, builder).getPlainText();
56895141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook    }
56995141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook
57095141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook    /**
57195141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook     * Returns a {@link HtmlTree} representation of the specified HTML string.
57295141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook     */
57395141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook    public static HtmlTree getHtmlTree(String htmlText) {
574cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp        return getHtmlTree(htmlText, new HtmlParser(), new HtmlTreeBuilder());
575cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp    }
576cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp
577cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp    /**
578cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp     * Returns a {@link HtmlTree} representation of the specified HTML string.
579cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp     */
5809cd585662be55469d4aeae3e0d288b575f9d21faPaul Westbrook    private static HtmlTree getHtmlTree(String htmlText, HtmlParser parser,
581cc399081e9f39d6c3238791b7116e36de66e4ac7mindyp            HtmlTreeBuilder builder) {
58295141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook        final HtmlDocument doc = parser.parse(htmlText);
58395141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook        doc.accept(builder);
58495141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook
58595141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook        return builder.getTree();
58695141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook    }
58795141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook
58895141f8887011fcdd647006ddd4f75866a7e1419Paul Westbrook    /**
5892c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Perform a simulated measure pass on the given child view, assuming the
5902c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * child has a ViewGroup parent and that it should be laid out within that
5912c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * parent with a matching width but variable height. Code largely lifted
5922c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * from AnimatedAdapter.measureChildHeight().
593f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     *
5942c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @param child a child view that has already been placed within its parent
5952c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     *            ViewGroup
5962c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @param parent the parent ViewGroup of child
5972c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * @return measured height of the child in px
5982c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
5992c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static int measureViewHeight(View child, ViewGroup parent) {
60018264b956bedb710e94e809a7fa30ad096021c10Andy Huang        final ViewGroup.LayoutParams lp = child.getLayoutParams();
60118264b956bedb710e94e809a7fa30ad096021c10Andy Huang        final int childSideMargin;
60218264b956bedb710e94e809a7fa30ad096021c10Andy Huang        if (lp instanceof MarginLayoutParams) {
60318264b956bedb710e94e809a7fa30ad096021c10Andy Huang            final MarginLayoutParams mlp = (MarginLayoutParams) lp;
60418264b956bedb710e94e809a7fa30ad096021c10Andy Huang            childSideMargin = mlp.leftMargin + mlp.rightMargin;
60518264b956bedb710e94e809a7fa30ad096021c10Andy Huang        } else {
60618264b956bedb710e94e809a7fa30ad096021c10Andy Huang            childSideMargin = 0;
60718264b956bedb710e94e809a7fa30ad096021c10Andy Huang        }
60818264b956bedb710e94e809a7fa30ad096021c10Andy Huang
60918264b956bedb710e94e809a7fa30ad096021c10Andy Huang        final int parentWSpec = MeasureSpec.makeMeasureSpec(parent.getWidth(), MeasureSpec.EXACTLY);
61018264b956bedb710e94e809a7fa30ad096021c10Andy Huang        final int wSpec = ViewGroup.getChildMeasureSpec(parentWSpec,
61118264b956bedb710e94e809a7fa30ad096021c10Andy Huang                parent.getPaddingLeft() + parent.getPaddingRight() + childSideMargin,
6122c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                ViewGroup.LayoutParams.MATCH_PARENT);
61318264b956bedb710e94e809a7fa30ad096021c10Andy Huang        final int hSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
6142c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        child.measure(wSpec, hSpec);
6152c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return child.getMeasuredHeight();
6162c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
617326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
61846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
61946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Encode the string in HTML.
62046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
62146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param removeEmptyDoubleQuotes If true, also remove any occurrence of ""
62246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *            found in the string
62346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
6242c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static Object cleanUpString(String string, boolean removeEmptyDoubleQuotes) {
6252c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return !TextUtils.isEmpty(string) ? TextUtils.htmlEncode(removeEmptyDoubleQuotes ? string
6262c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                .replace("\"\"", "") : string) : "";
6272c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
6282c47a117415bc4461150f190837e0e94389b7597Mindy Pereira
6292c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    /**
6302c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     * Get the correct display string for the unread count of a folder.
6312c47a117415bc4461150f190837e0e94389b7597Mindy Pereira     */
6322c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    public static String getUnreadCountString(Context context, int unreadCount) {
6332c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        String unreadCountString;
6342c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        Resources resources = context.getResources();
6352c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (sMaxUnreadCount == -1) {
6362c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            sMaxUnreadCount = resources.getInteger(R.integer.maxUnreadCount);
6372c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
6382c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        if (unreadCount > sMaxUnreadCount) {
6392c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            if (sUnreadText == null) {
6402c47a117415bc4461150f190837e0e94389b7597Mindy Pereira                sUnreadText = resources.getString(R.string.widget_large_unread_count);
6412c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            }
642d878a84ca3e1046fe39c61cc5da501982f85885eVikram Aggarwal            // Localize "999+" according to the device language
6432c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            unreadCountString = String.format(sUnreadText, sMaxUnreadCount);
6442c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        } else if (unreadCount <= 0) {
6452c47a117415bc4461150f190837e0e94389b7597Mindy Pereira            unreadCountString = "";
6462c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        } else {
647d878a84ca3e1046fe39c61cc5da501982f85885eVikram Aggarwal            // Localize unread count according to the device language
648d878a84ca3e1046fe39c61cc5da501982f85885eVikram Aggarwal            unreadCountString = String.format("%d", unreadCount);
6492c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        }
6502c47a117415bc4461150f190837e0e94389b7597Mindy Pereira        return unreadCountString;
6512c47a117415bc4461150f190837e0e94389b7597Mindy Pereira    }
65228beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira
65328beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira    /**
65428beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira     * Get text matching the last sync status.
65528beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira     */
65641b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal    public static CharSequence getSyncStatusText(Context context, int packedStatus) {
65717beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook        final String[] errors = context.getResources().getStringArray(R.array.sync_status);
65841b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal        final int status = packedStatus & 0x0f;
65928beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira        if (status >= errors.length) {
66028beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira            return "";
66128beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira        }
66228beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira        return errors[status];
66328beb84263683aa2a47d3e42bd322aa11e4dd838Mindy Pereira    }
6648a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira
6658a8c50d8fcc4f20549c9f395edbad017a940e72bMindy Pereira    /**
6669ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     * Create an intent to show a conversation.
6679ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     * @param conversation Conversation to open.
668161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira     * @param folder
669161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira     * @param account
6709ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     * @return
6719ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     */
67209400efa442422299acf21abe20e3470f9d965abScott Kennedy    public static Intent createViewConversationIntent(final Context context,
673b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy            Conversation conversation, final Uri folderUri, Account account) {
6749ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        final Intent intent = new Intent(Intent.ACTION_VIEW);
67509400efa442422299acf21abe20e3470f9d965abScott Kennedy        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
67609400efa442422299acf21abe20e3470f9d965abScott Kennedy                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
67709400efa442422299acf21abe20e3470f9d965abScott Kennedy        intent.setDataAndType(appendVersionQueryParameter(context, conversation.uri),
67809400efa442422299acf21abe20e3470f9d965abScott Kennedy                account.mimeType);
6795ad02918f663bc52522a2505de985df9ef5ea347Mindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account.serialize());
680b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy        intent.putExtra(Utils.EXTRA_FOLDER_URI, folderUri);
681963cdedf714e6e37c7447413cff767b3f2826b28Mindy Pereira        intent.putExtra(Utils.EXTRA_CONVERSATION, conversation);
6829ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        return intent;
6839ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira    }
6849ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira
6859ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira    /**
6869ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira     * Create an intent to open a folder.
687c7968873cb1b64b669733aff1e4e6ef766ebd815Mindy Pereira     *
688daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * @param folder Folder to open.
6890c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal     * @param account
690daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * @return
691daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     */
692b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy    public static Intent createViewFolderIntent(final Context context, final Uri folderUri,
69309400efa442422299acf21abe20e3470f9d965abScott Kennedy            Account account) {
694b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy        if (folderUri == null || account == null) {
695b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy            LogUtils.wtf(LOG_TAG, "Utils.createViewFolderIntent(%s,%s): Bad input", folderUri,
696b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy                    account);
6971672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal            return null;
6981672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal        }
6999ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        final Intent intent = new Intent(Intent.ACTION_VIEW);
7005ad02918f663bc52522a2505de985df9ef5ea347Mindy Pereira        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
7015ad02918f663bc52522a2505de985df9ef5ea347Mindy Pereira                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
702b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy        intent.setDataAndType(appendVersionQueryParameter(context, folderUri), account.mimeType);
7035ad02918f663bc52522a2505de985df9ef5ea347Mindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account.serialize());
704b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy        intent.putExtra(Utils.EXTRA_FOLDER_URI, folderUri);
7059ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira        return intent;
7069ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira    }
7079ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira
7089ae8ce0578b5b097e59fbd1b09fbfb8f824500fbMindy Pereira    /**
7090c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal     * Creates an intent to open the default inbox for the given account.
7100c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal     *
7110c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal     * @param account
7120c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal     * @return
7130c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal     */
7140c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal    public static Intent createViewInboxIntent(Account account) {
7150c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        if (account == null) {
7160c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal            LogUtils.wtf(LOG_TAG, "Utils.createViewInboxIntent(%s): Bad input", account);
7170c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal            return null;
7180c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        }
7190c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        final Intent intent = new Intent(Intent.ACTION_VIEW);
7200c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
7210c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
7220c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        intent.setDataAndType(account.settings.defaultInbox, account.mimeType);
7230c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        intent.putExtra(Utils.EXTRA_ACCOUNT, account.serialize());
7240c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        return intent;
7250c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal    }
7260c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal
7270c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal    /**
72894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * Helper method to show context-aware Gmail help.
72994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     *
73094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @param context Context to be used to open the help.
73194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @param fromWhere Information about the activity the user was in
73294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * when they requested help.
73394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     */
734498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook    public static void showHelp(Context context, Account account, String fromWhere) {
735c2b791d22684fc4fe4a19bf31bead54434eab354Paul Westbrook        final String urlString = (account != null && account.helpIntentUri != null) ?
736c2b791d22684fc4fe4a19bf31bead54434eab354Paul Westbrook                account.helpIntentUri.toString() : null;
737c2b791d22684fc4fe4a19bf31bead54434eab354Paul Westbrook        if (TextUtils.isEmpty(urlString) ) {
738498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook            LogUtils.e(LOG_TAG, "unable to show help for account: %s", account);
739498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook            return;
740498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook        }
741c2b791d22684fc4fe4a19bf31bead54434eab354Paul Westbrook        final Uri uri = addParamsToUrl(context, urlString);
74294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        Uri.Builder builder = uri.buildUpon();
74394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        // Add the activity specific information parameter.
74430745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook        if (!TextUtils.isEmpty(fromWhere)) {
74594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            builder = builder.appendQueryParameter(SMART_HELP_LINK_PARAMETER_NAME, fromWhere);
74694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        }
74794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
74817beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook        openUrl(context, builder.build(), null);
74994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    }
75094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
75194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    /**
75294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * Helper method to open a link in a browser.
75394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     *
75494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @param context Context
75594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @param uri Uri to open.
75694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     */
75717beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook    private static void openUrl(Context context, Uri uri, Bundle optionalExtras) {
75894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        if(uri == null || TextUtils.isEmpty(uri.toString())) {
75994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            LogUtils.wtf(LOG_TAG, "invalid url in Utils.openUrl(): %s", uri);
76094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            return;
76194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        }
76217beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook        final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
76317beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook        // Fill in any of extras that have been requested.
76417beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook        if (optionalExtras != null) {
76517beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook            intent.putExtras(optionalExtras);
76617beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook        }
76794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
7686f7a886390498b346daa03358ffd310d9e1f4ba0Paul Westbrook        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
76917beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook
77094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        context.startActivity(intent);
77194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    }
77294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
77394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
77494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static Uri addParamsToUrl(Context context, String url) {
77594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        url = replaceLocale(url);
77694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        Uri.Builder builder = Uri.parse(url).buildUpon();
777fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy        final int versionCode = getVersionCode(context);
778fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy        if (versionCode != -1) {
779fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy            builder = builder.appendQueryParameter(SMART_LINK_APP_VERSION,
780fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy                    String.valueOf(versionCode));
78194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        }
78294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
78394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        return builder.build();
78494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    }
78594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
78694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    /**
78794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * Replaces the language/country of the device into the given string.  The pattern "%locale%"
78894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * will be replaced with the <language_code>_<country_code> value.
78994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     *
79094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @param str the string to replace the language/country within
79194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     *
79294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     * @return the string with replacement
79394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     */
79494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    private static String replaceLocale(String str) {
79594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        // Substitute locale if present in string
79694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        if (str.contains("%locale%")) {
79794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            Locale locale = Locale.getDefault();
79894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            String tmp = locale.getLanguage() + "_" + locale.getCountry().toLowerCase();
79994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            str = str.replace("%locale%", tmp);
80094e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        }
80194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        return str;
80294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    }
80394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook
80494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    /**
805fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy     * Returns the version code for the package, or -1 if it cannot be retrieved.
80694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook     */
807fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy    public static int getVersionCode(Context context) {
808fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy        if (sVersionCode == -1) {
80994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            try {
810fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy                sVersionCode =
811fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy                        context.getPackageManager().getPackageInfo(context.getPackageName(),
812fafcd17adae9b7ba5c270611d0f53608ced92e2eScott Kennedy                                0 /* flags */).versionCode;
81394e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            } catch (NameNotFoundException e) {
81494e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook                LogUtils.e(Utils.LOG_TAG, "Error finding package %s",
81594e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook                        context.getApplicationInfo().packageName);
81694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook            }
81794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        }
81894e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook        return sVersionCode;
81994e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook    }
8201f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira
8211f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira    /**
8221f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira     * Show the settings screen for the supplied account.
8231f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira     */
8241f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira    public static void showSettings(Context context, Account account) {
82561400846077d5b4ea2da0374732cfd75e207c0c4Paul Westbrook        if (account == null) {
82661400846077d5b4ea2da0374732cfd75e207c0c4Paul Westbrook            LogUtils.e(LOG_TAG, "Invalid attempt to show setting screen with null account");
82761400846077d5b4ea2da0374732cfd75e207c0c4Paul Westbrook            return;
82861400846077d5b4ea2da0374732cfd75e207c0c4Paul Westbrook        }
8291f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        final Intent settingsIntent = new Intent(Intent.ACTION_EDIT, account.settingsIntentUri);
8306f7a886390498b346daa03358ffd310d9e1f4ba0Paul Westbrook        settingsIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
8311f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        context.startActivity(settingsIntent);
8321f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira    }
83368f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira
83468f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira    /**
835e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook     * Show the settings screen for the supplied account.
836e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook     */
837e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook     public static void showFolderSettings(Context context, Account account, Folder folder) {
83809400efa442422299acf21abe20e3470f9d965abScott Kennedy        if (account == null || folder == null) {
83909400efa442422299acf21abe20e3470f9d965abScott Kennedy            LogUtils.e(LOG_TAG, "Invalid attempt to show folder settings. account: %s folder: %s",
84009400efa442422299acf21abe20e3470f9d965abScott Kennedy                    account, folder);
84109400efa442422299acf21abe20e3470f9d965abScott Kennedy            return;
84209400efa442422299acf21abe20e3470f9d965abScott Kennedy        }
84309400efa442422299acf21abe20e3470f9d965abScott Kennedy        final Intent settingsIntent = new Intent(Intent.ACTION_EDIT,
84409400efa442422299acf21abe20e3470f9d965abScott Kennedy                appendVersionQueryParameter(context, account.settingsIntentUri));
845e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook
84609400efa442422299acf21abe20e3470f9d965abScott Kennedy        settingsIntent.putExtra(EditSettingsExtras.EXTRA_ACCOUNT, account);
84709400efa442422299acf21abe20e3470f9d965abScott Kennedy        settingsIntent.putExtra(EditSettingsExtras.EXTRA_FOLDER, folder);
84809400efa442422299acf21abe20e3470f9d965abScott Kennedy        settingsIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
84909400efa442422299acf21abe20e3470f9d965abScott Kennedy        context.startActivity(settingsIntent);
850e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook    }
851e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook
852e550355f79eed5b133c80b88b332de50dcad8697Paul Westbrook    /**
85318babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook     * Show the settings screen for managing all folders.
85418babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook     */
85518babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook     public static void showManageFolder(Context context, Account account) {
85618babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook         if (account == null) {
85718babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook             LogUtils.e(LOG_TAG, "Invalid attempt to the manage folders screen with null account");
85818babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook             return;
85918babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook         }
86018babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook         final Intent settingsIntent = new Intent(Intent.ACTION_EDIT, account.settingsIntentUri);
86118babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook
86218babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook         settingsIntent.putExtra(EditSettingsExtras.EXTRA_ACCOUNT, account);
86318babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook         settingsIntent.putExtra(EditSettingsExtras.EXTRA_MANAGE_FOLDERS, true);
8646f7a886390498b346daa03358ffd310d9e1f4ba0Paul Westbrook         settingsIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
86518babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook         context.startActivity(settingsIntent);
86618babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook    }
86718babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook
86818babd2334a0c3dfdcb3519299e4dcbd781c8c2dPaul Westbrook    /**
869fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira     * Show the feedback screen for the supplied account.
870fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira     */
87183e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    public static void sendFeedback(FeedbackEnabledActivity activity, Account account,
87283e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook            boolean reportingProblem) {
8736141205af6186ebd7feaf9f050a15611464f42d2Alice Yang        if (activity != null && account != null && !isEmpty(account.sendFeedbackIntentUri)) {
87483e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook            final Bundle optionalExtras = new Bundle(2);
87517beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook            optionalExtras.putBoolean(
87617beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook                    UIProvider.SendFeedbackExtras.EXTRA_REPORTING_PROBLEM, reportingProblem);
87783e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook            final Bitmap screenBitmap =  getReducedSizeBitmap(activity);
87883e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook            if (screenBitmap != null) {
87983e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook                optionalExtras.putParcelable(
88083e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook                        UIProvider.SendFeedbackExtras.EXTRA_SCREEN_SHOT, screenBitmap);
88183e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook            }
88283e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook            openUrl(activity.getActivityContext(), account.sendFeedbackIntentUri, optionalExtras);
8833ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
884fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira    }
885fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira
88683e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    public static Bitmap getReducedSizeBitmap(FeedbackEnabledActivity activity) {
88783e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        final Window activityWindow = activity.getWindow();
88883e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        final View currentView = activityWindow != null ? activityWindow.getDecorView() : null;
88983e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        final View rootView = currentView != null ? currentView.getRootView() : null;
89083e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        if (rootView != null) {
89183e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook            rootView.setDrawingCacheEnabled(true);
892c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang            final Bitmap drawingCache = rootView.getDrawingCache();
893c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang            // Null check to avoid NPE discovered from monkey crash:
894c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang            if (drawingCache != null) {
895c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                final Bitmap originalBitmap = drawingCache.copy(Bitmap.Config.RGB_565, false);
896c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                double originalHeight = originalBitmap.getHeight();
897c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                double originalWidth = originalBitmap.getWidth();
898c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                int newHeight = SCALED_SCREENSHOT_MAX_HEIGHT_WIDTH;
899c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                int newWidth = SCALED_SCREENSHOT_MAX_HEIGHT_WIDTH;
900c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                double scaleX, scaleY;
901c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                scaleX = newWidth  / originalWidth;
902c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                scaleY = newHeight / originalHeight;
903c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                final double scale = Math.min(scaleX, scaleY);
904c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                newWidth = (int)Math.round(originalWidth * scale);
905c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                newHeight = (int)Math.round(originalHeight * scale);
906c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang                return Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, true);
907c1ed8e1d12d8afa02cd23a6971f86deb20cf7f7aAlice Yang            }
90883e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        }
90983e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        return null;
91083e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    }
91183e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook
912fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira    /**
91368f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira     * Retrieves the mailbox search query associated with an intent (or null if not available),
91468f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira     * doing proper sanitizing (e.g. trims whitespace).
91568f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira     */
91668f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira    public static String mailSearchQueryForIntent(Intent intent) {
91768f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira        String query = intent.getStringExtra(SearchManager.QUERY);
91868f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira        return TextUtils.isEmpty(query) ? null : query.trim();
91968f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira   }
92088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
92188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
92288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * Split out a filename's extension and return it.
92388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * @param filename a file name
92488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * @return the file extension (max of 5 chars including period, like ".docx"), or null
92588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
92696f6bed5c71d3cec9725ee3efc6465176c3023a8Mindy Pereira    public static String getFileExtension(String filename) {
92788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        String extension = null;
92896f6bed5c71d3cec9725ee3efc6465176c3023a8Mindy Pereira        int index = !TextUtils.isEmpty(filename) ? filename.lastIndexOf('.') : -1;
92988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        // Limit the suffix to dot + four characters
93088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        if (index >= 0 && filename.length() - index <= FILE_EXTENSION_MAX_CHARS + 1) {
93188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang            extension = filename.substring(index);
93288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        }
93388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return extension;
93488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
93588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
93688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang   /**
93788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * (copied from {@link Intent#normalizeMimeType(String)} for pre-J)
93888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
9398750066b10f80e2a8080016973b3296d76d18266Mark Wei    * Normalize a MIME data type.
94088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
94188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * <p>A normalized MIME type has white-space trimmed,
94288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * content-type parameters removed, and is lower-case.
94388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * This aligns the type with Android best practices for
94488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * intent filtering.
94588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
94688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * <p>For example, "text/plain; charset=utf-8" becomes "text/plain".
94788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * "text/x-vCard" becomes "text/x-vcard".
94888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
94988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * <p>All MIME types received from outside Android (such as user input,
95088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * or external sources like Bluetooth, NFC, or the Internet) should
95188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * be normalized before they are used to create an Intent.
95288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
95388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * @param type MIME data type to normalize
95488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * @return normalized MIME data type, or null if the input was null
95588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * @see {@link #setType}
95688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * @see {@link #setTypeAndNormalize}
95788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    */
9588750066b10f80e2a8080016973b3296d76d18266Mark Wei   public static String normalizeMimeType(String type) {
95988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       if (type == null) {
96088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang           return null;
96188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       }
96288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
96388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       type = type.trim().toLowerCase(Locale.US);
96488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
96588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       final int semicolonIndex = type.indexOf(';');
96688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       if (semicolonIndex != -1) {
96788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang           type = type.substring(0, semicolonIndex);
96888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       }
9698750066b10f80e2a8080016973b3296d76d18266Mark Wei       return type;
97088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang   }
97188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
97288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang   /**
97388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * (copied from {@link Uri#normalize()} for pre-J)
97488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
97588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * Return a normalized representation of this Uri.
97688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
97788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * <p>A normalized Uri has a lowercase scheme component.
97888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * This aligns the Uri with Android best practices for
97988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * intent filtering.
98088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
98188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * <p>For example, "HTTP://www.android.com" becomes
98288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * "http://www.android.com"
98388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
98488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * <p>All URIs received from outside Android (such as user input,
98588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * or external sources like Bluetooth, NFC, or the Internet) should
98688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * be normalized before they are used to create an Intent.
98788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
98888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * <p class="note">This method does <em>not</em> validate bad URI's,
98988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * or 'fix' poorly formatted URI's - so do not use it for input validation.
99088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * A Uri will always be returned, even if the Uri is badly formatted to
99188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * begin with and a scheme component cannot be found.
99288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    *
99388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * @return normalized Uri (never null)
99488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * @see {@link android.content.Intent#setData}
99588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    * @see {@link #setNormalizedData}
99688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    */
99788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang   public static Uri normalizeUri(Uri uri) {
99888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       String scheme = uri.getScheme();
99988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       if (scheme == null) return uri;  // give up
100088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       String lowerScheme = scheme.toLowerCase(Locale.US);
100188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       if (scheme.equals(lowerScheme)) return uri;  // no change
100288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
100388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang       return uri.buildUpon().scheme(lowerScheme).build();
100488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang   }
100588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
10068750066b10f80e2a8080016973b3296d76d18266Mark Wei   public static Intent setIntentTypeAndNormalize(Intent intent, String type) {
10078750066b10f80e2a8080016973b3296d76d18266Mark Wei       return intent.setType(normalizeMimeType(type));
100888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang   }
100988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
10108750066b10f80e2a8080016973b3296d76d18266Mark Wei   public static Intent setIntentDataAndTypeAndNormalize(Intent intent, Uri data, String type) {
10118750066b10f80e2a8080016973b3296d76d18266Mark Wei       return intent.setDataAndType(normalizeUri(data), normalizeMimeType(type));
101288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang   }
101388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1014b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira   public static int getTransparentColor(int color) {
1015b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira       return 0x00ffffff & color;
1016b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira   }
1017863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira
1018863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira    public static void setMenuItemVisibility(Menu menu, int itemId, boolean shouldShow) {
1019863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira        final MenuItem item = menu.findItem(itemId);
1020863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira        if (item == null) {
1021863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira            return;
1022863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira        }
1023863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira        item.setVisible(shouldShow);
1024863e44160d9175023d30e7e225ecb69ad3892eecMindy Pereira    }
102592551d057965689f1952faeb06763f0762bc717fMindy Pereira
102692551d057965689f1952faeb06763f0762bc717fMindy Pereira    /**
102792551d057965689f1952faeb06763f0762bc717fMindy Pereira     * Parse a string (possibly null or empty) into a URI. If the string is null
102892551d057965689f1952faeb06763f0762bc717fMindy Pereira     * or empty, null is returned back. Otherwise an empty URI is returned.
102992551d057965689f1952faeb06763f0762bc717fMindy Pereira     *
103092551d057965689f1952faeb06763f0762bc717fMindy Pereira     * @param uri
103192551d057965689f1952faeb06763f0762bc717fMindy Pereira     * @return a valid URI, possibly {@link android.net.Uri#EMPTY}
103292551d057965689f1952faeb06763f0762bc717fMindy Pereira     */
103392551d057965689f1952faeb06763f0762bc717fMindy Pereira    public static Uri getValidUri(String uri) {
1034b378d64bab3c7517794ad7e2aee1d06c074e99eeMindy Pereira        if (TextUtils.isEmpty(uri) || uri == JSONObject.NULL)
103592551d057965689f1952faeb06763f0762bc717fMindy Pereira            return Uri.EMPTY;
103692551d057965689f1952faeb06763f0762bc717fMindy Pereira        return Uri.parse(uri);
103792551d057965689f1952faeb06763f0762bc717fMindy Pereira    }
103810ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blank
103910ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blank    public static boolean isEmpty(Uri uri) {
104010ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blank        return uri == null || uri.equals(Uri.EMPTY);
104110ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blank    }
1042ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang
1043bb9dd6b315c2b3a5816c8f52418a991c5c1b70fdAndy Huang    public static String dumpFragment(Fragment f) {
1044bb9dd6b315c2b3a5816c8f52418a991c5c1b70fdAndy Huang        final StringWriter sw = new StringWriter();
1045bb9dd6b315c2b3a5816c8f52418a991c5c1b70fdAndy Huang        f.dump("", new FileDescriptor(), new PrintWriter(sw), new String[0]);
1046bb9dd6b315c2b3a5816c8f52418a991c5c1b70fdAndy Huang        return sw.toString();
1047bb9dd6b315c2b3a5816c8f52418a991c5c1b70fdAndy Huang    }
1048bb9dd6b315c2b3a5816c8f52418a991c5c1b70fdAndy Huang
1049fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    public static void dumpViewTree(ViewGroup root) {
1050fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        dumpViewTree(root, "");
1051fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    }
1052fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
1053fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    private static void dumpViewTree(ViewGroup g, String prefix) {
1054fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        LogUtils.i(LOG_TAG, "%sVIEWGROUP: %s childCount=%s", prefix, g, g.getChildCount());
1055fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        final String childPrefix = prefix + "  ";
1056fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        for (int i = 0; i < g.getChildCount(); i++) {
1057fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            final View child = g.getChildAt(i);
1058fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            if (child instanceof ViewGroup) {
1059fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang                dumpViewTree((ViewGroup) child, childPrefix);
1060fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            } else {
1061fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang                LogUtils.i(LOG_TAG, "%sCHILD #%s: %s", childPrefix, i, child);
1062fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            }
1063fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        }
1064fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    }
1065fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
106669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal    /**
106769b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     * Executes an out-of-band command on the cursor.
106869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     * @param cursor
106969b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     * @param request Bundle with all keys and values set for the command.
107069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     * @param key The string value against which we will check for success or failure
107169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     * @return true if the operation was a success.
107269b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     */
107369b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal    private static boolean executeConversationCursorCommand(
107469b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            Cursor cursor, Bundle request, String key) {
107569b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        final Bundle response = cursor.respond(request);
107669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        final String result = response.getString(key,
1077ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang                UIProvider.ConversationCursorCommand.COMMAND_RESPONSE_FAILED);
1078ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang
1079ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang        return UIProvider.ConversationCursorCommand.COMMAND_RESPONSE_OK.equals(result);
1080ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang    }
1081ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang
1082ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang    /**
1083ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     * Commands a cursor representing a set of conversations to disable any network requests it may
1084ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     * do as clients move through the cursor.
1085ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     *
1086ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     * @param cursor a conversation cursor
1087ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     * @return true iff the provider supports network requests and they were previously enabled
1088ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     */
1089ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang    public static boolean disableConversationCursorNetworkAccess(Cursor cursor) {
109069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        final Bundle request = new Bundle();
109169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        final String key = UIProvider.ConversationCursorCommand.COMMAND_KEY_ALLOW_NETWORK_ACCESS;
109269b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        request.putBoolean(key, false);
109369b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        return executeConversationCursorCommand(cursor, request, key);
1094ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang    }
1095ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang
1096ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang    /**
1097ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     * Commands a cursor representing a set of conversations to [re-]enable any network requests it
1098ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     * may do as clients move through the cursor.
1099ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     *
1100ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     * @param cursor a conversation cursor
1101ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     * @return true iff the provider supports network requests and they are successfully enabled
1102ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang     */
1103ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang    public static boolean enableConversationCursorNetworkAccess(Cursor cursor) {
110469b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        final Bundle request = new Bundle();
110569b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        final String key = UIProvider.ConversationCursorCommand.COMMAND_KEY_ALLOW_NETWORK_ACCESS;
110669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        request.putBoolean(key, true);
110769b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        return executeConversationCursorCommand(cursor, request, key);
1108ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang    }
11099f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook
11109f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook    /**
11119f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook     * Commands a cursor representing a set of conversations to set its visibility state.
11129f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook     *
11139f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook     * @param cursor a conversation cursor
111469b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     * @param visible true if the conversation list is visible, false otherwise.
111569b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     * @param isFirstSeen true if you want to notify the cursor that this conversation list was seen
111669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     *        for the first time: the user launched the app into it, or the user switched from some
111769b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     *        other folder into it.
11189f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook     */
111969b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal    public static void setConversationCursorVisibility(
112069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            Cursor cursor, boolean visible, boolean isFirstSeen) {
112169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        new MarkConversationCursorVisibleTask(cursor, visible, isFirstSeen).execute();
11229f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook    }
11239f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook
11249f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook    /**
112569b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     * Async task for  marking conversations "seen" and informing the cursor that the folder was
112669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal     * seen for the first time by the UI.
11279f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook     */
11289f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook    private static class MarkConversationCursorVisibleTask extends AsyncTask<Void, Void, Void> {
11299f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook        private final Cursor mCursor;
11309f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook        private final boolean mVisible;
113169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        private final boolean mIsFirstSeen;
113269b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal
113369b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        /**
113469b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal         * Create a new task with the given cursor, with the given visibility and
113569b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal         *
113669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal         * @param cursor
113769b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal         * @param isVisible true if the conversation list is visible, false otherwise.
113869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal         * @param isFirstSeen true if the folder was shown for the first time: either the user has
113969b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal         *        just switched to it, or the user started the app in this folder.
114069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal         */
114169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal        public MarkConversationCursorVisibleTask(
114269b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal                Cursor cursor, boolean isVisible, boolean isFirstSeen) {
11439f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook            mCursor = cursor;
114469b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            mVisible = isVisible;
114569b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            mIsFirstSeen = isFirstSeen;
11469f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook        }
11479f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook
11489f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook        @Override
11499f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook        protected Void doInBackground(Void... params) {
115069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            if (mCursor == null) {
115169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal                return null;
115269b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            }
115369b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            final Bundle request = new Bundle();
115469b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            if (mIsFirstSeen) {
115569b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal                request.putBoolean(
115669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal                        UIProvider.ConversationCursorCommand.COMMAND_KEY_ENTERED_FOLDER, true);
11579f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook            }
115869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            final String key = UIProvider.ConversationCursorCommand.COMMAND_KEY_SET_VISIBILITY;
115969b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            request.putBoolean(key, mVisible);
116069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal            executeConversationCursorCommand(mCursor, request, key);
11619f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook            return null;
11629f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook        }
11639f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook    }
11649fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira
1165a13b3742522987f768ef9a1a1cddd32ff8105f0ePaul Westbrook
1166a13b3742522987f768ef9a1a1cddd32ff8105f0ePaul Westbrook    /**
1167a13b3742522987f768ef9a1a1cddd32ff8105f0ePaul Westbrook     * This utility method returns the conversation ID at the current cursor position.
1168a13b3742522987f768ef9a1a1cddd32ff8105f0ePaul Westbrook     * @return the conversation id at the cursor.
1169a13b3742522987f768ef9a1a1cddd32ff8105f0ePaul Westbrook     */
1170a13b3742522987f768ef9a1a1cddd32ff8105f0ePaul Westbrook    public static long getConversationId(ConversationCursor cursor) {
1171d781c02b91162afa91ba7d7477f40b7eec2aacedPaul Westbrook        return cursor.getLong(UIProvider.CONVERSATION_ID_COLUMN);
1172a13b3742522987f768ef9a1a1cddd32ff8105f0ePaul Westbrook    }
1173a13b3742522987f768ef9a1a1cddd32ff8105f0ePaul Westbrook
11749fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira    /**
11750a22d4482396f3717b36796e594d5f8e9760d509Paul Westbrook     * This utility method returns the conversation Uri at the current cursor position.
11760a22d4482396f3717b36796e594d5f8e9760d509Paul Westbrook     * @return the conversation id at the cursor.
11770a22d4482396f3717b36796e594d5f8e9760d509Paul Westbrook     */
11780a22d4482396f3717b36796e594d5f8e9760d509Paul Westbrook    public static String getConversationUri(ConversationCursor cursor) {
11790a22d4482396f3717b36796e594d5f8e9760d509Paul Westbrook        return cursor.getString(UIProvider.CONVERSATION_URI_COLUMN);
11800a22d4482396f3717b36796e594d5f8e9760d509Paul Westbrook    }
11810a22d4482396f3717b36796e594d5f8e9760d509Paul Westbrook
11820a22d4482396f3717b36796e594d5f8e9760d509Paul Westbrook    /**
11839fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira     * @return whether to show two pane or single pane search results.
11849fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira     */
11859fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira    public static boolean showTwoPaneSearchResults(Context context) {
11869fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira        return context.getResources().getBoolean(R.bool.show_two_pane_search_results);
11879fa43cab6a83c70a7739c3d5300fc354856f22ffMindy Pereira    }
1188a41a57a186b84f98b497e109cff94aa3c1362697Mindy Pereira
1189a41a57a186b84f98b497e109cff94aa3c1362697Mindy Pereira    /**
1190bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang     * Sets the layer type of a view to hardware if the view is attached and hardware acceleration
1191bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang     * is enabled. Does nothing otherwise.
1192bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang     */
1193bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang    public static void enableHardwareLayer(View v) {
1194bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang        if (v != null && v.isHardwareAccelerated()) {
1195bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang            v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
1196bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang            v.buildLayer();
1197bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang        }
1198bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang    }
1199bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang
1200bb6039ed45a5eeccf08d97cb91d1b91069fed5afAndy Huang    /**
1201a41a57a186b84f98b497e109cff94aa3c1362697Mindy Pereira     * Return whether menus should show the disabled archive menu item or just
1202a41a57a186b84f98b497e109cff94aa3c1362697Mindy Pereira     * remove it when archive is not available.
1203a41a57a186b84f98b497e109cff94aa3c1362697Mindy Pereira     */
1204a41a57a186b84f98b497e109cff94aa3c1362697Mindy Pereira    public static boolean shouldShowDisabledArchiveIcon(Context context) {
1205a41a57a186b84f98b497e109cff94aa3c1362697Mindy Pereira        return context.getResources().getBoolean(R.bool.show_disabled_archive_menu_item);
1206a41a57a186b84f98b497e109cff94aa3c1362697Mindy Pereira    }
120755137b88f01521d15a0677b7105416bbc6528a49Mindy Pereira
120855137b88f01521d15a0677b7105416bbc6528a49Mindy Pereira    public static int getDefaultFolderBackgroundColor(Context context) {
120955137b88f01521d15a0677b7105416bbc6528a49Mindy Pereira        if (sDefaultFolderBackgroundColor == -1) {
121055137b88f01521d15a0677b7105416bbc6528a49Mindy Pereira            sDefaultFolderBackgroundColor = context.getResources().getColor(
121155137b88f01521d15a0677b7105416bbc6528a49Mindy Pereira                    R.color.default_folder_background_color);
121255137b88f01521d15a0677b7105416bbc6528a49Mindy Pereira        }
121355137b88f01521d15a0677b7105416bbc6528a49Mindy Pereira        return sDefaultFolderBackgroundColor;
121455137b88f01521d15a0677b7105416bbc6528a49Mindy Pereira    }
1215443275a9e4f9f66d982cbcadca215be239663a7aVikram Aggarwal
1216a6e965ef4a7ac2266f0a5509be25ac1e8d272595Andy Huang    /**
1217601ab03706b6674c4154ca313080b6549bdb562fPaul Westbrook     * Returns the count that should be shown for the specified folder.  This method should be used
1218601ab03706b6674c4154ca313080b6549bdb562fPaul Westbrook     * when the UI wants to display an "unread" count.  For most labels, the returned value will be
1219601ab03706b6674c4154ca313080b6549bdb562fPaul Westbrook     * the unread count, but for some folder types (outbox, drafts, trash) this will return the
1220601ab03706b6674c4154ca313080b6549bdb562fPaul Westbrook     * total count.
1221601ab03706b6674c4154ca313080b6549bdb562fPaul Westbrook     */
12228c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy    public static int getFolderUnreadDisplayCount(final Folder folder) {
1223601ab03706b6674c4154ca313080b6549bdb562fPaul Westbrook        if (folder != null) {
12248c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy            if (folder.isDraft() || folder.isTrash()
12258c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy                    || folder.isType(UIProvider.FolderType.OUTBOX)) {
12268c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy                return folder.totalCount;
12278c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy            } else {
12288c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy                return folder.unreadCount;
1229601ab03706b6674c4154ca313080b6549bdb562fPaul Westbrook            }
1230601ab03706b6674c4154ca313080b6549bdb562fPaul Westbrook        }
12318c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy
12328c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy        return 0;
1233601ab03706b6674c4154ca313080b6549bdb562fPaul Westbrook    }
1234601ab03706b6674c4154ca313080b6549bdb562fPaul Westbrook
1235f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy    /**
1236f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy     * @return an intent which, if launched, will reply to the conversation
1237f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy     */
1238f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy    public static Intent createReplyIntent(final Context context, final Account account,
1239f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy            final Uri messageUri, final boolean isReplyAll) {
1240f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy        final Intent intent =
1241f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy                ComposeActivity.createReplyIntent(context, account, messageUri, isReplyAll);
1242f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy        return intent;
1243f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy    }
1244f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy
1245f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy    /**
1246f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy     * @return an intent which, if launched, will forward the conversation
1247f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy     */
1248f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy    public static Intent createForwardIntent(
1249f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy            final Context context, final Account account, final Uri messageUri) {
1250f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy        final Intent intent = ComposeActivity.createForwardIntent(context, account, messageUri);
1251f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy        return intent;
1252f2566a42b5dec4e846391ee0d7ecae0891356653Scott Kennedy    }
125309400efa442422299acf21abe20e3470f9d965abScott Kennedy
125409400efa442422299acf21abe20e3470f9d965abScott Kennedy    public static Uri appendVersionQueryParameter(final Context context, final Uri uri) {
125509400efa442422299acf21abe20e3470f9d965abScott Kennedy        int appVersion = 0;
125609400efa442422299acf21abe20e3470f9d965abScott Kennedy
125709400efa442422299acf21abe20e3470f9d965abScott Kennedy        try {
125809400efa442422299acf21abe20e3470f9d965abScott Kennedy            final PackageInfo packageInfo =
125909400efa442422299acf21abe20e3470f9d965abScott Kennedy                    context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
126009400efa442422299acf21abe20e3470f9d965abScott Kennedy            appVersion = packageInfo.versionCode;
126109400efa442422299acf21abe20e3470f9d965abScott Kennedy        } catch (final NameNotFoundException e) {
126209400efa442422299acf21abe20e3470f9d965abScott Kennedy            LogUtils.wtf(LOG_TAG, e, "Couldn't find our own PackageInfo");
126309400efa442422299acf21abe20e3470f9d965abScott Kennedy        }
126409400efa442422299acf21abe20e3470f9d965abScott Kennedy
126509400efa442422299acf21abe20e3470f9d965abScott Kennedy        return uri.buildUpon().appendQueryParameter(APP_VERSION_QUERY_PARAMETER,
126609400efa442422299acf21abe20e3470f9d965abScott Kennedy                Integer.toString(appVersion)).build();
126709400efa442422299acf21abe20e3470f9d965abScott Kennedy    }
12687b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira}
1269