add Arbitrary Data table

This commit is contained in:
tobiasKaminsky 2017-04-28 14:09:23 +02:00
parent fd161aa99f
commit aca5040a80
No known key found for this signature in database
GPG key ID: 0E00D4D47D0C5AF7
4 changed files with 305 additions and 25 deletions

View file

@ -0,0 +1,223 @@
/**
* Nextcloud Android client application
* <p>
* Copyright (C) 2017 Tobias Kaminsky
* Copyright (C) 2017 Nextcloud.
* <p>
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
* <p>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
* <p>
* You should have received a copy of the GNU Affero General Public
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.datamodel;
import android.accounts.Account;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import com.owncloud.android.db.ProviderMeta;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.util.ArrayList;
/**
* Database provider for handling the persistence aspects of arbitrary data table.
*/
public class ArbitraryDataProvider {
static private final String TAG = ArbitraryDataProvider.class.getSimpleName();
private ContentResolver contentResolver;
public ArbitraryDataProvider(ContentResolver contentResolver) {
if (contentResolver == null) {
throw new IllegalArgumentException("Cannot create an instance with a NULL contentResolver");
}
this.contentResolver = contentResolver;
}
public void storeOrUpdateKeyValue(Account account, String key, String newValue) {
Log_OC.v(TAG, "Adding arbitrary data with cloud id: " + account.name + " key: " + key + " value: " + newValue);
ArbitraryDataSet data = getArbitraryDataSet(account, key);
if (data == null) {
ContentValues cv = new ContentValues();
cv.put(ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_CLOUD_ID, account.name);
cv.put(ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_KEY, key);
cv.put(ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_VALUE, newValue);
Uri result = contentResolver.insert(ProviderMeta.ProviderTableMeta.CONTENT_URI_ARBITRARY_DATA, cv);
if (result == null) {
Log_OC.v(TAG, "Failed to store arbitrary data with cloud id: " + account.name + " key: " + key
+ " value: " + newValue);
}
} else {
ContentValues cv = new ContentValues();
cv.put(ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_CLOUD_ID, data.getCloudId());
cv.put(ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_KEY, data.getKey());
cv.put(ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_VALUE, newValue);
int result = contentResolver.update(
ProviderMeta.ProviderTableMeta.CONTENT_URI_ARBITRARY_DATA,
cv,
ProviderMeta.ProviderTableMeta._ID + "=?",
new String[]{String.valueOf(data.getId())}
);
if (result == 0) {
Log_OC.v(TAG, "Failed to update arbitrary data with cloud id: " + account.name + " key: " + key
+ " value: " + newValue);
}
}
}
public Long getLongValue(Account account, String key) {
String value = getValue(account, key);
if (value.isEmpty()) {
return -1l;
} else {
return Long.valueOf(value);
}
}
private ArrayList<String> getValues(Account account, String key) {
Cursor cursor = contentResolver.query(
ProviderMeta.ProviderTableMeta.CONTENT_URI_ARBITRARY_DATA,
null,
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_CLOUD_ID + " = ? and " +
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_KEY + " = ?",
new String[]{account.name, key},
null
);
if (cursor != null) {
ArrayList<String> list = new ArrayList<>();
if (cursor.moveToFirst()) {
do {
String value = cursor.getString(cursor.getColumnIndex(
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_VALUE));
if (value == null) {
Log_OC.e(TAG, "Arbitrary value could not be created from cursor");
} else {
list.add(value);
}
} while (cursor.moveToNext());
}
cursor.close();
return list;
} else {
Log_OC.e(TAG, "DB error restoring arbitrary values.");
}
return new ArrayList<>();
}
public String getValue(Account account, String key) {
Cursor cursor = contentResolver.query(
ProviderMeta.ProviderTableMeta.CONTENT_URI_ARBITRARY_DATA,
null,
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_CLOUD_ID + " = ? and " +
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_KEY + " = ?",
new String[]{account.name, key},
null
);
if (cursor != null) {
if (cursor.moveToFirst()) {
String value = cursor.getString(cursor.getColumnIndex(
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_VALUE));
if (value == null) {
Log_OC.e(TAG, "Arbitrary value could not be created from cursor");
} else {
return value;
}
}
cursor.close();
return "";
} else {
Log_OC.e(TAG, "DB error restoring arbitrary values.");
}
return "";
}
private ArbitraryDataSet getArbitraryDataSet(Account account, String key) {
Cursor cursor = contentResolver.query(
ProviderMeta.ProviderTableMeta.CONTENT_URI_ARBITRARY_DATA,
null,
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_CLOUD_ID + " = ? and " +
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_KEY + " = ?",
new String[]{account.name, key},
null
);
ArbitraryDataSet dataSet = null;
if (cursor != null) {
if (cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(ProviderMeta.ProviderTableMeta._ID));
String dbAccount = cursor.getString(cursor.getColumnIndex(
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_CLOUD_ID));
String dbKey = cursor.getString(cursor.getColumnIndex(
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_KEY));
String dbValue = cursor.getString(cursor.getColumnIndex(
ProviderMeta.ProviderTableMeta.ARBITRARY_DATA_VALUE));
if (id == -1) {
Log_OC.e(TAG, "Arbitrary value could not be created from cursor");
} else {
dataSet = new ArbitraryDataSet(id, dbAccount, dbKey, dbValue);
}
}
cursor.close();
} else {
Log_OC.e(TAG, "DB error restoring arbitrary values.");
}
return dataSet;
}
public class ArbitraryDataSet {
private int id;
private String cloudId;
private String key;
private String value;
public ArbitraryDataSet(int id, String cloudId, String key, String value) {
this.id = id;
this.cloudId = cloudId;
this.key = key;
this.value = value;
}
public int getId() {
return id;
}
public String getCloudId() {
return cloudId;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
}
}

