diff options
author | Andrew Sapperstein <asapperstein@google.com> | 2013-10-09 18:31:50 -0700 |
---|---|---|
committer | Andrew Sapperstein <asapperstein@google.com> | 2013-10-11 10:06:20 -0700 |
commit | 562c5ba7235948cf1d20a9afa40e67cd62f43cf7 (patch) | |
tree | a9f4b987f3fc76a7681850065659be35f2782af9 /src/com/android | |
parent | 926825ba228b25307cb23a6c384f24fc3637d627 (diff) | |
download | android_packages_apps_UnifiedEmail-562c5ba7235948cf1d20a9afa40e67cd62f43cf7.tar.gz android_packages_apps_UnifiedEmail-562c5ba7235948cf1d20a9afa40e67cd62f43cf7.tar.bz2 android_packages_apps_UnifiedEmail-562c5ba7235948cf1d20a9afa40e67cd62f43cf7.zip |
Print single message and offscreen webview.
b/10712542.
Also supports Eml printing and secure printing (though
that's email only and has some buggy rendering).
Also fixes the no subject crash. b/11136365
Change-Id: Ie5f6e7d7e1762c115df3169b6e62dc439545f08c
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/mail/browse/EmlMessageViewFragment.java | 14 | ||||
-rw-r--r-- | src/com/android/mail/browse/EmlViewerActivity.java | 1 | ||||
-rw-r--r-- | src/com/android/mail/browse/MessageHeaderView.java | 22 | ||||
-rw-r--r-- | src/com/android/mail/print/HtmlPrintTemplates.java | 10 | ||||
-rw-r--r-- | src/com/android/mail/print/PrintUtils.java (renamed from src/com/android/mail/print/Printer.java) | 118 | ||||
-rw-r--r-- | src/com/android/mail/ui/AbstractConversationViewFragment.java | 6 | ||||
-rw-r--r-- | src/com/android/mail/ui/ConversationViewFragment.java | 19 | ||||
-rw-r--r-- | src/com/android/mail/ui/SecureConversationViewController.java | 10 | ||||
-rw-r--r-- | src/com/android/mail/ui/SecureConversationViewFragment.java | 2 |
9 files changed, 153 insertions, 49 deletions
diff --git a/src/com/android/mail/browse/EmlMessageViewFragment.java b/src/com/android/mail/browse/EmlMessageViewFragment.java index c0f7f9b30..ad2223200 100644 --- a/src/com/android/mail/browse/EmlMessageViewFragment.java +++ b/src/com/android/mail/browse/EmlMessageViewFragment.java @@ -28,6 +28,7 @@ import android.os.Bundle; import android.os.Handler; import android.provider.OpenableColumns; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.webkit.WebView; @@ -149,6 +150,7 @@ public class EmlMessageViewFragment extends Fragment mWebViewClient = new EmlWebViewClient(null); mViewController = new SecureConversationViewController(this); + setHasOptionsMenu(true); getActivity().getActionBar().setTitle(R.string.attached_message); } @@ -165,6 +167,18 @@ public class EmlMessageViewFragment extends Fragment mViewController.onActivityCreated(savedInstanceState); } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + final int itemId = item.getItemId(); + if (itemId == R.id.print_message) { + mViewController.printMessage(); + } else { + return super.onOptionsItemSelected(item); + } + + return true; + } + // Start SecureConversationViewControllerCallbacks @Override diff --git a/src/com/android/mail/browse/EmlViewerActivity.java b/src/com/android/mail/browse/EmlViewerActivity.java index cc631c634..f40b3ef23 100644 --- a/src/com/android/mail/browse/EmlViewerActivity.java +++ b/src/com/android/mail/browse/EmlViewerActivity.java @@ -134,7 +134,6 @@ public class EmlViewerActivity extends Activity implements FeedbackEnabledActivi final int itemId = item.getItemId(); if (itemId == android.R.id.home) { finish(); - return true; } else if (itemId == R.id.settings) { Utils.showSettings(this, mAccount); } else if (itemId == R.id.help_info_menu_item) { diff --git a/src/com/android/mail/browse/MessageHeaderView.java b/src/com/android/mail/browse/MessageHeaderView.java index 677be9db2..ce24bf592 100644 --- a/src/com/android/mail/browse/MessageHeaderView.java +++ b/src/com/android/mail/browse/MessageHeaderView.java @@ -55,12 +55,14 @@ import com.android.mail.compose.ComposeActivity; import com.android.mail.perf.Timer; import com.android.mail.photomanager.LetterTileProvider; import com.android.mail.preferences.AccountPreferences; +import com.android.mail.print.PrintUtils; import com.android.mail.providers.Account; import com.android.mail.providers.Address; import com.android.mail.providers.Conversation; import com.android.mail.providers.Folder; import com.android.mail.providers.Message; import com.android.mail.providers.UIProvider; +import com.android.mail.ui.AbstractConversationViewFragment; import com.android.mail.ui.ImageCanvas; import com.android.mail.utils.LogTag; import com.android.mail.utils.LogUtils; @@ -869,14 +871,16 @@ public class MessageHeaderView extends LinearLayout implements OnClickListener, ComposeActivity.replyAll(getContext(), getAccount(), mMessage); } else if (id == R.id.forward) { ComposeActivity.forward(getContext(), getAccount(), mMessage); + } else if (id == R.id.print_message) { + printMessage(); } else if (id == R.id.report_rendering_problem) { final String text = getContext().getString(R.string.report_rendering_problem_desc); ComposeActivity.reportRenderingFeedback(getContext(), getAccount(), mMessage, - text + "\n\n" + mCallbacks.getMessageTransforms(mMessage)); + text + "\n\n" + mCallbacks.getMessageTransforms(mMessage)); } else if (id == R.id.report_rendering_improvement) { final String text = getContext().getString(R.string.report_rendering_improvement_desc); ComposeActivity.reportRenderingFeedback(getContext(), getAccount(), mMessage, - text + "\n\n" + mCallbacks.getMessageTransforms(mMessage)); + text + "\n\n" + mCallbacks.getMessageTransforms(mMessage)); } else if (id == R.id.star) { final boolean newValue = !v.isSelected(); v.setSelected(newValue); @@ -917,8 +921,20 @@ public class MessageHeaderView extends LinearLayout implements OnClickListener, return handled; } + private void printMessage() { + // Secure conversation view does not use a conversation view adapter + // so it's safe to test for existence as a signal to use javascript or not. + final boolean useJavascript = mMessageHeaderItem.getAdapter() != null; + final Account account = mAccountController.getAccount(); + final Conversation conversation = mMessage.getConversation(); + final String baseUri = + AbstractConversationViewFragment.buildBaseUri(account, conversation); + PrintUtils.printMessage(getContext(), mMessage, conversation.subject, + mAddressCache, conversation.getBaseUri(baseUri), useJavascript); + } + /** - * Set to true if the user should not be able to perfrom message actions + * Set to true if the user should not be able to perform message actions * on the message such as reply/reply all/forward/star/etc. * * Default is false. diff --git a/src/com/android/mail/print/HtmlPrintTemplates.java b/src/com/android/mail/print/HtmlPrintTemplates.java index 27dfba352..cf0399ca9 100644 --- a/src/com/android/mail/print/HtmlPrintTemplates.java +++ b/src/com/android/mail/print/HtmlPrintTemplates.java @@ -19,6 +19,7 @@ package com.android.mail.print; import android.content.Context; import android.content.res.Resources; +import android.text.TextUtils; import com.android.mail.R; import com.android.mail.ui.AbstractHtmlTemplates; @@ -51,8 +52,7 @@ public class HtmlPrintTemplates extends AbstractHtmlTemplates { * until {@link #endPrintConversation()} or {@link #endPrintConversationNoJavascript()} * is called. */ - public void startPrintConversation(String accountName, String accountAddress, - String subject, int numMessages) { + public void startPrintConversation(String subject, int numMessages) { if (mInProgress) { throw new IllegalStateException("Should not call startPrintConversation twice"); } @@ -62,9 +62,11 @@ public class HtmlPrintTemplates extends AbstractHtmlTemplates { final Resources res = mContext.getResources(); final String numMessageString = res.getQuantityString( R.plurals.num_messages, numMessages, numMessages); + + final String printedSubject = TextUtils.isEmpty(subject) + ? res.getString(R.string.no_subject) : subject; append(mConversationUpper, mContext.getString(R.string.app_name), - accountName == null ? "" : accountName, - accountAddress, subject, numMessageString); + printedSubject, numMessageString); mInProgress = true; } diff --git a/src/com/android/mail/print/Printer.java b/src/com/android/mail/print/PrintUtils.java index 0a3cd49c0..082bc5786 100644 --- a/src/com/android/mail/print/Printer.java +++ b/src/com/android/mail/print/PrintUtils.java @@ -19,16 +19,20 @@ package com.android.mail.print; import android.content.Context; import android.content.res.Resources; +import android.print.PrintAttributes; +import android.print.PrintManager; import android.text.TextUtils; +import android.webkit.WebSettings; +import android.webkit.WebView; import com.android.mail.FormattedDateBuilder; import com.android.mail.R; -import com.android.mail.browse.ConversationMessage; import com.android.mail.browse.MessageCursor; -import com.android.mail.providers.Account; + import com.android.mail.providers.Address; import com.android.mail.providers.Attachment; import com.android.mail.providers.Conversation; +import com.android.mail.providers.Message; import com.android.mail.providers.UIProvider; import com.android.mail.utils.AttachmentUtils; import com.android.mail.utils.Utils; @@ -37,17 +41,63 @@ import java.util.List; import java.util.Map; /** - * Static class that provides a {@link #print} function to build a print html document. + * Utility class that provides utility functions to print + * either a conversation or message. */ -public class Printer { +public class PrintUtils { private static final String DIV_START = "<div>"; private static final String REPLY_TO_DIV_START = "<div class=\"replyto\">"; private static final String DIV_END = "</div>"; /** + * Prints an entire conversation. + */ + public static void printConversation(Context context, + MessageCursor cursor, Map<String, Address> addressCache, + String baseUri, boolean useJavascript) { + final String convHtml = buildConversationHtml(context, cursor, + addressCache, useJavascript); + printHtml(context, convHtml, baseUri, cursor.getConversation().subject, useJavascript); + } + + /** + * Prints one message. + */ + public static void printMessage(Context context, Message message, String subject, + Map<String, Address> addressCache, String baseUri, boolean useJavascript) { + final String msgHtml = buildMessageHtml(context, message, + subject, addressCache, useJavascript); + printHtml(context, msgHtml, baseUri, subject, useJavascript); + } + + /** + * Prints the html provided using the framework printing APIs. + * + * Sets up a webview to perform the printing work. + */ + private static void printHtml(Context context, String html, + String baseUri, String subject, boolean useJavascript) { + final WebView webView = new WebView(context); + final WebSettings settings = webView.getSettings(); + settings.setBlockNetworkImage(false); + settings.setJavaScriptEnabled(useJavascript); + webView.loadDataWithBaseURL(baseUri, html, + "text/html", "utf-8", null); + final PrintManager printManager = + (PrintManager) context.getSystemService(Context.PRINT_SERVICE); + + final String printJobName = TextUtils.isEmpty(subject) + ? context.getString(R.string.app_name) + : context.getString(R.string.print_job_name, subject); + printManager.print(printJobName, + webView.createPrintDocumentAdapter(), + new PrintAttributes.Builder().build()); + } + + /** * Builds an html document that is suitable for printing and returns it as a {@link String}. */ - public static String print(Context context, Account account, + private static String buildConversationHtml(Context context, MessageCursor cursor, Map<String, Address> addressCache, boolean useJavascript) { final HtmlPrintTemplates templates = new HtmlPrintTemplates(context); final FormattedDateBuilder dateBuilder = new FormattedDateBuilder(context); @@ -56,25 +106,34 @@ public class Printer { throw new IllegalStateException("trying to print without a conversation"); } - // TODO - remove account name(not account.name which is email address) or get it somehow final Conversation conversation = cursor.getConversation(); - templates.startPrintConversation("", account.name, - conversation.subject, conversation.getNumMessages()); + templates.startPrintConversation(conversation.subject, conversation.getNumMessages()); // for each message in the conversation, add message html final Resources res = context.getResources(); do { - final ConversationMessage message = cursor.getMessage(); - final Address fromAddress = Utils.getAddress(addressCache, message.getFrom()); - final long when = message.dateReceivedMs; - final String date = res.getString(R.string.date_message_received_print, - dateBuilder.formatLongDayAndDate(when), dateBuilder.formatLongTime(when)); + final Message message = cursor.getMessage(); + appendSingleMessageHtml(context, res, message, addressCache, templates, dateBuilder); + } while (cursor.moveToNext()); + + // only include JavaScript if specifically requested + return useJavascript ? + templates.endPrintConversation() : templates.endPrintConversationNoJavascript(); + } + /** + * Builds an html document suitable for printing and returns it as a {@link String}. + */ + private static String buildMessageHtml(Context context, Message message, + String subject, Map<String, Address> addressCache, boolean useJavascript) { + final HtmlPrintTemplates templates = new HtmlPrintTemplates(context); + final FormattedDateBuilder dateBuilder = new FormattedDateBuilder(context); - templates.appendMessage(fromAddress.getName(), fromAddress.getAddress(), date, - renderRecipients(res, addressCache, message), message.getBodyAsHtml(), - renderAttachments(context, res, message)); - } while (cursor.moveToNext()); + templates.startPrintConversation(subject, 1 /* numMessages */); + + // add message html + final Resources res = context.getResources(); + appendSingleMessageHtml(context, res, message, addressCache, templates, dateBuilder); // only include JavaScript if specifically requested return useJavascript ? @@ -82,11 +141,29 @@ public class Printer { } /** + * Adds the html for a single message to the + * {@link HtmlPrintTemplates} provided. + */ + private static void appendSingleMessageHtml(Context context, Resources res, + Message message, Map<String, Address> addressCache, + HtmlPrintTemplates templates, FormattedDateBuilder dateBuilder) { + final Address fromAddress = Utils.getAddress(addressCache, message.getFrom()); + final long when = message.dateReceivedMs; + final String date = res.getString(R.string.date_message_received_print, + dateBuilder.formatLongDayAndDate(when), dateBuilder.formatLongTime(when)); + + + templates.appendMessage(fromAddress.getName(), fromAddress.getAddress(), date, + renderRecipients(res, addressCache, message), message.getBodyAsHtml(), + renderAttachments(context, res, message)); + } + + /** * Builds html for the message header. Specifically, the (optional) lists of * reply-to, to, cc, and bcc. */ - private static String renderRecipients(Resources res, Map<String, Address> addressCache, - ConversationMessage message) { + private static String renderRecipients(Resources res, + Map<String, Address> addressCache, Message message) { final StringBuilder recipients = new StringBuilder(); // reply-to @@ -163,7 +240,7 @@ public class Printer { * Builds and returns html for a message's attachments. */ private static String renderAttachments( - Context context, Resources resources, ConversationMessage message) { + Context context, Resources resources, Message message) { if (!message.hasAttachments) { return ""; } @@ -186,7 +263,6 @@ public class Printer { sb.append("<tr><td><table cellspacing=\"0\" cellpadding=\"0\"><tr>"); // TODO - thumbnail previews of images - sb.append("<td><img width=\"16\" height=\"16\" src=\"file:///android_asset/images/") .append(getIconFilename(attachment.getContentType())) .append("\"></td><td width=\"7\"></td><td><b>") diff --git a/src/com/android/mail/ui/AbstractConversationViewFragment.java b/src/com/android/mail/ui/AbstractConversationViewFragment.java index fc5218fc1..3e481906f 100644 --- a/src/com/android/mail/ui/AbstractConversationViewFragment.java +++ b/src/com/android/mail/ui/AbstractConversationViewFragment.java @@ -221,9 +221,13 @@ public abstract class AbstractConversationViewFragment extends Fragment implemen * (such as one that does not rely on account and/or conversation. */ protected void setBaseUri() { + mBaseUri = buildBaseUri(mAccount, mConversation); + } + + public static String buildBaseUri(Account account, Conversation conversation) { // Since the uri specified in the conversation base uri may not be unique, we specify a // base uri that us guaranteed to be unique for this conversation. - mBaseUri = "x-thread://" + mAccount.getEmailAddress().hashCode() + "/" + mConversation.id; + return "x-thread://" + account.getEmailAddress().hashCode() + "/" + conversation.id; } @Override diff --git a/src/com/android/mail/ui/ConversationViewFragment.java b/src/com/android/mail/ui/ConversationViewFragment.java index 63ade3979..e42b6e602 100644 --- a/src/com/android/mail/ui/ConversationViewFragment.java +++ b/src/com/android/mail/ui/ConversationViewFragment.java @@ -27,9 +27,6 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.SystemClock; -import android.print.PrintAttributes; -import android.print.PrintJob; -import android.print.PrintManager; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.ScaleGestureDetector; @@ -67,7 +64,7 @@ import com.android.mail.browse.SuperCollapsedBlock; import com.android.mail.browse.WebViewContextMenu; import com.android.mail.content.ObjectCursor; import com.android.mail.preferences.AccountPreferences; -import com.android.mail.print.Printer; +import com.android.mail.print.PrintUtils; import com.android.mail.providers.Account; import com.android.mail.providers.Address; import com.android.mail.providers.Conversation; @@ -1580,17 +1577,7 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i } protected void printConversation() { - // TODO - offscreen webview stuff so that we don't clobber - final String convHtml = - Printer.print(getContext(), mAccount, getMessageCursor(), - mAddressCache, true /* userJavascript */); - mWebView.getSettings().setBlockNetworkImage(false); - mWebView.loadDataWithBaseURL( - mConversation.getBaseUri(mBaseUri), convHtml, "text/html", "utf-8", null); - final PrintManager printManager = - (PrintManager) getContext().getSystemService(Context.PRINT_SERVICE); - printManager.print(mConversation.subject, - mWebView.createPrintDocumentAdapter(), - new PrintAttributes.Builder().build()); + PrintUtils.printConversation(getContext(), getMessageCursor(), mAddressCache, + mConversation.getBaseUri(mBaseUri), true /* useJavascript */); } } diff --git a/src/com/android/mail/ui/SecureConversationViewController.java b/src/com/android/mail/ui/SecureConversationViewController.java index 19a57e362..c65ea5a2f 100644 --- a/src/com/android/mail/ui/SecureConversationViewController.java +++ b/src/com/android/mail/ui/SecureConversationViewController.java @@ -37,6 +37,8 @@ import com.android.mail.browse.MessageFooterView; import com.android.mail.browse.MessageHeaderView; import com.android.mail.browse.MessageScrollView; import com.android.mail.browse.MessageWebView; +import com.android.mail.print.PrintUtils; +import com.android.mail.providers.Conversation; import com.android.mail.providers.Message; import com.android.mail.utils.ConversationViewUtils; @@ -185,8 +187,12 @@ public class SecureConversationViewController implements mConversationHeaderView.setSubject(subject); } - public void printConversation() { - // TODO - implement this + public void printMessage() { + final Conversation conversation = mMessage.getConversation(); + PrintUtils.printMessage(mCallbacks.getContext(), mMessage, + conversation != null ? conversation.subject : mMessage.subject, + mCallbacks.getAddressCache(), mCallbacks.getBaseUri(), false /* useJavascript */); + } // Start MessageHeaderViewCallbacks implementations diff --git a/src/com/android/mail/ui/SecureConversationViewFragment.java b/src/com/android/mail/ui/SecureConversationViewFragment.java index 9ee32e46c..051940c47 100644 --- a/src/com/android/mail/ui/SecureConversationViewFragment.java +++ b/src/com/android/mail/ui/SecureConversationViewFragment.java @@ -267,6 +267,6 @@ public class SecureConversationViewFragment extends AbstractConversationViewFrag } protected void printConversation() { - mViewController.printConversation(); + mViewController.printMessage(); } } |