am 99710c6c: am ccf9a34b: Add support for disabling email sanitization

* commit '99710c6cef8a0537c85afcd2618d95c7755865e6':
  Add support for disabling email sanitization
diff --git a/src/com/android/mail/browse/ConversationPagerAdapter.java b/src/com/android/mail/browse/ConversationPagerAdapter.java
index 70620b4..a6c794b 100644
--- a/src/com/android/mail/browse/ConversationPagerAdapter.java
+++ b/src/com/android/mail/browse/ConversationPagerAdapter.java
@@ -19,7 +19,7 @@
 
 import android.app.Fragment;
 import android.app.FragmentManager;
-import android.content.res.Resources;
+import android.content.Context;
 import android.database.Cursor;
 import android.database.DataSetObserver;
 import android.os.Bundle;
@@ -27,6 +27,7 @@
 import android.support.v4.view.ViewPager;
 import android.view.ViewGroup;
 
+import com.android.mail.preferences.MailPrefs;
 import com.android.mail.providers.Account;
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.Folder;
@@ -37,6 +38,7 @@
 import com.android.mail.ui.ConversationViewFragment;
 import com.android.mail.ui.SecureConversationViewFragment;
 import com.android.mail.utils.FragmentStatePagerAdapter2;
+import com.android.mail.utils.HtmlSanitizer;
 import com.android.mail.utils.LogUtils;
 
 public class ConversationPagerAdapter extends FragmentStatePagerAdapter2
@@ -67,10 +69,8 @@
      * True iff we are in the process of handling a dataset change.
      */
     private boolean mInDataSetChange = false;
-    /**
-     * Need to keep this around to look up pager title strings.
-     */
-    private Resources mResources;
+
+    private Context mContext;
     /**
      * This isn't great to create a circular dependency, but our usage of {@link #getPageTitle(int)}
      * requires knowing which page is the currently visible to dynamically name offscreen pages
@@ -81,7 +81,16 @@
      * minimize dangling references.
      */
     private ViewPager mPager;
-    private boolean mSanitizedHtml;
+
+    /**
+     * <tt>true</tt> indicates the server has already sanitized all HTML email from this account.
+     */
+    private boolean mServerSanitizedHtml;
+
+    /**
+     * <tt>true</tt> indicates the client is permitted to sanitize all HTML email for this account.
+     */
+    private boolean mClientSanitizedHtml;
 
     private boolean mStopListeningMode = false;
 
@@ -104,16 +113,18 @@
     private static final String BUNDLE_DETACHED_MODE =
             ConversationPagerAdapter.class.getName() + "-detachedmode";
 
