Best way to access all the details of android contacts - android

I am writing an application to sync contact details with my server. For this I need to query Contacts using content provider multiple times as all the data is not present in one table. For example by using contact id, I have to query separately to phone, email and address tables for each contact which I feel is not much efficient. It would be really helpful if someone could point me out ways to get all the contact details in a single query. Thanks in advance :)

If you have the rawContactId you don't need multiple query. You can have a single query with Data.CONTENT_URI as uri and with a selection on your rawContactId.
The you have to loop with the resulting cursor to read the info. To know in wich column you need to see for a given row in the Data table you need to check the MIMETYPE
EDIT
private interface DataQuery {
public static final String[] PROJECTION = new String[] { Data._ID, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3, };
public static final int COLUMN_ID = 0;
public static final int COLUMN_MIMETYPE = 1;
public static final int COLUMN_DATA1 = 2;
public static final int COLUMN_DATA2 = 3;
public static final int COLUMN_DATA3 = 4;
public static final int COLUMN_PHONE_NUMBER = COLUMN_DATA1;
public static final int COLUMN_PHONE_TYPE = COLUMN_DATA2;
public static final int COLUMN_GIVEN_NAME = COLUMN_DATA2;
public static final int COLUMN_FAMILY_NAME = COLUMN_DATA3;
public static final String SELECTION = Data.RAW_CONTACT_ID + "=?";
}
final Cursor c = resolver.query(Data.CONTENT_URI, DataQuery.PROJECTION, DataQuery.SELECTION, new String[] { String.valueOf(rawContactId) }, null);
try {
while (c.moveToNext()) {
final long id = c.getLong(DataQuery.COLUMN_ID);
final String mimeType = c.getString(DataQuery.COLUMN_MIMETYPE);
uri = ContentUris.withAppendedId(Data.CONTENT_URI, id);
if (mimeType.equals(StructuredName.CONTENT_ITEM_TYPE)) {
final String oldLastName = c.getString(DataQuery.COLUMN_FAMILY_NAME);
final String oldFirstName = c.getString(DataQuery.COLUMN_GIVEN_NAME);
//store them where you need
} else if (mimeType.equals(Phone.CONTENT_ITEM_TYPE)) {
final int type = c.getInt(DataQuery.COLUMN_PHONE_TYPE);
final String cellPhone = c.getString(DataQuery.COLUMN_PHONE_NUMBEIR);
//store them where you need
}
}
} // while
} finally {
if (c!=null) c.close();
}
Please consider that I did not check the code: I do not have a compiler here. I hope it will be useful anyway

Data is a generic table that can hold any kind of contact data.
The kind of data stored in a given row is specified by the row's MIMETYPE value, which determines the meaning of the generic columns DATA1 through DATA15.
For example, if the data kind is Phone.CONTENT_ITEM_TYPE, then the column DATA1 stores the phone number, but if the data kind is Email.CONTENT_ITEM_TYPE, then DATA1 stores the email address. Sync adapters and applications can introduce their own data kinds.

Related

Displaying SQLite row values if the row ID matches the listView item ID

here is my scenario:
lets say I have a SQLite table which displays some rows with and ID that is of course auto incremented.
public static final String DataTableName = "jobsTable";
public static final String ColID = "ID";
public static final String ColPlace = "placeName";
public static final String ColPosition = "position";
public static final String ColStartingTime = "startingTime";
public static final String ColHours = "hours";
public static final String ColAddress = "address";
public static final String ColPhoneNumber = "phoneNumber";
the "placeName" and "position" and "startingTime" are used to populate listView cells like so:
Click here to see screen capture
Now my question is, how can I display the values of a Table row, whose ID matches that of list item? so when the user presses on an item, the table row that share the same ID will be displayed. thanks
here is what I've tried so far (only the onItemClickedListner method) but I know I'm not retrieving the data right
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// get the IDs of each column in the database
String [] IDs = activity.getAllColumnsIDs().toArray(
new String[activity.getAllColumnsIDs().size()]);
// loop throught the IDs and see if they match the listView
// item ids. if yes, display the detail
DataBaseHelper summerJobDB;
summerJobDB = new DataBaseHelper(activity);
for (int i = 0; i >= IDs.length; i++) {
if (i == id) {
Cursor res = summerJobDB.getAllData();
if (res.getCount() ==0){
// show some message
showMessage("Error", "Nothing found");
return;
}
StringBuffer buffer = new StringBuffer();
// append the values from the database to the buffer.
// this is based on the index number of the columns
while (res.moveToNext()) {
buffer.append(res.getString(1)+ "/" + res.getString(2) +"\n");
buffer.append("Starts on " + res.getString(3)+"\n\n");
buffer.append("Address: \n"+ res.getString(5)+"\n\n");
buffer.append("Phone: \n"+ res.getString(6)+"\n\n");
buffer.append("Hours: \n"+ res.getString(4)+"\n\n");
}
// show all data here
showMessage("Data",buffer.toString());
}
}
}

