SecureConversationViewController.java revision 8ec43e877a9c1925514f066655984e21fbd255e8
1/*
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;
21import android.app.FragmentManager;
22import android.content.res.Resources;
23import android.os.Bundle;
24import android.view.LayoutInflater;
25import android.view.View;
26import android.view.ViewGroup;
27import android.webkit.WebSettings;
28
29import com.android.mail.FormattedDateBuilder;
30import com.android.mail.R;
31import com.android.mail.browse.BorderView;
32import com.android.mail.browse.ConversationMessage;
33import com.android.mail.browse.ConversationViewAdapter;
34import com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem;
35import com.android.mail.browse.ConversationViewHeader;
36import com.android.mail.browse.InlineAttachmentViewIntentBuilderCreator;
37import com.android.mail.browse.InlineAttachmentViewIntentBuilderCreatorHolder;
38import com.android.mail.browse.MessageFooterView;
39import com.android.mail.browse.MessageHeaderView;
40import com.android.mail.browse.MessageScrollView;
41import com.android.mail.browse.MessageWebView;
42import com.android.mail.browse.WebViewContextMenu;
43import com.android.mail.print.PrintUtils;
44import com.android.mail.providers.Conversation;
45import com.android.mail.providers.Message;
46import com.android.mail.utils.ConversationViewUtils;
47
48/**
49 * Controller to do most of the heavy lifting for {@link SecureConversationViewFragment}
50 * and {@link com.android.mail.browse.EmlMessageViewFragment}. Currently that work is
51 * pretty much the rendering logic.
52 */
53public class SecureConversationViewController implements
54        MessageHeaderView.MessageHeaderViewCallbacks {
55    private static final String BEGIN_HTML =
56            "<body style=\"margin: 0 %spx;\"><div style=\"margin: 16px 0; font-size: 80%%\">";
57    private static final String END_HTML = "</div></body>";
58
59    private final SecureConversationViewControllerCallbacks mCallbacks;
60
61    private MessageWebView mWebView;
62    private ConversationViewHeader mConversationHeaderView;
63    private MessageHeaderView mMessageHeaderView;
64    private MessageFooterView mMessageFooterView;
65    private ConversationMessage mMessage;
66    private MessageScrollView mScrollView;
67
68    private ConversationViewProgressController mProgressController;
69    private FormattedDateBuilder mDateBuilder;
70
71    private int mSideMarginInWebPx;
72
73    public SecureConversationViewController(SecureConversationViewControllerCallbacks callbacks) {
74        mCallbacks = callbacks;
75    }
76
77    public View onCreateView(LayoutInflater inflater, ViewGroup container,
78            Bundle savedInstanceState) {
79        View rootView = inflater.inflate(R.layout.secure_conversation_view, container, false);
80        mScrollView = (MessageScrollView) rootView.findViewById(R.id.scroll_view);
81        mConversationHeaderView = (ConversationViewHeader) rootView.findViewById(R.id.conv_header);
82        mMessageHeaderView = (MessageHeaderView) rootView.findViewById(R.id.message_header);
83        mMessageFooterView = (MessageFooterView) rootView.findViewById(R.id.message_footer);
84
85        // Add color backgrounds to the header and footer.
86        // Otherwise the backgrounds are grey. They can't
87        // be set in xml because that would add more overdraw
88        // in ConversationViewFragment.
89        final int color = rootView.getResources().getColor(
90                R.color.message_header_background_color);
91        mMessageHeaderView.setBackgroundColor(color);
92        mMessageFooterView.setBackgroundColor(color);
93
94        ((BorderView) rootView.findViewById(R.id.top_border)).disableCardBottomBorder();
95        ((BorderView) rootView.findViewById(R.id.bottom_border)).disableCardTopBorder();
96
97        mProgressController = new ConversationViewProgressController(
98                mCallbacks.getFragment(), mCallbacks.getHandler());
99        mProgressController.instantiateProgressIndicators(rootView);
100        mWebView = (MessageWebView) rootView.findViewById(R.id.webview);
101        mWebView.setOverScrollMode(View.OVER_SCROLL_NEVER);
102        mWebView.setWebViewClient(mCallbacks.getWebViewClient());
103        final InlineAttachmentViewIntentBuilderCreator creator =
104                InlineAttachmentViewIntentBuilderCreatorHolder.
105                getInlineAttachmentViewIntentCreator();
106        mWebView.setOnCreateContextMenuListener(new WebViewContextMenu(
107                mCallbacks.getFragment().getActivity(),
108                creator.createInlineAttachmentViewIntentBuilder(null, null, -1)));
109        mWebView.setFocusable(false);
110        final WebSettings settings = mWebView.getSettings();
111
112        settings.setJavaScriptEnabled(false);
113        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
114
115        ConversationViewUtils.setTextZoom(mCallbacks.getFragment().getResources(), settings);
116
117        settings.setSupportZoom(true);
118        settings.setBuiltInZoomControls(true);
119        settings.setDisplayZoomControls(false);
120
121        mScrollView.setInnerScrollableView(mWebView);
122
123        return rootView;
124    }
125
126    public void onActivityCreated(Bundle savedInstanceState) {
127        mCallbacks.setupConversationHeaderView(mConversationHeaderView);
128
129        final Fragment fragment = mCallbacks.getFragment();
130
131        mDateBuilder = new FormattedDateBuilder(fragment.getActivity());
132        mMessageHeaderView.initialize(
133                mCallbacks.getConversationAccountController(), mCallbacks.getAddressCache());
134        mMessageHeaderView.setContactInfoSource(mCallbacks.getContactInfoSource());
135        mMessageHeaderView.setCallbacks(this);
136        mMessageHeaderView.setExpandable(false);
137        mMessageHeaderView.setViewOnlyMode(mCallbacks.isViewOnlyMode());
138
139        mCallbacks.setupMessageHeaderVeiledMatcher(mMessageHeaderView);
140
141        mMessageFooterView.initialize(fragment.getLoaderManager(), fragment.getFragmentManager());
142
143        mCallbacks.startMessageLoader();
144
145        mProgressController.showLoadingStatus(mCallbacks.isViewVisibleToUser());
146
147        final Resources r = mCallbacks.getFragment().getResources();
148        mSideMarginInWebPx = (int) (r.getDimensionPixelOffset(
149                R.dimen.conversation_message_content_margin_side) / r.getDisplayMetrics().density);
150    }
151
152    /**
153     * Populate the adapter with overlay views (message headers, super-collapsed
154     * blocks, a conversation header), and return an HTML document with spacer
155     * divs inserted for all overlays.
156     */
157    public void renderMessage(ConversationMessage message) {
158        mMessage = message;
159
160        final boolean alwaysShowImages = mCallbacks.shouldAlwaysShowImages();
161        mWebView.getSettings().setBlockNetworkImage(
162                !alwaysShowImages && !mMessage.alwaysShowImages);
163
164        // Add formatting to message body
165        // At this point, only adds margins.
166        StringBuilder dataBuilder = new StringBuilder(
167                String.format(BEGIN_HTML, mSideMarginInWebPx));
168        dataBuilder.append(mMessage.getBodyAsHtml());
169        dataBuilder.append(END_HTML);
170
171        mWebView.loadDataWithBaseURL(mCallbacks.getBaseUri(), dataBuilder.toString(),
172                "text/html", "utf-8", null);
173        final MessageHeaderItem item = ConversationViewAdapter.newMessageHeaderItem(
174                null, mDateBuilder, mMessage, true, mMessage.alwaysShowImages);
175        // Clear out the old info from the header before (re)binding
176        mMessageHeaderView.unbind();
177        mMessageHeaderView.bind(item, false);
178        if (mMessage.hasAttachments) {
179            mMessageFooterView.setVisibility(View.VISIBLE);
180            mMessageFooterView.bind(item, mCallbacks.getAccountUri(), false);
181        }
182    }
183
184    public ConversationMessage getMessage() {
185        return mMessage;
186    }
187
188    public ConversationViewHeader getConversationHeaderView() {
189        return mConversationHeaderView;
190    }
191
192    public void dismissLoadingStatus() {
193        mProgressController.dismissLoadingStatus();
194    }
195
196    public void setSubject(String subject) {
197        mConversationHeaderView.setSubject(subject);
198    }
199
200    public void printMessage() {
201        final Conversation conversation = mMessage.getConversation();
202        PrintUtils.printMessage(mCallbacks.getFragment().getActivity(), mMessage,
203                conversation != null ? conversation.subject : mMessage.subject,
204                mCallbacks.getAddressCache(), mCallbacks.getBaseUri(), false /* useJavascript */);
205
206    }
207
208    // Start MessageHeaderViewCallbacks implementations
209
210    @Override
211    public void setMessageSpacerHeight(MessageHeaderItem item, int newSpacerHeight) {
212        // Do nothing.
213    }
214
215    @Override
216    public void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight,
217            int topBorderHeight, int bottomBorderHeight) {
218        // Do nothing.
219    }
220
221    @Override
222    public void setMessageDetailsExpanded(MessageHeaderItem i, boolean expanded, int heightBefore) {
223        // Do nothing.
224    }
225
226    @Override
227    public void showExternalResources(final Message msg) {
228        mWebView.getSettings().setBlockNetworkImage(false);
229    }
230
231    @Override
232    public void showExternalResources(final String rawSenderAddress) {
233        mWebView.getSettings().setBlockNetworkImage(false);
234    }
235
236    @Override
237    public boolean supportsMessageTransforms() {
238        return false;
239    }
240
241    @Override
242    public String getMessageTransforms(final Message msg) {
243        return null;
244    }
245
246    @Override
247    public FragmentManager getFragmentManager() {
248        return mCallbacks.getFragment().getFragmentManager();
249    }
250
251    // End MessageHeaderViewCallbacks implementations
252}
253