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