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 <email>". 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