Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f824386d authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Improve error/account settings notifications

* move address book settings from account user data to ContactsContract.SyncState
* remove "VCard4 capable?" setting (as it's detected at every sync)
* show user notification when updating settings version or when Android version was increased
* improve stack trace in DebugInfoActivity
* get rid of Guava (use Commons again)
parent 68ee33b2
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -17,8 +17,8 @@ android {
        minSdkVersion 14
        targetSdkVersion 23

        versionCode 75
        versionName "0.9-alpha3"
        versionCode 76
        versionName "0.9-alpha4"

        buildConfigField "java.util.Date", "buildTime", "new java.util.Date()"
    }
@@ -49,8 +49,8 @@ configurations.all {
}

dependencies {
    compile 'com.google.guava:guava:18.0'
    compile 'dnsjava:dnsjava:2.1.7'
    compile 'org.apache.commons:commons-lang3:3.4'
    provided 'org.projectlombok:lombok:1.16.6'
    compile('org.slf4j:slf4j-android:1.7.12')

+10 −2
Original line number Diff line number Diff line
@@ -14,8 +14,16 @@ public class Constants {
	public static final String
		ACCOUNT_TYPE = "bitfire.at.davdroid",
		WEB_URL_MAIN = "https://davdroid.bitfire.at/?pk_campaign=davdroid-app",
		WEB_URL_HELP = "https://davdroid.bitfire.at/configuration?pk_campaign=davdroid-app",
		WEB_URL_VIEW_LOGS = "https://github.com/bitfireAT/davdroid/wiki/How-to-view-the-logs";
		WEB_URL_HELP = "https://davdroid.bitfire.at/configuration?pk_campaign=davdroid-app";

    public static final Logger log = LoggerFactory.getLogger("davdroid");

    // notification IDs
    public final static int
            NOTIFICATION_ANDROID_VERSION_UPDATED = 0,
            NOTIFICATION_ACCOUNT_SETTINGS_UPDATED = 1,
            NOTIFICATION_CONTACTS_SYNC = 10,
            NOTIFICATION_CALENDAR_SYNC = 11,
            NOTIFICATION_TASK_SYNC = 12;

}
+25 −6
Original line number Diff line number Diff line
@@ -26,7 +26,9 @@ import lombok.Synchronized;

public class LocalAddressBook extends AndroidAddressBook implements LocalCollection {

    protected static final String SYNC_STATE_CTAG = "ctag";
    protected static final String
            SYNC_STATE_CTAG = "ctag",
            SYNC_STATE_URL = "url";

    private Bundle syncState = new Bundle();

@@ -80,6 +82,27 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect
            syncState.clear();
    }

    protected void writeSyncState() throws ContactsStorageException {
        @Cleanup("recycle") Parcel parcel = Parcel.obtain();
        parcel.writeBundle(syncState);
        setSyncState(parcel.marshall());
    }

    public String getURL() throws ContactsStorageException {
        synchronized (syncState) {
            readSyncState();
            return syncState.getString(SYNC_STATE_URL);
        }
    }

    public void setURL(String url) throws ContactsStorageException {
        synchronized (syncState) {
            readSyncState();
            syncState.putString(SYNC_STATE_URL, url);
            writeSyncState();
        }
    }

    @Override
    public String getCTag() throws ContactsStorageException {
        synchronized (syncState) {
@@ -93,11 +116,7 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect
        synchronized (syncState) {
            readSyncState();
            syncState.putString(SYNC_STATE_CTAG, cTag);

            // write sync state bundle
            @Cleanup("recycle") Parcel parcel = Parcel.obtain();
            parcel.writeBundle(syncState);
            setSyncState(parcel.marshall());
            writeSyncState();
        }
    }

+4 −5
Original line number Diff line number Diff line
@@ -24,11 +24,10 @@ import android.provider.CalendarContract.Events;
import android.provider.CalendarContract.Reminders;
import android.text.TextUtils;

import com.google.common.base.Joiner;

import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.model.component.VTimeZone;

import org.apache.commons.lang3.StringUtils;

import java.io.FileNotFoundException;
import java.util.LinkedList;
import java.util.List;
@@ -96,8 +95,8 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection {
        }
        values.put(Calendars.ALLOWED_REMINDERS, Reminders.METHOD_ALERT);
        if (Build.VERSION.SDK_INT >= 15) {
            values.put(Calendars.ALLOWED_AVAILABILITY, Joiner.on(",").join(Reminders.AVAILABILITY_TENTATIVE, Reminders.AVAILABILITY_FREE, Reminders.AVAILABILITY_BUSY));
            values.put(Calendars.ALLOWED_ATTENDEE_TYPES, Joiner.on(",").join(CalendarContract.Attendees.TYPE_OPTIONAL, CalendarContract.Attendees.TYPE_REQUIRED, CalendarContract.Attendees.TYPE_RESOURCE));
            values.put(Calendars.ALLOWED_AVAILABILITY, StringUtils.join(new int[] { Reminders.AVAILABILITY_TENTATIVE, Reminders.AVAILABILITY_FREE, Reminders.AVAILABILITY_BUSY }, ","));
            values.put(Calendars.ALLOWED_ATTENDEE_TYPES, StringUtils.join(new int[] { CalendarContract.Attendees.TYPE_OPTIONAL, CalendarContract.Attendees.TYPE_REQUIRED, CalendarContract.Attendees.TYPE_RESOURCE }, ", "));
        }
        return create(account, provider, values);
    }
+104 −64
Original line number Diff line number Diff line
@@ -9,6 +9,9 @@ package at.bitfire.davdroid.syncadapter;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -16,32 +19,34 @@ import android.content.Context;
import android.content.PeriodicSync;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.provider.CalendarContract.Calendars;
import android.util.Log;
import android.provider.ContactsContract;
import android.text.TextUtils;

import org.apache.commons.lang3.math.NumberUtils;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;

import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.resource.LocalAddressBook;
import at.bitfire.davdroid.resource.ServerInfo;
import ezvcard.VCardVersion;
import at.bitfire.vcard4android.ContactsStorageException;
import lombok.Cleanup;

public class AccountSettings {
	private final static String TAG = "davdroid.AccountSettings";
	
	private final static int CURRENT_VERSION = 1;
	private final static int CURRENT_VERSION = 2;
	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",
		KEY_ADDRESSBOOK_VCARD_VERSION = "addressbook_vcard_version";
        KEY_LAST_ANDROID_VERSION = "last_android_version";

	public final static long SYNC_INTERVAL_MANUALLY = -1;

@@ -62,9 +67,42 @@ public class AccountSettings {
				version = Integer.parseInt(accountManager.getUserData(account, KEY_SETTINGS_VERSION));
			} catch(NumberFormatException e) {
			}
			if (version < CURRENT_VERSION)
            Constants.log.info("AccountSettings version: v" + version + ", should be: " + 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));
                update(version);
            }

            // check whether Android version has changed
            int lastAndroidVersion = NumberUtils.toInt(accountManager.getUserData(account, KEY_LAST_ANDROID_VERSION));
            if (lastAndroidVersion < 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));
            }
		}
	}

    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());
    }
	
	
