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