Backup preferences, backup as a service

pull/14/head
Tim Su 14 years ago
parent 4ad61000a8
commit abb753d2ee

@ -201,6 +201,19 @@
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity android:name="com.todoroo.astrid.backup.BackupPreferences"
android:label="@string/backup_BPr_header">
<intent-filter>
<action android:name="com.todoroo.astrid.SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<receiver android:name="com.todoroo.astrid.backup.BackupStartupReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- notes -->

@ -9,6 +9,8 @@ import android.os.Parcelable;
import com.todoroo.andlib.sql.QueryTemplate;
import edu.umd.cs.findbugs.annotations.CheckForNull;
/**
* A <code>FilterListFilter</code> allows users to display tasks that have
* something in common.
@ -36,6 +38,7 @@ public final class Filter extends FilterListItem {
* <p>
* e.g "Tasks With Notes"
*/
@CheckForNull
public String title;
/**
@ -53,6 +56,7 @@ public final class Filter extends FilterListItem {
* metadata.value = 'b' GROUP BY tasks.id ORDER BY tasks.title"</code>
* </ul>
*/
@CheckForNull
public String sqlQuery;
/**
@ -61,6 +65,7 @@ public final class Filter extends FilterListItem {
* tasks they create should also be tagged 'ABC'. If set to null, no
* additional values will be stored for a task.
*/
@CheckForNull
public ContentValues valuesForNewTasks = null;
/**

@ -5,6 +5,7 @@ package com.todoroo.astrid.api;
import android.os.Parcel;
import android.os.Parcelable;
import edu.umd.cs.findbugs.annotations.CheckForNull;
/**
* A <code>FilterCategory</code> groups common {@link Filter}s and allows
@ -18,6 +19,7 @@ public class FilterCategory extends FilterListItem {
/**
* {@link Filter}s contained by this category
*/
@CheckForNull
public Filter[] children;
/**

@ -7,6 +7,7 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
import edu.umd.cs.findbugs.annotations.CheckForNull;
/**
* Represents an item displayed by Astrid's FilterListActivity
@ -19,17 +20,20 @@ abstract public class FilterListItem implements Parcelable {
/**
* Title of this item displayed on the Filters page
*/
@CheckForNull
public String listingTitle = null;
/**
* Bitmap for icon used on listing page. <code>null</code> => no icon
*/
@CheckForNull
public Bitmap listingIcon = null;
/**
* Context Menu labels. The context menu will be displayed when users
* long-press on this filter list item.
*/
@CheckForNull
public String contextMenuLabels[] = new String[0];
/**
@ -37,6 +41,7 @@ abstract public class FilterListItem implements Parcelable {
* content menu label is invoked. This array must be the same size as
* the contextMenuLabels array.
*/
@CheckForNull
public Intent contextMenuIntents[] = new Intent[0];
// --- parcelable helpers

