blob: 0f12de72e08276da706d74b24495fae3300adf37 [file] [log] [blame]
Katherine Kuan79700882011-06-14 17:40:33 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.contacts.detail;
18
19import com.android.contacts.ContactLoader;
20import com.android.contacts.ContactLoader.Result;
21import com.android.contacts.R;
22import com.android.contacts.format.FormatUtils;
23import com.android.contacts.preference.ContactsPreferences;
24import com.android.contacts.util.ContactBadgeUtil;
25
26import android.content.ContentValues;
27import android.content.Context;
28import android.content.Entity;
29import android.content.Entity.NamedContentValues;
30import android.graphics.Bitmap;
31import android.graphics.BitmapFactory;
32import android.graphics.Typeface;
33import android.provider.ContactsContract;
34import android.provider.ContactsContract.CommonDataKinds.Organization;
35import android.provider.ContactsContract.Data;
36import android.provider.ContactsContract.DisplayNameSources;
37import android.text.Spanned;
38import android.text.TextUtils;
39import android.view.View;
40import android.view.animation.AccelerateInterpolator;
41import android.view.animation.AlphaAnimation;
42import android.widget.CheckBox;
43import android.widget.ImageView;
44import android.widget.TextView;
45
46/**
47 * This class contains utility methods to bind high-level contact details
48 * (meaning name, phonetic name, job, and attribution) from a
49 * {@link ContactLoader.Result} data object to appropriate {@link View}s.
50 */
51public class ContactDetailDisplayUtils {
52
53 private static final int PHOTO_FADE_IN_ANIMATION_DURATION_MILLIS = 100;
54
55 private ContactDetailDisplayUtils() {
56 // Disallow explicit creation of this class.
57 }
58
59 /**
60 * Returns the display name of the contact. Depending on the preference for
61 * display name ordering, the contact's first name may be bolded if
62 * possible. Returns empty string if there is no display name.
63 */
64 public static CharSequence getDisplayName(Context context, Result contactData) {
65 CharSequence displayName = contactData.getDisplayName();
66 CharSequence altDisplayName = contactData.getAltDisplayName();
67 ContactsPreferences prefs = new ContactsPreferences(context);
68 CharSequence styledName = "";
69 if (!TextUtils.isEmpty(displayName) && !TextUtils.isEmpty(altDisplayName)) {
70 if (prefs.getDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
71 int overlapPoint = FormatUtils.overlapPoint(
72 displayName.toString(), altDisplayName.toString());
73 if (overlapPoint > 0) {
74 styledName = FormatUtils.applyStyleToSpan(Typeface.BOLD,
75 displayName, 0, overlapPoint, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
76 } else {
77 styledName = displayName;
78 }
79 } else {
80 // Displaying alternate display name.
81 int overlapPoint = FormatUtils.overlapPoint(
82 altDisplayName.toString(), displayName.toString());
83 if (overlapPoint > 0) {
84 styledName = FormatUtils.applyStyleToSpan(Typeface.BOLD,
85 altDisplayName, overlapPoint, altDisplayName.length(),
86 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
87 } else {
88 styledName = altDisplayName;
89 }
90 }
91 }
92 return styledName;
93 }
94
95 /**
96 * Returns the phonetic name of the contact or null if there isn't one.
97 */
98 public static String getPhoneticName(Context context, Result contactData) {
99 String phoneticName = contactData.getPhoneticName();
100 if (!TextUtils.isEmpty(phoneticName)) {
101 return phoneticName;
102 }
103 return null;
104 }
105
106 /**
107 * Returns the attribution string for the contact. This could either specify
108 * that this is a joined contact or specify the contact directory that the
109 * contact came from. Returns null if there is none applicable.
110 */
111 public static String getAttribution(Context context, Result contactData) {
112 // Check if this is a joined contact
113 if (contactData.getEntities().size() > 1) {
114 return context.getString(R.string.indicator_joined_contact);
115 } else if (contactData.isDirectoryEntry()) {
116 // This contact is from a directory
117 String directoryDisplayName = contactData.getDirectoryDisplayName();
118 String directoryType = contactData.getDirectoryType();
119 String displayName = !TextUtils.isEmpty(directoryDisplayName)
120 ? directoryDisplayName
121 : directoryType;
122 return context.getString(R.string.contact_directory_description, displayName);
123 }
124 return null;
125 }
126
127 /**
128 * Returns the organization of the contact. If several organizations are given,
129 * the first one is used. Returns null if not applicable.
130 */
131 public static String getCompany(Context context, Result contactData) {
132 final boolean displayNameIsOrganization = contactData.getDisplayNameSource()
133 == DisplayNameSources.ORGANIZATION;
134 for (Entity entity : contactData.getEntities()) {
135 for (NamedContentValues subValue : entity.getSubValues()) {
136 final ContentValues entryValues = subValue.values;
137 final String mimeType = entryValues.getAsString(Data.MIMETYPE);
138
139 if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
140 final String company = entryValues.getAsString(Organization.COMPANY);
141 final String title = entryValues.getAsString(Organization.TITLE);
142 final String combined;
143 // We need to show company and title in a combined string. However, if the
144 // DisplayName is already the organization, it mirrors company or (if company
145 // is empty title). Make sure we don't show what's already shown as DisplayName
146 if (TextUtils.isEmpty(company)) {
147 combined = displayNameIsOrganization ? null : title;
148 } else {
149 if (TextUtils.isEmpty(title)) {
150 combined = displayNameIsOrganization ? null : company;
151 } else {
152 if (displayNameIsOrganization) {
153 combined = title;
154 } else {
155 combined = context.getString(
156 R.string.organization_company_and_title,
157 company, title);
158 }
159 }
160 }
161
162 if (!TextUtils.isEmpty(combined)) {
163 return combined;
164 }
165 }
166 }
167 }
168 return null;
169 }
170
171
172 /**
173 * Sets the contact photo to display in the given {@link ImageView}. If bitmap is null, the
174 * default placeholder image is shown.
175 */
176 public static void setPhoto(Context context, Result contactData, ImageView photoView) {
177 if (contactData.isLoadingPhoto()) {
178 photoView.setImageBitmap(null);
179 return;
180 }
181 byte[] photo = contactData.getPhotoBinaryData();
182 Bitmap bitmap = photo != null ? BitmapFactory.decodeByteArray(photo, 0, photo.length)
183 : ContactBadgeUtil.loadPlaceholderPhoto(context);
184 boolean fadeIn = contactData.isDirectoryEntry();
185 if (photoView.getDrawable() == null && fadeIn) {
186 AlphaAnimation animation = new AlphaAnimation(0, 1);
187 animation.setDuration(PHOTO_FADE_IN_ANIMATION_DURATION_MILLIS);
188 animation.setInterpolator(new AccelerateInterpolator());
189 photoView.startAnimation(animation);
190 }
191 photoView.setImageBitmap(bitmap);
192 }
193
194 /**
195 * Sets the starred state of this contact.
196 */
197 public static void setStarred(Result contactData, CheckBox starredView) {
198 // Check if the starred state should be visible
199 if (!contactData.isDirectoryEntry()) {
200 starredView.setVisibility(View.VISIBLE);
201 starredView.setChecked(contactData.getStarred());
202 } else {
203 starredView.setVisibility(View.GONE);
204 }
205 }
206
207 /**
208 * Set the social snippet text and date. If there isn't one, then set the view to gone.
209 */
210 public static void setSocialSnippetAndDate(Context context, Result contactData,
211 TextView statusView, TextView dateView) {
212 setDataOrHideIfNone(contactData.getSocialSnippet(), statusView);
213 setDataOrHideIfNone(ContactBadgeUtil.getSocialDate(contactData, context), dateView);
214 }
215
216 /**
217 * Sets the phonetic name of this contact to the given {@link TextView}. If
218 * there is none, then set the view to gone.
219 */
220 public static void setPhoneticName(Context context, Result contactData, TextView textView) {
221 setDataOrHideIfNone(getPhoneticName(context, contactData), textView);
222 }
223
224 /**
225 * Sets the attribution contact to the given {@link TextView}. If
226 * there is none, then set the view to gone.
227 */
228 public static void setAttribution(Context context, Result contactData, TextView textView) {
229 setDataOrHideIfNone(getAttribution(context, contactData), textView);
230 }
231
232 /**
233 * Helper function to display the given text in the {@link TextView} or
234 * hides the {@link TextView} if the text is empty or null.
235 */
236 private static void setDataOrHideIfNone(CharSequence textToDisplay, TextView textView) {
237 if (!TextUtils.isEmpty(textToDisplay)) {
238 textView.setText(textToDisplay);
239 textView.setVisibility(View.VISIBLE);
240 } else {
241 textView.setText(null);
242 textView.setVisibility(View.GONE);
243 }
244 }
245
246}