mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Convert and cleanup content providers
This commit is contained in:
parent
8772a5a208
commit
c0514798c8
13 changed files with 429 additions and 527 deletions
|
|
@ -1,129 +0,0 @@
|
||||||
package fr.free.nrw.commons.bookmarks.items;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_ID;
|
|
||||||
import static fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.TABLE_NAME;
|
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteQueryBuilder;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
|
||||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerContentProvider;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles private storage for bookmarked items
|
|
||||||
*/
|
|
||||||
public class BookmarkItemsContentProvider extends CommonsDaggerContentProvider {
|
|
||||||
|
|
||||||
private static final String BASE_PATH = "bookmarksItems";
|
|
||||||
public static final Uri BASE_URI =
|
|
||||||
Uri.parse("content://" + BuildConfig.BOOKMARK_ITEMS_AUTHORITY + "/" + BASE_PATH);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append bookmark items ID to the base uri
|
|
||||||
*/
|
|
||||||
public static Uri uriForName(final String id) {
|
|
||||||
return Uri.parse(BASE_URI + "/" + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
DBOpenHelper dbOpenHelper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType(@NonNull final Uri uri) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queries the SQLite database for the bookmark items
|
|
||||||
* @param uri : contains the uri for bookmark items
|
|
||||||
* @param projection : contains the all fields of the table
|
|
||||||
* @param selection : handles Where
|
|
||||||
* @param selectionArgs : the condition of Where clause
|
|
||||||
* @param sortOrder : ascending or descending
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public Cursor query(@NonNull final Uri uri, final String[] projection, final String selection,
|
|
||||||
final String[] selectionArgs, final String sortOrder) {
|
|
||||||
final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
|
||||||
queryBuilder.setTables(TABLE_NAME);
|
|
||||||
final SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
|
||||||
final Cursor cursor = queryBuilder.query(db, projection, selection,
|
|
||||||
selectionArgs, null, null, sortOrder);
|
|
||||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the update query of local SQLite Database
|
|
||||||
* @param uri : contains the uri for bookmark items
|
|
||||||
* @param contentValues : new values to be entered to db
|
|
||||||
* @param selection : handles Where
|
|
||||||
* @param selectionArgs : the condition of Where clause
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public int update(@NonNull final Uri uri, final ContentValues contentValues,
|
|
||||||
final String selection, final String[] selectionArgs) {
|
|
||||||
final SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
|
||||||
final int rowsUpdated;
|
|
||||||
if (TextUtils.isEmpty(selection)) {
|
|
||||||
final int id = Integer.parseInt(uri.getLastPathSegment());
|
|
||||||
rowsUpdated = sqlDB.update(TABLE_NAME,
|
|
||||||
contentValues,
|
|
||||||
COLUMN_ID + " = ?",
|
|
||||||
new String[]{String.valueOf(id)});
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Parameter `selection` should be empty when updating an ID");
|
|
||||||
}
|
|
||||||
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return rowsUpdated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the insertion of new bookmark items record to local SQLite Database
|
|
||||||
* @param uri
|
|
||||||
* @param contentValues
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public Uri insert(@NonNull final Uri uri, final ContentValues contentValues) {
|
|
||||||
final SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
|
||||||
final long id = sqlDB.insert(TABLE_NAME, null, contentValues);
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return Uri.parse(BASE_URI + "/" + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the deletion of new bookmark items record to local SQLite Database
|
|
||||||
* @param uri
|
|
||||||
* @param s
|
|
||||||
* @param strings
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public int delete(@NonNull final Uri uri, final String s, final String[] strings) {
|
|
||||||
final int rows;
|
|
||||||
final SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
|
||||||
Timber.d("Deleting bookmark name %s", uri.getLastPathSegment());
|
|
||||||
rows = db.delete(
|
|
||||||
TABLE_NAME,
|
|
||||||
"item_id = ?",
|
|
||||||
new String[]{uri.getLastPathSegment()}
|
|
||||||
);
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
package fr.free.nrw.commons.bookmarks.items
|
||||||
|
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.database.sqlite.SQLiteQueryBuilder
|
||||||
|
import android.net.Uri
|
||||||
|
import fr.free.nrw.commons.BuildConfig
|
||||||
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.TABLE_NAME
|
||||||
|
import fr.free.nrw.commons.di.CommonsDaggerContentProvider
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_ID
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles private storage for bookmarked items
|
||||||
|
*/
|
||||||
|
class BookmarkItemsContentProvider : CommonsDaggerContentProvider() {
|
||||||
|
override fun getType(uri: Uri): String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries the SQLite database for the bookmark items
|
||||||
|
* @param uri : contains the uri for bookmark items
|
||||||
|
* @param projection : contains the all fields of the table
|
||||||
|
* @param selection : handles Where
|
||||||
|
* @param selectionArgs : the condition of Where clause
|
||||||
|
* @param sortOrder : ascending or descending
|
||||||
|
*/
|
||||||
|
override fun query(
|
||||||
|
uri: Uri, projection: Array<String>?, selection: String?,
|
||||||
|
selectionArgs: Array<String>?, sortOrder: String?
|
||||||
|
): Cursor {
|
||||||
|
val queryBuilder = SQLiteQueryBuilder().apply {
|
||||||
|
tables = TABLE_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryBuilder.query(
|
||||||
|
requireDb(), projection, selection,
|
||||||
|
selectionArgs, null, null, sortOrder
|
||||||
|
).apply {
|
||||||
|
setNotificationUri(requireContext().contentResolver, uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the update query of local SQLite Database
|
||||||
|
* @param uri : contains the uri for bookmark items
|
||||||
|
* @param contentValues : new values to be entered to db
|
||||||
|
* @param selection : handles Where
|
||||||
|
* @param selectionArgs : the condition of Where clause
|
||||||
|
*/
|
||||||
|
override fun update(
|
||||||
|
uri: Uri, contentValues: ContentValues?,
|
||||||
|
selection: String?, selectionArgs: Array<String>?
|
||||||
|
): Int {
|
||||||
|
val rowsUpdated: Int
|
||||||
|
if (selection.isNullOrEmpty()) {
|
||||||
|
val id = uri.lastPathSegment!!.toInt()
|
||||||
|
rowsUpdated = requireDb().update(
|
||||||
|
TABLE_NAME,
|
||||||
|
contentValues,
|
||||||
|
"$COLUMN_ID = ?",
|
||||||
|
arrayOf(id.toString())
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw IllegalArgumentException(
|
||||||
|
"Parameter `selection` should be empty when updating an ID"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
requireContext().contentResolver.notifyChange(uri, null)
|
||||||
|
return rowsUpdated
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the insertion of new bookmark items record to local SQLite Database
|
||||||
|
*/
|
||||||
|
override fun insert(uri: Uri, contentValues: ContentValues?): Uri? {
|
||||||
|
val id = requireDb().insert(TABLE_NAME, null, contentValues)
|
||||||
|
requireContext().contentResolver.notifyChange(uri, null)
|
||||||
|
return "$BASE_URI/$id".toUri()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the deletion of new bookmark items record to local SQLite Database
|
||||||
|
*/
|
||||||
|
override fun delete(uri: Uri, s: String?, strings: Array<String>?): Int {
|
||||||
|
val rows: Int = requireDb().delete(
|
||||||
|
TABLE_NAME,
|
||||||
|
"$COLUMN_ID = ?",
|
||||||
|
arrayOf(uri.lastPathSegment)
|
||||||
|
)
|
||||||
|
requireContext().contentResolver.notifyChange(uri, null)
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_PATH = "bookmarksItems"
|
||||||
|
val BASE_URI: Uri = "content://${BuildConfig.BOOKMARK_ITEMS_AUTHORITY}/$BASE_PATH".toUri()
|
||||||
|
fun uriForName(id: String) = "$BASE_URI/$id".toUri()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,8 +6,8 @@ import android.content.ContentValues
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.os.RemoteException
|
import android.os.RemoteException
|
||||||
import androidx.core.content.contentValuesOf
|
import androidx.core.content.contentValuesOf
|
||||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsContentProvider.BASE_URI
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsContentProvider.Companion.BASE_URI
|
||||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsContentProvider.uriForName
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsContentProvider.Companion.uriForName
|
||||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_CATEGORIES_DESCRIPTION_LIST
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_CATEGORIES_DESCRIPTION_LIST
|
||||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_CATEGORIES_NAME_LIST
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_CATEGORIES_NAME_LIST
|
||||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_CATEGORIES_THUMBNAIL_LIST
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_CATEGORIES_THUMBNAIL_LIST
|
||||||
|
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
package fr.free.nrw.commons.bookmarks.pictures;
|
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteQueryBuilder;
|
|
||||||
// We can get uri using java.Net.Uri, but andoid implimentation is faster (but it's forgiving with handling exceptions though)
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
|
||||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerContentProvider;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.COLUMN_MEDIA_NAME;
|
|
||||||
import static fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.TABLE_NAME;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles private storage for Bookmark pictures
|
|
||||||
*/
|
|
||||||
public class BookmarkPicturesContentProvider extends CommonsDaggerContentProvider {
|
|
||||||
|
|
||||||
private static final String BASE_PATH = "bookmarks";
|
|
||||||
public static final Uri BASE_URI = Uri.parse("content://" + BuildConfig.BOOKMARK_AUTHORITY + "/" + BASE_PATH);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append bookmark pictures name to the base uri
|
|
||||||
*/
|
|
||||||
public static Uri uriForName(String name) {
|
|
||||||
return Uri.parse(BASE_URI.toString() + "/" + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
DBOpenHelper dbOpenHelper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType(@NonNull Uri uri) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queries the SQLite database for the bookmark pictures
|
|
||||||
* @param uri : contains the uri for bookmark pictures
|
|
||||||
* @param projection
|
|
||||||
* @param selection : handles Where
|
|
||||||
* @param selectionArgs : the condition of Where clause
|
|
||||||
* @param sortOrder : ascending or descending
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
|
|
||||||
String[] selectionArgs, String sortOrder) {
|
|
||||||
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
|
||||||
queryBuilder.setTables(TABLE_NAME);
|
|
||||||
|
|
||||||
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
|
||||||
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
|
|
||||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
|
||||||
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the update query of local SQLite Database
|
|
||||||
* @param uri : contains the uri for bookmark pictures
|
|
||||||
* @param contentValues : new values to be entered to db
|
|
||||||
* @param selection : handles Where
|
|
||||||
* @param selectionArgs : the condition of Where clause
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public int update(@NonNull Uri uri, ContentValues contentValues, String selection,
|
|
||||||
String[] selectionArgs) {
|
|
||||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
|
||||||
int rowsUpdated;
|
|
||||||
if (TextUtils.isEmpty(selection)) {
|
|
||||||
int id = Integer.valueOf(uri.getLastPathSegment());
|
|
||||||
rowsUpdated = sqlDB.update(TABLE_NAME,
|
|
||||||
contentValues,
|
|
||||||
COLUMN_MEDIA_NAME + " = ?",
|
|
||||||
new String[]{String.valueOf(id)});
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Parameter `selection` should be empty when updating an ID");
|
|
||||||
}
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return rowsUpdated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the insertion of new bookmark pictures record to local SQLite Database
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public Uri insert(@NonNull Uri uri, ContentValues contentValues) {
|
|
||||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
|
||||||
long id = sqlDB.insert(BookmarkPicturesDao.Table.TABLE_NAME, null, contentValues);
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return Uri.parse(BASE_URI + "/" + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public int delete(@NonNull Uri uri, String s, String[] strings) {
|
|
||||||
int rows;
|
|
||||||
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
|
||||||
Timber.d("Deleting bookmark name %s", uri.getLastPathSegment());
|
|
||||||
rows = db.delete(TABLE_NAME,
|
|
||||||
"media_name = ?",
|
|
||||||
new String[]{uri.getLastPathSegment()}
|
|
||||||
);
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
package fr.free.nrw.commons.bookmarks.pictures
|
||||||
|
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.database.sqlite.SQLiteQueryBuilder
|
||||||
|
import android.net.Uri
|
||||||
|
import android.text.TextUtils
|
||||||
|
import fr.free.nrw.commons.BuildConfig
|
||||||
|
import fr.free.nrw.commons.di.CommonsDaggerContentProvider
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.COLUMN_MEDIA_NAME
|
||||||
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.TABLE_NAME
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles private storage for Bookmark pictures
|
||||||
|
*/
|
||||||
|
class BookmarkPicturesContentProvider : CommonsDaggerContentProvider() {
|
||||||
|
override fun getType(uri: Uri): String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries the SQLite database for the bookmark pictures
|
||||||
|
* @param uri : contains the uri for bookmark pictures
|
||||||
|
* @param projection
|
||||||
|
* @param selection : handles Where
|
||||||
|
* @param selectionArgs : the condition of Where clause
|
||||||
|
* @param sortOrder : ascending or descending
|
||||||
|
*/
|
||||||
|
override fun query(
|
||||||
|
uri: Uri, projection: Array<String>?, selection: String?,
|
||||||
|
selectionArgs: Array<String>?, sortOrder: String?
|
||||||
|
): Cursor {
|
||||||
|
val queryBuilder = SQLiteQueryBuilder().apply {
|
||||||
|
tables = TABLE_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
val cursor = queryBuilder.query(
|
||||||
|
requireDb(), projection, selection,
|
||||||
|
selectionArgs, null, null, sortOrder
|
||||||
|
)
|
||||||
|
cursor.setNotificationUri(requireContext().contentResolver, uri)
|
||||||
|
|
||||||
|
return cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the update query of local SQLite Database
|
||||||
|
* @param uri : contains the uri for bookmark pictures
|
||||||
|
* @param contentValues : new values to be entered to db
|
||||||
|
* @param selection : handles Where
|
||||||
|
* @param selectionArgs : the condition of Where clause
|
||||||
|
*/
|
||||||
|
override fun update(
|
||||||
|
uri: Uri, contentValues: ContentValues?, selection: String?,
|
||||||
|
selectionArgs: Array<String>?
|
||||||
|
): Int {
|
||||||
|
val rowsUpdated: Int
|
||||||
|
if (selection.isNullOrEmpty()) {
|
||||||
|
val id = uri.lastPathSegment!!.toInt()
|
||||||
|
rowsUpdated = requireDb().update(
|
||||||
|
TABLE_NAME,
|
||||||
|
contentValues,
|
||||||
|
"$COLUMN_MEDIA_NAME = ?",
|
||||||
|
arrayOf(id.toString())
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw IllegalArgumentException(
|
||||||
|
"Parameter `selection` should be empty when updating an ID"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
requireContext().contentResolver.notifyChange(uri, null)
|
||||||
|
return rowsUpdated
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the insertion of new bookmark pictures record to local SQLite Database
|
||||||
|
*/
|
||||||
|
override fun insert(uri: Uri, contentValues: ContentValues?): Uri {
|
||||||
|
val id = requireDb().insert(TABLE_NAME, null, contentValues)
|
||||||
|
requireContext().contentResolver.notifyChange(uri, null)
|
||||||
|
return "$BASE_URI/$id".toUri()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun delete(uri: Uri, s: String?, strings: Array<String>?): Int {
|
||||||
|
val rows: Int = requireDb().delete(
|
||||||
|
TABLE_NAME,
|
||||||
|
"media_name = ?",
|
||||||
|
arrayOf(uri.lastPathSegment)
|
||||||
|
)
|
||||||
|
requireContext().contentResolver.notifyChange(uri, null)
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_PATH = "bookmarks"
|
||||||
|
@JvmField
|
||||||
|
val BASE_URI: Uri = "content://${BuildConfig.BOOKMARK_AUTHORITY}/$BASE_PATH".toUri()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun uriForName(name: String): Uri = "$BASE_URI/$name".toUri()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,12 +9,9 @@ import android.database.sqlite.SQLiteDatabase
|
||||||
import android.database.sqlite.SQLiteQueryBuilder
|
import android.database.sqlite.SQLiteQueryBuilder
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import androidx.annotation.NonNull
|
|
||||||
import fr.free.nrw.commons.BuildConfig
|
import fr.free.nrw.commons.BuildConfig
|
||||||
import fr.free.nrw.commons.data.DBOpenHelper
|
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerContentProvider
|
import fr.free.nrw.commons.di.CommonsDaggerContentProvider
|
||||||
import timber.log.Timber
|
import androidx.core.net.toUri
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class CategoryContentProvider : CommonsDaggerContentProvider() {
|
class CategoryContentProvider : CommonsDaggerContentProvider() {
|
||||||
|
|
||||||
|
|
@ -23,9 +20,6 @@ class CategoryContentProvider : CommonsDaggerContentProvider() {
|
||||||
addURI(BuildConfig.CATEGORY_AUTHORITY, "${BASE_PATH}/#", CATEGORIES_ID)
|
addURI(BuildConfig.CATEGORY_AUTHORITY, "${BASE_PATH}/#", CATEGORIES_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var dbOpenHelper: DBOpenHelper
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
override fun query(uri: Uri, projection: Array<String>?, selection: String?,
|
override fun query(uri: Uri, projection: Array<String>?, selection: String?,
|
||||||
selectionArgs: Array<String>?, sortOrder: String?): Cursor? {
|
selectionArgs: Array<String>?, sortOrder: String?): Cursor? {
|
||||||
|
|
@ -34,7 +28,7 @@ class CategoryContentProvider : CommonsDaggerContentProvider() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val uriType = uriMatcher.match(uri)
|
val uriType = uriMatcher.match(uri)
|
||||||
val db = dbOpenHelper.readableDatabase
|
val db = requireDb()
|
||||||
|
|
||||||
val cursor: Cursor? = when (uriType) {
|
val cursor: Cursor? = when (uriType) {
|
||||||
CATEGORIES -> queryBuilder.query(
|
CATEGORIES -> queryBuilder.query(
|
||||||
|
|
@ -58,45 +52,37 @@ class CategoryContentProvider : CommonsDaggerContentProvider() {
|
||||||
else -> throw IllegalArgumentException("Unknown URI $uri")
|
else -> throw IllegalArgumentException("Unknown URI $uri")
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor?.setNotificationUri(context?.contentResolver, uri)
|
cursor?.setNotificationUri(requireContext().contentResolver, uri)
|
||||||
return cursor
|
return cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getType(uri: Uri): String? {
|
override fun getType(uri: Uri): String? = null
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
override fun insert(uri: Uri, contentValues: ContentValues?): Uri? {
|
override fun insert(uri: Uri, contentValues: ContentValues?): Uri {
|
||||||
val uriType = uriMatcher.match(uri)
|
val uriType = uriMatcher.match(uri)
|
||||||
val sqlDB = dbOpenHelper.writableDatabase
|
|
||||||
val id: Long
|
val id: Long
|
||||||
when (uriType) {
|
when (uriType) {
|
||||||
CATEGORIES -> {
|
CATEGORIES -> {
|
||||||
id = sqlDB.insert(TABLE_NAME, null, contentValues)
|
id = requireDb().insert(TABLE_NAME, null, contentValues)
|
||||||
}
|
}
|
||||||
else -> throw IllegalArgumentException("Unknown URI: $uri")
|
else -> throw IllegalArgumentException("Unknown URI: $uri")
|
||||||
}
|
}
|
||||||
context?.contentResolver?.notifyChange(uri, null)
|
requireContext().contentResolver?.notifyChange(uri, null)
|
||||||
return Uri.parse("${Companion.BASE_URI}/$id")
|
return "${BASE_URI}/$id".toUri()
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
|
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int = 0
|
||||||
// Not implemented
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
override fun bulkInsert(uri: Uri, values: Array<ContentValues>): Int {
|
override fun bulkInsert(uri: Uri, values: Array<ContentValues>): Int {
|
||||||
Timber.d("Hello, bulk insert! (CategoryContentProvider)")
|
|
||||||
val uriType = uriMatcher.match(uri)
|
val uriType = uriMatcher.match(uri)
|
||||||
val sqlDB = dbOpenHelper.writableDatabase
|
val sqlDB = requireDb()
|
||||||
sqlDB.beginTransaction()
|
sqlDB.beginTransaction()
|
||||||
when (uriType) {
|
when (uriType) {
|
||||||
CATEGORIES -> {
|
CATEGORIES -> {
|
||||||
for (value in values) {
|
for (value in values) {
|
||||||
Timber.d("Inserting! %s", value)
|
|
||||||
sqlDB.insert(TABLE_NAME, null, value)
|
sqlDB.insert(TABLE_NAME, null, value)
|
||||||
}
|
}
|
||||||
sqlDB.setTransactionSuccessful()
|
sqlDB.setTransactionSuccessful()
|
||||||
|
|
@ -104,7 +90,7 @@ class CategoryContentProvider : CommonsDaggerContentProvider() {
|
||||||
else -> throw IllegalArgumentException("Unknown URI: $uri")
|
else -> throw IllegalArgumentException("Unknown URI: $uri")
|
||||||
}
|
}
|
||||||
sqlDB.endTransaction()
|
sqlDB.endTransaction()
|
||||||
context?.contentResolver?.notifyChange(uri, null)
|
requireContext().contentResolver?.notifyChange(uri, null)
|
||||||
return values.size
|
return values.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,17 +98,18 @@ class CategoryContentProvider : CommonsDaggerContentProvider() {
|
||||||
override fun update(uri: Uri, contentValues: ContentValues?, selection: String?,
|
override fun update(uri: Uri, contentValues: ContentValues?, selection: String?,
|
||||||
selectionArgs: Array<String>?): Int {
|
selectionArgs: Array<String>?): Int {
|
||||||
val uriType = uriMatcher.match(uri)
|
val uriType = uriMatcher.match(uri)
|
||||||
val sqlDB = dbOpenHelper.writableDatabase
|
|
||||||
val rowsUpdated: Int
|
val rowsUpdated: Int
|
||||||
when (uriType) {
|
when (uriType) {
|
||||||
CATEGORIES_ID -> {
|
CATEGORIES_ID -> {
|
||||||
if (TextUtils.isEmpty(selection)) {
|
if (TextUtils.isEmpty(selection)) {
|
||||||
val id = uri.lastPathSegment?.toInt()
|
val id = uri.lastPathSegment?.toInt()
|
||||||
?: throw IllegalArgumentException("Invalid ID")
|
?: throw IllegalArgumentException("Invalid ID")
|
||||||
rowsUpdated = sqlDB.update(TABLE_NAME,
|
rowsUpdated = requireDb().update(
|
||||||
|
TABLE_NAME,
|
||||||
contentValues,
|
contentValues,
|
||||||
"$COLUMN_ID = ?",
|
"$COLUMN_ID = ?",
|
||||||
arrayOf(id.toString()))
|
arrayOf(id.toString())
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
throw IllegalArgumentException(
|
throw IllegalArgumentException(
|
||||||
"Parameter `selection` should be empty when updating an ID")
|
"Parameter `selection` should be empty when updating an ID")
|
||||||
|
|
@ -130,7 +117,7 @@ class CategoryContentProvider : CommonsDaggerContentProvider() {
|
||||||
}
|
}
|
||||||
else -> throw IllegalArgumentException("Unknown URI: $uri with type $uriType")
|
else -> throw IllegalArgumentException("Unknown URI: $uri with type $uriType")
|
||||||
}
|
}
|
||||||
context?.contentResolver?.notifyChange(uri, null)
|
requireContext().contentResolver?.notifyChange(uri, null)
|
||||||
return rowsUpdated
|
return rowsUpdated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,13 +152,9 @@ class CategoryContentProvider : CommonsDaggerContentProvider() {
|
||||||
"$COLUMN_TIMES_USED INTEGER" +
|
"$COLUMN_TIMES_USED INTEGER" +
|
||||||
");"
|
");"
|
||||||
|
|
||||||
fun uriForId(id: Int): Uri {
|
fun uriForId(id: Int): Uri = Uri.parse("${BASE_URI}/$id")
|
||||||
return Uri.parse("${BASE_URI}/$id")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onCreate(db: SQLiteDatabase) {
|
fun onCreate(db: SQLiteDatabase) = db.execSQL(CREATE_TABLE_STATEMENT)
|
||||||
db.execSQL(CREATE_TABLE_STATEMENT)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onDelete(db: SQLiteDatabase) {
|
fun onDelete(db: SQLiteDatabase) {
|
||||||
db.execSQL(DROP_TABLE_STATEMENT)
|
db.execSQL(DROP_TABLE_STATEMENT)
|
||||||
|
|
@ -200,6 +183,6 @@ class CategoryContentProvider : CommonsDaggerContentProvider() {
|
||||||
private const val CATEGORIES = 1
|
private const val CATEGORIES = 1
|
||||||
private const val CATEGORIES_ID = 2
|
private const val CATEGORIES_ID = 2
|
||||||
private const val BASE_PATH = "categories"
|
private const val BASE_PATH = "categories"
|
||||||
val BASE_URI: Uri = Uri.parse("content://${BuildConfig.CATEGORY_AUTHORITY}/${Companion.BASE_PATH}")
|
val BASE_URI: Uri = "content://${BuildConfig.CATEGORY_AUTHORITY}/${BASE_PATH}".toUri()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,25 @@
|
||||||
package fr.free.nrw.commons.di
|
package fr.free.nrw.commons.di
|
||||||
|
|
||||||
import android.content.ContentProvider
|
import android.content.ContentProvider
|
||||||
|
import android.database.sqlite.SQLiteDatabase
|
||||||
|
import fr.free.nrw.commons.data.DBOpenHelper
|
||||||
import fr.free.nrw.commons.di.ApplicationlessInjection.Companion.getInstance
|
import fr.free.nrw.commons.di.ApplicationlessInjection.Companion.getInstance
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
abstract class CommonsDaggerContentProvider : ContentProvider() {
|
abstract class CommonsDaggerContentProvider : ContentProvider() {
|
||||||
|
@JvmField
|
||||||
|
@Inject
|
||||||
|
var dbOpenHelper: DBOpenHelper? = null
|
||||||
|
|
||||||
override fun onCreate(): Boolean {
|
override fun onCreate(): Boolean {
|
||||||
inject()
|
inject()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun requireDbOpenHelper(): DBOpenHelper = dbOpenHelper!!
|
||||||
|
|
||||||
|
fun requireDb(): SQLiteDatabase = requireDbOpenHelper().writableDatabase!!
|
||||||
|
|
||||||
private fun inject() {
|
private fun inject() {
|
||||||
val injection = getInstance(context!!)
|
val injection = getInstance(context!!)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,202 +0,0 @@
|
||||||
package fr.free.nrw.commons.explore.recentsearches;
|
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.UriMatcher;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteQueryBuilder;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
|
||||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerContentProvider;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import static android.content.UriMatcher.NO_MATCH;
|
|
||||||
import static fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.ALL_FIELDS;
|
|
||||||
import static fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.COLUMN_ID;
|
|
||||||
import static fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.TABLE_NAME;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class contains functions for executing queries for
|
|
||||||
* inserting, searching, deleting, editing recent searches in SqLite DB
|
|
||||||
**/
|
|
||||||
public class RecentSearchesContentProvider extends CommonsDaggerContentProvider {
|
|
||||||
|
|
||||||
// For URI matcher
|
|
||||||
private static final int RECENT_SEARCHES = 1;
|
|
||||||
private static final int RECENT_SEARCHES_ID = 2;
|
|
||||||
private static final String BASE_PATH = "recent_searches";
|
|
||||||
public static final Uri BASE_URI = Uri.parse("content://" + BuildConfig.RECENT_SEARCH_AUTHORITY + "/" + BASE_PATH);
|
|
||||||
private static final UriMatcher uriMatcher = new UriMatcher(NO_MATCH);
|
|
||||||
|
|
||||||
static {
|
|
||||||
uriMatcher.addURI(BuildConfig.RECENT_SEARCH_AUTHORITY, BASE_PATH, RECENT_SEARCHES);
|
|
||||||
uriMatcher.addURI(BuildConfig.RECENT_SEARCH_AUTHORITY, BASE_PATH + "/#", RECENT_SEARCHES_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Uri uriForId(int id) {
|
|
||||||
return Uri.parse(BASE_URI.toString() + "/" + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject DBOpenHelper dbOpenHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This functions executes query for searching recent searches in SqLite DB
|
|
||||||
**/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
|
|
||||||
String[] selectionArgs, String sortOrder) {
|
|
||||||
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
|
||||||
queryBuilder.setTables(TABLE_NAME);
|
|
||||||
|
|
||||||
int uriType = uriMatcher.match(uri);
|
|
||||||
|
|
||||||
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
|
||||||
Cursor cursor;
|
|
||||||
|
|
||||||
switch (uriType) {
|
|
||||||
case RECENT_SEARCHES:
|
|
||||||
cursor = queryBuilder.query(db, projection, selection, selectionArgs,
|
|
||||||
null, null, sortOrder);
|
|
||||||
break;
|
|
||||||
case RECENT_SEARCHES_ID:
|
|
||||||
cursor = queryBuilder.query(db,
|
|
||||||
ALL_FIELDS,
|
|
||||||
"_id = ?",
|
|
||||||
new String[]{uri.getLastPathSegment()},
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
sortOrder
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown URI" + uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
|
||||||
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType(@NonNull Uri uri) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This functions executes query for inserting a recentSearch object in SqLite DB
|
|
||||||
**/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public Uri insert(@NonNull Uri uri, ContentValues contentValues) {
|
|
||||||
int uriType = uriMatcher.match(uri);
|
|
||||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
|
||||||
long id;
|
|
||||||
switch (uriType) {
|
|
||||||
case RECENT_SEARCHES:
|
|
||||||
id = sqlDB.insert(TABLE_NAME, null, contentValues);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown URI: " + uri);
|
|
||||||
}
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return Uri.parse(BASE_URI + "/" + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This functions executes query for deleting a recentSearch object in SqLite DB
|
|
||||||
**/
|
|
||||||
@Override
|
|
||||||
public int delete(@NonNull Uri uri, String s, String[] strings) {
|
|
||||||
int rows;
|
|
||||||
int uriType = uriMatcher.match(uri);
|
|
||||||
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
|
||||||
switch (uriType) {
|
|
||||||
case RECENT_SEARCHES_ID:
|
|
||||||
Timber.d("Deleting recent searches id %s", uri.getLastPathSegment());
|
|
||||||
rows = db.delete(RecentSearchesDao.Table.TABLE_NAME,
|
|
||||||
"_id = ?",
|
|
||||||
new String[]{uri.getLastPathSegment()}
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown URI" + uri);
|
|
||||||
}
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This functions executes query for inserting multiple recentSearch objects in SqLite DB
|
|
||||||
**/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
|
|
||||||
Timber.d("Hello, bulk insert! (RecentSearchesContentProvider)");
|
|
||||||
int uriType = uriMatcher.match(uri);
|
|
||||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
|
||||||
sqlDB.beginTransaction();
|
|
||||||
switch (uriType) {
|
|
||||||
case RECENT_SEARCHES:
|
|
||||||
for (ContentValues value : values) {
|
|
||||||
Timber.d("Inserting! %s", value);
|
|
||||||
sqlDB.insert(TABLE_NAME, null, value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown URI: " + uri);
|
|
||||||
}
|
|
||||||
sqlDB.setTransactionSuccessful();
|
|
||||||
sqlDB.endTransaction();
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return values.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This functions executes query for updating a particular recentSearch object in SqLite DB
|
|
||||||
**/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public int update(@NonNull Uri uri, ContentValues contentValues, String selection,
|
|
||||||
String[] selectionArgs) {
|
|
||||||
/*
|
|
||||||
SQL Injection warnings: First, note that we're not exposing this to the
|
|
||||||
outside world (exported="false"). Even then, we should make sure to sanitize
|
|
||||||
all user input appropriately. Input that passes through ContentValues
|
|
||||||
should be fine. So only issues are those that pass in via concating.
|
|
||||||
|
|
||||||
In here, the only concat created argument is for id. It is cast to an int,
|
|
||||||
and will error out otherwise.
|
|
||||||
*/
|
|
||||||
int uriType = uriMatcher.match(uri);
|
|
||||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
|
||||||
int rowsUpdated;
|
|
||||||
switch (uriType) {
|
|
||||||
case RECENT_SEARCHES_ID:
|
|
||||||
if (TextUtils.isEmpty(selection)) {
|
|
||||||
int id = Integer.valueOf(uri.getLastPathSegment());
|
|
||||||
rowsUpdated = sqlDB.update(TABLE_NAME,
|
|
||||||
contentValues,
|
|
||||||
COLUMN_ID + " = ?",
|
|
||||||
new String[]{String.valueOf(id)});
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Parameter `selection` should be empty when updating an ID");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown URI: " + uri + " with type " + uriType);
|
|
||||||
}
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return rowsUpdated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
package fr.free.nrw.commons.explore.recentsearches
|
||||||
|
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.content.UriMatcher
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.database.sqlite.SQLiteQueryBuilder
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import fr.free.nrw.commons.BuildConfig
|
||||||
|
import fr.free.nrw.commons.di.CommonsDaggerContentProvider
|
||||||
|
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.ALL_FIELDS
|
||||||
|
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.COLUMN_ID
|
||||||
|
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.TABLE_NAME
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class contains functions for executing queries for
|
||||||
|
* inserting, searching, deleting, editing recent searches in SqLite DB
|
||||||
|
*/
|
||||||
|
class RecentSearchesContentProvider : CommonsDaggerContentProvider() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions executes query for searching recent searches in SqLite DB
|
||||||
|
*/
|
||||||
|
override fun query(
|
||||||
|
uri: Uri, projection: Array<String>?, selection: String?,
|
||||||
|
selectionArgs: Array<String>?, sortOrder: String?
|
||||||
|
): Cursor {
|
||||||
|
val queryBuilder = SQLiteQueryBuilder().apply {
|
||||||
|
tables = TABLE_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
val uriType = uriMatcher.match(uri)
|
||||||
|
|
||||||
|
val cursor = when (uriType) {
|
||||||
|
RECENT_SEARCHES -> queryBuilder.query(
|
||||||
|
requireDb(), projection, selection, selectionArgs,
|
||||||
|
null, null, sortOrder
|
||||||
|
)
|
||||||
|
|
||||||
|
RECENT_SEARCHES_ID -> queryBuilder.query(
|
||||||
|
requireDb(),
|
||||||
|
ALL_FIELDS,
|
||||||
|
"$COLUMN_ID = ?",
|
||||||
|
arrayOf(uri.lastPathSegment),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
sortOrder
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> throw IllegalArgumentException("Unknown URI$uri")
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor.setNotificationUri(requireContext().contentResolver, uri)
|
||||||
|
|
||||||
|
return cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getType(uri: Uri): String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions executes query for inserting a recentSearch object in SqLite DB
|
||||||
|
*/
|
||||||
|
override fun insert(uri: Uri, contentValues: ContentValues?): Uri? {
|
||||||
|
val uriType = uriMatcher.match(uri)
|
||||||
|
val id: Long = when (uriType) {
|
||||||
|
RECENT_SEARCHES -> requireDb().insert(TABLE_NAME, null, contentValues)
|
||||||
|
|
||||||
|
else -> throw IllegalArgumentException("Unknown URI: $uri")
|
||||||
|
}
|
||||||
|
requireContext().contentResolver.notifyChange(uri, null)
|
||||||
|
return "$BASE_URI/$id".toUri()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions executes query for deleting a recentSearch object in SqLite DB
|
||||||
|
*/
|
||||||
|
override fun delete(uri: Uri, s: String?, strings: Array<String>?): Int {
|
||||||
|
val rows: Int
|
||||||
|
val uriType = uriMatcher.match(uri)
|
||||||
|
when (uriType) {
|
||||||
|
RECENT_SEARCHES_ID -> {
|
||||||
|
rows = requireDb().delete(
|
||||||
|
TABLE_NAME,
|
||||||
|
"_id = ?",
|
||||||
|
arrayOf(uri.lastPathSegment)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> throw IllegalArgumentException("Unknown URI - $uri")
|
||||||
|
}
|
||||||
|
requireContext().contentResolver.notifyChange(uri, null)
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions executes query for inserting multiple recentSearch objects in SqLite DB
|
||||||
|
*/
|
||||||
|
override fun bulkInsert(uri: Uri, values: Array<ContentValues>): Int {
|
||||||
|
val uriType = uriMatcher.match(uri)
|
||||||
|
val sqlDB = requireDb()
|
||||||
|
sqlDB.beginTransaction()
|
||||||
|
when (uriType) {
|
||||||
|
RECENT_SEARCHES -> for (value in values) {
|
||||||
|
sqlDB.insert(TABLE_NAME, null, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> throw IllegalArgumentException("Unknown URI: $uri")
|
||||||
|
}
|
||||||
|
sqlDB.setTransactionSuccessful()
|
||||||
|
sqlDB.endTransaction()
|
||||||
|
requireContext().contentResolver.notifyChange(uri, null)
|
||||||
|
return values.size
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions executes query for updating a particular recentSearch object in SqLite DB
|
||||||
|
*/
|
||||||
|
override fun update(
|
||||||
|
uri: Uri, contentValues: ContentValues?, selection: String?,
|
||||||
|
selectionArgs: Array<String>?
|
||||||
|
): Int {
|
||||||
|
/*
|
||||||
|
SQL Injection warnings: First, note that we're not exposing this to the
|
||||||
|
outside world (exported="false"). Even then, we should make sure to sanitize
|
||||||
|
all user input appropriately. Input that passes through ContentValues
|
||||||
|
should be fine. So only issues are those that pass in via concating.
|
||||||
|
|
||||||
|
In here, the only concat created argument is for id. It is cast to an int,
|
||||||
|
and will error out otherwise.
|
||||||
|
*/
|
||||||
|
val uriType = uriMatcher.match(uri)
|
||||||
|
val rowsUpdated: Int
|
||||||
|
when (uriType) {
|
||||||
|
RECENT_SEARCHES_ID -> if (selection.isNullOrEmpty()) {
|
||||||
|
val id = uri.lastPathSegment!!.toInt()
|
||||||
|
rowsUpdated = requireDb().update(
|
||||||
|
TABLE_NAME,
|
||||||
|
contentValues,
|
||||||
|
"$COLUMN_ID = ?",
|
||||||
|
arrayOf(id.toString())
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw IllegalArgumentException(
|
||||||
|
"Parameter `selection` should be empty when updating an ID"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> throw IllegalArgumentException("Unknown URI: $uri with type $uriType")
|
||||||
|
}
|
||||||
|
requireContext().contentResolver.notifyChange(uri, null)
|
||||||
|
return rowsUpdated
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// For URI matcher
|
||||||
|
private const val RECENT_SEARCHES = 1
|
||||||
|
private const val RECENT_SEARCHES_ID = 2
|
||||||
|
private const val BASE_PATH = "recent_searches"
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val BASE_URI: Uri = "content://${BuildConfig.RECENT_SEARCH_AUTHORITY}/$BASE_PATH".toUri()
|
||||||
|
|
||||||
|
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
|
||||||
|
|
||||||
|
init {
|
||||||
|
uriMatcher.addURI(BuildConfig.RECENT_SEARCH_AUTHORITY, BASE_PATH, RECENT_SEARCHES)
|
||||||
|
uriMatcher.addURI(BuildConfig.RECENT_SEARCH_AUTHORITY, "$BASE_PATH/#", RECENT_SEARCHES_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun uriForId(id: Int): Uri = "$BASE_URI/$id".toUri()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -3,17 +3,13 @@ package fr.free.nrw.commons.recentlanguages
|
||||||
|
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.database.sqlite.SQLiteDatabase
|
|
||||||
import android.database.sqlite.SQLiteQueryBuilder
|
import android.database.sqlite.SQLiteQueryBuilder
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.text.TextUtils
|
|
||||||
import fr.free.nrw.commons.BuildConfig
|
import fr.free.nrw.commons.BuildConfig
|
||||||
import fr.free.nrw.commons.data.DBOpenHelper
|
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerContentProvider
|
import fr.free.nrw.commons.di.CommonsDaggerContentProvider
|
||||||
import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao.Table.COLUMN_NAME
|
import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao.Table.COLUMN_NAME
|
||||||
import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao.Table.TABLE_NAME
|
import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao.Table.TABLE_NAME
|
||||||
import javax.inject.Inject
|
import androidx.core.net.toUri
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -23,27 +19,17 @@ class RecentLanguagesContentProvider : CommonsDaggerContentProvider() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val BASE_PATH = "recent_languages"
|
private const val BASE_PATH = "recent_languages"
|
||||||
val BASE_URI: Uri =
|
val BASE_URI: Uri = "content://${BuildConfig.RECENT_LANGUAGE_AUTHORITY}/$BASE_PATH".toUri()
|
||||||
Uri.parse(
|
|
||||||
"content://${BuildConfig.RECENT_LANGUAGE_AUTHORITY}/$BASE_PATH"
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append language code to the base URI
|
* Append language code to the base URI
|
||||||
* @param languageCode Code of a language
|
* @param languageCode Code of a language
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun uriForCode(languageCode: String): Uri {
|
fun uriForCode(languageCode: String): Uri = "$BASE_URI/$languageCode".toUri()
|
||||||
return Uri.parse("$BASE_URI/$languageCode")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
override fun getType(uri: Uri): String? = null
|
||||||
lateinit var dbOpenHelper: DBOpenHelper
|
|
||||||
|
|
||||||
override fun getType(uri: Uri): String? {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries the SQLite database for the recently used languages
|
* Queries the SQLite database for the recently used languages
|
||||||
|
|
@ -60,11 +46,12 @@ class RecentLanguagesContentProvider : CommonsDaggerContentProvider() {
|
||||||
selectionArgs: Array<String>?,
|
selectionArgs: Array<String>?,
|
||||||
sortOrder: String?
|
sortOrder: String?
|
||||||
): Cursor? {
|
): Cursor? {
|
||||||
val queryBuilder = SQLiteQueryBuilder()
|
val queryBuilder = SQLiteQueryBuilder().apply {
|
||||||
queryBuilder.tables = TABLE_NAME
|
tables = TABLE_NAME
|
||||||
val db = dbOpenHelper.readableDatabase
|
}
|
||||||
|
|
||||||
val cursor = queryBuilder.query(
|
val cursor = queryBuilder.query(
|
||||||
db,
|
requireDb(),
|
||||||
projection,
|
projection,
|
||||||
selection,
|
selection,
|
||||||
selectionArgs,
|
selectionArgs,
|
||||||
|
|
@ -72,7 +59,7 @@ class RecentLanguagesContentProvider : CommonsDaggerContentProvider() {
|
||||||
null,
|
null,
|
||||||
sortOrder
|
sortOrder
|
||||||
)
|
)
|
||||||
cursor.setNotificationUri(context?.contentResolver, uri)
|
cursor.setNotificationUri(requireContext().contentResolver, uri)
|
||||||
return cursor
|
return cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,12 +76,11 @@ class RecentLanguagesContentProvider : CommonsDaggerContentProvider() {
|
||||||
selection: String?,
|
selection: String?,
|
||||||
selectionArgs: Array<String>?
|
selectionArgs: Array<String>?
|
||||||
): Int {
|
): Int {
|
||||||
val sqlDB = dbOpenHelper.writableDatabase
|
|
||||||
val rowsUpdated: Int
|
val rowsUpdated: Int
|
||||||
if (selection.isNullOrEmpty()) {
|
if (selection.isNullOrEmpty()) {
|
||||||
val id = uri.lastPathSegment?.toInt()
|
val id = uri.lastPathSegment?.toInt()
|
||||||
?: throw IllegalArgumentException("Invalid URI: $uri")
|
?: throw IllegalArgumentException("Invalid URI: $uri")
|
||||||
rowsUpdated = sqlDB.update(
|
rowsUpdated = requireDb().update(
|
||||||
TABLE_NAME,
|
TABLE_NAME,
|
||||||
contentValues,
|
contentValues,
|
||||||
"$COLUMN_NAME = ?",
|
"$COLUMN_NAME = ?",
|
||||||
|
|
@ -104,7 +90,7 @@ class RecentLanguagesContentProvider : CommonsDaggerContentProvider() {
|
||||||
throw IllegalArgumentException("Parameter `selection` should be empty when updating an ID")
|
throw IllegalArgumentException("Parameter `selection` should be empty when updating an ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
context?.contentResolver?.notifyChange(uri, null)
|
requireContext().contentResolver?.notifyChange(uri, null)
|
||||||
return rowsUpdated
|
return rowsUpdated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,14 +100,13 @@ class RecentLanguagesContentProvider : CommonsDaggerContentProvider() {
|
||||||
* @param contentValues : new values to be entered to the database
|
* @param contentValues : new values to be entered to the database
|
||||||
*/
|
*/
|
||||||
override fun insert(uri: Uri, contentValues: ContentValues?): Uri? {
|
override fun insert(uri: Uri, contentValues: ContentValues?): Uri? {
|
||||||
val sqlDB = dbOpenHelper.writableDatabase
|
val id = requireDb().insert(
|
||||||
val id = sqlDB.insert(
|
|
||||||
TABLE_NAME,
|
TABLE_NAME,
|
||||||
null,
|
null,
|
||||||
contentValues
|
contentValues
|
||||||
)
|
)
|
||||||
context?.contentResolver?.notifyChange(uri, null)
|
requireContext().contentResolver?.notifyChange(uri, null)
|
||||||
return Uri.parse("$BASE_URI/$id")
|
return "$BASE_URI/$id".toUri()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -129,14 +114,12 @@ class RecentLanguagesContentProvider : CommonsDaggerContentProvider() {
|
||||||
* @param uri : contains the URI for recently used languages
|
* @param uri : contains the URI for recently used languages
|
||||||
*/
|
*/
|
||||||
override fun delete(uri: Uri, s: String?, strings: Array<String>?): Int {
|
override fun delete(uri: Uri, s: String?, strings: Array<String>?): Int {
|
||||||
val db = dbOpenHelper.readableDatabase
|
val rows = requireDb().delete(
|
||||||
Timber.d("Deleting recently used language %s", uri.lastPathSegment)
|
|
||||||
val rows = db.delete(
|
|
||||||
TABLE_NAME,
|
TABLE_NAME,
|
||||||
"language_code = ?",
|
"language_code = ?",
|
||||||
arrayOf(uri.lastPathSegment)
|
arrayOf(uri.lastPathSegment)
|
||||||
)
|
)
|
||||||
context?.contentResolver?.notifyChange(uri, null)
|
requireContext().contentResolver?.notifyChange(uri, null)
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import com.nhaarman.mockitokotlin2.verify
|
||||||
import com.nhaarman.mockitokotlin2.whenever
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
import fr.free.nrw.commons.TestCommonsApplication
|
import fr.free.nrw.commons.TestCommonsApplication
|
||||||
import fr.free.nrw.commons.bookmarks.models.Bookmark
|
import fr.free.nrw.commons.bookmarks.models.Bookmark
|
||||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider.BASE_URI
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider.Companion.BASE_URI
|
||||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.COLUMN_CREATOR
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.COLUMN_CREATOR
|
||||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.COLUMN_MEDIA_NAME
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.COLUMN_MEDIA_NAME
|
||||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.CREATE_TABLE_STATEMENT
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.CREATE_TABLE_STATEMENT
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import fr.free.nrw.commons.category.CategoryDao.Table.DROP_TABLE_STATEMENT
|
||||||
import fr.free.nrw.commons.category.CategoryDao.Table.onCreate
|
import fr.free.nrw.commons.category.CategoryDao.Table.onCreate
|
||||||
import fr.free.nrw.commons.category.CategoryDao.Table.onDelete
|
import fr.free.nrw.commons.category.CategoryDao.Table.onDelete
|
||||||
import fr.free.nrw.commons.category.CategoryDao.Table.onUpdate
|
import fr.free.nrw.commons.category.CategoryDao.Table.onUpdate
|
||||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.uriForId
|
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.Companion.uriForId
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertNotNull
|
import org.junit.Assert.assertNotNull
|
||||||
import org.junit.Assert.assertNull
|
import org.junit.Assert.assertNull
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ import com.nhaarman.mockitokotlin2.verify
|
||||||
import com.nhaarman.mockitokotlin2.whenever
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
import fr.free.nrw.commons.TestCommonsApplication
|
import fr.free.nrw.commons.TestCommonsApplication
|
||||||
import fr.free.nrw.commons.explore.models.RecentSearch
|
import fr.free.nrw.commons.explore.models.RecentSearch
|
||||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.BASE_URI
|
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.Companion.BASE_URI
|
||||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.uriForId
|
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.Companion.uriForId
|
||||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.ALL_FIELDS
|
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.ALL_FIELDS
|
||||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.COLUMN_ID
|
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.COLUMN_ID
|
||||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.COLUMN_LAST_USED
|
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao.Table.COLUMN_LAST_USED
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue