Add support for showing help

Change-Id: I61755c203eaef56f2c27d9110f297ee410265934
diff --git a/src/com/android/mail/providers/Account.java b/src/com/android/mail/providers/Account.java
index 8392c54..172df23 100644
--- a/src/com/android/mail/providers/Account.java
+++ b/src/com/android/mail/providers/Account.java
@@ -94,6 +94,12 @@
     public final String settingIntentUri;
 
     /**
+     * Uri for VIEW intent that will cause the help screens for this account type to be
+     * shown.
+     */
+    public final String helpIntentUri;
+
+    /**
      * The sync status of the account
      */
     public final int syncStatus;
@@ -104,7 +110,7 @@
      * includes the members described above and name and type from the
      * superclass.
      */
-    private static final int NUMBER_MEMBERS = 14;
+    private static final int NUMBER_MEMBERS = 15;
 
     /**
      * Examples of expected format for the joined account strings
@@ -137,6 +143,7 @@
         out.append(expungeMessageUri).append(ACCOUNT_COMPONENT_SEPARATOR);
         out.append(undoUri).append(ACCOUNT_COMPONENT_SEPARATOR);
         out.append(settingIntentUri).append(ACCOUNT_COMPONENT_SEPARATOR);
+        out.append(helpIntentUri).append(ACCOUNT_COMPONENT_SEPARATOR);
         out.append(syncStatus);
         return out.toString();
     }
@@ -165,7 +172,8 @@
         expungeMessageUri = accountMembers[10];
         undoUri = accountMembers[11];
         settingIntentUri = accountMembers[12];
-        syncStatus = Integer.valueOf(accountMembers[13]);
+        helpIntentUri = accountMembers[13];
+        syncStatus = Integer.valueOf(accountMembers[14]);
     }
 
     public Account(Parcel in) {
@@ -181,6 +189,7 @@
         expungeMessageUri = in.readString();
         undoUri = in.readString();
         settingIntentUri = in.readString();
+        helpIntentUri = in.readString();
         syncStatus = in.readInt();
     }
 
@@ -197,6 +206,7 @@
         expungeMessageUri = cursor.getString(UIProvider.ACCOUNT_EXPUNGE_MESSAGE_URI_COLUMN);
         undoUri = cursor.getString(UIProvider.ACCOUNT_UNDO_URI_COLUMN);
         settingIntentUri = cursor.getString(UIProvider.ACCOUNT_SETTINGS_INTENT_URI_COLUMN);
+        helpIntentUri = cursor.getString(UIProvider.ACCOUNT_HELP_INTENT_URI_COLUMN);
         syncStatus = cursor.getInt(UIProvider.ACCOUNT_SYNC_STATUS_COLUMN);
     }
 
@@ -242,6 +252,7 @@
         dest.writeString(expungeMessageUri);
         dest.writeString(undoUri);
         dest.writeString(settingIntentUri);
+        dest.writeString(helpIntentUri);
         dest.writeInt(syncStatus);
     }
 
diff --git a/src/com/android/mail/providers/AccountCacheProvider.java b/src/com/android/mail/providers/AccountCacheProvider.java
index 84d8d38..c7ec0f3 100644
--- a/src/com/android/mail/providers/AccountCacheProvider.java
+++ b/src/com/android/mail/providers/AccountCacheProvider.java
@@ -116,6 +116,9 @@
                 } else if (TextUtils.equals(column,
                         UIProvider.AccountColumns.SETTINGS_INTENT_URI)) {
                     builder.add(account.mSettingsIntentUri);
+                } else if (TextUtils.equals(column,
+                        UIProvider.AccountColumns.HELP_INTENT_URI)) {
+                    builder.add(account.mHelpIntentUri);
                 } else if (TextUtils.equals(column, UIProvider.AccountColumns.SYNC_STATUS)) {
                     builder.add(Integer.valueOf((int)account.mSyncStatus));
                 } else {
@@ -198,12 +201,13 @@
         private final String mExpungeMessageUri;
         private final String mUndoUri;
         private final String mSettingsIntentUri;
+        private final String mHelpIntentUri;
         private final int mSyncStatus;
 
         public CachedAccount(long id, String name, String uri, long capabilities,
                 String folderListUri, String searchUri, String fromAddressesUri,
                 String saveDraftUri, String sendMailUri, String expungeMessageUri,
-                String undoUri, String settingsIntentUri, int syncStatus) {
+                String undoUri, String settingsIntentUri, String helpIntentUri, int syncStatus) {
             mId = id;
             mName = name;
             mUri = uri;
@@ -216,6 +220,7 @@
             mExpungeMessageUri = expungeMessageUri;
             mUndoUri = undoUri;
             mSettingsIntentUri = settingsIntentUri;
+            mHelpIntentUri = helpIntentUri;
             mSyncStatus = syncStatus;
         }
 
@@ -240,6 +245,7 @@
                     TextUtils.equals(mExpungeMessageUri, other.mExpungeMessageUri) &&
                     TextUtils.equals(mUndoUri, other.mUndoUri) &&
                     TextUtils.equals(mSettingsIntentUri, other.mSettingsIntentUri) &&
+                    TextUtils.equals(mHelpIntentUri, other.mHelpIntentUri) &&
                     (mSyncStatus == other.mSyncStatus);
         }
 
@@ -247,7 +253,7 @@
         public int hashCode() {
             return Objects.hashCode(mId, mName, mUri, mCapabilities, mFolderListUri, mSearchUri,
                     mAccountFromAddressesUri, mSaveDraftUri, mSendMailUri, mExpungeMessageUri,
-                    mUndoUri, mSettingsIntentUri, mSyncStatus);
+                    mUndoUri, mSettingsIntentUri, mHelpIntentUri, mSyncStatus);
         }
     }
 }
\ No newline at end of file
diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java
index 18c5044..d8c5290 100644
--- a/src/com/android/mail/providers/UIProvider.java
+++ b/src/com/android/mail/providers/UIProvider.java
@@ -92,7 +92,8 @@
             AccountColumns.EXPUNGE_MESSAGE_URI,
             AccountColumns.UNDO_URI,
             AccountColumns.SETTINGS_INTENT_URI,
-            AccountColumns.SYNC_STATUS
+            AccountColumns.SYNC_STATUS,
+            AccountColumns.HELP_INTENT_URI
     };
 
     public static final int ACCOUNT_ID_COLUMN = 0;
@@ -109,6 +110,7 @@
     public static final int ACCOUNT_UNDO_URI_COLUMN = 11;
     public static final int ACCOUNT_SETTINGS_INTENT_URI_COLUMN = 12;
     public static final int ACCOUNT_SYNC_STATUS_COLUMN = 13;
+    public static final int ACCOUNT_HELP_INTENT_URI_COLUMN = 14;
 
     public static final class AccountCapabilities {
         /**
@@ -184,6 +186,10 @@
          * Whether the provider supports undoing operations. If it doesn't, never show the undo bar.
          */
         public static final int UNDO = 0x2000;
