diff options
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 Binary files differindex 4162bdb98..3008de882 100644 --- a/res/drawable-hdpi/card_top.9.png +++ b/res/drawable-hdpi/card_top.9.png diff --git a/res/drawable-hdpi/snap_header_gradient.9.png b/res/drawable-hdpi/snap_header_gradient.9.png Binary files differindex 7f59fd148..08d4ff127 100644 --- a/res/drawable-hdpi/snap_header_gradient.9.png +++ b/res/drawable-hdpi/snap_header_gradient.9.png diff --git a/res/drawable-hdpi/stacked_message_gradient.9.png b/res/drawable-hdpi/stacked_message_gradient.9.png Binary files differnew file mode 100644 index 000000000..7f59fd148 --- /dev/null +++ b/res/drawable-hdpi/stacked_message_gradient.9.png diff --git a/res/drawable-mdpi/card_top.9.png b/res/drawable-mdpi/card_top.9.png Binary files differindex ae7f41a95..bfa86aa18 100644 --- a/res/drawable-mdpi/card_top.9.png +++ b/res/drawable-mdpi/card_top.9.png diff --git a/res/drawable-mdpi/snap_header_gradient.9.png b/res/drawable-mdpi/snap_header_gradient.9.png Binary files differindex 083a660f7..f847fb72c 100644 --- a/res/drawable-mdpi/snap_header_gradient.9.png +++ b/res/drawable-mdpi/snap_header_gradient.9.png diff --git a/res/drawable-mdpi/stacked_message_gradient.9.png b/res/drawable-mdpi/stacked_message_gradient.9.png Binary files differnew file mode 100644 index 000000000..083a660f7 --- /dev/null +++ b/res/drawable-mdpi/stacked_message_gradient.9.png diff --git a/res/drawable-xhdpi/card_top.9.png b/res/drawable-xhdpi/card_top.9.png Binary files differindex 06b3714f6..2be4cdebf 100644 --- a/res/drawable-xhdpi/card_top.9.png +++ b/res/drawable-xhdpi/card_top.9.png diff --git a/res/drawable-xhdpi/snap_header_gradient.9.png b/res/drawable-xhdpi/snap_header_gradient.9.png Binary files differindex dd56f3818..05a2af885 100644 --- a/res/drawable-xhdpi/snap_header_gradient.9.png +++ b/res/drawable-xhdpi/snap_header_gradient.9.png diff --git a/res/drawable-xhdpi/stacked_message_gradient.9.png b/res/drawable-xhdpi/stacked_message_gradient.9.png Binary files differnew file mode 100644 index 000000000..dd56f3818 --- /dev/null +++ b/res/drawable-xhdpi/stacked_message_gradient.9.png 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. } |