@@ -73,11 +111,6 @@ public class AccountSettings {
		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());
				break;
			}
		return bundle;
	}
	
@@ -124,65 +157,44 @@ public class AccountSettings {
	}

	
	// 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);
	}
	
	public VCardVersion getAddressBookVCardVersion() {
		VCardVersion version = VCardVersion.V3_0;
		String versionStr = accountManager.getUserData(account, KEY_ADDRESSBOOK_VCARD_VERSION);
		if (versionStr != null)
			version = VCardVersion.valueOfByStr(versionStr);
		return version;
	}

	public void setAddressBookVCardVersion(VCardVersion version) {
		accountManager.setUserData(account, KEY_ADDRESSBOOK_VCARD_VERSION, version.getVersion());
	}
	
	
	// 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);
		for (int toVersion = fromVersion + 1; toVersion <= CURRENT_VERSION; toVersion++)
            updateTo(toVersion);
	}
	
	private void update(int fromVersion, int toVersion) {
		Log.i(TAG, "Updating account settings from v" + fromVersion + " to " + toVersion);
	private void updateTo(int toVersion) {
        final int fromVersion = toVersion - 1;
        Constants.log.info("Updating account settings from v" + fromVersion + " to " + toVersion);
		try {
			if (fromVersion == 0 && toVersion == 1)
			switch (toVersion) {
                case 1:
                    update_0_1();
			else
				Log.wtf(TAG, "Don't know how to update settings from v" + fromVersion + " to v" + toVersion);
                    break;
                case 2:
                    update_1_2();
                    break;
                default:
                    Constants.log.error("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);
            Constants.log.error("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);
        Constants.log.debug("Old principal URL = " + v0_principalURL);
        Constants.log.debug("Old address book path = " + v0_addressBookPath);
		
		URI principalURI = new URI(v0_principalURL);

		// update address book
		if (v0_addressBookPath != null) {
			String addressBookURL = principalURI.resolve(v0_addressBookPath).toASCIIString();
			Log.d(TAG, "New address book URL = " + addressBookURL);
            Constants.log.debug("New address book URL = " + addressBookURL);
			accountManager.setUserData(account, "addressbook_url", addressBookURL);
		}
		
@@ -197,7 +209,7 @@ public class AccountSettings {
			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);
            Constants.log.debug("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)
@@ -205,14 +217,42 @@ public class AccountSettings {
			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");
                Constants.log.debug("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");
	}

    private void update_1_2() throws ContactsStorageException {
        /* - KEY_ADDRESSBOOK_URL ("addressbook_url"),,
           - KEY_ADDRESSBOOK_CTAG ("addressbook_ctag"),
           - KEY_ADDRESSBOOK_VCARD_VERSION ("addressbook_vcard_version") are not used anymore (now stored in ContactsContract.SyncState)
           - KEY_LAST_ANDROID_VERSION ("last_android_version") has been added
        */

        // move previous address book info to ContactsContract.SyncState
        @Cleanup("release") ContentProviderClient provider = context.getContentResolver().acquireContentProviderClient(ContactsContract.AUTHORITY);
        if (provider != null) {
            LocalAddressBook addr = new LocalAddressBook(account, provider);

            String url = accountManager.getUserData(account, "addressbook_url");
            if (!TextUtils.isEmpty(url))
                addr.setURL(url);
            accountManager.setUserData(account, "addressbook_url", null);

            String cTag = accountManager.getUserData(account, "addressbook_ctag");
            if (!TextUtils.isEmpty(cTag))
                addr.setCTag(cTag);
            accountManager.setUserData(account, "addressbook_ctag", null);
        }

        // store current Android version
        accountManager.setUserData(account, KEY_LAST_ANDROID_VERSION, String.valueOf(Build.VERSION.SDK_INT));

        accountManager.setUserData(account, KEY_SETTINGS_VERSION, "2");
    }

}
Loading