Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ContentResolver.query() method throws "Invalid token limit" error

The following error occurs on Pixel devices with build number RQ1A.201205.003 or later.
I would like to know the cause of the error and how to deal with it.
Is this a bug or a spec change?

■code

      ContentResolver resolver = getContentResolver();
      String order = "date ASC limit 100";
      Cursor cursor = resolver.query(
          CallLog.Calls.CONTENT_URI,
          null,
          null,
          null,
          order);

■error

"Invalid token limit,LINE:142,Method:readExceptionFromParcel Exception:Invalid token limit"

■Build number where the error occurs

https://support.google.com/pixelphone/thread/87641266
・RQ1A.201205.003
・RQ1A.201205.008
・RQ1A.201205.011

https://support.google.com/pixelphone/thread/93232095
・RQ1A.210105.002
・RQ1A.210105.003

https://support.google.com/pixelphone/thread/96244000
・RQ1A.210205.004

■If you replace it with the following code, no error will occur.

buildUpon().appendQueryParameter("limit", "100")

■Additional Information When implemented using the official documentation method, no error occurred, but the LIMIT clause did not work (all records were retrieved).

ContentProvider - query

 // Request 20 records starting at row index 30.
 Bundle queryArgs = new Bundle();
 queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 30);
 queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 20);
 
 Cursor cursor = getContentResolver().query(
       contentUri,    // Content Uri is specific to individual content providers.
       projection,    // String[] describing which columns to return.
       queryArgs,     // Query arguments.
       null);         // Cancellation signal.
like image 718
user44032 Avatar asked Feb 19 '21 16:02

user44032


1 Answers

From Android 11, LIMIT and OFFSET should be retrieved using Bundle by

public Cursor query (Uri uri, 
                String[] projection, 
                Bundle queryArgs, 
                CancellationSignal cancellationSignal) 

I use such solution and it works for me:

private fun fetchGalleryImages(
    context: Context,
    orderBy: String,
    orderAscending: Boolean,
    limit: Int = 20,
    offset: Int = 0
): List<MediaItem> {
    val galleryImageUrls = mutableListOf<MediaItem>()
    val collection = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
    val projection = arrayOf(
        MediaStore.Files.FileColumns._ID,
        MediaStore.Files.FileColumns.DATA,
        MediaStore.Files.FileColumns.DATE_ADDED,
        MediaStore.Files.FileColumns.MEDIA_TYPE,
        MediaStore.Files.FileColumns.MIME_TYPE,
        MediaStore.Files.FileColumns.TITLE,
        MediaStore.Video.Media.DURATION
    )
    val whereCondition = "${MediaStore.Files.FileColumns.MEDIA_TYPE} = ? OR ${MediaStore.Files.FileColumns.MEDIA_TYPE} = ?"
    val selectionArgs = arrayOf(
        MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE.toString(),
        MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO.toString()
    )
    createCursor(
        contentResolver = context.contentResolver,
        collection = collection,
        projection = projection,
        whereCondition = whereCondition,
        selectionArgs = selectionArgs,
        orderBy = orderBy,
        orderAscending = orderAscending,
        limit = limit,
        offset = offset
    )?.use { cursor ->
        while (cursor.moveToNext()) {
            galleryImageUrls.add(
                MediaItem(
                    cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns._ID)),
                    ContentUris.withAppendedId(collection, cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns._ID))),
                    cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)),
                    cursor.getStringOrNull(cursor.getColumnIndex(MediaStore.Files.FileColumns.MIME_TYPE)),
                    cursor.getLongOrNull(cursor.getColumnIndex(MediaStore.Video.Media.DURATION))
                )
            )
        }
    }
    return galleryImageUrls
}

private fun createCursor(
    contentResolver: ContentResolver,
    collection: Uri,
    projection: Array<String>,
    whereCondition: String,
    selectionArgs: Array<String>,
    orderBy: String,
    orderAscending: Boolean,
    limit: Int = 20,
    offset: Int = 0
): Cursor? = when {
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
        val selection = createSelectionBundle(whereCondition, selectionArgs, orderBy, orderAscending, limit, offset)
        contentResolver.query(collection, projection, selection, null)
    }
    else -> {
        val orderDirection = if (orderAscending) "ASC" else "DESC"
        var order = when (orderBy) {
            "ALPHABET" -> "${MediaStore.Audio.Media.TITLE}, ${MediaStore.Audio.Media.ARTIST} $orderDirection"
            else -> "${MediaStore.Audio.Media.DATE_ADDED} $orderDirection"
        }
        order += " LIMIT $limit OFFSET $offset"
        contentResolver.query(collection, projection, whereCondition, selectionArgs, order)
    }
}

@RequiresApi(Build.VERSION_CODES.O)
fun createSelectionBundle(
    whereCondition: String,
    selectionArgs: Array<String>,
    orderBy: String,
    orderAscending: Boolean,
    limit: Int = 20,
    offset: Int = 0
): Bundle = Bundle().apply {
    // Limit & Offset
    putInt(ContentResolver.QUERY_ARG_LIMIT, limit)
    putInt(ContentResolver.QUERY_ARG_OFFSET, offset)
    // Sort function
    when (orderBy) {
        "ALPHABET" -> putStringArray(ContentResolver.QUERY_ARG_SORT_COLUMNS, arrayOf(MediaStore.Files.FileColumns.TITLE))
        else -> putStringArray(ContentResolver.QUERY_ARG_SORT_COLUMNS, arrayOf(MediaStore.Files.FileColumns.DATE_ADDED))
    }
    // Sorting direction
    val orderDirection =
        if (orderAscending) ContentResolver.QUERY_SORT_DIRECTION_ASCENDING else ContentResolver.QUERY_SORT_DIRECTION_DESCENDING
    putInt(ContentResolver.QUERY_ARG_SORT_DIRECTION, orderDirection)
    // Selection
    putString(ContentResolver.QUERY_ARG_SQL_SELECTION, whereCondition)
    putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs)
}
like image 56
Space Avatar answered Oct 16 '22 23:10

Space