From 6b2bf9b87cf597cc27ebfdbe652771a0e160fdac Mon Sep 17 00:00:00 2001 From: Andrew Grosner Date: Sun, 17 Dec 2017 10:54:36 -0500 Subject: [PATCH] [content] update gradle plugin to 3.0.1. Add support for Android O content observing. --- README.md | 4 +- build.gradle | 2 +- .../contentobserver/ContentObserverTest.kt | 14 +- dbflow-tests/src/main/AndroidManifest.xml | 4 + .../dbflow/config/DatabaseDefinition.java | 2 +- .../android/dbflow/config/FlowManager.java | 2 + .../android/dbflow/list/FlowQueryList.java | 133 +++++++++--------- .../runtime/ContentResolverNotifier.java | 26 ++-- .../dbflow/runtime/FlowContentObserver.java | 32 +++-- .../dbflow/runtime/StubContentProvider.java | 56 ++++++++ .../raizlabs/android/dbflow/sql/SqlUtils.java | 38 +++-- gradle.properties | 2 +- 12 files changed, 202 insertions(+), 113 deletions(-) create mode 100644 dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/StubContentProvider.java diff --git a/README.md b/README.md index 8f6b007eb..135a7d2ca 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![Image](https://github.com/agrosner/DBFlow/blob/develop/dbflow_banner.png?raw=true) -[![JitPack.io](https://img.shields.io/badge/JitPack.io-4.1.1-red.svg?style=flat)](https://jitpack.io/#Raizlabs/DBFlow) [![Android Weekly](http://img.shields.io/badge/Android%20Weekly-%23129-2CB3E5.svg?style=flat)](http://androidweekly.net/issues/issue-129) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-DBFlow-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1134) +[![JitPack.io](https://img.shields.io/badge/JitPack.io-4.2.0-red.svg?style=flat)](https://jitpack.io/#Raizlabs/DBFlow) [![Android Weekly](http://img.shields.io/badge/Android%20Weekly-%23129-2CB3E5.svg?style=flat)](http://androidweekly.net/issues/issue-129) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-DBFlow-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1134) A robust, powerful, and very simple ORM android database library with **annotation processing**. @@ -43,7 +43,7 @@ Add the library to the project-level build.gradle, using the apt plugin to enabl apply plugin: 'kotlin-kapt' // required for kotlin. - def dbflow_version = "4.1.1" + def dbflow_version = "4.2.0" // or dbflow_version = "develop-SNAPSHOT" for grabbing latest dependency in your project on the develop branch // or 10-digit short-hash of a specific commit. (Useful for bugs fixed in develop, but not in a release yet) diff --git a/build.gradle b/build.gradle index d1d25895c..5b5bd31c1 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.0-rc2' + classpath 'com.android.tools.build:gradle:3.0.1' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.7.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" diff --git a/dbflow-tests/src/androidTest/java/com/raizlabs/android/dbflow/contentobserver/ContentObserverTest.kt b/dbflow-tests/src/androidTest/java/com/raizlabs/android/dbflow/contentobserver/ContentObserverTest.kt index aaf231ac4..6f46cee17 100644 --- a/dbflow-tests/src/androidTest/java/com/raizlabs/android/dbflow/contentobserver/ContentObserverTest.kt +++ b/dbflow-tests/src/androidTest/java/com/raizlabs/android/dbflow/contentobserver/ContentObserverTest.kt @@ -16,7 +16,6 @@ import com.raizlabs.android.dbflow.sql.language.Delete import com.raizlabs.android.dbflow.sql.language.SQLOperator import com.raizlabs.android.dbflow.structure.BaseModel import org.junit.Assert.assertEquals -import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import java.util.concurrent.CountDownLatch @@ -34,11 +33,12 @@ class ContentObserverTest : BaseInstrumentedUnitTest() { @Test fun testSpecificUris() { val conditionGroup = FlowManager.getModelAdapter(User::class.java) - .getPrimaryConditionClause(user) - val uri = SqlUtils.getNotificationUri(User::class.java, BaseModel.Action.DELETE, - conditionGroup.conditions.toTypedArray()) + .getPrimaryConditionClause(user) + val uri = SqlUtils.getNotificationUri(FlowManager.DEFAULT_AUTHORITY, + User::class.java, BaseModel.Action.DELETE, + conditionGroup.conditions.toTypedArray()) - assertEquals(uri.authority, FlowManager.getTableName(User::class.java)) + assertEquals(uri.authority, FlowManager.DEFAULT_AUTHORITY) assertEquals(uri.fragment, BaseModel.Action.DELETE.name) assertEquals(Uri.decode(uri.getQueryParameter(Uri.encode(id.query))), "5") assertEquals(Uri.decode(uri.getQueryParameter(Uri.encode(name.query))), "Something") @@ -69,7 +69,7 @@ class ContentObserverTest : BaseInstrumentedUnitTest() { } private fun assertProperConditions(action: BaseModel.Action, userFunc: (User) -> Unit) { - val contentObserver = FlowContentObserver() + val contentObserver = FlowContentObserver(FlowManager.DEFAULT_AUTHORITY) val countDownLatch = CountDownLatch(1) val mockOnModelStateChangedListener = MockOnModelStateChangedListener(countDownLatch) contentObserver.addModelChangeListener(mockOnModelStateChangedListener) @@ -79,7 +79,7 @@ class ContentObserverTest : BaseInstrumentedUnitTest() { countDownLatch.await() val ops = mockOnModelStateChangedListener.operators!! - assertTrue(ops.size == 2) + assertEquals(2, ops.size) assertEquals(ops[0].columnName(), id.query) assertEquals(ops[1].columnName(), name.query) assertEquals(ops[1].value(), "Something") diff --git a/dbflow-tests/src/main/AndroidManifest.xml b/dbflow-tests/src/main/AndroidManifest.xml index 1f4db6ec2..201a00531 100644 --- a/dbflow-tests/src/main/AndroidManifest.xml +++ b/dbflow-tests/src/main/AndroidManifest.xml @@ -13,6 +13,10 @@ + + diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseDefinition.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseDefinition.java index 737c0e13f..637246f61 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseDefinition.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseDefinition.java @@ -263,7 +263,7 @@ public ModelNotifier getModelNotifier() { DatabaseConfig config = FlowManager.getConfig().databaseConfigMap() .get(getAssociatedDatabaseClassFile()); if (config == null || config.modelNotifier() == null) { - modelNotifier = new ContentResolverNotifier(); + modelNotifier = new ContentResolverNotifier(FlowManager.DEFAULT_AUTHORITY); } else { modelNotifier = config.modelNotifier(); } diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowManager.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowManager.java index 836d0d913..569c02173 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowManager.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowManager.java @@ -65,6 +65,8 @@ public boolean isInitialized() { private static final String DEFAULT_DATABASE_HOLDER_CLASSNAME = DEFAULT_DATABASE_HOLDER_PACKAGE_NAME + "." + DEFAULT_DATABASE_HOLDER_NAME; + public static final String DEFAULT_AUTHORITY = "com.dbflow.authority"; + /** * Returns the table name for the specific model class * diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/list/FlowQueryList.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/list/FlowQueryList.java index fb7e9aef5..ba83b4f67 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/list/FlowQueryList.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/list/FlowQueryList.java @@ -37,7 +37,7 @@ * on the underlying table. */ public class FlowQueryList extends FlowContentObserver - implements List, IFlowCursorIterator { + implements List, IFlowCursorIterator { private static final Handler REFRESH_HANDLER = new Handler(Looper.myLooper()); @@ -60,16 +60,17 @@ public class FlowQueryList extends FlowContentObserver private FlowQueryList(Builder builder) { + super(FlowManager.DEFAULT_AUTHORITY); transact = builder.transact; changeInTransaction = builder.changeInTransaction; successCallback = builder.success; errorCallback = builder.error; internalCursorList = new FlowCursorList.Builder<>(builder.table) - .cursor(builder.cursor) - .cacheModels(builder.cacheModels) - .modelQueriable(builder.modelQueriable) - .modelCache(builder.modelCache) - .build(); + .cursor(builder.cursor) + .cacheModels(builder.cacheModels) + .modelQueriable(builder.modelQueriable) + .modelCache(builder.modelCache) + .build(); } /** @@ -92,8 +93,8 @@ public void removeOnCursorRefreshListener(@NonNull OnCursorRefreshListener table) { throw new RuntimeException( - "This method is not to be used in the FlowQueryList. We should only ever receive" + - " notifications for one class here. Call registerForContentChanges(Context) instead"); + "This method is not to be used in the FlowQueryList. We should only ever receive" + + " notifications for one class here. Call registerForContentChanges(Context) instead"); } @Override @@ -165,10 +166,10 @@ InstanceAdapter getInstanceAdapter() { @NonNull public Builder newBuilder() { return new Builder<>(internalCursorList) - .success(successCallback) - .error(errorCallback) - .changeInTransaction(changeInTransaction) - .transact(transact); + .success(successCallback) + .error(errorCallback) + .changeInTransaction(changeInTransaction) + .transact(transact); } /** @@ -223,10 +224,10 @@ public void add(int location, @Nullable TModel model) { public boolean add(@Nullable TModel model) { if (model != null) { Transaction transaction = FlowManager.getDatabaseForTable(internalCursorList.table()) - .beginTransactionAsync(new ProcessModelTransaction.Builder<>(saveModel) - .add(model).build()) - .error(internalErrorCallback) - .success(internalSuccessCallback).build(); + .beginTransactionAsync(new ProcessModelTransaction.Builder<>(saveModel) + .add(model).build()) + .error(internalErrorCallback) + .success(internalSuccessCallback).build(); if (transact) { transaction.execute(); @@ -265,10 +266,10 @@ public boolean addAll(@NonNull Collection collection) { final Collection tmpCollection = (Collection) collection; Transaction transaction = FlowManager.getDatabaseForTable(internalCursorList.table()) - .beginTransactionAsync(new ProcessModelTransaction.Builder<>(saveModel) - .addAll(tmpCollection).build()) - .error(internalErrorCallback) - .success(internalSuccessCallback).build(); + .beginTransactionAsync(new ProcessModelTransaction.Builder<>(saveModel) + .addAll(tmpCollection).build()) + .error(internalErrorCallback) + .success(internalSuccessCallback).build(); if (transact) { transaction.execute(); @@ -284,11 +285,11 @@ public boolean addAll(@NonNull Collection collection) { @Override public void clear() { Transaction transaction = FlowManager.getDatabaseForTable(internalCursorList.table()) - .beginTransactionAsync(new QueryTransaction.Builder<>( - SQLite.delete().from(internalCursorList.table())).build()) - .error(internalErrorCallback) - .success(internalSuccessCallback) - .build(); + .beginTransactionAsync(new QueryTransaction.Builder<>( + SQLite.delete().from(internalCursorList.table())).build()) + .error(internalErrorCallback) + .success(internalSuccessCallback) + .build(); if (transact) { transaction.execute(); @@ -369,7 +370,7 @@ public TModel get(int row) { @Override public int indexOf(Object object) { throw new UnsupportedOperationException( - "We cannot determine which index in the table this item exists at efficiently"); + "We cannot determine which index in the table this item exists at efficiently"); } @Override @@ -396,7 +397,7 @@ public FlowCursorIterator iterator(int startingLocation, long limit) { @Override public int lastIndexOf(Object object) { throw new UnsupportedOperationException( - "We cannot determine which index in the table this item exists at efficiently"); + "We cannot determine which index in the table this item exists at efficiently"); } /** @@ -433,10 +434,10 @@ public TModel remove(int location) { TModel model = internalCursorList.getItem(location); Transaction transaction = FlowManager.getDatabaseForTable(internalCursorList.table()) - .beginTransactionAsync(new ProcessModelTransaction.Builder<>(deleteModel) - .add(model).build()) - .error(internalErrorCallback) - .success(internalSuccessCallback).build(); + .beginTransactionAsync(new ProcessModelTransaction.Builder<>(deleteModel) + .add(model).build()) + .error(internalErrorCallback) + .success(internalSuccessCallback).build(); if (transact) { transaction.execute(); @@ -462,10 +463,10 @@ public boolean remove(Object object) { if (internalCursorList.table().isAssignableFrom(object.getClass())) { TModel model = ((TModel) object); Transaction transaction = FlowManager.getDatabaseForTable(internalCursorList.table()) - .beginTransactionAsync(new ProcessModelTransaction.Builder<>(deleteModel) - .add(model).build()) - .error(internalErrorCallback) - .success(internalSuccessCallback).build(); + .beginTransactionAsync(new ProcessModelTransaction.Builder<>(deleteModel) + .add(model).build()) + .error(internalErrorCallback) + .success(internalSuccessCallback).build(); if (transact) { transaction.execute(); @@ -492,10 +493,10 @@ public boolean removeAll(@NonNull Collection collection) { // if its a ModelClass Collection modelCollection = (Collection) collection; Transaction transaction = FlowManager.getDatabaseForTable(internalCursorList.table()) - .beginTransactionAsync(new ProcessModelTransaction.Builder<>(deleteModel) - .addAll(modelCollection).build()) - .error(internalErrorCallback) - .success(internalSuccessCallback).build(); + .beginTransactionAsync(new ProcessModelTransaction.Builder<>(deleteModel) + .addAll(modelCollection).build()) + .error(internalErrorCallback) + .success(internalSuccessCallback).build(); if (transact) { transaction.execute(); @@ -518,10 +519,10 @@ public boolean retainAll(@NonNull Collection collection) { List tableList = internalCursorList.getAll(); tableList.removeAll(collection); Transaction transaction = FlowManager.getDatabaseForTable(internalCursorList.table()) - .beginTransactionAsync(new ProcessModelTransaction.Builder<>(tableList, deleteModel) - .build()) - .error(internalErrorCallback) - .success(internalSuccessCallback).build(); + .beginTransactionAsync(new ProcessModelTransaction.Builder<>(tableList, deleteModel) + .build()) + .error(internalErrorCallback) + .success(internalSuccessCallback).build(); if (transact) { transaction.execute(); @@ -552,11 +553,11 @@ public TModel set(int location, TModel object) { */ public TModel set(TModel object) { Transaction transaction = FlowManager.getDatabaseForTable(internalCursorList.table()) - .beginTransactionAsync(new ProcessModelTransaction.Builder<>(updateModel) - .add(object) - .build()) - .error(internalErrorCallback) - .success(internalSuccessCallback).build(); + .beginTransactionAsync(new ProcessModelTransaction.Builder<>(updateModel) + .add(object) + .build()) + .error(internalErrorCallback) + .success(internalSuccessCallback).build(); if (transact) { transaction.execute(); @@ -598,28 +599,28 @@ public void close() { } private final ProcessModelTransaction.ProcessModel saveModel = - new ProcessModelTransaction.ProcessModel() { - @Override - public void processModel(TModel model, DatabaseWrapper wrapper) { - getModelAdapter().save(model); - } - }; + new ProcessModelTransaction.ProcessModel() { + @Override + public void processModel(TModel model, DatabaseWrapper wrapper) { + getModelAdapter().save(model); + } + }; private final ProcessModelTransaction.ProcessModel updateModel = - new ProcessModelTransaction.ProcessModel() { - @Override - public void processModel(TModel model, DatabaseWrapper wrapper) { - getModelAdapter().update(model); - } - }; + new ProcessModelTransaction.ProcessModel() { + @Override + public void processModel(TModel model, DatabaseWrapper wrapper) { + getModelAdapter().update(model); + } + }; private final ProcessModelTransaction.ProcessModel deleteModel = - new ProcessModelTransaction.ProcessModel() { - @Override - public void processModel(TModel model, DatabaseWrapper wrapper) { - getModelAdapter().delete(model); - } - }; + new ProcessModelTransaction.ProcessModel() { + @Override + public void processModel(TModel model, DatabaseWrapper wrapper) { + getModelAdapter().delete(model); + } + }; private final Transaction.Error internalErrorCallback = new Transaction.Error() { @Override diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/ContentResolverNotifier.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/ContentResolverNotifier.java index 8adc6d539..fcf0eb1d9 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/ContentResolverNotifier.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/ContentResolverNotifier.java @@ -14,13 +14,22 @@ * The default use case, it notifies via the {@link ContentResolver} system. */ public class ContentResolverNotifier implements ModelNotifier { + + @NonNull + private final String contentAuthority; + + public ContentResolverNotifier(@NonNull String contentAuthority) { + this.contentAuthority = contentAuthority; + } + @Override public void notifyModelChanged(@NonNull T model, @NonNull ModelAdapter adapter, @NonNull BaseModel.Action action) { if (FlowContentObserver.shouldNotify()) { FlowManager.getContext().getContentResolver() - .notifyChange(SqlUtils.getNotificationUri(adapter.getModelClass(), action, - adapter.getPrimaryConditionClause(model).getConditions()), null, true); + .notifyChange(SqlUtils.getNotificationUri(contentAuthority, + adapter.getModelClass(), action, + adapter.getPrimaryConditionClause(model).getConditions()), null, true); } } @@ -28,23 +37,24 @@ public void notifyModelChanged(@NonNull T model, @NonNull ModelAdapter ad public void notifyTableChanged(@NonNull Class table, @NonNull BaseModel.Action action) { if (FlowContentObserver.shouldNotify()) { FlowManager.getContext().getContentResolver() - .notifyChange(SqlUtils.getNotificationUri(table, action, (SQLOperator[]) null), null, true); + .notifyChange(SqlUtils.getNotificationUri(contentAuthority, + table, action, (SQLOperator[]) null), null, true); } } @Override public TableNotifierRegister newRegister() { - return new FlowContentTableNotifierRegister(); + return new FlowContentTableNotifierRegister(contentAuthority); } public static class FlowContentTableNotifierRegister implements TableNotifierRegister { - - private final FlowContentObserver flowContentObserver = new FlowContentObserver(); + private final FlowContentObserver flowContentObserver; @Nullable private OnTableChangedListener tableChangedListener; - public FlowContentTableNotifierRegister() { + public FlowContentTableNotifierRegister(@NonNull String contentAuthority) { + flowContentObserver = new FlowContentObserver(contentAuthority); flowContentObserver.addOnTableChangedListener(internalContentChangeListener); } @@ -75,7 +85,7 @@ public boolean isSubscribed() { } private final OnTableChangedListener internalContentChangeListener - = new OnTableChangedListener() { + = new OnTableChangedListener() { @Override public void onTableChanged(@Nullable Class tableChanged, @NonNull BaseModel.Action action) { diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/FlowContentObserver.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/FlowContentObserver.java index 06aa336e4..32a667779 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/FlowContentObserver.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/FlowContentObserver.java @@ -38,6 +38,7 @@ public class FlowContentObserver extends ContentObserver { private static final AtomicInteger REGISTERED_COUNT = new AtomicInteger(0); private static boolean forceNotify = false; + @NonNull private final String contentAuthority; /** * @return true if we have registered for content changes. Otherwise we do not notify @@ -96,12 +97,14 @@ public interface ContentChangeListener extends OnModelStateChangedListener, OnTa protected boolean isInTransaction = false; private boolean notifyAllUris = false; - public FlowContentObserver() { + public FlowContentObserver(@NonNull String contentAuthority) { super(null); + this.contentAuthority = contentAuthority; } - public FlowContentObserver(@Nullable Handler handler) { + public FlowContentObserver(@Nullable Handler handler, @NonNull String contentAuthority) { super(handler); + this.contentAuthority = contentAuthority; } /** @@ -145,7 +148,7 @@ public void endTransactionAndNotify() { for (Uri uri : tableUris) { for (OnTableChangedListener onTableChangedListener : onTableChangedListeners) { onTableChangedListener.onTableChanged(registeredTables.get(uri.getAuthority()), - Action.valueOf(uri.getFragment())); + Action.valueOf(uri.getFragment())); } } tableUris.clear(); @@ -213,7 +216,8 @@ public void registerForContentChanges(@NonNull Context context, */ public void registerForContentChanges(@NonNull ContentResolver contentResolver, @NonNull Class table) { - contentResolver.registerContentObserver(SqlUtils.getNotificationUri(table, null), true, this); + contentResolver.registerContentObserver( + SqlUtils.getNotificationUri(contentAuthority, table, null), true, this); REGISTERED_COUNT.incrementAndGet(); if (!registeredTables.containsValue(table)) { registeredTables.put(FlowManager.getTableName(table), table); @@ -253,21 +257,23 @@ public void onChange(boolean selfChange, Uri uri) { @TargetApi(VERSION_CODES.JELLY_BEAN) private void onChange(boolean selfChanges, Uri uri, boolean calledInternally) { String fragment = uri.getFragment(); - String tableName = uri.getAuthority(); + String tableName = uri.getQueryParameter(SqlUtils.TABLE_QUERY_PARAM); String columnName; String param; Set queryNames = uri.getQueryParameterNames(); - SQLOperator[] columnsChanged = new SQLOperator[queryNames.size()]; + SQLOperator[] columnsChanged = new SQLOperator[queryNames.size() - 1]; if (!queryNames.isEmpty()) { int index = 0; for (String key : queryNames) { - param = Uri.decode(uri.getQueryParameter(key)); - columnName = Uri.decode(key); - columnsChanged[index] = Operator.op(new NameAlias.Builder(columnName).build()) - .eq(param); - index++; + if (!SqlUtils.TABLE_QUERY_PARAM.equals(key)) { + param = Uri.decode(uri.getQueryParameter(key)); + columnName = Uri.decode(key); + columnsChanged[index] = Operator.op(new NameAlias.Builder(columnName).build()) + .eq(param); + index++; + } } } @@ -288,7 +294,7 @@ private void onChange(boolean selfChanges, Uri uri, boolean calledInternally) { // convert this uri to a CHANGE op if we don't care about individual changes. if (!notifyAllUris) { action = Action.CHANGE; - uri = SqlUtils.getNotificationUri(table, action); + uri = SqlUtils.getNotificationUri(contentAuthority, table, action); } synchronized (notificationUris) { // add and keep track of unique notification uris for when transaction completes. @@ -296,7 +302,7 @@ private void onChange(boolean selfChanges, Uri uri, boolean calledInternally) { } synchronized (tableUris) { - tableUris.add(SqlUtils.getNotificationUri(table, action)); + tableUris.add(SqlUtils.getNotificationUri(contentAuthority, table, action)); } } } diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/StubContentProvider.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/StubContentProvider.java new file mode 100644 index 000000000..fd498ca43 --- /dev/null +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/runtime/StubContentProvider.java @@ -0,0 +1,56 @@ +package com.raizlabs.android.dbflow.runtime; + +/** + * Description: + */ + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +/** + * Description: Used as a stub, include this in order to work around Android O changes to {@link ContentProvider} + */ +public class StubContentProvider extends ContentProvider { + + @Nullable + @Override + public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { + return null; + } + + @Nullable + @Override + public Cursor query(@NonNull Uri uri, + @Nullable String[] projection, + @Nullable String selection, + @Nullable String[] selectionArgs, + @Nullable String sortOrder) { + return null; + } + + @Override + public boolean onCreate() { + return true; + } + + @Override + public int update(@NonNull Uri uri, @Nullable ContentValues values, + @Nullable String selection, @Nullable String[] selectionArgs) { + return 0; + } + + @Override + public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { + return 0; + } + + @Nullable + @Override + public String getType(@NonNull Uri uri) { + return null; + } +} diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java index b90777162..a23db14d8 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java @@ -27,16 +27,19 @@ */ public class SqlUtils { + public static final String TABLE_QUERY_PARAM = "tableName"; + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); /** * Notifies the {@link ContentObserver} that the model has changed. */ @Deprecated - public static void notifyModelChanged(Class table, Action action, + public static void notifyModelChanged(@NonNull String contentAuthority, + Class table, Action action, Iterable sqlOperators) { FlowManager.getContext().getContentResolver().notifyChange( - getNotificationUri(table, action, sqlOperators), null, true); + getNotificationUri(contentAuthority, table, action, sqlOperators), null, true); } /** @@ -71,11 +74,13 @@ public static void notifyTableChanged(@NonNull Class table, * @param conditions The set of key-value {@link SQLOperator} to construct into a uri. * @return The {@link Uri}. */ - public static Uri getNotificationUri(@NonNull Class modelClass, + public static Uri getNotificationUri(@NonNull String contentAuthority, + @NonNull Class modelClass, @Nullable Action action, @Nullable Iterable conditions) { Uri.Builder uriBuilder = new Uri.Builder().scheme("dbflow") - .authority(FlowManager.getTableName(modelClass)); + .authority(contentAuthority) + .appendQueryParameter(TABLE_QUERY_PARAM, FlowManager.getTableName(modelClass)); if (action != null) { uriBuilder.fragment(action.name()); } @@ -96,11 +101,13 @@ public static Uri getNotificationUri(@NonNull Class modelClass, * @param conditions The set of key-value {@link SQLOperator} to construct into a uri. * @return The {@link Uri}. */ - public static Uri getNotificationUri(@NonNull Class modelClass, + public static Uri getNotificationUri(@NonNull String contentAuthority, + @NonNull Class modelClass, @NonNull Action action, @Nullable SQLOperator[] conditions) { Uri.Builder uriBuilder = new Uri.Builder().scheme("dbflow") - .authority(FlowManager.getTableName(modelClass)); + .authority(contentAuthority) + .appendQueryParameter(TABLE_QUERY_PARAM, FlowManager.getTableName(modelClass)); if (action != null) { uriBuilder.fragment(action.name()); } @@ -124,7 +131,8 @@ public static Uri getNotificationUri(@NonNull Class modelClass, * @return Notification uri. */ - public static Uri getNotificationUri(@NonNull Class modelClass, + public static Uri getNotificationUri(@NonNull String contentAuthority, + @NonNull Class modelClass, @NonNull Action action, @NonNull String notifyKey, @Nullable Object notifyValue) { @@ -132,7 +140,7 @@ public static Uri getNotificationUri(@NonNull Class modelClass, if (StringUtils.isNotNullOrEmpty(notifyKey)) { operator = Operator.op(new NameAlias.Builder(notifyKey).build()).value(notifyValue); } - return getNotificationUri(modelClass, action, new SQLOperator[]{operator}); + return getNotificationUri(contentAuthority, modelClass, action, new SQLOperator[]{operator}); } /** @@ -140,8 +148,10 @@ public static Uri getNotificationUri(@NonNull Class modelClass, * @param action The {@link Action} to use. * @return The uri for updates to {@link Model}, meant for general changes. */ - public static Uri getNotificationUri(@NonNull Class modelClass, @NonNull Action action) { - return getNotificationUri(modelClass, action, null, null); + public static Uri getNotificationUri(@NonNull String contentAuthority, + @NonNull Class modelClass, + @NonNull Action action) { + return getNotificationUri(contentAuthority, modelClass, action, "", null); } @@ -153,7 +163,7 @@ public static Uri getNotificationUri(@NonNull Class modelClass, @NonNull Acti */ public static void dropTrigger(@NonNull Class mOnTable, @NonNull String triggerName) { QueryBuilder queryBuilder = new QueryBuilder("DROP TRIGGER IF EXISTS ") - .append(triggerName); + .append(triggerName); FlowManager.getDatabaseForTable(mOnTable).getWritableDatabase().execSQL(queryBuilder.getQuery()); } @@ -165,7 +175,7 @@ public static void dropTrigger(@NonNull Class mOnTable, @NonNull String trigg public static void dropIndex(@NonNull DatabaseWrapper databaseWrapper, @NonNull String indexName) { QueryBuilder queryBuilder = new QueryBuilder("DROP INDEX IF EXISTS ") - .append(QueryBuilder.quoteIfNeeded(indexName)); + .append(QueryBuilder.quoteIfNeeded(indexName)); databaseWrapper.execSQL(queryBuilder.getQuery()); } @@ -186,7 +196,7 @@ public static void addContentValues(@NonNull ContentValues contentValues, @NonNu for (Map.Entry entry : entries) { String key = entry.getKey(); operatorGroup.and(Operator.op(new NameAlias.Builder(key).build()) - .is(contentValues.get(key))); + .is(contentValues.get(key))); } } @@ -221,7 +231,7 @@ public static long longForQuery(@NonNull DatabaseWrapper wrapper, } public static double doubleForQuery(@NonNull DatabaseWrapper wrapper, - @NonNull String query) { + @NonNull String query) { DatabaseStatement statement = wrapper.compileStatement(query); try { return statement.simpleQueryForLong(); diff --git a/gradle.properties b/gradle.properties index 2d2b9ba60..120393fbe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=4.1.1 +version=4.2.0 version_code=1 group=com.raizlabs.android bt_siteUrl=https://github.com/Raizlabs/DBFlow