diff --git a/astrid/common-src/com/todoroo/andlib/data/AbstractDatabase.java b/astrid/common-src/com/todoroo/andlib/data/AbstractDatabase.java index 468c1ff46..e3525a0ca 100644 --- a/astrid/common-src/com/todoroo/andlib/data/AbstractDatabase.java +++ b/astrid/common-src/com/todoroo/andlib/data/AbstractDatabase.java @@ -9,8 +9,8 @@ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; import com.todoroo.andlib.data.Property.PropertyVisitor; diff --git a/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java b/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java index 75cc4c9e9..8ab1674a0 100644 --- a/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java +++ b/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java @@ -8,6 +8,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; +import java.util.Arrays; +import java.util.Comparator; import java.util.Map.Entry; import android.app.Activity; @@ -23,8 +25,8 @@ import android.text.InputType; import android.util.Log; import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup; import android.view.View.OnTouchListener; +import android.view.ViewGroup; import android.widget.TextView; import com.todoroo.andlib.service.Autowired; @@ -357,6 +359,18 @@ public class AndroidUtilities { } } + /** + * Sort files by date so the newest file is on top + * @param files + */ + public static void sortFilesByDateDesc(File[] files) { + Arrays.sort(files, new Comparator() { + public int compare(File o1, File o2) { + return Long.valueOf(o2.lastModified()).compareTo(Long.valueOf(o1.lastModified())); + } + }); + } + /** * Sleep, ignoring interruption * @param l diff --git a/astrid/plugin-src/com/todoroo/astrid/backup/FilePickerBuilder.java b/astrid/plugin-src/com/todoroo/astrid/backup/FilePickerBuilder.java index fe3a72f26..582e5b948 100644 --- a/astrid/plugin-src/com/todoroo/astrid/backup/FilePickerBuilder.java +++ b/astrid/plugin-src/com/todoroo/astrid/backup/FilePickerBuilder.java @@ -2,9 +2,6 @@ package com.todoroo.astrid.backup; import java.io.File; import java.io.FilenameFilter; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; import android.app.AlertDialog; import android.content.Context; @@ -12,6 +9,7 @@ import android.content.DialogInterface; import android.util.Log; import com.timsu.astrid.R; +import com.todoroo.andlib.utility.AndroidUtilities; @SuppressWarnings("nls") public class FilePickerBuilder extends AlertDialog.Builder implements DialogInterface.OnClickListener { @@ -46,11 +44,14 @@ public class FilePickerBuilder extends AlertDialog.Builder implements DialogInte private void setPath(File path) { if (path != null && path.exists()) { this.path = path.getAbsolutePath(); - // Reverse the order of the file list so newest time-stamped file is first. - List fileList = Arrays.asList(path.list(filter)); - Collections.sort(fileList); - Collections.reverse(fileList); - files = (String[]) fileList.toArray(); + + File[] filesAsFile = path.listFiles(filter); + AndroidUtilities.sortFilesByDateDesc(filesAsFile); + + files = new String[filesAsFile.length]; + for(int i = 0; i < files.length; i++) + files[i] = filesAsFile[i].getName(); + setItems(files, this); } else { Log.e("FilePicker", "Cannot access sdcard."); diff --git a/astrid/plugin-src/com/todoroo/astrid/backup/TasksXmlExporter.java b/astrid/plugin-src/com/todoroo/astrid/backup/TasksXmlExporter.java index 1829d1c4f..e9722312e 100644 --- a/astrid/plugin-src/com/todoroo/astrid/backup/TasksXmlExporter.java +++ b/astrid/plugin-src/com/todoroo/astrid/backup/TasksXmlExporter.java @@ -50,7 +50,7 @@ public class TasksXmlExporter { private static final int FORMAT = 2; private final Context context; - private int exportCount; + private int exportCount = 0; private XmlSerializer xml; private final TaskService taskService = PluginServices.getTaskService(); private final MetadataService metadataService = PluginServices.getMetadataService(); @@ -93,7 +93,11 @@ public class TasksXmlExporter { try { String output = setupFile(BackupConstants.getExportDirectory(), isService); - doTasksExport(output); + int tasks = taskService.countTasks(); + + if(tasks > 0) + doTasksExport(output); + Preferences.setLong(BackupPreferences.PREF_BACKUP_LAST_DATE, DateUtilities.now()); Preferences.setString(BackupPreferences.PREF_BACKUP_LAST_ERROR, null); @@ -270,12 +274,17 @@ public class TasksXmlExporter { handler.post(new Runnable() { @Override public void run() { - CharSequence text = String.format(context.getString(R.string.export_toast), - context.getResources().getQuantityString(R.plurals.Ntasks, exportCount, - exportCount), outputFile); - Toast.makeText(context, text, Toast.LENGTH_LONG).show(); - if(progressDialog.isShowing()) - progressDialog.dismiss(); + + if(exportCount == 0) + Toast.makeText(context, context.getString(R.string.export_toast_no_tasks), Toast.LENGTH_LONG).show(); + else { + CharSequence text = String.format(context.getString(R.string.export_toast), + context.getResources().getQuantityString(R.plurals.Ntasks, exportCount, + exportCount), outputFile); + Toast.makeText(context, text, Toast.LENGTH_LONG).show(); + if(progressDialog.isShowing()) + progressDialog.dismiss(); + } } }); } diff --git a/astrid/plugin-src/com/todoroo/astrid/backup/TasksXmlImporter.java b/astrid/plugin-src/com/todoroo/astrid/backup/TasksXmlImporter.java index f25e10811..1ec6a5cb2 100644 --- a/astrid/plugin-src/com/todoroo/astrid/backup/TasksXmlImporter.java +++ b/astrid/plugin-src/com/todoroo/astrid/backup/TasksXmlImporter.java @@ -42,6 +42,7 @@ import com.todoroo.astrid.rmilk.data.MilkTask; import com.todoroo.astrid.service.MetadataService; import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.tags.TagService; +import com.todoroo.astrid.utility.Flags; public class TasksXmlImporter { @@ -146,6 +147,7 @@ public class TasksXmlImporter { } } } finally { + Flags.set(Flags.REFRESH); handler.post(new Runnable() { @Override public void run() { diff --git a/astrid/res/values/strings-backup.xml b/astrid/res/values/strings-backup.xml index c3bf1b728..8e5dc967d 100644 --- a/astrid/res/values/strings-backup.xml +++ b/astrid/res/values/strings-backup.xml @@ -56,6 +56,8 @@ Import Error Backed Up %s to %s. + + No Tasks to Export. Exporting... diff --git a/astrid/res/values/strings-core.xml b/astrid/res/values/strings-core.xml index 86f1936a9..5f26a33d3 100644 --- a/astrid/res/values/strings-core.xml +++ b/astrid/res/values/strings-core.xml @@ -162,6 +162,9 @@ Sort & Hidden + + Sync Now! + Settings diff --git a/astrid/src/com/todoroo/astrid/service/StartupService.java b/astrid/src/com/todoroo/astrid/service/StartupService.java index e621ddcef..3a1fcc57a 100644 --- a/astrid/src/com/todoroo/astrid/service/StartupService.java +++ b/astrid/src/com/todoroo/astrid/service/StartupService.java @@ -1,5 +1,6 @@ package com.todoroo.astrid.service; +import java.io.File; import java.util.List; import android.Manifest; @@ -14,14 +15,18 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.util.Log; +import com.flurry.android.FlurryAgent; import com.timsu.astrid.R; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.service.ExceptionService; import com.todoroo.andlib.service.ExceptionService.TodorooUncaughtExceptionHandler; +import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.astrid.alarms.AlarmService; +import com.todoroo.astrid.backup.BackupConstants; import com.todoroo.astrid.backup.BackupService; +import com.todoroo.astrid.backup.TasksXmlImporter; import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.producteev.ProducteevBackgroundService; import com.todoroo.astrid.producteev.ProducteevUtilities; @@ -59,6 +64,9 @@ public class StartupService { @Autowired TaskService taskService; + @Autowired + MetadataService metadataService; + @Autowired Database database; @@ -93,6 +101,8 @@ public class StartupService { Log.i("astrid", "Astrid Startup. " + latestSetVersion + //$NON-NLS-1$ //$NON-NLS-2$ " => " + version); //$NON-NLS-1$ + databaseRestoreIfEmpty(context); + // invoke upgrade service boolean justUpgraded = latestSetVersion != version; if(justUpgraded && version > 0) { @@ -105,6 +115,7 @@ public class StartupService { // perform startup activities in a background thread new Thread(new Runnable() { public void run() { + // start widget updating alarm AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, UpdateService.class); @@ -144,8 +155,35 @@ public class StartupService { hasStartedUp = true; } + /** + * If database exists, no tasks but metadata, and a backup file exists, restore it + */ + private void databaseRestoreIfEmpty(Context context) { + try { + if(Preferences.getCurrentVersion() > 135 && !context.getDatabasePath(database.getName()).exists()) { + // we didn't have a database! restore latest file + File directory = BackupConstants.getExportDirectory(); + if(!directory.exists()) + return; + File[] children = directory.listFiles(); + AndroidUtilities.sortFilesByDateDesc(children); + if(children.length > 0) { + FlurryAgent.onStartSession(context, Constants.FLURRY_KEY); + TasksXmlImporter.importTasks(context, children[0].getAbsolutePath(), null); + FlurryAgent.onEvent("lost-tasks-restored"); //$NON-NLS-1$ + } + } + } catch (Exception e) { + Log.w("astrid-database-restore", e); //$NON-NLS-1$ + } + } + private static final String P_TASK_KILLER_HELP = "taskkiller"; //$NON-NLS-1$ + /** + * Show task killer helper + * @param context + */ private static void showTaskKillerHelp(final Context context) { if(!Preferences.getBoolean(P_TASK_KILLER_HELP, false)) return; diff --git a/astrid/src/com/todoroo/astrid/service/TaskService.java b/astrid/src/com/todoroo/astrid/service/TaskService.java index 525f26174..da61e96a2 100644 --- a/astrid/src/com/todoroo/astrid/service/TaskService.java +++ b/astrid/src/com/todoroo/astrid/service/TaskService.java @@ -256,6 +256,21 @@ public class TaskService { } } + /** + * Count tasks overall + * @param filter + * @return + */ + public int countTasks() { + TodorooCursor cursor = query(Query.select(Task.ID)); + try { + return cursor.getCount(); + } finally { + cursor.close(); + } + } + + /** count tasks in a given filter */ public int countTasks(Filter filter) { String queryTemplate = PermaSql.replacePlaceholders(filter.sqlQuery); TodorooCursor cursor = query(Query.select(Task.ID).withQueryTemplate(