+        /**
+         * Whether the account provides help content.
+         */
+        public static final int HELP_CONTENT = 0x4000;
     }
 
     public static final class AccountColumns {
@@ -263,6 +269,14 @@
         public static String SETTINGS_INTENT_URI = "accountSettingsIntentUri";
 
         /**
+         * Uri for VIEW intent that will cause the help screens for this account type to be
+         * shown.
+         * TODO: When we want to support a heterogeneous set of account types, this value may need
+         * to be moved to a global content provider.
+         */
+        public static String HELP_INTENT_URI = "helpIntentUri";
+
+        /**
          * This int column contains the current sync status of the account (the logical AND of the
          * sync status of folders in this account)
          */
diff --git a/src/com/android/mail/providers/protos/mock/MockUiProvider.java b/src/com/android/mail/providers/protos/mock/MockUiProvider.java
index 3166b39..7347f9b 100644
--- a/src/com/android/mail/providers/protos/mock/MockUiProvider.java
+++ b/src/com/android/mail/providers/protos/mock/MockUiProvider.java
@@ -269,6 +269,7 @@
         accountMap.put(AccountColumns.EXPUNGE_MESSAGE_URI, accountUri + "/expungeMessage");
         accountMap.put(AccountColumns.UNDO_URI, accountUri + "/undo");
         accountMap.put(AccountColumns.SETTINGS_INTENT_URI, "http://www.google.com");
+        accountMap.put(AccountColumns.HELP_INTENT_URI, "http://www.google.com");
         accountMap.put(AccountColumns.SYNC_STATUS, 0);
 
         if (cacheMap) {
@@ -359,6 +360,7 @@
                         (String)accountInfo.get(AccountColumns.EXPUNGE_MESSAGE_URI),
                         (String)accountInfo.get(AccountColumns.UNDO_URI),
                         (String)accountInfo.get(AccountColumns.SETTINGS_INTENT_URI),
+                        (String)accountInfo.get(AccountColumns.HELP_INTENT_URI),
                         (Integer)accountInfo.get(AccountColumns.SYNC_STATUS));
 
 
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 27825e3..c175c18 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -32,6 +32,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.net.Uri;
+import android.text.TextUtils;
 import android.view.ActionMode;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -51,11 +52,14 @@
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.Folder;
 import com.android.mail.providers.UIProvider;
+import com.android.mail.providers.UIProvider.AccountCapabilities;
 import com.android.mail.providers.UIProvider.LastSyncResult;
 import com.android.mail.ui.AsyncRefreshTask;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
 
+import java.lang.Readable;
+
 /**
  * This is an abstract implementation of the Activity Controller. This class knows how to
  * respond to menu items, state changes, layout changes, etc.  It weaves together the views and
@@ -103,6 +107,7 @@
     private AsyncRefreshTask mAsyncRefreshTask;
 
     private MenuItem mRefreshItem;
+    private MenuItem mHelpItem;
     private View mRefreshActionView;
     private boolean mRefreshInProgress;
     private final Handler mHandler = new Handler();
@@ -237,6 +242,8 @@
             mAccount = account;
 
             fetchAccountFolderInfo();
+
+            updateHelpMenuItem();
         }
     }
 
@@ -335,6 +342,7 @@
         MenuInflater inflater = mActivity.getMenuInflater();
         inflater.inflate(mActionBarView.getOptionsMenuId(), menu);
         mRefreshItem = menu.findItem(R.id.refresh);
+        mHelpItem = menu.findItem(R.id.help_info_menu_item);
         return true;
     }
 
@@ -370,6 +378,10 @@
             case R.id.preferences:
                 showPreferences();
                 break;
+            case R.id.help_info_menu_item:
+                // TODO: enable context sensitive help
+                Utils.showHelp(mActivity.getActivityContext(), mAccount.helpIntentUri, null);
+                break;
             default:
                 handled = false;
                 break;
@@ -437,9 +449,19 @@
                 mRefreshItem.setActionView(null);
             }
         }
+
+        // Show/hide the help menu item
+        updateHelpMenuItem();
         return true;
     }
 
+    private void updateHelpMenuItem() {
+        if (mHelpItem != null) {
+            mHelpItem.setVisible(mAccount != null &&
+                    mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
+        }
+    }
+
     @Override
     public void onResume() {
         if (mActionBarView != null) {
diff --git a/src/com/android/mail/utils/Utils.java b/src/com/android/mail/utils/Utils.java
index 3648cf5..0711233 100644
--- a/src/com/android/mail/utils/Utils.java
+++ b/src/com/android/mail/utils/Utils.java
@@ -20,9 +20,13 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Typeface;
 import android.net.Uri;
+import android.provider.Browser;
 import android.text.Html;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -40,10 +44,12 @@
 import android.webkit.WebView;
 
 import com.android.mail.R;
+import com.android.mail.browse.ConversationCursor;
 import com.android.mail.providers.Account;
 import com.android.mail.providers.Folder;
 import com.android.mail.providers.UIProvider;
 
+import java.util.Locale;
 import java.util.Map;
 
 public class Utils {
@@ -70,8 +76,16 @@
      * can be very broad and is NOT the preferred way of getting notification.
      */
     // TODO: UI Provider has this notification URI?
-   public static final String ACTION_NOTIFY_DATASET_CHANGED =
-           "com.android.mail.ACTION_NOTIFY_DATASET_CHANGED";
+    public static final String ACTION_NOTIFY_DATASET_CHANGED =
+            "com.android.mail.ACTION_NOTIFY_DATASET_CHANGED";
+
+    /** Parameter keys for context-aware help. */
+    private static final String SMART_HELP_LINK_PARAMETER_NAME = "p";
+
+    private static final String SMART_LINK_APP_VERSION = "version";
+    private static String sVersionCode = null;
+
+    private static final String LOG_TAG = new LogUtils().getLogTag();
 
     /**
      * Sets WebView in a restricted mode suitable for email use.
@@ -570,4 +584,88 @@
 
         return intent;
     }
+
+    /**
+     * Helper method to show context-aware Gmail help.
+     *
+     * @param context Context to be used to open the help.
+     * @param fromWhere Information about the activity the user was in
+     * when they requested help.
+     */
+    public static void showHelp(Context context, String accountHelpUrl, String fromWhere) {
+        final Uri uri = addParamsToUrl(context, accountHelpUrl);
+        Uri.Builder builder = uri.buildUpon();
+        // Add the activity specific information parameter.
+        if (fromWhere != null) {
+            builder = builder.appendQueryParameter(SMART_HELP_LINK_PARAMETER_NAME, fromWhere);
+        }
+
+        openUrl(context, builder.build());
+    }
+
+    /**
+     * Helper method to open a link in a browser.
+     *
+     * @param context Context
+     * @param uri Uri to open.
+     */
+    private static void openUrl(Context context, Uri uri) {
+        if(uri == null || TextUtils.isEmpty(uri.toString())) {
+            LogUtils.wtf(LOG_TAG, "invalid url in Utils.openUrl(): %s", uri);
+            return;
+        }
+        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+        intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
+        context.startActivity(intent);
+    }
+
+
+    private static Uri addParamsToUrl(Context context, String url) {
+        url = replaceLocale(url);
+        Uri.Builder builder = Uri.parse(url).buildUpon();
+        final String versionCode = getVersionCode(context);
+        if (versionCode != null) {
+            builder = builder.appendQueryParameter(SMART_LINK_APP_VERSION, versionCode);
+        }
+
+        return builder.build();
+    }
+
+    /**
+     * Replaces the language/country of the device into the given string.  The pattern "%locale%"
+     * will be replaced with the <language_code>_<country_code> value.
+     *
+     * @param str the string to replace the language/country within
+     *
+     * @return the string with replacement
+     */
+    private static String replaceLocale(String str) {
+        // Substitute locale if present in string
+        if (str.contains("%locale%")) {
+            Locale locale = Locale.getDefault();
+            String tmp = locale.getLanguage() + "_" + locale.getCountry().toLowerCase();
+            str = str.replace("%locale%", tmp);
+        }
+        return str;
+    }
+
+    /**
+     * Returns the version code for the package, or null if it cannot be retrieved.
+     */
+    public static String getVersionCode(Context context) {
+        if (sVersionCode == null) {
+            try {
+                sVersionCode = String.valueOf(context.getPackageManager()
+                        .getPackageInfo(context.getPackageName(), 0 /* flags */)
+                        .versionCode);
+            } catch (NameNotFoundException e) {
+                LogUtils.e(Utils.LOG_TAG, "Error finding package %s",
+                        context.getApplicationInfo().packageName);
+            }
+        }
+        return sVersionCode;
+    }
+
+
+
 }