Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3a4d867 authored by Paul Sliwowski's avatar Paul Sliwowski
Browse files

Remove social widget.

Bug: 10328519
Change-Id: I075db4ca4dcbcf170b71c253d7232c3d3d7d17f4
parent 45f23d4d
Loading
Loading
Loading
Loading
+0 −18
Original line number Diff line number Diff line
@@ -453,24 +453,6 @@
            </intent-filter>
        </activity>

        <!-- The widget that shows details and the social stream of a contact -->
        <receiver android:name=".socialwidget.SocialWidgetProvider"
            android:label="@string/social_widget_label" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                    android:resource="@xml/social_widget_info" />
        </receiver>

        <activity
            android:name=".socialwidget.SocialWidgetConfigureActivity"
            android:theme="@android:style/Theme.Translucent.NoTitleBar" >
            <intent-filter>
                <action android:name="android.intent.action.APPWIDGET_PICK" />
            </intent-filter>
        </activity>

        <!-- Intercept Dialer Intents for devices without a phone.
             This activity should have the same intent filters as the DialtactsActivity,
             so that its capturing the same events. Omit android.intent.category.LAUNCHER, because

res/xml/social_widget_info.xml

deleted100644 → 0
+0 −26
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->

 <!-- It is enough to update once per day, as the widget watches the database for changes -->
 
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="260dip"
    android:minHeight="40dip"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/social_widget"
    android:previewImage="@drawable/contacts_widget_preview"
    android:configure="com.android.contacts.socialwidget.SocialWidgetConfigureActivity" >
</appwidget-provider>
+0 −78
Original line number Diff line number Diff line
/*
 * 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.Activity;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.os.Bundle;
import android.provider.ContactsContract.Contacts;

public class SocialWidgetConfigureActivity extends Activity {
    private static final String KEY_LAUNCHED = "already_launched_picker_activity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // If the user presses back, we want to cancel
        setResult(RESULT_CANCELED);

        // Don't launch contact-picker if we already launched it (for example, if
        // we launched it in a previous onCreate() and the device orientation changes
        // before the picker returns its result, then this activity will be recreated).
        if (savedInstanceState != null && savedInstanceState.getBoolean(KEY_LAUNCHED)) return;

        // Forward the Intent to the picker
        final Intent pickerIntent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
        pickerIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivityForResult(pickerIntent, 0);
    }

    @Override
    protected void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);

        // We know for sure that we've launched the contact-picker... see onCreate()
        savedInstanceState.putBoolean(KEY_LAUNCHED, true);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // We came back from the Picker. If the user actually selected a contact,
        // return it now
        if (resultCode == Activity.RESULT_OK) {
            final Bundle extras = getIntent().getExtras();
            if (extras == null) throw new IllegalStateException("Intent extras are null");
            final int widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
                    AppWidgetManager.INVALID_APPWIDGET_ID);

            // Save the setting
            final SocialWidgetConfigureActivity context = SocialWidgetConfigureActivity.this;
            SocialWidgetSettings.getInstance().setContactUri(context, widgetId, data.getData());

            // Update the widget
            SocialWidgetProvider.loadWidgetData(
                    context, AppWidgetManager.getInstance(this), widgetId, true);

            // Return OK so that the system won't remove the widget
            final Intent resultValue = new Intent();
            resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
            setResult(RESULT_OK, resultValue);
        }
        finish();
    }
}
+0 −232
Original line number Diff line number Diff line
/*
 * 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,
                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));
            }
        }
    }
}
+0 −115
Original line number Diff line number Diff line
/*
 * 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.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.util.Log;

public class SocialWidgetSettings {
    private static final String TAG = "SocialWidgetSettings";

    // To migrate from earlier versions...
    private static final String LEGACY_PREFS_NAME = "WidgetSettings";

    // Prefix to use for all preferences used by this class.
    private static final String PREFERENCES_PREFIX = "SocialWidgetSettings_";

    private static final String CONTACT_URI_PREFIX = "CONTACT_URI_";

    private static final String KEY_MIGRATED = PREFERENCES_PREFIX + "settings_migrated";

    private static final SocialWidgetSettings sInstance = new SocialWidgetSettings();

    public static SocialWidgetSettings getInstance() {
        return sInstance;
    }

    private final String getPreferenceKey(int widgetId) {
        return PREFERENCES_PREFIX + CONTACT_URI_PREFIX + Integer.toString(widgetId);
    }

    public void remove(Context context, int[] widgetIds) {
        final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
        final Editor editor = settings.edit();
        for (int widgetId : widgetIds) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "remove(" + widgetId + ")");
            }
            editor.remove(getPreferenceKey(widgetId));
        }
        editor.apply();
    }

    public Uri getContactUri(Context context, int widgetId) {
        final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);

        ensureMigrated(context, settings);

        final String resultString = settings.getString(getPreferenceKey(widgetId), null);
        final Uri result = resultString == null ? null : Uri.parse(resultString);
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "getContactUri(" + widgetId + ") --> " + result);
        }
        return result;
    }

    public void setContactUri(Context context, int widgetId, Uri contactLookupUri) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "setContactUri(" + widgetId + ", " + contactLookupUri + ")");
        }
        final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
        final Editor editor = settings.edit();
        if (contactLookupUri == null) {
            editor.remove(getPreferenceKey(widgetId));
        } else {
            editor.putString(getPreferenceKey(widgetId), contactLookupUri.toString());
        }
        editor.apply();
    }

    private void ensureMigrated(Context context, SharedPreferences settings) {
        if (settings.getBoolean(KEY_MIGRATED, false)) {
            return; // Migrated already
        }

        Log.i(TAG, "Migrating widget settings...");

        // Old preferences only had the "CONTACT_URI_" prefix.
        // New preferences have the "SocialWidgetSettings_CONTACT_URI_" prefix.
        // So just copy all the entries with adding "SocialWidgetSettings_" to their key names.

        final SharedPreferences.Editor editor = settings.edit();

        final SharedPreferences legacySettings =
            context.getSharedPreferences(LEGACY_PREFS_NAME, Context.MODE_PRIVATE);
        for (String key : legacySettings.getAll().keySet()) {
            final String value = legacySettings.getString(key, null);
            if (value == null) continue; // Just in case.

            Log.i(TAG, "Found: " + key + ": " + value);

            editor.putString(PREFERENCES_PREFIX + key, value);
        }

        editor.apply();
        settings.edit().putBoolean(KEY_MIGRATED, true).apply();
    }
}