RxJava: Reduce or Combine or Merge

What I want to do is query the Android ContentProvider for Contacts.
The Cursor returns contains multiple duplicates for a contact where they may have more than one number registered against their contact_id)
So far, I have queried the DB, and am iterating through the Cursor rows.
I map() these rows and converting them into a ValueObjects
Next I want to go through all the list of VO’s and merge the ones that have the same contact_id (the VO would store an array of label & numbers)
But, I am stuck, I can not figure out how to perform the last part, how can I loop through the list of ValueObjects, merging the duplicates into one and then disposing the unneeded ones.
This is a sample of the Cursor returned by the ContentProvider:
86 {
_id=5190
contact_id=2167
display_name=John Doe
data1=+44 20 7123 7890
data2=3
data3=null
photo_thumb_uri=content://com.android.contacts/contacts/2167/photo
lookup=731i7g4b3e9879f40515
}
87 {
_id=5191
contact_id=2167
display_name=John Doe
data1=+44 7967 123 789
data2=2
data3=null
photo_thumb_uri=content://com.android.contacts/contacts/2167/photo
lookup=731i7g4b3e9879f40515
}
88 {
_id=5192
contact_id=2167
display_name=John Doe
data1=+44 208 123 7890
data2=1
data3=null
photo_thumb_uri=content://com.android.contacts/contacts/2167/photo
lookup=731i7g4b3e9879f40515
}
Sample of the function
public static Observable<List<ContactVO>> fetchAllContacts(final Context context) {
allContactsQuery(context);
return ContentObservable.fromCursor(allContactsQuery(context))
.map(mapToContactVO())
.toList()
// I am stuck
}
private static Cursor allContactsQuery(Context context) {
final String[] CONTACTS = new String[]{
Phone._ID, //.....0
Phone.CONTACT_ID, //.....1
Contacts.DISPLAY_NAME_PRIMARY, //.....2
Phone.NUMBER, //.....3
Phone.TYPE, //.....4
Phone.LABEL, //.....5
Contacts.PHOTO_THUMBNAIL_URI, //.....6
Contacts.LOOKUP_KEY, //.....7
};
String SELECTION = Contacts.DISPLAY_NAME_PRIMARY +
"<>''" + " AND " + Contacts.IN_VISIBLE_GROUP + "=1" +
" AND " + Contacts.HAS_PHONE_NUMBER + "=1";
final String[] SELECTION_ARGS = null;
final String SORT_ORDER = Contacts.SORT_KEY_PRIMARY;
Cursor cursor = context.getContentResolver().query(
Phone.CONTENT_URI,
CONTACTS,
SELECTION,
SELECTION_ARGS,
SORT_ORDER);
return cursor;
}
#NonNull
private static Func1<Cursor, ContactVO> mapToContactVO() {
return cursor -> {
int len = cursor.getCount();
final ContactVO contact = new ContactVO();
contact.contactId = cursor.getString(CONTACT_ID);
contact.displayName = cursor.getString(DISPLAY_NAME);
contact.photoThumbnailUri = cursor.getString(PHOTO_THUMBNAIL_URI);
contact.lookUp = cursor.getString(LOOK_UP);
contact.addData(
new Pair<String, String>(
cursor.getString(PHONE_TYPE),
cursor.getString(PHONE_NUMBER)
)
);
return contact;
};
}
public final static int CONTACT_ID = 1;
public final static int DISPLAY_NAME = 2;
public final static int PHONE_NUMBER = 3;
public final static int PHONE_TYPE = 4;
public final static int PHONE_LABEL = 5;
public final static int PHOTO_THUMBNAIL_URI = 6;
public final static int LOOK_UP = 7;
Use groupBy to get the records with the same contactId together then flatMap and reduce to merge the records
ContentObservable.fromCursor(allContactsQuery(context))
.map(mapToContactVO())
.groupBy(contact -> contact.contactId)
.flatMap(g -> g.reduce(mergeContacts()));

