15c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein/**
2f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Copyright (C) 2012 Google Inc.
3f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Licensed to The Android Open Source Project.
4f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang *
5f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Licensed under the Apache License, Version 2.0 (the "License");
6f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * you may not use this file except in compliance with the License.
7f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * You may obtain a copy of the License at
8f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang *
9f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang *      http://www.apache.org/licenses/LICENSE-2.0
10f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang *
11f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Unless required by applicable law or agreed to in writing, software
12f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * distributed under the License is distributed on an "AS IS" BASIS,
13f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * See the License for the specific language governing permissions and
15f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * limitations under the License.
16f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang */
17f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
18f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangpackage com.android.mail.ui;
19f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
20f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport android.content.Context;
21e46a5307264962338b70b22f4b97704714694634Andrew Sappersteinimport android.support.v4.text.TextUtilsCompat;
22e46a5307264962338b70b22f4b97704714694634Andrew Sappersteinimport android.support.v4.view.ViewCompat;
23f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
24f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport com.android.mail.R;
25b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
26f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport com.android.mail.utils.LogUtils;
274ca3eb4fea185a57b4ecd770f50fe9ae03af8ee0Andrew Sappersteinimport com.android.mail.utils.Utils;
289e2d407fdafeb874e640eb84017feaf784309075Scott Kennedyimport com.google.common.annotations.VisibleForTesting;
29f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
30e46a5307264962338b70b22f4b97704714694634Andrew Sappersteinimport java.util.Locale;
31f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport java.util.regex.Pattern;
32f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
33f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang/**
34f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Renders data into very simple string-substitution HTML templates for conversation view.
35f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang */
365c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinpublic class HtmlConversationTemplates extends AbstractHtmlTemplates {
37f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
38f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    /**
39f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * Prefix applied to a message id for use as a div id
40f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     */
41f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    public static final String MESSAGE_PREFIX = "m";
428ec43e877a9c1925514f066655984e21fbd255e8Andrew Sapperstein    public static final int MESSAGE_PREFIX_LENGTH = MESSAGE_PREFIX.length();
43f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
44b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String TAG = LogTag.getLogTag();
45f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
46f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    /**
47f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * Pattern for HTML img tags with a "src" attribute where the value is an absolutely-specified
48f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * HTTP or HTTPS URL. In other words, these are images with valid URLs that we should munge to
49f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * prevent WebView from firing bad onload handlers for them. Part of the workaround for
50f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * b/5522414.
51f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     *
52f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * Pattern documentation:
53f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * There are 3 top-level parts of the pattern:
54f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * 1. required preceding string
55f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * 2. the literal string "src"
56f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * 3. required trailing string
57f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     *
58f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * The preceding string must be an img tag "<img " with intermediate spaces allowed. The
59f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * trailing whitespace is required.
60f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * Non-whitespace chars are allowed before "src", but if they are present, they must be followed
61f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * by another whitespace char. The idea is to allow other attributes, and avoid matching on
62f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * "src" in a later attribute value as much as possible.
63f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     *
64f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * The following string must contain "=" and "http", with intermediate whitespace and single-
65f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * and double-quote allowed in between. The idea is to avoid matching Gmail-hosted relative URLs
66f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * for inline attachment images of the form "?view=KEYVALUES".
67f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     *
68f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     */
69f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    private static final Pattern sAbsoluteImgUrlPattern = Pattern.compile(
70f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            "(<\\s*img\\s+(?:[^>]*\\s+)?)src(\\s*=[\\s'\"]*http)", Pattern.CASE_INSENSITIVE
71f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang                    | Pattern.MULTILINE);
72f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    /**
73f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * The text replacement for {@link #sAbsoluteImgUrlPattern}. The "src" attribute is set to
74f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     * something inert and not left unset to minimize interactions with existing JS.
75f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang     */
763233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang    private static final String IMG_URL_REPLACEMENT = "$1src='data:' blocked-src$2";
77f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
78e46a5307264962338b70b22f4b97704714694634Andrew Sapperstein    private static final String LEFT_TO_RIGHT_TRIANGLE = "\u25B6 ";
79e46a5307264962338b70b22f4b97704714694634Andrew Sapperstein    private static final String RIGHT_TO_LEFT_TRIANGLE = "\u25C0 ";
80e46a5307264962338b70b22f4b97704714694634Andrew Sapperstein
81f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    private static boolean sLoadedTemplates;
82f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    private static String sSuperCollapsed;
83f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    private static String sMessage;
84f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    private static String sConversationUpper;
85f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    private static String sConversationLower;
86f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
87f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    public HtmlConversationTemplates(Context context) {
885c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        super(context);
89f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
90f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        // The templates are small (~2KB total in ICS MR2), so it's okay to load them once and keep
91f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        // them in memory.
92f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        if (!sLoadedTemplates) {
93f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            sLoadedTemplates = true;
94f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            sSuperCollapsed = readTemplate(R.raw.template_super_collapsed);
95f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            sMessage = readTemplate(R.raw.template_message);
96f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            sConversationUpper = readTemplate(R.raw.template_conversation_upper);
97f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            sConversationLower = readTemplate(R.raw.template_conversation_lower);
98f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        }
99f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    }
100f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
101f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    public void appendSuperCollapsedHtml(int firstCollapsed, int blockHeight) {
102f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        if (!mInProgress) {
103f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            throw new IllegalStateException("must call startConversation first");
104f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        }
105f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
106f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        append(sSuperCollapsed, firstCollapsed, blockHeight);
107f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    }
108f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
109f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    @VisibleForTesting
110f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    static String replaceAbsoluteImgUrls(final String html) {
111f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        return sAbsoluteImgUrlPattern.matcher(html).replaceAll(IMG_URL_REPLACEMENT);
112f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    }
113f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
114986776bbd046c9569a4abb67501819bee61e7194Andy Huang    /**
115986776bbd046c9569a4abb67501819bee61e7194Andy Huang     * Wrap a given message body string to prevent its contents from flowing out of the current DOM
116986776bbd046c9569a4abb67501819bee61e7194Andy Huang     * block context.
117986776bbd046c9569a4abb67501819bee61e7194Andy Huang     *
118986776bbd046c9569a4abb67501819bee61e7194Andy Huang     */
119986776bbd046c9569a4abb67501819bee61e7194Andy Huang    public static String wrapMessageBody(String msgBody) {
120cd7e48431ef9800e46a4b3cb0a33768bd47a2452Andy Huang        // FIXME: this breaks RTL for an as-yet undetermined reason. b/13678928
121cd7e48431ef9800e46a4b3cb0a33768bd47a2452Andy Huang        // no-op for now.
122cd7e48431ef9800e46a4b3cb0a33768bd47a2452Andy Huang        return msgBody;
123cd7e48431ef9800e46a4b3cb0a33768bd47a2452Andy Huang
124cd7e48431ef9800e46a4b3cb0a33768bd47a2452Andy Huang//        final StringBuilder sb = new StringBuilder("<div style=\"display: table-cell;\">");
125cd7e48431ef9800e46a4b3cb0a33768bd47a2452Andy Huang//        sb.append(msgBody);
126cd7e48431ef9800e46a4b3cb0a33768bd47a2452Andy Huang//        sb.append("</div>");
127cd7e48431ef9800e46a4b3cb0a33768bd47a2452Andy Huang//        return sb.toString();
128986776bbd046c9569a4abb67501819bee61e7194Andy Huang    }
129986776bbd046c9569a4abb67501819bee61e7194Andy Huang
130606dbd7a44b8445e872c25c0fe080e3e12a47adfAndrew Sapperstein    public void appendMessageHtml(HtmlMessage message, boolean isExpanded,
131256b35c0a8287f48c28e0d1ba3fae65790063295Andy Huang            boolean safeForImages, int headerHeight, int footerHeight) {
132f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
133f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        final String bodyDisplay = isExpanded ? "block" : "none";
1347bdc3750454efe59617b7df945eadd7e59bee954Andy Huang        final String expandedClass = isExpanded ? "expanded" : "";
1353233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang        final String showImagesClass = safeForImages ? "mail-show-images" : "";
136f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
137014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang        String body = message.getBodyAsHtml();
138f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
139f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        /* Work around a WebView bug (5522414) in setBlockNetworkImage that causes img onload event
140f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * handlers to fire before an image is loaded.
141f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * WebView will report bad dimensions when revealing inline images with absolute URLs, but
142f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * we can prevent WebView from ever seeing those images by changing all img "src" attributes
143f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * into "gm-src" before loading the HTML. Parsing the potentially dirty HTML input is
144f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * prohibitively expensive with TagSoup, so use a little regular expression instead.
145f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         *
146f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * To limit the scope of this workaround, only use it on messages that the server claims to
147f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * have external resources, and even then, only use it on img tags where the src is absolute
148f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * (i.e. url does not begin with "?"). The existing JavaScript implementation of this
149f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * attribute swap will continue to handle inline image attachments (they have relative
150f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * URLs) and any false negatives that the regex misses. This maintains overall security
151f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         * level by not relying solely on the regex.
152f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang         */
153606dbd7a44b8445e872c25c0fe080e3e12a47adfAndrew Sapperstein        if (!safeForImages && message.embedsExternalResources()) {
154f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            body = replaceAbsoluteImgUrls(body);
155f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        }
156f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
157f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        append(sMessage,
1583233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang                getMessageDomId(message),
1597bdc3750454efe59617b7df945eadd7e59bee954Andy Huang                expandedClass,
160f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang                headerHeight,
161f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang                showImagesClass,
162f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang                bodyDisplay,
163986776bbd046c9569a4abb67501819bee61e7194Andy Huang                wrapMessageBody(body),
164c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang                bodyDisplay,
1657bdc3750454efe59617b7df945eadd7e59bee954Andy Huang                footerHeight
166f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        );
167f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    }
168f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
169606dbd7a44b8445e872c25c0fe080e3e12a47adfAndrew Sapperstein    public String getMessageDomId(HtmlMessage msg) {
170606dbd7a44b8445e872c25c0fe080e3e12a47adfAndrew Sapperstein        return MESSAGE_PREFIX + msg.getId();
1713233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang    }
1723233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang
1733c6fd44f9ae0cf60248dc64ee74d46afed633c45Andy Huang    public String getMessageIdForDomId(String domMessageId) {
1743c6fd44f9ae0cf60248dc64ee74d46afed633c45Andy Huang        return domMessageId.substring(MESSAGE_PREFIX_LENGTH);
1753c6fd44f9ae0cf60248dc64ee74d46afed633c45Andy Huang    }
1763c6fd44f9ae0cf60248dc64ee74d46afed633c45Andy Huang
1774dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang    public void startConversation(int viewportWidth, int sideMargin, int conversationHeaderHeight) {
178f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        if (mInProgress) {
1795c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            throw new IllegalStateException(
1805c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein                    "Should not call start conversation until end conversation has been called");
181f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        }
182f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
183f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        reset();
1844ca3eb4fea185a57b4ecd770f50fe9ae03af8ee0Andrew Sapperstein        final String border = Utils.isRunningKitkatOrLater() ?
1854ca3eb4fea185a57b4ecd770f50fe9ae03af8ee0Andrew Sapperstein                "img[blocked-src] { border: 1px solid #CCCCCC; }" : "";
1862160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang        append(sConversationUpper, viewportWidth, border, sideMargin, conversationHeaderHeight);
187f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        mInProgress = true;
188f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    }
189f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
190e2a30e19a9fff0e4368c4ec36280a3fcd4ca03e2Andrew Sapperstein    public String endConversation(int convFooterPx, String docBaseUri, String conversationBaseUri,
1914dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang            int viewportWidth, int webviewWidth, boolean enableContentReadySignal,
1924dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang            boolean normalizeMessageWidths, boolean enableMungeTables, boolean enableMungeImages) {
193f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        if (!mInProgress) {
194f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            throw new IllegalStateException("must call startConversation first");
195f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        }
196f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
19769aecc996f92521e3b2e1a11f7d3797227868cf2Andy Huang        final String contentReadyClass = enableContentReadySignal ? "initial-load" : "";
19869aecc996f92521e3b2e1a11f7d3797227868cf2Andy Huang
199e46a5307264962338b70b22f4b97704714694634Andrew Sapperstein        final boolean isRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
200e46a5307264962338b70b22f4b97704714694634Andrew Sapperstein                == ViewCompat.LAYOUT_DIRECTION_RTL;
201e46a5307264962338b70b22f4b97704714694634Andrew Sapperstein        final String showElided = (isRtl ? RIGHT_TO_LEFT_TRIANGLE : LEFT_TO_RIGHT_TRIANGLE) +
202e46a5307264962338b70b22f4b97704714694634Andrew Sapperstein                mContext.getString(R.string.show_elided);
203e2a30e19a9fff0e4368c4ec36280a3fcd4ca03e2Andrew Sapperstein        append(sConversationLower, convFooterPx, contentReadyClass,
204e2a30e19a9fff0e4368c4ec36280a3fcd4ca03e2Andrew Sapperstein                mContext.getString(R.string.hide_elided),
205e46a5307264962338b70b22f4b97704714694634Andrew Sapperstein                showElided, docBaseUri, conversationBaseUri, viewportWidth, webviewWidth,
206e46a5307264962338b70b22f4b97704714694634Andrew Sapperstein                enableContentReadySignal, normalizeMessageWidths,
207d56ecc5f959baa497a7620eaff295f1417db4fdaRay Chen                enableMungeTables, enableMungeImages, Utils.isRunningKitkatOrLater(),
208d56ecc5f959baa497a7620eaff295f1417db4fdaRay Chen                mContext.getString(R.string.forms_are_disabled));
209f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
210f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        mInProgress = false;
211f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
212f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        LogUtils.d(TAG, "rendered conversation of %d bytes, buffer capacity=%d",
213f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang                mBuilder.length() << 1, mBuilder.capacity() << 1);
214f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
215f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        return emit();
216f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    }
217f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang}
218