diff --git a/app/src/main/java/com/todoroo/astrid/service/StartupService.java b/app/src/main/java/com/todoroo/astrid/service/StartupService.java index 16a76a860..4e11bb0b2 100644 --- a/app/src/main/java/com/todoroo/astrid/service/StartupService.java +++ b/app/src/main/java/com/todoroo/astrid/service/StartupService.java @@ -6,38 +6,19 @@ package com.todoroo.astrid.service; -import static com.google.common.base.Strings.isNullOrEmpty; - import android.content.Context; -import android.os.Environment; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableListMultimap; -import com.google.common.collect.ListMultimap; -import com.google.common.collect.Multimaps; -import com.todoroo.astrid.api.GtasksFilter; import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.tags.TagService; -import java.io.File; -import java.util.List; +import dagger.Lazy; import javax.inject.Inject; import org.tasks.BuildConfig; import org.tasks.LocalBroadcastManager; -import org.tasks.R; import org.tasks.analytics.Tracker; -import org.tasks.analytics.Tracking; -import org.tasks.data.Filter; import org.tasks.data.FilterDao; -import org.tasks.data.GoogleTaskAccount; -import org.tasks.data.GoogleTaskList; import org.tasks.data.GoogleTaskListDao; -import org.tasks.data.Tag; import org.tasks.data.TagDao; -import org.tasks.data.TagData; import org.tasks.data.TagDataDao; -import org.tasks.data.TaskAttachment; import org.tasks.data.TaskAttachmentDao; -import org.tasks.data.UserActivity; import org.tasks.data.UserActivityDao; import org.tasks.injection.ForApplication; import org.tasks.preferences.DefaultFilterProvider; @@ -47,26 +28,10 @@ import timber.log.Timber; public class StartupService { - private static final int V4_8_0 = 380; - private static final int V4_9_5 = 434; - private static final int V5_3_0 = 491; - private static final int V6_0_beta_1 = 522; - private static final int V6_0_beta_2 = 523; - private static final int V6_4 = 546; - private final Database database; private final Preferences preferences; - private final Tracker tracker; - private final TagDataDao tagDataDao; - private final TagService tagService; - private final LocalBroadcastManager localBroadcastManager; private final Context context; - private final TagDao tagDao; - private final FilterDao filterDao; - private final DefaultFilterProvider defaultFilterProvider; - private final GoogleTaskListDao googleTaskListDao; - private final UserActivityDao userActivityDao; - private final TaskAttachmentDao taskAttachmentDao; + private final Lazy upgrader; @Inject public StartupService( @@ -82,20 +47,12 @@ public class StartupService { DefaultFilterProvider defaultFilterProvider, GoogleTaskListDao googleTaskListDao, UserActivityDao userActivityDao, - TaskAttachmentDao taskAttachmentDao) { + TaskAttachmentDao taskAttachmentDao, + Lazy upgrader) { this.database = database; this.preferences = preferences; - this.tracker = tracker; - this.tagDataDao = tagDataDao; - this.tagService = tagService; - this.localBroadcastManager = localBroadcastManager; this.context = context; - this.tagDao = tagDao; - this.filterDao = filterDao; - this.defaultFilterProvider = defaultFilterProvider; - this.googleTaskListDao = googleTaskListDao; - this.userActivityDao = userActivityDao; - this.taskAttachmentDao = taskAttachmentDao; + this.upgrader = upgrader; } /** Called when this application is started up */ @@ -110,158 +67,10 @@ public class StartupService { // invoke upgrade service if (lastVersion != currentVersion) { - upgrade(lastVersion, currentVersion); + upgrader.get().upgrade(lastVersion, currentVersion); preferences.setDefaults(); } BackgroundScheduler.enqueueWork(context); } - - private void upgrade(int from, int to) { - try { - if (from > 0) { - if (from < V4_8_0) { - performMarshmallowMigration(); - } - if (from < V4_9_5) { - removeDuplicateTags(); - } - if (from < V5_3_0) { - migrateFilters(); - } - if (from < V6_0_beta_1) { - migrateDefaultSyncList(); - } - if (from < V6_0_beta_2) { - migrateGoogleTaskAccount(); - } - if (from < V6_4) { - migrateUris(); - } - tracker.reportEvent(Tracking.Events.UPGRADE, Integer.toString(from)); - } - preferences.setCurrentVersion(to); - } finally { - localBroadcastManager.broadcastRefresh(); - } - } - - private void performMarshmallowMigration() { - try { - // preserve pre-marshmallow default backup location - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - if (!preferences.isStringValueSet(R.string.p_backup_dir)) { - String directory = String.format("%s/astrid", Environment.getExternalStorageDirectory()); - File file = new File(directory); - if (file.exists() && file.isDirectory()) { - preferences.setString(R.string.p_backup_dir, directory); - } - } - } - } catch (Exception e) { - tracker.reportException(e); - } - } - - private void removeDuplicateTags() { - ListMultimap tagsByUuid = - Multimaps.index(tagService.getTagList(), TagData::getRemoteId); - for (String uuid : tagsByUuid.keySet()) { - removeDuplicateTagData(tagsByUuid.get(uuid)); - removeDuplicateTagMetadata(uuid); - } - localBroadcastManager.broadcastRefresh(); - } - - private void migrateFilters() { - for (Filter filter : filterDao.getFilters()) { - filter.setSql(migrate(filter.getSql())); - filter.setCriterion(migrate(filter.getCriterion())); - filterDao.update(filter); - } - } - - private void migrateDefaultSyncList() { - String account = preferences.getStringValue("gtasks_user"); - if (isNullOrEmpty(account)) { - return; - } - - String defaultGoogleTaskList = preferences.getStringValue("gtasks_defaultlist"); - if (isNullOrEmpty(defaultGoogleTaskList)) { - // TODO: look up default list - } else { - GoogleTaskList googleTaskList = googleTaskListDao.getByRemoteId(defaultGoogleTaskList); - if (googleTaskList != null) { - defaultFilterProvider.setDefaultRemoteList(new GtasksFilter(googleTaskList)); - } - } - } - - private void migrateGoogleTaskAccount() { - String account = preferences.getStringValue("gtasks_user"); - if (!isNullOrEmpty(account)) { - GoogleTaskAccount googleTaskAccount = new GoogleTaskAccount(); - googleTaskAccount.setAccount(account); - googleTaskListDao.insert(googleTaskAccount); - } - } - - private void migrateUris() { - migrateUriPreference(R.string.p_backup_dir); - migrateUriPreference(R.string.p_attachment_dir); - for (UserActivity userActivity : userActivityDao.getComments()) { - userActivity.convertPictureUri(); - userActivityDao.update(userActivity); - } - for (TaskAttachment attachment : taskAttachmentDao.getAttachments()) { - attachment.convertPathUri(); - taskAttachmentDao.update(attachment); - } - } - - private void migrateUriPreference(int pref) { - String path = preferences.getStringValue(pref); - if (Strings.isNullOrEmpty(path)) { - return; - } - File file = new File(path); - try { - if (file.canWrite()) { - preferences.setUri(pref, file.toURI()); - } else { - preferences.remove(pref); - } - } catch (SecurityException ignored) { - preferences.remove(pref); - } - } - - private String migrate(String input) { - return input - .replaceAll( - "SELECT metadata\\.task AS task FROM metadata INNER JOIN tasks ON \\(\\(metadata\\.task=tasks\\._id\\)\\) WHERE \\(\\(\\(tasks\\.completed=0\\) AND \\(tasks\\.deleted=0\\) AND \\(tasks\\.hideUntil<\\(strftime\\(\\'%s\\',\\'now\\'\\)\\*1000\\)\\)\\) AND \\(metadata\\.key=\\'tags-tag\\'\\) AND \\(metadata\\.value", - "SELECT tags.task AS task FROM tags INNER JOIN tasks ON ((tags.task=tasks._id)) WHERE (((tasks.completed=0) AND (tasks.deleted=0) AND (tasks.hideUntil<(strftime('%s','now')*1000))) AND (tags.name") - .replaceAll( - "SELECT metadata\\.task AS task FROM metadata INNER JOIN tasks ON \\(\\(metadata\\.task=tasks\\._id\\)\\) WHERE \\(\\(\\(tasks\\.completed=0\\) AND \\(tasks\\.deleted=0\\) AND \\(tasks\\.hideUntil<\\(strftime\\(\\'%s\\',\\'now\\'\\)\\*1000\\)\\)\\) AND \\(metadata\\.key=\\'gtasks\\'\\) AND \\(metadata\\.value2", - "SELECT google_tasks.task AS task FROM google_tasks INNER JOIN tasks ON ((google_tasks.task=tasks._id)) WHERE (((tasks.completed=0) AND (tasks.deleted=0) AND (tasks.hideUntil<(strftime('%s','now')*1000))) AND (google_tasks.list_id") - .replaceAll("AND \\(metadata\\.deleted=0\\)", ""); - } - - private void removeDuplicateTagData(List tagData) { - for (int i = 1; i < tagData.size(); i++) { - tagDataDao.delete(tagData.get(i).getId()); - } - } - - private void removeDuplicateTagMetadata(String uuid) { - List metadatas = tagDao.getByTagUid(uuid); - ImmutableListMultimap metadataByTask = Multimaps.index(metadatas, Tag::getTask); - for (Long key : metadataByTask.keySet()) { - ImmutableList tagData = metadataByTask.get(key); - for (int i = 1; i < tagData.size(); i++) { - tagDao.deleteById(tagData.get(i).getId()); - } - } - } } diff --git a/app/src/main/java/com/todoroo/astrid/service/Upgrader.java b/app/src/main/java/com/todoroo/astrid/service/Upgrader.java new file mode 100644 index 000000000..3aaf638b4 --- /dev/null +++ b/app/src/main/java/com/todoroo/astrid/service/Upgrader.java @@ -0,0 +1,230 @@ +package com.todoroo.astrid.service; + +import static com.google.common.base.Strings.isNullOrEmpty; + +import android.os.Environment; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.Multimaps; +import com.todoroo.astrid.api.GtasksFilter; +import com.todoroo.astrid.tags.TagService; +import java.io.File; +import java.util.List; +import javax.inject.Inject; +import org.tasks.LocalBroadcastManager; +import org.tasks.R; +import org.tasks.analytics.Tracker; +import org.tasks.analytics.Tracking; +import org.tasks.data.Filter; +import org.tasks.data.FilterDao; +import org.tasks.data.GoogleTaskAccount; +import org.tasks.data.GoogleTaskList; +import org.tasks.data.GoogleTaskListDao; +import org.tasks.data.Tag; +import org.tasks.data.TagDao; +import org.tasks.data.TagData; +import org.tasks.data.TagDataDao; +import org.tasks.data.TaskAttachment; +import org.tasks.data.TaskAttachmentDao; +import org.tasks.data.UserActivity; +import org.tasks.data.UserActivityDao; +import org.tasks.preferences.DefaultFilterProvider; +import org.tasks.preferences.Preferences; + +public class Upgrader { + + private static final int V4_8_0 = 380; + private static final int V4_9_5 = 434; + private static final int V5_3_0 = 491; + private static final int V6_0_beta_1 = 522; + private static final int V6_0_beta_2 = 523; + private static final int V6_4 = 546; + + private final Preferences preferences; + private final Tracker tracker; + private final TagDataDao tagDataDao; + private final TagService tagService; + private final LocalBroadcastManager localBroadcastManager; + private final TagDao tagDao; + private final FilterDao filterDao; + private final DefaultFilterProvider defaultFilterProvider; + private final GoogleTaskListDao googleTaskListDao; + private final UserActivityDao userActivityDao; + private final TaskAttachmentDao taskAttachmentDao; + + @Inject + public Upgrader( + Preferences preferences, + Tracker tracker, + TagDataDao tagDataDao, + TagService tagService, + LocalBroadcastManager localBroadcastManager, + TagDao tagDao, + FilterDao filterDao, + DefaultFilterProvider defaultFilterProvider, + GoogleTaskListDao googleTaskListDao, + UserActivityDao userActivityDao, + TaskAttachmentDao taskAttachmentDao) { + this.preferences = preferences; + this.tracker = tracker; + this.tagDataDao = tagDataDao; + this.tagService = tagService; + this.localBroadcastManager = localBroadcastManager; + this.tagDao = tagDao; + this.filterDao = filterDao; + this.defaultFilterProvider = defaultFilterProvider; + this.googleTaskListDao = googleTaskListDao; + this.userActivityDao = userActivityDao; + this.taskAttachmentDao = taskAttachmentDao; + } + + public void upgrade(int from, int to) { + try { + if (from > 0) { + if (from < V4_8_0) { + performMarshmallowMigration(); + } + if (from < V4_9_5) { + removeDuplicateTags(); + } + if (from < V5_3_0) { + migrateFilters(); + } + if (from < V6_0_beta_1) { + migrateDefaultSyncList(); + } + if (from < V6_0_beta_2) { + migrateGoogleTaskAccount(); + } + if (from < V6_4) { + migrateUris(); + } + tracker.reportEvent(Tracking.Events.UPGRADE, Integer.toString(from)); + } + preferences.setCurrentVersion(to); + } finally { + localBroadcastManager.broadcastRefresh(); + } + } + + private void performMarshmallowMigration() { + try { + // preserve pre-marshmallow default backup location + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + if (!preferences.isStringValueSet(R.string.p_backup_dir)) { + String directory = String.format("%s/astrid", Environment.getExternalStorageDirectory()); + File file = new File(directory); + if (file.exists() && file.isDirectory()) { + preferences.setString(R.string.p_backup_dir, directory); + } + } + } + } catch (Exception e) { + tracker.reportException(e); + } + } + + private void removeDuplicateTags() { + ListMultimap tagsByUuid = + Multimaps.index(tagService.getTagList(), TagData::getRemoteId); + for (String uuid : tagsByUuid.keySet()) { + removeDuplicateTagData(tagsByUuid.get(uuid)); + removeDuplicateTagMetadata(uuid); + } + localBroadcastManager.broadcastRefresh(); + } + + private void migrateFilters() { + for (Filter filter : filterDao.getFilters()) { + filter.setSql(migrate(filter.getSql())); + filter.setCriterion(migrate(filter.getCriterion())); + filterDao.update(filter); + } + } + + private void migrateDefaultSyncList() { + String account = preferences.getStringValue("gtasks_user"); + if (isNullOrEmpty(account)) { + return; + } + + String defaultGoogleTaskList = preferences.getStringValue("gtasks_defaultlist"); + if (isNullOrEmpty(defaultGoogleTaskList)) { + // TODO: look up default list + } else { + GoogleTaskList googleTaskList = googleTaskListDao.getByRemoteId(defaultGoogleTaskList); + if (googleTaskList != null) { + defaultFilterProvider.setDefaultRemoteList(new GtasksFilter(googleTaskList)); + } + } + } + + private void migrateGoogleTaskAccount() { + String account = preferences.getStringValue("gtasks_user"); + if (!isNullOrEmpty(account)) { + GoogleTaskAccount googleTaskAccount = new GoogleTaskAccount(); + googleTaskAccount.setAccount(account); + googleTaskListDao.insert(googleTaskAccount); + } + } + + private void migrateUris() { + migrateUriPreference(R.string.p_backup_dir); + migrateUriPreference(R.string.p_attachment_dir); + for (UserActivity userActivity : userActivityDao.getComments()) { + userActivity.convertPictureUri(); + userActivityDao.update(userActivity); + } + for (TaskAttachment attachment : taskAttachmentDao.getAttachments()) { + attachment.convertPathUri(); + taskAttachmentDao.update(attachment); + } + } + + private void migrateUriPreference(int pref) { + String path = preferences.getStringValue(pref); + if (Strings.isNullOrEmpty(path)) { + return; + } + File file = new File(path); + try { + if (file.canWrite()) { + preferences.setUri(pref, file.toURI()); + } else { + preferences.remove(pref); + } + } catch (SecurityException ignored) { + preferences.remove(pref); + } + } + + private String migrate(String input) { + return input + .replaceAll( + "SELECT metadata\\.task AS task FROM metadata INNER JOIN tasks ON \\(\\(metadata\\.task=tasks\\._id\\)\\) WHERE \\(\\(\\(tasks\\.completed=0\\) AND \\(tasks\\.deleted=0\\) AND \\(tasks\\.hideUntil<\\(strftime\\(\\'%s\\',\\'now\\'\\)\\*1000\\)\\)\\) AND \\(metadata\\.key=\\'tags-tag\\'\\) AND \\(metadata\\.value", + "SELECT tags.task AS task FROM tags INNER JOIN tasks ON ((tags.task=tasks._id)) WHERE (((tasks.completed=0) AND (tasks.deleted=0) AND (tasks.hideUntil<(strftime('%s','now')*1000))) AND (tags.name") + .replaceAll( + "SELECT metadata\\.task AS task FROM metadata INNER JOIN tasks ON \\(\\(metadata\\.task=tasks\\._id\\)\\) WHERE \\(\\(\\(tasks\\.completed=0\\) AND \\(tasks\\.deleted=0\\) AND \\(tasks\\.hideUntil<\\(strftime\\(\\'%s\\',\\'now\\'\\)\\*1000\\)\\)\\) AND \\(metadata\\.key=\\'gtasks\\'\\) AND \\(metadata\\.value2", + "SELECT google_tasks.task AS task FROM google_tasks INNER JOIN tasks ON ((google_tasks.task=tasks._id)) WHERE (((tasks.completed=0) AND (tasks.deleted=0) AND (tasks.hideUntil<(strftime('%s','now')*1000))) AND (google_tasks.list_id") + .replaceAll("AND \\(metadata\\.deleted=0\\)", ""); + } + + private void removeDuplicateTagData(List tagData) { + for (int i = 1; i < tagData.size(); i++) { + tagDataDao.delete(tagData.get(i).getId()); + } + } + + private void removeDuplicateTagMetadata(String uuid) { + List metadatas = tagDao.getByTagUid(uuid); + ImmutableListMultimap metadataByTask = Multimaps.index(metadatas, Tag::getTask); + for (Long key : metadataByTask.keySet()) { + ImmutableList tagData = metadataByTask.get(key); + for (int i = 1; i < tagData.size(); i++) { + tagDao.deleteById(tagData.get(i).getId()); + } + } + } +}