@ -7,6 +7,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.widget.RemoteViews;
import android.widget.RemoteViews.RemoteView;
import edu.umd.cs.findbugs.annotations.CheckForNull;
/**
* Represents a line of text displayed in the Task List
@ -29,6 +30,7 @@ public final class TaskDecoration implements Parcelable {
/**
* {@link RemoteView} decoration
*/
@CheckForNull
public RemoteViews decoration = null;
/**

@ -0,0 +1,125 @@
package com.todoroo.astrid.backup;
import java.util.Date;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.view.View;
import android.view.ViewGroup.OnHierarchyChangeListener;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.widget.TodorooPreferences;
import com.todoroo.astrid.utility.Preferences;
/**
* Displays synchronization preferences and an action panel so users can
* initiate actions from the menu.
*
* @author timsu
*
*/
public class BackupPreferences extends TodorooPreferences {
static final String PREF_BACKUP_LAST_DATE = "backupDate"; //$NON-NLS-1$
static final String PREF_BACKUP_LAST_ERROR = "backupError"; //$NON-NLS-1$
@Autowired
private DialogUtilities dialogUtilities;
private int statusColor = Color.BLACK;
@Override
public int getPreferenceResource() {
return R.xml.preferences_backup;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getListView().setOnHierarchyChangeListener(new OnHierarchyChangeListener() {
@Override
public void onChildViewRemoved(View parent, View child) {
//
}
@Override
public void onChildViewAdded(View parent, View child) {
View view = findViewById(R.id.status);
if(view != null)
view.setBackgroundColor(statusColor);
}
});
}
@Override
protected void onPause() {
super.onPause();
BackupService.scheduleService(this);
}
/**
*
* @param resource
* if null, updates all resources
*/
@Override
public void updatePreferences(Preference preference, Object value) {
final Resources r = getResources();
// auto
if (r.getString(R.string.backup_BPr_auto_key).equals(
preference.getKey())) {
if (value != null && !(Boolean)value)
preference.setSummary(R.string.backup_BPr_auto_disabled);
else
preference.setSummary(R.string.backup_BPr_auto_enabled);
}
// status
else if (r.getString(R.string.backup_BPr_status_key).equals(preference.getKey())) {
String status;
String subtitle = ""; //$NON-NLS-1$
// last backup was error
final long last = Preferences.getLong(PREF_BACKUP_LAST_DATE, 0);
final String error = Preferences.getStringValue(PREF_BACKUP_LAST_ERROR);
if(error != null) {
status = r.getString(R.string.backup_status_failed);
subtitle = r.getString(R.string.backup_status_failed_subtitle);
statusColor = Color.rgb(100, 0, 0);
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
dialogUtilities.okDialog(BackupPreferences.this, error, null);
return true;
}
});
} else if(last > 0) {
status = r.getString(R.string.backup_status_success,
DateUtilities.getDateWithTimeFormat(BackupPreferences.this).
format(new Date(last)));
statusColor = Color.rgb(0, 100, 0);
preference.setOnPreferenceClickListener(null);
} else {
status = r.getString(R.string.backup_status_never);
statusColor = Color.rgb(0, 0, 100);
preference.setOnPreferenceClickListener(null);
}
preference.setTitle(status);
preference.setSummary(subtitle);
View view = findViewById(R.id.status);
if(view != null)
view.setBackgroundColor(statusColor);
}
}
}

