I am looking for a way to get the contacts in the favorites list inside service from phone number or from name it dose not matter. Can any one help me with this?
It's not important to use any code related to this code
I found in the developer.android.com something like this (IN_VISIBLE_GROUP).
How to use this variable in my case?
case (PICK_CONTACT):
if (resultCode == Activity.RESULT_OK) {
Uri contactData = data.getData();
Cursor c = managedQuery(contactData, null, null, null, null);
ContentResolver cr = getContentResolver();
if (c.moveToFirst()) {
String name = c.getString(c.getColumnIndexOrThrow(People.NAME));
String id =c.getString(c.getColumnIndexOrThrow(People._ID));
Cursor phones = cr.query(Phone.CONTENT_URI, null,
Phone.CONTACT_ID + " = " + id, null, null);
}
Lets assume that you are searching a contact by name..
If you want to get Favourite value of all the possible contacts , drop the selection parameter in the given code.
//First get the contact ID from a display name as:-
String displayName = "Albert Einstein";
Uri contacts = ContactsContract.Contacts.CONTENT_URI;
cur = cr.query(contacts, null, ContactsContract.Contacts.DISPLAY_NAME +"="+displayName,null, null);
int contactIdIndex = cur.getColumnIndex(ContactsContract.PhoneLookup._ID);
int contactId = cur.getInt(contactIdIndex);
//Make a query to get the Starred value:-
Cursor starred = cr.query(ContactsContract.Contacts.CONTENT_URI,
new String[] { ContactsContract.Contacts.STARRED },
ContactsContract.Contacts._ID + " = " + contactId,
null, null);
if (starred != null && starred.moveToFirst())
{
int fav = starred.getInt(0);
}
if (starred != null)
starred.close();
}
You can drop the step of getting Contact ID and then querying for Starred value and directly query based on Display name
Something like this?
final private static class DataQuery {
public static final int COLUMN_MIMETYPE = 1;
public static final int COLUMN_PHONE = 2;
public static final int COLUMN_RAWCONTACT_ID = 3;
public static final int COLUMN_PHONE_NUMBER = COLUMN_DATA1;
public static final String[] PROJECTION = new String[] { Data._ID, Data.MIMETYPE, Data.DATA1, Data.RAW_CONTACT_ID };
public static final String SELECTION_PHONE = Data.DATA1 + "=?";
}
long findContact(Context context, String number) {
long rawContactId = -1;
final Cursor cursor = context.getContentResolver().query(Data.CONTENT_URI, DataQuery.PROJECTION, DataQuery.SELECTION_PHONE, new String[] { number }, null);
try {
if (cursor.moveToFirst()) {
rawContactId = cursor.getLong(DataQuery.COLUMN_RAWCONTACT_ID);
}
} finally {
if (cursor != null)
cursor.close();
}
return rawContactId;
}
Ok let's try with this...
private static final Uri DATAGROUP_CONTENT_URI = ContactsContract.Data.CONTENT_URI.buildUpon().appendQueryParameter(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE).build();
public static void querytGroups(Context context) {
final ContentResolver resolver = context.getContentResolver();
long groupid=getGroupId(resolver, "Family");
final Cursor c = resolver.query(DATAGROUP_CONTENT_URI, DataQueryForContactsInGroup.PROJECTION, DataQueryForContactsInGroup.SELECTION, new String[] {ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(groupid)}, null);
try {
while (c.moveToNext()) {
final long rawContactId = c.getLong(DataQueryForContactsInGroup.RAW_CONTACT_ID);
//do something
}
}finally {
c.close();
}
}
private static long getGroupId(final ContentResolver resolver, String groupName) {
long groupid = -1;
Cursor cur = null;
try {
cur = resolver.query(Groups.CONTENT_URI, DataQueryForGroup.PROJECTION, DataQueryForGroup.SELECTION, new String[]{"%"+groupName+"%"}, null);
while (cur.moveToNext()) {
return groupid= cur.getLong(DataQueryForGroup.GROUP_ID);
}
}finally {
if (cur!=null) cur.close();
}
return groupid;
}
private interface DataQueryForGroup {
public final static String[] PROJECTION = new String[] {Groups._ID};
public static final String SELECTION = Groups.TITLE+" LIKE ?";
public final static int GROUP_ID = 0;
}
private interface DataQueryForContactsInGroup {
public final static String[] PROJECTION = new String[] { Data.RAW_CONTACT_ID };
public static final String SELECTION = "("+Data.MIMETYPE + "=?) and ("+ ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID+ "=?)";
public final static int RAW_CONTACT_ID = 0;
}
Please consider that if your google account is not English you need to look for the proper group's name
Related
I want to display contacts, which has phone numbers, but with all assigned numbers. I want to improve the performance. Is there any more effective way to do this? Like obtaining all contacts thumbnails at once? This approach somehow fails for me, as the cursor is not empty, but returns empty(?) uri.
I have done some time tracking and it looks like appendContactNumber() takes to execute from 15 ms (one phone number) up to about 20 ms (three phone numbers).
// List specific variables
private static ArrayList<String> Contacts;
private static ArrayList<String> Numbers;
private static ArrayList<Bitmap> Photo;
// ContentResolver query specific variables
private static final Uri CONTACTS_URI = ContactsContract.Contacts.CONTENT_URI;
private static final String[] CONTACTS_PROJECTION = {
ContactsContract.Contacts._ID,
};
private static final String CONTACTS_SELECTION = ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1";
private static final String CONTACTS_SORT_ORDER = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
private static final Uri PHONES_URI = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
private static final String[] PHONE_PROJECTION = {
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER
};
private static final String PHONE_SELECTION = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ";
private static final String[] PHOTO_PROJECTION = { ContactsContract.Contacts.Photo.PHOTO };
private Context context;
public ContactsLoader(Context context) {
this.context = context;
}
#Override
public void run()
{
loadContacts();
}
private void loadContacts() {
Contacts = new ArrayList<>();
Numbers = new ArrayList<>();
Photo = new ArrayList<>();
// Retrieve all contacts with phone numbers
Cursor contactsCursor = context.getContentResolver().query(
CONTACTS_URI,
CONTACTS_PROJECTION,
CONTACTS_SELECTION,
null,
CONTACTS_SORT_ORDER
);
if (contactsCursor != null) {
while (contactsCursor.moveToNext()) {
appendContactNumber(contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.Contacts._ID)));
}
contactsCursor.close();
}
}
private void appendContactNumber(final String contactId) {
// Retrieve phone numbers for contact specified by id
Cursor numbersCursor = context.getContentResolver().query(
PHONES_URI,
PHONE_PROJECTION,
PHONE_SELECTION + contactId,
null,
null
);
// If phone numbers cursor is not empty
if (numbersCursor != null) {
Bitmap thumbnail = getContactThumb(contactId);
while (numbersCursor.moveToNext()) {
Contacts.add(numbersCursor.getString(numbersCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
Numbers.add(numbersCursor.getString(numbersCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
Photo.add(thumbnail);
}
numbersCursor.close();
}
}
private Bitmap getContactThumb(final String contactId) {
// Get contact thumbnail for given contactId
Uri contactUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(contactId));
Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
Cursor thumbnailCursor = context.getContentResolver().query(
photoUri,
PHOTO_PROJECTION,
null,
null,
null
);
if (thumbnailCursor != null) {
// If contact thumbnail is not empty
if (thumbnailCursor.moveToFirst()) {
Bitmap contactPhoto = BitmapFactory.decodeStream(new ByteArrayInputStream(thumbnailCursor.getBlob(0)));
thumbnailCursor.close();
return contactPhoto;
}
}
// Default Bitmap
return BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_contact_picture);
}
I did some workaround: rather than query for Bitmap it is faster to get photo URI. Here is my code:
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.util.Log;
import java.util.ArrayList;
public class PhoneContactsLoader extends ContactsLoader {
// Class specific variables
private ArrayList<String> Numbers;
public PhoneContactsLoader(Context context) {
super(context);
// ContentResolver query specific variables
URI = ContactsContract.CommonDataKinds.Phone.CONTENT_URI.toString();
PROJECTION = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.Contacts.PHOTO_URI
};
SELECTION = ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1";
SORT_ORDER = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
}
#Override
protected void fetchContacts() {
Contacts = new ArrayList<>();
Numbers = new ArrayList<>();
Photos = new ArrayList<>();
Long timer = System.currentTimeMillis();
// Retrieve all contacts containing phone numbers
Cursor contactsCursor = context.getContentResolver().query(
Uri.parse(URI),
PROJECTION,
SELECTION,
null,
SORT_ORDER
);
if (contactsCursor != null) {
while (contactsCursor.moveToNext()) {
Contacts.add(contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
Numbers.add(contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
String photoUri = contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.Contacts.PHOTO_URI));
if (photoUri != null)
Photos.add(photoUri);
else
Photos.add("useDefault");
}
contactsCursor.close();
}
Log.i("PhoneContactsLoader", "Thread execution time: " + (System.currentTimeMillis() - timer) + " ms");
}
#Override
public ArrayList<String> getNumbers() {
return Numbers;
}
}
I’m trying to get phone number from contacts by providing the phone number. what I've done so far:
public static String getPhone(Context context, String displayName) {
ContentResolver cr = context.getContentResolver();
Uri uri = CommonDataKinds.Phone.CONTENT_URI;
String selection = CommonDataKinds.Phone.DISPLAY_NAME+" LIKE '%" + displayName + "&'";
Cursor cursor = cr.query(uri, new String[]{CommonDataKinds.Phone._ID,CommonDataKinds.Phone.DISPLAY_NAME,CommonDataKinds.Phone.NUMBER}, selection, null, null);
if (cursor == null) {
return null;
}
String contactName = null;
if(cursor.moveToFirst()) {
contactName = cursor.getString(cursor.getColumnIndex(CommonDataKinds.Phone.NUMBER));
}
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
//Log.d("Contact",contactName.toString());
return contactName;
}
Try this code out. You will need to set the permission in the manifest "android.permission.READ_CONTACTS" on true.
public String getPhoneNumber(String name, Context context) {
String ret = null;
String selection = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+" like'%" + name +"%'";
String[] projection = new String[] { ContactsContract.CommonDataKinds.Phone.NUMBER};
Cursor c = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection, selection, null, null);
if (c.moveToFirst()) {
ret = c.getString(0);
}
c.close();
if(ret==null)
ret = "Unsaved";
return ret;
}
UPDATE:
This code snippet will allow you to read all messages from a particular contact:
StringBuilder smsBuilder = new StringBuilder();
final String SMS_URI_INBOX = "content://sms/inbox";
final String SMS_URI_ALL = "content://sms/";
try {
Uri uri = Uri.parse(SMS_URI_INBOX);
String[] projection = new String[] { "_id", "address", "person", "body", "date", "type" };
Cursor cur = getContentResolver().query(uri, projection, "address='123456789'", null, "date desc");
if (cur.moveToFirst()) {
int index_Address = cur.getColumnIndex("address");
int index_Person = cur.getColumnIndex("person");
int index_Body = cur.getColumnIndex("body");
int index_Date = cur.getColumnIndex("date");
int index_Type = cur.getColumnIndex("type");
do {
String strAddress = cur.getString(index_Address);
int intPerson = cur.getInt(index_Person);
String strbody = cur.getString(index_Body);
long longDate = cur.getLong(index_Date);
int int_Type = cur.getInt(index_Type);
smsBuilder.append("[ ");
smsBuilder.append(strAddress + ", ");
smsBuilder.append(intPerson + ", ");
smsBuilder.append(strbody + ", ");
smsBuilder.append(longDate + ", ");
smsBuilder.append(int_Type);
smsBuilder.append(" ]\n\n");
} while (cur.moveToNext());
if (!cur.isClosed()) {
cur.close();
cur = null;
}
} else {
smsBuilder.append("no result!");
} // end if
}
} catch (SQLiteException ex) {
Log.d("SQLiteException", ex.getMessage());
}
I want to display all native contacts in a list and make user to add contacts from the list (Multiple contacts)to my application database.How to dothis can any one give me idea or share some code..
thanks in advance..
I used this code on Android 2.1. It pulls down anyone who has a phone number (as defined by the String SELECTION variable) and returns a List of type Person. Person is an object that held the name and phone number of the user. You will have to implement a Person object in order to use this code, but it works perfectly:
public List<Person> getContactList(){
ArrayList<Person> contactList = new ArrayList<Person>();
Uri contactUri = ContactsContract.Contacts.CONTENT_URI;
String[] PROJECTION = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER,
};
String SELECTION = ContactsContract.Contacts.HAS_PHONE_NUMBER + "='1'";
Cursor contacts = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, null, null);
if (contacts.getCount() > 0)
{
while(contacts.moveToNext()) {
Person aContact = new Person();
int idFieldColumnIndex = 0;
int nameFieldColumnIndex = 0;
int numberFieldColumnIndex = 0;
String contactId = contacts.getString(contacts.getColumnIndex(ContactsContract.Contacts._ID));
nameFieldColumnIndex = contacts.getColumnIndex(PhoneLookup.DISPLAY_NAME);
if (nameFieldColumnIndex > -1)
{
aContact.setName(contacts.getString(nameFieldColumnIndex));
}
PROJECTION = new String[] {Phone.NUMBER};
final Cursor phone = managedQuery(Phone.CONTENT_URI, PROJECTION, Data.CONTACT_ID + "=?", new String[]{String.valueOf(contactId)}, null);
if(phone.moveToFirst()) {
while(!phone.isAfterLast())
{
numberFieldColumnIndex = phone.getColumnIndex(Phone.NUMBER);
if (numberFieldColumnIndex > -1)
{
aContact.setPhoneNum(phone.getString(numberFieldColumnIndex));
phone.moveToNext();
TelephonyManager mTelephonyMgr;
mTelephonyMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (!mTelephonyMgr.getLine1Number().contains(aContact.getPhoneNum()))
{
contactList.add(aContact);
}
}
}
}
phone.close();
}
contacts.close();
}
return contactList;
}
EDIT: A rudimentary Person class:
public class Person {
String myName = "";
String myNumber = "";
public String getName() {
return myName;
}
public void setName(String name) {
myName = name;
}
public String getPhoneNum() {
return myNumber;
}
public void setPhoneNum(String number) {
myNumber = number;
}
}
This code works perfectly in android 4.2. And it works much faster, because you don't make additional query for each contact
private static final String CONTACT_ID = ContactsContract.Contacts._ID;
private static final String DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME;
private static final String HAS_PHONE_NUMBER = ContactsContract.Contacts.HAS_PHONE_NUMBER;
private static final String PHONE_NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER;
private static final String PHONE_CONTACT_ID = ContactsContract.CommonDataKinds.Phone.CONTACT_ID;
public static ArrayList<Contact> getAll(Context context) {
ContentResolver cr = context.getContentResolver();
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[]{PHONE_NUMBER, PHONE_CONTACT_ID},
null,
null,
null
);
if(pCur != null){
if(pCur.getCount() > 0) {
HashMap<Integer, ArrayList<String>> phones = new HashMap<>();
while (pCur.moveToNext()) {
Integer contactId = pCur.getInt(pCur.getColumnIndex(PHONE_CONTACT_ID));
ArrayList<String> curPhones = new ArrayList<>();
if (phones.containsKey(contactId)) {
curPhones = phones.get(contactId);
}
curPhones.add(pCur.getString(pCur.getColumnIndex(PHONE_CONTACT_ID)));
phones.put(contactId, curPhones);
}
Cursor cur = cr.query(
ContactsContract.Contacts.CONTENT_URI,
new String[]{CONTACT_ID, DISPLAY_NAME, HAS_PHONE_NUMBER},
HAS_PHONE_NUMBER + " > 0",
null,
DISPLAY_NAME + " ASC");
if (cur != null) {
if (cur.getCount() > 0) {
ArrayList<Contact> contacts = new ArrayList<>();
while (cur.moveToNext()) {
int id = cur.getInt(cur.getColumnIndex(CONTACT_ID));
if(phones.containsKey(id)) {
Contact con = new Contact();
con.setMyId(id);
con.setName(cur.getString(cur.getColumnIndex(DISPLAY_NAME)));
con.setPhone(TextUtils.join(",", phones.get(id).toArray()));
contacts.add(con);
}
}
return contacts;
}
cur.close();
}
}
pCur.close();
}
return null;
}
Class Contact is similar to class Person from the answer.
I've spent a lot of hours searching and reading similar posts, but none of them seem to truly reflect my problem and thus I haven't found anything that works for me.
I've got a database, on which I perform a query, the results of which are stored in a cursor. There's two things to that:
-the query is performed everytime a certain button is pressed (thus the query is inside the OnClickListener for that Button)
-the query returns two different columns with String values, which must be treated separately (one column stores the names which must be shown in the ListView, the other stores the paths to the image associated toa row)
My problem is, I try to create a String[] which I need to pass to the ArrayAdapter creator for the ListView, but trying to assign it a size of Cursor getCount() crashes my activity. I hope the code will be more of an explanation:
OnClickListener searchListener = new OnClickListener() {
public void onClick(View v) {
CardDatabaseOpenHelper helper = new
CardDatabaseOpenHelper(DeckEditorScreen1.this);
SQLiteDatabase db = helper.getReadableDatabase();
String columns[] = {"name","number","path"};
Cursor c = db.query("cards", columns, null, null, null, null, "number");
int count = c.getCount();
String[] resultNameStrings;
if (count != 0) resultNameStrings = new String[count];
else {resultNameStrings = new String[1]; resultNameStrings[1] = "No results";}
// This is the offending code
//Note that if I assign fixed values to resutNameStrings, the code works just
//fine
for (int i = 0; i < count; ++i) {
c.moveToNext();
int col = c.getColumnIndex("name");
String s = c.getString(col);
//Ideally here I would to something like:
//resultNameStrings[i] = s;
col = c.getColumnIndex("number");
int conv = c.getInt(col);
col = c.getColumnIndex("path");
String s2 = c.getString(col);
}
db.close();
ArrayAdapter<?> searchResultItemAdapter = new ArrayAdapter<String>
(DBScreen.this,
R.layout.search_result_item,
resultNameStrings);
ListView searchResultList = (ListView)
DBScreen.this.findViewById(R.id.search_result_list);
searchResultList.setAdapter(searchResultItemAdapter);
}
};
Button search_button = (Button) findViewById(R.id.search_button);
search_button.setOnClickListener(searchListener);
EDITED twice :)
do it in "Android Way" ...
first use CursorAdapter (fx.: SimpleCursorAdapter with overrided
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
Cursor cursor = managedQuery(MobileTraderProvider.CONTENT_URI,
null, null, new String[] { constraint.toString() }, null);
return cursor;
}
then
customAdapter.getFilter().filter(filterText)
// it will call runQueryOnBackgroundThread
second use ContentProvider(it will manage curosors for you ... it will even requery if data changed)
EDIT:
first really use my advice
second before
for (int i = 0; i < count; ++i) {
c.moveToNext();
//...
add c.moveToFirst();
thrid: use
if(c.moveToNext())
{
int col = c.getColumnIndex("name");
//..... rest goes here
}
SECOND EDIT:
MyProvider.java
public class MyProvider extends ContentProvider {
static final String LTAG = "MyAppName";
public static final Uri CONTENT_URI = Uri.parse("content://my.app.Content");
static final int CARDS = 1;
static final int CARD = 2;
public static final String CARDS_MIME_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/Cards";
public static final String CARD_MIME_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/Cards";
static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
static final HashMap<String, String> map = new HashMap<String, String>();
static {
//static "Constructor"
matcher.addURI(Constants.AUTHORITY, "Cards", LISTS);
matcher.addURI(Constants.AUTHORITY, "Cards/*", LIST);
map.put(BaseColumns._ID, "ROWID AS _id");
map.put(Tables.Cards.C_NAME, Tables.Cards.C_NAME);
map.put(Tables.Cards.C_NUMBER, Tables.Cards.C_NUMBER);
map.put(Tables.Cards.C_PATH, Tables.Cards.C_PATH);
}
private CardDatabaseOpenHelper mDB;
#Override
public boolean onCreate() {
try {
mDB = new CardDatabaseOpenHelper(getContext());
} catch (Exception e) {
Log.e(LTAG, e.getLocalizedMessage());
}
return true;
}
public int delete(Uri uri, String selection, String[] selectionArgs) {
String table = null;
switch (matcher.match(uri)) {
case CARD:
//overriding selection and selectionArgs
selection = "ROWID=?";
selectionArgs = new String[] { uri.getPathSegments().get(1) };
table = uri.getPathSegments().get(0);
break;
case CARDS:
//this version will delete all rows if you dont provide selection and selectionargs
table = uri.getPathSegments().get(0);
break;
default:
throw new IllegalArgumentException("Unknown URL " + uri);
}
int ret = mDB.getWritableDatabase().delete(table, selection, selectionArgs);
getContext().getContentResolver().notifyChange(Uri.withAppendedPath(CONTENT_URI, table), null);
return ret;
}
#Override
public String getType(Uri uri) {
switch (matcher.match(uri)) {
case CARDS:
return CARDS_MIME_TYPE;
case CARD:
return CARD_MIME_TYPE;
default:
throw new IllegalArgumentException("Unknown URL " + uri);
}
}
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
String table, rowid;
switch (matcher.match(uri)) {
case CARD:
//overriding selection and selectionArgs
selection = "ROWID=?";
selectionArgs = new String[] { uri.getPathSegments().get(1) };
table = uri.getPathSegments().get(0);
break;
case CARDS:
//this version will update all rows if you dont provide selection and selectionargs
table = uri.getPathSegments().get(0);
break;
default:
throw new IllegalArgumentException("Unknown URL " + uri);
}
int ret = mDB.getWritableDatabase().update(table, values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(Uri.withAppendedPath(CONTENT_URI, table), null);
return ret;
}
public Uri insert(Uri uri, ContentValues values) {
String table = null;
switch (matcher.match(uri)) {
case CARDS:
table = uri.getPathSegments().get(0);
break;
default:
throw new IllegalArgumentException("Unknown URL " + uri);
}
mDB.getWritableDatabase().insert(table, null, values);
getContext().getContentResolver().notifyChange(Uri.withAppendedPath(CONTENT_URI, table), null);
return null;
}
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
switch (matcher.match(uri)) {
case CARDS:
builder.setTables(uri.getPathSegments().get(0));
break;
case CARD:
builder.setTables(uri.getPathSegments().get(0));
selection = "ROWID=?";
selectionArgs = new String[] { uri.getPathSegments().get(1) };
default:
throw new IllegalArgumentException("Unknown URL " + uri);
}
builder.setProjectionMap(map);
Cursor cursor = builder.query(mDB.getReadableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
if (cursor == null) {
return null;
}
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
}
CardCursorAdapter.java
class CardCursorAdapter extends SimpleCursorAdapter {
public MyCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
}
#Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
//search in cards.name
String selection = Tables.Cards.C_NAME + " LIKE ?";
String[] selectionArgs = new String[] {"%" + constraint.toString() + "%"};
Cursor cursor = managedQuery(Uri.withAppendedPath(MyProvider.CONTENT_URI, Tables.Cards.Name),
getCursor().getColumnNames(), selection, selectionArgs, null);
return cursor;
}
}
Tables.java
public static class Tables {
//table definition
public static interface Cards {
public static final String NAME = "cards";
public static final String C_NAME = "name";
public static final String C_NUMBER = "number";
public static final String C_PATH = "path";
}
//other tables go here
}
AndroidManifest.xml
</manifest>
</application>
<!-- ....... other stuff ....... -->
<provider android:name="MyProvider" android:authorities="my.app.Content" />
</application>
</manifest>
then in activity
onCreate(...){
listView.setAdapter(new CardCursorAdapter(this, R.layout.listrow,
managedQuery(Uri.withAppendedPath(MyProvider.CONTENT_URI, Tables.Cards.NAME),
new String[] { BaseColumns._ID, Tables.Cards.C_NAME, Tables.Cards.C_NUMBER, Tables.Cards.C_PATH },
null,null, number),
new String[] { Tables.Cards.C_NAME, Tables.Cards.C_NUMBER, Tables.Cards.C_PATH },
new int[] { R.id.tName, R.id.tNumber, R.id.tPath }));
}
OnClickListener searchListener = new OnClickListener() {
public void onClick(View v) {
DeckEditorScreen1.this.listView.getAdapter().getFilter().filter("text for search in name column of card table set me to empty for all rows");
}
}
Ok, I've done some testing and I think I know what was the problem. Java allows constructs like:
String[] whatever;
if (something) whatever = new String[avalue];
else whatever = new String[anothervalue];
The crash occurs if you don't assign a concrete value to each and every field whatever[i]. The rest of the code is now just fine, though I've added Selvin's correction
if (c.moveToNext) ...
c.moveToFirst() is not correctly used in my case, as the for iterates count times. If you perform a moveToFirst first, you're always missing the first element pointed by the cursor.
Cursor cursor = resolver.query(
Data.CONTENT_URI,
DataQuery.PROJECTION,
DataQuery.SELECTION,
new String[] {String.valueOf(rawContactId)},
null);
With PROJECTION being:
public static final String[] PROJECTION = new String[] {
Data._ID,
Data.MIMETYPE,
Data.DATA1,
Data.DATA2,
Data.DATA3};
and SELECTION being:
public static final String SELECTION = Data.RAW_CONTACT_ID + "=?";
The rawcontactId does return values, I've made logs to check. To give it some context I'm working with Account sync. The goal here is for it to find the data columns for existing contacts and writing over them with any new data. I'm working from the following sample code provided by android: http://developer.android.com/resources/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.html
To summarize my problem, I have two contacts via this synced account which are added without any problems, but are not being able to be updated. Anyone have experience with this? Thanks.
EDIT: Here is my rawContact returning method
private static long lookupRawContact(ContentResolver resolver, String username) {
Log.e("Looking up Raw Contact", username);
long authorId = 0;
Cursor cursor = resolver.query(
Data.CONTENT_URI,
UserIdQuery.PROJECTION,
UserIdQuery.SELECTION,
new String[] {username},
null);
try {
if(cursor != null && cursor.moveToFirst()) {
authorId = cursor.getLong(UserIdQuery.COLUMN_ID);
}
} finally {
if(cursor != null) {
cursor.close();
}
}
return authorId;
}
The numbers I get back are like 3061. Here is the UserIdQuery class:
final private static class UserIdQuery {
private UserIdQuery() {
}
public final static String[] PROJECTION = new String[] {RawContacts._ID};
public final static int COLUMN_ID = 0;
public static final String SELECTION = RawContacts.ACCOUNT_TYPE + "='" +
"com.tagapp.android" + "' AND " + RawContacts.SOURCE_ID + "=?";
}
And here is my constructor for a ContactSyncOperations class being used to add a new contact. The source id here is a username, the same as I call in my SELECTION argument.
public ContactSyncOperations(Context context, String username,
String accountName, BatchOperationForSync batchOperation) {
this(context, batchOperation);
mBackReference = mBatchOperation.size();
mIsNewContact = true;
mValues.put(RawContacts.SOURCE_ID, username);
mValues.put(RawContacts.ACCOUNT_TYPE, "com.tagapp.android");
mValues.put(RawContacts.ACCOUNT_NAME, accountName);
mBuilder = newInsertCpo(RawContacts.CONTENT_URI, true).withValues(mValues);
mBatchOperation.add(mBuilder.build());
}
Thanks!
There was an error in the lookupRawContactId method, the rawcontactId long I was getting wasn't the right one. It should have looked like this:
private static long lookupRawContact(ContentResolver resolver, String username) {
Log.e("Looking up Raw Contact", username);
long authorId = 0;
Cursor cursor = resolver.query(
RawContacts.CONTENT_URI,
UserIdQuery.PROJECTION,
UserIdQuery.SELECTION,
new String[] {username},
null);
try {
if(cursor != null && cursor.moveToFirst()) {
authorId = cursor.getLong(UserIdQuery.COLUMN_ID);
}
} finally {
if(cursor != null) {
cursor.close();
}
}
return authorId;
}
There are a few issues that i could locate with the following query:
Cursor cursor = resolver.query(Data.CONTENT_URI,
UserIdQuery.PROJECTION,
UserIdQuery.SELECTION,
new String[] {username}, null);
If all the columns are pointing out at RawContacts table then you should use RawContacts.CONTENT_URI instead of Data.CONTENT_URI.
Here the value of RawContacts.SOURCE_ID is compared with username
public static final String SELECTION = RawContacts.ACCOUNT_TYPE + "='" +
"com.tagapp.android" + "' AND " + RawContacts.SOURCE_ID + "=?";
new String[] {username}