View file

@ -33,7 +33,7 @@ import com.owncloud.android.MainApp;
public class ProviderMeta {
public static final String DB_NAME = "filelist";
public static final int DB_VERSION = 19;
public static final int DB_VERSION = 20;
private ProviderMeta() {
}
@ -45,6 +45,7 @@ public class ProviderMeta {
public static final String UPLOADS_TABLE_NAME = "list_of_uploads";
public static final String SYNCED_FOLDERS_TABLE_NAME = "synced_folders";
public static final String EXTERNAL_LINKS_TABLE_NAME = "external_links";
public static final String ARBITRARY_DATA_TABLE_NAME = "arbitrary_data";
private static final String CONTENT_PREFIX = "content://";
@ -64,6 +65,8 @@ public class ProviderMeta {
+ MainApp.getAuthority() + "/synced_folders");
public static final Uri CONTENT_URI_EXTERNAL_LINKS = Uri.parse(CONTENT_PREFIX
+ MainApp.getAuthority() + "/external_links");
public static final Uri CONTENT_URI_ARBITRARY_DATA = Uri.parse(CONTENT_PREFIX
+ MainApp.getAuthority() + "/arbitrary_data");
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file";
public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file";
@ -178,5 +181,10 @@ public class ProviderMeta {
public static final String EXTERNAL_LINKS_TYPE = "type";
public static final String EXTERNAL_LINKS_NAME = "name";
public static final String EXTERNAL_LINKS_URL = "url";
// Columns of arbitrary data table
public static final String ARBITRARY_DATA_CLOUD_ID = "cloud_id";
public static final String ARBITRARY_DATA_KEY = "key";
public static final String ARBITRARY_DATA_VALUE = "value";
}
}

View file

@ -72,6 +72,7 @@ public class FileContentProvider extends ContentProvider {
private static final int UPLOADS = 6;
private static final int SYNCED_FOLDERS = 7;
private static final int EXTERNAL_LINKS = 8;
private static final int ARBITRARY_DATA = 9;
private static final String TAG = FileContentProvider.class.getSimpleName();
@ -201,6 +202,9 @@ public class FileContentProvider extends ContentProvider {
case EXTERNAL_LINKS:
count = db.delete(ProviderTableMeta.EXTERNAL_LINKS_TABLE_NAME, where, whereArgs);
break;
case ARBITRARY_DATA:
count = db.delete(ProviderTableMeta.ARBITRARY_DATA_TABLE_NAME, where, whereArgs);
break;
default:
//Log_OC.e(TAG, "Unknown uri " + uri);
throw new IllegalArgumentException("Unknown uri: " + uri.toString());
@ -335,6 +339,18 @@ public class FileContentProvider extends ContentProvider {
}
return insertedExternalLinkUri;
case ARBITRARY_DATA:
Uri insertedArbitraryDataUri = null;
long arbitraryDataId = db.insert(ProviderTableMeta.ARBITRARY_DATA_TABLE_NAME, null, values);
if (arbitraryDataId > 0) {
insertedArbitraryDataUri =
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_ARBITRARY_DATA, arbitraryDataId);
} else {
throw new SQLException("ERROR " + uri);
}
return insertedArbitraryDataUri;
default:
throw new IllegalArgumentException("Unknown uri id: " + uri);
}
@ -385,6 +401,7 @@ public class FileContentProvider extends ContentProvider {
mUriMatcher.addURI(authority, "uploads/#", UPLOADS);
mUriMatcher.addURI(authority, "synced_folders", SYNCED_FOLDERS);
mUriMatcher.addURI(authority, "external_links", EXTERNAL_LINKS);
mUriMatcher.addURI(authority, "arbitrary_data", ARBITRARY_DATA);
return true;
}
@ -473,6 +490,13 @@ public class FileContentProvider extends ContentProvider {
+ uri.getPathSegments().get(1));
}
break;
case ARBITRARY_DATA:
sqlQuery.setTables(ProviderTableMeta.ARBITRARY_DATA_TABLE_NAME);
if (uri.getPathSegments().size() > 1) {
sqlQuery.appendWhere(ProviderTableMeta._ID + "="
+ uri.getPathSegments().get(1));
}
break;
default:
throw new IllegalArgumentException("Unknown uri id: " + uri);
}
@ -495,6 +519,9 @@ public class FileContentProvider extends ContentProvider {
case EXTERNAL_LINKS:
order = ProviderTableMeta.EXTERNAL_LINKS_NAME;
break;
case ARBITRARY_DATA:
order = ProviderTableMeta.ARBITRARY_DATA_CLOUD_ID;
break;
default: // Files
order = ProviderTableMeta.FILE_DEFAULT_SORT_ORDER;
break;
@ -538,25 +565,19 @@ public class FileContentProvider extends ContentProvider {
case DIRECTORY:
return 0; //updateFolderSize(db, selectionArgs[0]);
case SHARES:
return db.update(
ProviderTableMeta.OCSHARES_TABLE_NAME, values, selection, selectionArgs
);
return db.update(ProviderTableMeta.OCSHARES_TABLE_NAME, values, selection, selectionArgs);
case CAPABILITIES:
return db.update(
ProviderTableMeta.CAPABILITIES_TABLE_NAME, values, selection, selectionArgs
);
return db.update(ProviderTableMeta.CAPABILITIES_TABLE_NAME, values, selection, selectionArgs);
case UPLOADS:
int ret = db.update(
ProviderTableMeta.UPLOADS_TABLE_NAME, values, selection, selectionArgs
);
int ret = db.update(ProviderTableMeta.UPLOADS_TABLE_NAME, values, selection, selectionArgs);
trimSuccessfulUploads(db);
return ret;
case SYNCED_FOLDERS:
return db.update(ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME, values, selection, selectionArgs);
case ARBITRARY_DATA:
return db.update(ProviderTableMeta.ARBITRARY_DATA_TABLE_NAME, values, selection, selectionArgs);
default:
return db.update(
ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs
);
return db.update(ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs);
}
}
@ -611,6 +632,9 @@ public class FileContentProvider extends ContentProvider {
// Create external links table
createExternalLinksTable(db);
// Create arbitrary data table
createArbitraryData(db);
}
@Override
@ -927,6 +951,22 @@ public class FileContentProvider extends ContentProvider {
if (!upgraded) {
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
}
if (oldVersion < 20 && newVersion >= 20) {
Log_OC.i(SQL, "Adding arbitrary data table");
db.beginTransaction();
try {
createArbitraryData(db);
upgraded = true;
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
if (!upgraded) {
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
}
}
}
@ -1064,6 +1104,15 @@ public class FileContentProvider extends ContentProvider {
);
}
private void createArbitraryData(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + ProviderTableMeta.ARBITRARY_DATA_TABLE_NAME + "("
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " // id
+ ProviderTableMeta.ARBITRARY_DATA_CLOUD_ID + " TEXT, " // cloud id (account name + FQDN)
+ ProviderTableMeta.ARBITRARY_DATA_KEY + " TEXT, " // key
+ ProviderTableMeta.ARBITRARY_DATA_VALUE + " TEXT) " // value
);
}
/**
* Version 10 of database does not modify its scheme. It coincides with the upgrade of the ownCloud account names
* structure to include in it the path to the server instance. Updating the account names and path to local files

View file

@ -26,7 +26,6 @@ import android.accounts.Account;
import android.app.DatePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
@ -45,8 +44,8 @@ import com.evernote.android.job.JobManager;
import com.evernote.android.job.JobRequest;
import com.evernote.android.job.util.support.PersistableBundleCompat;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.ArbitraryDataProvider;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.db.PreferenceManager;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.services.ContactsBackupJob;
import com.owncloud.android.ui.fragment.FileFragment;
@ -70,7 +69,7 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
public static final String PREFERENCE_CONTACTS_LAST_BACKUP = "PREFERENCE_CONTACTS_LAST_BACKUP";
private SwitchCompat backupSwitch;
private SharedPreferences sharedPreferences;
private ArbitraryDataProvider arbitraryDataProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -87,10 +86,11 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
getSupportActionBar().setTitle(R.string.actionbar_contacts);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
backupSwitch = (SwitchCompat) findViewById(R.id.contacts_automatic_backup);
backupSwitch.setChecked(sharedPreferences.getBoolean(PREFERENCE_CONTACTS_AUTOMATIC_BACKUP, false));
backupSwitch.setChecked(arbitraryDataProvider.getValue(getAccount(), PREFERENCE_CONTACTS_AUTOMATIC_BACKUP)
.equals("true"));
backupSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
@ -113,7 +113,7 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
// display last backup
TextView lastBackup = (TextView) findViewById(R.id.contacts_last_backup_timestamp);
Long lastBackupTimestamp = sharedPreferences.getLong(PREFERENCE_CONTACTS_LAST_BACKUP, -1);
Long lastBackupTimestamp = arbitraryDataProvider.getLongValue(getAccount(), PREFERENCE_CONTACTS_LAST_BACKUP);
if (lastBackupTimestamp == -1) {
lastBackup.setText(R.string.contacts_preference_backup_never);
@ -186,9 +186,8 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
private void setAutomaticBackup(SwitchCompat backupSwitch, boolean bool) {
backupSwitch.setChecked(bool);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(PREFERENCE_CONTACTS_AUTOMATIC_BACKUP, bool);
editor.apply();
arbitraryDataProvider.storeOrUpdateKeyValue(getAccount(),
PREFERENCE_CONTACTS_AUTOMATIC_BACKUP, String.valueOf(bool));
}
private boolean checkAndAskForContactsReadPermission(final int permission) {
@ -200,12 +199,13 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
if (PermissionUtil.shouldShowRequestPermissionRationale(ContactsPreferenceActivity.this,
android.Manifest.permission.READ_CONTACTS)) {
// Show explanation to the user and then request permission
Snackbar snackbar = Snackbar.make(findViewById(R.id.contacts_linear_layout), R.string.contacts_read_permission,
Snackbar.LENGTH_INDEFINITE)
Snackbar snackbar = Snackbar.make(findViewById(R.id.contacts_linear_layout),
R.string.contacts_read_permission, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.common_ok, new View.OnClickListener() {
@Override
public void onClick(View v) {
PermissionUtil.requestReadContactPermission(ContactsPreferenceActivity.this, permission);
PermissionUtil.requestReadContactPermission(ContactsPreferenceActivity.this,
permission);
}
});