blob: 1fed820c5026582735f04a708b015885e1ae3981 [file] [log] [blame]
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -07001/*
2 * Copyright (C) 2013 Google Inc.
3 * Licensed to The Android Open Source Project.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mail.ui;
19
20import android.app.Fragment;
Andrew Sapperstein21a6ed22013-07-17 18:33:00 -070021import android.app.FragmentManager;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070022import android.content.res.Resources;
Martin Hibdon50554de2014-01-07 16:28:04 -080023import android.graphics.Rect;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070024import android.os.Bundle;
25import android.view.LayoutInflater;
26import android.view.View;
27import android.view.ViewGroup;
28import android.webkit.WebSettings;
29
30import com.android.mail.FormattedDateBuilder;
31import com.android.mail.R;
Andrew Sapperstein381c3222014-04-20 12:23:57 -070032import com.android.mail.browse.AttachmentActionHandler;
Andrew Sappersteine7e2c0a2013-08-02 17:09:54 -070033import com.android.mail.browse.BorderView;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070034import com.android.mail.browse.ConversationMessage;
35import com.android.mail.browse.ConversationViewAdapter;
Andrew Sapperstein381c3222014-04-20 12:23:57 -070036import com.android.mail.browse.ConversationViewAdapter.MessageFooterItem;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070037import com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem;
38import com.android.mail.browse.ConversationViewHeader;
Andrew Sapperstein8ec43e82013-12-17 18:27:55 -080039import com.android.mail.browse.InlineAttachmentViewIntentBuilderCreator;
40import com.android.mail.browse.InlineAttachmentViewIntentBuilderCreatorHolder;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070041import com.android.mail.browse.MessageFooterView;
42import com.android.mail.browse.MessageHeaderView;
43import com.android.mail.browse.MessageScrollView;
44import com.android.mail.browse.MessageWebView;
Martin Hibdon50554de2014-01-07 16:28:04 -080045import com.android.mail.browse.ScrollNotifier.ScrollListener;
Andrew Sappersteine3077852013-12-11 18:04:25 -080046import com.android.mail.browse.WebViewContextMenu;
Andrew Sapperstein562c5ba2013-10-09 18:31:50 -070047import com.android.mail.print.PrintUtils;
48import com.android.mail.providers.Conversation;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070049import com.android.mail.providers.Message;
50import com.android.mail.utils.ConversationViewUtils;
51
52/**
Martin Hibdon50554de2014-01-07 16:28:04 -080053 * Controller to do most of the heavy lifting for
54 * {@link SecureConversationViewFragment} and
55 * {@link com.android.mail.browse.EmlMessageViewFragment}. Currently that work
56 * is pretty much the rendering logic.
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070057 */
58public class SecureConversationViewController implements
Andrew Sapperstein381c3222014-04-20 12:23:57 -070059 MessageHeaderView.MessageHeaderViewCallbacks, ScrollListener,
60 MessageFooterView.MessageFooterCallbacks {
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070061 private static final String BEGIN_HTML =
Andrew Sappersteind4945f22014-03-29 18:36:09 -070062 "<body style=\"margin: 0 %spx;\"><div style=\"margin: 16px 0; font-size: 80%%\">";
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070063 private static final String END_HTML = "</div></body>";
64
65 private final SecureConversationViewControllerCallbacks mCallbacks;
66
67 private MessageWebView mWebView;
68 private ConversationViewHeader mConversationHeaderView;
69 private MessageHeaderView mMessageHeaderView;
Martin Hibdon50554de2014-01-07 16:28:04 -080070 private MessageHeaderView mSnapHeaderView;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070071 private MessageFooterView mMessageFooterView;
72 private ConversationMessage mMessage;
73 private MessageScrollView mScrollView;
74
75 private ConversationViewProgressController mProgressController;
76 private FormattedDateBuilder mDateBuilder;
77
78 private int mSideMarginInWebPx;
79
80 public SecureConversationViewController(SecureConversationViewControllerCallbacks callbacks) {
81 mCallbacks = callbacks;
82 }
83
84 public View onCreateView(LayoutInflater inflater, ViewGroup container,
85 Bundle savedInstanceState) {
86 View rootView = inflater.inflate(R.layout.secure_conversation_view, container, false);
87 mScrollView = (MessageScrollView) rootView.findViewById(R.id.scroll_view);
88 mConversationHeaderView = (ConversationViewHeader) rootView.findViewById(R.id.conv_header);
89 mMessageHeaderView = (MessageHeaderView) rootView.findViewById(R.id.message_header);
Martin Hibdon50554de2014-01-07 16:28:04 -080090 mSnapHeaderView = (MessageHeaderView) rootView.findViewById(R.id.snap_header);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070091 mMessageFooterView = (MessageFooterView) rootView.findViewById(R.id.message_footer);
92
Martin Hibdon50554de2014-01-07 16:28:04 -080093 mScrollView.addScrollListener(this);
94
Andrew Sappersteine7e2c0a2013-08-02 17:09:54 -070095 // Add color backgrounds to the header and footer.
96 // Otherwise the backgrounds are grey. They can't
97 // be set in xml because that would add more overdraw
98 // in ConversationViewFragment.
99 final int color = rootView.getResources().getColor(
100 R.color.message_header_background_color);
101 mMessageHeaderView.setBackgroundColor(color);
Andrew Sapperstein2ed8c042014-02-27 18:52:32 -0800102 mSnapHeaderView.findViewById(R.id.upper_header).setBackgroundColor(color);
Andrew Sappersteine7e2c0a2013-08-02 17:09:54 -0700103 mMessageFooterView.setBackgroundColor(color);
104
105 ((BorderView) rootView.findViewById(R.id.top_border)).disableCardBottomBorder();
106 ((BorderView) rootView.findViewById(R.id.bottom_border)).disableCardTopBorder();
107
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700108 mProgressController = new ConversationViewProgressController(
109 mCallbacks.getFragment(), mCallbacks.getHandler());
110 mProgressController.instantiateProgressIndicators(rootView);
111 mWebView = (MessageWebView) rootView.findViewById(R.id.webview);
Andrew Sappersteine45fd112013-08-29 17:34:34 -0700112 mWebView.setOverScrollMode(View.OVER_SCROLL_NEVER);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700113 mWebView.setWebViewClient(mCallbacks.getWebViewClient());
Andrew Sapperstein8ec43e82013-12-17 18:27:55 -0800114 final InlineAttachmentViewIntentBuilderCreator creator =
115 InlineAttachmentViewIntentBuilderCreatorHolder.
Martin Hibdon50554de2014-01-07 16:28:04 -0800116 getInlineAttachmentViewIntentCreator();
Andrew Sapperstein8ec43e82013-12-17 18:27:55 -0800117 mWebView.setOnCreateContextMenuListener(new WebViewContextMenu(
118 mCallbacks.getFragment().getActivity(),
Andy Huang3c6fd442014-03-24 19:56:46 -0700119 creator.createInlineAttachmentViewIntentBuilder(null, -1)));
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700120 mWebView.setFocusable(false);
121 final WebSettings settings = mWebView.getSettings();
122
123 settings.setJavaScriptEnabled(false);
124 settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
125
126 ConversationViewUtils.setTextZoom(mCallbacks.getFragment().getResources(), settings);
127
128 settings.setSupportZoom(true);
129 settings.setBuiltInZoomControls(true);
130 settings.setDisplayZoomControls(false);
131
132 mScrollView.setInnerScrollableView(mWebView);
133
134 return rootView;
135 }
136
137 public void onActivityCreated(Bundle savedInstanceState) {
138 mCallbacks.setupConversationHeaderView(mConversationHeaderView);
139
140 final Fragment fragment = mCallbacks.getFragment();
141
142 mDateBuilder = new FormattedDateBuilder(fragment.getActivity());
Andrew Sapperstein14f93742013-07-25 14:29:56 -0700143 mMessageHeaderView.initialize(
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700144 mCallbacks.getConversationAccountController(), mCallbacks.getAddressCache());
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700145 mMessageHeaderView.setContactInfoSource(mCallbacks.getContactInfoSource());
146 mMessageHeaderView.setCallbacks(this);
147 mMessageHeaderView.setExpandable(false);
148 mMessageHeaderView.setViewOnlyMode(mCallbacks.isViewOnlyMode());
149
Martin Hibdon50554de2014-01-07 16:28:04 -0800150 mSnapHeaderView.setSnappy();
151 mSnapHeaderView.initialize(
152 mCallbacks.getConversationAccountController(), mCallbacks.getAddressCache());
153 mSnapHeaderView.setContactInfoSource(mCallbacks.getContactInfoSource());
154 mSnapHeaderView.setCallbacks(this);
155 mSnapHeaderView.setExpandable(false);
156 mSnapHeaderView.setViewOnlyMode(mCallbacks.isViewOnlyMode());
157
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700158 mCallbacks.setupMessageHeaderVeiledMatcher(mMessageHeaderView);
Martin Hibdon50554de2014-01-07 16:28:04 -0800159 mCallbacks.setupMessageHeaderVeiledMatcher(mSnapHeaderView);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700160
Andrew Sappersteinf59d01c2014-02-20 10:27:06 -0800161 mMessageFooterView.initialize(fragment.getLoaderManager(), fragment.getFragmentManager(),
Andrew Sapperstein381c3222014-04-20 12:23:57 -0700162 mCallbacks.getConversationAccountController(), this);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700163
164 mCallbacks.startMessageLoader();
165
166 mProgressController.showLoadingStatus(mCallbacks.isViewVisibleToUser());
167
168 final Resources r = mCallbacks.getFragment().getResources();
Andrew Sapperstein90eccf92013-08-22 11:53:23 -0700169 mSideMarginInWebPx = (int) (r.getDimensionPixelOffset(
170 R.dimen.conversation_message_content_margin_side) / r.getDisplayMetrics().density);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700171 }
172
Andrew Sapperstein381c3222014-04-20 12:23:57 -0700173 public void onDestroyView() {
Andrew Sapperstein41d2b6b2014-04-23 14:20:15 -0700174 if (mMessage != null && mMessage.getConversation() != null) {
175 AttachmentActionHandler.unregisterDismissListeners(mMessage.getConversation().uri);
176 }
Andrew Sapperstein381c3222014-04-20 12:23:57 -0700177 }
178
Martin Hibdon50554de2014-01-07 16:28:04 -0800179 @Override
180 public void onNotifierScroll(final int y) {
181 // We need to decide whether or not to display the snap header.
182 // Get the location of the moveable message header inside the scroll view.
183 Rect rect = new Rect();
184 mScrollView.offsetDescendantRectToMyCoords(mMessageHeaderView, rect);
185
186 // If we have scrolled further than the distance from the top of the scrollView to the top
187 // of the message header, then the message header is at least partially ofscreen. As soon
188 // as the message header goes partially offscreen we need to display the snap header.
189 if (y > rect.top) {
190 mSnapHeaderView.setVisibility(View.VISIBLE);
191 } else {
192 mSnapHeaderView.setVisibility(View.GONE);
193 }
194 }
195
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700196 /**
197 * Populate the adapter with overlay views (message headers, super-collapsed
198 * blocks, a conversation header), and return an HTML document with spacer
199 * divs inserted for all overlays.
200 */
201 public void renderMessage(ConversationMessage message) {
202 mMessage = message;
203
Andrew Sapperstein8ec43e82013-12-17 18:27:55 -0800204 final boolean alwaysShowImages = mCallbacks.shouldAlwaysShowImages();
205 mWebView.getSettings().setBlockNetworkImage(
206 !alwaysShowImages && !mMessage.alwaysShowImages);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700207
208 // Add formatting to message body
209 // At this point, only adds margins.
210 StringBuilder dataBuilder = new StringBuilder(
211 String.format(BEGIN_HTML, mSideMarginInWebPx));
212 dataBuilder.append(mMessage.getBodyAsHtml());
213 dataBuilder.append(END_HTML);
214
215 mWebView.loadDataWithBaseURL(mCallbacks.getBaseUri(), dataBuilder.toString(),
216 "text/html", "utf-8", null);
217 final MessageHeaderItem item = ConversationViewAdapter.newMessageHeaderItem(
Andrew Sapperstein14f93742013-07-25 14:29:56 -0700218 null, mDateBuilder, mMessage, true, mMessage.alwaysShowImages);
Tony Mantler37ce6072013-10-04 09:28:43 -0700219 // Clear out the old info from the header before (re)binding
220 mMessageHeaderView.unbind();
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700221 mMessageHeaderView.bind(item, false);
Martin Hibdon50554de2014-01-07 16:28:04 -0800222
223 mSnapHeaderView.unbind();
224 mSnapHeaderView.bind(item, false);
225
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700226 if (mMessage.hasAttachments) {
227 mMessageFooterView.setVisibility(View.VISIBLE);
Andrew Sapperstein381c3222014-04-20 12:23:57 -0700228 mMessageFooterView.bind(
229 item, ConversationViewAdapter.newMessageFooterItem(null, item), false);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700230 }
231 }
232
233 public ConversationMessage getMessage() {
234 return mMessage;
235 }
236
237 public ConversationViewHeader getConversationHeaderView() {
238 return mConversationHeaderView;
239 }
240
241 public void dismissLoadingStatus() {
242 mProgressController.dismissLoadingStatus();
243 }
244
245 public void setSubject(String subject) {
Andrew Sappersteine6bf30d2014-03-13 19:19:26 -0700246 mConversationHeaderView.setSubject(subject);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700247 }
248
Andrew Sapperstein562c5ba2013-10-09 18:31:50 -0700249 public void printMessage() {
250 final Conversation conversation = mMessage.getConversation();
Andrew Sapperstein234d3532013-10-29 14:54:04 -0700251 PrintUtils.printMessage(mCallbacks.getFragment().getActivity(), mMessage,
Andrew Sapperstein562c5ba2013-10-09 18:31:50 -0700252 conversation != null ? conversation.subject : mMessage.subject,
253 mCallbacks.getAddressCache(), mCallbacks.getBaseUri(), false /* useJavascript */);
254
Andrew Sapperstein5c1692a2013-09-16 11:56:13 -0700255 }
256
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700257 // Start MessageHeaderViewCallbacks implementations
258
259 @Override
260 public void setMessageSpacerHeight(MessageHeaderItem item, int newSpacerHeight) {
261 // Do nothing.
262 }
263
264 @Override
Andrew Sappersteincee3c902013-07-31 10:52:02 -0700265 public void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight,
266 int topBorderHeight, int bottomBorderHeight) {
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700267 // Do nothing.
268 }
269
270 @Override
271 public void setMessageDetailsExpanded(MessageHeaderItem i, boolean expanded, int heightBefore) {
272 // Do nothing.
273 }
274
275 @Override
276 public void showExternalResources(final Message msg) {
277 mWebView.getSettings().setBlockNetworkImage(false);
278 }
279
280 @Override
281 public void showExternalResources(final String rawSenderAddress) {
282 mWebView.getSettings().setBlockNetworkImage(false);
283 }
284
285 @Override
286 public boolean supportsMessageTransforms() {
287 return false;
288 }
289
290 @Override
291 public String getMessageTransforms(final Message msg) {
292 return null;
293 }
294
Andrew Sapperstein21a6ed22013-07-17 18:33:00 -0700295 @Override
James Lemieux8e1ffbf2014-04-22 15:53:31 -0700296 public boolean isSecure() {
297 return true;
298 }
299
300 @Override
Andrew Sapperstein21a6ed22013-07-17 18:33:00 -0700301 public FragmentManager getFragmentManager() {
302 return mCallbacks.getFragment().getFragmentManager();
303 }
304
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700305 // End MessageHeaderViewCallbacks implementations
Andrew Sapperstein381c3222014-04-20 12:23:57 -0700306
307 // START MessageFooterCallbacks
308
309 @Override
310 public void setMessageSpacerHeight(MessageFooterItem item, int newSpacerHeight) {
311 // Do nothing.
312 }
313
314 @Override
315 public MessageFooterView getViewForItem(MessageFooterItem item) {
316 return mMessageFooterView;
317 }
318
319 @Override
320 public int getUpdatedHeight(MessageFooterItem item) {
321 return 0; // should never get called since we'll always have a footer view
322 }
323
324 // END MessageFooterCallbacks
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700325}