summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Sapperstein <asapperstein@google.com>2014-04-20 12:23:57 -0700
committerAndrew Sapperstein <asapperstein@google.com>2014-04-22 15:06:40 -0700
commit381c322eb30c39f63a2bb82812d63262eb3c1c1c (patch)
tree9525210ecd37f6b67f36cd0aa3d3e1b3133867da
parent8aed2ce1cf1d976f8f0e1bd8e1d3b176815987be (diff)
downloadandroid_packages_apps_UnifiedEmail-381c322eb30c39f63a2bb82812d63262eb3c1c1c.tar.gz
android_packages_apps_UnifiedEmail-381c322eb30c39f63a2bb82812d63262eb3c1c1c.tar.bz2
android_packages_apps_UnifiedEmail-381c322eb30c39f63a2bb82812d63262eb3c1c1c.zip
Save to drive promo. b/7659807.
Provides a space above the attachment bars to show some additional content. Default behavior does nothing. Hooks have been added to allow resizing of the message footer. Change-Id: Ib950091d176311bdb06c7c7a466223beb997a7b5
-rw-r--r--assets/script.js9
-rw-r--r--res/layout/above_attachment_bar_list_layout.xml18
-rw-r--r--res/layout/conversation_message_footer.xml4
-rw-r--r--src/com/android/mail/browse/AttachmentActionHandler.java53
-rw-r--r--src/com/android/mail/browse/ConversationContainer.java1
-rw-r--r--src/com/android/mail/browse/ConversationViewAdapter.java53
-rw-r--r--src/com/android/mail/browse/EmlMessageViewFragment.java6
-rw-r--r--src/com/android/mail/browse/MessageAttachmentBar.java2
-rw-r--r--src/com/android/mail/browse/MessageFooterView.java88
-rw-r--r--src/com/android/mail/browse/UrlSpan.java45
-rw-r--r--src/com/android/mail/ui/ConversationViewFragment.java37
-rw-r--r--src/com/android/mail/ui/SecureConversationViewController.java33
-rw-r--r--src/com/android/mail/ui/SecureConversationViewFragment.java6
-rw-r--r--src/com/android/mail/utils/StyleUtils.java48
14 files changed, 378 insertions, 25 deletions
diff --git a/assets/script.js b/assets/script.js
index cd3045e03..b096c4b2c 100644
--- a/assets/script.js
+++ b/assets/script.js
@@ -662,6 +662,15 @@ function setConversationHeaderSpacerHeight(spacerHeight) {
function setMessageHeaderSpacerHeight(messageDomId, spacerHeight) {
var spacer = document.querySelector("#" + messageDomId + " > .mail-message-header");
+ setSpacerHeight(spacer, spacerHeight);
+}
+
+function setMessageFooterSpacerHeight(messageDomId, spacerHeight) {
+ var spacer = document.querySelector("#" + messageDomId + " > .mail-message-footer");
+ setSpacerHeight(spacer, spacerHeight);
+}
+
+function setSpacerHeight(spacer, spacerHeight) {
if (!spacer) {
console.log("can't set spacer for message with id: " + messageDomId);
return;
diff --git a/res/layout/above_attachment_bar_list_layout.xml b/res/layout/above_attachment_bar_list_layout.xml
new file mode 100644
index 000000000..a0bd285b2
--- /dev/null
+++ b/res/layout/above_attachment_bar_list_layout.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 Google Inc.
+ Licensed to The Android Open Source Project.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<merge /> \ No newline at end of file
diff --git a/res/layout/conversation_message_footer.xml b/res/layout/conversation_message_footer.xml
index a1eefb8bd..55f331069 100644
--- a/res/layout/conversation_message_footer.xml
+++ b/res/layout/conversation_message_footer.xml
@@ -53,6 +53,10 @@
android:visibility="gone"
style="@style/AttachmentMarginStyle" />
+ <include
+ layout="@layout/above_attachment_bar_list_layout"
+ android:id="@+id/above_attachment_bar_list_layout"/>
+
<LinearLayout
android:id="@+id/attachment_bar_list"
android:layout_width="match_parent"
diff --git a/src/com/android/mail/browse/AttachmentActionHandler.java b/src/com/android/mail/browse/AttachmentActionHandler.java
index 8a72533f5..33f612e09 100644
--- a/src/com/android/mail/browse/AttachmentActionHandler.java
+++ b/src/com/android/mail/browse/AttachmentActionHandler.java
@@ -29,6 +29,7 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Parcelable;
+import android.view.View;
import com.android.mail.providers.Attachment;
import com.android.mail.providers.Message;
@@ -265,6 +266,37 @@ public class AttachmentActionHandler {
sOptionHandler.handleOption1(mContext, mAccount, mMessage, mAttachment, mFragmentManager);
}
+ public static boolean shouldShowAboveBarAttachmentLayout(Context context) {
+ return (sOptionHandler != null) &&
+ sOptionHandler.shouldShowAboveBarAttachmentLayout(context);
+ }
+
+ public static void setupAboveBarAttachmentLayout(View view) {
+ if (sOptionHandler != null) {
+ sOptionHandler.setupAboveBarAttachmentLayout(view);
+ }
+ }
+
+ public static void onOverflowOpened(Context context) {
+ if(sOptionHandler != null) {
+ sOptionHandler.onOverflowOpened(context);
+ }
+ }
+
+ public static void registerDismissListener(Uri conversationUri,
+ AboveAttachmentLayoutDismissedListener listener) {
+ if (sOptionHandler != null) {
+ sOptionHandler.registerDismissListener(conversationUri, listener);
+ }
+ }
+
+ public static void unregisterDismissListeners(Uri conversationUri) {
+ if(sOptionHandler != null) {
+ sOptionHandler.unregisterDismissListeners(conversationUri);
+ }
+ }
+
+
/**
* A default, no-op option class. Override this and set it globally with
* {@link AttachmentActionHandler#setOptionHandler(OptionHandler)}.<br>
@@ -278,12 +310,31 @@ public class AttachmentActionHandler {
return false;
}
- @SuppressWarnings("unused")
public void handleOption1(Context context, String account, Message message,
Attachment attachment, FragmentManager fm) {
// no-op
}
+ public boolean shouldShowAboveBarAttachmentLayout(Context context) {
+ return false;
+ }
+
+ public void setupAboveBarAttachmentLayout(View view) { /* no-op */ }
+
+ public void onOverflowOpened(Context context) { /* no-op */ }
+
+ public void registerDismissListener(Uri conversationUri,
+ AboveAttachmentLayoutDismissedListener listener) {
+ // no-op
+ }
+
+ public void unregisterDismissListeners(Uri conversationUri) {
+ // no-op
+ }
+ }
+
+ public interface AboveAttachmentLayoutDismissedListener {
+ void onOtherLayoutDismissed();
}
}
diff --git a/src/com/android/mail/browse/ConversationContainer.java b/src/com/android/mail/browse/ConversationContainer.java
index b75dd5ab3..19380eafb 100644
--- a/src/com/android/mail/browse/ConversationContainer.java
+++ b/src/com/android/mail/browse/ConversationContainer.java
@@ -206,7 +206,6 @@ public class ConversationContainer extends ViewGroup implements ScrollListener {
/**
* Child views of this container should implement this interface to be notified when they are
* being detached.
- *
*/
public interface DetachListener {
/**
diff --git a/src/com/android/mail/browse/ConversationViewAdapter.java b/src/com/android/mail/browse/ConversationViewAdapter.java
index 08f5cf5bb..1cc729bfb 100644
--- a/src/com/android/mail/browse/ConversationViewAdapter.java
+++ b/src/com/android/mail/browse/ConversationViewAdapter.java
@@ -32,6 +32,7 @@ import com.android.mail.ContactInfoSource;
import com.android.mail.FormattedDateBuilder;
import com.android.mail.R;
import com.android.mail.browse.ConversationViewHeader.ConversationViewHeaderCallbacks;
+import com.android.mail.browse.MessageFooterView.MessageFooterCallbacks;
import com.android.mail.browse.MessageHeaderView.MessageHeaderViewCallbacks;
import com.android.mail.browse.SuperCollapsedBlock.OnClickListener;
import com.android.mail.providers.Conversation;
@@ -64,6 +65,7 @@ public class ConversationViewAdapter extends BaseAdapter {
private final LoaderManager mLoaderManager;
private final FragmentManager mFragmentManager;
private final MessageHeaderViewCallbacks mMessageCallbacks;
+ private final MessageFooterCallbacks mFooterCallbacks;
private final ContactInfoSource mContactInfoSource;
private final ConversationViewHeaderCallbacks mConversationCallbacks;
private final OnClickListener mSuperCollapsedListener;
@@ -266,15 +268,19 @@ public class ConversationViewAdapter extends BaseAdapter {
}
}
- public class MessageFooterItem extends ConversationOverlayItem {
+ public static class MessageFooterItem extends ConversationOverlayItem implements
+ AttachmentActionHandler.AboveAttachmentLayoutDismissedListener {
+ private final ConversationViewAdapter mAdapter;
+
/**
* A footer can only exist if there is a matching header. Requiring a header allows a
* footer to stay in sync with the expanded state of the header.
*/
- private final MessageHeaderItem mHeaderitem;
+ private final MessageHeaderItem mHeaderItem;
- private MessageFooterItem(MessageHeaderItem item) {
- mHeaderitem = item;
+ private MessageFooterItem(ConversationViewAdapter adapter, MessageHeaderItem item) {
+ mAdapter = adapter;
+ mHeaderItem = item;
}
@Override
@@ -286,14 +292,15 @@ public class ConversationViewAdapter extends BaseAdapter {
public View createView(Context context, LayoutInflater inflater, ViewGroup parent) {
final MessageFooterView v = (MessageFooterView) inflater.inflate(
R.layout.conversation_message_footer, parent, false);
- v.initialize(mLoaderManager, mFragmentManager, mAccountController);
+ v.initialize(mAdapter.mLoaderManager, mAdapter.mFragmentManager,
+ mAdapter.mAccountController, mAdapter.mFooterCallbacks);
return v;
}
@Override
public void bindView(View v, boolean measureOnly) {
final MessageFooterView attachmentsView = (MessageFooterView) v;
- attachmentsView.bind(mHeaderitem, measureOnly);
+ attachmentsView.bind(mHeaderItem, this, measureOnly);
}
@Override
@@ -303,7 +310,7 @@ public class ConversationViewAdapter extends BaseAdapter {
@Override
public boolean isExpanded() {
- return mHeaderitem.isExpanded();
+ return mHeaderItem.isExpanded();
}
@Override
@@ -317,11 +324,32 @@ public class ConversationViewAdapter extends BaseAdapter {
public int getHeight() {
// a footer may change height while its view does not exist because it is offscreen
// (but the header is onscreen and thus collapsible)
- if (!mHeaderitem.isExpanded()) {
+ if (!mHeaderItem.isExpanded()) {
return 0;
}
return super.getHeight();
}
+
+ public MessageHeaderItem getHeaderItem() {
+ return mHeaderItem;
+ }
+
+ @Override
+ public void onOtherLayoutDismissed() {
+ final MessageFooterView view = mAdapter.mFooterCallbacks.getViewForItem(this);
+
+ // the item has a view, use the normal path
+ if (view != null) {
+ view.collapseAboveBarAttachmentsView();
+ return;
+ }
+
+ // the item is offscreen or otherwise doesn't have a view
+ // just update the HTML
+ final int newHeight = mAdapter.mFooterCallbacks.getUpdatedHeight(this);
+ setHeight(newHeight);
+ mAdapter.mFooterCallbacks.setMessageSpacerHeight(this, newHeight);
+ }
}
public class SuperCollapsedBlockItem extends ConversationOverlayItem {
@@ -453,6 +481,7 @@ public class ConversationViewAdapter extends BaseAdapter {
ConversationAccountController accountController,
LoaderManager loaderManager,
MessageHeaderViewCallbacks messageCallbacks,
+ MessageFooterCallbacks footerCallbacks,
ContactInfoSource contactInfoSource,
ConversationViewHeaderCallbacks convCallbacks,
SuperCollapsedBlock.OnClickListener scbListener, Map<String, Address> addressCache,
@@ -463,6 +492,7 @@ public class ConversationViewAdapter extends BaseAdapter {
mLoaderManager = loaderManager;
mFragmentManager = controllableActivity.getFragmentManager();
mMessageCallbacks = messageCallbacks;
+ mFooterCallbacks = footerCallbacks;
mContactInfoSource = contactInfoSource;
mConversationCallbacks = convCallbacks;
mSuperCollapsedListener = scbListener;
@@ -548,7 +578,7 @@ public class ConversationViewAdapter extends BaseAdapter {
}
public int addMessageFooter(MessageHeaderItem headerItem) {
- return addItem(new MessageFooterItem(headerItem));
+ return addItem(new MessageFooterItem(this, headerItem));
}
public static MessageHeaderItem newMessageHeaderItem(ConversationViewAdapter adapter,
@@ -557,8 +587,9 @@ public class ConversationViewAdapter extends BaseAdapter {
return new MessageHeaderItem(adapter, dateBuilder, message, expanded, showImages);
}
- public MessageFooterItem newMessageFooterItem(MessageHeaderItem headerItem) {
- return new MessageFooterItem(headerItem);
+ public static MessageFooterItem newMessageFooterItem(
+ ConversationViewAdapter adapter, MessageHeaderItem headerItem) {
+ return new MessageFooterItem(adapter, headerItem);
}
public int addSuperCollapsedBlock(int start, int end) {
diff --git a/src/com/android/mail/browse/EmlMessageViewFragment.java b/src/com/android/mail/browse/EmlMessageViewFragment.java
index 8da260670..eb56bf930 100644
--- a/src/com/android/mail/browse/EmlMessageViewFragment.java
+++ b/src/com/android/mail/browse/EmlMessageViewFragment.java
@@ -174,6 +174,12 @@ public class EmlMessageViewFragment extends Fragment
}
@Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ mViewController.onDestroyView();
+ }
+
+ @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (Utils.isRunningKitkatOrLater()) {
inflater.inflate(R.menu.eml_fragment_menu, menu);
diff --git a/src/com/android/mail/browse/MessageAttachmentBar.java b/src/com/android/mail/browse/MessageAttachmentBar.java
index fffbb8d12..230e63431 100644
--- a/src/com/android/mail/browse/MessageAttachmentBar.java
+++ b/src/com/android/mail/browse/MessageAttachmentBar.java
@@ -225,6 +225,8 @@ public class MessageAttachmentBar extends FrameLayout implements OnClickListener
menu.findItem(R.id.attachment_extra_option1).setVisible(shouldShowExtraOption1());
mPopup.show();
+
+ AttachmentActionHandler.onOverflowOpened(getContext());
}
} else {
// Handles clicking the attachment
diff --git a/src/com/android/mail/browse/MessageFooterView.java b/src/com/android/mail/browse/MessageFooterView.java
index 07212943c..cfec4e319 100644
--- a/src/com/android/mail/browse/MessageFooterView.java
+++ b/src/com/android/mail/browse/MessageFooterView.java
@@ -30,6 +30,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -37,15 +38,18 @@ import com.android.mail.R;
import com.android.mail.analytics.Analytics;
import com.android.mail.browse.AttachmentLoader.AttachmentCursor;
import com.android.mail.browse.ConversationContainer.DetachListener;
+import com.android.mail.browse.ConversationViewAdapter.MessageFooterItem;
import com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem;
import com.android.mail.providers.Account;
import com.android.mail.providers.Attachment;
+import com.android.mail.providers.Conversation;
import com.android.mail.providers.Message;
import com.android.mail.ui.AccountFeedbackActivity;
import com.android.mail.ui.AttachmentTile;
import com.android.mail.ui.AttachmentTileGrid;
import com.android.mail.utils.LogTag;
import com.android.mail.utils.LogUtils;
+import com.android.mail.utils.Utils;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
@@ -55,6 +59,7 @@ import java.util.List;
public class MessageFooterView extends LinearLayout implements DetachListener,
LoaderManager.LoaderCallbacks<Cursor>, View.OnClickListener {
+ private MessageFooterItem mMessageFooterItem;
private MessageHeaderItem mMessageHeaderItem;
private LoaderManager mLoaderManager;
private FragmentManager mFragmentManager;
@@ -63,6 +68,7 @@ public class MessageFooterView extends LinearLayout implements DetachListener,
private TextView mTitleText;
private AttachmentTileGrid mAttachmentGrid;
private LinearLayout mAttachmentBarList;
+ private View mAboveAttachmentBarListLayout;
private final LayoutInflater mInflater;
@@ -72,6 +78,19 @@ public class MessageFooterView extends LinearLayout implements DetachListener,
private BidiFormatter mBidiFormatter;
+ private MessageFooterCallbacks mCallbacks;
+
+ /**
+ * Callbacks for the MessageFooterView to enable resizing the height.
+ */
+ public interface MessageFooterCallbacks {
+ void setMessageSpacerHeight(MessageFooterItem item, int newSpacerHeight);
+
+ MessageFooterView getViewForItem(MessageFooterItem item);
+
+ int getUpdatedHeight(MessageFooterItem item);
+ }
+
public MessageFooterView(Context context) {
this(context, null);
}
@@ -90,18 +109,21 @@ public class MessageFooterView extends LinearLayout implements DetachListener,
mTitleText = (TextView) findViewById(R.id.attachments_header_text);
mAttachmentGrid = (AttachmentTileGrid) findViewById(R.id.attachment_tile_grid);
mAttachmentBarList = (LinearLayout) findViewById(R.id.attachment_bar_list);
+ mAboveAttachmentBarListLayout = findViewById(R.id.above_attachment_bar_list_layout);
mViewEntireMessagePrompt.setOnClickListener(this);
}
public void initialize(LoaderManager loaderManager, FragmentManager fragmentManager,
- ConversationAccountController accountController) {
+ ConversationAccountController accountController, MessageFooterCallbacks callbacks) {
mLoaderManager = loaderManager;
mFragmentManager = fragmentManager;
mAccountController = accountController;
+ mCallbacks = callbacks;
}
- public void bind(MessageHeaderItem headerItem, boolean measureOnly) {
+ public void bind(
+ MessageHeaderItem headerItem, MessageFooterItem footerItem, boolean measureOnly) {
// Resets the footer view. This step is only done if the
// attachmentsListUri changes so that we don't
// repeat the work of layout and measure when
@@ -117,12 +139,14 @@ public class MessageFooterView extends LinearLayout implements DetachListener,
mTitleText.setVisibility(View.GONE);
mAttachmentGrid.setVisibility(View.GONE);
mAttachmentBarList.setVisibility(View.GONE);
+ hideAboveAttachmentBarListLayout();
}
// If this MessageFooterView is being bound to a new attachment, we need to unbind with the
// old loader
final Integer oldAttachmentLoaderId = getAttachmentLoaderId();
+ mMessageFooterItem = footerItem;
mMessageHeaderItem = headerItem;
final Integer attachmentLoaderId = getAttachmentLoaderId();
@@ -152,6 +176,25 @@ public class MessageFooterView extends LinearLayout implements DetachListener,
setVisibility(mMessageHeaderItem.isExpanded() ? VISIBLE : GONE);
}
+ private void hideAboveAttachmentBarListLayout() {
+ if (mAboveAttachmentBarListLayout != null) {
+ mAboveAttachmentBarListLayout.setVisibility(GONE);
+ }
+ }
+
+ private void showAboveAttachmentBarListLayout() {
+ if (mAboveAttachmentBarListLayout != null) {
+ final Conversation conversation = mMessageHeaderItem.getMessage().getConversation();
+ if (conversation == null) {
+ hideAboveAttachmentBarListLayout();
+ return;
+ }
+ AttachmentActionHandler.registerDismissListener(conversation.uri, mMessageFooterItem);
+ mAboveAttachmentBarListLayout.setVisibility(VISIBLE);
+ AttachmentActionHandler.setupAboveBarAttachmentLayout(mAboveAttachmentBarListLayout);
+ }
+ }
+
private void renderAttachments(boolean loaderResult) {
final List<Attachment> attachments;
if (mAttachmentsCursor != null && !mAttachmentsCursor.isClosed()) {
@@ -198,8 +241,12 @@ public class MessageFooterView extends LinearLayout implements DetachListener,
mTitleText.setVisibility(View.VISIBLE);
- renderTiledAttachments(tiledAttachments, loaderResult);
- renderBarAttachments(barAttachments, loaderResult);
+ if (!tiledAttachments.isEmpty()) {
+ renderTiledAttachments(tiledAttachments, loaderResult);
+ }
+ if (!barAttachments.isEmpty()) {
+ renderBarAttachments(barAttachments, loaderResult);
+ }
}
private void renderTiledAttachments(List<Attachment> tiledAttachments, boolean loaderResult) {
@@ -213,6 +260,13 @@ public class MessageFooterView extends LinearLayout implements DetachListener,
private void renderBarAttachments(List<Attachment> barAttachments, boolean loaderResult) {
mAttachmentBarList.setVisibility(View.VISIBLE);
+ if (!barAttachments.isEmpty() &&
+ AttachmentActionHandler.shouldShowAboveBarAttachmentLayout(getContext())) {
+ showAboveAttachmentBarListLayout();
+ } else {
+ hideAboveAttachmentBarListLayout();
+ }
+
final Account account = getAccount();
for (Attachment attachment : barAttachments) {
final Uri id = attachment.getIdentifierUri();
@@ -242,7 +296,7 @@ public class MessageFooterView extends LinearLayout implements DetachListener,
@Override
public void onDetachedFromParent() {
- // Do nothing
+ // Do nothing.
}
@Override
@@ -311,4 +365,28 @@ public class MessageFooterView extends LinearLayout implements DetachListener,
private Account getAccount() {
return mAccountController != null ? mAccountController.getAccount() : null;
}
+
+ public void collapseAboveBarAttachmentsView() {
+ int heightBefore = measureHeight();
+ mAboveAttachmentBarListLayout.setVisibility(View.GONE);
+ updateSpacerHeight();
+ }
+
+ private int measureHeight() {
+ ViewGroup parent = (ViewGroup) getParent();
+ if (parent == null) {
+ LogUtils.e(LOG_TAG, new Error(), "Unable to measure height of detached header");
+ return getHeight();
+ }
+ return Utils.measureViewHeight(this, parent);
+ }
+
+ private void updateSpacerHeight() {
+ final int h = measureHeight();
+
+ mMessageFooterItem.setHeight(h);
+ if (mCallbacks != null) {
+ mCallbacks.setMessageSpacerHeight(mMessageFooterItem, h);
+ }
+ }
}
diff --git a/src/com/android/mail/browse/UrlSpan.java b/src/com/android/mail/browse/UrlSpan.java
new file mode 100644
index 000000000..9e3d17208
--- /dev/null
+++ b/src/com/android/mail/browse/UrlSpan.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ * Licensed to The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.browse;
+
+import android.text.TextPaint;
+import android.text.style.URLSpan;
+
+/**
+ * Extension to URLSpan that does not have underlines.
+ * Stupid URLSpan.<p/>
+ *
+ * WARNING: this span will not work if the TextView it uses
+ * saves and restores its text since TextView can only save
+ * and restore {@link android.text.ParcelableSpan}s which
+ * can only be implemented by framework Spans.
+ */
+public class UrlSpan extends URLSpan {
+ public UrlSpan(String url) {
+ super(url);
+ }
+
+ /**
+ * Makes the text in the link color and not underlined.
+ */
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ ds.setColor(ds.linkColor);
+ ds.setUnderlineText(false);
+ }
+}
diff --git a/src/com/android/mail/ui/ConversationViewFragment.java b/src/com/android/mail/ui/ConversationViewFragment.java
index 5d54b94bc..74805d5cf 100644
--- a/src/com/android/mail/ui/ConversationViewFragment.java
+++ b/src/com/android/mail/ui/ConversationViewFragment.java
@@ -48,6 +48,7 @@ import com.android.mail.FormattedDateBuilder;
import com.android.mail.R;
import com.android.mail.analytics.Analytics;
import com.android.mail.analytics.AnalyticsTimer;
+import com.android.mail.browse.AttachmentActionHandler;
import com.android.mail.browse.ConversationContainer;
import com.android.mail.browse.ConversationContainer.OverlayPosition;
import com.android.mail.browse.ConversationMessage;
@@ -63,6 +64,7 @@ import com.android.mail.browse.InlineAttachmentViewIntentBuilderCreator;
import com.android.mail.browse.InlineAttachmentViewIntentBuilderCreatorHolder;
import com.android.mail.browse.MailWebView.ContentSizeChangeListener;
import com.android.mail.browse.MessageCursor;
+import com.android.mail.browse.MessageFooterView;
import com.android.mail.browse.MessageHeaderView;
import com.android.mail.browse.ScrollIndicatorsView;
import com.android.mail.browse.SuperCollapsedBlock;
@@ -94,7 +96,8 @@ import java.util.Set;
*/
public class ConversationViewFragment extends AbstractConversationViewFragment implements
SuperCollapsedBlock.OnClickListener, OnLayoutChangeListener,
- MessageHeaderView.MessageHeaderViewCallbacks, WebViewContextMenu.Callbacks {
+ MessageHeaderView.MessageHeaderViewCallbacks,
+ MessageFooterView.MessageFooterCallbacks, WebViewContextMenu.Callbacks {
private static final String LOG_TAG = LogTag.getLogTag();
public static final String LAYOUT_TAG = "ConvLayout";
@@ -272,7 +275,7 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
final FormattedDateBuilder dateBuilder = new FormattedDateBuilder(context);
mAdapter = new ConversationViewAdapter(mActivity, this,
- getLoaderManager(), this, getContactInfoSource(), this,
+ getLoaderManager(), this, this, getContactInfoSource(), this,
this, mAddressCache, dateBuilder, mBidiFormatter);
mConversationContainer.setOverlayAdapter(mAdapter);
@@ -448,6 +451,7 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
public void onDestroyView() {
super.onDestroyView();
mConversationContainer.setOverlayAdapter(null);
+ AttachmentActionHandler.unregisterDismissListeners(mConversation.uri);
mAdapter = null;
resetLoadWaiting(); // be sure to unregister any active load observer
mViewsCreated = false;
@@ -886,7 +890,7 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
final MessageHeaderItem header = ConversationViewAdapter.newMessageHeaderItem(
mAdapter, mAdapter.getDateBuilder(), msg, false /* expanded */,
alwaysShowImages || mViewState.getShouldShowImages(msg));
- final MessageFooterItem footer = mAdapter.newMessageFooterItem(header);
+ final MessageFooterItem footer = mAdapter.newMessageFooterItem(mAdapter, header);
final int headerPx = measureOverlayHeight(header);
final int footerPx = measureOverlayHeight(footer);
@@ -933,7 +937,7 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
* @param convItem adapter item with data to render and measure
* @return height of the rendered view in screen px
*/
- private int measureOverlayHeight(ConversationOverlayItem convItem) {
+ public int measureOverlayHeight(ConversationOverlayItem convItem) {
final int type = convItem.getType();
final View convertView = mConversationContainer.getScrapView(type);
@@ -1633,6 +1637,31 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
mDiff = (expanded ? 1 : -1) * Math.abs(i.getHeight() - heightBefore);
}
+ // START MessageFooterCallbacks
+
+ @Override
+ public void setMessageSpacerHeight(MessageFooterItem item, int newSpacerHeight) {
+ mConversationContainer.invalidateSpacerGeometry();
+
+ // update message HTML spacer height
+ final int h = mWebView.screenPxToWebPx(newSpacerHeight);
+ LogUtils.i(LAYOUT_TAG, "setting HTML spacer h=%dwebPx (%dscreenPx)", h, newSpacerHeight);
+ mWebView.loadUrl(String.format("javascript:setMessageFooterSpacerHeight('%s', %s);",
+ mTemplates.getMessageDomId(item.getHeaderItem().getMessage()), h));
+ }
+
+ @Override
+ public MessageFooterView getViewForItem(MessageFooterItem item) {
+ return (MessageFooterView) mConversationContainer.getViewForItem(item);
+ }
+
+ @Override
+ public int getUpdatedHeight(MessageFooterItem item) {
+ return measureOverlayHeight(item);
+ }
+
+ // END MessageFooterCallbacks
+
/**
* @return {@code true} because either the Print or Print All menu item is shown in GMail
*/
diff --git a/src/com/android/mail/ui/SecureConversationViewController.java b/src/com/android/mail/ui/SecureConversationViewController.java
index 5e10794b6..a0e190e6e 100644
--- a/src/com/android/mail/ui/SecureConversationViewController.java
+++ b/src/com/android/mail/ui/SecureConversationViewController.java
@@ -29,9 +29,11 @@ import android.webkit.WebSettings;
import com.android.mail.FormattedDateBuilder;
import com.android.mail.R;
+import com.android.mail.browse.AttachmentActionHandler;
import com.android.mail.browse.BorderView;
import com.android.mail.browse.ConversationMessage;
import com.android.mail.browse.ConversationViewAdapter;
+import com.android.mail.browse.ConversationViewAdapter.MessageFooterItem;
import com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem;
import com.android.mail.browse.ConversationViewHeader;
import com.android.mail.browse.InlineAttachmentViewIntentBuilderCreator;
@@ -54,7 +56,8 @@ import com.android.mail.utils.ConversationViewUtils;
* is pretty much the rendering logic.
*/
public class SecureConversationViewController implements
- MessageHeaderView.MessageHeaderViewCallbacks, ScrollListener {
+ MessageHeaderView.MessageHeaderViewCallbacks, ScrollListener,
+ MessageFooterView.MessageFooterCallbacks {
private static final String BEGIN_HTML =
"<body style=\"margin: 0 %spx;\"><div style=\"margin: 16px 0; font-size: 80%%\">";
private static final String END_HTML = "</div></body>";
@@ -156,7 +159,7 @@ public class SecureConversationViewController implements
mCallbacks.setupMessageHeaderVeiledMatcher(mSnapHeaderView);
mMessageFooterView.initialize(fragment.getLoaderManager(), fragment.getFragmentManager(),
- mCallbacks.getConversationAccountController());
+ mCallbacks.getConversationAccountController(), this);
mCallbacks.startMessageLoader();
@@ -167,6 +170,10 @@ public class SecureConversationViewController implements
R.dimen.conversation_message_content_margin_side) / r.getDisplayMetrics().density);
}
+ public void onDestroyView() {
+ AttachmentActionHandler.unregisterDismissListeners(mMessage.conversationUri);
+ }
+
@Override
public void onNotifierScroll(final int x, final int y) {
// We need to decide whether or not to display the snap header.
@@ -216,7 +223,8 @@ public class SecureConversationViewController implements
if (mMessage.hasAttachments) {
mMessageFooterView.setVisibility(View.VISIBLE);
- mMessageFooterView.bind(item, false);
+ mMessageFooterView.bind(
+ item, ConversationViewAdapter.newMessageFooterItem(null, item), false);
}
}
@@ -288,4 +296,23 @@ public class SecureConversationViewController implements
}
// End MessageHeaderViewCallbacks implementations
+
+ // START MessageFooterCallbacks
+
+ @Override
+ public void setMessageSpacerHeight(MessageFooterItem item, int newSpacerHeight) {
+ // Do nothing.
+ }
+
+ @Override
+ public MessageFooterView getViewForItem(MessageFooterItem item) {
+ return mMessageFooterView;
+ }
+
+ @Override
+ public int getUpdatedHeight(MessageFooterItem item) {
+ return 0; // should never get called since we'll always have a footer view
+ }
+
+ // END MessageFooterCallbacks
}
diff --git a/src/com/android/mail/ui/SecureConversationViewFragment.java b/src/com/android/mail/ui/SecureConversationViewFragment.java
index f13bb0dbf..d96ff67bc 100644
--- a/src/com/android/mail/ui/SecureConversationViewFragment.java
+++ b/src/com/android/mail/ui/SecureConversationViewFragment.java
@@ -127,6 +127,12 @@ public class SecureConversationViewFragment extends AbstractConversationViewFrag
mViewController.onActivityCreated(savedInstanceState);
}
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ mViewController.onDestroyView();
+ }
+
// Start implementations of SecureConversationViewControllerCallbacks
@Override
diff --git a/src/com/android/mail/utils/StyleUtils.java b/src/com/android/mail/utils/StyleUtils.java
new file mode 100644
index 000000000..5a0a38e0c
--- /dev/null
+++ b/src/com/android/mail/utils/StyleUtils.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ * Licensed to The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.utils;
+
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.style.URLSpan;
+import android.widget.TextView;
+
+import com.android.mail.browse.UrlSpan;
+
+/**
+ * Utility class for styling UI.
+ */
+public class StyleUtils {
+
+ /**
+ * Removes any {@link android.text.style.URLSpan}s from the text view
+ * and replaces them with their non-underline version {@link com.android.mail.browse.UrlSpan}.
+ */
+ public static void stripUnderlines(TextView textView) {
+ final Spannable spannable = (Spannable) textView.getText();
+ final URLSpan[] urls = textView.getUrls();
+
+ for (URLSpan span : urls) {
+ final int start = spannable.getSpanStart(span);
+ final int end = spannable.getSpanEnd(span);
+ spannable.removeSpan(span);
+ span = new UrlSpan(span.getURL());
+ spannable.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+}