ContentResolver.delete deletes all entries from my ContentProvider

I have created an app in which I use a ContentProvider I created to keep track of some photos my app creates.
The concept is simple.
I capture some Images and save the Image name, date, and path to a ContentProvider.
And then I use this content provider to load each time thumbnails etc from this ContentProvider when my app starts etc.
I use a CursorAdapter and ListActivity for the full picture.
If the user deletes the image from a file manager or through my app, I want to delete that entry from the ContentProvider.
I have this method which is supposed to do so.
private void deletePhotoFromContentProvider(String path){
String[] selectionArgs=new String[]{path};
Log.i(TAG, "Path to delete:" + path);
String whereClause=""+PhotosContract.PHOTO_FILE_PATH+"=?";
int res = mContext.getContentResolver().delete(PhotosContract.CONTENT_URI,
whereClause, selectionArgs);
Log.i(TAG, "Deleted :" + Integer.toString(res));
mContext.getContentResolver().notifyChange(PhotosContract.CONTENT_URI, null);
}
My table has an ID, a photo_name, photo_date, photo_file_path.
I perform the delete based on the file_path which is basically unique.
I checked the path and the Log prints the correct one, but when i try to delete this deletes all my entries. Note that the
ContentValues values = initValues();
mContext.getContentResolver().insert(PhotosContract.CONTENT_URI, values);
works properly.
This is also my PhotosContract class
public class PhotosContract {
public static final String AUTHORITY = "com.android.testapp.provider";
public static final Uri BASE_URI = Uri
.parse("content://" + AUTHORITY + "/");
public static final String PHOTOS_TABLE_NAME = "photos";
// The URI for this table.
public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_URI,
PHOTOS_TABLE_NAME);
public static final String _ID = "_id";
public static final String PHOTO_FILE_PATH = "photo_file_path";
public static final String PHOTO_FILE_NAME = "photo_name";
public static final String PHOTO_DATE = "photo_date";
}
I also tried to use something like this:
String whereClause=""+PhotosContract.PHOTO_FILE_PATH+"=" + path;
int res = mContext.getContentResolver().delete(PhotosContract.CONTENT_URI,
whereClause, null);
but does not work either. It also deletes all my ContentProvider entries.
Any help?
Thanks in advance.
EDIT:
I am posting my delete method from my ContentProvider:
#Override
public int delete(Uri arg0, String arg1, String[] arg2) {
int rowsDeleted = mDbHelper.getWritableDatabase().delete(
PhotosContract.PHOTOS_TABLE_NAME, arg1, arg2);
getContext().getContentResolver().notifyChange(
PhotosContract.CONTENT_URI, null);
return rowsDeleted;
}

android: Query SMS Unique DisplayName(s) Efficiently

