179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan/*
279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * Copyright (C) 2011 The Android Open Source Project
379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan *
479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * Licensed under the Apache License, Version 2.0 (the "License");
579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * you may not use this file except in compliance with the License.
679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * You may obtain a copy of the License at
779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan *
879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan *      http://www.apache.org/licenses/LICENSE-2.0
979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan *
1079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * Unless required by applicable law or agreed to in writing, software
1179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * distributed under the License is distributed on an "AS IS" BASIS,
1279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * See the License for the specific language governing permissions and
1479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * limitations under the License.
1579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan */
1679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
1779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanpackage com.android.contacts.detail;
1879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
1979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport com.android.contacts.ContactLoader;
2079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport com.android.contacts.ContactLoader.Result;
213915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoroimport com.android.contacts.ContactPhotoManager;
2279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport com.android.contacts.R;
2379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport com.android.contacts.preference.ContactsPreferences;
2479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport com.android.contacts.util.ContactBadgeUtil;
251b4572ba0ba449a4ed0cc896f5f694f33b43f073Dmitri Plotnikovimport com.android.contacts.util.HtmlUtils;
263915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoroimport com.android.contacts.util.StreamItemEntry;
273915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoroimport com.android.contacts.util.StreamItemPhotoEntry;
285a77a5563706fe1b143d976d1b47abaeb873e138Flavio Lerdaimport com.google.common.annotations.VisibleForTesting;
2979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
30f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onukiimport android.content.ContentUris;
3179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.content.ContentValues;
3279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.content.Context;
3379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.content.Entity;
3479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.content.Entity.NamedContentValues;
3565ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerdaimport android.content.pm.PackageManager;
3665ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerdaimport android.content.pm.PackageManager.NameNotFoundException;
3765ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerdaimport android.content.res.Resources;
3865ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerdaimport android.content.res.Resources.NotFoundException;
3979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.graphics.Bitmap;
4079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.graphics.BitmapFactory;
4165ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerdaimport android.graphics.drawable.Drawable;
423915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoroimport android.net.Uri;
4379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.provider.ContactsContract;
4479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Organization;
4579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.provider.ContactsContract.Data;
4679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.provider.ContactsContract.DisplayNameSources;
47f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onukiimport android.provider.ContactsContract.StreamItems;
483915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoroimport android.text.Html;
4965ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerdaimport android.text.Html.ImageGetter;
5079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.text.TextUtils;
5165ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerdaimport android.util.Log;
523915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoroimport android.view.LayoutInflater;
5379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.view.View;
543915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoroimport android.view.ViewGroup;
5579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.view.animation.AccelerateInterpolator;
5679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.view.animation.AlphaAnimation;
5779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.widget.CheckBox;
5879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.widget.ImageView;
593915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoroimport android.widget.LinearLayout;
606c0470e21d8506fb53915df7463634fd47288343Katherine Kuanimport android.widget.ListView;
6179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanimport android.widget.TextView;
6279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
633915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoroimport java.util.List;
643915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro
6579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan/**
6679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * This class contains utility methods to bind high-level contact details
6779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * (meaning name, phonetic name, job, and attribution) from a
6879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan * {@link ContactLoader.Result} data object to appropriate {@link View}s.
6979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan */
7079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuanpublic class ContactDetailDisplayUtils {
7165ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda    private static final String TAG = "ContactDetailDisplayUtils";
7265ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
7379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    private static final int PHOTO_FADE_IN_ANIMATION_DURATION_MILLIS = 100;
7479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
75f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki    /**
76f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki     * Tag object used for stream item photos.
77f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki     */
78f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki    public static class StreamPhotoTag {
79f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki        public final StreamItemEntry streamItem;
80f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki        public final StreamItemPhotoEntry streamItemPhoto;
81f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki
82f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki        public StreamPhotoTag(StreamItemEntry streamItem, StreamItemPhotoEntry streamItemPhoto) {
83f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            this.streamItem = streamItem;
84f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            this.streamItemPhoto = streamItemPhoto;
85f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki        }
86f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki
87f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki        public Uri getStreamItemPhotoUri() {
88f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            final Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
89f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            ContentUris.appendId(builder, streamItem.getId());
90f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            builder.appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
91f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            ContentUris.appendId(builder, streamItemPhoto.getId());
92f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            return builder.build();
93f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki        }
94f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki    }
95f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki
9679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    private ContactDetailDisplayUtils() {
9779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        // Disallow explicit creation of this class.
9879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
9979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
10079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    /**
101599700fb0182a17435cc86137b5f8bd39b8581e2Makoto Onuki     * Returns the display name of the contact, using the current display order setting.
102599700fb0182a17435cc86137b5f8bd39b8581e2Makoto Onuki     * Returns res/string/missing_name if there is no display name.
10379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     */
10479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    public static CharSequence getDisplayName(Context context, Result contactData) {
10579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        CharSequence displayName = contactData.getDisplayName();
10679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        CharSequence altDisplayName = contactData.getAltDisplayName();
10779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        ContactsPreferences prefs = new ContactsPreferences(context);
10879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        CharSequence styledName = "";
10979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        if (!TextUtils.isEmpty(displayName) && !TextUtils.isEmpty(altDisplayName)) {
11079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            if (prefs.getDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
111599700fb0182a17435cc86137b5f8bd39b8581e2Makoto Onuki                styledName = displayName;
11279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            } else {
113599700fb0182a17435cc86137b5f8bd39b8581e2Makoto Onuki                styledName = altDisplayName;
11479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            }
11581281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        } else {
11681281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan            styledName = context.getResources().getString(R.string.missing_name);
11779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        }
11879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        return styledName;
11979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
12079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
12179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    /**
12279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * Returns the phonetic name of the contact or null if there isn't one.
12379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     */
12479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    public static String getPhoneticName(Context context, Result contactData) {
12579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        String phoneticName = contactData.getPhoneticName();
12679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        if (!TextUtils.isEmpty(phoneticName)) {
12779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            return phoneticName;
12879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        }
12979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        return null;
13079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
13179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
13279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    /**
133afd283a8a65e0cfd62204c948fa2bce3004db657Katherine Kuan     * Returns the attribution string for the contact, which may specify the contact directory that
134afd283a8a65e0cfd62204c948fa2bce3004db657Katherine Kuan     * the contact came from. Returns null if there is none applicable.
13579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     */
13679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    public static String getAttribution(Context context, Result contactData) {
137afd283a8a65e0cfd62204c948fa2bce3004db657Katherine Kuan        if (contactData.isDirectoryEntry()) {
13879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            String directoryDisplayName = contactData.getDirectoryDisplayName();
13979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            String directoryType = contactData.getDirectoryType();
14079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            String displayName = !TextUtils.isEmpty(directoryDisplayName)
14179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    ? directoryDisplayName
14279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    : directoryType;
14379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            return context.getString(R.string.contact_directory_description, displayName);
14479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        }
14579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        return null;
14679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
14779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
14879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    /**
14979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * Returns the organization of the contact. If several organizations are given,
15079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * the first one is used. Returns null if not applicable.
15179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     */
15279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    public static String getCompany(Context context, Result contactData) {
15379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        final boolean displayNameIsOrganization = contactData.getDisplayNameSource()
15479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                == DisplayNameSources.ORGANIZATION;
15579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        for (Entity entity : contactData.getEntities()) {
15679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            for (NamedContentValues subValue : entity.getSubValues()) {
15779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                final ContentValues entryValues = subValue.values;
15879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                final String mimeType = entryValues.getAsString(Data.MIMETYPE);
15979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
16079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
16179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    final String company = entryValues.getAsString(Organization.COMPANY);
16279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    final String title = entryValues.getAsString(Organization.TITLE);
16379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    final String combined;
16479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    // We need to show company and title in a combined string. However, if the
16579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    // DisplayName is already the organization, it mirrors company or (if company
16679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    // is empty title). Make sure we don't show what's already shown as DisplayName
16779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    if (TextUtils.isEmpty(company)) {
16879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                        combined = displayNameIsOrganization ? null : title;
16979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    } else {
17079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                        if (TextUtils.isEmpty(title)) {
17179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                            combined = displayNameIsOrganization ? null : company;
17279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                        } else {
17379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                            if (displayNameIsOrganization) {
17479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                                combined = title;
17579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                            } else {
17679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                                combined = context.getString(
17779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                                        R.string.organization_company_and_title,
17879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                                        company, title);
17979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                            }
18079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                        }
18179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    }
18279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
18379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    if (!TextUtils.isEmpty(combined)) {
18479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                        return combined;
18579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                    }
18679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan                }
18779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            }
18879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        }
18979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        return null;
19079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
19179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
19279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    /**
19379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * Sets the contact photo to display in the given {@link ImageView}. If bitmap is null, the
19479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * default placeholder image is shown.
19579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     */
19679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    public static void setPhoto(Context context, Result contactData, ImageView photoView) {
19779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        if (contactData.isLoadingPhoto()) {
19879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            photoView.setImageBitmap(null);
19979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            return;
20079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        }
20179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        byte[] photo = contactData.getPhotoBinaryData();
20279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        Bitmap bitmap = photo != null ? BitmapFactory.decodeByteArray(photo, 0, photo.length)
203ecfc26c3f9495f1a4efed69a1582ff2b0deb2c71Daniel Lehmann                : ContactBadgeUtil.loadDefaultAvatarPhoto(context, true, false);
20479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        boolean fadeIn = contactData.isDirectoryEntry();
20579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        if (photoView.getDrawable() == null && fadeIn) {
20679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            AlphaAnimation animation = new AlphaAnimation(0, 1);
20779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            animation.setDuration(PHOTO_FADE_IN_ANIMATION_DURATION_MILLIS);
20879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            animation.setInterpolator(new AccelerateInterpolator());
20979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            photoView.startAnimation(animation);
21079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        }
21179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        photoView.setImageBitmap(bitmap);
21279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
21379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
21479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    /**
21579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * Sets the starred state of this contact.
21679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     */
21779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    public static void setStarred(Result contactData, CheckBox starredView) {
21879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        // Check if the starred state should be visible
219ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        if (!contactData.isDirectoryEntry() && !contactData.isUserProfile()) {
22079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            starredView.setVisibility(View.VISIBLE);
22179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            starredView.setChecked(contactData.getStarred());
22279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        } else {
22379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            starredView.setVisibility(View.GONE);
22479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        }
22579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
22679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
22779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    /**
228d814e42a6ac71962a6eeb9ce37b4abc2c1205952Katherine Kuan     * Set the social snippet text. If there isn't one, then set the view to gone.
229d814e42a6ac71962a6eeb9ce37b4abc2c1205952Katherine Kuan     */
2303915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro    public static void setSocialSnippet(Context context, Result contactData, TextView statusView,
2313915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro            ImageView statusPhotoView) {
232d814e42a6ac71962a6eeb9ce37b4abc2c1205952Katherine Kuan        if (statusView == null) {
233d814e42a6ac71962a6eeb9ce37b4abc2c1205952Katherine Kuan            return;
234d814e42a6ac71962a6eeb9ce37b4abc2c1205952Katherine Kuan        }
2353915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro
2367c03fd16d9c6138118b6d236694f650289f27326Makoto Onuki        CharSequence snippet = null;
2373915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro        String photoUri = null;
2383915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro        if (!contactData.getStreamItems().isEmpty()) {
2393915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro            StreamItemEntry firstEntry = contactData.getStreamItems().get(0);
2401b4572ba0ba449a4ed0cc896f5f694f33b43f073Dmitri Plotnikov            snippet = HtmlUtils.fromHtml(context, firstEntry.getText());
2413915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro            if (!firstEntry.getPhotos().isEmpty()) {
2423915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro                StreamItemPhotoEntry firstPhoto = firstEntry.getPhotos().get(0);
2433915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro                photoUri = firstPhoto.getPhotoUri();
2443915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro
2453915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro                // If displaying an image, hide the snippet text.
2463915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro                snippet = null;
2473915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro            }
2483915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro        }
2493915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro        setDataOrHideIfNone(snippet, statusView);
2503915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro        if (photoUri != null) {
2513915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro            ContactPhotoManager.getInstance(context).loadPhoto(
2523d3a15c465b0c4105148458307a7b50e9b267fd0Makoto Onuki                    statusPhotoView, Uri.parse(photoUri), true, false,
2533d3a15c465b0c4105148458307a7b50e9b267fd0Makoto Onuki                    ContactPhotoManager.DEFAULT_BLANK);
2543915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro            statusPhotoView.setVisibility(View.VISIBLE);
2553915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro        } else {
2563915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro            statusPhotoView.setVisibility(View.GONE);
2573915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro        }
258d814e42a6ac71962a6eeb9ce37b4abc2c1205952Katherine Kuan    }
259d814e42a6ac71962a6eeb9ce37b4abc2c1205952Katherine Kuan
260a21993720988a5fc0b48594d1ff0ce6f932780b7Flavio Lerda    /** Creates the view that represents a stream item. */
261a21993720988a5fc0b48594d1ff0ce6f932780b7Flavio Lerda    public static View createStreamItemView(LayoutInflater inflater, Context context,
262f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            StreamItemEntry streamItem, LinearLayout parent,
263f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            View.OnClickListener photoClickListener) {
264fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda        View container = inflater.inflate(R.layout.stream_item_container, parent, false);
265fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda        ViewGroup contentTable = (ViewGroup) container.findViewById(R.id.stream_item_content);
2663915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro
267fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda        ContactPhotoManager contactPhotoManager = ContactPhotoManager.getInstance(context);
2683915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro        List<StreamItemPhotoEntry> photos = streamItem.getPhotos();
269fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda        final int photoCount = photos.size();
270fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda
271be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan        // This stream item only has text.
272be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan        if (photoCount == 0) {
273be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan            View textOnlyContainer = inflater.inflate(R.layout.stream_item_row_text, contentTable,
274be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    false);
275be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan            addStreamItemText(context, streamItem, textOnlyContainer);
276be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan            contentTable.addView(textOnlyContainer);
277be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan        } else {
278be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan            // This stream item has text and photos. Process the photos, two at a time.
279be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan            for (int index = 0; index < photoCount; index += 2) {
280be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                final StreamItemPhotoEntry firstPhoto = photos.get(index);
281be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                if (index + 1 < photoCount) {
282be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    // Put in two photos, side by side.
283be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    final StreamItemPhotoEntry secondPhoto = photos.get(index + 1);
284be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    View photoContainer = inflater.inflate(R.layout.stream_item_row_two_images,
285be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                            contentTable, false);
286be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    loadPhoto(contactPhotoManager, streamItem, firstPhoto, photoContainer,
287be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                            R.id.stream_item_first_image, photoClickListener);
288be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    loadPhoto(contactPhotoManager, streamItem, secondPhoto, photoContainer,
289be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                            R.id.stream_item_second_image, photoClickListener);
290be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    contentTable.addView(photoContainer);
291be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                } else {
292be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    // Put in a single photo
293be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    View photoContainer = inflater.inflate(
294be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                            R.layout.stream_item_row_one_image, contentTable, false);
295be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    loadPhoto(contactPhotoManager, streamItem, firstPhoto, photoContainer,
296be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                            R.id.stream_item_first_image, photoClickListener);
297be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    contentTable.addView(photoContainer);
298be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                }
2993915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro            }
3003915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro
301be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan            // Add text, comments, and attribution if applicable
302be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan            View textContainer = inflater.inflate(R.layout.stream_item_row_text, contentTable,
303fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda                    false);
304be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan            // Add extra padding between the text and the images
305be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan            int extraVerticalPadding = context.getResources().getDimensionPixelSize(
306be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    R.dimen.detail_update_section_between_items_vertical_padding);
307be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan            textContainer.setPadding(textContainer.getPaddingLeft(),
308be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    textContainer.getPaddingTop() + extraVerticalPadding,
309be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    textContainer.getPaddingRight(),
310be7a9d511eed5a549226b2e1bc2ebd6f65018c4cKatherine Kuan                    textContainer.getPaddingBottom());
311fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda            addStreamItemText(context, streamItem, textContainer);
312fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda            contentTable.addView(textContainer);
3132eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        }
3143915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro
315a21993720988a5fc0b48594d1ff0ce6f932780b7Flavio Lerda        if (parent != null) {
316fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda            parent.addView(container);
31722cb663a251af60bc6beeb1954568c8e6a4c34e9Flavio Lerda        }
31822cb663a251af60bc6beeb1954568c8e6a4c34e9Flavio Lerda
319fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda        return container;
320fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda    }
321fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda
322f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki    /** Loads a photo into an image view. The image view is identified by the given id. */
323fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda    private static void loadPhoto(ContactPhotoManager contactPhotoManager,
324f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            final StreamItemEntry streamItem, final StreamItemPhotoEntry streamItemPhoto,
325f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki            View photoContainer, int imageViewId, View.OnClickListener photoClickListener) {
3267b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki        final View frame = photoContainer.findViewById(imageViewId);
3277b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki        final View pushLayerView = frame.findViewById(R.id.push_layer);
3287b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki        final ImageView imageView = (ImageView) frame.findViewById(R.id.image);
329f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki        if (photoClickListener != null) {
3307b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki            pushLayerView.setOnClickListener(photoClickListener);
3317b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki            pushLayerView.setTag(new StreamPhotoTag(streamItem, streamItemPhoto));
3327b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki            pushLayerView.setFocusable(true);
3337b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki            pushLayerView.setEnabled(true);
334f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki        } else {
3357b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki            pushLayerView.setOnClickListener(null);
3367b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki            pushLayerView.setTag(null);
3377b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki            pushLayerView.setFocusable(false);
3387b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki            // setOnClickListener makes it clickable, so we need to overwrite it
3397b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki            pushLayerView.setClickable(false);
3407b45613a6df9eef617d73c9058ec1fb296142119Makoto Onuki            pushLayerView.setEnabled(false);
341f748d59e8a31f8c9d054fd11deb9b70250387dabMakoto Onuki        }
342ecfc26c3f9495f1a4efed69a1582ff2b0deb2c71Daniel Lehmann        contactPhotoManager.loadPhoto(imageView, Uri.parse(streamItemPhoto.getPhotoUri()), true,
3433d3a15c465b0c4105148458307a7b50e9b267fd0Makoto Onuki                false, ContactPhotoManager.DEFAULT_BLANK);
3443915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro    }
3453915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro
3465a77a5563706fe1b143d976d1b47abaeb873e138Flavio Lerda    @VisibleForTesting
347fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda    static View addStreamItemText(Context context, StreamItemEntry streamItem, View rootView) {
348fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda        TextView htmlView = (TextView) rootView.findViewById(R.id.stream_item_html);
349fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda        TextView attributionView = (TextView) rootView.findViewById(
3503915600d2b0ff499e0129e951dfd39bff46b2f42Dave Santoro                R.id.stream_item_attribution);
351fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda        TextView commentsView = (TextView) rootView.findViewById(R.id.stream_item_comments);
35265ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        ImageGetter imageGetter = new DefaultImageGetter(context.getPackageManager());
3533ab9a63014a2d5e097d221b424d6d4809295abd0Makoto Onuki
3543ab9a63014a2d5e097d221b424d6d4809295abd0Makoto Onuki        // Stream item text
3553ab9a63014a2d5e097d221b424d6d4809295abd0Makoto Onuki        setDataOrHideIfNone(HtmlUtils.fromHtml(context, streamItem.getText(), imageGetter, null),
3563ab9a63014a2d5e097d221b424d6d4809295abd0Makoto Onuki                htmlView);
3573ab9a63014a2d5e097d221b424d6d4809295abd0Makoto Onuki        // Attribution
3583ab9a63014a2d5e097d221b424d6d4809295abd0Makoto Onuki        setDataOrHideIfNone(ContactBadgeUtil.getSocialDate(streamItem, context),
3593ab9a63014a2d5e097d221b424d6d4809295abd0Makoto Onuki                attributionView);
3603ab9a63014a2d5e097d221b424d6d4809295abd0Makoto Onuki        // Comments
3613ab9a63014a2d5e097d221b424d6d4809295abd0Makoto Onuki        setDataOrHideIfNone(HtmlUtils.fromHtml(context, streamItem.getComments(), imageGetter,
3623ab9a63014a2d5e097d221b424d6d4809295abd0Makoto Onuki                null), commentsView);
363fd43cddee690e84f56163cd1c0899c3200b624e7Flavio Lerda        return rootView;
36479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
36579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
36679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    /**
3672eb969cc399d87b659a45568fa951d394c216917Katherine Kuan     * Sets the display name of this contact to the given {@link TextView}. If
3682eb969cc399d87b659a45568fa951d394c216917Katherine Kuan     * there is none, then set the view to gone.
3692eb969cc399d87b659a45568fa951d394c216917Katherine Kuan     */
3702eb969cc399d87b659a45568fa951d394c216917Katherine Kuan    public static void setDisplayName(Context context, Result contactData, TextView textView) {
3712eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        if (textView == null) {
3722eb969cc399d87b659a45568fa951d394c216917Katherine Kuan            return;
3732eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        }
3742eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        setDataOrHideIfNone(getDisplayName(context, contactData), textView);
3752eb969cc399d87b659a45568fa951d394c216917Katherine Kuan    }
3762eb969cc399d87b659a45568fa951d394c216917Katherine Kuan
3772eb969cc399d87b659a45568fa951d394c216917Katherine Kuan    /**
3782eb969cc399d87b659a45568fa951d394c216917Katherine Kuan     * Sets the company and job title of this contact to the given {@link TextView}. If
3792eb969cc399d87b659a45568fa951d394c216917Katherine Kuan     * there is none, then set the view to gone.
3802eb969cc399d87b659a45568fa951d394c216917Katherine Kuan     */
3812eb969cc399d87b659a45568fa951d394c216917Katherine Kuan    public static void setCompanyName(Context context, Result contactData, TextView textView) {
3822eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        if (textView == null) {
3832eb969cc399d87b659a45568fa951d394c216917Katherine Kuan            return;
3842eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        }
3852eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        setDataOrHideIfNone(getCompany(context, contactData), textView);
3862eb969cc399d87b659a45568fa951d394c216917Katherine Kuan    }
3872eb969cc399d87b659a45568fa951d394c216917Katherine Kuan
3882eb969cc399d87b659a45568fa951d394c216917Katherine Kuan    /**
38979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * Sets the phonetic name of this contact to the given {@link TextView}. If
39079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * there is none, then set the view to gone.
39179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     */
39279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    public static void setPhoneticName(Context context, Result contactData, TextView textView) {
3932eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        if (textView == null) {
3942eb969cc399d87b659a45568fa951d394c216917Katherine Kuan            return;
3952eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        }
39679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        setDataOrHideIfNone(getPhoneticName(context, contactData), textView);
39779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
39879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
39979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    /**
40079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * Sets the attribution contact to the given {@link TextView}. If
40179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * there is none, then set the view to gone.
40279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     */
40379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    public static void setAttribution(Context context, Result contactData, TextView textView) {
4042eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        if (textView == null) {
4052eb969cc399d87b659a45568fa951d394c216917Katherine Kuan            return;
4062eb969cc399d87b659a45568fa951d394c216917Katherine Kuan        }
40779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        setDataOrHideIfNone(getAttribution(context, contactData), textView);
40879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
40979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
41079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    /**
41179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * Helper function to display the given text in the {@link TextView} or
41279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     * hides the {@link TextView} if the text is empty or null.
41379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan     */
41479700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    private static void setDataOrHideIfNone(CharSequence textToDisplay, TextView textView) {
41579700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        if (!TextUtils.isEmpty(textToDisplay)) {
41679700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            textView.setText(textToDisplay);
41779700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            textView.setVisibility(View.VISIBLE);
41879700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        } else {
41979700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            textView.setText(null);
42079700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan            textView.setVisibility(View.GONE);
42179700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan        }
42279700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan    }
42379700889dad553dcde9e22a2fd23df768f68080fKatherine Kuan
42465ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda    /** Fetcher for images from resources to be included in HTML text. */
42565ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda    private static class DefaultImageGetter implements Html.ImageGetter {
42665ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        /** The scheme used to load resources. */
42765ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        private static final String RES_SCHEME = "res";
42865ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
42965ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        private final PackageManager mPackageManager;
43065ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
43165ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        public DefaultImageGetter(PackageManager packageManager) {
43265ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            mPackageManager = packageManager;
43365ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        }
43465ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
43565ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        @Override
43665ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        public Drawable getDrawable(String source) {
43765ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            // Returning null means that a default image will be used.
43865ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            Uri uri;
43965ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            try {
44065ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                uri = Uri.parse(source);
44165ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            } catch (Throwable e) {
44265ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                Log.d(TAG, "Could not parse image source: " + source);
44365ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                return null;
44465ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            }
44565ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            if (!RES_SCHEME.equals(uri.getScheme())) {
44665ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                Log.d(TAG, "Image source does not correspond to a resource: " + source);
44765ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                return null;
44865ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            }
44965ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            // The URI authority represents the package name.
45065ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            String packageName = uri.getAuthority();
45165ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
45265ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            Resources resources = getResourcesForResourceName(packageName);
45365ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            if (resources == null) {
45465ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                Log.d(TAG, "Could not parse image source: " + source);
45565ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                return null;
45665ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            }
45765ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
45865ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            List<String> pathSegments = uri.getPathSegments();
45965ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            if (pathSegments.size() != 1) {
46065ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                Log.d(TAG, "Could not parse image source: " + source);
46165ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                return null;
46265ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            }
46365ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
46465ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            final String name = pathSegments.get(0);
46565ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            final int resId = resources.getIdentifier(name, "drawable", packageName);
46665ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
46765ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            if (resId == 0) {
46865ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                // Use the default image icon in this case.
46965ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                Log.d(TAG, "Cannot resolve resource identifier: " + source);
47065ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                return null;
47165ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            }
47265ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
47365ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            try {
47465ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                return getResourceDrawable(resources, resId);
47565ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            } catch (NotFoundException e) {
47665ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                Log.d(TAG, "Resource not found: " + source, e);
47765ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                return null;
47865ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            }
47965ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        }
48065ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
48165ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        /** Returns the drawable associated with the given id. */
48265ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        private Drawable getResourceDrawable(Resources resources, int resId)
48365ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                throws NotFoundException {
48465ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            Drawable drawable = resources.getDrawable(resId);
48565ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
48665ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            return drawable;
48765ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        }
48865ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda
48965ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        /** Returns the {@link Resources} of the package of the given resource name. */
49065ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        private Resources getResourcesForResourceName(String packageName) {
49165ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            try {
49265ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                return mPackageManager.getResourcesForApplication(packageName);
49365ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            } catch (NameNotFoundException e) {
49465ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                Log.d(TAG, "Could not find package: " + packageName);
49565ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda                return null;
49665ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda            }
49765ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda        }
49865ca8b2082300ec9849082e5718b85fbbf30dd31Flavio Lerda    }
49925594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan
50025594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan    /**
50125594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan     * Sets an alpha value on the view.
50225594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan     */
50325594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan    public static void setAlphaOnViewBackground(View view, float alpha) {
50425594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan        if (view != null) {
50525594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan            // Convert alpha layer to a black background HEX color with an alpha value for better
50625594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan            // performance (i.e. use setBackgroundColor() instead of setAlpha())
50725594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan            view.setBackgroundColor((int) (alpha * 255) << 24);
50825594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan        }
50925594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan    }
5106c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5116c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    /**
5126c0470e21d8506fb53915df7463634fd47288343Katherine Kuan     * Returns the top coordinate of the first item in the {@link ListView}. If the first item
5136c0470e21d8506fb53915df7463634fd47288343Katherine Kuan     * in the {@link ListView} is not visible or there are no children in the list, then return
5146c0470e21d8506fb53915df7463634fd47288343Katherine Kuan     * Integer.MIN_VALUE. Note that the returned value will be <= 0 because the first item in the
5156c0470e21d8506fb53915df7463634fd47288343Katherine Kuan     * list cannot have a positive offset.
5166c0470e21d8506fb53915df7463634fd47288343Katherine Kuan     */
5176c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    public static int getFirstListItemOffset(ListView listView) {
5186c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        if (listView == null || listView.getChildCount() == 0 ||
5196c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                listView.getFirstVisiblePosition() != 0) {
5206c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            return Integer.MIN_VALUE;
5216c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
5226c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        return listView.getChildAt(0).getTop();
5236c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    }
5246c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5256c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    /**
5266c0470e21d8506fb53915df7463634fd47288343Katherine Kuan     * Tries to scroll the first item in the list to the given offset (this can be a no-op if the
5276c0470e21d8506fb53915df7463634fd47288343Katherine Kuan     * list is already in the correct position).
5286c0470e21d8506fb53915df7463634fd47288343Katherine Kuan     * @param listView that should be scrolled
5296c0470e21d8506fb53915df7463634fd47288343Katherine Kuan     * @param offset which should be <= 0
5306c0470e21d8506fb53915df7463634fd47288343Katherine Kuan     */
5316c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    public static void requestToMoveToOffset(ListView listView, int offset) {
5326c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        // We try to offset the list if the first item in the list is showing (which is presumed
5336c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        // to have a larger height than the desired offset). If the first item in the list is not
5346c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        // visible, then we simply do not scroll the list at all (since it can get complicated to
5356c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        // compute how many items in the list will equal the given offset). Potentially
5366c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        // some animation elsewhere will make the transition smoother for the user to compensate
5376c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        // for this simplification.
5386c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        if (listView == null || listView.getChildCount() == 0 ||
5396c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                listView.getFirstVisiblePosition() != 0 || offset > 0) {
5406c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            return;
5416c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
5426c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5436c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        // As an optimization, check if the first item is already at the given offset.
5446c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        if (listView.getChildAt(0).getTop() == offset) {
5456c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            return;
5466c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
5476c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5486c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        listView.setSelectionFromTop(0, offset);
5496c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    }
55022cb663a251af60bc6beeb1954568c8e6a4c34e9Flavio Lerda}
551