summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--assets/script.js24
-rw-r--r--res/drawable-hdpi/card_top.9.pngbin267 -> 189 bytes
-rw-r--r--res/drawable-hdpi/snap_header_gradient.9.pngbin441 -> 466 bytes
-rw-r--r--res/drawable-hdpi/stacked_message_gradient.9.pngbin0 -> 441 bytes
-rw-r--r--res/drawable-mdpi/card_top.9.pngbin224 -> 144 bytes
-rw-r--r--res/drawable-mdpi/snap_header_gradient.9.pngbin289 -> 319 bytes
-rw-r--r--res/drawable-mdpi/stacked_message_gradient.9.pngbin0 -> 289 bytes
-rw-r--r--res/drawable-xhdpi/card_top.9.pngbin302 -> 223 bytes
-rw-r--r--res/drawable-xhdpi/snap_header_gradient.9.pngbin596 -> 629 bytes
-rw-r--r--res/drawable-xhdpi/stacked_message_gradient.9.pngbin0 -> 596 bytes
-rw-r--r--res/layout/card_border.xml18
-rw-r--r--res/layout/conversation_message_header.xml5
-rw-r--r--res/layout/conversation_message_upper_header.xml1
-rw-r--r--res/values-sw600dp/dimen.xml1
-rw-r--r--res/values/dimen.xml3
-rw-r--r--src/com/android/mail/browse/BorderView.java61
-rw-r--r--src/com/android/mail/browse/ConversationContainer.java1
-rw-r--r--src/com/android/mail/browse/ConversationOverlayItem.java34
-rw-r--r--src/com/android/mail/browse/ConversationViewAdapter.java74
-rw-r--r--src/com/android/mail/browse/MessageHeaderView.java74
-rw-r--r--src/com/android/mail/ui/ConversationViewFragment.java73
-rw-r--r--src/com/android/mail/ui/ConversationViewState.java9
-rw-r--r--src/com/android/mail/ui/SecureConversationViewController.java3
23 files changed, 335 insertions, 46 deletions
diff --git a/assets/script.js b/assets/script.js
index be22529dd..b30305a48 100644
--- a/assets/script.js
+++ b/assets/script.js
@@ -638,7 +638,8 @@ function setMessageHeaderSpacerHeight(messageDomId, spacerHeight) {
measurePositions();
}
-function setMessageBodyVisible(messageDomId, isVisible, spacerHeight) {
+function setMessageBodyVisible(messageDomId, isVisible, spacerHeight,
+ topBorderHeight, bottomBorderHeight) {
var i, len;
var visibility = isVisible ? "block" : "none";
var messageDiv = document.querySelector("#" + messageDomId);
@@ -647,6 +648,27 @@ function setMessageBodyVisible(messageDomId, isVisible, spacerHeight) {
console.log("can't set body visibility for message with id: " + messageDomId);
return;
}
+
+ // if the top border has changed, update the height of its spacer
+ if (topBorderHeight > 0) {
+ var border = messageDiv.previousElementSibling;
+ if (!border) {
+ console.log("can't set spacer for top border");
+ return;
+ }
+ border.style.height = topBorderHeight + "px";
+ }
+
+ // if the bottom border has changed, update the height of its spacer
+ if (bottomBorderHeight > 0) {
+ var border = messageDiv.nextElementSibling;
+ if (!border) {
+ console.log("can't set spacer for bottom border");
+ return;
+ }
+ border.style.height = bottomBorderHeight + "px";
+ }
+
messageDiv.classList.toggle("expanded");
for (i = 0, len = collapsibleDivs.length; i < len; i++) {
collapsibleDivs[i].style.display = visibility;
diff --git a/res/drawable-hdpi/card_top.9.png b/res/drawable-hdpi/card_top.9.png
index 4162bdb98..3008de882 100644
--- a/res/drawable-hdpi/card_top.9.png
+++ b/res/drawable-hdpi/card_top.9.png
Binary files differ
diff --git a/res/drawable-hdpi/snap_header_gradient.9.png b/res/drawable-hdpi/snap_header_gradient.9.png
index 7f59fd148..08d4ff127 100644
--- a/res/drawable-hdpi/snap_header_gradient.9.png
+++ b/res/drawable-hdpi/snap_header_gradient.9.png
Binary files differ
diff --git a/res/drawable-hdpi/stacked_message_gradient.9.png b/res/drawable-hdpi/stacked_message_gradient.9.png
new file mode 100644
index 000000000..7f59fd148
--- /dev/null
+++ b/res/drawable-hdpi/stacked_message_gradient.9.png
Binary files differ
diff --git a/res/drawable-mdpi/card_top.9.png b/res/drawable-mdpi/card_top.9.png
index ae7f41a95..bfa86aa18 100644
--- a/res/drawable-mdpi/card_top.9.png
+++ b/res/drawable-mdpi/card_top.9.png
Binary files differ
diff --git a/res/drawable-mdpi/snap_header_gradient.9.png b/res/drawable-mdpi/snap_header_gradient.9.png
index 083a660f7..f847fb72c 100644
--- a/res/drawable-mdpi/snap_header_gradient.9.png
+++ b/res/drawable-mdpi/snap_header_gradient.9.png
Binary files differ
diff --git a/res/drawable-mdpi/stacked_message_gradient.9.png b/res/drawable-mdpi/stacked_message_gradient.9.png
new file mode 100644
index 000000000..083a660f7
--- /dev/null
+++ b/res/drawable-mdpi/stacked_message_gradient.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/card_top.9.png b/res/drawable-xhdpi/card_top.9.png
index 06b3714f6..2be4cdebf 100644
--- a/res/drawable-xhdpi/card_top.9.png
+++ b/res/drawable-xhdpi/card_top.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/snap_header_gradient.9.png b/res/drawable-xhdpi/snap_header_gradient.9.png
index dd56f3818..05a2af885 100644
--- a/res/drawable-xhdpi/snap_header_gradient.9.png
+++ b/res/drawable-xhdpi/snap_header_gradient.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/stacked_message_gradient.9.png b/res/drawable-xhdpi/stacked_message_gradient.9.png
new file mode 100644
index 000000000..dd56f3818
--- /dev/null
+++ b/res/drawable-xhdpi/stacked_message_gradient.9.png
Binary files differ
diff --git a/res/layout/card_border.xml b/res/layout/card_border.xml
index 12be259c9..dc2d71cac 100644
--- a/res/layout/card_border.xml
+++ b/res/layout/card_border.xml
@@ -25,14 +25,24 @@
android:id="@+id/card_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/conversation_view_margin_side"
- android:layout_marginLeft="@dimen/conversation_view_margin_side"
- android:layout_marginEnd="@dimen/conversation_view_margin_side"
- android:layout_marginRight="@dimen/conversation_view_margin_side"
+ android:layout_marginStart="@dimen/conversation_view_margin_side_minus_gradient"
+ android:layout_marginLeft="@dimen/conversation_view_margin_side_minus_gradient"
+ android:layout_marginEnd="@dimen/conversation_view_margin_side_minus_gradient"
+ android:layout_marginRight="@dimen/conversation_view_margin_side_minus_gradient"
android:layout_gravity="top"
android:background="@drawable/card_bottom" />
<Space
android:id="@+id/border_space"
android:layout_width="match_parent"
android:layout_height="@dimen/message_border_height" />
+ <View
+ android:id="@+id/card_top"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/conversation_view_margin_side_minus_gradient"
+ android:layout_marginLeft="@dimen/conversation_view_margin_side_minus_gradient"
+ android:layout_marginEnd="@dimen/conversation_view_margin_side_minus_gradient"
+ android:layout_marginRight="@dimen/conversation_view_margin_side_minus_gradient"
+ android:layout_gravity="bottom"
+ android:background="@drawable/card_top" />
</com.android.mail.browse.BorderView>
diff --git a/res/layout/conversation_message_header.xml b/res/layout/conversation_message_header.xml
index 8734131c0..21c111c9b 100644
--- a/res/layout/conversation_message_header.xml
+++ b/res/layout/conversation_message_header.xml
@@ -20,7 +20,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible"
- android:background="@color/message_header_background_color"
android:orientation="vertical"
android:layout_marginStart="@dimen/conversation_view_margin_side"
android:layout_marginEnd="@dimen/conversation_view_margin_side"
@@ -33,7 +32,7 @@
<View
android:id="@+id/snap_header_bottom_border"
android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="@color/conversation_view_border_color"
+ android:layout_height="12dp"
+ android:background="@drawable/snap_header_gradient"
android:visibility="gone" />
</com.android.mail.browse.MessageHeaderView>
diff --git a/res/layout/conversation_message_upper_header.xml b/res/layout/conversation_message_upper_header.xml
index 82ede70c7..3e9d2e857 100644
--- a/res/layout/conversation_message_upper_header.xml
+++ b/res/layout/conversation_message_upper_header.xml
@@ -18,6 +18,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:background="@color/message_header_background_color"
android:duplicateParentState="true" >
<QuickContactBadge
diff --git a/res/values-sw600dp/dimen.xml b/res/values-sw600dp/dimen.xml
index ba74f9e3f..93184c437 100644
--- a/res/values-sw600dp/dimen.xml
+++ b/res/values-sw600dp/dimen.xml
@@ -24,6 +24,7 @@
<dimen name="conversation_header_side_padding">40dip</dimen>
<dimen name="conversation_page_gutter">0dip</dimen>
<dimen name="message_border_height">16dp</dimen>
+ <dimen name="message_border_height_with_card">23dp</dimen>
<dimen name="message_header_padding_start">24dp</dimen>
<dimen name="message_header_inner_side_padding">16dp</dimen>
<dimen name="message_header_contact_photo_width">64dp</dimen>
diff --git a/res/values/dimen.xml b/res/values/dimen.xml
index 0c69b73ee..eef4024ac 100644
--- a/res/values/dimen.xml
+++ b/res/values/dimen.xml
@@ -42,6 +42,7 @@
<dimen name="conversation_message_content_margin_side">16dp</dimen>
<dimen name="conversation_view_margin_side">8dp</dimen>
<dimen name="conversation_view_margin_side_minus_gradient">7dp</dimen>
+ <dimen name="conversation_view_margin_side_gradient">1dp</dimen>
<dimen name="conversation_header_font_size">18sp</dimen>
<dimen name="conversation_header_font_size_condensed">14sp</dimen>
<dimen name="conversation_header_vertical_padding">16dip</dimen>
@@ -57,6 +58,8 @@
<dimen name="message_details_header_padding_end">10dip</dimen>
<dimen name="message_details_header_vertical_padding">7dp</dimen>
<dimen name="message_border_height">8dp</dimen>
+ <dimen name="message_border_height_collapsed">1dp</dimen>
+ <dimen name="message_border_height_with_card">15dp</dimen>
<dimen name="message_header_presence_top_margin">-4dp</dimen>
<dimen name="message_header_action_button_width">48dp</dimen>
<dimen name="message_header_action_button_height">48dp</dimen>
diff --git a/src/com/android/mail/browse/BorderView.java b/src/com/android/mail/browse/BorderView.java
index 79322b48a..1fab0a871 100644
--- a/src/com/android/mail/browse/BorderView.java
+++ b/src/com/android/mail/browse/BorderView.java
@@ -17,18 +17,30 @@
package com.android.mail.browse;
import android.content.Context;
+import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.LinearLayout;
-import com.android.mail.browse.ConversationViewAdapter.BorderItem;
-
import com.android.mail.R;
+import com.android.mail.browse.ConversationViewAdapter.BorderItem;
+/**
+ * View displaying the border between messages.
+ * Contains two nine-patches and a {@link android.widget.Space}.
+ * The nine patches are the bottom of the preceding message
+ * and the top of the following message.
+ */
public class BorderView extends LinearLayout {
+ private static int sMessageBorderSpaceHeight = -1;
+ private static int sMessageBorderHeightCollapsed = -1;
+ private static int sMessageBorderHeightWithCard = -1;
+
private View mCardBottom;
private View mBorderSpace;
+ private View mCardTop;
public BorderView(Context context) {
this(context, null);
@@ -40,6 +52,22 @@ public class BorderView extends LinearLayout {
public BorderView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+
+ // In order to update the height appropriately based on
+ // whether the border is expanded or collapsed,
+ // we want to stash the height values for for the
+ // space in both its expanded and collapsed values.
+ // Additionally, we stash the total height of the view
+ // when both nine patches are visible.
+ if (sMessageBorderSpaceHeight == -1) {
+ final Resources res = context.getResources();
+ sMessageBorderSpaceHeight =
+ res.getDimensionPixelSize(R.dimen.message_border_height);
+ sMessageBorderHeightCollapsed = res.getDimensionPixelSize(
+ R.dimen.message_border_height_collapsed);
+ sMessageBorderHeightWithCard = res.getDimensionPixelSize(
+ R.dimen.message_border_height_with_card);
+ }
}
@Override
@@ -48,9 +76,36 @@ public class BorderView extends LinearLayout {
mCardBottom = findViewById(R.id.card_bottom);
mBorderSpace = findViewById(R.id.border_space);
+ mCardTop = findViewById(R.id.card_top);
}
public void bind(BorderItem borderItem, boolean measureOnly) {
- mCardBottom.setVisibility(borderItem.isFirstBorder() ? GONE : VISIBLE);
+ final boolean isExpanded = borderItem.isExpanded();
+
+ // Selectively show/hide the card nine-patches if the border is expanded or collapsed.
+ // Additionally this will occur if this is the first or last border.
+ mCardBottom.setVisibility(!isExpanded || borderItem.isFirstBorder() ? GONE : VISIBLE);
+ mCardTop.setVisibility(!isExpanded || borderItem.isLastBorder() ? GONE : VISIBLE);
+
+ // Adjust space height based on expanded state.
+ final ViewGroup.LayoutParams params = mBorderSpace.getLayoutParams();
+ params.height = isExpanded ? sMessageBorderSpaceHeight : sMessageBorderHeightCollapsed;
+ mBorderSpace.setLayoutParams(params);
+ }
+
+ /**
+ * Returns the full expanded height value of the border view.
+ * This height should never change.
+ */
+ public static int getExpandedHeight() {
+ return sMessageBorderHeightWithCard;
+ }
+
+ /**
+ * Returns the collapsed height value of the border view.
+ * This height should never change.
+ */
+ public static int getCollapsedHeight() {
+ return sMessageBorderHeightCollapsed;
}
}
diff --git a/src/com/android/mail/browse/ConversationContainer.java b/src/com/android/mail/browse/ConversationContainer.java
index b6e20548a..192278b1d 100644
--- a/src/com/android/mail/browse/ConversationContainer.java
+++ b/src/com/android/mail/browse/ConversationContainer.java
@@ -739,6 +739,7 @@ public class ConversationContainer extends ViewGroup implements ScrollListener {
} else {
traceLayout("move overlay %d", adapterIndex);
if (!item.isMeasurementValid()) {
+ item.rebindView(overlayView);
measureOverlayView(overlayView);
item.markMeasurementValid();
traceLayout("and (re)measure overlay %d, old/new heights=%d/%d", adapterIndex,
diff --git a/src/com/android/mail/browse/ConversationOverlayItem.java b/src/com/android/mail/browse/ConversationOverlayItem.java
index cae878f46..f9253f3a1 100644
--- a/src/com/android/mail/browse/ConversationOverlayItem.java
+++ b/src/com/android/mail/browse/ConversationOverlayItem.java
@@ -35,6 +35,8 @@ public abstract class ConversationOverlayItem {
public static final String LOG_TAG = ConversationViewFragment.LAYOUT_TAG;
+ private int mPosition;
+
/**
* @see Adapter#getItemViewType(int)
*/
@@ -60,6 +62,13 @@ public abstract class ConversationOverlayItem {
*/
public abstract boolean isContiguous();
+ /**
+ * Returns true if this overlay view is in its expanded state.
+ */
+ public boolean isExpanded() {
+ return true;
+ }
+
public int getGravity() {
return Gravity.BOTTOM;
}
@@ -137,4 +146,29 @@ public abstract class ConversationOverlayItem {
public void onModelUpdated(View v) {
}
+ public void setPosition(int position) {
+ mPosition = position;
+ }
+
+ public int getPosition() {
+ return mPosition;
+ }
+
+ /**
+ * This is a hack. Now that one view can update the
+ * state of another view, we need a mechanism when the
+ * view's associated item changes to update the state of the
+ * view. Typically, classes that override this class should not
+ * override this method. This method is used by
+ * {@link com.android.mail.browse.ConversationViewAdapter.BorderItem}
+ * to update the height of the border based on whether the neighboring messages
+ * are collapsed or expanded. The only other way would be to
+ * {@link com.android.mail.browse.ConversationViewAdapter#notifyDataSetChanged()}
+ * but that makes the entire screen flicker since the entire adapter performs
+ * a layout of the every item.
+ * @param view the view to be re-bound
+ */
+ public void rebindView(View view) {
+ // DO NOTHING
+ }
}
diff --git a/src/com/android/mail/browse/ConversationViewAdapter.java b/src/com/android/mail/browse/ConversationViewAdapter.java
index 620a5fc6b..64fc2f496 100644
--- a/src/com/android/mail/browse/ConversationViewAdapter.java
+++ b/src/com/android/mail/browse/ConversationViewAdapter.java
@@ -187,6 +187,7 @@ public class ConversationViewAdapter extends BaseAdapter {
return !isExpanded();
}
+ @Override
public boolean isExpanded() {
return mExpanded;
}
@@ -242,6 +243,10 @@ public class ConversationViewAdapter extends BaseAdapter {
mTimestampLong = mDateBuilder.formatLongDateTime(mTimestampMs);
}
}
+
+ public ConversationViewAdapter getAdapter() {
+ return mAdapter;
+ }
}
public class MessageFooterItem extends ConversationOverlayItem {
@@ -249,10 +254,10 @@ public class ConversationViewAdapter extends BaseAdapter {
* 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 headerItem;
+ private final MessageHeaderItem mHeaderitem;
private MessageFooterItem(MessageHeaderItem item) {
- headerItem = item;
+ mHeaderitem = item;
}
@Override
@@ -271,7 +276,7 @@ public class ConversationViewAdapter extends BaseAdapter {
@Override
public void bindView(View v, boolean measureOnly) {
final MessageFooterView attachmentsView = (MessageFooterView) v;
- attachmentsView.bind(headerItem, mAccountController.getAccount().uri, measureOnly);
+ attachmentsView.bind(mHeaderitem, mAccountController.getAccount().uri, measureOnly);
}
@Override
@@ -280,6 +285,11 @@ public class ConversationViewAdapter extends BaseAdapter {
}
@Override
+ public boolean isExpanded() {
+ return mHeaderitem.isExpanded();
+ }
+
+ @Override
public int getGravity() {
// attachments are top-aligned within their spacer area
// Attachments should stay near the body they belong to, even when zoomed far in.
@@ -290,7 +300,7 @@ 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 (!headerItem.isExpanded()) {
+ if (!mHeaderitem.isExpanded()) {
return 0;
}
return super.getHeight();
@@ -331,6 +341,11 @@ public class ConversationViewAdapter extends BaseAdapter {
return true;
}
+ @Override
+ public boolean isExpanded() {
+ return false;
+ }
+
public int getStart() {
return mStart;
}
@@ -348,11 +363,16 @@ public class ConversationViewAdapter extends BaseAdapter {
public class BorderItem extends ConversationOverlayItem {
private final boolean mContiguous;
+ private boolean mExpanded;
private final boolean mFirstBorder;
+ private boolean mLastBorder;
- public BorderItem(boolean contiguous, boolean firstBorder) {
+ public BorderItem(boolean contiguous, boolean isExpanded,
+ boolean firstBorder, boolean lastBorder) {
mContiguous = contiguous;
+ mExpanded = isExpanded;
mFirstBorder = firstBorder;
+ mLastBorder = lastBorder;
}
@Override
@@ -377,13 +397,39 @@ public class ConversationViewAdapter extends BaseAdapter {
}
@Override
+ public boolean isExpanded() {
+ return mExpanded;
+ }
+
+ public void setExpanded(boolean isExpanded) {
+ mExpanded = isExpanded;
+ }
+
+ @Override
public boolean canPushSnapHeader() {
- return true;
+ return false;
}
public boolean isFirstBorder() {
return mFirstBorder;
}
+
+ public boolean isLastBorder() {
+ return mLastBorder;
+ }
+
+ public void setIsLastBorder(boolean isLastBorder) {
+ mLastBorder = isLastBorder;
+ }
+
+ public ConversationViewAdapter getAdapter() {
+ return ConversationViewAdapter.this;
+ }
+
+ @Override
+ public void rebindView(View view) {
+ bindView(view, false);
+ }
}
public ConversationViewAdapter(ControllableActivity controllableActivity,
@@ -460,6 +506,7 @@ public class ConversationViewAdapter extends BaseAdapter {
public int addItem(ConversationOverlayItem item) {
final int pos = mItems.size();
+ item.setPosition(pos);
mItems.add(item);
return pos;
}
@@ -495,12 +542,14 @@ public class ConversationViewAdapter extends BaseAdapter {
return addItem(new SuperCollapsedBlockItem(start, end));
}
- public int addBorder(boolean contiguous, boolean firstBorder) {
- return addItem(new BorderItem(contiguous, firstBorder));
+ public int addBorder(
+ boolean contiguous, boolean expanded, boolean firstBorder, boolean lastBorder) {
+ return addItem(new BorderItem(contiguous, expanded, firstBorder, lastBorder));
}
- public BorderItem newBorderItem(boolean contiguous, boolean firstBorder) {
- return new BorderItem(contiguous, firstBorder);
+ public BorderItem newBorderItem(boolean contiguous, boolean expanded) {
+ return new BorderItem(
+ contiguous, expanded, false /* firstBorder */, false /* lastBorder */);
}
public void replaceSuperCollapsedBlock(SuperCollapsedBlockItem blockToRemove,
@@ -512,6 +561,11 @@ public class ConversationViewAdapter extends BaseAdapter {
mItems.remove(pos);
mItems.addAll(pos, replacements);
+
+ // update position for all items
+ for (int i = 0, size = mItems.size(); i < size; i++) {
+ mItems.get(i).setPosition(i);
+ }
}
public void updateItemsForMessage(ConversationMessage message,
diff --git a/src/com/android/mail/browse/MessageHeaderView.java b/src/com/android/mail/browse/MessageHeaderView.java
index feafb9a88..29df7aea5 100644
--- a/src/com/android/mail/browse/MessageHeaderView.java
+++ b/src/com/android/mail/browse/MessageHeaderView.java
@@ -30,7 +30,6 @@ import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
-import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import android.text.style.URLSpan;
import android.util.AttributeSet;
@@ -51,6 +50,7 @@ import android.widget.Toast;
import com.android.mail.ContactInfo;
import com.android.mail.ContactInfoSource;
import com.android.mail.R;
+import com.android.mail.browse.ConversationViewAdapter.BorderItem;
import com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem;
import com.android.mail.compose.ComposeActivity;
import com.android.mail.perf.Timer;
@@ -221,7 +221,8 @@ public class MessageHeaderView extends LinearLayout implements OnClickListener,
public interface MessageHeaderViewCallbacks {
void setMessageSpacerHeight(MessageHeaderItem item, int newSpacerHeight);
- void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight);
+ void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight,
+ int topBorderHeight, int bottomBorderHeight);
void setMessageDetailsExpanded(MessageHeaderItem messageHeaderItem, boolean expanded,
int previousMessageHeaderItemHeight);
@@ -967,14 +968,81 @@ public class MessageHeaderView extends LinearLayout implements OnClickListener,
updateChildVisibility();
+ final BorderHeights borderHeights = updateBorderExpandedState();
+
// Force-measure the new header height so we can set the spacer size and
// reveal the message div in one pass. Force-measuring makes it unnecessary to set
// mSizeChanged.
int h = measureHeight();
mMessageHeaderItem.setHeight(h);
if (mCallbacks != null) {
- mCallbacks.setMessageExpanded(mMessageHeaderItem, h);
+ mCallbacks.setMessageExpanded(mMessageHeaderItem, h,
+ borderHeights.topHeight, borderHeights.bottomHeight);
+ }
+ }
+
+ /**
+ * Checks the neighboring messages to this message and
+ * updates the {@link BorderItem}s of the borders of this message
+ * in case they should be collapsed or expanded.
+ * @return a {@link BorderHeights} object containing
+ * the new heights of the top and bottom borders.
+ */
+ private BorderHeights updateBorderExpandedState() {
+ final int position = mMessageHeaderItem.getPosition();
+ final boolean isExpanded = mMessageHeaderItem.isExpanded();
+ final int abovePosition = position - 2; // position of MessageFooterItem above header
+ final int belowPosition = position + 3; // position of next MessageHeaderItem
+ final ConversationViewAdapter adapter = mMessageHeaderItem.getAdapter();
+ final int size = adapter.getCount();
+ final BorderHeights borderHeights = new BorderHeights();
+
+ // if an above message exists, update the border above this message
+ if (isValidPosition(abovePosition, size)) {
+ final ConversationOverlayItem item = adapter.getItem(abovePosition);
+ final int type = item.getType();
+ if (type == ConversationViewAdapter.VIEW_TYPE_MESSAGE_FOOTER ||
+ type == ConversationViewAdapter.VIEW_TYPE_SUPER_COLLAPSED_BLOCK) {
+ final BorderItem borderItem = (BorderItem) adapter.getItem(abovePosition + 1);
+ final boolean borderIsExpanded = isExpanded || item.isExpanded();
+ borderItem.setExpanded(borderIsExpanded);
+ borderHeights.topHeight = borderIsExpanded ?
+ BorderView.getExpandedHeight() : BorderView.getCollapsedHeight();
+ borderItem.setHeight(borderHeights.topHeight);
+ }
+ }
+
+
+ // if a below message exists, update the border below this message
+ if (isValidPosition(belowPosition, size)) {
+ final ConversationOverlayItem item = adapter.getItem(belowPosition);
+ if (item.getType() == ConversationViewAdapter.VIEW_TYPE_MESSAGE_HEADER) {
+ final BorderItem borderItem = (BorderItem) adapter.getItem(belowPosition - 1);
+ final boolean borderIsExpanded = isExpanded || item.isExpanded();
+ borderItem.setExpanded(borderIsExpanded);
+ borderHeights.bottomHeight = borderIsExpanded ?
+ BorderView.getExpandedHeight() : BorderView.getCollapsedHeight();
+ borderItem.setHeight(borderHeights.bottomHeight);
+ }
}
+
+ return borderHeights;
+ }
+
+ /**
+ * A plain-old-data class used to return the new heights of the top and bottom borders
+ * in {@link #updateBorderExpandedState()}.
+ * If {@link #topHeight} or {@link #bottomHeight} are -1 after returning,
+ * do not update the heights of the spacer for their respective borders
+ * as their state has not changed.
+ */
+ private class BorderHeights {
+ public int topHeight = -1;
+ public int bottomHeight = -1;
+ }
+
+ private boolean isValidPosition(int position, int size) {
+ return position >= 0 && position < size;
}
private void toggleMessageDetails(View visibleDetailsView) {
diff --git a/src/com/android/mail/ui/ConversationViewFragment.java b/src/com/android/mail/ui/ConversationViewFragment.java
index e0a45d698..b298e6947 100644
--- a/src/com/android/mail/ui/ConversationViewFragment.java
+++ b/src/com/android/mail/ui/ConversationViewFragment.java
@@ -645,6 +645,9 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
ConversationMessage prevCollapsedMsg = null;
boolean prevSafeForImages = false;
+ // Store the previous expanded state so that the border between
+ // the previous and current message can be properly initialized.
+ int previousExpandedState = ExpansionState.NONE;
while (messageCursor.moveToPosition(++pos)) {
final ConversationMessage msg = messageCursor.getMessage();
@@ -693,15 +696,18 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
// This line puts the from address in the address cache so that
// we get the sender image for it if it's in a super-collapsed block.
getAddress(msg.getFrom());
+ previousExpandedState = expandedState;
continue;
}
// resolve any deferred decisions on previous collapsed items
if (collapsedStart >= 0) {
if (pos - collapsedStart == 1) {
- // special-case for a single collapsed message: no need to super-collapse it
- renderMessage(prevCollapsedMsg, false /* expanded */,
- prevSafeForImages, true /* firstBorder */);
+ // Special-case for a single collapsed message: no need to super-collapse it.
+ // Since it is super-collapsed, there is no previous message to be
+ // collapsed and the border above it is the first border.
+ renderMessage(prevCollapsedMsg, false /* previousCollapsed */,
+ false /* expanded */, prevSafeForImages, true /* firstBorder */);
} else {
renderSuperCollapsedBlock(collapsedStart, pos - 1);
}
@@ -709,15 +715,19 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
collapsedStart = -1;
}
- renderMessage(msg, ExpansionState.isExpanded(expandedState), safeForImages,
+ renderMessage(msg, ExpansionState.isCollapsed(previousExpandedState),
+ ExpansionState.isExpanded(expandedState), safeForImages,
pos == 0 /* firstBorder */);
+
+ previousExpandedState = expandedState;
}
mWebView.getSettings().setBlockNetworkImage(!allowNetworkImages);
final boolean applyTransforms = shouldApplyTransforms();
- renderBorder(true /* contiguous */, false /* firstBorder */);
+ renderBorder(true /* contiguous */, true /* expanded */,
+ false /* firstBorder */, true /* lastBorder */);
// If the conversation has specified a base uri, use it here, otherwise use mBaseUri
return mTemplates.endConversation(mBaseUri, mConversation.getBaseUri(mBaseUri), 320,
@@ -726,27 +736,33 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
}
private void renderSuperCollapsedBlock(int start, int end) {
- renderBorder(true /* contiguous */, true /* firstBorder */);
+ renderBorder(true /* contiguous */, true /* expanded */,
+ true /* firstBorder */, false /* lastBorder */);
final int blockPos = mAdapter.addSuperCollapsedBlock(start, end);
final int blockPx = measureOverlayHeight(blockPos);
mTemplates.appendSuperCollapsedHtml(start, mWebView.screenPxToWebPx(blockPx));
}
- protected void renderBorder(boolean contiguous, boolean firstBorder) {
- final int blockPos = mAdapter.addBorder(contiguous, firstBorder);
+ protected void renderBorder(
+ boolean contiguous, boolean expanded, boolean firstBorder, boolean lastBorder) {
+ final int blockPos = mAdapter.addBorder(contiguous, expanded, firstBorder, lastBorder);
final int blockPx = measureOverlayHeight(blockPos);
mTemplates.appendBorder(mWebView.screenPxToWebPx(blockPx));
}
- private void renderMessage(ConversationMessage msg, boolean expanded,
- boolean safeForImages, boolean firstBorder) {
- renderMessage(msg, expanded, safeForImages, true /* renderBorder */, firstBorder);
+ private void renderMessage(ConversationMessage msg, boolean previousCollapsed,
+ boolean expanded, boolean safeForImages, boolean firstBorder) {
+ renderMessage(msg, previousCollapsed, expanded, safeForImages,
+ true /* renderBorder */, firstBorder);
}
- private void renderMessage(ConversationMessage msg, boolean expanded,
- boolean safeForImages, boolean renderBorder, boolean firstBorder) {
+ private void renderMessage(ConversationMessage msg, boolean previousCollapsed,
+ boolean expanded, boolean safeForImages, boolean renderBorder, boolean firstBorder) {
if (renderBorder) {
- renderBorder(true /* contiguous */, firstBorder);
+ // The border should be collapsed only if both the current
+ // and previous messages are collapsed.
+ renderBorder(true /* contiguous */, !previousCollapsed || expanded,
+ firstBorder, false /* lastBorder */);
}
final int headerPos = mAdapter.addMessageHeader(msg, expanded,
@@ -785,8 +801,10 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
borderPx = 0;
first = false;
} else {
- final BorderItem border =
- mAdapter.newBorderItem(true /* contiguous */, false /* firstBorder */);
+ // When replacing the super-collapsed block,
+ // the border is always collapsed between messages.
+ final BorderItem border = mAdapter.newBorderItem(
+ true /* contiguous */, false /* expanded */);
borderPx = measureOverlayHeight(border);
replacements.add(border);
mTemplates.appendBorder(mWebView.screenPxToWebPx(borderPx));
@@ -881,15 +899,19 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
}
@Override
- public void setMessageExpanded(MessageHeaderItem item, int newSpacerHeightPx) {
+ public void setMessageExpanded(MessageHeaderItem item, int newSpacerHeightPx,
+ int topBorderHeight, int bottomBorderHeight) {
mConversationContainer.invalidateSpacerGeometry();
// show/hide the HTML message body and update the spacer height
final int h = mWebView.screenPxToWebPx(newSpacerHeightPx);
+ final int topHeight = mWebView.screenPxToWebPx(topBorderHeight);
+ final int bottomHeight = mWebView.screenPxToWebPx(bottomBorderHeight);
LogUtils.i(LAYOUT_TAG, "setting HTML spacer expanded=%s h=%dwebPx (%dscreenPx)",
item.isExpanded(), h, newSpacerHeightPx);
- mWebView.loadUrl(String.format("javascript:setMessageBodyVisible('%s', %s, %s);",
- mTemplates.getMessageDomId(item.getMessage()), item.isExpanded(), h));
+ mWebView.loadUrl(String.format("javascript:setMessageBodyVisible('%s', %s, %s, %s, %s);",
+ mTemplates.getMessageDomId(item.getMessage()), item.isExpanded(),
+ h, topHeight, bottomHeight));
mViewState.setExpansionState(item.getMessage(),
item.isExpanded() ? ExpansionState.EXPANDED : ExpansionState.COLLAPSED);
@@ -1411,12 +1433,21 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
}
private void processNewOutgoingMessage(ConversationMessage msg) {
+ // make the last border no longer be the border
+ ((BorderItem) mAdapter.getItem(mAdapter.getCount() - 1)).setIsLastBorder(false);
+
mTemplates.reset();
// this method will add some items to mAdapter, but we deliberately want to avoid notifying
// adapter listeners (i.e. ConversationContainer) until onWebContentGeometryChange is next
// called, to prevent N+1 headers rendering with N message bodies.
- renderMessage(msg, true /* expanded */, msg.alwaysShowImages, false /* renderBorder */);
- renderBorder(true /* contiguous */, false /* firstBorder */);
+
+ // We can just call previousCollapsed false here since the border
+ // above the message we're about to render should always show
+ // (which it also will since the message being render is expanded).
+ renderMessage(msg, false /* previousCollapsed */, true /* expanded */,
+ msg.alwaysShowImages, false /* renderBorder */, false /* firstBorder */);
+ renderBorder(true /* contiguous */, true /* expanded */,
+ false /* firstBorder */, true /* lastBorder */);
mTempBodiesHtml = mTemplates.emit();
mViewState.setExpansionState(msg, ExpansionState.EXPANDED);
diff --git a/src/com/android/mail/ui/ConversationViewState.java b/src/com/android/mail/ui/ConversationViewState.java
index 2d733fa53..b93c990ac 100644
--- a/src/com/android/mail/ui/ConversationViewState.java
+++ b/src/com/android/mail/ui/ConversationViewState.java
@@ -43,6 +43,7 @@ public class ConversationViewState implements Parcelable {
private byte[] mConversationInfo;
public static final class ExpansionState {
+ public static int NONE = 0;
public static int EXPANDED = 1;
public static int COLLAPSED = 2;
public static int SUPER_COLLAPSED = 3;
@@ -55,6 +56,14 @@ public class ConversationViewState implements Parcelable {
public static boolean isSuperCollapsed(int state) {
return state == SUPER_COLLAPSED;
}
+
+ /**
+ * Returns true if the {@link ExpansionState} is
+ * {@link #COLLAPSED} or {@link #SUPER_COLLAPSED}.
+ */
+ public static boolean isCollapsed(int state) {
+ return state > EXPANDED;
+ }
}
public ConversationViewState() {}
diff --git a/src/com/android/mail/ui/SecureConversationViewController.java b/src/com/android/mail/ui/SecureConversationViewController.java
index 77f618ec5..55a466bc0 100644
--- a/src/com/android/mail/ui/SecureConversationViewController.java
+++ b/src/com/android/mail/ui/SecureConversationViewController.java
@@ -178,7 +178,8 @@ public class SecureConversationViewController implements
}
@Override
- public void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight) {
+ public void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight,
+ int topBorderHeight, int bottomBorderHeight) {
// Do nothing.
}