I'm trying to write an activity that shows the DisplayNames of contacts evolved in SMS conversations.
Unfortunately:
The SMS database doesn't contain the DisplayName
so I used a function that uses the address "phone number" to get the DisplayName
I don't know how to query unique addresses from the SMS database
so I used sorted query, used a loop to find unique DisplayNames, and then put them in an array
If not, is it better to run this process in the background? but how will the activity open if the list is not prepared yet?!
Finally, I used this array in an ArrayAdapter to populate my ListView (pretty much trying to mimic the native Messaging app)
The activity turned out to take a lot of time to open up (around 2-3 seconds, and I don't have much messages)
Is there a way to solve any or both of my problems efficiently?
Here's my code
public class MessagesPicker extends Activity {
Cursor myCursor;
ListView pickerListView;
public static final String MessageAddress = address;
public static final String MessageID = _id;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.picker);
ContentResolver cr = getContentResolver();
myCursor = cr.query(Uri.parse(contentsms), null, null, null, MessageAddress + ASC); //getting sorted data to easy finding uniqueness
/**setting up unique DisplayNames array**/
int allCount = myCursor.getCount(), uniqueCount = 0;
String[] uniqueNames = new String[allCount];
String temp1,temp2;
myCursor.moveToFirst();
temp1 = getContactDiplayNameByAddr();
uniqueNames[uniqueCount++] = temp1;
do {
temp2 = getContactDiplayNameByAddr();
if (temp1.compareTo(temp2) != 0){
uniqueNames[uniqueCount++] = temp2;
temp1 = temp2;
}
}while(myCursor.moveToNext());
String [] valuesArray = new String[uniqueCount]; //filling the array
for (int i = 0 ; i uniqueCount ; i++)
valuesArray[i] = uniqueNames[i];
/**setting up the ListView**/
ArrayAdapterString adapter = new ArrayAdapterString(this, android.R.layout.simple_list_item_multiple_choice, valuesArray);
pickerListView = (ListView)findViewById(R.id.PickerLV); //linking the object to the interface
pickerListView.setAdapter(adapter); //setting the adapter
pickerListView.setItemsCanFocus(false); //allowing to check the checkbox
pickerListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); //allowing multiple choices
}
String getContactDiplayNameByAddr() { //this function returns DisplayName, or if not available, returns the address
String Address = myCursor.getString(myCursor.getColumnIndex(address));
Uri personUri = Uri.withAppendedPath( ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Address);
Cursor cur = getContentResolver().query(personUri,
new String[] {PhoneLookup.DISPLAY_NAME},
null, null, null );
if( cur.moveToFirst() ) {
String DisplayName = cur.getString(cur.getColumnIndex(PhoneLookup.DISPLAY_NAME));
cur.close();
return DisplayName;
}
return Address;
}
}

Android : Sqlite Database insert?

How to insert a string array values to a table?
1,1,null,null,9876543210,null,1,-1,3,null,null,Testing message,null,0,0,0
The above is the value in a String[]. I want to insert this to my database table.
Here's my code : -
while((st = reader.readLine()) != null)
{
try
{
splitArray = st.split("\\n+");
}catch(PatternSyntaxException e ) { }
for(String result_array : splitArray)
{
Toast.makeText(context, result_array, Toast.LENGTH_SHORT).show();
}
What's the SQL statement to do this?
i have been trying to do the same thing and just worked it out. you
want to do something similar to this.
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
Code
public static final String ADDRESS = "address";
public static final String PERSON = "person";
public static final String DATE = "date";
public static final String READ = "read";
public static final String STATUS = "status";
public static final String TYPE = "type";
public static final String BODY = "body";
public static final int MESSAGE_TYPE_INBOX = 1;
public static final int MESSAGE_TYPE_SENT = 2;
ContentValues values = new ContentValues();
values.put(SMSHelper.ADDRESS, "+61408219690");
values.put(SMSHelper.DATE, "1237080365055");
values.put(SMSHelper.READ, 1);
values.put(SMSHelper.STATUS, -1);
values.put(SMSHelper.TYPE, 2);
values.put(SMSHelper.BODY, "SMS inserting test");
Uri inserted = getContentResolver().insert(Uri.parse("content:// sms"), values);
If you have a table with one column of type 'TEXT' and all you wish is to enter
those string but in one commit: then as far as I know you have to make an INSERT statement
for each of them, there is no way to insert all the string in only 1 INSERT statement (as long as you want each string to be a row in the table)
Read more

Categories

Resources