-    public ConversationPagerAdapter(Resources res, FragmentManager fm, Account account,
+    public ConversationPagerAdapter(Context context, FragmentManager fm, Account account,
             Folder folder, Conversation initialConversation) {
         super(fm, false /* enableSavedStates */);
-        mResources = res;
+        mContext = context;
         mCommonFragmentArgs = AbstractConversationViewFragment.makeBasicArgs(account);
         mInitialConversation = initialConversation;
         mAccount = account;
         mFolder = folder;
-        mSanitizedHtml = mAccount.supportsCapability
-                (UIProvider.AccountCapabilities.SANITIZED_HTML);
+        mServerSanitizedHtml =
+                mAccount.supportsCapability(UIProvider.AccountCapabilities.SERVER_SANITIZED_HTML);
+        mClientSanitizedHtml =
+                mAccount.supportsCapability(UIProvider.AccountCapabilities.CLIENT_SANITIZED_HTML);
     }
 
     public boolean matches(Account account, Folder folder) {
@@ -194,11 +205,23 @@
     }
 
     private AbstractConversationViewFragment getConversationViewFragment(Conversation c) {
-        if (mSanitizedHtml) {
+        // if Html email bodies are already sanitized by the mail server, scripting can be enabled
+        if (mServerSanitizedHtml) {
             return ConversationViewFragment.newInstance(mCommonFragmentArgs, c);
-        } else {
-            return SecureConversationViewFragment.newInstance(mCommonFragmentArgs, c);
         }
+
+        // if this client is permitted to sanitize emails for this account, attempt to do so
+        if (mClientSanitizedHtml) {
+            // if the version of the Html Sanitizer meets or exceeds the required version, the
+            // results of the sanitizer can be trusted and scripting can be enabled
+            final MailPrefs mailPrefs = MailPrefs.get(mContext);
+            if (HtmlSanitizer.VERSION >= mailPrefs.getRequiredSanitizerVersionNumber()) {
+                return ConversationViewFragment.newInstance(mCommonFragmentArgs, c);
+            }
+        }
+
+        // otherwise we do not enable scripting
+        return SecureConversationViewFragment.newInstance(mCommonFragmentArgs, c);
     }
 
     @Override
diff --git a/src/com/android/mail/browse/ConversationPagerController.java b/src/com/android/mail/browse/ConversationPagerController.java
index 347b4ae..87190f5 100644
--- a/src/com/android/mail/browse/ConversationPagerController.java
+++ b/src/com/android/mail/browse/ConversationPagerController.java
@@ -117,7 +117,7 @@
             mPager.setVisibility(View.VISIBLE);
         }
 
-        mPagerAdapter = new ConversationPagerAdapter(mPager.getResources(), mFragmentManager,
+        mPagerAdapter = new ConversationPagerAdapter(mPager.getContext(), mFragmentManager,
                 account, folder, initialConversation);
         mPagerAdapter.setSingletonMode(ENABLE_SINGLETON_INITIAL_LOAD);
         mPagerAdapter.setActivityController(mActivityController);
diff --git a/src/com/android/mail/preferences/MailPrefs.java b/src/com/android/mail/preferences/MailPrefs.java
index 4d6957d..609877d 100644
--- a/src/com/android/mail/preferences/MailPrefs.java
+++ b/src/com/android/mail/preferences/MailPrefs.java
@@ -117,6 +117,8 @@
 
         public static final String RECENT_ACCOUNTS = "recent-accounts";
 
+        public static final String REQUIRED_SANITIZER_VERSION_NUMBER = "required-sanitizer-version-number";
+
         public static final ImmutableSet<String> BACKUP_KEYS =
                 new ImmutableSet.Builder<String>()
                 .add(DEFAULT_REPLY_ALL)
@@ -527,4 +529,22 @@
     public void setRecentAccounts(Set<String> recentAccounts) {
         getEditor().putStringSet(PreferenceKeys.RECENT_ACCOUNTS, recentAccounts).apply();
     }
+
+    /**
+     * Returns the minimum version number of the {@link com.android.mail.utils.HtmlSanitizer} which
+     * is trusted. If the version of the HtmlSanitizer does not meet or exceed this value,
+     * sanitization will be deemed untrustworthy and emails will be displayed in a sandbox that does
+     * not allow script execution.
+     */
+    public int getRequiredSanitizerVersionNumber() {
+        return getSharedPreferences().getInt(PreferenceKeys.REQUIRED_SANITIZER_VERSION_NUMBER, 1);
+    }
+
+    /**
+     * @param versionNumber the minimum version number of the
+     *      {@link com.android.mail.utils.HtmlSanitizer} which produces trusted output
+     */
+    public void setRequiredSanitizerVersionNumber(int versionNumber) {
+        getEditor().putInt(PreferenceKeys.REQUIRED_SANITIZER_VERSION_NUMBER, versionNumber).apply();
+    }
 }
diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java
index 7f22bca..a280c55 100644
--- a/src/com/android/mail/providers/UIProvider.java
+++ b/src/com/android/mail/providers/UIProvider.java
@@ -238,7 +238,7 @@
         /**
          * Whether the server sends us sanitized HTML (guaranteed to not contain malicious HTML).
          */
-        public static final int SANITIZED_HTML = 0x0080;
+        public static final int SERVER_SANITIZED_HTML = 0x0080;
         /**
          * Whether the server allows synchronization of draft messages. This does NOT require
          * SYNCABLE_FOLDERS to be set.
@@ -316,6 +316,10 @@
          * Whether the account supports nested folders
          */
         public static final int NESTED_FOLDERS = 0x800000;
+        /**
+         * Whether the client is permitted to sanitize HTML for this account.
+         */
+        public static final int CLIENT_SANITIZED_HTML = 0x1000000;
     }
 
     public static final class AccountColumns implements BaseColumns {
diff --git a/src/com/android/mail/providers/protos/mock/MockUiProvider.java b/src/com/android/mail/providers/protos/mock/MockUiProvider.java
index dcd4019..37a219b 100644
--- a/src/com/android/mail/providers/protos/mock/MockUiProvider.java
+++ b/src/com/android/mail/providers/protos/mock/MockUiProvider.java
@@ -318,7 +318,7 @@
                         AccountCapabilities.MUTE |
                         AccountCapabilities.SERVER_SEARCH |
                         AccountCapabilities.FOLDER_SERVER_SEARCH |
-                        AccountCapabilities.SANITIZED_HTML |
+                        AccountCapabilities.SERVER_SANITIZED_HTML |
                         AccountCapabilities.DRAFT_SYNCHRONIZATION |
                         AccountCapabilities.MULTIPLE_FROM_ADDRESSES |
                         AccountCapabilities.SMART_REPLY |
diff --git a/src/com/android/mail/utils/HtmlSanitizer.java b/src/com/android/mail/utils/HtmlSanitizer.java
index 976bdaa..da29345 100644
--- a/src/com/android/mail/utils/HtmlSanitizer.java
+++ b/src/com/android/mail/utils/HtmlSanitizer.java
@@ -44,6 +44,17 @@
  * or comparable.
  */
 public final class HtmlSanitizer {
+
+    /**
+     * This version number should be bumped each time a meaningful change is made to this sanitizer
+     * configuration which influences its output. It is compared against a minimum target version
+     * number. If it meets or exceeds the minimum target version, the result of the sanitizer is
+     * free to be shown in a standard webview. If it does not meet the minimum target version then
+     * the sanitized output is deemed untrustworthy and is shown in a sandboxed webview with
+     * javascript execution disabled.
+     */
+    public static final int VERSION = 1;
+
     private static final String LOG_TAG = LogTag.getLogTag();
 
     /**
@@ -90,7 +101,7 @@
                 final String value = attrs.remove(idIndex + 1);
                 attrs.remove(idIndex);
 
-                // AOL uses a specifc id value to indicate quoted text
+                // AOL uses a specific id value to indicate quoted text
                 showHideQuotedText = value.startsWith("AOLMsgPart");
             }