Posprocessing HTML for stream items.
- Aligning images
- Fixing the margin and color of the blockquote
Bug: 5250700
Bug: 5243091
Change-Id: Ife799c669ac98bf8f7033529fb2b0977ad91ce09
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 5e8bd70..e83988b 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -108,4 +108,7 @@
<!-- Color of the semi-transparent shadow box on contact tiles -->
<color name="contact_tile_shadow_box_color">#7F000000</color>
+ <!-- Color of the vertical stripe that goes on the left of a block quote inside a stream item -->
+ <color name="stream_item_stripe_color">#CCCCCC</color>
+
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 13bb791..b5eaa52 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -270,4 +270,7 @@
<!-- Vertical and horizontal padding in between contact tiles -->
<dimen name="contact_tile_divider_padding">1dip</dimen>
+ <!-- Width of the lead margin on the left of a block quote inside a stream item -->
+ <dimen name="stream_item_stripe_width">8dip</dimen>
+
</resources>
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index cd4add6..f94629b 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -22,6 +22,7 @@
import com.android.contacts.R;
import com.android.contacts.preference.ContactsPreferences;
import com.android.contacts.util.ContactBadgeUtil;
+import com.android.contacts.util.HtmlUtils;
import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.StreamItemPhotoEntry;
import com.google.common.annotations.VisibleForTesting;
@@ -236,7 +237,7 @@
String photoUri = null;
if (!contactData.getStreamItems().isEmpty()) {
StreamItemEntry firstEntry = contactData.getStreamItems().get(0);
- snippet = Html.fromHtml(firstEntry.getText());
+ snippet = HtmlUtils.fromHtml(context, firstEntry.getText());
if (!firstEntry.getPhotos().isEmpty()) {
StreamItemPhotoEntry firstPhoto = firstEntry.getPhotos().get(0);
photoUri = firstPhoto.getPhotoUri();
@@ -338,10 +339,11 @@
R.id.stream_item_attribution);
TextView commentsView = (TextView) rootView.findViewById(R.id.stream_item_comments);
ImageGetter imageGetter = new DefaultImageGetter(context.getPackageManager());
- htmlView.setText(Html.fromHtml(streamItem.getText(), imageGetter, null));
+ htmlView.setText(HtmlUtils.fromHtml(context, streamItem.getText(), imageGetter, null));
attributionView.setText(ContactBadgeUtil.getSocialDate(streamItem, context));
if (streamItem.getComments() != null) {
- commentsView.setText(Html.fromHtml(streamItem.getComments(), imageGetter, null));
+ commentsView.setText(HtmlUtils.fromHtml(context, streamItem.getComments(), imageGetter,
+ null));
commentsView.setVisibility(View.VISIBLE);
} else {
commentsView.setVisibility(View.GONE);
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index dd44310..9d064a5 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -21,6 +21,7 @@
import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.util.ContactBadgeUtil;
+import com.android.contacts.util.HtmlUtils;
import com.android.contacts.util.StreamItemEntry;
import android.app.PendingIntent;
@@ -36,7 +37,6 @@
import android.net.Uri;
import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsContract.StreamItems;
-import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
@@ -208,7 +208,7 @@
} else {
// TODO: Rotate between all the stream items?
StreamItemEntry streamItem = streamItems.get(0);
- CharSequence status = Html.fromHtml(streamItem.getText());
+ CharSequence status = HtmlUtils.fromHtml(context, streamItem.getText());
if (status.length() <= SHORT_SNIPPET_LENGTH) {
sb.append("\n");
} else {
diff --git a/src/com/android/contacts/util/HtmlUtils.java b/src/com/android/contacts/util/HtmlUtils.java
new file mode 100644
index 0000000..4663657
--- /dev/null
+++ b/src/com/android/contacts/util/HtmlUtils.java
@@ -0,0 +1,101 @@
+package com.android.contacts.util;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.text.Html;
+import android.text.Html.ImageGetter;
+import android.text.Html.TagHandler;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.ImageSpan;
+import android.text.style.QuoteSpan;
+
+import com.android.contacts.R;
+
+/**
+ * Provides static functions to perform custom HTML to text conversions.
+ * Specifically, it adjusts the color and padding of the vertical
+ * stripe on block quotes and alignment of inlined images.
+ */
+public class HtmlUtils {
+
+ /**
+ * Converts HTML string to a {@link Spanned} text, adjusting formatting.
+ */
+ public static Spanned fromHtml(Context context, String text) {
+ Spanned spanned = Html.fromHtml(text);
+ postprocess(context, spanned);
+ return spanned;
+ }
+
+ /**
+ * Converts HTML string to a {@link Spanned} text, adjusting formatting and using a custom
+ * image getter.
+ */
+ public static CharSequence fromHtml(Context context, String text, ImageGetter imageGetter,
+ TagHandler tagHandler) {
+ Spanned spanned = Html.fromHtml(text, imageGetter, tagHandler);
+ postprocess(context, spanned);
+ return spanned;
+ }
+
+ /**
+ * Replaces some spans with custom versions of those.
+ */
+ private static void postprocess(Context context, Spanned spanned) {
+ if (!(spanned instanceof SpannableStringBuilder)) {
+ return;
+ }
+
+ int length = spanned.length();
+
+ SpannableStringBuilder builder = (SpannableStringBuilder)spanned;
+ QuoteSpan[] quoteSpans = spanned.getSpans(0, length, QuoteSpan.class);
+ if (quoteSpans != null && quoteSpans.length != 0) {
+ Resources resources = context.getResources();
+ int color = resources.getColor(R.color.stream_item_stripe_color);
+ int width = resources.getDimensionPixelSize(R.dimen.stream_item_stripe_width);
+ for (int i = 0; i < quoteSpans.length; i++) {
+ replaceSpan(builder, quoteSpans[i], new StreamItemQuoteSpan(color, width));
+ }
+ }
+
+ ImageSpan[] imageSpans = spanned.getSpans(0, length, ImageSpan.class);
+ if (imageSpans != null) {
+ for (int i = 0; i < imageSpans.length; i++) {
+ ImageSpan span = imageSpans[i];
+ replaceSpan(builder, span, new ImageSpan(span.getDrawable(),
+ ImageSpan.ALIGN_BASELINE));
+ }
+ }
+ }
+
+ /**
+ * Replaces one span with the other.
+ */
+ private static void replaceSpan(SpannableStringBuilder builder, Object originalSpan,
+ Object newSpan) {
+ builder.setSpan(newSpan,
+ builder.getSpanStart(originalSpan),
+ builder.getSpanEnd(originalSpan),
+ builder.getSpanFlags(originalSpan));
+ builder.removeSpan(originalSpan);
+ }
+
+ public static class StreamItemQuoteSpan extends QuoteSpan {
+ private final int mWidth;
+
+ public StreamItemQuoteSpan(int color, int width) {
+ super(color);
+ this.mWidth = width;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getLeadingMargin(boolean first) {
+ return mWidth;
+ }
+ }
+}