diff --git a/build.gradle b/build.gradle index 9febb49..4640cb4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.3.0' repositories { + google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.2' + classpath 'com.android.tools.build:gradle:3.2.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -13,6 +16,7 @@ buildscript { allprojects { repositories { + google() jcenter() } } diff --git a/example/build.gradle b/example/build.gradle index e298d95..a7c8f04 100644 --- a/example/build.gradle +++ b/example/build.gradle @@ -1,15 +1,15 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 24 - buildToolsVersion "23.0.2" + compileSdkVersion 28 + buildToolsVersion "28.0.3" defaultConfig { applicationId "world.rafoufoun.providerdelegate.example" minSdkVersion 14 - targetSdkVersion 24 - versionCode 1 - versionName "1.0" + targetSdkVersion 28 + versionCode 2 + versionName "2.0" } buildTypes { release { @@ -20,7 +20,6 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:24.0.0' - compile project(':library') + implementation project(':library') + implementation 'com.android.support:appcompat-v7:28.0.0' } diff --git a/example/src/main/java/world/rafoufoun/providerdelegate/example/database/ExampleDatabase.java b/example/src/main/java/world/rafoufoun/providerdelegate/example/database/ExampleDatabase.java index a212b38..a116a1f 100644 --- a/example/src/main/java/world/rafoufoun/providerdelegate/example/database/ExampleDatabase.java +++ b/example/src/main/java/world/rafoufoun/providerdelegate/example/database/ExampleDatabase.java @@ -8,23 +8,23 @@ public class ExampleDatabase extends SQLiteOpenHelper { - private static final String DATABASE_NAME = "example"; - private static final int DATABASE_VERSION = 1; + private static final String DATABASE_NAME = "example"; + private static final int DATABASE_VERSION = 1; - public ExampleDatabase(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } + public ExampleDatabase(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + ExampleTable.TABLE_NAME + " ( '" + ExampleTable._ID + "' INTEGER PRIMARY KEY AUTOINCREMENT, '" + ExampleTable.TITLE + "' TEXT NOT NULL );"); - db.execSQL("INSERT INTO " + ExampleTable.TABLE_NAME + " ( '" + ExampleTable.TITLE + "' ) VALUES ('Hello World');"); - db.execSQL("INSERT INTO " + ExampleTable.TABLE_NAME + " ( '" + ExampleTable.TITLE + "' ) VALUES ('Bonjour');"); - db.execSQL("INSERT INTO " + ExampleTable.TABLE_NAME + " ( '" + ExampleTable.TITLE + "' ) VALUES ('Hallo');"); - } + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + ExampleTable.TABLE_NAME + " ( '" + ExampleTable._ID + "' INTEGER PRIMARY KEY AUTOINCREMENT, '" + ExampleTable.TITLE + "' TEXT NOT NULL );"); + db.execSQL("INSERT INTO " + ExampleTable.TABLE_NAME + " ( '" + ExampleTable.TITLE + "' ) VALUES ('Hello World');"); + db.execSQL("INSERT INTO " + ExampleTable.TABLE_NAME + " ( '" + ExampleTable.TITLE + "' ) VALUES ('Bonjour');"); + db.execSQL("INSERT INTO " + ExampleTable.TABLE_NAME + " ( '" + ExampleTable.TITLE + "' ) VALUES ('Hallo');"); + } - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - } + } } diff --git a/example/src/main/java/world/rafoufoun/providerdelegate/example/database/delegate/example/ExampleDelegate.java b/example/src/main/java/world/rafoufoun/providerdelegate/example/database/delegate/example/ExampleDelegate.java index 88fde72..b8c9d18 100644 --- a/example/src/main/java/world/rafoufoun/providerdelegate/example/database/delegate/example/ExampleDelegate.java +++ b/example/src/main/java/world/rafoufoun/providerdelegate/example/database/delegate/example/ExampleDelegate.java @@ -7,6 +7,7 @@ import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.provider.BaseColumns; +import android.support.annotation.NonNull; import android.text.TextUtils; import world.rafoufoun.providerdelegate.ProviderDelegate; @@ -17,24 +18,26 @@ public class ExampleDelegate extends ProviderDelegate { private static final String TAG = "ExampleDelegate"; - public ExampleDelegate(String authority) { - super(authority); + public ExampleDelegate() { + super(); } @Override - protected void initUriMatcher(String authority) { - uriMatcher.addURI(authority, ExampleTable.TABLE_NAME, ConstantProviderDelegate.EXAMPLE); - uriMatcher.addURI(authority, ExampleTable.TABLE_NAME + ConstantProviderDelegate.SLASH + ConstantProviderDelegate.STAR, ConstantProviderDelegate.EXAMPLE_ITEM); + public void initUriMatcher(@NonNull String authority) { + getUriMatcher().addURI(authority, ExampleTable.TABLE_NAME, ConstantProviderDelegate.EXAMPLE); + getUriMatcher().addURI(authority, ExampleTable.TABLE_NAME + ConstantProviderDelegate.SLASH + ConstantProviderDelegate.STAR, ConstantProviderDelegate.EXAMPLE_ITEM); } + @NonNull @Override public String getTable() { return ExampleTable.TABLE_NAME; } + @NonNull @Override - public String getType(Uri uri) { - final int match = uriMatcher.match(uri); + public String getType(@NonNull Uri uri) { + final int match = getUriMatcher().match(uri); switch (match) { case ConstantProviderDelegate.EXAMPLE: return ExampleTable.CONTENT_TYPE; @@ -45,13 +48,14 @@ public String getType(Uri uri) { } } - public Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) { + @NonNull + public Uri insert(@NonNull SQLiteDatabase db, @NonNull Uri uri, ContentValues values) { long itemId = db.insert(ExampleTable.TABLE_NAME, null, values); return ExampleTable.buildItemUri((int) itemId); } - public int delete(SQLiteDatabase db, Uri uri, String selection, String[] selectionArgs) { - final int match = uriMatcher.match(uri); + public int delete(@NonNull SQLiteDatabase db, @NonNull Uri uri, String selection, String[] selectionArgs) { + final int match = getUriMatcher().match(uri); if (TextUtils.isEmpty(selection)) { selection = ""; } @@ -65,8 +69,8 @@ public int delete(SQLiteDatabase db, Uri uri, String selection, String[] selecti } } - public int update(SQLiteDatabase db, Uri uri, ContentValues values, String selection, String[] selectionArgs) { - final int match = uriMatcher.match(uri); + public int update(@NonNull SQLiteDatabase db, @NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) { + final int match = getUriMatcher().match(uri); if (TextUtils.isEmpty(selection)) { selection = ""; } @@ -80,8 +84,9 @@ public int update(SQLiteDatabase db, Uri uri, ContentValues values, String selec } } - public Cursor query(SQLiteDatabase db, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - final int match = uriMatcher.match(uri); + @NonNull + public Cursor query(@NonNull SQLiteDatabase db, @NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + final int match = getUriMatcher().match(uri); SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); switch (match) { case ConstantProviderDelegate.EXAMPLE_ITEM: diff --git a/example/src/main/java/world/rafoufoun/providerdelegate/example/database/provider/ExampleProvider.java b/example/src/main/java/world/rafoufoun/providerdelegate/example/database/provider/ExampleProvider.java index 53b1091..c18254a 100644 --- a/example/src/main/java/world/rafoufoun/providerdelegate/example/database/provider/ExampleProvider.java +++ b/example/src/main/java/world/rafoufoun/providerdelegate/example/database/provider/ExampleProvider.java @@ -2,6 +2,7 @@ import android.database.sqlite.SQLiteDatabase; +import android.support.annotation.NonNull; import world.rafoufoun.providerdelegate.DelegationProvider; import world.rafoufoun.providerdelegate.ProviderDelegateManager; @@ -19,20 +20,23 @@ public void initializeProvider() { } @Override - protected void addProviderDelegate(ProviderDelegateManager delegateManager) { - delegateManager.addDelegate(new ExampleDelegate(getAuthority())); + protected void addProviderDelegate(@NonNull ProviderDelegateManager delegateManager) { + delegateManager.addDelegate(new ExampleDelegate()); } + @NonNull @Override protected String getAuthority() { return Contract.AUTHORITY; } + @NonNull @Override protected SQLiteDatabase getWritableDatabase() { return database.getWritableDatabase(); } + @NonNull @Override protected SQLiteDatabase getReadableDatabase() { return database.getReadableDatabase(); diff --git a/example/src/main/java/world/rafoufoun/providerdelegate/example/ui/ExampleActivity.java b/example/src/main/java/world/rafoufoun/providerdelegate/example/ui/ExampleActivity.java index 97a46f4..04a6fd8 100644 --- a/example/src/main/java/world/rafoufoun/providerdelegate/example/ui/ExampleActivity.java +++ b/example/src/main/java/world/rafoufoun/providerdelegate/example/ui/ExampleActivity.java @@ -6,39 +6,38 @@ import android.support.v7.app.AppCompatActivity; import android.widget.TextView; - import world.rafoufoun.providerdelegate.example.R; import world.rafoufoun.providerdelegate.example.database.table.ExampleTable; public class ExampleActivity extends AppCompatActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity); - TextView titleItem =(TextView) findViewById(R.id.textView); - TextView countItem =(TextView) findViewById(R.id.textView2); - - Cursor cursorTitle = this.getContentResolver().query(ExampleTable.buildItemUri(1),new String[]{ExampleTable.TITLE},null,null,null); - - if(cursorTitle!=null) { - if (cursorTitle.moveToFirst()){ - titleItem.setText(String.format(getString(R.string.title_item), cursorTitle.getString(0))); - }else{ - titleItem.setText(getString(R.string.error)); - } - cursorTitle.close(); - } - - Cursor cursorCount = this.getContentResolver().query(ExampleTable.buildUri(),new String[]{"count('"+ExampleTable.TABLE_NAME+"') AS count"},null,null,null); - - if(cursorCount!=null) { - if (cursorCount.moveToFirst()) { - countItem.setText(String.format(getString(R.string.num_item), cursorCount.getInt(0))); - } else { - countItem.setText(getString(R.string.error)); - } - cursorCount.close(); - } - } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity); + TextView titleItem = findViewById(R.id.textView); + TextView countItem = findViewById(R.id.textView2); + + Cursor cursorTitle = this.getContentResolver().query(ExampleTable.buildItemUri(1), new String[]{ExampleTable.TITLE}, null, null, null); + + if (cursorTitle != null) { + if (cursorTitle.moveToFirst()) { + titleItem.setText(String.format(getString(R.string.title_item), cursorTitle.getString(0))); + } else { + titleItem.setText(getString(R.string.error)); + } + cursorTitle.close(); + } + + Cursor cursorCount = this.getContentResolver().query(ExampleTable.buildUri(), new String[]{"count('" + ExampleTable.TABLE_NAME + "') AS count"}, null, null, null); + + if (cursorCount != null) { + if (cursorCount.moveToFirst()) { + countItem.setText(String.format(getString(R.string.num_item), cursorCount.getInt(0))); + } else { + countItem.setText(getString(R.string.error)); + } + cursorCount.close(); + } + } } diff --git a/gradle.properties b/gradle.properties index ac34890..9da1d27 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,6 @@ -VERSION_NAME=1.0.1 -VERSION_CODE=5 +VERSION_NAME=2.0.0 +VERSION_CODE=6 GROUP=com.gitlab.rafoufoun - POM_DESCRIPTION=Delegate pattern applied to ContentProvider for Android applications. POM_URL=https://gitlab.com/rafoufoun/ProviderDelegate POM_SCM_URL=https://gitlab.com/rafoufoun/ProviderDelegate diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e67977c..297d844 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip diff --git a/library/build.gradle b/library/build.gradle index 4f18adb..a8b2c4c 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,14 +1,16 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + android { - compileSdkVersion 24 - buildToolsVersion "23.0.2" + compileSdkVersion 28 + buildToolsVersion "28.0.3" defaultConfig { minSdkVersion 9 - targetSdkVersion 24 + targetSdkVersion 28 versionCode 5 - versionName "1.0.1" + versionName "1.0.0" } buildTypes { release { @@ -19,10 +21,13 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' - compile 'com.android.support:support-v4:24.0.0' - compile 'com.android.support:appcompat-v7:24.0.0' + testImplementation 'junit:junit:4.12' + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'com.android.support:support-v4:28.0.0' + implementation 'com.android.support:appcompat-v7:28.0.0' } apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle' +repositories { + mavenCentral() +} diff --git a/library/src/main/java/world/rafoufoun/providerdelegate/DelegationProvider.java b/library/src/main/java/world/rafoufoun/providerdelegate/DelegationProvider.java deleted file mode 100644 index f580f61..0000000 --- a/library/src/main/java/world/rafoufoun/providerdelegate/DelegationProvider.java +++ /dev/null @@ -1,83 +0,0 @@ -package world.rafoufoun.providerdelegate; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -/** - * A ready to go {@link ContentProvider} implementation having a {@link ProviderDelegateManager} - * ready to use. You can call {@link ProviderDelegateManager#addDelegate(ProviderDelegate)} - * at any time if you have called {@link #onCreate()} into your subclass {@link DelegationProvider#onCreate()} - */ -public abstract class DelegationProvider extends ContentProvider { - - private ProviderDelegateManager delegateManager; - - /** - * Initialize the ProviderDelegateManager. - * - * @return return true if the initialization is ok. - */ - @Override - public final boolean onCreate() { - delegateManager = new ProviderDelegateManager(getContext(), getAuthority()); - initializeProvider(); - addProviderDelegate(delegateManager); - return true; - } - - /** - * Method called from {@link DelegationProvider#onCreate()} - * This stand for initializing anything you need that would normally be in {@link ContentProvider#onCreate()} - */ - public abstract void initializeProvider(); - - /** - * Thi method is called from {@link DelegationProvider#onCreate()} - * Add your {@link ProviderDelegate} here with {@link ProviderDelegateManager#addDelegate(ProviderDelegate)} - */ - protected abstract void addProviderDelegate(ProviderDelegateManager delegateManager); - - /** - * Get the authority for this provider - * - * @return return the provider authority - */ - protected abstract String getAuthority(); - - protected abstract SQLiteDatabase getWritableDatabase(); - - protected abstract SQLiteDatabase getReadableDatabase(); - - @Nullable - @Override - public String getType(@NonNull Uri uri) { - return delegateManager.getType(uri); - } - - @Nullable - @Override - public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - return delegateManager.query(getReadableDatabase(), uri, projection, selection, selectionArgs, sortOrder); - } - - @Nullable - @Override - public Uri insert(@NonNull Uri uri, ContentValues values) { - return delegateManager.insert(getWritableDatabase(), uri, values); - } - - @Override - public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) { - return delegateManager.delete(getWritableDatabase(), uri, selection, selectionArgs); - } - - @Override - public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return delegateManager.update(getWritableDatabase(), uri, values, selection, selectionArgs); - } -} diff --git a/library/src/main/java/world/rafoufoun/providerdelegate/DelegationProvider.kt b/library/src/main/java/world/rafoufoun/providerdelegate/DelegationProvider.kt new file mode 100644 index 0000000..4d8021d --- /dev/null +++ b/library/src/main/java/world/rafoufoun/providerdelegate/DelegationProvider.kt @@ -0,0 +1,72 @@ +package world.rafoufoun.providerdelegate + +import android.content.ContentProvider +import android.content.ContentValues +import android.database.Cursor +import android.database.sqlite.SQLiteDatabase +import android.net.Uri + +/** + * A ready to go [ContentProvider] implementation having a [ProviderDelegateManager] + * ready to use. You can call [ProviderDelegateManager.addDelegate] + * at any time if you have called [.onCreate] into your subclass [DelegationProvider.onCreate] + */ +abstract class DelegationProvider : ContentProvider() { + + private lateinit var delegateManager: ProviderDelegateManager + + /** + * Get the authority for this provider + * + * @return return the provider authority + */ + protected abstract val authority: String + + protected abstract val writableDatabase: SQLiteDatabase + + protected abstract val readableDatabase: SQLiteDatabase + + /** + * Initialize the ProviderDelegateManager. + * + * @return return true if the initialization is ok. + */ + override fun onCreate(): Boolean { + delegateManager = ProviderDelegateManager(context!!.contentResolver, authority) + initializeProvider() + addProviderDelegate(delegateManager) + return true + } + + /** + * Method called from [DelegationProvider.onCreate] + * This stand for initializing anything you need that would normally be in [ContentProvider.onCreate] + */ + abstract fun initializeProvider() + + /** + * Thi method is called from [DelegationProvider.onCreate] + * Add your [ProviderDelegate] here with [ProviderDelegateManager.addDelegate] + */ + protected abstract fun addProviderDelegate(delegateManager: ProviderDelegateManager) + + override fun getType(uri: Uri): String { + return delegateManager.getType(uri) + } + + override fun query(uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor { + return delegateManager.query(readableDatabase, uri, projection, selection, selectionArgs, sortOrder) + } + + override fun insert(uri: Uri, values: ContentValues?): Uri { + return delegateManager.insert(writableDatabase, uri, values) + } + + override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int { + return delegateManager.delete(writableDatabase, uri, selection, selectionArgs) + } + + override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int { + return delegateManager.update(writableDatabase, uri, values, selection, selectionArgs) + } +} diff --git a/library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegate.java b/library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegate.kt similarity index 51% rename from library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegate.java rename to library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegate.kt index 4d5f647..9318367 100644 --- a/library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegate.java +++ b/library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegate.kt @@ -1,74 +1,69 @@ -package world.rafoufoun.providerdelegate; +package world.rafoufoun.providerdelegate -import android.content.ContentValues; -import android.content.UriMatcher; -import android.database.ContentObserver; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; +import android.content.ContentValues +import android.content.UriMatcher +import android.database.Cursor +import android.database.sqlite.SQLiteDatabase +import android.net.Uri /** * This abstract class handle all the database logic for a database table. Here are done all the operations * related to one model object. - *

- * CRUD methods throw an {@link UnsupportedOperationException} by default. Override them only if needed. + * + * + * CRUD methods throw an [UnsupportedOperationException] by default. Override them only if needed. */ -public abstract class ProviderDelegate { +abstract class ProviderDelegate { - protected UriMatcher uriMatcher; - - public ProviderDelegate(String authority) { - this.uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - initUriMatcher(authority); - } - - /** - * Initialize the {@link #uriMatcher}. Declare all the handled URIs by this {@link ProviderDelegate} associating it with a URI code (int). - * These code will be used into you CRUD methods to know which URI is called. - */ - protected abstract void initUriMatcher(String authority); + protected val uriMatcher: UriMatcher by lazy { UriMatcher(UriMatcher.NO_MATCH) } /** * Return the table to which this delegate responds. This value MUST be unique across all the delegates * * @return the handled URI as String */ - public abstract String getTable(); + abstract val table: String /** - * {@link android.content.ContentProvider#getType(Uri)} + * Initialize the [uriMatcher]. Declare all the handled URIs by this [ProviderDelegate] associating it with a URI code (int). + * These code will be used into you CRUD methods to know which URI is called. + */ + abstract fun initUriMatcher(authority: String) + + /** + * [android.content.ContentProvider.getType] * * @param uri the URI to query. * @return a MIME type string, or null if there is no type. */ - public abstract String getType(Uri uri); + abstract fun getType(uri: Uri): String /** - * {@link android.content.ContentProvider#insert(Uri, ContentValues)} + * [android.content.ContentProvider.insert] * * @param db the database object, must be writable * @param uri the URI to query. * @param values the content values to insert * @return the URI for the newly inserted item. */ - public Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) { - throw new UnsupportedOperationException("insert not allowed on this uri : " + uri); + open fun insert(db: SQLiteDatabase, uri: Uri, values: ContentValues?): Uri { + throw UnsupportedOperationException("insert not allowed on this uri : $uri") } /** - * {@link android.content.ContentProvider#delete(Uri, String, String[])} + * [android.content.ContentProvider.delete] * * @param db the database object, must be writable * @param uri the URI to query. * @param selection An optional restriction to apply to rows when deleting. * @return the number of rows affected. */ - public int delete(SQLiteDatabase db, Uri uri, String selection, String[] selectionArgs) { - throw new UnsupportedOperationException("delete not allowed on this uri : " + uri); + open fun delete(db: SQLiteDatabase, uri: Uri, selection: String?, selectionArgs: Array?): Int { + throw UnsupportedOperationException("delete not allowed on this uri : $uri") } /** - * {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])} + * [android.content.ContentProvider.update] * * @param db the database object, must be writable * @param uri the URI to query. @@ -76,12 +71,12 @@ public int delete(SQLiteDatabase db, Uri uri, String selection, String[] selecti * @param selection An optional filter to match rows to update. * @return the number of rows affected. */ - public int update(SQLiteDatabase db, Uri uri, ContentValues values, String selection, String[] selectionArgs) { - throw new UnsupportedOperationException("update not allowed on this uri : " + uri); + open fun update(db: SQLiteDatabase, uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int { + throw UnsupportedOperationException("update not allowed on this uri : $uri") } /** - * {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)} + * [android.content.ContentProvider.query] * * @param db the database object, readable is OK * @param uri the URI to query @@ -91,18 +86,16 @@ public int update(SQLiteDatabase db, Uri uri, ContentValues values, String selec * @param sortOrder how the rows in the cursor should be sorted. If null then the provider is free to define the sort order. * @return a Cursor or null. */ - public Cursor query(SQLiteDatabase db, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - throw new UnsupportedOperationException("query not allowed on this uri : " + uri); + open fun query(db: SQLiteDatabase, uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor { + throw UnsupportedOperationException("query not allowed on this uri : $uri") } /** - * check if a notification must be sent through the ContentResolver. See {@link android.content.ContentResolver#notifyChange(Uri, ContentObserver)} + * check if a notification must be sent through the ContentResolver. See [android.content.ContentResolver.notifyChange] * * @param uri the URI on which the operation has been done * @param operation the operation done on the URI * @return true if must notify, false otherwise. Return true by default */ - public boolean mustSendNotification(Uri uri, Operation operation) { - return true; - } + open fun mustSendNotification(uri: Uri, operation: Operation): Boolean = true } diff --git a/library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegateManager.java b/library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegateManager.java deleted file mode 100644 index a383d90..0000000 --- a/library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegateManager.java +++ /dev/null @@ -1,197 +0,0 @@ -package world.rafoufoun.providerdelegate; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.text.TextUtils; - -import java.util.HashMap; -import java.util.List; - -/** - * This class is the element that link the ContentProvider and all the {@link ProviderDelegate}. - * Here are dispatched all the ContentProvider calls to match the right {@link ProviderDelegate} registered. - */ -public class ProviderDelegateManager { - - protected final Context context; - - /** - * The ContentProvider's authority - */ - protected final String authority; - - /** - * Collection of delegates - */ - protected final HashMap delegates; - - public ProviderDelegateManager(Context context, String authority) { - this.context = context; - delegates = new HashMap<>(); - this.authority = authority; - } - - /** - * Add a delegate. Throw IllegalArgumentException if this delegate is already registered, regarding the - * table (see {@link ProviderDelegate#getTable()}) - * - * @param delegate the delegate to add. - * @throws NullPointerException if delegate is null - * @throws IllegalArgumentException if delegate is already registered or another delegate handle this Uri - */ - public void addDelegate(ProviderDelegate delegate) { - if (delegate == null) { - throw new NullPointerException("ProviderDelegate is null, can't add !"); - } - - String table = delegate.getTable(); - if (delegates.get(table) != null) { - throw new IllegalArgumentException("ProviderDelegate is already registered !"); - } - - delegates.put(table, delegate); - } - - public void removeDelegate(ProviderDelegate delegate) { - if (delegate == null) { - throw new NullPointerException("ProviderDelegate is null, can't remove !"); - } - - String table = delegate.getTable(); - if (delegates.get(table) == null) { - throw new IllegalArgumentException("ProviderDelegate is not registered !"); - } - - delegates.remove(table); - } - - - public String getType(Uri uri) { - - for (ProviderDelegate delegate : delegates.values()) { - if (isTableMatcher(delegate.getTable(), uri)) { - return delegate.getType(uri); - } - } - - throw new IllegalArgumentException("No ProviderDelegate registered for this Uri ! " + uri); - } - - /** - * This method must be called in {@link DelegationProvider#query(Uri, String[], String, String[], String)} - * - * @param db Readable Database - * @param uri Uri - * @param projection Projection - * @param selection Selection - * @param selectionArgs Selection args - * @param sortOrder Sort order - * @return Cursor - * @throws IllegalArgumentException if no delegate is registered for this uri - */ - public Cursor query(SQLiteDatabase db, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - - for (ProviderDelegate delegate : delegates.values()) { - if (isTableMatcher(delegate.getTable(), uri)) { - Cursor cursor = delegate.query(db, uri, projection, selection, selectionArgs, sortOrder); - cursor.setNotificationUri(context.getContentResolver(), uri); - return cursor; - } - } - throw new IllegalArgumentException("No ProviderDelegate registered for this Uri ! " + uri); - } - - /** - * This method must be called in {@link DelegationProvider#insert(Uri, ContentValues)} - * - * @param db Writable database - * @param uri Uri - * @param values Values to be inserted - * @return New item Uri - * @throws IllegalArgumentException if no delegate is registered for this uri - */ - public Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) { - - for (ProviderDelegate delegate : delegates.values()) { - if (isTableMatcher(delegate.getTable(), uri)) { - Uri newUri = delegate.insert(db, uri, values); - if (delegate.mustSendNotification(uri, Operation.INSERT)) { - notifyUri(context, uri); - } - return newUri; - } - } - - throw new IllegalArgumentException("No ProviderDelegate registered for this Uri ! " + uri); - } - - /** - * This method must be called in {@link DelegationProvider#delete(Uri, String, String[])} - * - * @param db Writable database - * @param uri Uri - * @param selection Selection - * @param selectionArgs Selection args - * @return Deleted row count - * @throws IllegalArgumentException if no delegate is registered for this uri - */ - public int delete(SQLiteDatabase db, Uri uri, String selection, String[] selectionArgs) { - - for (ProviderDelegate delegate : delegates.values()) { - if (isTableMatcher(delegate.getTable(), uri)) { - int rowDeleted = delegate.delete(db, uri, selection, selectionArgs); - if (delegate.mustSendNotification(uri, Operation.DELETE)) { - notifyUri(context, uri); - } - return rowDeleted; - } - } - - throw new IllegalArgumentException("No ProviderDelegate registered for this Uri ! " + uri); - } - - /** - * This method must be called in {@link DelegationProvider#update(Uri, ContentValues, String, String[])} - * - * @param db Writable database - * @param uri Uri - * @param values Values to update - * @param selection Selection - * @param selectionArgs Selection args - * @return Updated row count - * @throws IllegalArgumentException if no delegate is registered for this uri - */ - public int update(SQLiteDatabase db, Uri uri, ContentValues values, String selection, String[] selectionArgs) { - - for (ProviderDelegate delegate : delegates.values()) { - if (isTableMatcher(delegate.getTable(), uri)) { - int rowUpdate = delegate.update(db, uri, values, selection, selectionArgs); - if (delegate.mustSendNotification(uri, Operation.UPDATE)) { - notifyUri(context, uri); - } - return rowUpdate; - } - } - - throw new IllegalArgumentException("No ProviderDelegate registered for this Uri ! " + uri); - } - - private boolean isTableMatcher(String table, Uri uri) { - List segments = uri.getPathSegments(); - if (segments != null && segments.size() > 0) { - String uriTable = segments.get(0); - return TextUtils.equals(table, uriTable); - } else { - return false; - } - } - - public void notifyUri(Context context, Uri uri) { - if (context != null) { - context.getContentResolver().notifyChange(uri, null); - } - } -} diff --git a/library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegateManager.kt b/library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegateManager.kt new file mode 100644 index 0000000..d52b884 --- /dev/null +++ b/library/src/main/java/world/rafoufoun/providerdelegate/ProviderDelegateManager.kt @@ -0,0 +1,173 @@ +package world.rafoufoun.providerdelegate + +import android.content.ContentResolver +import android.content.ContentValues +import android.database.Cursor +import android.database.sqlite.SQLiteDatabase +import android.net.Uri +import android.text.TextUtils +import java.util.* + +/** + * This class is the element that link the ContentProvider and all the [ProviderDelegate]. + * Here are dispatched all the ContentProvider calls to match the right [ProviderDelegate] registered. + */ +class ProviderDelegateManager(private val contentResolver: ContentResolver, private val authority: String) { + + /** + * Collection of delegates + */ + private val delegates: HashMap = HashMap() + + /** + * Add a delegate. Throw IllegalArgumentException if this delegate is already registered, regarding the + * table (see [ProviderDelegate.table]) + * + * @param delegate the delegate to add. + * @throws NullPointerException if delegate is null + * @throws IllegalArgumentException if delegate is already registered or another delegate handle this Uri + */ + fun addDelegate(delegate: ProviderDelegate) { + val table = delegate.table + if (delegates.containsKey(table)) { + throw IllegalArgumentException("ProviderDelegate is already registered !") + } + + delegate.initUriMatcher(authority) + delegates[table] = delegate + } + + fun removeDelegate(delegate: ProviderDelegate) { + val table = delegate.table + if (!delegates.containsKey(table)) { + throw IllegalArgumentException("ProviderDelegate is not registered !") + } + + delegates.remove(table) + } + + + fun getType(uri: Uri): String { + + for (delegate in delegates.values) { + if (isTableMatcher(delegate.table, uri)) { + return delegate.getType(uri) + } + } + + throw IllegalArgumentException("No ProviderDelegate registered for this Uri ! $uri") + } + + /** + * This method must be called in [DelegationProvider.query] + * + * @param db Readable Database + * @param uri Uri + * @param projection Projection + * @param selection Selection + * @param selectionArgs Selection args + * @param sortOrder Sort order + * @return Cursor + * @throws IllegalArgumentException if no delegate is registered for this uri + */ + fun query(db: SQLiteDatabase, uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor { + + for (delegate in delegates.values) { + if (isTableMatcher(delegate.table, uri)) { + val cursor = delegate.query(db, uri, projection, selection, selectionArgs, sortOrder) + cursor.setNotificationUri(contentResolver, uri) + return cursor + } + } + throw IllegalArgumentException("No ProviderDelegate registered for this Uri ! $uri") + } + + /** + * This method must be called in [DelegationProvider.insert] + * + * @param db Writable database + * @param uri Uri + * @param values Values to be inserted + * @return New item Uri + * @throws IllegalArgumentException if no delegate is registered for this uri + */ + fun insert(db: SQLiteDatabase, uri: Uri, values: ContentValues?): Uri { + + for (delegate in delegates.values) { + if (isTableMatcher(delegate.table, uri)) { + val newUri = delegate.insert(db, uri, values) + if (delegate.mustSendNotification(uri, Operation.INSERT)) { + notifyUri(contentResolver, uri) + } + return newUri + } + } + + throw IllegalArgumentException("No ProviderDelegate registered for this Uri ! $uri") + } + + /** + * This method must be called in [DelegationProvider.delete] + * + * @param db Writable database + * @param uri Uri + * @param selection Selection + * @param selectionArgs Selection args + * @return Deleted row count + * @throws IllegalArgumentException if no delegate is registered for this uri + */ + fun delete(db: SQLiteDatabase, uri: Uri, selection: String?, selectionArgs: Array?): Int { + + for (delegate in delegates.values) { + if (isTableMatcher(delegate.table, uri)) { + val rowDeleted = delegate.delete(db, uri, selection, selectionArgs) + if (delegate.mustSendNotification(uri, Operation.DELETE)) { + notifyUri(contentResolver, uri) + } + return rowDeleted + } + } + + throw IllegalArgumentException("No ProviderDelegate registered for this Uri ! $uri") + } + + /** + * This method must be called in [DelegationProvider.update] + * + * @param db Writable database + * @param uri Uri + * @param values Values to update + * @param selection Selection + * @param selectionArgs Selection args + * @return Updated row count + * @throws IllegalArgumentException if no delegate is registered for this uri + */ + fun update(db: SQLiteDatabase, uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int { + + for (delegate in delegates.values) { + if (isTableMatcher(delegate.table, uri)) { + val rowUpdate = delegate.update(db, uri, values, selection, selectionArgs) + if (delegate.mustSendNotification(uri, Operation.UPDATE)) { + notifyUri(contentResolver, uri) + } + return rowUpdate + } + } + + throw IllegalArgumentException("No ProviderDelegate registered for this Uri ! $uri") + } + + private fun isTableMatcher(table: String, uri: Uri): Boolean { + val segments = uri.pathSegments + return if (segments != null && segments.size > 0) { + val uriTable = segments[0] + TextUtils.equals(table, uriTable) + } else { + false + } + } + + private fun notifyUri(contentResolver: ContentResolver, uri: Uri) { + contentResolver.notifyChange(uri, null) + } +}