blob: 795ed62bf27935abbd4fd680e648529b34c56447 [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.detail;
import com.android.contacts.ContactLoader;
import com.android.contacts.ContactLoader.Result;
import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
import com.android.contacts.format.FormatUtils;
import com.android.contacts.preference.ContactsPreferences;
import com.android.contacts.util.ContactBadgeUtil;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.Entity;
import android.content.Entity.NamedContentValues;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.DisplayNameSources;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
/**
* Header for displaying a title bar with contact info. You
* can bind specific values by calling
* {@link ContactDetailHeaderView#loadData(com.android.contacts.ContactLoader.Result)}
*/
public class ContactDetailHeaderView extends FrameLayout
implements View.OnClickListener, View.OnLongClickListener {
private static final String TAG = "ContactDetailHeaderView";
private static final int PHOTO_FADE_IN_ANIMATION_DURATION_MILLIS = 100;
private TextView mDisplayNameView;
private TextView mPhoneticNameView;
private TextView mOrganizationTextView;
private CheckBox mStarredView;
private ImageView mPhotoView;
private View mStatusContainerView;
private TextView mStatusView;
private TextView mStatusDateView;
private TextView mAttributionView;
private Uri mContactUri;
private Listener mListener;
/**
* Interface for callbacks invoked when the user interacts with a header.
*/
public interface Listener {
public void onPhotoClick(View view);
public void onDisplayNameClick(View view);
}
public ContactDetailHeaderView(Context context) {
this(context, null);
}
public ContactDetailHeaderView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ContactDetailHeaderView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final LayoutInflater inflater =
(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.contact_detail_header_view, this);
mDisplayNameView = (TextView) findViewById(R.id.name);
mDisplayNameView.setOnLongClickListener(this);
mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name);
mPhoneticNameView.setOnLongClickListener(this);
mOrganizationTextView = (TextView) findViewById(R.id.organization);
mOrganizationTextView.setOnLongClickListener(this);
mStarredView = (CheckBox)findViewById(R.id.star);
mStarredView.setOnClickListener(this);
mPhotoView = (ImageView) findViewById(R.id.photo);
mStatusContainerView = findViewById(R.id.status_container);
mStatusView = (TextView)findViewById(R.id.status);
mStatusDateView = (TextView)findViewById(R.id.status_date);
mAttributionView = (TextView) findViewById(R.id.attribution);
}
/**
* Loads the data from the Loader-Result. This is the only function that has to be called
* from the outside to fully setup the View
*/
public void loadData(ContactLoader.Result contactData) {
mContactUri = contactData.getLookupUri();
setDisplayName(contactData.getDisplayName(), contactData.getAltDisplayName(),
contactData.getPhoneticName());
setCompany(contactData);
if (contactData.isLoadingPhoto()) {
setPhoto(null, false);
} else {
byte[] photo = contactData.getPhotoBinaryData();
setPhoto(photo != null ? BitmapFactory.decodeByteArray(photo, 0, photo.length)
: ContactBadgeUtil.loadPlaceholderPhoto(mContext),
contactData.isDirectoryEntry());
}
setStared(!contactData.isDirectoryEntry(), contactData.getStarred());
setSocialSnippet(contactData.getSocialSnippet());
setSocialDate(ContactBadgeUtil.getSocialDate(contactData, getContext()));
setAttribution(contactData.getEntities().size() > 1, contactData.isDirectoryEntry(),
contactData.getDirectoryDisplayName(), contactData.getDirectoryType());
}
/**
* Set the given {@link Listener} to handle header events.
*/
public void setListener(Listener listener) {
mListener = listener;
}
private void performPhotoClick() {
if (mListener != null) {
mListener.onPhotoClick(mPhotoView);
}
}
private void performDisplayNameClick() {
if (mListener != null) {
mListener.onDisplayNameClick(mDisplayNameView);
}
}
/**
* Set the starred state of this header widget.
*/
private void setStared(boolean visible, boolean starred) {
if (visible) {
mStarredView.setVisibility(View.VISIBLE);
mStarredView.setChecked(starred);
} else {
mStarredView.setVisibility(View.GONE);
}
}
/**
* Set the photo to display in the header. If bitmap is null, the default placeholder
* image is shown
*/
private void setPhoto(Bitmap bitmap, boolean fadeIn) {
if (mPhotoView.getDrawable() == null && fadeIn) {
AlphaAnimation animation = new AlphaAnimation(0, 1);
animation.setDuration(PHOTO_FADE_IN_ANIMATION_DURATION_MILLIS);
animation.setInterpolator(new AccelerateInterpolator());
mPhotoView.startAnimation(animation);
}
mPhotoView.setImageBitmap(bitmap);
}
/**
* Set the display name and phonetic name to show in the header.
*/
private void setDisplayName(CharSequence displayName, CharSequence altDisplayName,
CharSequence phoneticName) {
// Check the preference for display name ordering, and bold the contact's first name if
// possible.
ContactsPreferences prefs = new ContactsPreferences(getContext());
CharSequence styledName = "";
if (!TextUtils.isEmpty(displayName) && !TextUtils.isEmpty(altDisplayName)) {
if (prefs.getDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
int overlapPoint = FormatUtils.overlapPoint(
displayName.toString(), altDisplayName.toString());
if (overlapPoint > 0) {
styledName = FormatUtils.applyStyleToSpan(Typeface.BOLD,
displayName, 0, overlapPoint, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
styledName = displayName;
}
} else {
// Displaying alternate display name.
int overlapPoint = FormatUtils.overlapPoint(
altDisplayName.toString(), displayName.toString());
if (overlapPoint > 0) {
styledName = FormatUtils.applyStyleToSpan(Typeface.BOLD,
altDisplayName, overlapPoint, altDisplayName.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
styledName = altDisplayName;
}
}
}
mDisplayNameView.setText(styledName);
if (TextUtils.isEmpty(phoneticName)) {
mPhoneticNameView.setVisibility(View.GONE);
} else {
mPhoneticNameView.setText(phoneticName);
mPhoneticNameView.setVisibility(View.VISIBLE);
}
}
/**
* Sets the organization info. If several organizations are given, the first one is used
*/
private void setCompany(Result contactData) {
final boolean displayNameIsOrganization =
contactData.getDisplayNameSource() == DisplayNameSources.ORGANIZATION;
for (Entity entity : contactData.getEntities()) {
for (NamedContentValues subValue : entity.getSubValues()) {
final ContentValues entryValues = subValue.values;
final String mimeType = entryValues.getAsString(Data.MIMETYPE);
if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
final String company = entryValues.getAsString(Organization.COMPANY);
final String title = entryValues.getAsString(Organization.TITLE);
final String combined;
// We need to show company and title in a combined string. However, if the
// DisplayName is already the organization, it mirrors company or (if company
// is empty title). Make sure we don't show what's already shown as DisplayName
if (TextUtils.isEmpty(company)) {
combined = displayNameIsOrganization ? null : title;
} else {
if (TextUtils.isEmpty(title)) {
combined = displayNameIsOrganization ? null : company;
} else {
if (displayNameIsOrganization) {
combined = title;
} else {
combined = getResources().getString(
R.string.organization_company_and_title,
company, title);
}
}
}
if (TextUtils.isEmpty(combined)) {
mOrganizationTextView.setVisibility(GONE);
} else {
mOrganizationTextView.setVisibility(VISIBLE);
mOrganizationTextView.setText(combined);
}
return;
}
}
}
mOrganizationTextView.setVisibility(GONE);
}
/**
* Set the social snippet text to display in the header.
*/
private void setSocialSnippet(CharSequence snippet) {
if (TextUtils.isEmpty(snippet)) {
// No status info. Hide everything
if (mStatusContainerView != null) mStatusContainerView.setVisibility(View.GONE);
mStatusView.setVisibility(View.GONE);
mStatusDateView.setVisibility(View.GONE);
} else {
// We have status info. Show the bubble
if (mStatusContainerView != null) mStatusContainerView.setVisibility(View.VISIBLE);
mStatusView.setVisibility(View.VISIBLE);
mStatusView.setText(snippet);
}
}
/**
* Set the status attribution text to display in the header.
*/
private void setSocialDate(CharSequence dateText) {
if (TextUtils.isEmpty(dateText)) {
mStatusDateView.setVisibility(View.GONE);
} else {
mStatusDateView.setText(dateText);
mStatusDateView.setVisibility(View.VISIBLE);
}
}
private void setAttribution(boolean isJoinedContact, boolean isDirectoryEntry,
String directoryDisplayName, String directoryType) {
if (isJoinedContact) {
mAttributionView.setText(R.string.indicator_joined_contact);
mAttributionView.setVisibility(View.VISIBLE);
} else if (isDirectoryEntry) {
String displayName = !TextUtils.isEmpty(directoryDisplayName)
? directoryDisplayName
: directoryType;
String text = getContext().getString(
R.string.contact_directory_description, displayName);
mAttributionView.setText(text);
mAttributionView.setVisibility(View.VISIBLE);
} else {
mAttributionView.setVisibility(View.INVISIBLE);
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.star: {
// Toggle "starred" state
// Make sure there is a contact
if (mContactUri != null) {
Intent intent = ContactSaveService.createSetStarredIntent(
getContext(), mContactUri, mStarredView.isChecked());
getContext().startService(intent);
}
break;
}
case R.id.photo: {
performPhotoClick();
break;
}
case R.id.name: {
performDisplayNameClick();
break;
}
}
}
@Override
public boolean onLongClick(View v) {
if (!(v instanceof TextView)) {
return false;
}
CharSequence text = ((TextView)v).getText();
if (TextUtils.isEmpty(text)) {
return false;
}
ClipboardManager cm = (ClipboardManager) getContext().getSystemService(
Context.CLIPBOARD_SERVICE);
cm.setPrimaryClip(ClipData.newPlainText(null, text));
Toast.makeText(getContext(), R.string.toast_text_copied, Toast.LENGTH_SHORT).show();
return true;
}
}