/* * Copyright (c) 2015-present, Parse, LLC. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.parse; import android.annotation.TargetApi; import android.content.ContentResolver; import android.database.CharArrayBuffer; import android.database.ContentObserver; import android.database.Cursor; import android.database.DataSetObserver; import android.net.Uri; import android.os.Build; import android.os.Bundle; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import bolts.Task; /** * Wrapper class to invoke {@link Cursor#close()} on a specific thread on Android versions below * android-14 as they require {@link Cursor#close()} to be called on the same thread the cursor * was created in * * https://github.com/android/platform_frameworks_base/commit/6f37f83a4802a0d411395f3abc5f24a2cfec025d */ /** package */ class ParseSQLiteCursor implements Cursor { public static Cursor create(Cursor cursor, Executor executor) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { return cursor; } return new ParseSQLiteCursor(cursor, executor); } private Cursor cursor; private Executor executor; private ParseSQLiteCursor(Cursor cursor, Executor executor) { this.cursor = cursor; this.executor = executor; } @Override public int getCount() { return cursor.getCount(); } @Override public int getPosition() { return cursor.getPosition(); } @Override public boolean move(int offset) { return cursor.move(offset); } @Override public boolean moveToPosition(int position) { return cursor.moveToPosition(position); } @Override public boolean moveToFirst() { return cursor.moveToFirst(); } @Override public boolean moveToLast() { return cursor.moveToLast(); } @Override public boolean moveToNext() { return cursor.moveToNext(); } @Override public boolean moveToPrevious() { return cursor.moveToPrevious(); } @Override public boolean isFirst() { return cursor.isFirst(); } @Override public boolean isLast() { return cursor.isLast(); } @Override public boolean isBeforeFirst() { return cursor.isBeforeFirst(); } @Override public boolean isAfterLast() { return cursor.isAfterLast(); } @Override public int getColumnIndex(String columnName) { return cursor.getColumnIndex(columnName); } @Override public int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException { return cursor.getColumnIndexOrThrow(columnName); } @Override public String getColumnName(int columnIndex) { return cursor.getColumnName(columnIndex); } @Override public String[] getColumnNames() { return cursor.getColumnNames(); } @Override public int getColumnCount() { return cursor.getColumnCount(); } @Override public byte[] getBlob(int columnIndex) { return cursor.getBlob(columnIndex); } @Override public String getString(int columnIndex) { return cursor.getString(columnIndex); } @Override public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) { cursor.copyStringToBuffer(columnIndex, buffer); } @Override public short getShort(int columnIndex) { return cursor.getShort(columnIndex); } @Override public int getInt(int columnIndex) { return cursor.getInt(columnIndex); } @Override public long getLong(int columnIndex) { return cursor.getLong(columnIndex); } @Override public float getFloat(int columnIndex) { return cursor.getFloat(columnIndex); } @Override public double getDouble(int columnIndex) { return cursor.getDouble(columnIndex); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public int getType(int columnIndex) { return cursor.getType(columnIndex); } @Override public boolean isNull(int columnIndex) { return cursor.isNull(columnIndex); } @Override @Deprecated public void deactivate() { cursor.deactivate(); } @Override @Deprecated public boolean requery() { return cursor.requery(); } @Override public void close() { // Basically close _eventually_. Task.call(new Callable<Void>() { @Override public Void call() throws Exception { cursor.close(); return null; } }, executor); } @Override public boolean isClosed() { return cursor.isClosed(); } @Override public void registerContentObserver(ContentObserver observer) { cursor.registerContentObserver(observer); } @Override public void unregisterContentObserver(ContentObserver observer) { cursor.unregisterContentObserver(observer); } @Override public void registerDataSetObserver(DataSetObserver observer) { cursor.registerDataSetObserver(observer); } @Override public void unregisterDataSetObserver(DataSetObserver observer) { cursor.unregisterDataSetObserver(observer); } @Override public void setNotificationUri(ContentResolver cr, Uri uri) { cursor.setNotificationUri(cr, uri); } @TargetApi(Build.VERSION_CODES.KITKAT) @Override public Uri getNotificationUri() { return cursor.getNotificationUri(); } @Override public boolean getWantsAllOnMoveCalls() { return cursor.getWantsAllOnMoveCalls(); } @Override public Bundle getExtras() { return cursor.getExtras(); } @Override public Bundle respond(Bundle extras) { return cursor.respond(extras); } @TargetApi(Build.VERSION_CODES.M) @Override public void setExtras(Bundle bundle) { cursor.setExtras(bundle); } }