Remove ContactHeaderWidget, because it lives directly in the Contacts App from now on
Change-Id: I1d3646f2744e01a1e64db8787b4cd7dd746d540e
This commit is contained in:
@@ -1,727 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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.internal.widget;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.SystemClock;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.Data;
|
||||
import android.provider.ContactsContract.PhoneLookup;
|
||||
import android.provider.ContactsContract.RawContacts;
|
||||
import android.provider.ContactsContract.StatusUpdates;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Email;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Photo;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.QuickContactBadge;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* Header used across system for displaying a title bar with contact info. You
|
||||
* can bind specific values on the header, or use helper methods like
|
||||
* {@link #bindFromContactLookupUri(Uri)} to populate asynchronously.
|
||||
* <p>
|
||||
* The parent must request the {@link Manifest.permission#READ_CONTACTS}
|
||||
* permission to access contact data.
|
||||
*/
|
||||
public class ContactHeaderWidget extends FrameLayout implements View.OnClickListener {
|
||||
|
||||
private static final String TAG = "ContactHeaderWidget";
|
||||
|
||||
private TextView mDisplayNameView;
|
||||
private View mAggregateBadge;
|
||||
private TextView mPhoneticNameView;
|
||||
private CheckBox mStarredView;
|
||||
private QuickContactBadge mPhotoView;
|
||||
private ImageView mPresenceView;
|
||||
private TextView mStatusView;
|
||||
private TextView mStatusAttributionView;
|
||||
private int mNoPhotoResource;
|
||||
private QueryHandler mQueryHandler;
|
||||
|
||||
protected Uri mContactUri;
|
||||
|
||||
protected String[] mExcludeMimes = null;
|
||||
|
||||
protected ContentResolver mContentResolver;
|
||||
|
||||
/**
|
||||
* Interface for callbacks invoked when the user interacts with a header.
|
||||
*/
|
||||
public interface ContactHeaderListener {
|
||||
public void onPhotoClick(View view);
|
||||
public void onDisplayNameClick(View view);
|
||||
}
|
||||
|
||||
private ContactHeaderListener mListener;
|
||||
|
||||
|
||||
private interface ContactQuery {
|
||||
//Projection used for the summary info in the header.
|
||||
String[] COLUMNS = new String[] {
|
||||
Contacts._ID,
|
||||
Contacts.LOOKUP_KEY,
|
||||
Contacts.PHOTO_ID,
|
||||
Contacts.DISPLAY_NAME,
|
||||
Contacts.PHONETIC_NAME,
|
||||
Contacts.STARRED,
|
||||
Contacts.CONTACT_PRESENCE,
|
||||
Contacts.CONTACT_STATUS,
|
||||
Contacts.CONTACT_STATUS_TIMESTAMP,
|
||||
Contacts.CONTACT_STATUS_RES_PACKAGE,
|
||||
Contacts.CONTACT_STATUS_LABEL,
|
||||
};
|
||||
int _ID = 0;
|
||||
int LOOKUP_KEY = 1;
|
||||
int PHOTO_ID = 2;
|
||||
int DISPLAY_NAME = 3;
|
||||
int PHONETIC_NAME = 4;
|
||||
//TODO: We need to figure out how we're going to get the phonetic name.
|
||||
//static final int HEADER_PHONETIC_NAME_COLUMN_INDEX
|
||||
int STARRED = 5;
|
||||
int CONTACT_PRESENCE_STATUS = 6;
|
||||
int CONTACT_STATUS = 7;
|
||||
int CONTACT_STATUS_TIMESTAMP = 8;
|
||||
int CONTACT_STATUS_RES_PACKAGE = 9;
|
||||
int CONTACT_STATUS_LABEL = 10;
|
||||
}
|
||||
|
||||
private interface PhotoQuery {
|
||||
String[] COLUMNS = new String[] {
|
||||
Photo.PHOTO
|
||||
};
|
||||
|
||||
int PHOTO = 0;
|
||||
}
|
||||
|
||||
//Projection used for looking up contact id from phone number
|
||||
protected static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
|
||||
PhoneLookup._ID,
|
||||
PhoneLookup.LOOKUP_KEY,
|
||||
};
|
||||
protected static final int PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
|
||||
protected static final int PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1;
|
||||
|
||||
//Projection used for looking up contact id from email address
|
||||
protected static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
|
||||
RawContacts.CONTACT_ID,
|
||||
Contacts.LOOKUP_KEY,
|
||||
};
|
||||
protected static final int EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
|
||||
protected static final int EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1;
|
||||
|
||||
protected static final String[] CONTACT_LOOKUP_PROJECTION = new String[] {
|
||||
Contacts._ID,
|
||||
};
|
||||
protected static final int CONTACT_LOOKUP_ID_COLUMN_INDEX = 0;
|
||||
|
||||
private static final int TOKEN_CONTACT_INFO = 0;
|
||||
private static final int TOKEN_PHONE_LOOKUP = 1;
|
||||
private static final int TOKEN_EMAIL_LOOKUP = 2;
|
||||
private static final int TOKEN_PHOTO_QUERY = 3;
|
||||
|
||||
public ContactHeaderWidget(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ContactHeaderWidget(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ContactHeaderWidget(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
mContentResolver = mContext.getContentResolver();
|
||||
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
inflater.inflate(R.layout.contact_header, this);
|
||||
|
||||
mDisplayNameView = (TextView) findViewById(R.id.name);
|
||||
mAggregateBadge = findViewById(R.id.aggregate_badge);
|
||||
|
||||
mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name);
|
||||
|
||||
mStarredView = (CheckBox)findViewById(R.id.star);
|
||||
mStarredView.setOnClickListener(this);
|
||||
|
||||
mPhotoView = (QuickContactBadge) findViewById(R.id.photo);
|
||||
|
||||
mPresenceView = (ImageView) findViewById(R.id.presence);
|
||||
|
||||
mStatusView = (TextView)findViewById(R.id.status);
|
||||
mStatusAttributionView = (TextView)findViewById(R.id.status_date);
|
||||
|
||||
// Set the photo with a random "no contact" image
|
||||
long now = SystemClock.elapsedRealtime();
|
||||
int num = (int) now & 0xf;
|
||||
if (num < 9) {
|
||||
// Leaning in from right, common
|
||||
mNoPhotoResource = R.drawable.ic_contact_picture;
|
||||
} else if (num < 14) {
|
||||
// Leaning in from left uncommon
|
||||
mNoPhotoResource = R.drawable.ic_contact_picture_2;
|
||||
} else {
|
||||
// Coming in from the top, rare
|
||||
mNoPhotoResource = R.drawable.ic_contact_picture_3;
|
||||
}
|
||||
|
||||
resetAsyncQueryHandler();
|
||||
}
|
||||
|
||||
public void enableClickListeners() {
|
||||
mDisplayNameView.setOnClickListener(this);
|
||||
mPhotoView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given {@link ContactHeaderListener} to handle header events.
|
||||
*/
|
||||
public void setContactHeaderListener(ContactHeaderListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
private void performPhotoClick() {
|
||||
if (mListener != null) {
|
||||
mListener.onPhotoClick(mPhotoView);
|
||||
}
|
||||
}
|
||||
|
||||
private void performDisplayNameClick() {
|
||||
if (mListener != null) {
|
||||
mListener.onDisplayNameClick(mDisplayNameView);
|
||||
}
|
||||
}
|
||||
|
||||
private class QueryHandler extends AsyncQueryHandler {
|
||||
|
||||
public QueryHandler(ContentResolver cr) {
|
||||
super(cr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
try{
|
||||
if (this != mQueryHandler) {
|
||||
Log.d(TAG, "onQueryComplete: discard result, the query handler is reset!");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (token) {
|
||||
case TOKEN_PHOTO_QUERY: {
|
||||
//Set the photo
|
||||
Bitmap photoBitmap = null;
|
||||
if (cursor != null && cursor.moveToFirst()
|
||||
&& !cursor.isNull(PhotoQuery.PHOTO)) {
|
||||
byte[] photoData = cursor.getBlob(PhotoQuery.PHOTO);
|
||||
photoBitmap = BitmapFactory.decodeByteArray(photoData, 0,
|
||||
photoData.length, null);
|
||||
}
|
||||
|
||||
if (photoBitmap == null) {
|
||||
photoBitmap = loadPlaceholderPhoto(null);
|
||||
}
|
||||
setPhoto(photoBitmap);
|
||||
if (cookie != null && cookie instanceof Uri) {
|
||||
mPhotoView.assignContactUri((Uri) cookie);
|
||||
}
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
case TOKEN_CONTACT_INFO: {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
bindContactInfo(cursor);
|
||||
final Uri lookupUri = Contacts.getLookupUri(
|
||||
cursor.getLong(ContactQuery._ID),
|
||||
cursor.getString(ContactQuery.LOOKUP_KEY));
|
||||
|
||||
final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
|
||||
|
||||
setPhotoId(photoId, lookupUri);
|
||||
} else {
|
||||
// shouldn't really happen
|
||||
setDisplayName(null, null);
|
||||
setSocialSnippet(null);
|
||||
setPhoto(loadPlaceholderPhoto(null));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TOKEN_PHONE_LOOKUP: {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
long contactId = cursor.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
|
||||
String lookupKey = cursor.getString(
|
||||
PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
|
||||
bindFromContactUriInternal(Contacts.getLookupUri(contactId, lookupKey),
|
||||
false /* don't reset query handler */);
|
||||
} else {
|
||||
String phoneNumber = (String) cookie;
|
||||
setDisplayName(phoneNumber, null);
|
||||
setSocialSnippet(null);
|
||||
setPhoto(loadPlaceholderPhoto(null));
|
||||
mPhotoView.assignContactFromPhone(phoneNumber, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TOKEN_EMAIL_LOOKUP: {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
long contactId = cursor.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
|
||||
String lookupKey = cursor.getString(
|
||||
EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
|
||||
bindFromContactUriInternal(Contacts.getLookupUri(contactId, lookupKey),
|
||||
false /* don't reset query handler */);
|
||||
} else {
|
||||
String emailAddress = (String) cookie;
|
||||
setDisplayName(emailAddress, null);
|
||||
setSocialSnippet(null);
|
||||
setPhoto(loadPlaceholderPhoto(null));
|
||||
mPhotoView.assignContactFromEmail(emailAddress, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn on/off showing of the aggregate badge element.
|
||||
*/
|
||||
public void showAggregateBadge(boolean showBagde) {
|
||||
mAggregateBadge.setVisibility(showBagde ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn on/off showing of the star element.
|
||||
*/
|
||||
public void showStar(boolean showStar) {
|
||||
mStarredView.setVisibility(showStar ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the starred state of this header widget. This doesn't change
|
||||
* the underlying {@link Contacts} value, only the UI state.
|
||||
*/
|
||||
public void setStared(boolean starred) {
|
||||
mStarredView.setChecked(starred);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the presence.
|
||||
*/
|
||||
public void setPresence(int presence) {
|
||||
mPresenceView.setImageResource(StatusUpdates.getPresenceIconResourceId(presence));
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the presence. If presence is null, it is hidden.
|
||||
* This doesn't change the underlying {@link Contacts} value, only the UI state.
|
||||
* @hide
|
||||
*/
|
||||
public void setPresence(Integer presence) {
|
||||
if (presence == null) {
|
||||
showPresence(false);
|
||||
} else {
|
||||
showPresence(true);
|
||||
setPresence(presence.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn on/off showing the presence.
|
||||
* @hide this is here for consistency with setStared/showStar and should be public
|
||||
*/
|
||||
public void showPresence(boolean showPresence) {
|
||||
mPresenceView.setVisibility(showPresence ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the contact uri without loading any data
|
||||
*/
|
||||
public void setContactUri(Uri uri) {
|
||||
setContactUri(uri, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the contact uri without loading any data
|
||||
*/
|
||||
public void setContactUri(Uri uri, boolean sendToQuickContact) {
|
||||
mContactUri = uri;
|
||||
if (sendToQuickContact) {
|
||||
mPhotoView.assignContactUri(uri);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the photo to display in the header. This doesn't change the
|
||||
* underlying {@link Contacts}, only the UI state.
|
||||
*/
|
||||
public void setPhoto(Bitmap bitmap) {
|
||||
mPhotoView.setImageBitmap(bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the photo given its id. If the id is 0, a placeholder picture will
|
||||
* be loaded. For any other Id, an async query is started
|
||||
* @hide
|
||||
*/
|
||||
public void setPhotoId(final long photoId, final Uri lookupUri) {
|
||||
if (photoId == 0) {
|
||||
setPhoto(loadPlaceholderPhoto(null));
|
||||
mPhotoView.assignContactUri(lookupUri);
|
||||
invalidate();
|
||||
} else {
|
||||
startPhotoQuery(photoId, lookupUri,
|
||||
false /* don't reset query handler */);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the display name and phonetic name to show in the header.
|
||||
* This doesn't change the underlying {@link Contacts}, only the UI state.
|
||||
*/
|
||||
public void setDisplayName(CharSequence displayName, CharSequence phoneticName) {
|
||||
mDisplayNameView.setText(displayName);
|
||||
if (!TextUtils.isEmpty(phoneticName)) {
|
||||
mPhoneticNameView.setText(phoneticName);
|
||||
mPhoneticNameView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mPhoneticNameView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the social snippet text to display in the header. This doesn't change the
|
||||
* underlying {@link Contacts}, only the UI state.
|
||||
*/
|
||||
public void setSocialSnippet(CharSequence snippet) {
|
||||
if (snippet == null) {
|
||||
mStatusView.setVisibility(View.GONE);
|
||||
mStatusAttributionView.setVisibility(View.GONE);
|
||||
} else {
|
||||
mStatusView.setText(snippet);
|
||||
mStatusView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set the status attribution text to display in the header.
|
||||
* This doesn't change the underlying {@link Contacts}, only the UI state.
|
||||
* @hide
|
||||
*/
|
||||
public void setStatusAttribution(CharSequence attribution) {
|
||||
if (attribution != null) {
|
||||
mStatusAttributionView.setText(attribution);
|
||||
mStatusAttributionView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mStatusAttributionView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a list of specific MIME-types to exclude and not display. For
|
||||
* example, this can be used to hide the {@link Contacts#CONTENT_ITEM_TYPE}
|
||||
* profile icon.
|
||||
*/
|
||||
public void setExcludeMimes(String[] excludeMimes) {
|
||||
mExcludeMimes = excludeMimes;
|
||||
mPhotoView.setExcludeMimes(excludeMimes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set all the status values to display in the header.
|
||||
* This doesn't change the underlying {@link Contacts}, only the UI state.
|
||||
* @hide
|
||||
* @param status The status of the contact. If this is either null or empty,
|
||||
* the status is cleared and the other parameters are ignored.
|
||||
* @param statusTimestamp The timestamp (retrieved via a call to
|
||||
* {@link System#currentTimeMillis()}) of the last status update.
|
||||
* This value can be null if it is not known.
|
||||
* @param statusLabel The id of a resource string that specifies the current
|
||||
* status. This value can be null if no Label should be used.
|
||||
* @param statusResPackage The name of the resource package containing the resource string
|
||||
* referenced in the parameter statusLabel.
|
||||
*/
|
||||
public void setStatus(final String status, final Long statusTimestamp,
|
||||
final Integer statusLabel, final String statusResPackage) {
|
||||
if (TextUtils.isEmpty(status)) {
|
||||
setSocialSnippet(null);
|
||||
return;
|
||||
}
|
||||
|
||||
setSocialSnippet(status);
|
||||
|
||||
final CharSequence timestampDisplayValue;
|
||||
|
||||
if (statusTimestamp != null) {
|
||||
// Set the date/time field by mixing relative and absolute
|
||||
// times.
|
||||
int flags = DateUtils.FORMAT_ABBREV_RELATIVE;
|
||||
|
||||
timestampDisplayValue = DateUtils.getRelativeTimeSpanString(
|
||||
statusTimestamp.longValue(), System.currentTimeMillis(),
|
||||
DateUtils.MINUTE_IN_MILLIS, flags);
|
||||
} else {
|
||||
timestampDisplayValue = null;
|
||||
}
|
||||
|
||||
|
||||
String labelDisplayValue = null;
|
||||
|
||||
if (statusLabel != null) {
|
||||
Resources resources;
|
||||
if (TextUtils.isEmpty(statusResPackage)) {
|
||||
resources = getResources();
|
||||
} else {
|
||||
PackageManager pm = getContext().getPackageManager();
|
||||
try {
|
||||
resources = pm.getResourcesForApplication(statusResPackage);
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.w(TAG, "Contact status update resource package not found: "
|
||||
+ statusResPackage);
|
||||
resources = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (resources != null) {
|
||||
try {
|
||||
labelDisplayValue = resources.getString(statusLabel.intValue());
|
||||
} catch (NotFoundException e) {
|
||||
Log.w(TAG, "Contact status update resource not found: " + statusResPackage + "@"
|
||||
+ statusLabel.intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final CharSequence attribution;
|
||||
if (timestampDisplayValue != null && labelDisplayValue != null) {
|
||||
attribution = getContext().getString(
|
||||
R.string.contact_status_update_attribution_with_date,
|
||||
timestampDisplayValue, labelDisplayValue);
|
||||
} else if (timestampDisplayValue == null && labelDisplayValue != null) {
|
||||
attribution = getContext().getString(
|
||||
R.string.contact_status_update_attribution,
|
||||
labelDisplayValue);
|
||||
} else if (timestampDisplayValue != null) {
|
||||
attribution = timestampDisplayValue;
|
||||
} else {
|
||||
attribution = null;
|
||||
}
|
||||
setStatusAttribution(attribution);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for binding all available data from an existing
|
||||
* contact.
|
||||
*
|
||||
* @param contactLookupUri a {Contacts.CONTENT_LOOKUP_URI} style URI.
|
||||
*/
|
||||
public void bindFromContactLookupUri(Uri contactLookupUri) {
|
||||
bindFromContactUriInternal(contactLookupUri, true /* reset query handler */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for binding all available data from an existing
|
||||
* contact.
|
||||
*
|
||||
* @param contactUri a {Contacts.CONTENT_URI} style URI.
|
||||
* @param resetQueryHandler whether to use a new AsyncQueryHandler or not.
|
||||
*/
|
||||
private void bindFromContactUriInternal(Uri contactUri, boolean resetQueryHandler) {
|
||||
mContactUri = contactUri;
|
||||
startContactQuery(contactUri, resetQueryHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for binding all available data from an existing
|
||||
* contact.
|
||||
*
|
||||
* @param emailAddress The email address used to do a reverse lookup in
|
||||
* the contacts database. If more than one contact contains this email
|
||||
* address, one of them will be chosen to bind to.
|
||||
*/
|
||||
public void bindFromEmail(String emailAddress) {
|
||||
resetAsyncQueryHandler();
|
||||
|
||||
mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, emailAddress,
|
||||
Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(emailAddress)),
|
||||
EMAIL_LOOKUP_PROJECTION, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for binding all available data from an existing
|
||||
* contact.
|
||||
*
|
||||
* @param number The phone number used to do a reverse lookup in
|
||||
* the contacts database. If more than one contact contains this phone
|
||||
* number, one of them will be chosen to bind to.
|
||||
*/
|
||||
public void bindFromPhoneNumber(String number) {
|
||||
resetAsyncQueryHandler();
|
||||
|
||||
mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, number,
|
||||
Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)),
|
||||
PHONE_LOOKUP_PROJECTION, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* startContactQuery
|
||||
*
|
||||
* internal method to query contact by Uri.
|
||||
*
|
||||
* @param contactUri the contact uri
|
||||
* @param resetQueryHandler whether to use a new AsyncQueryHandler or not
|
||||
*/
|
||||
private void startContactQuery(Uri contactUri, boolean resetQueryHandler) {
|
||||
if (resetQueryHandler) {
|
||||
resetAsyncQueryHandler();
|
||||
}
|
||||
|
||||
mQueryHandler.startQuery(TOKEN_CONTACT_INFO, contactUri, contactUri, ContactQuery.COLUMNS,
|
||||
null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* startPhotoQuery
|
||||
*
|
||||
* internal method to query contact photo by photo id and uri.
|
||||
*
|
||||
* @param photoId the photo id.
|
||||
* @param lookupKey the lookup uri.
|
||||
* @param resetQueryHandler whether to use a new AsyncQueryHandler or not.
|
||||
*/
|
||||
protected void startPhotoQuery(long photoId, Uri lookupKey, boolean resetQueryHandler) {
|
||||
if (resetQueryHandler) {
|
||||
resetAsyncQueryHandler();
|
||||
}
|
||||
|
||||
mQueryHandler.startQuery(TOKEN_PHOTO_QUERY, lookupKey,
|
||||
ContentUris.withAppendedId(Data.CONTENT_URI, photoId), PhotoQuery.COLUMNS,
|
||||
null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to force this widget to forget everything it knows about the contact.
|
||||
* We need to stop any existing async queries for phone, email, contact, and photos.
|
||||
*/
|
||||
public void wipeClean() {
|
||||
resetAsyncQueryHandler();
|
||||
|
||||
setDisplayName(null, null);
|
||||
setPhoto(loadPlaceholderPhoto(null));
|
||||
setSocialSnippet(null);
|
||||
setPresence(0);
|
||||
mContactUri = null;
|
||||
mExcludeMimes = null;
|
||||
}
|
||||
|
||||
|
||||
private void resetAsyncQueryHandler() {
|
||||
// the api AsyncQueryHandler.cancelOperation() doesn't really work. Since we really
|
||||
// need the old async queries to be cancelled, let's do it the hard way.
|
||||
mQueryHandler = new QueryHandler(mContentResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the contact details provided by the given {@link Cursor}.
|
||||
*/
|
||||
protected void bindContactInfo(Cursor c) {
|
||||
final String displayName = c.getString(ContactQuery.DISPLAY_NAME);
|
||||
final String phoneticName = c.getString(ContactQuery.PHONETIC_NAME);
|
||||
this.setDisplayName(displayName, phoneticName);
|
||||
|
||||
final boolean starred = c.getInt(ContactQuery.STARRED) != 0;
|
||||
setStared(starred);
|
||||
|
||||
//Set the presence status
|
||||
if (!c.isNull(ContactQuery.CONTACT_PRESENCE_STATUS)) {
|
||||
int presence = c.getInt(ContactQuery.CONTACT_PRESENCE_STATUS);
|
||||
setPresence(presence);
|
||||
showPresence(true);
|
||||
} else {
|
||||
showPresence(false);
|
||||
}
|
||||
|
||||
//Set the status update
|
||||
final String status = c.getString(ContactQuery.CONTACT_STATUS);
|
||||
final Long statusTimestamp = c.isNull(ContactQuery.CONTACT_STATUS_TIMESTAMP)
|
||||
? null
|
||||
: c.getLong(ContactQuery.CONTACT_STATUS_TIMESTAMP);
|
||||
final Integer statusLabel = c.isNull(ContactQuery.CONTACT_STATUS_LABEL)
|
||||
? null
|
||||
: c.getInt(ContactQuery.CONTACT_STATUS_LABEL);
|
||||
final String statusResPackage = c.getString(ContactQuery.CONTACT_STATUS_RES_PACKAGE);
|
||||
|
||||
setStatus(status, statusTimestamp, statusLabel, statusResPackage);
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.star: {
|
||||
// Toggle "starred" state
|
||||
// Make sure there is a contact
|
||||
if (mContactUri != null) {
|
||||
final ContentValues values = new ContentValues(1);
|
||||
values.put(Contacts.STARRED, mStarredView.isChecked());
|
||||
mContentResolver.update(mContactUri, values, null, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case R.id.photo: {
|
||||
performPhotoClick();
|
||||
break;
|
||||
}
|
||||
case R.id.name: {
|
||||
performDisplayNameClick();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap loadPlaceholderPhoto(BitmapFactory.Options options) {
|
||||
if (mNoPhotoResource == 0) {
|
||||
return null;
|
||||
}
|
||||
return BitmapFactory.decodeResource(mContext.getResources(),
|
||||
mNoPhotoResource, options);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 883 B |
Binary file not shown.
|
Before Width: | Height: | Size: 671 B |
@@ -1,116 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/banner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/title_bar_medium"
|
||||
android:paddingRight="5dip">
|
||||
|
||||
<android.widget.QuickContactBadge android:id="@+id/photo"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginRight="8dip"
|
||||
android:layout_marginLeft="-1dip"
|
||||
style="@*android:style/Widget.QuickContactBadge.WindowSmall" />
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_vertical" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/aggregate_badge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="3dip"
|
||||
android:paddingTop="3dip"
|
||||
android:src="@drawable/ic_aggregated"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<TextView android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold"
|
||||
android:shadowColor="#BB000000"
|
||||
android:shadowRadius="2.75"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView android:id="@+id/phonetic_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:layout_marginTop="-2dip"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<TextView android:id="@+id/status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:layout_marginTop="-2dip"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<TextView android:id="@+id/status_date"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginTop="-2dip"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/presence"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingLeft="3dip"
|
||||
android:paddingRight="6dip"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/star"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:visibility="gone"
|
||||
android:contentDescription="@string/description_star"
|
||||
style="?android:attr/starStyle" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1421,12 +1421,6 @@
|
||||
<!-- Custom organization type -->
|
||||
<string name="orgTypeCustom">Custom</string>
|
||||
|
||||
<!-- Attbution of a contact status update, when the time of update is unknown -->
|
||||
<string name="contact_status_update_attribution">via <xliff:g id="source" example="Google Talk">%1$s</xliff:g></string>
|
||||
|
||||
<!-- Attbution of a contact status update, when the time of update is known -->
|
||||
<string name="contact_status_update_attribution_with_date"><xliff:g id="date" example="3 hours ago">%1$s</xliff:g> via <xliff:g id="source" example="Google Talk">%2$s</xliff:g></string>
|
||||
|
||||
<!-- Instructions telling the user to enter their SIM PIN to unlock the keyguard.
|
||||
Displayed in one line in a large font. -->
|
||||
<string name="keyguard_password_enter_pin_code">Enter PIN code</string>
|
||||
@@ -2270,12 +2264,6 @@
|
||||
<!-- Label for <input type="submit"> button in html -->
|
||||
<string name="submit">Submit</string>
|
||||
|
||||
<!-- String describing the Star/Favorite checkbox
|
||||
|
||||
Used by AccessibilityService to announce the purpose of the view.
|
||||
-->
|
||||
<string name="description_star">favorite</string>
|
||||
|
||||
<!-- Strings for car mode notification -->
|
||||
<!-- Shown when car mode is enabled -->
|
||||
<string name="car_mode_disable_notification_title">Car mode enabled</string>
|
||||
|
||||
@@ -684,7 +684,6 @@ com.android.internal.view.menu.ListMenuItemView
|
||||
com.android.internal.view.menu.MenuBuilder
|
||||
com.android.internal.view.menu.MenuItemImpl
|
||||
com.android.internal.view.menu.SubMenuBuilder
|
||||
com.android.internal.widget.ContactHeaderWidget
|
||||
com.android.internal.widget.DialogTitle
|
||||
com.android.internal.widget.EditableInputConnection
|
||||
com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
|
||||
|
||||
Reference in New Issue
Block a user