CalendarContract query with limit - android

How can I query CalendcarContract.Instances with a LIMIT clause?
I would like to query starting with a particular start date for a LIMIT of "n" rows.
What I've tried is:
final Uri uri = Uri.parse(CalendarContract.Instances.CONTENT_URI + "/" +
Long.toString(startDate) + "/" +
Long.MAX_VALUE);
final String sortOrder = Instances.BEGIN;
String selection = " limit " + rows;
Cursor cursor = context.getContentResolver().query (
uri,
projection,
selection,
null,
sortOrder);
This generates an error, reported in the log file:
...while compiling: SELECT Instances._id...WHERE (begin<=? AND end>=? AND (limit 1)...
I believe the error is the "AND" before (limit 1). The service is adding that, not me. So, is there another URI I can use or another technique?
NB: I specifically want the Instances versions, which joins single events with recurring events.
Thanks.

Ok, never mind unless you have a better answer.
I realized this is a more general URI problem, not specifically related to CalendarContract. In searching for other results, I found one suggestion to append LIMIT n to the sort clause, e.g.
final String sortOrder = Instances.BEGIN + " limit " + 10;
Credit to
How to add limit clause using content provider

Related

for Calendars.CONTENT_URI how to detect if calendar is read-only?

Events for the holidays and birthdays calendars apparently cannot be modified. In general, how do I tell if a calendar's events are read-only? I'm guessing I can look at the CALENDAR_ACCESS_LEVEL column. Anyone know for sure, and what value(s) to check for?
Yes, you need to check the value of CALENDAR_ACCESS_LEVEL.
You should get all the calendar with the following access level:
CAL_ACCESS_OWNER
Full access to the calendar
CAL_ACCESS_EDITOR
Full access to modify the calendar, but not the
access control settings
CAL_ACCESS_CONTRIBUTOR
Full access to modify the calendar, but not the
access control settings
CAL_ACCESS_ROOT
Domain admin
This is an example that returns all the writable calendars:
String selection = "(" + CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL + " = ? OR "
+ CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL + " = ? OR "
+ CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL + " = ? OR "
+ CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL + " = ?)";
String[] selectionArgs = new String[]{
Integer.toString(CalendarContract.Calendars.CAL_ACCESS_OWNER),
Integer.toString(CalendarContract.Calendars.CAL_ACCESS_EDITOR),
Integer.toString(CalendarContract.Calendars.CAL_ACCESS_CONTRIBUTOR),
Integer.toString(CalendarContract.Calendars.CAL_ACCESS_ROOT)};
Cursor cursor = getContentResolver().query(CalendarContract.Calendars.CONTENT_URI, null, selection, selectionArgs, null);
I'll consider the following to be the correct answer unless someone corrects me.
Via
Cursor calCursor = context.getContentResolver().query(
Calendars.CONTENT_URI,
projection, // whatever cols you want
(Calendars.VISIBLE + " = 1 and " +
Calendars.CALENDAR_ACCESS_LEVEL + " >= " + Calendars.CAL_ACCESS_CONTRIBUTOR),
null,
Calendars._ID + " ASC");
I'm getting a list that does not include the holidays or birthdays calendars. So, I'm assuming that any calender in the list I get is writeable and, thus, my app can easily make holidays and birthdays read only. So far that assumption has been working for me.

Use custom where clause for CalendarContract.Instances

Is it possible to query CalendarContract.Instances with a custom where clause?
The normal syntax for using this URI is:
Uri.Builder builder = CalendarContract.Instances.CONTENT_URI.buildUpon();
ContentUris.appendId (builder, startDate);
ContentUris.appendId (builder, endDate);
But I want to manipulate the start date comparison by providing my own where clause and omitting the start and stop times from the URI. For sake of a simple example, like this ("projection" defined elsewhere):
final Uri uri = CalendarContract.Instances.CONTENT_URI;
String selection = Instances.BEGIN + " >= " + startTime + " and " +
Instances.END + " <= " + endTime;
Cursor cursor = context.getContentResolver().query (
uri,
projection,
selection,
null,
null);
This is resulting in a DatabaseUtils exception:
03-16 09:57:06.041 W/System.err: java.lang.IllegalArgumentException: Unknown URL content://com.android.calendar/instances/when
03-16 09:57:06.041 W/System.err: at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:167)
My real code is more complicated. I need the custom where clause so that I can adjust the start time of all day events, which are stored in UTC time rather than local time. Without an adjustment, the comparison of all day events fails in the where clause and in sorting.
Is there a different URI that I can use with Instances to do what I want?

