From e0b21abc35c4a2d88e7e28e11bbb243ae081cc87 Mon Sep 17 00:00:00 2001 From: rfc2822 Date: Sun, 16 Mar 2014 17:54:48 +0100 Subject: [PATCH] New settings management * Account settings are now read/set using AccountSettings * AccountSettings upgrades old account settings when necessary * Settings v1: use absolute URLs instead of paths and discard principal path (required for future implementation of well-known URIs) --- src/at/bitfire/davdroid/Constants.java | 7 - .../davdroid/resource/LocalAddressBook.java | 13 +- .../davdroid/resource/LocalCalendar.java | 8 +- .../syncadapter/AccountDetailsFragment.java | 6 +- .../davdroid/syncadapter/AccountSettings.java | 162 ++++++++++++++++++ .../CalendarsSyncAdapterService.java | 15 +- .../ContactsSyncAdapterService.java | 21 +-- .../QueryServerDialogFragment.java | 4 +- .../syncadapter/SelectCollectionsAdapter.java | 2 +- .../davdroid/syncadapter/ServerInfo.java | 2 +- 10 files changed, 192 insertions(+), 48 deletions(-) create mode 100644 src/at/bitfire/davdroid/syncadapter/AccountSettings.java diff --git a/src/at/bitfire/davdroid/Constants.java b/src/at/bitfire/davdroid/Constants.java index 17274cd8..bc089404 100644 --- a/src/at/bitfire/davdroid/Constants.java +++ b/src/at/bitfire/davdroid/Constants.java @@ -16,12 +16,5 @@ public class Constants { ACCOUNT_TYPE = "bitfire.at.davdroid", - ACCOUNT_KEY_USERNAME = "user_name", - ACCOUNT_KEY_BASE_URL = "principal_url", - ACCOUNT_KEY_AUTH_PREEMPTIVE = "auth_preemptive", - - ACCOUNT_KEY_ADDRESSBOOK_PATH = "addressbook_path", - ACCOUNT_KEY_ADDRESSBOOK_CTAG = "addressbook_ctag", - WEB_URL_HELP = "http://davdroid.bitfire.at/configuration?pk_campaign=davdroid-app"; } diff --git a/src/at/bitfire/davdroid/resource/LocalAddressBook.java b/src/at/bitfire/davdroid/resource/LocalAddressBook.java index 102b76d2..6870ea9d 100644 --- a/src/at/bitfire/davdroid/resource/LocalAddressBook.java +++ b/src/at/bitfire/davdroid/resource/LocalAddressBook.java @@ -25,7 +25,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.WordUtils; import android.accounts.Account; -import android.accounts.AccountManager; import android.content.ContentProviderClient; import android.content.ContentProviderOperation; import android.content.ContentProviderOperation.Builder; @@ -50,7 +49,7 @@ import android.provider.ContactsContract.CommonDataKinds.Website; import android.provider.ContactsContract.Data; import android.provider.ContactsContract.RawContacts; import android.util.Log; -import at.bitfire.davdroid.Constants; +import at.bitfire.davdroid.syncadapter.AccountSettings; import ezvcard.parameter.AddressType; import ezvcard.parameter.EmailType; import ezvcard.parameter.ImppType; @@ -66,7 +65,7 @@ import ezvcard.property.Telephone; public class LocalAddressBook extends LocalCollection { private final static String TAG = "davdroid.LocalAddressBook"; - protected AccountManager accountManager; + protected AccountSettings accountSettings; /* database fields */ @@ -91,9 +90,9 @@ public class LocalAddressBook extends LocalCollection { - public LocalAddressBook(Account account, ContentProviderClient providerClient, AccountManager accountManager) { + public LocalAddressBook(Account account, ContentProviderClient providerClient, AccountSettings accountSettings) { super(account, providerClient); - this.accountManager = accountManager; + this.accountSettings = accountSettings; } @@ -106,12 +105,12 @@ public class LocalAddressBook extends LocalCollection { @Override public String getCTag() { - return accountManager.getUserData(account, Constants.ACCOUNT_KEY_ADDRESSBOOK_CTAG); + return accountSettings.getAddressBookCTag(); } @Override public void setCTag(String cTag) { - accountManager.setUserData(account, Constants.ACCOUNT_KEY_ADDRESSBOOK_CTAG, cTag); + accountSettings.setAddressBookCTag(cTag); } diff --git a/src/at/bitfire/davdroid/resource/LocalCalendar.java b/src/at/bitfire/davdroid/resource/LocalCalendar.java index 3eb48135..5761d07a 100644 --- a/src/at/bitfire/davdroid/resource/LocalCalendar.java +++ b/src/at/bitfire/davdroid/resource/LocalCalendar.java @@ -69,7 +69,7 @@ public class LocalCalendar extends LocalCollection { private static final String TAG = "davdroid.LocalCalendar"; @Getter protected long id; - @Getter protected String path, cTag; + @Getter protected String url, cTag; protected static String COLLECTION_COLUMN_CTAG = Calendars.CAL_SYNC1; @@ -119,7 +119,7 @@ public class LocalCalendar extends LocalCollection { ContentValues values = new ContentValues(); values.put(Calendars.ACCOUNT_NAME, account.name); values.put(Calendars.ACCOUNT_TYPE, account.type); - values.put(Calendars.NAME, info.getPath()); + values.put(Calendars.NAME, info.getURL()); values.put(Calendars.CALENDAR_DISPLAY_NAME, info.getTitle()); values.put(Calendars.CALENDAR_COLOR, color); values.put(Calendars.OWNER_ACCOUNT, account.name); @@ -158,10 +158,10 @@ public class LocalCalendar extends LocalCollection { return calendars.toArray(new LocalCalendar[0]); } - public LocalCalendar(Account account, ContentProviderClient providerClient, int id, String path, String cTag) throws RemoteException { + public LocalCalendar(Account account, ContentProviderClient providerClient, int id, String url, String cTag) throws RemoteException { super(account, providerClient); this.id = id; - this.path = path; + this.url = url; this.cTag = cTag; } diff --git a/src/at/bitfire/davdroid/syncadapter/AccountDetailsFragment.java b/src/at/bitfire/davdroid/syncadapter/AccountDetailsFragment.java index 01b11558..72790478 100644 --- a/src/at/bitfire/davdroid/syncadapter/AccountDetailsFragment.java +++ b/src/at/bitfire/davdroid/syncadapter/AccountDetailsFragment.java @@ -86,15 +86,11 @@ public class AccountDetailsFragment extends Fragment implements TextWatcher { AccountManager accountManager = AccountManager.get(getActivity()); Account account = new Account(accountName, Constants.ACCOUNT_TYPE); - Bundle userData = new Bundle(); - userData.putString(Constants.ACCOUNT_KEY_BASE_URL, serverInfo.getBaseURL()); - userData.putString(Constants.ACCOUNT_KEY_USERNAME, serverInfo.getUserName()); - userData.putString(Constants.ACCOUNT_KEY_AUTH_PREEMPTIVE, Boolean.toString(serverInfo.isAuthPreemptive())); + Bundle userData = AccountSettings.createBundle(serverInfo); boolean syncContacts = false; for (ServerInfo.ResourceInfo addressBook : serverInfo.getAddressBooks()) if (addressBook.isEnabled()) { - userData.putString(Constants.ACCOUNT_KEY_ADDRESSBOOK_PATH, addressBook.getPath()); ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1); syncContacts = true; continue; diff --git a/src/at/bitfire/davdroid/syncadapter/AccountSettings.java b/src/at/bitfire/davdroid/syncadapter/AccountSettings.java new file mode 100644 index 00000000..13d3882d --- /dev/null +++ b/src/at/bitfire/davdroid/syncadapter/AccountSettings.java @@ -0,0 +1,162 @@ +package at.bitfire.davdroid.syncadapter; + +import java.net.URI; +import java.net.URISyntaxException; + +import lombok.Cleanup; +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.CalendarContract; +import android.provider.CalendarContract.Calendars; +import android.util.Log; + +public class AccountSettings { + private final static String TAG = "davdroid.AccountSettings"; + + private final static int CURRENT_VERSION = 1; + private final static String + KEY_SETTINGS_VERSION = "version", + + KEY_USERNAME = "user_name", + KEY_AUTH_PREEMPTIVE = "auth_preemptive", + + KEY_ADDRESSBOOK_URL = "addressbook_url", + KEY_ADDRESSBOOK_CTAG = "addressbook_ctag"; + + Context context; + AccountManager accountManager; + Account account; + + + public AccountSettings(Context context, Account account) { + this.context = context; + this.account = account; + + accountManager = AccountManager.get(context); + + synchronized(AccountSettings.class) { + int version = 0; + try { + version = Integer.parseInt(accountManager.getUserData(account, KEY_SETTINGS_VERSION)); + } catch(NumberFormatException e) { + } + if (version < CURRENT_VERSION) + update(version); + } + } + + + public static Bundle createBundle(ServerInfo serverInfo) { + Bundle bundle = new Bundle(); + bundle.putString(KEY_SETTINGS_VERSION, String.valueOf(CURRENT_VERSION)); + bundle.putString(KEY_USERNAME, serverInfo.getUserName()); + bundle.putString(KEY_AUTH_PREEMPTIVE, Boolean.toString(serverInfo.isAuthPreemptive())); + for (ServerInfo.ResourceInfo addressBook : serverInfo.getAddressBooks()) + if (addressBook.isEnabled()) { + bundle.putString(KEY_ADDRESSBOOK_URL, addressBook.getURL()); + continue; + } + return bundle; + } + + + // general settings + + public String getUserName() { + return accountManager.getUserData(account, KEY_USERNAME); + } + + public String getPassword() { + return accountManager.getPassword(account); + } + + public boolean getPreemptiveAuth() { + return Boolean.parseBoolean(accountManager.getUserData(account, KEY_AUTH_PREEMPTIVE)); + } + + + // address book (CardDAV) settings + + public String getAddressBookURL() { + return accountManager.getUserData(account, KEY_ADDRESSBOOK_URL); + } + + public String getAddressBookCTag() { + return accountManager.getUserData(account, KEY_ADDRESSBOOK_CTAG); + } + + public void setAddressBookCTag(String cTag) { + accountManager.setUserData(account, KEY_ADDRESSBOOK_CTAG, cTag); + } + + + // update from previous account settings + + private void update(int fromVersion) { + Log.i(TAG, "Account settings must be updated from v" + fromVersion + " to v" + CURRENT_VERSION); + for (int toVersion = CURRENT_VERSION; toVersion > fromVersion; toVersion--) + update(fromVersion, toVersion); + } + + private void update(int fromVersion, int toVersion) { + Log.i(TAG, "Updating account settings from v" + fromVersion + " to " + toVersion); + try { + if (fromVersion == 0 && toVersion == 1) + update_0_1(); + else + Log.wtf(TAG, "Don't know how to update settings from v" + fromVersion + " to v" + toVersion); + } catch(Exception e) { + Log.e(TAG, "Couldn't update account settings (DAVdroid will probably crash)!", e); + } + } + + private void update_0_1() throws URISyntaxException { + String v0_principalURL = accountManager.getUserData(account, "principal_url"), + v0_addressBookPath = accountManager.getUserData(account, "addressbook_path"); + Log.d(TAG, "Old principal URL = " + v0_principalURL); + Log.d(TAG, "Old address book path = " + v0_addressBookPath); + + URI principalURI = new URI(v0_principalURL); + + // update address book + String addressBookURL = principalURI.resolve(v0_addressBookPath).toASCIIString(); + Log.d(TAG, "New address book URL = " + addressBookURL); + accountManager.setUserData(account, "addressbook_url", addressBookURL); + + // update calendars + ContentResolver resolver = context.getContentResolver(); + Uri calendars = Calendars.CONTENT_URI.buildUpon() + .appendQueryParameter(Calendars.ACCOUNT_NAME, account.name) + .appendQueryParameter(Calendars.ACCOUNT_TYPE, account.type) + .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true").build(); + @Cleanup Cursor cursor = resolver.query(calendars, new String[] { Calendars._ID, Calendars.NAME }, null, null, null); + while (cursor != null && cursor.moveToNext()) { + int id = cursor.getInt(0); + String v0_path = cursor.getString(1), + v1_url = principalURI.resolve(v0_path).toASCIIString(); + Log.d(TAG, "Updating calendar #" + id + " name: " + v0_path + " -> " + v1_url); + Uri calendar = ContentUris.appendId(Calendars.CONTENT_URI.buildUpon() + .appendQueryParameter(Calendars.ACCOUNT_NAME, account.name) + .appendQueryParameter(Calendars.ACCOUNT_TYPE, account.type) + .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true"), id).build(); + ContentValues newValues = new ContentValues(1); + newValues.put(Calendars.NAME, v1_url); + if (resolver.update(calendar, newValues, null, null) != 1) + Log.e(TAG, "Number of modified calendars != 1"); + } + + Log.d(TAG, "Cleaning old principal URL and address book path"); + accountManager.setUserData(account, "principal_url", null); + accountManager.setUserData(account, "addressbook_path", null); + + Log.d(TAG, "Updated settings successfully!"); + accountManager.setUserData(account, KEY_SETTINGS_VERSION, "1"); + } +} diff --git a/src/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java b/src/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java index 797e1f9c..c20dc143 100644 --- a/src/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java +++ b/src/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java @@ -10,7 +10,6 @@ ******************************************************************************/ package at.bitfire.davdroid.syncadapter; -import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; @@ -24,7 +23,6 @@ import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; -import at.bitfire.davdroid.Constants; import at.bitfire.davdroid.resource.CalDavCalendar; import at.bitfire.davdroid.resource.LocalCalendar; import at.bitfire.davdroid.resource.LocalCollection; @@ -53,17 +51,16 @@ public class CalendarsSyncAdapterService extends Service { @Override protected Map, RemoteCollection> getSyncPairs(Account account, ContentProviderClient provider) { + AccountSettings settings = new AccountSettings(context, account); + String userName = settings.getUserName(), + password = settings.getPassword(); + boolean preemptive = settings.getPreemptiveAuth(); + try { Map, RemoteCollection> map = new HashMap, RemoteCollection>(); for (LocalCalendar calendar : LocalCalendar.findAll(account, provider)) { - URI baseURI = new URI(accountManager.getUserData(account, Constants.ACCOUNT_KEY_BASE_URL)); - URI uri = baseURI.resolve(calendar.getPath()); - RemoteCollection dav = new CalDavCalendar(uri.toString(), - accountManager.getUserData(account, Constants.ACCOUNT_KEY_USERNAME), - accountManager.getPassword(account), - Boolean.parseBoolean(accountManager.getUserData(account, Constants.ACCOUNT_KEY_AUTH_PREEMPTIVE))); - + RemoteCollection dav = new CalDavCalendar(calendar.getUrl(), userName, password, preemptive); map.put(calendar, dav); } return map; diff --git a/src/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.java b/src/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.java index 45fc690a..81b9a9c9 100644 --- a/src/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.java +++ b/src/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.java @@ -10,7 +10,6 @@ ******************************************************************************/ package at.bitfire.davdroid.syncadapter; -import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; @@ -23,7 +22,6 @@ import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.util.Log; -import at.bitfire.davdroid.Constants; import at.bitfire.davdroid.resource.CardDavAddressBook; import at.bitfire.davdroid.resource.LocalAddressBook; import at.bitfire.davdroid.resource.LocalCollection; @@ -52,19 +50,18 @@ public class ContactsSyncAdapterService extends Service { @Override protected Map, RemoteCollection> getSyncPairs(Account account, ContentProviderClient provider) { - String addressBookPath = accountManager.getUserData(account, Constants.ACCOUNT_KEY_ADDRESSBOOK_PATH); - if (addressBookPath == null) + AccountSettings settings = new AccountSettings(context, account); + String userName = settings.getUserName(), + password = settings.getPassword(); + boolean preemptive = settings.getPreemptiveAuth(); + + String addressBookURL = settings.getAddressBookURL(); + if (addressBookURL == null) return null; try { - LocalCollection database = new LocalAddressBook(account, provider, accountManager); - - URI uri = new URI(accountManager.getUserData(account, Constants.ACCOUNT_KEY_BASE_URL)).resolve(addressBookPath); - RemoteCollection dav = new CardDavAddressBook( - uri.toString(), - accountManager.getUserData(account, Constants.ACCOUNT_KEY_USERNAME), - accountManager.getPassword(account), - Boolean.parseBoolean(accountManager.getUserData(account, Constants.ACCOUNT_KEY_AUTH_PREEMPTIVE))); + LocalCollection database = new LocalAddressBook(account, provider, settings); + RemoteCollection dav = new CardDavAddressBook(addressBookURL, userName, password, preemptive); Map, RemoteCollection> map = new HashMap, RemoteCollection>(); map.put(database, dav); diff --git a/src/at/bitfire/davdroid/syncadapter/QueryServerDialogFragment.java b/src/at/bitfire/davdroid/syncadapter/QueryServerDialogFragment.java index ae6c7fd8..c79622ae 100644 --- a/src/at/bitfire/davdroid/syncadapter/QueryServerDialogFragment.java +++ b/src/at/bitfire/davdroid/syncadapter/QueryServerDialogFragment.java @@ -167,7 +167,7 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC ServerInfo.ResourceInfo info = new ServerInfo.ResourceInfo( ServerInfo.ResourceInfo.Type.ADDRESS_BOOK, resource.isReadOnly(), - resource.getLocation().getRawPath(), + resource.getLocation().toASCIIString(), resource.getDisplayName(), resource.getDescription(), resource.getColor() ); @@ -199,7 +199,7 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC ServerInfo.ResourceInfo info = new ServerInfo.ResourceInfo( ServerInfo.ResourceInfo.Type.CALENDAR, resource.isReadOnly(), - resource.getLocation().getRawPath(), + resource.getLocation().toASCIIString(), resource.getDisplayName(), resource.getDescription(), resource.getColor() ); diff --git a/src/at/bitfire/davdroid/syncadapter/SelectCollectionsAdapter.java b/src/at/bitfire/davdroid/syncadapter/SelectCollectionsAdapter.java index fa311fbf..ee1fcfd3 100644 --- a/src/at/bitfire/davdroid/syncadapter/SelectCollectionsAdapter.java +++ b/src/at/bitfire/davdroid/syncadapter/SelectCollectionsAdapter.java @@ -134,7 +134,7 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter String description = info.getDescription(); if (description == null) - description = info.getPath(); + description = info.getURL(); // FIXME escape HTML view.setText(Html.fromHtml(title + "
" + description)); diff --git a/src/at/bitfire/davdroid/syncadapter/ServerInfo.java b/src/at/bitfire/davdroid/syncadapter/ServerInfo.java index bcd773a4..29162535 100644 --- a/src/at/bitfire/davdroid/syncadapter/ServerInfo.java +++ b/src/at/bitfire/davdroid/syncadapter/ServerInfo.java @@ -55,7 +55,7 @@ public class ServerInfo implements Serializable { final Type type; final boolean readOnly; - final String path, title, description, color; + final String URL, title, description, color; String timezone; }