SecureConversationViewFragment.java revision ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6b
1f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp/* 2f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * Copyright (C) 2012 Google Inc. 3f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * Licensed to The Android Open Source Project. 4f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * 5f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * Licensed under the Apache License, Version 2.0 (the "License"); 6f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * you may not use this file except in compliance with the License. 7f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * You may obtain a copy of the License at 8f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * 9f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * http://www.apache.org/licenses/LICENSE-2.0 10f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * 11f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * Unless required by applicable law or agreed to in writing, software 12f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * distributed under the License is distributed on an "AS IS" BASIS, 13f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * See the License for the specific language governing permissions and 15f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * limitations under the License. 16f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp */ 17f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 18f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyppackage com.android.mail.browse; 19f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 20f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.content.Loader; 21f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.database.Cursor; 22f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.net.Uri; 23f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.os.Bundle; 24f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.text.TextUtils; 25f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.view.LayoutInflater; 26f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.view.View; 27f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.view.ViewGroup; 28f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.webkit.WebSettings; 29f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.webkit.WebSettings.LayoutAlgorithm; 30f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport android.webkit.WebView; 31ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6bmindypimport android.webkit.WebViewClient; 32f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 33f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.R; 34f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem; 35f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.browse.MessageCursor.ConversationMessage; 36f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.browse.MessageHeaderView.MessageHeaderViewCallbacks; 37f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.providers.Conversation; 38f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.providers.ConversationInfo; 39f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.providers.Message; 40f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.providers.UIProvider; 41f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.ui.AbstractConversationViewFragment; 42f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.ui.ControllableActivity; 43f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.ui.ConversationViewFragment; 44f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.ui.SubjectDisplayChanger; 45f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.utils.LogTag; 46f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.utils.LogUtils; 47f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 48f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport java.util.HashSet; 49f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 50f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyppublic class SecureConversationViewFragment extends AbstractConversationViewFragment implements 51f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp MessageHeaderViewCallbacks { 52f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp private static final String LOG_TAG = LogTag.getLogTag(); 53f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp private WebView mWebView; 54f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp private ConversationViewHeader mConversationHeaderView; 55f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp private MessageHeaderView mMessageHeaderView; 56f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp private ConversationMessage mMessage; 57ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6bmindyp private WebViewClient mWebViewClient = new WebViewClient() { 58ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6bmindyp @Override 59ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6bmindyp public void onPageFinished(WebView view, String url) { 60ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6bmindyp dismissLoadingStatus(); 61ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6bmindyp } 62ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6bmindyp }; 63f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 64f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp /** 65f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * Creates a new instance of {@link ConversationViewFragment}, initialized 66f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * to display a conversation with other parameters inherited/copied from an 67f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * existing bundle, typically one created using {@link #makeBasicArgs}. 68f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp */ 69f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp public static SecureConversationViewFragment newInstance(Bundle existingArgs, 70f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp Conversation conversation) { 71f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp SecureConversationViewFragment f = new SecureConversationViewFragment(); 72f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp Bundle args = new Bundle(existingArgs); 73f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp args.putParcelable(ARG_CONVERSATION, conversation); 74f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp f.setArguments(args); 75f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp return f; 76f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 77f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 78f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp /** 79f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * Constructor needs to be public to handle orientation changes and activity 80f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * lifecycle events. 81f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp */ 82f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp public SecureConversationViewFragment() { 83f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp super(); 84f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 85f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 86f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp @Override 87f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp public void onActivityCreated(Bundle savedInstanceState) { 88f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp super.onActivityCreated(savedInstanceState); 89f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mConversationHeaderView.setCallbacks(this, this); 90f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mConversationHeaderView.setSubject(mConversation.subject, false /* notify */); 91f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp if (mAccount.supportsCapability(UIProvider.AccountCapabilities.MULTIPLE_FOLDERS_PER_CONV)) { 92f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mConversationHeaderView.setFolders(mConversation, false /* notify */); 93f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 94f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp final SubjectDisplayChanger sdc = mActivity.getSubjectDisplayChanger(); 95f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp if (sdc != null) { 96f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp sdc.setSubject(mConversation.subject); 97f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 98f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mMessageHeaderView.setContactInfoSource(getContactInfoSource()); 99f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mMessageHeaderView.setCallbacks(this); 100f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mMessageHeaderView.setExpandable(false); 101f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp getLoaderManager().initLoader(MESSAGE_LOADER, null, getMessageLoaderCallbacks()); 102ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6bmindyp showLoadingStatus(); 103f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 104f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 105f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp @Override 106f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp public View onCreateView(LayoutInflater inflater, ViewGroup container, 107f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp Bundle savedInstanceState) { 108f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp View rootView = inflater.inflate(R.layout.secure_conversation_view, container, false); 109f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mConversationHeaderView = (ConversationViewHeader) rootView.findViewById(R.id.conv_header); 110f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mMessageHeaderView = (MessageHeaderView) rootView.findViewById(R.id.message_header); 111ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6bmindyp instantiateProgressIndicators(rootView); 112f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mWebView = (WebView) rootView.findViewById(R.id.webview); 113ff282d0ef252dbdaf6e9f4e2a7fd640287c01e6bmindyp mWebView.setWebViewClient(mWebViewClient); 114f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp final WebSettings settings = mWebView.getSettings(); 115f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 116f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp settings.setJavaScriptEnabled(false); 117f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL); 118f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 119f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp settings.setSupportZoom(true); 120f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp settings.setBuiltInZoomControls(true); 121f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp settings.setDisplayZoomControls(false); 122f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp return rootView; 123f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 124f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 125f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp @Override 126f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp protected void markUnread() { 127f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // Ignore unsafe calls made after a fragment is detached from an 128f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // activity 129f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp final ControllableActivity activity = (ControllableActivity) getActivity(); 130f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp if (activity == null) { 131f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp LogUtils.w(LOG_TAG, "ignoring markUnread for conv=%s", mConversation.id); 132f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp return; 133f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 134f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp HashSet<Uri> uris = new HashSet<Uri>(); 135f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp uris.add(mMessage.uri); 136f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp activity.getConversationUpdater().markConversationMessagesUnread(mConversation, uris, 137f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp ConversationInfo.toString(mConversation.conversationInfo)); 138f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 139f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 140f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp @Override 141f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp public void onAccountChanged() { 142f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // Do nothing. 143f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 144f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 145f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp @Override 146f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp public void setMessageSpacerHeight(MessageHeaderItem item, int newSpacerHeight) { 147f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // Do nothing. 148f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 149f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 150f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp @Override 151f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp public void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight) { 152f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // Do nothing. 153f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 154f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 155f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp @Override 156f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp public void onConversationViewHeaderHeightChange(int newHeight) { 157f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // Do nothing. 158f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 159f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 160f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp @Override 161f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp public void onUserVisibleHintChanged() { 162f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // Do nothing. 163f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 164f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 165f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp @Override 166f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp public void showExternalResources(Message msg) { 167f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mWebView.getSettings().setBlockNetworkImage(false); 168f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 169f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 170f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp @Override 171f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp protected void onMessageCursorLoadFinished(Loader<Cursor> loader, Cursor data, 172f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp boolean wasNull, boolean changed) { 173f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp MessageCursor messageCursor = getMessageCursor(); 174f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 175f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // ignore cursors that are still loading results 176f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp if (messageCursor == null || !messageCursor.isLoaded()) { 177f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp LogUtils.i(LOG_TAG, "CONV RENDER: existing cursor is null, rendering from scratch"); 178f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp return; 179f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 180f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp renderMessageBodies(messageCursor, mEnableContentReadySignal); 181f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 182f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 183f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp /** 184f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * Populate the adapter with overlay views (message headers, super-collapsed 185f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * blocks, a conversation header), and return an HTML document with spacer 186f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp * divs inserted for all overlays. 187f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp */ 188f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp private void renderMessageBodies(MessageCursor messageCursor, 189f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp boolean enableContentReadySignal) { 190f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp StringBuilder convHtml = new StringBuilder(); 191f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp String content; 192f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp if (messageCursor.moveToFirst()) { 193f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp content = messageCursor.getString(UIProvider.MESSAGE_BODY_HTML_COLUMN); 194f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp if (TextUtils.isEmpty(content)) { 195f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp content = messageCursor.getString(UIProvider.MESSAGE_BODY_TEXT_COLUMN); 196f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 197f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp convHtml.append(content); 198f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mWebView.loadDataWithBaseURL(mBaseUri, convHtml.toString(), "text/html", "utf-8", null); 199f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mMessage = messageCursor.getMessage(); 200f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp ConversationViewAdapter mAdapter = new ConversationViewAdapter(mActivity, null, null, 201f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp null, null, null, null, null, null); 202f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp MessageHeaderItem item = mAdapter.newMessageHeaderItem(mMessage, true); 203f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mMessageHeaderView.initialize(mDateBuilder, this, mAddressCache); 204f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mMessageHeaderView.bind(item, false); 205f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mMessageHeaderView.setMessageDetailsVisibility(View.VISIBLE); 206f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 207f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 208f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp} 209