Content loader reverse cursor order

I have a simple chat application. I am using content loaders to display messages inside a channel. Since I want 100 recent messages I sort messages based on the time stamp desc and limit it to 100. but I want to display recent messages at the bottom of the screen. Right now the cursor adaptor displays recent message first. How do I reverse the order of the cursor ?
According to me, I will have to write some smart query inside content provider or somehow have to manipulate the cursor inside cursor adaptor's bindView.
Try to sort your messages based on timestamp ASC instead of DESC.
edit: Sorry, didn't grasp the subtility here.
You can try something like this to get data in reverse order:
for (cursor.moveToLast(); !cursor.isBeforeFirst(); cursor.moveToPrevious())
{
// do your magic
}
I would probably use subquery
SELECT * FROM table ORDER BY timestamp WHERE _id
IN (SELECT _id FROM table ORDER BY timestamp DESC LIMIT 100)
To use that with content provider:
String sel = BaseColumns._ID + " IN (SELECT " + BaseColumns._ID +
" FROM " + MyDb.TableName._TABLE_NAME + " ORDER BY " +
MyDb.TableName.TIMESTAMP + " DESC LIMIT 100)";
Cursor q = getContentResolver().query(MyDb.TableName.CONTENT_URI,
null, sel, null, MyDb.TableName.TIMESTAMP);
MyDb is yours class defining tables and its fields, UriS etc.

How to add limit clause using content provider [duplicate]

This question already has answers here:
Specifying limit / offset for ContentProvider queries
(4 answers)
Closed 4 years ago.
Is there a way to limit the number of rows returned from content provider?
I found this solution, however, it did not work for me. All of the rows are still being returned.
Uri uri = Playlists.createIdUri(playlistId); //generates URI
uri = uri.buildUpon().appendQueryParameter("limit", "3").build();
Cursor cursor = activity.managedQuery(playlistUri, null, null, null, null);
I have had this issue and had to break my head till I finally figured it out, or rather got a whay that worked for me. Try the following
Cursor cursor = activity.managedQuery(playlistUri, null, null, null, " ASC "+" LIMIT 2");
The last parameter is for sortOrder. I provided the sort order and also appended the LIMIT to it. Make sure you give the spaces properly. I had to check the query that was being formed and this seemed to work.
Unfortunately, ContentResolver can't query having limit argument. Inside your ContentProvider, your MySQLQueryBuilder can query adding the additional limit parameter.
Following the agenda, we can add an additional URI rule inside ContentProvider.
static final int ELEMENTS_LIMIT = 5;
public static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher( UriMatcher.NO_MATCH );
........
uriMatcher.addURI(AUTHORITY, "elements/limit/#", ELEMENTS_LIMIT);
}
Then in your query method
String limit = null; //default....
switch( uriMatcher.match(uri)){
.......
case ELEMENTS_LIMIT:
limit = uri.getPathSegments().get(2);
break;
......
}
return mySQLBuilder.query( db, projection, selection, selectionArgs, null, null, sortOrder, limit );
Querying ContentProvider from Activity.
uri = Uri.parse("content://" + ContentProvider.AUTHORITY + "/elements/limit/" + 1 );
//In My case I want to sort and get the greatest value in an X column. So having the column sorted and limiting to 1 works.
Cursor query = resolver.query(uri,
new String[]{YOUR_COLUMNS},
null,
null,
(X_COLUMN + " desc") );
A content provider should on general principle pay attention to a limit parameter.
Unfortunately, it is not universally implemented.
For instance, when writing a content provider to handle SearchManager queries:
String limit = uri.getQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT);
Where it isn't implemented you can only fall back on the ugly option of gluing a limit on the sort clause.

Fetching only first 100 rows of image from mediastore

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

Categories

Resources