Hi I am trying to get the content of bucket Id using content resolver in android Q I am getting this Error
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #7
Process: com.dev.newtermain, PID: 13048
java.lang.IllegalArgumentException: Invalid token SELECT
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:172)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:472)
at android.content.ContentResolver.query(ContentResolver.java:1183)
at android.content.ContentResolver.query(ContentResolver.java:1115)
at android.content.ContentResolver.query(ContentResolver.java:1071)
My Selection query is
selection = "bucket_id = ?) UNION SELECT _data, date_added, 0 as isImage FROM video WHERE (bucket_id = ?";
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
selectionArgs = new String[]{bucketIdString};
String[] projection = new String[]{
MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DATE_ADDED, MediaStore.Video.VideoColumns.DATE_ADDED
};
Cursor cur = context.getContentResolver()
.query(uri, projection, selection, selectionArgs, MediaStore.Images.ImageColumns.DATE_ADDED + " DESC");
Any idea how I can fix this query
The selection parameter in ContentResolver::query does only support WHERE clauses (without the WHERE keyword). docs
Your approach is including the UNION clause in the selection which is invalid. If you need a union, you may have to do two separate queries and combine the two results yourself.
EDIT
For your specifc case the selection should be defined as follows
selection = "bucket_id = ?"
check out this selection
"SELECT _data, date_added, 0 as isImage FROM video WHERE bucket_id = ?";
removed bucket_id = ?) on start - this is just wrong, not proper format, doesn't fit to beginning of query...
removed following UNION as there is no union two selectors at all, just simple query for single video table
at the end removed unneeded opening bracket (WHERE (bucket_id = ? to WHERE bucket_id = ?)
but note that query is encapsulated and won't accept full single-string sqlite query, you have to split it for parts. variable selection would be "bucket_id = ?" for matching selectionArgs
also note that projection is a bit weird...
String[] projection = new String[]{
MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DATE_ADDED, MediaStore.Video.VideoColumns.DATE_ADDED
};
first two values are using MediaStore.Images instead of MediaStore.Video and all three doesn't match params in selection SELECT _data, date_added, 0 as isImage FROM - I see two params and one probably not needed static value
edit: I've just noticed you are selecting by Images - MediaStore.Images.Media.EXTERNAL_CONTENT_URI - but selection is pointing on video column... also I doubt that bucket_id column exists in MediaStore database, there is no such value in static declarations of columns... I would suggest you read a bit about sql and querying, because your snippet looks like every line is comming from another piece of code....
Related
I'm working on an application in which I should be able to access all the contacts, able to update or delete the numbers in any contact.
I want to delete few numbers in a contact. I'm using batchOperations to perform delete operation.
phone = ContactsContract.Data.RAW_CONTACT_ID + " = ? AND " +
ContactsContract.Data.MIMETYPE + " = ? AND " +
ContactsContract.CommonDataKinds.Phone._ID + " = ?";
String[] phoneArgs = new String[]{Integer.toString(rawContactId), ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE, String.valueOf(id)};
batchOperations.add(ContentProviderOperation.newDelete(Data.CONTENT_URI).withSelection(phone, phoneArgs).build());
this.mContext.getContentResolver().applyBatch("com.android.contacts", batchOperations);
batchOperations.clear();
I'm using this part of code to delete a specific number from the Contact. Using debugger, for a sample delete operation, I found the values as:
raw_contact_id = 4093
id = 21579
These values correspond to specific number("+814444444444") in a group of numbers in a sample contact.(Please refer image below)
But still the number is not getting deleted. I've been trying to figure it out for the last couple of hours but couldn't solve it. Please help.
Instead of supplying selection + selectionArgs, you can build a uri of the specific item you want to delete, like so:
Uri phoneUri = ContentUris.withAppendedId(Data.CONTENT_URI, phoneId);
batchOperations.add(ContentProviderOperation.newDelete(phoneUri).build());
A couple of other notes:
Always check the return value of applyBatch, if it's false, there's some issue with your code / permissions.
Use the constant ContactsContract.AUTHORITY instead of the hard-coded string "com.android.contacts".
Another reason for the observed behavior is that the phone "+814444444444" is stored on multiple RawContacts aggregated into a single contact.
In which case even when you properly delete the row from RawContact A, the contact profile would still get the number from RawContact B.
This is especially true for phone numbers when certain apps such as Whatsapp are installed which tend to copy over contacts' phone numbers to a separate RawContact under their own account.
If that's the issue you'll need to delete the phone number from ALL the contact's RawContacts holding that phone.
EDIT
Here's how to dump all phone numbers that belong to a specific contact, along with the raw-contact that holds them:
String selection = Data.CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?";
String[] selectionArgs = new String[] { contactId.toString(), Phone.CONTENT_ITEM_TYPE };
String[] projection = new String[] { Data.CONTACT_ID, Data.RAW_CONTACT_ID, Data.DATA1 };
Cursor cur = getContentResolver().query(Data.CONTENT_URI, projection, selection, selectionArgs, projection);
DatabaseUtils.dumpCursor(cur);
Also, note that a rawContactId is not an integer, it's a long.
When String[] ids has one argument, query return data, when more then one, get error:
Cannot bind argument at index X(number of arguments) because the index is out of range. The statement has 1 parameter.
Cursor cr = ctx.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null,
"_id = ?",
ids,
orderBy
);
"_id = ?"
This construction serves to reserve place for one parameter. If you want to select items with several ids you better use the folowing:
"_id IN (?,?,?..?)"
Here is the answer about parametrization of this type of query: IN clause and placeholders
I'm trying to get "notes" from a single contact. It added fine but retrieving it has been a problem.
String selection = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+" like'%" + sender +"%'";
String[] projection = new String[] { ContactsContract.CommonDataKinds.Note.NOTE};
Cursor c2 = getContentResolver().query(ContactsContract.Data.CONTENT_URI, projection, selection, null, null);
if (c2.moveToFirst()) {
notes = c2.getString(0);
}
It works fine with other values like name or phone number but can't seem to get notes to retrieve correctly. It retrieves a random value like email instead.
I believe that your problem is that not all rows in the table represent contact types that have notes. You have to request the proper MIME Type.
ContactsContract.CommonDataKinds.Note is an alias for the 'data1' column that is present on all rows, so when you get a row of a different MIME Type, it represents different data.
How to get contacts in Android should give you an idea of how to do this.
I need to make a query to ContactsContract.Data table and values in CONTACT_ID column would be different (distinct).
Code:
final Uri uri = ContactsContract.Data.CONTENT_URI;
final String[] projection = new String[] {//
ContactsContract.Data.CONTACT_ID, //
ContactsContract.Data._ID, //
ContactsContract.Data.DISPLAY_NAME,//
ContactsContract.Data.LOOKUP_KEY //
};
final StringBuilder selectionBuilder = new StringBuilder();
selectionBuilder.append(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID);
selectionBuilder.append("= ? AND ");
selectionBuilder.append(ContactsContract.Data.MIMETYPE);
selectionBuilder.append("= ? ");
final String selection = selectionBuilder.toString();
final String[] selectionArgs = new String[] {//
String.valueOf(groupId), //
ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE //
};
return context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
First of all, I've tried to add "DISTINCT " to ContactsContract.Data.CONTACT_ID in projection. But there was an exception: java.lang.IllegalArgumentException: Invalid column DISTINCT contact_id
Then, I write this way:
"'DISTINCT "+ContactsContract.Data.CONTACT_ID+"'".
java.lang.IllegalArgumentException: Invalid column 'DISTINCT contact_id'
Then, I add to selectionBuilder:
selectionBuilder.append(" GROUP BY ").append(ContactsContract.Data.CONTACT_ID);
Once again, an exception: android.database.sqlite.SQLiteException: near "GROUP": syntax error: , while compiling: SELECT contact_id, _id, display_name, lookup FROM view_data_restricted data WHERE (1) AND (data1= ? AND mimetype= ? GROUP BY contact_id) ORDER BY display_name ASC
At last, I've append "group by" statement right after sortOrder, but:
android.database.sqlite.SQLiteException: near "GROUP": syntax error: , while compiling: SELECT contact_id, _id, display_name, lookup FROM view_data_restricted data WHERE (1) AND (data1= ? AND mimetype= ? ) ORDER BY display_name ASC GROUP BY contact_id
Is it ever possible to make query with distinct?
Maybe, I should append something to URI?
If you are targeting devices below ICS, you can use the GROUP_BY clause by adding a ) before the group by and a ( after:
selectionBuilder.append(") GROUP BY (")
As of ICS and above, the query interpretor is smarter and closes any unclosed parenthesis to prevent injection.
However, I don't see why you need distinct contact_ids here. A contact should probably have only one Data to make the association with one group, so you probably receive a different contact on each line.
Also, there may be something to do with http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html#CONTENT_GROUP_URI it is not documented, but given its position, it may well be a direct access to Contacts belonging to a Group. You would use that Uri :
Uri uri = ContentUri.withAppendedId(ContactsContract.Contacts.CONTENT_GROUP_URI, groupId);
And then query it like the Contacts.CONTENT_URI
Is there a way to limit the result retrieved from mediastore using managedQuery function on Android. Since I currently have a grid that displaying all photos found on the sd card but it is too intensive of fetching it so I decide to limit the result retrieved from the media store but could not find a limit function that can reduce the resulting set of data.
Please help
use order in contentresolver's query method to implement your function,
such as 'columnname asc limit number'
in my case:
cursor = resolver.query(STORAGE_URI, projection,
Media.BUCKET_DISPLAY_NAME + "=?",
new String[] { folderName },
" _id asc limit " + num);
You can limit the result using the sortOrder parameter in query method. Something like this
ContentResolver contentResolver = getContentResolver();
Cursor androidCursor = null;
String sortOrder = String.format("%s limit 100",BaseColumns._ID);
androidCursor = contentResolver.query(IMAGE_URI,PROJECTION, null, null, sortOrder);
This will order the result set by id and limit the result.
When targeting Android 11 the suggested answer will cause an exception, with java.lang.IllegalArgumentException: Invalid token LIMIT
Instead you should provide a "limit" query parameter on the URI that the MediaProvider will read.
val queryUri = IMAGE_URI.buildUpon().appendQueryParameter("limit", limit.toString()).build()
I haven't found documentation for this, but it's present in the sources