Merge pull request #1047 from psh/more-database-cleanup

More database related cleanup
This commit is contained in:
neslihanturan 2018-01-12 17:41:58 +03:00 committed by GitHub
commit 1224302ccb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 211 additions and 151 deletions

View file

@ -21,8 +21,8 @@ import javax.inject.Named;
import dagger.android.AndroidInjector;
import dagger.android.DaggerApplication;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.category.CategoryDao;
import fr.free.nrw.commons.contributions.ContributionDao;
import fr.free.nrw.commons.data.CategoryDao;
import fr.free.nrw.commons.data.DBOpenHelper;
import fr.free.nrw.commons.di.CommonsApplicationComponent;
import fr.free.nrw.commons.di.CommonsApplicationModule;

View file

@ -8,13 +8,13 @@ import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import fr.free.nrw.commons.contributions.ContributionsContentProvider;
import fr.free.nrw.commons.modifications.ModificationsContentProvider;
import timber.log.Timber;
import static android.accounts.AccountManager.ERROR_CODE_REMOTE_EXCEPTION;
import static android.accounts.AccountManager.KEY_ACCOUNT_NAME;
import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE;
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.CONTRIBUTION_AUTHORITY;
import static fr.free.nrw.commons.modifications.ModificationsContentProvider.MODIFICATIONS_AUTHORITY;
public class AccountUtil {
@ -51,8 +51,8 @@ public class AccountUtil {
}
// FIXME: If the user turns it off, it shouldn't be auto turned back on
ContentResolver.setSyncAutomatically(account, ContributionsContentProvider.AUTHORITY, true); // Enable sync by default!
ContentResolver.setSyncAutomatically(account, ModificationsContentProvider.AUTHORITY, true); // Enable sync by default!
ContentResolver.setSyncAutomatically(account, CONTRIBUTION_AUTHORITY, true); // Enable sync by default!
ContentResolver.setSyncAutomatically(account, MODIFICATIONS_AUTHORITY, true); // Enable sync by default!
}
private AccountManager accountManager() {

View file

@ -1,6 +1,5 @@
package fr.free.nrw.commons.category;
import android.content.ContentProviderClient;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
@ -36,8 +35,6 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import dagger.android.support.DaggerFragment;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.data.Category;
import fr.free.nrw.commons.data.CategoryDao;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.upload.MwVolleyApi;
import fr.free.nrw.commons.utils.StringSortingUtils;
@ -48,7 +45,6 @@ import timber.log.Timber;
import static android.view.KeyEvent.ACTION_UP;
import static android.view.KeyEvent.KEYCODE_BACK;
import static fr.free.nrw.commons.category.CategoryContentProvider.AUTHORITY;
/**
* Displays the category suggestion and selection screen. Category search is initiated here.
@ -70,12 +66,12 @@ public class CategorizationFragment extends DaggerFragment {
@Inject MediaWikiApi mwApi;
@Inject @Named("default_preferences") SharedPreferences prefs;
@Inject CategoryDao categoryDao;
private RVRendererAdapter<CategoryItem> categoriesAdapter;
private OnCategoriesSaveHandler onCategoriesSaveHandler;
private HashMap<String, ArrayList<String>> categoriesCache;
private List<CategoryItem> selectedCategories = new ArrayList<>();
private ContentProviderClient databaseClient;
private final CategoriesAdapterFactory adapterFactory = new CategoriesAdapterFactory(item -> {
if (item.isSelected()) {
@ -141,7 +137,6 @@ public class CategorizationFragment extends DaggerFragment {
@Override
public void onDestroy() {
super.onDestroy();
databaseClient.release();
}
@Override
@ -179,7 +174,6 @@ public class CategorizationFragment extends DaggerFragment {
setHasOptionsMenu(true);
onCategoriesSaveHandler = (OnCategoriesSaveHandler) getActivity();
getActivity().setTitle(R.string.categories_activity_title);
databaseClient = getActivity().getContentResolver().acquireContentProviderClient(AUTHORITY);
}
private void updateCategoryList(String filter) {
@ -262,7 +256,7 @@ public class CategorizationFragment extends DaggerFragment {
}
private Observable<CategoryItem> recentCategories() {
return Observable.fromIterable(new CategoryDao(databaseClient).recentCategories(SEARCH_CATS_LIMIT))
return Observable.fromIterable(categoryDao.recentCategories(SEARCH_CATS_LIMIT))
.map(s -> new CategoryItem(s, false));
}
@ -313,7 +307,6 @@ public class CategorizationFragment extends DaggerFragment {
}
private void updateCategoryCount(CategoryItem item) {
CategoryDao categoryDao = new CategoryDao(databaseClient);
Category category = categoryDao.find(item.getName());
// Newly used category...

View file

@ -1,4 +1,4 @@
package fr.free.nrw.commons.data;
package fr.free.nrw.commons.category;
import android.net.Uri;

View file

@ -17,9 +17,9 @@ import fr.free.nrw.commons.data.DBOpenHelper;
import timber.log.Timber;
import static android.content.UriMatcher.NO_MATCH;
import static fr.free.nrw.commons.data.CategoryDao.Table.ALL_FIELDS;
import static fr.free.nrw.commons.data.CategoryDao.Table.COLUMN_ID;
import static fr.free.nrw.commons.data.CategoryDao.Table.TABLE_NAME;
import static fr.free.nrw.commons.category.CategoryDao.Table.ALL_FIELDS;
import static fr.free.nrw.commons.category.CategoryDao.Table.COLUMN_ID;
import static fr.free.nrw.commons.category.CategoryDao.Table.TABLE_NAME;
public class CategoryContentProvider extends ContentProvider {

View file

@ -1,4 +1,4 @@
package fr.free.nrw.commons.data;
package fr.free.nrw.commons.category;
import android.content.ContentProviderClient;
import android.content.ContentValues;
@ -12,25 +12,31 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import fr.free.nrw.commons.category.CategoryContentProvider;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
public class CategoryDao {
private final ContentProviderClient client;
private final Provider<ContentProviderClient> clientProvider;
public CategoryDao(ContentProviderClient client) {
this.client = client;
@Inject
public CategoryDao(@Named("category") Provider<ContentProviderClient> clientProvider) {
this.clientProvider = clientProvider;
}
public void save(Category category) {
ContentProviderClient db = clientProvider.get();
try {
if (category.getContentUri() == null) {
category.setContentUri(client.insert(CategoryContentProvider.BASE_URI, toContentValues(category)));
category.setContentUri(db.insert(CategoryContentProvider.BASE_URI, toContentValues(category)));
} else {
client.update(category.getContentUri(), toContentValues(category), null, null);
db.update(category.getContentUri(), toContentValues(category), null, null);
}
} catch (RemoteException e) {
throw new RuntimeException(e);
} finally {
db.release();
}
}
@ -40,11 +46,12 @@ public class CategoryDao {
* @param name Category's name
* @return category from database, or null if not found
*/
public @Nullable
@Nullable
Category find(String name) {
Cursor cursor = null;
ContentProviderClient db = clientProvider.get();
try {
cursor = client.query(
cursor = db.query(
CategoryContentProvider.BASE_URI,
Table.ALL_FIELDS,
Table.COLUMN_NAME + "=?",
@ -60,6 +67,7 @@ public class CategoryDao {
if (cursor != null) {
cursor.close();
}
db.release();
}
return null;
}
@ -69,12 +77,13 @@ public class CategoryDao {
*
* @return a list containing recent categories
*/
public @NonNull
@NonNull
List<String> recentCategories(int limit) {
List<String> items = new ArrayList<>();
Cursor cursor = null;
ContentProviderClient db = clientProvider.get();
try {
cursor = client.query(
cursor = db.query(
CategoryContentProvider.BASE_URI,
Table.ALL_FIELDS,
null,
@ -91,6 +100,7 @@ public class CategoryDao {
if (cursor != null) {
cursor.close();
}
db.release();
}
return items;
}
@ -147,7 +157,7 @@ public class CategoryDao {
onCreate(db);
}
static void onUpdate(SQLiteDatabase db, int from, int to) {
public static void onUpdate(SQLiteDatabase db, int from, int to) {
if (from == to) {
return;
}

View file

@ -11,44 +11,81 @@ import android.text.TextUtils;
import java.util.Date;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import fr.free.nrw.commons.settings.Prefs;
import static fr.free.nrw.commons.contributions.ContributionDao.Table.ALL_FIELDS;
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI;
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.uriForId;
public class ContributionDao {
private final ContentProviderClient client;
/*
This sorts in the following order:
Currently Uploading
Failed (Sorted in ascending order of time added - FIFO)
Queued to Upload (Sorted in ascending order of time added - FIFO)
Completed (Sorted in descending order of time added)
public ContributionDao(ContentProviderClient client) {
this.client = client;
This is why Contribution.STATE_COMPLETED is -1.
*/
static final String CONTRIBUTION_SORT = Table.COLUMN_STATE + " DESC, "
+ Table.COLUMN_UPLOADED + " DESC , ("
+ Table.COLUMN_TIMESTAMP + " * "
+ Table.COLUMN_STATE + ")";
private final Provider<ContentProviderClient> clientProvider;
@Inject
public ContributionDao(@Named("contribution") Provider<ContentProviderClient> clientProvider) {
this.clientProvider = clientProvider;
}
Cursor loadAllContributions() {
ContentProviderClient db = clientProvider.get();
try {
return db.query(BASE_URI, ALL_FIELDS, "", null, CONTRIBUTION_SORT);
} catch (RemoteException e) {
return null;
} finally {
db.release();
}
}
public void save(Contribution contribution) {
ContentProviderClient db = clientProvider.get();
try {
if (contribution.getContentUri() == null) {
contribution.setContentUri(client.insert(BASE_URI, toContentValues(contribution)));
contribution.setContentUri(db.insert(BASE_URI, toContentValues(contribution)));
} else {
client.update(contribution.getContentUri(), toContentValues(contribution), null, null);
db.update(contribution.getContentUri(), toContentValues(contribution), null, null);
}
} catch (RemoteException e) {
throw new RuntimeException(e);
} finally {
db.release();
}
}
public void delete(Contribution contribution) {
ContentProviderClient db = clientProvider.get();
try {
if (contribution.getContentUri() == null) {
// noooo
throw new RuntimeException("tried to delete item with no content URI");
} else {
client.delete(contribution.getContentUri(), null, null);
db.delete(contribution.getContentUri(), null, null);
}
} catch (RemoteException e) {
throw new RuntimeException(e);
} finally {
db.release();
}
}
public static ContentValues toContentValues(Contribution contribution) {
ContentValues toContentValues(Contribution contribution) {
ContentValues cv = new ContentValues();
cv.put(Table.COLUMN_FILENAME, contribution.getFilename());
if (contribution.getLocalUri() != null) {
@ -74,7 +111,7 @@ public class ContributionDao {
return cv;
}
public static Contribution fromCursor(Cursor cursor) {
public Contribution fromCursor(Cursor cursor) {
// Hardcoding column positions!
//Check that cursor has a value to avoid CursorIndexOutOfBoundsException
if (cursor.getCount() > 0) {

View file

@ -43,7 +43,6 @@ import timber.log.Timber;
import static android.content.ContentResolver.requestSync;
import static fr.free.nrw.commons.contributions.Contribution.STATE_FAILED;
import static fr.free.nrw.commons.contributions.ContributionDao.Table.ALL_FIELDS;
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.AUTHORITY;
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI;
import static fr.free.nrw.commons.settings.Prefs.UPLOADS_SHOWING;
@ -58,6 +57,7 @@ public class ContributionsActivity
@Inject MediaWikiApi mediaWikiApi;
@Inject SessionManager sessionManager;
@Inject @Named("default_preferences") SharedPreferences prefs;
@Inject ContributionDao contributionDao;
private Cursor allContributions;
private ContributionsListFragment contributionsList;
@ -65,21 +65,6 @@ public class ContributionsActivity
private UploadService uploadService;
private boolean isUploadServiceConnected;
private ArrayList<DataSetObserver> observersWaitingForLoad = new ArrayList<>();
private String CONTRIBUTION_SELECTION = "";
/*
This sorts in the following order:
Currently Uploading
Failed (Sorted in ascending order of time added - FIFO)
Queued to Upload (Sorted in ascending order of time added - FIFO)
Completed (Sorted in descending order of time added)
This is why Contribution.STATE_COMPLETED is -1.
*/
private String CONTRIBUTION_SORT = ContributionDao.Table.COLUMN_STATE + " DESC, "
+ ContributionDao.Table.COLUMN_UPLOADED + " DESC , ("
+ ContributionDao.Table.COLUMN_TIMESTAMP + " * "
+ ContributionDao.Table.COLUMN_STATE + ")";
private CompositeDisposable compositeDisposable = new CompositeDisposable();
@ -121,14 +106,13 @@ public class ContributionsActivity
@Override
protected void onAuthCookieAcquired(String authCookie) {
// Do a sync everytime we get here!
requestSync(sessionManager.getCurrentAccount(), ContributionsContentProvider.AUTHORITY, new Bundle());
requestSync(sessionManager.getCurrentAccount(), ContributionsContentProvider.CONTRIBUTION_AUTHORITY, new Bundle());
Intent uploadServiceIntent = new Intent(this, UploadService.class);
uploadServiceIntent.setAction(UploadService.ACTION_START_SERVICE);
startService(uploadServiceIntent);
bindService(uploadServiceIntent, uploadServiceConnection, Context.BIND_AUTO_CREATE);
allContributions = getContentResolver().query(BASE_URI, ALL_FIELDS,
CONTRIBUTION_SELECTION, null, CONTRIBUTION_SORT);
allContributions = contributionDao.loadAllContributions();
getSupportLoaderManager().initLoader(0, null, this);
}
@ -186,7 +170,7 @@ public class ContributionsActivity
public void retryUpload(int i) {
allContributions.moveToPosition(i);
Contribution c = ContributionDao.fromCursor(allContributions);
Contribution c = contributionDao.fromCursor(allContributions);
if (c.getState() == STATE_FAILED) {
uploadService.queue(UploadService.ACTION_UPLOAD_FILE, c);
Timber.d("Restarting for %s", c.toString());
@ -197,10 +181,10 @@ public class ContributionsActivity
public void deleteUpload(int i) {
allContributions.moveToPosition(i);
Contribution c = ContributionDao.fromCursor(allContributions);
Contribution c = contributionDao.fromCursor(allContributions);
if (c.getState() == STATE_FAILED) {
Timber.d("Deleting failed contrib %s", c.toString());
new ContributionDao(getContentResolver().acquireContentProviderClient(AUTHORITY)).delete(c);
contributionDao.delete(c);
} else {
Timber.d("Skipping deletion for non-failed contrib %s", c.toString());
}
@ -238,8 +222,8 @@ public class ContributionsActivity
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
int uploads = prefs.getInt(UPLOADS_SHOWING, 100);
return new CursorLoader(this, BASE_URI,
ALL_FIELDS, CONTRIBUTION_SELECTION, null,
CONTRIBUTION_SORT + "LIMIT " + uploads);
ALL_FIELDS, "", null,
ContributionDao.CONTRIBUTION_SORT + "LIMIT " + uploads);
}
@Override
@ -248,7 +232,7 @@ public class ContributionsActivity
if (contributionsList.getAdapter() == null) {
contributionsList.setAdapter(new ContributionsListAdapter(getApplicationContext(),
cursor, 0));
cursor, 0, contributionDao));
} else {
((CursorAdapter) contributionsList.getAdapter()).swapCursor(cursor);
}
@ -269,7 +253,7 @@ public class ContributionsActivity
// not yet ready to return data
return null;
} else {
return ContributionDao.fromCursor((Cursor) contributionsList.getAdapter().getItem(i));
return contributionDao.fromCursor((Cursor) contributionsList.getAdapter().getItem(i));
}
}

View file

@ -26,13 +26,13 @@ public class ContributionsContentProvider extends ContentProvider {
private static final int CONTRIBUTIONS_ID = 2;
private static final String BASE_PATH = "contributions";
private static final UriMatcher uriMatcher = new UriMatcher(NO_MATCH);
public static final String AUTHORITY = "fr.free.nrw.commons.contributions.contentprovider";
public static final String CONTRIBUTION_AUTHORITY = "fr.free.nrw.commons.contributions.contentprovider";
public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);
public static final Uri BASE_URI = Uri.parse("content://" + CONTRIBUTION_AUTHORITY + "/" + BASE_PATH);
static {
uriMatcher.addURI(AUTHORITY, BASE_PATH, CONTRIBUTIONS);
uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", CONTRIBUTIONS_ID);
uriMatcher.addURI(CONTRIBUTION_AUTHORITY, BASE_PATH, CONTRIBUTIONS);
uriMatcher.addURI(CONTRIBUTION_AUTHORITY, BASE_PATH + "/#", CONTRIBUTIONS_ID);
}
public static Uri uriForId(int id) {

View file

@ -11,8 +11,11 @@ import fr.free.nrw.commons.R;
class ContributionsListAdapter extends CursorAdapter {
public ContributionsListAdapter(Context context, Cursor c, int flags) {
private final ContributionDao contributionDao;
public ContributionsListAdapter(Context context, Cursor c, int flags, ContributionDao contributionDao) {
super(context, c, flags);
this.contributionDao = contributionDao;
}
@Override
@ -26,7 +29,7 @@ class ContributionsListAdapter extends CursorAdapter {
@Override
public void bindView(View view, Context context, Cursor cursor) {
final ContributionViewHolder views = (ContributionViewHolder)view.getTag();
final Contribution contribution = ContributionDao.fromCursor(cursor);
final Contribution contribution = contributionDao.fromCursor(cursor);
views.imageView.setMedia(contribution);
views.titleView.setText(contribution.getDisplayTitle());

View file

@ -89,6 +89,7 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter {
LogEventResult result;
Boolean done = false;
String queryContinue = null;
ContributionDao contributionDao = new ContributionDao(() -> contentProviderClient);
while (!done) {
try {
@ -121,7 +122,7 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter {
"", -1, dateUpdated, dateUpdated, user,
"", "");
contrib.setState(STATE_COMPLETED);
imageValues.add(ContributionDao.toContentValues(contrib));
imageValues.add(contributionDao.toContentValues(contrib));
if (imageValues.size() % COMMIT_THRESHOLD == 0) {
try {

View file

@ -4,6 +4,7 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import fr.free.nrw.commons.category.CategoryDao;
import fr.free.nrw.commons.contributions.ContributionDao;
import fr.free.nrw.commons.modifications.ModifierSequenceDao;

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.di;
import android.content.ContentProviderClient;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v4.util.LruCache;
@ -22,10 +23,14 @@ import fr.free.nrw.commons.nearby.NearbyPlaces;
import fr.free.nrw.commons.upload.UploadController;
import static android.content.Context.MODE_PRIVATE;
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.CONTRIBUTION_AUTHORITY;
import static fr.free.nrw.commons.modifications.ModificationsContentProvider.MODIFICATIONS_AUTHORITY;
@Module
@SuppressWarnings({"WeakerAccess", "unused"})
public class CommonsApplicationModule {
public static final String CATEGORY_AUTHORITY = "fr.free.nrw.commons.categories.contentprovider";
private CommonsApplication application;
public CommonsApplicationModule(CommonsApplication application) {
@ -37,6 +42,24 @@ public class CommonsApplicationModule {
return new AccountUtil(application);
}
@Provides
@Named("category")
public ContentProviderClient provideCategoryContentProviderClient() {
return application.getContentResolver().acquireContentProviderClient(CATEGORY_AUTHORITY);
}
@Provides
@Named("contribution")
public ContentProviderClient provideContributionContentProviderClient() {
return application.getContentResolver().acquireContentProviderClient(CONTRIBUTION_AUTHORITY);
}
@Provides
@Named("modification")
public ContentProviderClient provideModificationContentProviderClient() {
return application.getContentResolver().acquireContentProviderClient(MODIFICATIONS_AUTHORITY);
}
@Provides
@Named("application_preferences")
public SharedPreferences providesApplicationSharedPreferences() {

View file

@ -23,15 +23,15 @@ public class ModificationsContentProvider extends ContentProvider {
private static final int MODIFICATIONS = 1;
private static final int MODIFICATIONS_ID = 2;
public static final String AUTHORITY = "fr.free.nrw.commons.modifications.contentprovider";
public static final String MODIFICATIONS_AUTHORITY = "fr.free.nrw.commons.modifications.contentprovider";
public static final String BASE_PATH = "modifications";
public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);
public static final Uri BASE_URI = Uri.parse("content://" + MODIFICATIONS_AUTHORITY + "/" + BASE_PATH);
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
uriMatcher.addURI(AUTHORITY, BASE_PATH, MODIFICATIONS);
uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", MODIFICATIONS_ID);
uriMatcher.addURI(MODIFICATIONS_AUTHORITY, BASE_PATH, MODIFICATIONS);
uriMatcher.addURI(MODIFICATIONS_AUTHORITY, BASE_PATH + "/#", MODIFICATIONS_ID);
}
public static Uri uriForId(int id) {

View file

@ -26,6 +26,8 @@ import timber.log.Timber;
public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
@Inject MediaWikiApi mwApi;
@Inject ContributionDao contributionDao;
@Inject ModifierSequenceDao modifierSequenceDao;
public ModificationsSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
@ -80,11 +82,10 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
ContentProviderClient contributionsClient = null;
try {
contributionsClient = getContext().getContentResolver().acquireContentProviderClient(ContributionsContentProvider.AUTHORITY);
contributionsClient = getContext().getContentResolver().acquireContentProviderClient(ContributionsContentProvider.CONTRIBUTION_AUTHORITY);
while (!allModifications.isAfterLast()) {
ModifierSequence sequence = ModifierSequenceDao.fromCursor(allModifications);
ModifierSequenceDao dao = new ModifierSequenceDao(contributionsClient);
ModifierSequence sequence = modifierSequenceDao.fromCursor(allModifications);
Contribution contrib;
Cursor contributionCursor;
@ -94,7 +95,7 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
throw new RuntimeException(e);
}
contributionCursor.moveToFirst();
contrib = ContributionDao.fromCursor(contributionCursor);
contrib = contributionDao.fromCursor(contributionCursor);
if (contrib.getState() == Contribution.STATE_COMPLETED) {
String pageContent;
@ -122,7 +123,7 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
// FIXME: Log this somewhere else
Timber.d("Non success result! %s", editResult);
} else {
dao.delete(sequence);
modifierSequenceDao.delete(sequence);
}
}
allModifications.moveToNext();

View file

@ -11,20 +11,51 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
public class ModifierSequenceDao {
private final ContentProviderClient client;
private final Provider<ContentProviderClient> clientProvider;
public ModifierSequenceDao(ContentProviderClient client) {
this.client = client;
@Inject
public ModifierSequenceDao(@Named("modification") Provider<ContentProviderClient> clientProvider) {
this.clientProvider = clientProvider;
}
public static ModifierSequence fromCursor(Cursor cursor) {
public void save(ModifierSequence sequence) {
ContentProviderClient db = clientProvider.get();
try {
if (sequence.getContentUri() == null) {
sequence.setContentUri(db.insert(ModificationsContentProvider.BASE_URI, toContentValues(sequence)));
} else {
db.update(sequence.getContentUri(), toContentValues(sequence), null, null);
}
} catch (RemoteException e) {
throw new RuntimeException(e);
} finally {
db.release();
}
}
public void delete(ModifierSequence sequence) {
ContentProviderClient db = clientProvider.get();
try {
db.delete(sequence.getContentUri(), null, null);
} catch (RemoteException e) {
throw new RuntimeException(e);
} finally {
db.release();
}
}
ModifierSequence fromCursor(Cursor cursor) {
// Hardcoding column positions!
ModifierSequence ms = null;
try {
ms = new ModifierSequence(Uri.parse(cursor.getString(1)),
new JSONObject(cursor.getString(2)));
new JSONObject(cursor.getString(2)));
} catch (JSONException e) {
throw new RuntimeException(e);
}
@ -33,26 +64,6 @@ public class ModifierSequenceDao {
return ms;
}
public void save(ModifierSequence sequence) {
try {
if (sequence.getContentUri() == null) {
sequence.setContentUri(client.insert(ModificationsContentProvider.BASE_URI, toContentValues(sequence)));
} else {
client.update(sequence.getContentUri(), toContentValues(sequence), null, null);
}
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
public void delete(ModifierSequence sequence) {
try {
client.delete(sequence.getContentUri(), null, null);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
private JSONObject toJSON(ModifierSequence sequence) {
JSONObject data = new JSONObject();
try {

View file

@ -2,7 +2,6 @@ package fr.free.nrw.commons.upload;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@ -55,6 +54,7 @@ public class MultipleShareActivity extends AuthenticatedActivity
@Inject MediaWikiApi mwApi;
@Inject SessionManager sessionManager;
@Inject UploadController uploadController;
@Inject ModifierSequenceDao modifierSequenceDao;
@Inject @Named("default_preferences") SharedPreferences prefs;
private ArrayList<Contribution> photosList = null;
@ -166,19 +166,18 @@ public class MultipleShareActivity extends AuthenticatedActivity
@Override
public void onCategoriesSave(List<String> categories) {
if (categories.size() > 0) {
ModifierSequenceDao dao = new ModifierSequenceDao(getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY));
for (Contribution contribution : photosList) {
ModifierSequence categoriesSequence = new ModifierSequence(contribution.getContentUri());
categoriesSequence.queueModifier(new CategoryModifier(categories.toArray(new String[]{})));
categoriesSequence.queueModifier(new TemplateRemoveModifier("Uncategorized"));
dao.save(categoriesSequence);
modifierSequenceDao.save(categoriesSequence);
}
}
// FIXME: Make sure that the content provider is up
// This is the wrong place for it, but bleh - better than not having it turned on by default for people who don't go throughl ogin
ContentResolver.setSyncAutomatically(sessionManager.getCurrentAccount(), ModificationsContentProvider.AUTHORITY, true); // Enable sync by default!
ContentResolver.setSyncAutomatically(sessionManager.getCurrentAccount(), ModificationsContentProvider.MODIFICATIONS_AUTHORITY, true); // Enable sync by default!
finish();
}

View file

@ -76,6 +76,7 @@ public class ShareActivity
@Inject CacheController cacheController;
@Inject SessionManager sessionManager;
@Inject UploadController uploadController;
@Inject ModifierSequenceDao modifierSequenceDao;
@Inject @Named("default_preferences") SharedPreferences prefs;
private String source;
@ -166,13 +167,12 @@ public class ShareActivity
categoriesSequence.queueModifier(new CategoryModifier(categories.toArray(new String[]{})));
categoriesSequence.queueModifier(new TemplateRemoveModifier("Uncategorized"));
ModifierSequenceDao dao = new ModifierSequenceDao(getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY));
dao.save(categoriesSequence);
modifierSequenceDao.save(categoriesSequence);
}
// FIXME: Make sure that the content provider is up
// This is the wrong place for it, but bleh - better than not having it turned on by default for people who don't go throughl ogin
ContentResolver.setSyncAutomatically(sessionManager.getCurrentAccount(), ModificationsContentProvider.AUTHORITY, true); // Enable sync by default!
ContentResolver.setSyncAutomatically(sessionManager.getCurrentAccount(), ModificationsContentProvider.MODIFICATIONS_AUTHORITY, true); // Enable sync by default!
finish();
}

View file

@ -4,7 +4,6 @@ import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
@ -52,9 +51,9 @@ public class UploadService extends HandlerService<Contribution> {
@Inject MediaWikiApi mwApi;
@Inject SessionManager sessionManager;
@Inject @Named("default_preferences") SharedPreferences prefs;
@Inject ContributionDao contributionDao;
private NotificationManager notificationManager;
private ContentProviderClient contributionsProviderClient;
private NotificationCompat.Builder curProgressNotification;
private int toUpload;
@ -67,7 +66,6 @@ public class UploadService extends HandlerService<Contribution> {
public static final int NOTIFICATION_UPLOAD_IN_PROGRESS = 1;
public static final int NOTIFICATION_UPLOAD_COMPLETE = 2;
public static final int NOTIFICATION_UPLOAD_FAILED = 3;
private ContributionDao dao;
public UploadService() {
super("UploadService");
@ -107,7 +105,7 @@ public class UploadService extends HandlerService<Contribution> {
startForeground(NOTIFICATION_UPLOAD_IN_PROGRESS, curProgressNotification.build());
contribution.setTransferred(transferred);
dao.save(contribution);
contributionDao.save(contribution);
}
}
@ -115,7 +113,6 @@ public class UploadService extends HandlerService<Contribution> {
@Override
public void onDestroy() {
super.onDestroy();
contributionsProviderClient.release();
Timber.d("UploadService.onDestroy; %s are yet to be uploaded", unfinishedUploads);
}
@ -124,8 +121,6 @@ public class UploadService extends HandlerService<Contribution> {
super.onCreate();
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
contributionsProviderClient = this.getContentResolver().acquireContentProviderClient(ContributionsContentProvider.AUTHORITY);
dao = new ContributionDao(contributionsProviderClient);
}
@Override
@ -147,7 +142,7 @@ public class UploadService extends HandlerService<Contribution> {
contribution.setState(Contribution.STATE_QUEUED);
contribution.setTransferred(0);
dao.save(contribution);
contributionDao.save(contribution);
toUpload++;
if (curProgressNotification != null && toUpload != 1) {
curProgressNotification.setContentText(getResources().getQuantityString(R.plurals.uploads_pending_notification_indicator, toUpload, toUpload));
@ -262,7 +257,7 @@ public class UploadService extends HandlerService<Contribution> {
contribution.setImageUrl(uploadResult.getImageUrl());
contribution.setState(Contribution.STATE_COMPLETED);
contribution.setDateUploaded(uploadResult.getDateUploaded());
dao.save(contribution);
contributionDao.save(contribution);
}
} catch (IOException e) {
Timber.d("I have a network fuckup");
@ -274,7 +269,7 @@ public class UploadService extends HandlerService<Contribution> {
toUpload--;
if (toUpload == 0) {
// Sync modifications right after all uplaods are processed
ContentResolver.requestSync(sessionManager.getCurrentAccount(), ModificationsContentProvider.AUTHORITY, new Bundle());
ContentResolver.requestSync(sessionManager.getCurrentAccount(), ModificationsContentProvider.MODIFICATIONS_AUTHORITY, new Bundle());
stopForeground(true);
}
}
@ -293,7 +288,7 @@ public class UploadService extends HandlerService<Contribution> {
notificationManager.notify(NOTIFICATION_UPLOAD_FAILED, failureNotification);
contribution.setState(Contribution.STATE_FAILED);
dao.save(contribution);
contributionDao.save(contribution);
}
private String findUniqueFilename(String fileName) throws IOException {

View file

@ -1,4 +1,4 @@
package fr.free.nrw.commons.data;
package fr.free.nrw.commons.category;
import android.content.ContentProviderClient;
import android.content.ContentValues;
@ -27,8 +27,7 @@ import java.util.List;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.TestCommonsApplication;
import fr.free.nrw.commons.category.CategoryContentProvider;
import fr.free.nrw.commons.data.CategoryDao.Table;
import fr.free.nrw.commons.category.CategoryDao.Table;
import static fr.free.nrw.commons.category.CategoryContentProvider.BASE_URI;
import static fr.free.nrw.commons.category.CategoryContentProvider.uriForId;
@ -50,20 +49,20 @@ import static org.mockito.Mockito.when;
public class CategoryDaoTest {
@Mock
ContentProviderClient client;
private ContentProviderClient client;
@Mock
SQLiteDatabase database;
private SQLiteDatabase database;
@Captor
ArgumentCaptor<ContentValues> captor;
private ArgumentCaptor<ContentValues> captor;
@Captor
ArgumentCaptor<String[]> queryCaptor;
private ArgumentCaptor<String[]> queryCaptor;
private CategoryDao testObject;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
testObject = new CategoryDao(client);
testObject = new CategoryDao(() -> client);
}
@Test

View file

@ -31,10 +31,13 @@ import static fr.free.nrw.commons.contributions.Contribution.SOURCE_CAMERA;
import static fr.free.nrw.commons.contributions.Contribution.SOURCE_GALLERY;
import static fr.free.nrw.commons.contributions.Contribution.STATE_COMPLETED;
import static fr.free.nrw.commons.contributions.Contribution.STATE_QUEUED;
import static fr.free.nrw.commons.contributions.ContributionDao.*;
import static fr.free.nrw.commons.contributions.ContributionDao.Table;
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI;
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.uriForId;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
@ -49,22 +52,22 @@ public class ContributionDaoTest {
private static final String LOCAL_URI = "http://example.com/";
@Mock
ContentProviderClient client;
private ContentProviderClient client;
@Mock
SQLiteDatabase database;
private SQLiteDatabase database;
@Captor
ArgumentCaptor<ContentValues> captor;
private ArgumentCaptor<ContentValues> captor;
private Uri contentUri;
private ContributionDao testObject;
@Before
public void setUp() throws Exception {
public void setUp() {
MockitoAnnotations.initMocks(this);
contentUri = uriForId(111);
testObject = new ContributionDao(client);
testObject = new ContributionDao(() -> client);
}
@Test
@ -288,7 +291,7 @@ public class ContributionDaoTest {
long uploaded = 456L;
MatrixCursor mc = createCursor(created, uploaded, false, LOCAL_URI);
Contribution c = ContributionDao.fromCursor(mc);
Contribution c = testObject.fromCursor(mc);
assertEquals(uriForId(111), c.getContentUri());
assertEquals("file", c.getFilename());
@ -312,7 +315,7 @@ public class ContributionDaoTest {
public void createFromCursor_nullableTimestamps() {
MatrixCursor mc = createCursor(0L, 0L, false, LOCAL_URI);
Contribution c = ContributionDao.fromCursor(mc);
Contribution c = testObject.fromCursor(mc);
assertNull(c.getTimestamp());
assertNull(c.getDateCreated());
@ -323,7 +326,7 @@ public class ContributionDaoTest {
public void createFromCursor_nullableLocalUri() {
MatrixCursor mc = createCursor(0L, 0L, false, "");
Contribution c = ContributionDao.fromCursor(mc);
Contribution c = testObject.fromCursor(mc);
assertNull(c.getLocalUri());
assertNull(c.getDateCreated());
@ -333,10 +336,10 @@ public class ContributionDaoTest {
@Test
public void createFromCursor_booleanEncoding() {
MatrixCursor mcFalse = createCursor(0L, 0L, false, LOCAL_URI);
assertFalse(ContributionDao.fromCursor(mcFalse).getMultiple());
assertFalse(testObject.fromCursor(mcFalse).getMultiple());
MatrixCursor mcHammer = createCursor(0L, 0L, true, LOCAL_URI);
assertTrue(ContributionDao.fromCursor(mcHammer).getMultiple());
assertTrue(testObject.fromCursor(mcHammer).getMultiple());
}
@NonNull

View file

@ -52,14 +52,14 @@ public class ModifierSequenceDaoTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
testObject = new ModifierSequenceDao(client);
testObject = new ModifierSequenceDao(() -> client);
}
@Test
public void createFromCursorWithEmptyModifiers() {
MatrixCursor cursor = createCursor("");
ModifierSequence seq = ModifierSequenceDao.fromCursor(cursor);
ModifierSequence seq = testObject.fromCursor(cursor);
assertEquals(EXPECTED_MEDIA_URI, seq.getMediaUri().toString());
assertEquals(BASE_URI.buildUpon().appendPath("1").toString(), seq.getContentUri().toString());
@ -70,7 +70,7 @@ public class ModifierSequenceDaoTest {
public void createFromCursorWtihCategoryModifier() {
MatrixCursor cursor = createCursor("{\"name\": \"CategoriesModifier\", \"data\": {}}");
ModifierSequence seq = ModifierSequenceDao.fromCursor(cursor);
ModifierSequence seq = testObject.fromCursor(cursor);
assertEquals(1, seq.getModifiers().size());
assertTrue(seq.getModifiers().get(0) instanceof CategoryModifier);
@ -80,7 +80,7 @@ public class ModifierSequenceDaoTest {
public void createFromCursorWithRemoveModifier() {
MatrixCursor cursor = createCursor("{\"name\": \"TemplateRemoverModifier\", \"data\": {}}");
ModifierSequence seq = ModifierSequenceDao.fromCursor(cursor);
ModifierSequence seq = testObject.fromCursor(cursor);
assertEquals(1, seq.getModifiers().size());
assertTrue(seq.getModifiers().get(0) instanceof TemplateRemoveModifier);
@ -89,7 +89,7 @@ public class ModifierSequenceDaoTest {
@Test
public void deleteSequence() throws Exception {
when(client.delete(isA(Uri.class), isNull(String.class), isNull(String[].class))).thenReturn(1);
ModifierSequence seq = ModifierSequenceDao.fromCursor(createCursor(""));
ModifierSequence seq = testObject.fromCursor(createCursor(""));
testObject.delete(seq);
@ -99,7 +99,7 @@ public class ModifierSequenceDaoTest {
@Test(expected = RuntimeException.class)
public void deleteTranslatesRemoteExceptions() throws Exception {
when(client.delete(isA(Uri.class), isNull(String.class), isNull(String[].class))).thenThrow(new RemoteException(""));
ModifierSequence seq = ModifierSequenceDao.fromCursor(createCursor(""));
ModifierSequence seq = testObject.fromCursor(createCursor(""));
testObject.delete(seq);
}
@ -110,9 +110,9 @@ public class ModifierSequenceDaoTest {
String expectedData = "{\"modifiers\":[" + modifierJson + "]}";
MatrixCursor cursor = createCursor(modifierJson);
testObject.save(ModifierSequenceDao.fromCursor(cursor));
testObject.save(testObject.fromCursor(cursor));
verify(client).update(eq(ModifierSequenceDao.fromCursor(cursor).getContentUri()), contentValuesCaptor.capture(), isNull(String.class), isNull(String[].class));
verify(client).update(eq(testObject.fromCursor(cursor).getContentUri()), contentValuesCaptor.capture(), isNull(String.class), isNull(String[].class));
ContentValues cv = contentValuesCaptor.getValue();
assertEquals(2, cv.size());
assertEquals(EXPECTED_MEDIA_URI, cv.get(ModifierSequenceDao.Table.COLUMN_MEDIA_URI));