blob: 52d6c7853bcea4ba4c8d572d4fc354761681260b [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;
Andrew Sapperstein2fd167d2014-01-28 10:07:38 -080025import android.support.v4.text.BidiFormatter;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070026import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.webkit.WebSettings;
30
31import com.android.mail.FormattedDateBuilder;
32import com.android.mail.R;
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;
36import com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem;
37import com.android.mail.browse.ConversationViewHeader;
Andrew Sapperstein8ec43e82013-12-17 18:27:55 -080038import com.android.mail.browse.InlineAttachmentViewIntentBuilderCreator;
39import com.android.mail.browse.InlineAttachmentViewIntentBuilderCreatorHolder;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070040import com.android.mail.browse.MessageFooterView;
41import com.android.mail.browse.MessageHeaderView;
42import com.android.mail.browse.MessageScrollView;
43import com.android.mail.browse.MessageWebView;
Martin Hibdon50554de2014-01-07 16:28:04 -080044import com.android.mail.browse.ScrollNotifier.ScrollListener;
Andrew Sappersteine3077852013-12-11 18:04:25 -080045import com.android.mail.browse.WebViewContextMenu;
Andrew Sapperstein562c5ba2013-10-09 18:31:50 -070046import com.android.mail.print.PrintUtils;
47import com.android.mail.providers.Conversation;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070048import com.android.mail.providers.Message;
49import com.android.mail.utils.ConversationViewUtils;
50
51/**
Martin Hibdon50554de2014-01-07 16:28:04 -080052 * Controller to do most of the heavy lifting for
53 * {@link SecureConversationViewFragment} and
54 * {@link com.android.mail.browse.EmlMessageViewFragment}. Currently that work
55 * is pretty much the rendering logic.
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070056 */
57public class SecureConversationViewController implements
Martin Hibdon50554de2014-01-07 16:28:04 -080058 MessageHeaderView.MessageHeaderViewCallbacks, ScrollListener {
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070059 private static final String BEGIN_HTML =
Martin Hibdon50554de2014-01-07 16:28:04 -080060 "<body style=\"margin: 0 %spx;\"><div style=\"margin: 16px 0; font-size: 80%%\">";
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070061 private static final String END_HTML = "</div></body>";
62
63 private final SecureConversationViewControllerCallbacks mCallbacks;
Andrew Sapperstein2fd167d2014-01-28 10:07:38 -080064 private final BidiFormatter mBidiFormatter;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070065
66 private MessageWebView mWebView;
67 private ConversationViewHeader mConversationHeaderView;
68 private MessageHeaderView mMessageHeaderView;
Martin Hibdon50554de2014-01-07 16:28:04 -080069 private MessageHeaderView mSnapHeaderView;
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070070 private MessageFooterView mMessageFooterView;
71 private ConversationMessage mMessage;
72 private MessageScrollView mScrollView;
73
74 private ConversationViewProgressController mProgressController;
75 private FormattedDateBuilder mDateBuilder;
76
77 private int mSideMarginInWebPx;
78
79 public SecureConversationViewController(SecureConversationViewControllerCallbacks callbacks) {
80 mCallbacks = callbacks;
Andrew Sapperstein2fd167d2014-01-28 10:07:38 -080081 mBidiFormatter = BidiFormatter.getInstance();
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -070082 }
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(),
119 creator.createInlineAttachmentViewIntentBuilder(null, 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
161 mMessageFooterView.initialize(fragment.getLoaderManager(), fragment.getFragmentManager());
162
163 mCallbacks.startMessageLoader();
164
165 mProgressController.showLoadingStatus(mCallbacks.isViewVisibleToUser());
166
167 final Resources r = mCallbacks.getFragment().getResources();
Andrew Sapperstein90eccf92013-08-22 11:53:23 -0700168 mSideMarginInWebPx = (int) (r.getDimensionPixelOffset(
169 R.dimen.conversation_message_content_margin_side) / r.getDisplayMetrics().density);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700170 }
171
Martin Hibdon50554de2014-01-07 16:28:04 -0800172 @Override
173 public void onNotifierScroll(final int y) {
174 // We need to decide whether or not to display the snap header.
175 // Get the location of the moveable message header inside the scroll view.
176 Rect rect = new Rect();
177 mScrollView.offsetDescendantRectToMyCoords(mMessageHeaderView, rect);
178
179 // If we have scrolled further than the distance from the top of the scrollView to the top
180 // of the message header, then the message header is at least partially ofscreen. As soon
181 // as the message header goes partially offscreen we need to display the snap header.
182 if (y > rect.top) {
183 mSnapHeaderView.setVisibility(View.VISIBLE);
184 } else {
185 mSnapHeaderView.setVisibility(View.GONE);
186 }
187 }
188
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700189 /**
190 * Populate the adapter with overlay views (message headers, super-collapsed
191 * blocks, a conversation header), and return an HTML document with spacer
192 * divs inserted for all overlays.
193 */
194 public void renderMessage(ConversationMessage message) {
195 mMessage = message;
196
Andrew Sapperstein8ec43e82013-12-17 18:27:55 -0800197 final boolean alwaysShowImages = mCallbacks.shouldAlwaysShowImages();
198 mWebView.getSettings().setBlockNetworkImage(
199 !alwaysShowImages && !mMessage.alwaysShowImages);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700200
201 // Add formatting to message body
202 // At this point, only adds margins.
203 StringBuilder dataBuilder = new StringBuilder(
204 String.format(BEGIN_HTML, mSideMarginInWebPx));
205 dataBuilder.append(mMessage.getBodyAsHtml());
206 dataBuilder.append(END_HTML);
207
208 mWebView.loadDataWithBaseURL(mCallbacks.getBaseUri(), dataBuilder.toString(),
209 "text/html", "utf-8", null);
210 final MessageHeaderItem item = ConversationViewAdapter.newMessageHeaderItem(
Andrew Sapperstein14f93742013-07-25 14:29:56 -0700211 null, mDateBuilder, mMessage, true, mMessage.alwaysShowImages);
Tony Mantler37ce6072013-10-04 09:28:43 -0700212 // Clear out the old info from the header before (re)binding
213 mMessageHeaderView.unbind();
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700214 mMessageHeaderView.bind(item, false);
Martin Hibdon50554de2014-01-07 16:28:04 -0800215
216 mSnapHeaderView.unbind();
217 mSnapHeaderView.bind(item, false);
218
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700219 if (mMessage.hasAttachments) {
220 mMessageFooterView.setVisibility(View.VISIBLE);
Andrew Sapperstein7638a102013-06-25 13:54:52 -0700221 mMessageFooterView.bind(item, mCallbacks.getAccountUri(), false);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700222 }
223 }
224
225 public ConversationMessage getMessage() {
226 return mMessage;
227 }
228
229 public ConversationViewHeader getConversationHeaderView() {
230 return mConversationHeaderView;
231 }
232
233 public void dismissLoadingStatus() {
234 mProgressController.dismissLoadingStatus();
235 }
236
237 public void setSubject(String subject) {
Andrew Sapperstein2fd167d2014-01-28 10:07:38 -0800238 mConversationHeaderView.setSubject(subject, mBidiFormatter);
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700239 }
240
Andrew Sapperstein562c5ba2013-10-09 18:31:50 -0700241 public void printMessage() {
242 final Conversation conversation = mMessage.getConversation();
Andrew Sapperstein234d3532013-10-29 14:54:04 -0700243 PrintUtils.printMessage(mCallbacks.getFragment().getActivity(), mMessage,
Andrew Sapperstein562c5ba2013-10-09 18:31:50 -0700244 conversation != null ? conversation.subject : mMessage.subject,
245 mCallbacks.getAddressCache(), mCallbacks.getBaseUri(), false /* useJavascript */);
246
Andrew Sapperstein5c1692a2013-09-16 11:56:13 -0700247 }
248
Andrew Sapperstein2fd167d2014-01-28 10:07:38 -0800249 public BidiFormatter getBidiFormatter() {
250 return mBidiFormatter;
251 }
252
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700253 // Start MessageHeaderViewCallbacks implementations
254
255 @Override
256 public void setMessageSpacerHeight(MessageHeaderItem item, int newSpacerHeight) {
257 // Do nothing.
258 }
259
260 @Override
Andrew Sappersteincee3c902013-07-31 10:52:02 -0700261 public void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight,
262 int topBorderHeight, int bottomBorderHeight) {
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700263 // Do nothing.
264 }
265
266 @Override
267 public void setMessageDetailsExpanded(MessageHeaderItem i, boolean expanded, int heightBefore) {
268 // Do nothing.
269 }
270
271 @Override
272 public void showExternalResources(final Message msg) {
273 mWebView.getSettings().setBlockNetworkImage(false);
274 }
275
276 @Override
277 public void showExternalResources(final String rawSenderAddress) {
278 mWebView.getSettings().setBlockNetworkImage(false);
279 }
280
281 @Override
282 public boolean supportsMessageTransforms() {
283 return false;
284 }
285
286 @Override
287 public String getMessageTransforms(final Message msg) {
288 return null;
289 }
290
Andrew Sapperstein21a6ed22013-07-17 18:33:00 -0700291 @Override
292 public FragmentManager getFragmentManager() {
293 return mCallbacks.getFragment().getFragmentManager();
294 }
295
Andrew Sapperstein4ddda2f2013-06-10 11:15:38 -0700296 // End MessageHeaderViewCallbacks implementations
297}