am 3c513ed9: Converting CallerInfo to new Contacts API.
Merge commit '3c513ed95cee2e0bcd7208cb7e46307f09c907c9' * commit '3c513ed95cee2e0bcd7208cb7e46307f09c907c9': Converting CallerInfo to new Contacts API.
This commit is contained in:
@@ -27,8 +27,7 @@ import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.provider.Contacts;
|
||||
import android.provider.Contacts.People;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
@@ -39,35 +38,35 @@ import java.io.InputStream;
|
||||
* Helper class for async access of images.
|
||||
*/
|
||||
public class ContactsAsyncHelper extends Handler {
|
||||
|
||||
|
||||
private static final boolean DBG = false;
|
||||
private static final String LOG_TAG = "ContactsAsyncHelper";
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a WorkerHandler result return.
|
||||
*/
|
||||
public interface OnImageLoadCompleteListener {
|
||||
/**
|
||||
* Called when the image load is complete.
|
||||
*
|
||||
*
|
||||
* @param imagePresent true if an image was found
|
||||
*/
|
||||
*/
|
||||
public void onImageLoadComplete(int token, Object cookie, ImageView iView,
|
||||
boolean imagePresent);
|
||||
}
|
||||
|
||||
|
||||
// constants
|
||||
private static final int EVENT_LOAD_IMAGE = 1;
|
||||
private static final int DEFAULT_TOKEN = -1;
|
||||
|
||||
|
||||
// static objects
|
||||
private static Handler sThreadHandler;
|
||||
private static ContactsAsyncHelper sInstance;
|
||||
|
||||
|
||||
static {
|
||||
sInstance = new ContactsAsyncHelper();
|
||||
}
|
||||
|
||||
|
||||
private static final class WorkerArgs {
|
||||
public Context context;
|
||||
public ImageView view;
|
||||
@@ -78,12 +77,12 @@ public class ContactsAsyncHelper extends Handler {
|
||||
public OnImageLoadCompleteListener listener;
|
||||
public CallerInfo info;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* public inner class to help out the ContactsAsyncHelper callers
|
||||
* with tracking the state of the CallerInfo Queries and image
|
||||
* public inner class to help out the ContactsAsyncHelper callers
|
||||
* with tracking the state of the CallerInfo Queries and image
|
||||
* loading.
|
||||
*
|
||||
*
|
||||
* Logic contained herein is used to remove the race conditions
|
||||
* that exist as the CallerInfo queries run and mix with the image
|
||||
* loads, which then mix with the Phone state changes.
|
||||
@@ -94,11 +93,11 @@ public class ContactsAsyncHelper extends Handler {
|
||||
public static final int DISPLAY_UNDEFINED = 0;
|
||||
public static final int DISPLAY_IMAGE = -1;
|
||||
public static final int DISPLAY_DEFAULT = -2;
|
||||
|
||||
|
||||
// State of the image on the imageview.
|
||||
private CallerInfo mCurrentCallerInfo;
|
||||
private int displayMode;
|
||||
|
||||
|
||||
public ImageTracker() {
|
||||
mCurrentCallerInfo = null;
|
||||
displayMode = DISPLAY_UNDEFINED;
|
||||
@@ -107,17 +106,17 @@ public class ContactsAsyncHelper extends Handler {
|
||||
/**
|
||||
* Used to see if the requested call / connection has a
|
||||
* different caller attached to it than the one we currently
|
||||
* have in the CallCard.
|
||||
* have in the CallCard.
|
||||
*/
|
||||
public boolean isDifferentImageRequest(CallerInfo ci) {
|
||||
// note, since the connections are around for the lifetime of the
|
||||
// call, and the CallerInfo-related items as well, we can
|
||||
// call, and the CallerInfo-related items as well, we can
|
||||
// definitely use a simple != comparison.
|
||||
return (mCurrentCallerInfo != ci);
|
||||
}
|
||||
|
||||
|
||||
public boolean isDifferentImageRequest(Connection connection) {
|
||||
// if the connection does not exist, see if the
|
||||
// if the connection does not exist, see if the
|
||||
// mCurrentCallerInfo is also null to match.
|
||||
if (connection == null) {
|
||||
if (DBG) Log.d(LOG_TAG, "isDifferentImageRequest: connection is null");
|
||||
@@ -133,57 +132,58 @@ public class ContactsAsyncHelper extends Handler {
|
||||
}
|
||||
return runQuery;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple setter for the CallerInfo object.
|
||||
* Simple setter for the CallerInfo object.
|
||||
*/
|
||||
public void setPhotoRequest(CallerInfo ci) {
|
||||
mCurrentCallerInfo = ci;
|
||||
mCurrentCallerInfo = ci;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenience method used to retrieve the URI
|
||||
* representing the Photo file recorded in the attached
|
||||
* CallerInfo Object.
|
||||
* Convenience method used to retrieve the URI
|
||||
* representing the Photo file recorded in the attached
|
||||
* CallerInfo Object.
|
||||
*/
|
||||
public Uri getPhotoUri() {
|
||||
if (mCurrentCallerInfo != null) {
|
||||
return ContentUris.withAppendedId(People.CONTENT_URI,
|
||||
return ContentUris.withAppendedId(Contacts.CONTENT_URI,
|
||||
mCurrentCallerInfo.person_id);
|
||||
}
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple setter for the Photo state.
|
||||
* Simple setter for the Photo state.
|
||||
*/
|
||||
public void setPhotoState(int state) {
|
||||
displayMode = state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple getter for the Photo state.
|
||||
* Simple getter for the Photo state.
|
||||
*/
|
||||
public int getPhotoState() {
|
||||
return displayMode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thread worker class that handles the task of opening the stream and loading
|
||||
* Thread worker class that handles the task of opening the stream and loading
|
||||
* the images.
|
||||
*/
|
||||
private class WorkerHandler extends Handler {
|
||||
public WorkerHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
WorkerArgs args = (WorkerArgs) msg.obj;
|
||||
|
||||
|
||||
switch (msg.arg1) {
|
||||
case EVENT_LOAD_IMAGE:
|
||||
InputStream inputStream = Contacts.People.openContactPhotoInputStream(
|
||||
InputStream inputStream = Contacts.openContactPhotoInputStream(
|
||||
args.context.getContentResolver(), args.uri);
|
||||
if (inputStream != null) {
|
||||
args.result = Drawable.createFromStream(inputStream, args.uri.toString());
|
||||
@@ -192,22 +192,22 @@ public class ContactsAsyncHelper extends Handler {
|
||||
" token: " + msg.what + " image URI: " + args.uri);
|
||||
} else {
|
||||
args.result = null;
|
||||
if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
|
||||
" token: " + msg.what + " image URI: " + args.uri +
|
||||
if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
|
||||
" token: " + msg.what + " image URI: " + args.uri +
|
||||
", using default image.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
// send the reply to the enclosing class.
|
||||
|
||||
// send the reply to the enclosing class.
|
||||
Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
|
||||
reply.arg1 = msg.arg1;
|
||||
reply.obj = msg.obj;
|
||||
reply.sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Private constructor for static class
|
||||
*/
|
||||
@@ -216,14 +216,14 @@ public class ContactsAsyncHelper extends Handler {
|
||||
thread.start();
|
||||
sThreadHandler = new WorkerHandler(thread.getLooper());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenience method for calls that do not want to deal with listeners and tokens.
|
||||
*/
|
||||
public static final void updateImageViewWithContactPhotoAsync(Context context,
|
||||
public static final void updateImageViewWithContactPhotoAsync(Context context,
|
||||
ImageView imageView, Uri person, int placeholderImageResource) {
|
||||
// Added additional Cookie field in the callee.
|
||||
updateImageViewWithContactPhotoAsync (null, DEFAULT_TOKEN, null, null, context,
|
||||
updateImageViewWithContactPhotoAsync (null, DEFAULT_TOKEN, null, null, context,
|
||||
imageView, person, placeholderImageResource);
|
||||
}
|
||||
|
||||
@@ -231,24 +231,24 @@ public class ContactsAsyncHelper extends Handler {
|
||||
* Convenience method for calls that do not want to deal with listeners and tokens, but have
|
||||
* a CallerInfo object to cache the image to.
|
||||
*/
|
||||
public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, Context context,
|
||||
public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, Context context,
|
||||
ImageView imageView, Uri person, int placeholderImageResource) {
|
||||
// Added additional Cookie field in the callee.
|
||||
updateImageViewWithContactPhotoAsync (info, DEFAULT_TOKEN, null, null, context,
|
||||
updateImageViewWithContactPhotoAsync (info, DEFAULT_TOKEN, null, null, context,
|
||||
imageView, person, placeholderImageResource);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Start an image load, attach the result to the specified CallerInfo object.
|
||||
* Note, when the query is started, we make the ImageView INVISIBLE if the
|
||||
* placeholderImageResource value is -1. When we're given a valid (!= -1)
|
||||
* placeholderImageResource value, we make sure the image is visible.
|
||||
*/
|
||||
public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, int token,
|
||||
OnImageLoadCompleteListener listener, Object cookie, Context context,
|
||||
public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, int token,
|
||||
OnImageLoadCompleteListener listener, Object cookie, Context context,
|
||||
ImageView imageView, Uri person, int placeholderImageResource) {
|
||||
|
||||
|
||||
// in case the source caller info is null, the URI will be null as well.
|
||||
// just update using the placeholder image in this case.
|
||||
if (person == null) {
|
||||
@@ -257,10 +257,10 @@ public class ContactsAsyncHelper extends Handler {
|
||||
imageView.setImageResource(placeholderImageResource);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Added additional Cookie field in the callee to handle arguments
|
||||
// sent to the callback function.
|
||||
|
||||
|
||||
// setup arguments
|
||||
WorkerArgs args = new WorkerArgs();
|
||||
args.cookie = cookie;
|
||||
@@ -270,15 +270,15 @@ public class ContactsAsyncHelper extends Handler {
|
||||
args.defaultResource = placeholderImageResource;
|
||||
args.listener = listener;
|
||||
args.info = info;
|
||||
|
||||
|
||||
// setup message arguments
|
||||
Message msg = sThreadHandler.obtainMessage(token);
|
||||
msg.arg1 = EVENT_LOAD_IMAGE;
|
||||
msg.obj = args;
|
||||
|
||||
if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
|
||||
|
||||
if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
|
||||
", displaying default image for now.");
|
||||
|
||||
|
||||
// set the default image first, when the query is complete, we will
|
||||
// replace the image with the correct one.
|
||||
if (placeholderImageResource != -1) {
|
||||
@@ -287,11 +287,11 @@ public class ContactsAsyncHelper extends Handler {
|
||||
} else {
|
||||
imageView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
|
||||
// notify the thread to begin working
|
||||
sThreadHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when loading is done.
|
||||
*/
|
||||
@@ -316,21 +316,21 @@ public class ContactsAsyncHelper extends Handler {
|
||||
args.view.setVisibility(View.VISIBLE);
|
||||
args.view.setImageResource(args.defaultResource);
|
||||
}
|
||||
|
||||
|
||||
// Note that the data is cached.
|
||||
if (args.info != null) {
|
||||
args.info.isCachedPhotoCurrent = true;
|
||||
}
|
||||
|
||||
|
||||
// notify the listener if it is there.
|
||||
if (args.listener != null) {
|
||||
if (DBG) Log.d(LOG_TAG, "Notifying listener: " + args.listener.toString() +
|
||||
if (DBG) Log.d(LOG_TAG, "Notifying listener: " + args.listener.toString() +
|
||||
" image: " + args.uri + " completed");
|
||||
args.listener.onImageLoadComplete(msg.what, args.cookie, args.view,
|
||||
imagePresent);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,15 +19,21 @@ package android.provider;
|
||||
import android.accounts.Account;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* The contract between the contacts provider and applications. Contains definitions
|
||||
* for the supported URIs and columns.
|
||||
@@ -299,6 +305,55 @@ public final class ContactsContract {
|
||||
*/
|
||||
public static final String CONTENT_DIRECTORY = "suggestions";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a URI that can be used to retrieve the contact's default photo.
|
||||
*
|
||||
* @param contactUri the contact whose photo should be used
|
||||
*/
|
||||
public static Uri getPhotoUri(ContentResolver cr, Uri contactUri) {
|
||||
long photoId = -1;
|
||||
Cursor cursor = cr.query(contactUri, new String[]{Contacts.PHOTO_ID}, null, null, null);
|
||||
try {
|
||||
if (!cursor.moveToNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cursor.isNull(0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
photoId = cursor.getLong(0);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, photoId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an InputStream for the person's default photo and returns the
|
||||
* photo as a Bitmap stream.
|
||||
*
|
||||
* @param contactUri the contact whose photo should be used
|
||||
*/
|
||||
public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
|
||||
Uri photoUri = getPhotoUri(cr, contactUri);
|
||||
Cursor cursor = cr.query(photoUri,
|
||||
new String[]{ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
|
||||
try {
|
||||
if (!cursor.moveToNext()) {
|
||||
return null;
|
||||
}
|
||||
byte[] data = cursor.getBlob(0);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
return new ByteArrayInputStream(data);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private interface RawContactsColumns {
|
||||
|
||||
@@ -20,9 +20,8 @@ import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.provider.Contacts;
|
||||
import android.provider.Contacts.People;
|
||||
import android.provider.Contacts.Phones;
|
||||
import android.provider.ContactsContract.PhoneLookup;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||
import android.text.TextUtils;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
@@ -134,44 +133,39 @@ public class CallerInfo {
|
||||
int columnIndex;
|
||||
|
||||
// Look for the name
|
||||
columnIndex = cursor.getColumnIndex(People.NAME);
|
||||
columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
|
||||
if (columnIndex != -1) {
|
||||
info.name = cursor.getString(columnIndex);
|
||||
}
|
||||
|
||||
// Look for the number
|
||||
columnIndex = cursor.getColumnIndex(Phones.NUMBER);
|
||||
columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
|
||||
if (columnIndex != -1) {
|
||||
info.phoneNumber = cursor.getString(columnIndex);
|
||||
}
|
||||
|
||||
// Look for the label/type combo
|
||||
columnIndex = cursor.getColumnIndex(Phones.LABEL);
|
||||
columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL);
|
||||
if (columnIndex != -1) {
|
||||
int typeColumnIndex = cursor.getColumnIndex(Phones.TYPE);
|
||||
int typeColumnIndex = cursor.getColumnIndex(PhoneLookup.TYPE);
|
||||
if (typeColumnIndex != -1) {
|
||||
info.numberType = cursor.getInt(typeColumnIndex);
|
||||
info.numberLabel = cursor.getString(columnIndex);
|
||||
info.phoneLabel = Contacts.Phones.getDisplayLabel(context,
|
||||
info.phoneLabel = Phone.getDisplayLabel(context,
|
||||
info.numberType, info.numberLabel)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the person ID
|
||||
columnIndex = cursor.getColumnIndex(Phones.PERSON_ID);
|
||||
columnIndex = cursor.getColumnIndex(PhoneLookup._ID);
|
||||
if (columnIndex != -1) {
|
||||
info.person_id = cursor.getLong(columnIndex);
|
||||
} else {
|
||||
columnIndex = cursor.getColumnIndex(People._ID);
|
||||
if (columnIndex != -1) {
|
||||
info.person_id = cursor.getLong(columnIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// look for the custom ringtone, create from the string stored
|
||||
// in the database.
|
||||
columnIndex = cursor.getColumnIndex(People.CUSTOM_RINGTONE);
|
||||
columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE);
|
||||
if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) {
|
||||
info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex));
|
||||
} else {
|
||||
@@ -180,7 +174,7 @@ public class CallerInfo {
|
||||
|
||||
// look for the send to voicemail flag, set it to true only
|
||||
// under certain circumstances.
|
||||
columnIndex = cursor.getColumnIndex(People.SEND_TO_VOICEMAIL);
|
||||
columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL);
|
||||
info.shouldSendToVoicemail = (columnIndex != -1) &&
|
||||
((cursor.getInt(columnIndex)) == 1);
|
||||
info.contactExists = true;
|
||||
@@ -256,8 +250,7 @@ public class CallerInfo {
|
||||
}
|
||||
}
|
||||
|
||||
Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL,
|
||||
Uri.encode(number));
|
||||
Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number);
|
||||
|
||||
CallerInfo info = getCallerInfo(context, contactUri);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.provider.Contacts;
|
||||
import android.provider.ContactsContract.PhoneLookup;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
@@ -303,7 +303,7 @@ public class CallerInfoAsyncQuery {
|
||||
public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
|
||||
OnQueryCompleteListener listener, Object cookie) {
|
||||
//contruct the URI object and start Query.
|
||||
Uri contactRef = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, number);
|
||||
Uri contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number);
|
||||
|
||||
CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
|
||||
c.allocate(context, contactRef);
|
||||
|
||||
Reference in New Issue
Block a user