blob: 40c29b993f9ea9cdc74640b7c8374ea02b9f1417 [file] [log] [blame]
/*
* Copyright (C) 2010 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.contacts.socialwidget;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.net.Uri;
import android.provider.ContactsContract.StreamItems;
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;
import android.widget.RemoteViews;
import com.android.contacts.R;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.Contact;
import com.android.contacts.model.ContactLoader;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.quickcontact.QuickContactBroadcastReceiver;
import com.android.contacts.util.ContactBadgeUtil;
import com.android.contacts.util.HtmlUtils;
import com.android.contacts.util.StreamItemEntry;
import java.util.List;
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
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
Log.d(TAG, "onUpdate called for " + appWidgetId);
}
for (int appWidgetId : appWidgetIds) {
loadWidgetData(context, appWidgetManager, appWidgetId, false);
}
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
ContactLoader loader = sLoaders.get(appWidgetId);
if (loader != null) {
Log.d(TAG, "Stopping loader for widget with id=" + appWidgetId);
loader.reset();
sLoaders.delete(appWidgetId);
}
}
SocialWidgetSettings.getInstance().remove(context, appWidgetIds);
}
public static void loadWidgetData(final Context context,
final AppWidgetManager appWidgetManager, final int widgetId, boolean forceLoad) {
ContactLoader previousLoader = sLoaders.get(widgetId);
if (previousLoader != null && !forceLoad) {
previousLoader.startLoading();
return;
}
if (previousLoader != null) {
previousLoader.reset();
}
// Show that we are loading
final RemoteViews loadingViews =
new RemoteViews(context.getPackageName(), R.layout.social_widget);
loadingViews.setTextViewText(R.id.name,
context.getString(R.string.social_widget_loading));
loadingViews.setViewVisibility(R.id.name, View.VISIBLE);
loadingViews.setViewVisibility(R.id.name_and_snippet, View.GONE);
appWidgetManager.updateAppWidget(widgetId, loadingViews);
// Load
final Uri contactUri =
SocialWidgetSettings.getInstance().getContactUri(context, widgetId);
if (contactUri == null) {
// Not yet set-up (this can happen while the Configuration activity is visible)
return;
}
final ContactLoader contactLoader = new ContactLoader(context, contactUri, false, true,
false, true, false);
contactLoader.registerListener(0,
new ContactLoader.OnLoadCompleteListener<Contact>() {
@Override
public void onLoadComplete(Loader<Contact> loader,
Contact contactData) {
bindRemoteViews(context, widgetId, appWidgetManager, contactData);
}
});
contactLoader.startLoading();
sLoaders.append(widgetId, contactLoader);
}
private static void bindRemoteViews(final Context context, final int widgetId,
final AppWidgetManager widgetManager, Contact contactData) {
Log.d(TAG, "Loaded " + contactData.getLookupKey()
+ " for widget with id=" + widgetId);
final RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.social_widget);
if (!contactData.isLoaded()) {
setDisplayNameAndSnippet(context, views,
context.getString(R.string.invalidContactMessage), null, null, null);
setPhoto(views, ContactBadgeUtil.loadDefaultAvatarPhoto(context, false, false));
} else {
byte[] photo = contactData.getPhotoBinaryData();
setPhoto(views, photo != null
? BitmapFactory.decodeByteArray(photo, 0, photo.length)
: ContactBadgeUtil.loadDefaultAvatarPhoto(context, false, false));
// TODO: Rotate between all the stream items?
final Intent intent = new Intent(context, QuickContactBroadcastReceiver.class);
intent.setData(contactData.getLookupUri());
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.border, pendingIntent);
setDisplayNameAndSnippet(context, views, contactData.getDisplayName(),
contactData.getPhoneticName(), contactData.getStreamItems(), 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,
List<StreamItemEntry> streamItems, PendingIntent defaultIntent) {
SpannableStringBuilder sb = new SpannableStringBuilder();
CharSequence name = displayName;
// If there is no display name, use the default missing name string
if (TextUtils.isEmpty(name)) {
name = context.getString(R.string.missing_name);
}
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 (streamItems == null || streamItems.isEmpty()) {
views.setTextViewText(R.id.name, sb);
views.setViewVisibility(R.id.name, View.VISIBLE);
views.setViewVisibility(R.id.name_and_snippet, View.GONE);
// Don't set a pending intent if the intent is null, otherwise the system will try
// to write the null intent to a Parcel.
if (defaultIntent != null) {
views.setOnClickPendingIntent(R.id.widget_container, defaultIntent);
}
} else {
// TODO: Rotate between all the stream items?
StreamItemEntry streamItem = streamItems.get(0);
CharSequence status = HtmlUtils.fromHtml(context, streamItem.getText());
if (status == null) {
status = "";
}
if (status.length() <= SHORT_SNIPPET_LENGTH) {
sb.append("\n");
} else {
sb.append(" ");
}
sb.append(status);
views.setTextViewText(R.id.name_and_snippet, sb);
views.setViewVisibility(R.id.name, View.GONE);
views.setViewVisibility(R.id.name_and_snippet, View.VISIBLE);
final AccountTypeManager manager = AccountTypeManager.getInstance(context);
final AccountType accountType =
manager.getAccountType(streamItem.getAccountType(), streamItem.getDataSet());
if (accountType.getViewStreamItemActivity() != null) {
final Uri uri = ContentUris.withAppendedId(StreamItems.CONTENT_URI,
streamItem.getId());
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setClassName(accountType.syncAdapterPackageName,
accountType.getViewStreamItemActivity());
views.setOnClickPendingIntent(R.id.name_and_snippet_container,
PendingIntent.getActivity(context, 0, intent, 0));
}
}
}
}