15c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein/**
25c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein * Copyright (C) 2013 Google Inc.
35c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein * Licensed to The Android Open Source Project.
45c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein *
55c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein * Licensed under the Apache License, Version 2.0 (the "License");
65c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein * you may not use this file except in compliance with the License.
75c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein * You may obtain a copy of the License at
85c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein *
95c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein *      http://www.apache.org/licenses/LICENSE-2.0
105c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein *
115c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein * Unless required by applicable law or agreed to in writing, software
125c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein * distributed under the License is distributed on an "AS IS" BASIS,
135c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein * See the License for the specific language governing permissions and
155c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein * limitations under the License.
165c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein */
175c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
185c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinpackage com.android.mail.print;
195c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
20f390417da9ed6293253d501fe8166e839fd2bbd2Andrew Sappersteinimport android.annotation.SuppressLint;
215c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinimport android.content.Context;
225c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinimport android.content.res.Resources;
23562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sappersteinimport android.print.PrintAttributes;
24562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sappersteinimport android.print.PrintManager;
255c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinimport android.text.TextUtils;
26562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sappersteinimport android.webkit.WebSettings;
27562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sappersteinimport android.webkit.WebView;
285c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
29821e578a71c7015646522e729600618f0ec16fc0Tony Mantlerimport com.android.emailcommon.mail.Address;
305c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinimport com.android.mail.FormattedDateBuilder;
315c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinimport com.android.mail.R;
325c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinimport com.android.mail.browse.MessageCursor;
33562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein
349b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sappersteinimport com.android.mail.providers.Attachment;
355c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinimport com.android.mail.providers.Conversation;
36562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sappersteinimport com.android.mail.providers.Message;
375c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinimport com.android.mail.providers.UIProvider;
389b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sappersteinimport com.android.mail.utils.AttachmentUtils;
395c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinimport com.android.mail.utils.Utils;
405c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
419b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sappersteinimport java.util.List;
425c1692a5faeab220881a17a3427a8986ef874403Andrew Sappersteinimport java.util.Map;
435c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
445c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein/**
45562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein * Utility class that provides utility functions to print
46562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein * either a conversation or message.
475c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein */
48562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sappersteinpublic class PrintUtils {
495c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    private static final String DIV_START = "<div>";
505c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    private static final String REPLY_TO_DIV_START = "<div class=\"replyto\">";
515c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    private static final String DIV_END = "</div>";
525c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
535c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    /**
54562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     * Prints an entire conversation.
55562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     */
56562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    public static void printConversation(Context context,
57562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            MessageCursor cursor, Map<String, Address> addressCache,
58562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            String baseUri, boolean useJavascript) {
5971294e2340e5ee198c6898eb02b73015cf8f9823Andrew Sapperstein        if (cursor == null) {
6071294e2340e5ee198c6898eb02b73015cf8f9823Andrew Sapperstein            return;
6171294e2340e5ee198c6898eb02b73015cf8f9823Andrew Sapperstein        }
62562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        final String convHtml = buildConversationHtml(context, cursor,
63562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein                        addressCache, useJavascript);
64562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        printHtml(context, convHtml, baseUri, cursor.getConversation().subject, useJavascript);
65562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    }
66562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein
67562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    /**
68562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     * Prints one message.
69562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     */
70562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    public static void printMessage(Context context, Message message, String subject,
71562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            Map<String, Address> addressCache, String baseUri, boolean useJavascript) {
72562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        final String msgHtml = buildMessageHtml(context, message,
73562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein                subject, addressCache, useJavascript);
74562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        printHtml(context, msgHtml, baseUri, subject, useJavascript);
75562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    }
76562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein
772467437c9b24711d8b66d9945f346dd8f6868826Andrew Sapperstein    public static String buildPrintJobName(Context context, String name) {
782467437c9b24711d8b66d9945f346dd8f6868826Andrew Sapperstein        return TextUtils.isEmpty(name)
792467437c9b24711d8b66d9945f346dd8f6868826Andrew Sapperstein                ? context.getString(R.string.app_name)
802467437c9b24711d8b66d9945f346dd8f6868826Andrew Sapperstein                : context.getString(R.string.print_job_name, name);
812467437c9b24711d8b66d9945f346dd8f6868826Andrew Sapperstein    }
822467437c9b24711d8b66d9945f346dd8f6868826Andrew Sapperstein
83562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    /**
84562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     * Prints the html provided using the framework printing APIs.
85562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     *
86562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     * Sets up a webview to perform the printing work.
87562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     */
88dbcc98028f59244eacd9f127e6297aa98451f9b0Andrew Sapperstein    @SuppressLint({"NewApi", "SetJavaScriptEnabled"})
89562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    private static void printHtml(Context context, String html,
90562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            String baseUri, String subject, boolean useJavascript) {
91562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        final WebView webView = new WebView(context);
92562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        final WebSettings settings = webView.getSettings();
93562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        settings.setBlockNetworkImage(false);
94562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        settings.setJavaScriptEnabled(useJavascript);
95dbcc98028f59244eacd9f127e6297aa98451f9b0Andrew Sapperstein        webView.loadDataWithBaseURL(baseUri, html, "text/html", "utf-8", null);
96562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        final PrintManager printManager =
97562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein                (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
98562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein
992467437c9b24711d8b66d9945f346dd8f6868826Andrew Sapperstein        final String printJobName = buildPrintJobName(context, subject);
100562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        printManager.print(printJobName,
101dbcc98028f59244eacd9f127e6297aa98451f9b0Andrew Sapperstein                Utils.isRunningLOrLater() ?
102dbcc98028f59244eacd9f127e6297aa98451f9b0Andrew Sapperstein                        webView.createPrintDocumentAdapter(printJobName) :
103dbcc98028f59244eacd9f127e6297aa98451f9b0Andrew Sapperstein                        webView.createPrintDocumentAdapter(),
104562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein                new PrintAttributes.Builder().build());
105562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    }
106562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein
107562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    /**
1085c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein     * Builds an html document that is suitable for printing and returns it as a {@link String}.
1095c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein     */
110562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    private static String buildConversationHtml(Context context,
1115c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            MessageCursor cursor, Map<String, Address> addressCache, boolean useJavascript) {
1125c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final HtmlPrintTemplates templates = new HtmlPrintTemplates(context);
1135c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final FormattedDateBuilder dateBuilder = new FormattedDateBuilder(context);
1145c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
1155c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        if (!cursor.moveToFirst()) {
1165c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            throw new IllegalStateException("trying to print without a conversation");
1175c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        }
1185c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
1195c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final Conversation conversation = cursor.getConversation();
120562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        templates.startPrintConversation(conversation.subject, conversation.getNumMessages());
1215c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
1225c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        // for each message in the conversation, add message html
1235c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final Resources res = context.getResources();
1245c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        do {
125562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            final Message message = cursor.getMessage();
126562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            appendSingleMessageHtml(context, res, message, addressCache, templates, dateBuilder);
127562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        } while (cursor.moveToNext());
128562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein
129562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        // only include JavaScript if specifically requested
130562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        return useJavascript ?
131562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein                templates.endPrintConversation() : templates.endPrintConversationNoJavascript();
132562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    }
1335c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
134562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    /**
135562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     * Builds an html document suitable for printing and returns it as a {@link String}.
136562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     */
137562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    private static String buildMessageHtml(Context context, Message message,
138562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            String subject, Map<String, Address> addressCache, boolean useJavascript) {
139562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        final HtmlPrintTemplates templates = new HtmlPrintTemplates(context);
140562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        final FormattedDateBuilder dateBuilder = new FormattedDateBuilder(context);
1415c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
142562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        templates.startPrintConversation(subject, 1 /* numMessages */);
143562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein
144562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        // add message html
145562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        final Resources res = context.getResources();
146562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        appendSingleMessageHtml(context, res, message, addressCache, templates, dateBuilder);
1475c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
1485c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        // only include JavaScript if specifically requested
1495c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        return useJavascript ?
1505c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein                templates.endPrintConversation() : templates.endPrintConversationNoJavascript();
1515c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    }
1525c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
1535c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    /**
154562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     * Adds the html for a single message to the
155562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     * {@link HtmlPrintTemplates} provided.
156562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein     */
157562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    private static void appendSingleMessageHtml(Context context, Resources res,
158562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            Message message, Map<String, Address> addressCache,
159562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            HtmlPrintTemplates templates, FormattedDateBuilder dateBuilder) {
160562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        final Address fromAddress = Utils.getAddress(addressCache, message.getFrom());
161562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein        final long when = message.dateReceivedMs;
162b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon        final String date = dateBuilder.formatDateTimeForPrinting(when);
163562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein
16455ae5776ec084d5fb9cfa0326cd48efa99af91faJin Cao        templates.appendMessage(fromAddress == null ? "" : fromAddress.getPersonal(),
16555ae5776ec084d5fb9cfa0326cd48efa99af91faJin Cao                fromAddress == null ? "" : fromAddress.getAddress(), date,
166562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein                renderRecipients(res, addressCache, message), message.getBodyAsHtml(),
167562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein                renderAttachments(context, res, message));
168562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    }
169562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein
170562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    /**
1715c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein     * Builds html for the message header. Specifically, the (optional) lists of
1725c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein     * reply-to, to, cc, and bcc.
1735c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein     */
174562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein    private static String renderRecipients(Resources res,
175562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            Map<String, Address> addressCache, Message message) {
1765c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final StringBuilder recipients = new StringBuilder();
1775c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
1785c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        // reply-to
1795c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final String replyTo = renderEmailList(res, message.getReplyToAddresses(), addressCache);
1805c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        buildEmailDiv(res, recipients, replyTo, REPLY_TO_DIV_START, DIV_END,
1815c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein                R.string.replyto_heading);
1825c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
1835c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        // to
1845c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        // To has special semantics since the message can be a draft.
1855c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        // If it is a draft and there are no to addresses, we just print "Draft".
1865c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        // If it is a draft and there are to addresses, we print "Draft To: "
1875c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        // If not a draft, we just use "To: ".
1885c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final boolean isDraft = message.draftType != UIProvider.DraftType.NOT_A_DRAFT;
1895c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final String to = renderEmailList(res, message.getToAddresses(), addressCache);
1905c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        if (isDraft && to == null) {
1915c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            recipients.append(DIV_START).append(res.getString(R.string.draft_heading))
1925c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein                    .append(DIV_END);
1935c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        } else {
1945c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            buildEmailDiv(res, recipients, to, DIV_START, DIV_END,
195de40dd3a292531c7dd8a5741eb0980f666a88b84Andrew Sapperstein                    isDraft ? R.string.draft_to_heading : R.string.to_heading_no_space);
1965c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        }
1975c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
1985c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        // cc
1995c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final String cc = renderEmailList(res, message.getCcAddresses(), addressCache);
2005c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        buildEmailDiv(res, recipients, cc, DIV_START, DIV_END,
2015c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein                R.string.cc_heading);
2025c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
2035c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        // bcc
2045c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final String bcc = renderEmailList(res, message.getBccAddresses(), addressCache);
2055c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        buildEmailDiv(res, recipients, bcc, DIV_START, DIV_END,
2065c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein                R.string.bcc_heading);
2075c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
2085c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        return recipients.toString();
2095c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    }
2105c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
2115c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    /**
2125c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein     * Appends an html div containing a list of emails based on the passed in data.
2135c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein     */
2145c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    private static void buildEmailDiv(Resources res, StringBuilder recipients, String emailList,
2155c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            String divStart, String divEnd, int headingId) {
2165c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        if (emailList != null) {
2175c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            recipients.append(divStart).append(res.getString(headingId))
218de40dd3a292531c7dd8a5741eb0980f666a88b84Andrew Sapperstein                    .append('\u0020').append(emailList).append(divEnd);
2195c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        }
2205c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    }
2215c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
2225c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    /**
2235c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein     * Builds and returns a list of comma-separated emails of the form "Name &lt;email&gt;".
2245c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein     * If the email does not contain a name, "email" is used instead.
2255c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein     */
2265c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    private static String renderEmailList(Resources resources, String[] emails,
2275c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            Map<String, Address> addressCache) {
2285c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        if (emails == null || emails.length == 0) {
2295c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            return null;
2305c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        }
2315c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        final String[] formattedEmails = new String[emails.length];
2325c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        for (int i = 0; i < emails.length; i++) {
2335c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            final Address email = Utils.getAddress(addressCache, emails[i]);
234821e578a71c7015646522e729600618f0ec16fc0Tony Mantler            final String name = email.getPersonal();
2355c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            final String address = email.getAddress();
2365c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
2375c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            if (TextUtils.isEmpty(name)) {
2385c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein                formattedEmails[i] = address;
2395c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            } else {
2405c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein                formattedEmails[i] = resources.getString(R.string.address_print_display_format,
2415c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein                        name, address);
2425c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein            }
2435c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein        }
2445c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein
245a6e29eca5965025f2f788929834c01cc345d7670Andrew Sapperstein        return TextUtils.join(resources.getString(R.string.enumeration_comma), formattedEmails);
2465c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein    }
2479b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein
2489b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein    /**
2499b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein     * Builds and returns html for a message's attachments.
2509b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein     */
2519b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein    private static String renderAttachments(
252562c5ba7235948cf1d20a9afa40e67cd62f43cf7Andrew Sapperstein            Context context, Resources resources, Message message) {
2539b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        if (!message.hasAttachments) {
2549b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "";
2559b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        }
2569b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein
2575a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein        final int numAttachments = message.getAttachmentCount(false /* includeInline */);
2585a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein
2595a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein        // if we have no attachments after filtering out inline attachments, return.
2605a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein        if (numAttachments == 0) {
2615a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein            return "";
2625a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein        }
2635a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein
2649b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        final StringBuilder sb = new StringBuilder("<br clear=all>"
2659b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                + "<div style=\"width:50%;border-top:2px #AAAAAA solid\"></div>"
2669b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                + "<table class=att cellspacing=0 cellpadding=5 border=0>");
2679b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein
2689b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        // If the message has more than one attachment, list the number of attachments.
2699b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        if (numAttachments > 1) {
2709b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            sb.append("<tr><td colspan=2><b style=\"padding-left:3\">")
2719b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                    .append(resources.getQuantityString(
2729b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                            R.plurals.num_attachments, numAttachments, numAttachments))
2739b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                    .append("</b></td></tr>");
2749b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        }
2759b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein
2765a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein        final List<Attachment> attachments = message.getAttachments();
2775a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein        for (int i = 0, size = attachments.size(); i < size; i++) {
2785a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein            final Attachment attachment = attachments.get(i);
2795a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein            // skip inline attachments
2805a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein            if (attachment.isInlineAttachment()) {
2815a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein                continue;
2825a5c53d39abfa4d4d79081a450aecb61a6744911Andrew Sapperstein            }
2839b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            sb.append("<tr><td><table cellspacing=\"0\" cellpadding=\"0\"><tr>");
2849b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein
2859b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            // TODO - thumbnail previews of images
2869b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            sb.append("<td><img width=\"16\" height=\"16\" src=\"file:///android_asset/images/")
2879b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                    .append(getIconFilename(attachment.getContentType()))
2889b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                    .append("\"></td><td width=\"7\"></td><td><b>")
2899b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                    .append(attachment.getName())
2909b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                    .append("</b><br>").append(
2919b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                    AttachmentUtils.convertToHumanReadableSize(context, attachment.size))
2929b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                    .append("</td></tr></table></td></tr>");
2939b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        }
2949b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein
2959b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        sb.append("</table>");
2969b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein
2979b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        return sb.toString();
2989b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein    }
2999b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein
3009b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein    /**
3019b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein     * Returns an appropriate filename for various attachment mime types.
3029b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein     */
3039b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein    private static String getIconFilename(String mimeType) {
3049b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        if (mimeType.startsWith("application/msword") ||
3059b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                mimeType.startsWith("application/vnd.oasis.opendocument.text") ||
3069b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                mimeType.equals("application/rtf") ||
3079b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                mimeType.equals("application/"
3089b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                        + "vnd.openxmlformats-officedocument.wordprocessingml.document")) {
3099b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "doc.gif";
3109b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        } else if (mimeType.startsWith("image/")) {
3119b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "graphic.gif";
3129b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        } else if (mimeType.startsWith("text/html")) {
3139b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "html.gif";
3149b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        } else if (mimeType.startsWith("application/pdf")) {
3159b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "pdf.gif";
3169b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        } else if (mimeType.endsWith("powerpoint") ||
3179b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                mimeType.equals("application/vnd.oasis.opendocument.presentation") ||
3189b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                mimeType.equals("application/"
3199b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                        + "vnd.openxmlformats-officedocument.presentationml.presentation")) {
3209b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "ppt.gif";
3219b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        } else if ((mimeType.startsWith("audio/")) ||
3229b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                (mimeType.startsWith("music/"))) {
3239b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "sound.gif";
3249b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        } else if (mimeType.startsWith("text/plain")) {
3259b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "txt.gif";
3269b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        } else if (mimeType.endsWith("excel") ||
3279b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                mimeType.equals("application/vnd.oasis.opendocument.spreadsheet") ||
3289b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                mimeType.equals("application/"
3299b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                        + "vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
3309b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "xls.gif";
3319b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        } else if ((mimeType.endsWith("zip")) ||
3329b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                (mimeType.endsWith("/x-compress")) ||
3339b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein                (mimeType.endsWith("/x-compressed"))) {
3349b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "zip.gif";
3359b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        } else {
3369b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein            return "generic.gif";
3379b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein        }
3389b025f2b2811902d678e6467d89de9f07e5cc61aAndrew Sapperstein    }
3395c1692a5faeab220881a17a3427a8986ef874403Andrew Sapperstein}
340