New layout of the contact widget
Change-Id: Id440fb606fd5ddc6167af2b1491426080980a9ff
diff --git a/res/drawable-hdpi/statusbox_attribute_holo.9.png b/res/drawable-hdpi/statusbox_attribute_holo.9.png
new file mode 100644
index 0000000..13ffd7a
--- /dev/null
+++ b/res/drawable-hdpi/statusbox_attribute_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/statusbox_attribute_holo.9.png b/res/drawable-mdpi/statusbox_attribute_holo.9.png
new file mode 100644
index 0000000..b124392
--- /dev/null
+++ b/res/drawable-mdpi/statusbox_attribute_holo.9.png
Binary files differ
diff --git a/res/layout/social_widget.xml b/res/layout/social_widget.xml
index 54ece47..5adccf1 100644
--- a/res/layout/social_widget.xml
+++ b/res/layout/social_widget.xml
@@ -41,7 +41,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
- <FrameLayout
+ <RelativeLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -51,44 +51,38 @@
android:layout_marginBottom="6dip"
android:layout_marginLeft="0dip"
android:paddingLeft="47dip"
- android:paddingRight="8dip">
+ android:paddingRight="8dip"
+ android:paddingTop="3dip"
+ android:paddingBottom="6dip">
- <LinearLayout
+ <TextView
+ android:id="@+id/name_and_snippet"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:maxLines="3"
+ android:lineSpacingExtra="2sp"
+ android:textColor="#FFFFFFFF"
+ android:textSize="@dimen/widget_text_size_snippet" />
+
+ <TextView
+ android:id="@+id/name"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:textColor="#FFFFFFFF"
+ android:textSize="@dimen/widget_text_size_name" />
+
+ <TextView
+ android:id="@+id/status_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="left|center_vertical"
- android:orientation="vertical"
- android:paddingTop="2dip"
- android:paddingBottom="2dip"
- android:paddingRight="4dip">
-
- <TextView
- android:id="@+id/name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="end"
- android:textSize="14sp"
- android:textStyle="bold"
- android:textColor="#FFFFFFFF" />
-
- <TextView
- android:id="@+id/status"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="13sp"
- android:textColor="#FFFFFFFF"
- android:maxLines="1"
- android:ellipsize="end"
- android:visibility="gone" />
-
- <TextView
- android:id="@+id/status_date"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="13sp"
- android:textColor="#FF444444"
- android:visibility="gone" />
- </LinearLayout>
- </FrameLayout>
+ android:layout_alignParentRight="true"
+ android:layout_alignParentBottom="true"
+ android:background="@drawable/statusbox_attribute_holo"
+ android:textSize="13sp"
+ android:textColor="#FF444444"
+ android:visibility="gone" />
+ </RelativeLayout>
</LinearLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 00f5134..fdf2b4a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -48,4 +48,10 @@
<!-- Padding to be used between a visible scrollbar and the contact list -->
<dimen name="list_visible_scrollbar_padding">56dip</dimen>
+
+ <!-- Font size used for the contact name in the widget -->
+ <dimen name="widget_text_size_name">14sp</dimen>
+
+ <!-- Font size used for the social status in the widget -->
+ <dimen name="widget_text_size_snippet">13sp</dimen>
</resources>
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetConfigureActivity.java b/src/com/android/contacts/socialwidget/SocialWidgetConfigureActivity.java
index 0d63036..7bfca98 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetConfigureActivity.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetConfigureActivity.java
@@ -49,7 +49,8 @@
SocialWidgetSettings.getInstance().setContactUri(context, widgetId, data.getData());
// Update the widget
- SocialWidgetProvider.loadWidgetData(context, widgetId);
+ SocialWidgetProvider.loadWidgetData(
+ context, AppWidgetManager.getInstance(this), widgetId);
// Return OK so that the system won't remove the widget
final Intent resultValue = new Intent();
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index d5cf861..0c132b7 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -28,9 +28,13 @@
import android.content.Loader;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Typeface;
import android.net.Uri;
import android.provider.ContactsContract.QuickContact;
+import android.text.SpannableStringBuilder;
import android.text.TextUtils;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.StyleSpan;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
@@ -38,6 +42,13 @@
public class SocialWidgetProvider extends AppWidgetProvider {
private static final String TAG = "SocialWidgetProvider";
+
+ /**
+ * Max length of a snippet that is considered "short" and displayed in
+ * a separate line.
+ */
+ private static final int SHORT_SNIPPET_LENGTH = 48;
+
private static SparseArray<ContactLoader> sLoaders = new SparseArray<ContactLoader>();
@Override
@@ -47,7 +58,7 @@
}
for (int appWidgetId : appWidgetIds) {
- loadWidgetData(context, appWidgetId);
+ loadWidgetData(context, appWidgetManager, appWidgetId);
}
}
@@ -64,19 +75,21 @@
SocialWidgetSettings.getInstance().remove(context, appWidgetIds);
}
- public static void loadWidgetData(final Context context, final int widgetId) {
+ public static void loadWidgetData(
+ final Context context, final AppWidgetManager appWidgetManager, final int widgetId) {
final ContactLoader previousLoader = sLoaders.get(widgetId);
if (previousLoader != null) {
previousLoader.startLoading();
} else {
// Show that we are loading
- final AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
final RemoteViews loadingViews =
new RemoteViews(context.getPackageName(), R.layout.social_widget);
loadingViews.setTextViewText(R.id.name,
context.getString(R.string.social_widget_loading));
- widgetManager.updateAppWidget(widgetId, loadingViews);
+ loadingViews.setViewVisibility(R.id.name, View.VISIBLE);
+ loadingViews.setViewVisibility(R.id.name_and_snippet, View.GONE);
+ appWidgetManager.updateAppWidget(widgetId, loadingViews);
// Load
final Uri contactUri =
@@ -91,89 +104,106 @@
@Override
public void onLoadComplete(Loader<ContactLoader.Result> loader,
ContactLoader.Result contactData) {
- if (contactData == ContactLoader.Result.ERROR ||
- contactData == ContactLoader.Result.NOT_FOUND) {
- return;
- }
- Log.d(TAG, "Loaded " + contactData.getLookupKey()
- + " for widget with id=" + widgetId);
- final RemoteViews views = new RemoteViews(context.getPackageName(),
- R.layout.social_widget);
-
- setDisplayName(views, contactData.getDisplayName(),
- contactData.getPhoneticName());
-
- byte[] photo = contactData.getPhotoBinaryData();
- setPhoto(views, photo != null
- ? BitmapFactory.decodeByteArray(photo, 0, photo.length)
- : ContactBadgeUtil.loadPlaceholderPhoto(context));
- setSocialSnippet(views, contactData.getSocialSnippet());
- setStatusAttribution(views, ContactBadgeUtil.getSocialDate(
- contactData, context));
-
- // OnClick launch QuickContact
- final Intent intent = new Intent(QuickContact.ACTION_QUICK_CONTACT);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_TOP
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-
- intent.setData(contactData.getLookupUri());
- intent.putExtra(QuickContact.EXTRA_MODE, QuickContact.MODE_SMALL);
-
- final PendingIntent pendingIntent = PendingIntent.getActivity(context,
- 0, intent, 0);
- views.setOnClickPendingIntent(R.id.border, pendingIntent);
-
- // Configure Ui
- widgetManager.updateAppWidget(widgetId, views);
- }
-
- private void setPhoto(RemoteViews views, Bitmap photo) {
- views.setImageViewBitmap(R.id.image, photo);
- }
-
- /**
- * Set the display name and phonetic name to show in the header.
- */
- private void setDisplayName(RemoteViews views, CharSequence displayName,
- CharSequence phoneticName) {
- if (TextUtils.isEmpty(phoneticName)) {
- views.setTextViewText(R.id.name, displayName);
- } else {
- final String combinedName =
- context.getString(R.string.widget_name_and_phonetic,
- displayName, phoneticName);
- views.setTextViewText(R.id.name, combinedName);
- }
- }
-
- /**
- * Set the social snippet text to display in the header.
- */
- private void setSocialSnippet(RemoteViews views, CharSequence snippet) {
- if (TextUtils.isEmpty(snippet)) {
- views.setViewVisibility(R.id.status, View.GONE);
- } else {
- views.setTextViewText(R.id.status, snippet);
- views.setViewVisibility(R.id.status, View.VISIBLE);
- }
- }
-
- /**
- * Set the status attribution text to display in the header.
- */
- private void setStatusAttribution(RemoteViews views,
- CharSequence attribution) {
- if (attribution == null) {
- views.setViewVisibility(R.id.status_date, View.GONE);
- } else {
- views.setTextViewText(R.id.status_date, attribution);
- views.setViewVisibility(R.id.status_date, View.VISIBLE);
- }
+ bindRemoteViews(context, widgetId, appWidgetManager, contactData);
}
});
contactLoader.startLoading();
sLoaders.append(widgetId, contactLoader);
}
}
+
+ private static void bindRemoteViews(final Context context, final int widgetId,
+ final AppWidgetManager widgetManager, ContactLoader.Result contactData) {
+ if (contactData == ContactLoader.Result.ERROR ||
+ contactData == ContactLoader.Result.NOT_FOUND) {
+ return;
+ }
+
+ Log.d(TAG, "Loaded " + contactData.getLookupKey()
+ + " for widget with id=" + widgetId);
+ final RemoteViews views = new RemoteViews(context.getPackageName(),
+ R.layout.social_widget);
+
+ setDisplayNameAndSnippet(context, views, contactData.getDisplayName(),
+ contactData.getPhoneticName(), contactData.getSocialSnippet());
+
+ byte[] photo = contactData.getPhotoBinaryData();
+ setPhoto(views, photo != null
+ ? BitmapFactory.decodeByteArray(photo, 0, photo.length)
+ : ContactBadgeUtil.loadPlaceholderPhoto(context));
+ setStatusAttribution(views, ContactBadgeUtil.getSocialDate(
+ contactData, context));
+
+ // OnClick launch QuickContact
+ final Intent intent = new Intent(QuickContact.ACTION_QUICK_CONTACT);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+
+ intent.setData(contactData.getLookupUri());
+ intent.putExtra(QuickContact.EXTRA_MODE, QuickContact.MODE_SMALL);
+
+ final PendingIntent pendingIntent = PendingIntent.getActivity(context,
+ 0, intent, 0);
+ views.setOnClickPendingIntent(R.id.border, pendingIntent);
+
+ // Configure UI
+ widgetManager.updateAppWidget(widgetId, views);
+ }
+
+
+ private static void setPhoto(RemoteViews views, Bitmap photo) {
+ views.setImageViewBitmap(R.id.image, photo);
+ }
+
+ /**
+ * Set the display name, phonetic name and the social snippet.
+ */
+ private static void setDisplayNameAndSnippet(Context context, RemoteViews views,
+ CharSequence displayName, CharSequence phoneticName,
+ CharSequence snippet) {
+ SpannableStringBuilder sb = new SpannableStringBuilder();
+
+ CharSequence name = displayName;
+ if (!TextUtils.isEmpty(phoneticName)) {
+ name = context.getString(R.string.widget_name_and_phonetic,
+ name, phoneticName);
+ }
+ sb.append(name);
+
+ AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(
+ context.getResources().getDimensionPixelSize(R.dimen.widget_text_size_name));
+ StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);
+ sb.setSpan(sizeSpan, 0, name.length(), 0);
+ sb.setSpan(styleSpan, 0, name.length(), 0);
+
+ if (TextUtils.isEmpty(snippet)) {
+ views.setTextViewText(R.id.name, sb);
+ views.setViewVisibility(R.id.name, View.VISIBLE);
+ views.setViewVisibility(R.id.name_and_snippet, View.GONE);
+ } else {
+ if (snippet.length() <= SHORT_SNIPPET_LENGTH) {
+ sb.append("\n");
+ } else {
+ sb.append(" ");
+ }
+ sb.append(snippet);
+ views.setTextViewText(R.id.name_and_snippet, sb);
+ views.setViewVisibility(R.id.name, View.GONE);
+ views.setViewVisibility(R.id.name_and_snippet, View.VISIBLE);
+ }
+ }
+
+ /**
+ * Set the status attribution text to display in the header.
+ */
+ private static void setStatusAttribution(RemoteViews views,
+ CharSequence attribution) {
+ if (attribution == null) {
+ views.setViewVisibility(R.id.status_date, View.GONE);
+ } else {
+ views.setTextViewText(R.id.status_date, attribution);
+ views.setViewVisibility(R.id.status_date, View.VISIBLE);
+ }
+ }
}