diff --git a/app/src/main/java/at/bitfire/davdroid/AccountSettings.java b/app/src/main/java/at/bitfire/davdroid/AccountSettings.java index 0f1484bf..7b1e9cc1 100644 --- a/app/src/main/java/at/bitfire/davdroid/AccountSettings.java +++ b/app/src/main/java/at/bitfire/davdroid/AccountSettings.java @@ -9,7 +9,6 @@ package at.bitfire.davdroid; import android.accounts.Account; import android.accounts.AccountManager; -import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationManager; import android.content.ContentProviderClient; @@ -19,35 +18,44 @@ import android.content.ContentValues; import android.content.Context; import android.content.PeriodicSync; import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.provider.CalendarContract; import android.provider.CalendarContract.Calendars; import android.provider.ContactsContract; +import android.support.annotation.NonNull; +import android.support.v7.app.NotificationCompat; import android.text.TextUtils; -import org.apache.commons.lang3.math.NumberUtils; - +import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.logging.Level; +import at.bitfire.davdroid.model.ServiceDB; +import at.bitfire.davdroid.model.ServiceDB.*; import at.bitfire.davdroid.resource.LocalAddressBook; +import at.bitfire.davdroid.resource.LocalCalendar; +import at.bitfire.davdroid.resource.LocalTaskList; +import at.bitfire.ical4android.CalendarStorageException; +import at.bitfire.ical4android.TaskProvider; import at.bitfire.vcard4android.ContactsStorageException; import lombok.Cleanup; +import okhttp3.HttpUrl; public class AccountSettings { - private final static int CURRENT_VERSION = 2; + private final static int CURRENT_VERSION = 3; private final static String KEY_SETTINGS_VERSION = "version", - KEY_USERNAME = "user_name", - KEY_AUTH_PREEMPTIVE = "auth_preemptive", - KEY_LAST_ANDROID_VERSION = "last_android_version"; + KEY_USERNAME = "user_name", + KEY_AUTH_PREEMPTIVE = "auth_preemptive"; - /* Time range limitation to the past [days] + /** Time range limitation to the past [in days] value = null default value (DEFAULT_TIME_RANGE_PAST_DAYS) < 0 (-1) no limit >= 0 entries more than n days in the past won't be synchronized @@ -62,7 +70,7 @@ public class AccountSettings { final Account account; - public AccountSettings(Context context, Account account) { + public AccountSettings(@NonNull Context context, @NonNull Account account) { this.context = context; this.account = account; @@ -74,46 +82,25 @@ public class AccountSettings { version = Integer.parseInt(accountManager.getUserData(account, KEY_SETTINGS_VERSION)); } catch(NumberFormatException ignored) { } - App.log.info("AccountSettings version: v" + version + ", should be: " + version); + App.log.info("Account " + account.name + " has version " + version + ", current version: " + CURRENT_VERSION); if (version < CURRENT_VERSION) { - showNotification(Constants.NOTIFICATION_ACCOUNT_SETTINGS_UPDATED, - context.getString(R.string.settings_version_update_title), - context.getString(R.string.settings_version_update_description)); + Notification notify = new NotificationCompat.Builder(context) + .setSmallIcon(R.drawable.ic_launcher) + .setContentTitle(context.getString(R.string.settings_version_update)) + .setContentText(context.getString(R.string.settings_version_update_warning)) + .setCategory(NotificationCompat.CATEGORY_SYSTEM) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setLocalOnly(true) + .build(); + NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(Constants.NOTIFICATION_ACCOUNT_SETTINGS_UPDATED, notify); + update(version); } - - // check whether Android version has changed - String lastAndroidVersionInt = accountManager.getUserData(account, KEY_LAST_ANDROID_VERSION); - if (lastAndroidVersionInt != null && NumberUtils.toInt(lastAndroidVersionInt) < Build.VERSION.SDK_INT) { - // notify user - showNotification(Constants.NOTIFICATION_ANDROID_VERSION_UPDATED, - context.getString(R.string.settings_android_update_title), - context.getString(R.string.settings_android_update_description)); - } - accountManager.setUserData(account, KEY_LAST_ANDROID_VERSION, String.valueOf(Build.VERSION.SDK_INT)); } } - @TargetApi(21) - protected void showNotification(int id, String title, String message) { - NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); - - Notification.Builder n = new Notification.Builder(context); - if (Build.VERSION.SDK_INT >= 16) { - n.setPriority(Notification.PRIORITY_HIGH); - n.setStyle(new Notification.BigTextStyle().bigText(message)); - } if (Build.VERSION.SDK_INT >= 20) - n.setLocalOnly(true); - if (Build.VERSION.SDK_INT >= 21) - n.setCategory(Notification.CATEGORY_SYSTEM); - n.setSmallIcon(R.drawable.ic_launcher); - n.setContentTitle(title); - n.setContentText(message); - nm.notify(id, Build.VERSION.SDK_INT >= 16 ? n.build() : n.getNotification()); - } - - public static Bundle initialUserData(String userName, boolean preemptive) { Bundle bundle = new Bundle(); bundle.putString(KEY_SETTINGS_VERSION, String.valueOf(CURRENT_VERSION)); @@ -126,10 +113,10 @@ public class AccountSettings { // authentication settings public String username() { return accountManager.getUserData(account, KEY_USERNAME); } - public void username(String userName) { accountManager.setUserData(account, KEY_USERNAME, userName); } + public void username(@NonNull String userName) { accountManager.setUserData(account, KEY_USERNAME, userName); } public String password() { return accountManager.getPassword(account); } - public void password(String password) { accountManager.setPassword(account, password); } + public void password(@NonNull String password) { accountManager.setPassword(account, password); } public boolean preemptiveAuth() { return Boolean.parseBoolean(accountManager.getUserData(account, KEY_AUTH_PREEMPTIVE)); } public void preemptiveAuth(boolean preemptive) { accountManager.setUserData(account, KEY_AUTH_PREEMPTIVE, Boolean.toString(preemptive)); } @@ -137,7 +124,7 @@ public class AccountSettings { // sync. settings - public Long getSyncInterval(String authority) { + public Long getSyncInterval(@NonNull String authority) { if (ContentResolver.getIsSyncable(account, authority) <= 0) return null; @@ -151,7 +138,7 @@ public class AccountSettings { return SYNC_INTERVAL_MANUALLY; } - public void setSyncInterval(String authority, long seconds) { + public void setSyncInterval(@NonNull String authority, long seconds) { if (seconds == SYNC_INTERVAL_MANUALLY) { ContentResolver.setSyncAutomatically(account, authority, false); } else { @@ -177,30 +164,19 @@ public class AccountSettings { // update from previous account settings private void update(int fromVersion) { - for (int toVersion = fromVersion + 1; toVersion <= CURRENT_VERSION; toVersion++) - updateTo(toVersion); - } - - private void updateTo(int toVersion) { - final int fromVersion = toVersion - 1; - App.log.info("Updating account settings from v" + fromVersion + " to " + toVersion); - try { - switch (toVersion) { - case 1: - update_0_1(); - break; - case 2: - update_1_2(); - break; - default: - App.log.severe("Don't know how to update settings from v" + fromVersion + " to v" + toVersion); + for (int toVersion = fromVersion + 1; toVersion <= CURRENT_VERSION; toVersion++) { + App.log.info("Updating account " + account.name + " from version " + fromVersion + " to " + toVersion); + try { + Method updateProc = getClass().getDeclaredMethod("update_" + fromVersion + "_" + toVersion); + updateProc.invoke(this); + } catch (Exception e) { + App.log.log(Level.SEVERE, "Couldn't update account settings", e); } - } catch(Exception e) { - App.log.log(Level.SEVERE, "Couldn't update account settings (DAVdroid will probably crash)!", e); - } + fromVersion = toVersion; + } } - @SuppressWarnings("Recycle") + @SuppressWarnings({ "Recycle", "unused" }) private void update_0_1() throws URISyntaxException { String v0_principalURL = accountManager.getUserData(account, "principal_url"), v0_addressBookPath = accountManager.getUserData(account, "addressbook_path"); @@ -244,7 +220,7 @@ public class AccountSettings { accountManager.setUserData(account, KEY_SETTINGS_VERSION, "1"); } - @SuppressWarnings("Recycle") + @SuppressWarnings({ "Recycle", "unused" }) private void update_1_2() throws ContactsStorageException { /* - KEY_ADDRESSBOOK_URL ("addressbook_url"), - KEY_ADDRESSBOOK_CTAG ("addressbook_ctag"), @@ -277,4 +253,117 @@ public class AccountSettings { accountManager.setUserData(account, KEY_SETTINGS_VERSION, "2"); } + @SuppressWarnings({ "Recycle", "unused" }) + private void update_2_3() { + // Don't show a warning for Android updates anymore + accountManager.setUserData(account, "last_android_version", null); + + ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(context); + try { + SQLiteDatabase db = dbHelper.getWritableDatabase(); + // we have to create the WebDAV Service database only from the old address book, calendar and task list URLs + + // CardDAV: migrate address books + ContentProviderClient client = context.getContentResolver().acquireContentProviderClient(ContactsContract.AUTHORITY); + if (client != null) + try { + LocalAddressBook addrBook = new LocalAddressBook(account, client); + String url = addrBook.getURL(); + if (url != null) { + App.log.fine("Migrating address book " + url); + + // insert CardDAV service + ContentValues values = new ContentValues(); + values.put(Services.ACCOUNT_NAME, account.name); + values.put(Services.SERVICE, Services.SERVICE_CARDDAV); + long service = db.insert(Services._TABLE, null, values); + + // insert address book + values.clear(); + values.put(Collections.SERVICE_ID, service); + values.put(Collections.URL, url); + values.put(Collections.SYNC, 1); + db.insert(Collections._TABLE, null, values); + + // insert home set + HttpUrl homeSet = HttpUrl.parse(url).resolve("../"); + values.clear(); + values.put(HomeSets.SERVICE_ID, service); + values.put(HomeSets.URL, homeSet.toString()); + db.insert(HomeSets._TABLE, null, values); + } + } catch (ContactsStorageException e) { + App.log.log(Level.SEVERE, "Couldn't migrate address book", e); + } finally { + client.release(); + } + + // CalDAV: migrate calendars + task lists + Set collections = new HashSet<>(); + Set homeSets = new HashSet<>(); + + client = context.getContentResolver().acquireContentProviderClient(CalendarContract.AUTHORITY); + if (client != null) + try { + LocalCalendar calendars[] = (LocalCalendar[])LocalCalendar.find(account, client, LocalCalendar.Factory.INSTANCE, null, null); + for (LocalCalendar calendar : calendars) { + String url = calendar.getName(); + App.log.fine("Migrating calendar " + url); + collections.add(url); + homeSets.add(HttpUrl.parse(url).resolve("../")); + } + } catch (CalendarStorageException e) { + App.log.log(Level.SEVERE, "Couldn't migrate calendars", e); + } finally { + client.release(); + } + + TaskProvider provider = LocalTaskList.acquireTaskProvider(context.getContentResolver()); + if (provider != null) + try { + LocalTaskList[] taskLists = (LocalTaskList[])LocalTaskList.find(account, provider, LocalTaskList.Factory.INSTANCE, null, null); + for (LocalTaskList taskList : taskLists) { + String url = taskList.getSyncId(); + App.log.fine("Migrating task list " + url); + collections.add(url); + homeSets.add(HttpUrl.parse(url).resolve("../")); + } + } catch (CalendarStorageException e) { + App.log.log(Level.SEVERE, "Couldn't migrate task lists", e); + } finally { + provider.close(); + } + + if (!collections.isEmpty()) { + // insert CalDAV service + ContentValues values = new ContentValues(); + values.put(Services.ACCOUNT_NAME, account.name); + values.put(Services.SERVICE, Services.SERVICE_CALDAV); + long service = db.insert(Services._TABLE, null, values); + + // insert collections + for (String url : collections) { + values.clear(); + values.put(Collections.SERVICE_ID, service); + values.put(Collections.URL, url); + values.put(Collections.SYNC, 1); + db.insert(Collections._TABLE, null, values); + } + + // insert home sets + for (HttpUrl homeSet : homeSets) { + values.clear(); + values.put(HomeSets.SERVICE_ID, service); + values.put(HomeSets.URL, homeSet.toString()); + db.insert(HomeSets._TABLE, null, values); + } + } + + } finally { + dbHelper.close(); + } + + accountManager.setUserData(account, KEY_SETTINGS_VERSION, "3"); + } + } diff --git a/app/src/main/java/at/bitfire/davdroid/App.java b/app/src/main/java/at/bitfire/davdroid/App.java index ab847bd5..ec370b60 100644 --- a/app/src/main/java/at/bitfire/davdroid/App.java +++ b/app/src/main/java/at/bitfire/davdroid/App.java @@ -8,6 +8,7 @@ package at.bitfire.davdroid; +import android.accounts.Account; import android.app.Application; import android.content.SharedPreferences; import android.util.Log; @@ -16,6 +17,7 @@ import org.apache.commons.lang3.time.DateFormatUtils; import java.io.File; import java.io.IOException; +import java.lang.reflect.Method; import java.util.logging.FileHandler; import java.util.logging.Handler; import java.util.logging.Level; @@ -31,8 +33,8 @@ import okhttp3.internal.tls.OkHostnameVerifier; public class App extends Application implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String - PREF_FILE = "davdroid_preferences", - PREF_LOG_TO_FILE = "log_to_file"; + PREF_FILE = "davdroid_preferences", // preference file name + PREF_LOG_TO_FILE = "log_to_file"; // boolean: external logging enabled @Getter private static MemorizingTrustManager memorizingTrustManager; @@ -60,6 +62,7 @@ public class App extends Application implements SharedPreferences.OnSharedPrefer sslSocketFactoryCompat = new SSLSocketFactoryCompat(memorizingTrustManager); hostnameVerifier = memorizingTrustManager.wrapHostnameVerifier(OkHostnameVerifier.INSTANCE); + // initializer logger reinitLogger(); } diff --git a/app/src/main/java/at/bitfire/davdroid/log/PlainTextFormatter.java b/app/src/main/java/at/bitfire/davdroid/log/PlainTextFormatter.java index 1e50804d..1aceb994 100644 --- a/app/src/main/java/at/bitfire/davdroid/log/PlainTextFormatter.java +++ b/app/src/main/java/at/bitfire/davdroid/log/PlainTextFormatter.java @@ -43,9 +43,11 @@ public class PlainTextFormatter extends Formatter { builder.append(Log.getStackTraceString(r.getThrown())); } - if (r.getParameters() != null) + if (r.getParameters() != null) { + int idx = 1; for (Object param : r.getParameters()) - builder.append("\nPARAMETER " + param); + builder.append("\nPARAMETER #").append(idx).append(" = ").append(param); + } if (!logcat) builder.append("\n"); diff --git a/app/src/main/java/at/bitfire/davdroid/model/CollectionInfo.java b/app/src/main/java/at/bitfire/davdroid/model/CollectionInfo.java index 49e2fac3..06b9d0d9 100644 --- a/app/src/main/java/at/bitfire/davdroid/model/CollectionInfo.java +++ b/app/src/main/java/at/bitfire/davdroid/model/CollectionInfo.java @@ -127,7 +127,7 @@ public class CollectionInfo implements Serializable { info.supportsVEVENT = booleanField(values, Collections.SUPPORTS_VEVENT); info.supportsVTODO = booleanField(values, Collections.SUPPORTS_VTODO); - info.selected = booleanField(values, Collections.SELECTED); + info.selected = booleanField(values, Collections.SYNC); return info; } @@ -146,7 +146,7 @@ public class CollectionInfo implements Serializable { if (supportsVTODO != null) values.put(Collections.SUPPORTS_VTODO, supportsVTODO ? 1 : 0); - values.put(Collections.SELECTED, selected ? 1 : 0); + values.put(Collections.SYNC, selected ? 1 : 0); return values; } diff --git a/app/src/main/java/at/bitfire/davdroid/model/ServiceDB.java b/app/src/main/java/at/bitfire/davdroid/model/ServiceDB.java index 4080d7cf..8c390d3a 100644 --- a/app/src/main/java/at/bitfire/davdroid/model/ServiceDB.java +++ b/app/src/main/java/at/bitfire/davdroid/model/ServiceDB.java @@ -54,12 +54,12 @@ public class ServiceDB { TIME_ZONE = "timezone", SUPPORTS_VEVENT = "supportsVEVENT", SUPPORTS_VTODO = "supportsVTODO", - SELECTED = "selected"; + SYNC = "sync"; public static String[] _COLUMNS = new String[] { ID, SERVICE_ID, URL, DISPLAY_NAME, DESCRIPTION, COLOR, TIME_ZONE, SUPPORTS_VEVENT, SUPPORTS_VTODO, - SELECTED + SYNC }; } @@ -110,7 +110,7 @@ public class ServiceDB { Collections.TIME_ZONE + " TEXt NULL," + Collections.SUPPORTS_VEVENT + " INTEGER NULL," + Collections.SUPPORTS_VTODO + " INTEGER NULL," + - Collections.SELECTED + " INTEGER DEFAULT 0 NOT NULL" + + Collections.SYNC + " INTEGER DEFAULT 0 NOT NULL" + ")"); db.execSQL("CREATE UNIQUE INDEX collections_service_url ON " + Collections._TABLE + "(" + Collections.SERVICE_ID + "," + Collections.URL + ")"); } diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.java b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.java index 124e87a6..538b866e 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.java +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.java @@ -21,6 +21,9 @@ import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.os.IBinder; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.util.List; import at.bitfire.davdroid.App; import at.bitfire.davdroid.model.CollectionInfo; @@ -65,25 +68,30 @@ public class ContactsSyncAdapterService extends Service { // required for dav4android (ServiceLoader) Thread.currentThread().setContextClassLoader(getContext().getClassLoader()); - long service = getService(account); - CollectionInfo remote = remoteAddressBook(service); - - if (remote != null) { - ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, extras, authority, provider, syncResult, remote); - syncManager.performSync(); - } else - App.log.info("No address book collection selected for synchronization"); + Long service = getService(account); + if (service != null) { + CollectionInfo remote = remoteAddressBook(service); + if (remote != null) { + ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, extras, authority, provider, syncResult, remote); + syncManager.performSync(); + } else + App.log.info("No address book collection selected for synchronization"); + } App.log.info("Address book sync complete"); } - private long getService(@NonNull Account account) { + @Nullable + private Long getService(@NonNull Account account) { @Cleanup Cursor c = db.query(ServiceDB.Services._TABLE, new String[] { ServiceDB.Services.ID }, ServiceDB.Services.ACCOUNT_NAME + "=? AND " + ServiceDB.Services.SERVICE + "=?", new String[] { account.name, ServiceDB.Services.SERVICE_CARDDAV }, null, null, null); - c.moveToNext(); - return c.getLong(0); + if (c.moveToNext()) + return c.getLong(0); + else + return null; } + @Nullable private CollectionInfo remoteAddressBook(long service) { @Cleanup Cursor c = db.query(Collections._TABLE, Collections._COLUMNS, Collections.SERVICE_ID + "=? AND selected", new String[] { String.valueOf(service) }, null, null, null); diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java b/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java index 31ceb17f..dfaae9d8 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java @@ -62,7 +62,9 @@ import java.util.LinkedList; import java.util.List; import java.util.logging.Level; +import at.bitfire.davdroid.AccountSettings; import at.bitfire.davdroid.App; +import at.bitfire.davdroid.Constants; import at.bitfire.davdroid.DavService; import at.bitfire.davdroid.R; import at.bitfire.davdroid.model.CollectionInfo; @@ -199,12 +201,12 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu if (list.getChoiceMode() == AbsListView.CHOICE_MODE_SINGLE) { // disable all other collections ContentValues values = new ContentValues(1); - values.put(Collections.SELECTED, 0); + values.put(Collections.SYNC, 0); db.update(Collections._TABLE, values, Collections.SERVICE_ID + "=?", new String[] { String.valueOf(info.serviceID) }); } ContentValues values = new ContentValues(1); - values.put(Collections.SELECTED, nowChecked ? 1 : 0); + values.put(Collections.SYNC, nowChecked ? 1 : 0); db.update(Collections._TABLE, values, Collections.ID + "=?", new String[] { String.valueOf(info.id) }); db.setTransactionSuccessful(); @@ -314,8 +316,11 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu @Override public void onLoaderReset(Loader loader) { - listCardDAV.setAdapter(null); - listCalDAV.setAdapter(null); + if (listCardDAV != null) + listCardDAV.setAdapter(null); + + if (listCalDAV != null) + listCalDAV.setAdapter(null); } @@ -361,6 +366,11 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu @Override public AccountInfo loadInBackground() { + // peek into AccountSettings to call possible 0.9 -> 1.0 migration + // The next line can be removed as soon as migration from 0.9 is not required anymore! + new AccountSettings(getContext(), new Account(accountName, Constants.ACCOUNT_TYPE)); + + // get account info AccountInfo info = new AccountInfo(); try { SQLiteDatabase db = dbHelper.getReadableDatabase(); diff --git a/app/src/main/java/at/bitfire/davdroid/ui/StartupDialogFragment.java b/app/src/main/java/at/bitfire/davdroid/ui/StartupDialogFragment.java index 2fa752cb..ffdec345 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/StartupDialogFragment.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/StartupDialogFragment.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.logging.Level; import at.bitfire.davdroid.App; +import at.bitfire.davdroid.BuildConfig; import at.bitfire.davdroid.Constants; import at.bitfire.davdroid.R; import at.bitfire.davdroid.resource.LocalTaskList; @@ -39,24 +40,28 @@ public class StartupDialogFragment extends DialogFragment { private static final String ARGS_MODE = "mode"; enum Mode { + DEVELOPMENT_VERSION, FDROID_DONATE, GOOGLE_PLAY_ACCOUNTS_REMOVED, OPENTASKS_NOT_INSTALLED } - public static StartupDialogFragment[] getStartupDialogs(Context context) { List dialogs = new LinkedList<>(); - // store-specific information - final String installedFrom = installedFrom(context); - if (installedFrom == null || installedFrom.startsWith("org.fdroid")) - dialogs.add(StartupDialogFragment.instantiate(Mode.FDROID_DONATE)); + if (BuildConfig.VERSION_NAME.contains("-alpha") || BuildConfig.VERSION_NAME.contains("-beta")) + dialogs.add(StartupDialogFragment.instantiate(Mode.DEVELOPMENT_VERSION)); + else { + // store-specific information + final String installedFrom = installedFrom(context); + if (installedFrom == null || installedFrom.startsWith("org.fdroid")) + dialogs.add(StartupDialogFragment.instantiate(Mode.FDROID_DONATE)); - else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && // only on Android <5 - "com.android.vending".equals(installedFrom) && // only when installed from Play Store - App.getPreferences().getBoolean(PREF_HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED, true)) // and only when "Don't show again" hasn't been clicked yet - dialogs.add(StartupDialogFragment.instantiate(Mode.GOOGLE_PLAY_ACCOUNTS_REMOVED)); + else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && // only on Android <5 + "com.android.vending".equals(installedFrom) && // only when installed from Play Store + App.getPreferences().getBoolean(PREF_HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED, true)) // and only when "Don't show again" hasn't been clicked yet + dialogs.add(StartupDialogFragment.instantiate(Mode.GOOGLE_PLAY_ACCOUNTS_REMOVED)); + } // OpenTasks information if (!LocalTaskList.tasksProviderAvailable(context.getContentResolver()) && @@ -82,6 +87,24 @@ public class StartupDialogFragment extends DialogFragment { Mode mode = Mode.valueOf(getArguments().getString(ARGS_MODE)); switch (mode) { + case DEVELOPMENT_VERSION: + return new AlertDialog.Builder(getActivity()) + .setIcon(R.drawable.ic_launcher) + .setTitle(R.string.startup_development_version) + .setMessage(R.string.startup_development_version_message) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + } + }) + .setNeutralButton(R.string.startup_development_version_show_forums, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startActivity(new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("forums/").build())); + } + }) + .create(); + case FDROID_DONATE: return new AlertDialog.Builder(getActivity()) .setIcon(R.drawable.ic_launcher) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 940781c8..ca9b6adf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,6 +19,10 @@ Don\'t show again + DAVdroid Preview Release + This is a development version of DAVdroid. Be aware that things + may not work as expected. Please give us constructive feedback to improve DAVdroid. + Show forums Open-Source Information We\'re happy that you use DAVdroid, which is open-source software (GPLv3). Because developing DAVdroid is hard work and took us thousands of working hours, please consider a donation. Show donation page @@ -147,6 +151,8 @@ Events more than %d days in the past will be ignored Events which are more than this number of days in the past (may be 0) will be ignored. Leave blank to synchronize all events. + DAVdroid version update + Internal settings have been updated. In case of problems, please uninstall DAVdroid and then install it again. Create address book @@ -175,11 +181,6 @@ An I/O error has occurred. Show details - Android version update - Android version updates may have an impact on how DAVdroid works. If there are problems, please delete your DAVdroid accounts and add them again. - Settings have been updated - Internal settings have been updated. If there are problems, please uninstall DAVdroid and then install it again. - Debug info Calendar synchronization failed (%s) diff --git a/dav4android b/dav4android index 5e7334ce..05322829 160000 --- a/dav4android +++ b/dav4android @@ -1 +1 @@ -Subproject commit 5e7334cea2bbaacde7f61b9806c907ba7404753d +Subproject commit 0532282932b71209000e158dd9e6a1725c58b117