diff --git a/app/src/main/java/at/bitfire/davdroid/AccountSettings.java b/app/src/main/java/at/bitfire/davdroid/AccountSettings.java
index f7a0853c..a4356f7b 100644
--- a/app/src/main/java/at/bitfire/davdroid/AccountSettings.java
+++ b/app/src/main/java/at/bitfire/davdroid/AccountSettings.java
@@ -50,7 +50,7 @@ import lombok.Cleanup;
import okhttp3.HttpUrl;
public class AccountSettings {
- private final static int CURRENT_VERSION = 3;
+ private final static int CURRENT_VERSION = 4;
private final static String
KEY_SETTINGS_VERSION = "version",
@@ -80,10 +80,8 @@ public class AccountSettings {
private final static String KEY_MANAGE_CALENDAR_COLORS = "manage_calendar_colors";
/** Contact group method:
- automatic VCard4 if server supports VCard 4, VCard3 otherwise (default value)
- VCard3 adds a contact's groups to its CATEGORIES / interprets a contact's CATEGORIES as groups
- VCard4 uses groups as defined in VCard 4 (KIND/MEMBER properties)
- Apple uses Apple-proprietary X-ADDRESSBOOK-KIND/-MEMBER properties
+ value = null (not existing) groups as separate VCards (default)
+ "CATEGORIES" groups are per-contact CATEGORIES
*/
private final static String KEY_CONTACT_GROUP_METHOD = "contact_group_method";
@@ -240,11 +238,11 @@ public class AccountSettings {
final String name = accountManager.getUserData(account, KEY_CONTACT_GROUP_METHOD);
return name != null ?
GroupMethod.valueOf(name) :
- GroupMethod.AUTOMATIC;
+ GroupMethod.GROUP_VCARDS;
}
public void setGroupMethod(@NonNull GroupMethod method) {
- final String name = GroupMethod.AUTOMATIC.equals(method) ? null : method.name();
+ final String name = method == GroupMethod.GROUP_VCARDS ? null : method.name();
accountManager.setUserData(account, KEY_CONTACT_GROUP_METHOD, name);
}
@@ -424,6 +422,11 @@ public class AccountSettings {
accountManager.setUserData(account, KEY_SETTINGS_VERSION, "3");
}
+ @SuppressWarnings({ "Recycle", "unused" })
+ private void update_3_4() {
+ setGroupMethod(GroupMethod.CATEGORIES);
+ }
+
public static class AppUpdatedReceiver extends BroadcastReceiver {
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java
index 0a5d224c..ce0d7289 100644
--- a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java
+++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java
@@ -164,6 +164,14 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect
group.delete();
}
+ public void removeGroups() throws ContactsStorageException {
+ try {
+ provider.delete(syncAdapterURI(Groups.CONTENT_URI), null, null);
+ } catch(RemoteException e) {
+ throw new ContactsStorageException("Couldn't remove all groups", e);
+ }
+ }
+
// SYNC STATE
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalGroup.java b/app/src/main/java/at/bitfire/davdroid/resource/LocalGroup.java
index a083058b..88549fa4 100644
--- a/app/src/main/java/at/bitfire/davdroid/resource/LocalGroup.java
+++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalGroup.java
@@ -19,6 +19,7 @@ import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.RawContacts.Data;
+import android.provider.ContactsContract.RawContactsEntity;
import org.apache.commons.lang3.ArrayUtils;
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.java b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.java
index 28acc634..d14a7ce1 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.java
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.java
@@ -83,13 +83,13 @@ import okhttp3.ResponseBody;
*
Group handling differs according to the {@link #groupMethod}. There are two basic methods to
* handle/manage groups:
*
- * - VCard3 {@code CATEGORIES}: groups memberships are attached to each contact and represented as
+ *
- {@code CATEGORIES}: groups memberships are attached to each contact and represented as
* "category". When a group is dirty or has been deleted, all its members have to be set to
* dirty, too (because they have to be uploaded without the respective category). This
* is done in {@link #prepareDirty()}. Empty groups can be deleted without further processing,
* which is done in {@link #postProcess()} because groups may become empty after downloading
* updated remoted contacts.
- * - VCard4-style: individual and group contacts (with a list of member UIDs) are
+ *
- Groups as separate VCards: individual and group contacts (with a list of member UIDs) are
* distinguished. When a local group is dirty, its members don't need to be set to dirty.
*
* - However, when a contact is dirty, it has
@@ -171,11 +171,9 @@ public class ContactsSyncManager extends SyncManager {
App.log.info("Server advertises VCard/4 support: " + hasVCard4);
groupMethod = settings.getGroupMethod();
- if (GroupMethod.AUTOMATIC.equals(groupMethod))
- groupMethod = hasVCard4 ? GroupMethod.VCARD4 : GroupMethod.VCARD3_CATEGORIES;
App.log.info("Contact group method: " + groupMethod);
- localAddressBook().includeGroups = !GroupMethod.VCARD3_CATEGORIES.equals(groupMethod);
+ localAddressBook().includeGroups = groupMethod == GroupMethod.GROUP_VCARDS;
}
@Override
@@ -184,13 +182,14 @@ public class ContactsSyncManager extends SyncManager {
LocalAddressBook addressBook = localAddressBook();
- if (GroupMethod.VCARD3_CATEGORIES.equals(groupMethod)) {
- /* VCard3 group handling: groups memberships are represented as contact CATEGORIES */
+ if (groupMethod == GroupMethod.CATEGORIES) {
+ /* groups memberships are represented as contact CATEGORIES */
// groups with DELETED=1: set all members to dirty, then remove group
for (LocalGroup group : addressBook.getDeletedGroups()) {
- App.log.fine("Removing group " + group + " and marking its members as dirty");
- group.markMembersDirty();
+ App.log.fine("Finally removing group " + group);
+ // useless because Android deletes group memberships as soon as a group is set to DELETED:
+ // group.markMembersDirty();
group.delete();
}
@@ -201,7 +200,7 @@ public class ContactsSyncManager extends SyncManager {
group.clearDirty(null);
}
} else {
- /* VCard4 group handling: there are group contacts and individual contacts */
+ /* groups as separate VCards: there are group contacts and individual contacts */
// mark groups with changed members as dirty
BatchOperation batch = new BatchOperation(addressBook.provider);
@@ -231,8 +230,8 @@ public class ContactsSyncManager extends SyncManager {
LocalContact local = ((LocalContact)resource);
contact = local.getContact();
- if (groupMethod == GroupMethod.VCARD3_CATEGORIES) {
- // VCard3: add groups as CATEGORIES
+ if (groupMethod == GroupMethod.CATEGORIES) {
+ // add groups as CATEGORIES
for (long groupID : local.getGroupMemberships()) {
try {
@Cleanup Cursor c = provider.query(
@@ -362,7 +361,7 @@ public class ContactsSyncManager extends SyncManager {
@Override
protected void postProcess() throws CalendarStorageException, ContactsStorageException {
- if (groupMethod == GroupMethod.VCARD3_CATEGORIES) {
+ if (groupMethod == GroupMethod.CATEGORIES) {
/* VCard3 group handling: groups memberships are represented as contact CATEGORIES */
// remove empty groups
@@ -399,6 +398,13 @@ public class ContactsSyncManager extends SyncManager {
final Contact newData = contacts[0];
+ if (groupMethod == GroupMethod.CATEGORIES && newData.group) {
+ groupMethod = GroupMethod.GROUP_VCARDS;
+ App.log.warning("Received group VCard although group method is CATEGORIES. Deleting all groups; new group method: " + groupMethod);
+ localAddressBook().removeGroups();
+ settings.setGroupMethod(groupMethod);
+ }
+
// update local contact, if it exists
LocalResource local = localResources.get(fileName);
if (local != null) {
@@ -446,7 +452,7 @@ public class ContactsSyncManager extends SyncManager {
syncResult.stats.numInserts++;
}
- if (groupMethod == GroupMethod.VCARD3_CATEGORIES && local instanceof LocalContact) {
+ if (groupMethod == GroupMethod.CATEGORIES && local instanceof LocalContact) {
// VCard3: update group memberships from CATEGORIES
LocalContact contact = (LocalContact)local;
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AccountSettingsActivity.java b/app/src/main/java/at/bitfire/davdroid/ui/AccountSettingsActivity.java
index da77b75a..735532bc 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/AccountSettingsActivity.java
+++ b/app/src/main/java/at/bitfire/davdroid/ui/AccountSettingsActivity.java
@@ -85,7 +85,7 @@ public class AccountSettingsActivity extends AppCompatActivity {
try {
settings = new AccountSettings(getActivity(), account);
- } catch(InvalidAccountException e) {
+ } catch(InvalidAccountException e) {
App.log.log(Level.INFO, "Account is invalid or doesn't exist (anymore)", e);
getActivity().finish();
return;
@@ -98,8 +98,9 @@ public class AccountSettingsActivity extends AppCompatActivity {
prefUserName.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- settings.username((String) newValue);
- refresh(); return false;
+ settings.username((String)newValue);
+ refresh();
+ return false;
}
});
@@ -107,8 +108,9 @@ public class AccountSettingsActivity extends AppCompatActivity {
prefPassword.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- settings.password((String) newValue);
- refresh(); return false;
+ settings.password((String)newValue);
+ refresh();
+ return false;
}
});
@@ -117,8 +119,9 @@ public class AccountSettingsActivity extends AppCompatActivity {
prefPreemptive.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- settings.preemptiveAuth((Boolean) newValue);
- refresh(); return false;
+ settings.preemptiveAuth((Boolean)newValue);
+ refresh();
+ return false;
}
});
@@ -134,8 +137,9 @@ public class AccountSettingsActivity extends AppCompatActivity {
prefSyncContacts.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- settings.setSyncInterval(ContactsContract.AUTHORITY, Long.parseLong((String) newValue));
- refresh(); return false;
+ settings.setSyncInterval(ContactsContract.AUTHORITY, Long.parseLong((String)newValue));
+ refresh();
+ return false;
}
});
} else {
@@ -154,8 +158,9 @@ public class AccountSettingsActivity extends AppCompatActivity {
prefSyncCalendars.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- settings.setSyncInterval(CalendarContract.AUTHORITY, Long.parseLong((String) newValue));
- refresh(); return false;
+ settings.setSyncInterval(CalendarContract.AUTHORITY, Long.parseLong((String)newValue));
+ refresh();
+ return false;
}
});
} else {
@@ -174,8 +179,9 @@ public class AccountSettingsActivity extends AppCompatActivity {
prefSyncTasks.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, Long.parseLong((String) newValue));
- refresh(); return false;
+ settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, Long.parseLong((String)newValue));
+ refresh();
+ return false;
}
});
} else {
@@ -189,7 +195,8 @@ public class AccountSettingsActivity extends AppCompatActivity {
@Override
public boolean onPreferenceChange(Preference preference, Object wifiOnly) {
settings.setSyncWiFiOnly((Boolean)wifiOnly);
- refresh(); return false;
+ refresh();
+ return false;
}
});
@@ -205,68 +212,85 @@ public class AccountSettingsActivity extends AppCompatActivity {
public boolean onPreferenceChange(Preference preference, Object newValue) {
String ssid = (String)newValue;
settings.setSyncWifiOnlySSID(!TextUtils.isEmpty(ssid) ? ssid : null);
- refresh(); return false;
+ refresh();
+ return false;
}
});
// category: CardDAV
final SwitchPreferenceCompat prefRFC6868 = (SwitchPreferenceCompat)findPreference("vcard_rfc6868");
- prefRFC6868.setChecked(settings.getVCardRFC6868());
- prefRFC6868.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object o) {
- settings.setVCardRFC6868((Boolean)o);
- refresh(); return false;
- }
- });
+ if (syncIntervalContacts != null) {
+ prefRFC6868.setChecked(settings.getVCardRFC6868());
+ prefRFC6868.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object o) {
+ settings.setVCardRFC6868((Boolean)o);
+ refresh();
+ return false;
+ }
+ });
+ } else
+ prefRFC6868.setEnabled(false);
+
+ final ListPreference prefGroupMethod = (ListPreference)findPreference("contact_group_method");
+ if (syncIntervalContacts != null) {
+ prefGroupMethod.setValue(settings.getGroupMethod().name());
+ prefGroupMethod.setSummary(prefGroupMethod.getEntry());
+ prefGroupMethod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object o) {
+ String name = (String)o;
+ settings.setGroupMethod(GroupMethod.valueOf(name));
+ refresh();
+ return false;
+ }
+ });
+ } else
+ prefGroupMethod.setEnabled(false);
// category: CalDAV
final EditTextPreference prefTimeRangePastDays = (EditTextPreference)findPreference("time_range_past_days");
- Integer pastDays = settings.getTimeRangePastDays();
- if (pastDays != null) {
- prefTimeRangePastDays.setText(pastDays.toString());
- prefTimeRangePastDays.setSummary(getResources().getQuantityString(R.plurals.settings_sync_time_range_past_days, pastDays, pastDays));
- } else {
- prefTimeRangePastDays.setText(null);
- prefTimeRangePastDays.setSummary(R.string.settings_sync_time_range_past_none);
- }
- prefTimeRangePastDays.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- int days;
- try {
- days = Integer.parseInt((String)newValue);
- } catch(NumberFormatException ignored) {
- days = -1;
- }
- settings.setTimeRangePastDays(days < 0 ? null : days);
- refresh(); return false;
+ if (syncIntervalCalendars != null) {
+ Integer pastDays = settings.getTimeRangePastDays();
+ if (pastDays != null) {
+ prefTimeRangePastDays.setText(pastDays.toString());
+ prefTimeRangePastDays.setSummary(getResources().getQuantityString(R.plurals.settings_sync_time_range_past_days, pastDays, pastDays));
+ } else {
+ prefTimeRangePastDays.setText(null);
+ prefTimeRangePastDays.setSummary(R.string.settings_sync_time_range_past_none);
}
- });
+ prefTimeRangePastDays.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ int days;
+ try {
+ days = Integer.parseInt((String)newValue);
+ } catch(NumberFormatException ignored) {
+ days = -1;
+ }
+ settings.setTimeRangePastDays(days < 0 ? null : days);
+ refresh();
+ return false;
+ }
+ });
+ } else
+ prefTimeRangePastDays.setEnabled(false);
final SwitchPreferenceCompat prefManageColors = (SwitchPreferenceCompat)findPreference("manage_calendar_colors");
- prefManageColors.setChecked(settings.getManageCalendarColors());
- prefManageColors.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- settings.setManageCalendarColors((Boolean)newValue);
- refresh(); return false;
- }
- });
+ if (syncIntervalCalendars != null || syncIntervalTasks != null) {
+ prefManageColors.setChecked(settings.getManageCalendarColors());
+ prefManageColors.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ settings.setManageCalendarColors((Boolean)newValue);
+ refresh();
+ return false;
+ }
+ });
+ } else
+ prefManageColors.setEnabled(false);
- // category: CardDAV
- final ListPreference prefGroupMethod = (ListPreference)findPreference("contact_group_method");
- prefGroupMethod.setValue(settings.getGroupMethod().name());
- prefGroupMethod.setSummary(prefGroupMethod.getEntry());
- prefGroupMethod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object o) {
- String name = (String)o;
- settings.setGroupMethod(GroupMethod.valueOf(name));
- refresh(); return false;
- }
- });
}
-
}
+
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.java b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.java
index a7ddcd53..df3d963d 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.java
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.java
@@ -25,6 +25,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.Spinner;
import java.net.URI;
import java.util.logging.Level;
@@ -42,6 +43,7 @@ import at.bitfire.davdroid.model.ServiceDB.OpenHelper;
import at.bitfire.davdroid.model.ServiceDB.Services;
import at.bitfire.davdroid.resource.LocalTaskList;
import at.bitfire.ical4android.TaskProvider;
+import at.bitfire.vcard4android.GroupMethod;
import lombok.Cleanup;
public class AccountDetailsFragment extends Fragment {
@@ -49,6 +51,9 @@ public class AccountDetailsFragment extends Fragment {
private static final String KEY_CONFIG = "config";
private static final int DEFAULT_SYNC_INTERVAL = 4 * 3600; // 4 hours
+ Spinner spnrGroupMethod;
+
+
public static AccountDetailsFragment newInstance(DavResourceFinder.Configuration config) {
AccountDetailsFragment frag = new AccountDetailsFragment();
Bundle args = new Bundle(1);
@@ -57,6 +62,7 @@ public class AccountDetailsFragment extends Fragment {
return frag;
}
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.login_account_details, container, false);
@@ -74,6 +80,10 @@ public class AccountDetailsFragment extends Fragment {
final EditText editName = (EditText)v.findViewById(R.id.account_name);
editName.setText(config.userName);
+ // CardDAV-specific
+ v.findViewById(R.id.carddav).setVisibility(config.cardDAV != null ? View.VISIBLE : View.GONE);
+ spnrGroupMethod = (Spinner)v.findViewById(R.id.contact_group_method);
+
Button btnCreate = (Button)v.findViewById(R.id.create_account);
btnCreate.setOnClickListener(new View.OnClickListener() {
@Override
@@ -114,25 +124,39 @@ public class AccountDetailsFragment extends Fragment {
Intent refreshIntent = new Intent(getActivity(), DavService.class);
refreshIntent.setAction(DavService.ACTION_REFRESH_COLLECTIONS);
- db.beginTransactionNonExclusive();
if (config.cardDAV != null) {
+ // insert CardDAV service
long id = insertService(db, accountName, Services.SERVICE_CARDDAV, config.cardDAV);
+
+ // start CardDAV service detection (refresh collections)
refreshIntent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, id);
getActivity().startService(refreshIntent);
+ // initial CardDAV account settings
+ int idx = spnrGroupMethod.getSelectedItemPosition();
+ String groupMethodName = getResources().getStringArray(R.array.settings_contact_group_method_values)[idx];
+ settings.setGroupMethod(GroupMethod.valueOf(groupMethodName));
+
+ // enable contact sync
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1);
settings.setSyncInterval(ContactsContract.AUTHORITY, DEFAULT_SYNC_INTERVAL);
} else
+ // disable contact sync when CardDAV is not available
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
if (config.calDAV != null) {
+ // insert CalDAV service
long id = insertService(db, accountName, Services.SERVICE_CALDAV, config.calDAV);
+
+ // start CalDAV service detection (refresh collections)
refreshIntent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, id);
getActivity().startService(refreshIntent);
+ // enable calendar sync
ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 1);
settings.setSyncInterval(CalendarContract.AUTHORITY, DEFAULT_SYNC_INTERVAL);
+ // enable task sync, if possible
if (Build.VERSION.SDK_INT >= 23 || LocalTaskList.tasksProviderAvailable(getContext())) {
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 1);
settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, DEFAULT_SYNC_INTERVAL);
@@ -141,15 +165,13 @@ public class AccountDetailsFragment extends Fragment {
// because otherwise, there will be a non-catchable SecurityException as soon as OpenTasks is installed
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 0);
} else {
+ // disable calendar and task sync when CalDAV is not available
ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 0);
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 0);
}
- db.setTransactionSuccessful();
} catch(InvalidAccountException e) {
App.log.log(Level.SEVERE, "Couldn't access account settings", e);
- } finally {
- db.endTransaction();
}
return true;
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginCredentialsFragment.java b/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginCredentialsFragment.java
index 029c2df9..954df682 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginCredentialsFragment.java
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginCredentialsFragment.java
@@ -87,6 +87,7 @@ public class LoginCredentialsFragment extends Fragment implements CompoundButton
boolean loginByEmail = buttonView == radioUseEmail;
emailDetails.setVisibility(loginByEmail ? View.VISIBLE : View.GONE);
urlDetails.setVisibility(loginByEmail ? View.GONE : View.VISIBLE);
+ (loginByEmail ? editEmailAddress : editBaseURL).requestFocus();
}
}
diff --git a/app/src/main/res/layout/login_account_details.xml b/app/src/main/res/layout/login_account_details.xml
index 6cf090ff..84c0479b 100644
--- a/app/src/main/res/layout/login_account_details.xml
+++ b/app/src/main/res/layout/login_account_details.xml
@@ -38,11 +38,32 @@
android:inputType="textEmailAddress"/>
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 470d4c9f..66ec3af0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -126,6 +126,7 @@
Create account
Account name
Use your email address as account name because Android will use the account name as ORGANIZER field for events you create. You can\'t have two accounts with the same name.
+ Contact group method:
Account name required
Account could not be created
@@ -182,16 +183,12 @@
CardDAV
Contact group method
-
- AUTOMATIC
- - VCARD3_CATEGORIES
- - VCARD4
- - X_ADDRESSBOOK_SERVER
+ - GROUP_VCARDS
+ - CATEGORIES
- - Automatic (VCard3/VCard4)
- - VCard3 only (CATEGORIES)
- - VCard4 only (KIND/MEMBER)
- - Apple (X-ADDRESSBOOK-SERVER)
+ - Groups are separate VCards
+ - Groups are per-contact categories
Use RFC6868 for VCards
Double quotes can be used in parameter values
diff --git a/scripts/fetch-db.sh b/scripts/fetch-db.sh
new file mode 100755
index 00000000..e1bba452
--- /dev/null
+++ b/scripts/fetch-db.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+cd ~/tmp
+adb pull /data/data/com.android.providers.contacts/databases/contacts2.db
diff --git a/vcard4android b/vcard4android
index 38e24e8a..02eae2c0 160000
--- a/vcard4android
+++ b/vcard4android
@@ -1 +1 @@
-Subproject commit 38e24e8a19df339618ec33afb294a3e4a61b3cbe
+Subproject commit 02eae2c067c8fca4a9cf9f0e324af9bb4b91d3d0