• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.content.Loader;
22 import android.net.Uri;
23 import android.os.Bundle;
24 import android.view.LayoutInflater;
25 import android.view.View;
26 import android.view.ViewGroup;
27 import android.webkit.WebResourceResponse;
28 import android.webkit.WebView;
29 
30 import com.android.emailcommon.mail.Address;
31 import com.android.mail.browse.ConversationAccountController;
32 import com.android.mail.browse.ConversationMessage;
33 import com.android.mail.browse.ConversationViewHeader;
34 import com.android.mail.browse.MessageCursor;
35 import com.android.mail.browse.MessageHeaderView;
36 import com.android.mail.compose.ComposeActivity;
37 import com.android.mail.content.ObjectCursor;
38 import com.android.mail.providers.Account;
39 import com.android.mail.providers.Conversation;
40 import com.android.mail.utils.LogTag;
41 import com.android.mail.utils.LogUtils;
42 import com.google.common.collect.ImmutableList;
43 import com.google.common.collect.Sets;
44 
45 import java.util.HashSet;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Set;
49 
50 public class SecureConversationViewFragment extends AbstractConversationViewFragment
51         implements SecureConversationViewControllerCallbacks {
52     private static final String LOG_TAG = LogTag.getLogTag();
53 
54     private SecureConversationViewController mViewController;
55 
56     private class SecureConversationWebViewClient extends AbstractConversationWebViewClient {
SecureConversationWebViewClient(Account account)57         public SecureConversationWebViewClient(Account account) {
58             super(account);
59         }
60 
61         @Override
shouldInterceptRequest(WebView view, String url)62         public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
63             // try to load the url assuming it is a cid url
64             final Uri uri = Uri.parse(url);
65             final WebResourceResponse response = loadCIDUri(uri, mViewController.getMessage());
66             if (response != null) {
67                 return response;
68             }
69 
70             // otherwise, attempt the default handling
71             return super.shouldInterceptRequest(view, url);
72         }
73 
74         @Override
onPageFinished(WebView view, String url)75         public void onPageFinished(WebView view, String url) {
76             // Ignore unsafe calls made after a fragment is detached from an activity.
77             // This method needs to, for example, get at the loader manager, which needs
78             // the fragment to be added.
79             if (!isAdded()) {
80                 LogUtils.d(LOG_TAG, "ignoring SCVF.onPageFinished, url=%s fragment=%s", url,
81                         SecureConversationViewFragment.this);
82                 return;
83             }
84 
85             if (isUserVisible()) {
86                 onConversationSeen();
87             }
88 
89             mViewController.dismissLoadingStatus();
90 
91             final Set<String> emailAddresses = Sets.newHashSet();
92             final List<Address> cacheCopy;
93             synchronized (mAddressCache) {
94                 cacheCopy = ImmutableList.copyOf(mAddressCache.values());
95             }
96             for (Address addr : cacheCopy) {
97                 emailAddresses.add(addr.getAddress());
98             }
99             final ContactLoaderCallbacks callbacks = getContactInfoSource();
100             callbacks.setSenders(emailAddresses);
101             getLoaderManager().restartLoader(CONTACT_LOADER, Bundle.EMPTY, callbacks);
102         }
103     }
104 
105     /**
106      * Creates a new instance of {@link ConversationViewFragment}, initialized
107      * to display a conversation with other parameters inherited/copied from an
108      * existing bundle, typically one created using {@link #makeBasicArgs}.
109      */
newInstance(Bundle existingArgs, Conversation conversation)110     public static SecureConversationViewFragment newInstance(Bundle existingArgs,
111             Conversation conversation) {
112         SecureConversationViewFragment f = new SecureConversationViewFragment();
113         Bundle args = new Bundle(existingArgs);
114         args.putParcelable(ARG_CONVERSATION, conversation);
115         f.setArguments(args);
116         return f;
117     }
118 
119     /**
120      * Constructor needs to be public to handle orientation changes and activity
121      * lifecycle events.
122      */
SecureConversationViewFragment()123     public SecureConversationViewFragment() {}
124 
125     @Override
onCreate(Bundle savedState)126     public void onCreate(Bundle savedState) {
127         super.onCreate(savedState);
128 
129         mWebViewClient = new SecureConversationWebViewClient(mAccount);
130         mViewController = new SecureConversationViewController(this);
131     }
132 
133     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)134     public View onCreateView(LayoutInflater inflater, ViewGroup container,
135             Bundle savedInstanceState) {
136         return mViewController.onCreateView(inflater, container, savedInstanceState);
137     }
138 
139     @Override
onActivityCreated(Bundle savedInstanceState)140     public void onActivityCreated(Bundle savedInstanceState) {
141         super.onActivityCreated(savedInstanceState);
142         mViewController.onActivityCreated(savedInstanceState);
143     }
144 
145     // Start implementations of SecureConversationViewControllerCallbacks
146 
147     @Override
getFragment()148     public Fragment getFragment() {
149         return this;
150     }
151 
152     @Override
getWebViewClient()153     public AbstractConversationWebViewClient getWebViewClient() {
154         return mWebViewClient;
155     }
156 
157     @Override
setupConversationHeaderView(ConversationViewHeader headerView)158     public void setupConversationHeaderView(ConversationViewHeader headerView) {
159         headerView.setCallbacks(this, this, getListController());
160         headerView.setFolders(mConversation);
161         headerView.setSubject(mConversation.subject);
162         headerView.setStarred(mConversation.starred);
163     }
164 
165     @Override
isViewVisibleToUser()166     public boolean isViewVisibleToUser() {
167         return isUserVisible();
168     }
169 
170     @Override
getConversationAccountController()171     public ConversationAccountController getConversationAccountController() {
172         return this;
173     }
174 
175     @Override
getAddressCache()176     public Map<String, Address> getAddressCache() {
177         return mAddressCache;
178     }
179 
180     @Override
setupMessageHeaderVeiledMatcher(MessageHeaderView messageHeaderView)181     public void setupMessageHeaderVeiledMatcher(MessageHeaderView messageHeaderView) {
182         messageHeaderView.setVeiledMatcher(
183                 ((ControllableActivity) getActivity()).getAccountController()
184                         .getVeiledAddressMatcher());
185     }
186 
187     @Override
startMessageLoader()188     public void startMessageLoader() {
189         getLoaderManager().initLoader(MESSAGE_LOADER, null, getMessageLoaderCallbacks());
190     }
191 
192     @Override
getBaseUri()193     public String getBaseUri() {
194         return mBaseUri;
195     }
196 
197     @Override
isViewOnlyMode()198     public boolean isViewOnlyMode() {
199         return false;
200     }
201 
202     // End implementations of SecureConversationViewControllerCallbacks
203 
204     @Override
markUnread()205     protected void markUnread() {
206         super.markUnread();
207         // Ignore unsafe calls made after a fragment is detached from an activity
208         final ControllableActivity activity = (ControllableActivity) getActivity();
209         final ConversationMessage message = mViewController.getMessage();
210         if (activity == null || mConversation == null || message == null) {
211             LogUtils.w(LOG_TAG, "ignoring markUnread for conv=%s",
212                     mConversation != null ? mConversation.id : 0);
213             return;
214         }
215         final HashSet<Uri> uris = new HashSet<Uri>();
216         uris.add(message.uri);
217         activity.getConversationUpdater().markConversationMessagesUnread(mConversation, uris,
218                 mViewState.getConversationInfo());
219     }
220 
221     @Override
onAccountChanged(Account newAccount, Account oldAccount)222     public void onAccountChanged(Account newAccount, Account oldAccount) {
223         renderMessage(getMessageCursor());
224     }
225 
226     @Override
onConversationViewHeaderHeightChange(int newHeight)227     public void onConversationViewHeaderHeightChange(int newHeight) {
228         // Do nothing.
229     }
230 
231     @Override
onUserVisibleHintChanged()232     public void onUserVisibleHintChanged() {
233         if (mActivity == null) {
234             return;
235         }
236         if (isUserVisible()) {
237             onConversationSeen();
238         }
239     }
240 
241     @Override
onMessageCursorLoadFinished(Loader<ObjectCursor<ConversationMessage>> loader, MessageCursor newCursor, MessageCursor oldCursor)242     protected void onMessageCursorLoadFinished(Loader<ObjectCursor<ConversationMessage>> loader,
243             MessageCursor newCursor, MessageCursor oldCursor) {
244         renderMessage(newCursor);
245     }
246 
renderMessage(MessageCursor newCursor)247     private void renderMessage(MessageCursor newCursor) {
248         // ignore cursors that are still loading results
249         if (newCursor == null || !newCursor.isLoaded()) {
250             LogUtils.i(LOG_TAG, "CONV RENDER: existing cursor is null, rendering from scratch");
251             return;
252         }
253         if (mActivity == null || mActivity.isFinishing()) {
254             // Activity is finishing, just bail.
255             return;
256         }
257         if (!newCursor.moveToFirst()) {
258             LogUtils.e(LOG_TAG, "unable to open message cursor");
259             return;
260         }
261 
262         mViewController.renderMessage(newCursor.getMessage());
263     }
264 
265     @Override
onConversationUpdated(Conversation conv)266     public void onConversationUpdated(Conversation conv) {
267         final ConversationViewHeader headerView = mViewController.getConversationHeaderView();
268         if (headerView != null) {
269             headerView.onConversationUpdated(conv);
270         }
271     }
272 
273     // Need this stub here
274     @Override
supportsMessageTransforms()275     public boolean supportsMessageTransforms() {
276         return false;
277     }
278 
279     /**
280      * Users are expected to use the Print item in the Message overflow menu to print the single
281      * message.
282      *
283      * @return {@code false} because Print and Print All menu items are never shown in EMail.
284      */
285     @Override
shouldShowPrintInOverflow()286     protected boolean shouldShowPrintInOverflow() {
287         return false;
288     }
289 
290     @Override
printConversation()291     protected void printConversation() {
292         mViewController.printMessage();
293     }
294 
295     @Override
handleReply()296     protected void handleReply() {
297         final ConversationMessage msg = mViewController.getMessage();
298         if (msg != null) {
299             ComposeActivity.reply(getActivity(), mAccount, msg);
300         }
301     }
302 
303     @Override
handleReplyAll()304     protected void handleReplyAll() {
305         final ConversationMessage msg = mViewController.getMessage();
306         if (msg != null) {
307             ComposeActivity.replyAll(getActivity(), mAccount, msg);
308         }
309     }
310 }
311