@ -13,11 +13,16 @@ import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.timsu.astrid.R;
import com.todoroo.astrid.utility.Preferences;
/**
* Inspired heavily by SynchronizationService
*/
public class BackupService extends Service {
// --- constants for backup
/**
* when after phone starts to start first back up
*/
@ -27,13 +32,10 @@ public class BackupService extends Service {
* how often to back up
*/
private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_DAY;
public static final String BACKUP_ACTION = "backup";
public static final String BACKUP_FILE_NAME_REGEX = "auto\\.[-\\d]+\\.xml";
public static final String BACKUP_ACTION = "backup"; //$NON-NLS-1$
public static final String BACKUP_FILE_NAME_REGEX = "auto\\.[-\\d]+\\.xml"; //$NON-NLS-1$
private static final int DAYS_TO_KEEP_BACKUP = 7;
static final String PREF_BACKUP_LAST_ERROR = "backupError";
static final String PREF_BACKUP_LAST_DATE = "backupDate";
@Override
public IBinder onBind(Intent intent) {
return null;
@ -48,66 +50,56 @@ public class BackupService extends Service {
/**
* Test hook for backup
* @param ctx
* @param context
*/
public void testBackup(Context ctx) {
startBackup(ctx);
public void testBackup(Context context) {
startBackup(context);
}
private void startBackup(Context ctx) {
/*if (ctx == null || ctx.getResources() == null) {
private void startBackup(Context context) {
if (context == null || context.getResources() == null) {
return;
}
try {
if (!Preferences.isBackupEnabled(ctx)) {
if (!Preferences.getBoolean(R.string.backup_BPr_auto_key, true)) {
return;
}
try {
deleteOldBackups();
} catch (Exception e) {
Log.e("error-deleting", "Error deleting old backups: " + e);
Log.e("error-deleting", "Error deleting old backups", e); //$NON-NLS-1$ //$NON-NLS-2$
}
TasksXmlExporter exporter = new TasksXmlExporter(true);
exporter.setContext(ctx);
exporter.exportTasks(backupDirectorySetting.getBackupDirectory());
Preferences.setBackupSummary(ctx,
ctx.getString(R.string.BPr_backup_desc_success,
BackupDateUtilities.getFormattedDate(ctx, new Date())));
TasksXmlExporter.exportTasks(context, true, null);
} catch (Exception e) {
// unable to backup.
if (e == null || e.getMessage() == null) {
Preferences.setBackupSummary(ctx,
ctx.getString(R.string.BPr_backup_desc_failure_null));
} else {
Preferences.setBackupSummary(ctx,
ctx.getString(R.string.BPr_backup_desc_failure,
e.toString()));
}
}*/
Log.e("error-backup", "Error starting backups", e); //$NON-NLS-1$ //$NON-NLS-2$
Preferences.setString(BackupPreferences.PREF_BACKUP_LAST_ERROR, e.toString());
}
}
public static void scheduleService(Context ctx) {
/*AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(ctx, 0,
createAlarmIntent(ctx), PendingIntent.FLAG_UPDATE_CURRENT);
public static void scheduleService(Context context) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pendingIntent);
if (!Preferences.isBackupEnabled(ctx)) {
if (!Preferences.getBoolean(R.string.backup_BPr_auto_key, true)) {
return;
}
am.setInexactRepeating(AlarmManager.RTC, System.currentTimeMillis() + BACKUP_OFFSET,
BACKUP_INTERVAL, pendingIntent);*/
BACKUP_INTERVAL, pendingIntent);
}
public static void unscheduleService(Context ctx) {
AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(ctx, 0,
createAlarmIntent(ctx), PendingIntent.FLAG_UPDATE_CURRENT);
public static void unscheduleService(Context context) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pendingIntent);
}
private static Intent createAlarmIntent(Context ctx) {
Intent intent = new Intent(ctx, BackupService.class);
private static Intent createAlarmIntent(Context context) {
Intent intent = new Intent(context, BackupService.class);
intent.setAction(BACKUP_ACTION);
return intent;
}

@ -0,0 +1,26 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.backup;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.astrid.service.AstridDependencyInjector;
public class BackupStartupReceiver extends BroadcastReceiver {
static {
AstridDependencyInjector.initialize();
}
@Override
/** Called when device is restarted */
public void onReceive(final Context context, Intent intent) {
ContextManager.setContext(context);
BackupService.scheduleService(context);
}
}

@ -91,8 +91,9 @@ public class TasksXmlExporter {
String output = setupFile(BackupConstants.getExportDirectory(),
isService);
doTasksExport(output);
Preferences.setLong(BackupService.PREF_BACKUP_LAST_DATE,
Preferences.setLong(BackupPreferences.PREF_BACKUP_LAST_DATE,
DateUtilities.now());
Preferences.setString(BackupPreferences.PREF_BACKUP_LAST_ERROR, null);
if (!isService)
displayToast(output);
@ -102,7 +103,7 @@ public class TasksXmlExporter {
context.getString(R.string.backup_TXI_error), e);
else {
exceptionService.reportError("background-backup", e); //$NON-NLS-1$
Preferences.setString(BackupService.PREF_BACKUP_LAST_ERROR, e.toString());
Preferences.setString(BackupPreferences.PREF_BACKUP_LAST_ERROR, e.toString());
}
} finally {
if(runAfterExport != null)

@ -154,6 +154,8 @@ public final class LocaleEditAlerts extends ExpandableListActivity {
adapter.setSelection(item);
} else if(item instanceof FilterCategory) {
Filter[] filters = ((FilterCategory)item).children;
if(filters == null)
return;
for(Filter filter : filters)
if(finalSelection.equals(filter.sqlQuery)) {
adapter.setSelection(filter);
@ -243,7 +245,7 @@ public final class LocaleEditAlerts extends ExpandableListActivity {
/*
* This is the blurb concisely describing what your setting's state is. This is simply used for display in the UI.
*/
if (filterItem.title.length() > com.twofortyfouram.Intent.MAXIMUM_BLURB_LENGTH)
if (filterItem.title != null && filterItem.title.length() > com.twofortyfouram.Intent.MAXIMUM_BLURB_LENGTH)
returnIntent.putExtra(com.twofortyfouram.Intent.EXTRA_STRING_BLURB, filterItem.title.substring(0, com.twofortyfouram.Intent.MAXIMUM_BLURB_LENGTH));
else
returnIntent.putExtra(com.twofortyfouram.Intent.EXTRA_STRING_BLURB, filterItem.title);

@ -20,6 +20,37 @@
<!-- backup success message (%s -> date) -->
<string name="backup_BPr_backup_desc_success">Latest backup was on %s</string>
<!-- ================================================= BackupPreferences == -->
<!-- Preferences Title -->
<string name="backup_BPr_header">Backups</string>
<!-- Status Group Label -->
<string name="backup_BPr_group_status">Status</string>
<!-- Preference Key (do not translate) -->
<string name="backup_BPr_status_key">backup_status</string>
<!-- Status: success (%s -> last date) -->
<string name="backup_status_success">Latest: %s</string>
<!-- Status: error -->
<string name="backup_status_failed">Last Backup Failed</string>
<!-- Status: error subtitle -->
<string name="backup_status_failed_subtitle">(tap to show error)</string>
<!-- Status: never backed up -->
<string name="backup_status_never">Never Backed Up!</string>
<!-- Options Group Label -->
<string name="backup_BPr_group_options">Options</string>
<!-- Synchronization Interval Title -->
<string name="backup_BPr_auto_title">Automatic Backups</string>
<!-- Synchronization Interval Description (when disabled) -->
<string name="backup_BPr_auto_disabled">Automatic Backups Disabled</string>
<!-- Synchronization Interval Description (when enabled) -->
<string name="backup_BPr_auto_enabled">Backup will occur daily</string>
<!-- Preference Key (do not translate) -->
<string name="backup_BPr_auto_key">backup</string>
<!-- ================================================= BackupActivity == -->
<!-- backup activity label -->

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/backup_BPr_group_status">
<Preference
android:layout="@layout/status_preference"
android:key="@string/backup_BPr_status_key"
android:textSize="24sp"
android:gravity="center"/>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/backup_BPr_group_options">
<CheckBoxPreference
android:key="@string/backup_BPr_auto_key"
android:title="@string/backup_BPr_auto_title"
android:defaultValue="true" />
</PreferenceCategory>
</PreferenceScreen>

@ -6,7 +6,7 @@
android:title="@string/rmilk_MPr_group_status">
<Preference
android:layout="@layout/rmilk_status_preference"
android:layout="@layout/status_preference"
android:key="@string/rmilk_MPr_status_key"
android:textSize="24sp"
android:gravity="center"/>

@ -336,6 +336,8 @@ public class FilterListActivity extends ExpandableListActivity {
FrameLayout frameLayout = new FrameLayout(this);
frameLayout.setPadding(10, 0, 10, 0);
final EditText editText = new EditText(this);
if(filter.listingTitle == null)
filter.listingTitle = ""; //$NON-NLS-1$
editText.setText(filter.listingTitle.
replaceAll("\\(\\d+\\)$", "").trim()); //$NON-NLS-1$ //$NON-NLS-2$
frameLayout.addView(editText, new FrameLayout.LayoutParams(

@ -596,6 +596,8 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
}
// create a custom cursor
if(filter.sqlQuery == null)
filter.sqlQuery = "";
if(!filter.sqlQuery.contains("WHERE"))
filter.sqlQuery += " WHERE " + TaskCriteria.byId(withCustomId);
else

@ -110,7 +110,7 @@ public class FilterAdapter extends BaseExpandableListAdapter {
public Object getChild(int groupPosition, int childPosition) {
FilterListItem item = items.get(groupPosition);
if(!(item instanceof FilterCategory))
if(!(item instanceof FilterCategory) || ((FilterCategory)item).children == null)
return null;
return ((FilterCategory)item).children[childPosition];

Loading…
Cancel
Save