Merge branch 'dev' of github.com:todoroo/astrid into dev

pull/14/head
Tim Su 14 years ago
commit 50d2b56a3f

@ -100,32 +100,11 @@
<data android:mimeType="vnd.android.cursor.item/task" />
</intent-filter>
</activity>
<!-- Activity that lets users log in to sync providers -->
<activity android:name=".activities.SyncLoginActivity"/>
<!-- Activity that lets users edit app preferences -->
<activity android:name="com.todoroo.astrid.activity.EditPreferences"/>
<!-- Activity that lets users edit synchronization preferences -->
<activity android:name=".activities.SyncPreferences"/>
<!-- Activity that Locale displays to edit tag notification settings -->
<activity android:name=".activities.LocaleEditAlerts"
android:label="@string/locale_edit_alerts_title"
android:icon="@drawable/icon_32"
android:exported="true" >
<intent-filter>
<action android:name="com.twofortyfouram.locale.intent.action.EDIT_SETTING" />
</intent-filter>
</activity>
<!-- ======================================================= Receivers = -->
<receiver android:name="com.todoroo.astrid.reminders.Notifications" />
<receiver android:name=".utilities.LocaleReceiver">
<intent-filter>
<action android:name="com.timsu.astrid.action.LOCALE_ALERT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.widget.TasksWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -137,7 +116,6 @@
<!-- ======================================================== Services = -->
<service android:name="com.todoroo.astrid.widget.TasksWidget$UpdateService" />
<service android:name=".utilities.BackupService"/>
<!-- ======================================================= Providers = -->
@ -204,10 +182,28 @@
<action android:name="com.todoroo.astrid.TASK_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</receiver>
<!-- backup -->
<service android:name="com.todoroo.astrid.backup.BackupService"/>
<!-- notes -->
<!-- locale -->
<activity android:name="com.todoroo.astrid.locale.LocaleEditAlerts"
android:label="@string/locale_edit_alerts_title"
android:icon="@drawable/icon_32"
android:exported="true" >
<intent-filter>
<action android:name="com.twofortyfouram.locale.intent.action.EDIT_SETTING" />
</intent-filter>
</activity>
<receiver android:name="com.todoroo.astrid.locale.LocaleReceiver">
<intent-filter>
<action android:name="com.todoroo.astrid.action.LOCALE_ALERT" />
</intent-filter>
</receiver>
<!-- timers -->
<receiver android:name="com.todoroo.astrid.timers.TimerDecorationExposer">
<intent-filter>

@ -14,11 +14,9 @@
<booleanAttribute key="com.android.ide.eclipse.adt.wipedata" value="false"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/astrid"/>
<listEntry value="/astrid/AndroidManifest.xml"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
<listEntry value="1"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>

@ -19,6 +19,11 @@ import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.text.InputType;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
@ -59,6 +64,19 @@ public class AndroidUtilities {
}
}
/** Suppress virtual keyboard until user's first tap */
public static void suppressVirtualKeyboard(final TextView editor) {
final int inputType = editor.getInputType();
editor.setInputType(InputType.TYPE_NULL);
editor.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
editor.setInputType(inputType);
editor.setOnTouchListener(null);
return false;
}
});
}
/**
* @return true if we're connected to the internet
*/

@ -0,0 +1,82 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.todoroo.astrid.backup;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import android.util.Log;
public class BackupDateUtilities {
private static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ssz";
/* Format a Date into ISO 8601 Compliant format.
*/
public static String getIso8601String(Date d) {
SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_FORMAT);
String result = "";
if (d != null) {
result = sdf.format(d);
}
return result;
}
/* Take an ISO 8601 string and return a Date object.
On failure, returns null.
*/
public static Date getDateFromIso8601String(String s) {
SimpleDateFormat df = new SimpleDateFormat(ISO_8601_FORMAT);
try {
return df.parse(s);
} catch (ParseException e) {
Log.e("DateUtilities", "Error parsing ISO 8601 date");
return null;
}
}
/* Get current date and time as a string.
Used in TasksXmlExporter
*/
public static String getDateForExport() {
DateFormat df = new SimpleDateFormat("yyMMdd-HHmm");
return df.format(new Date());
}
public static boolean wasCreatedBefore(String s, int daysAgo) {
DateFormat df = new SimpleDateFormat("yyMMdd");
Date date;
try {
date = df.parse(s);
} catch (ParseException e) {
return false;
}
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -daysAgo);
Date calDate = cal.getTime();
return date.before(calDate);
}
}

@ -1,4 +1,4 @@
package com.timsu.astrid.utilities;
package com.todoroo.astrid.backup;
import java.io.File;
import java.io.FileFilter;
@ -73,7 +73,7 @@ public class BackupService extends Service {
exporter.exportTasks(backupDirectorySetting.getBackupDirectory());
Preferences.setBackupSummary(ctx,
ctx.getString(R.string.prefs_backup_desc_success,
DateUtilities.getFormattedDate(ctx, new Date())));
BackupDateUtilities.getFormattedDate(ctx, new Date())));
} catch (Exception e) {
// unable to backup.
if (e == null || e.getMessage() == null) {

@ -1,4 +1,4 @@
package com.timsu.astrid.utilities;
package com.todoroo.astrid.backup;
import java.io.File;
import java.io.FileOutputStream;
@ -19,15 +19,15 @@ import android.util.Xml;
import android.widget.Toast;
import com.timsu.astrid.R;
import com.timsu.astrid.data.TaskController;
import com.timsu.astrid.data.TaskIdentifier;
import com.timsu.astrid.data.TaskModelForXml;
import com.timsu.astrid.data.alerts.AlertController;
import com.timsu.astrid.data.sync.SyncDataController;
import com.timsu.astrid.data.sync.SyncMapping;
import com.timsu.astrid.data.tag.TagController;
import com.timsu.astrid.data.tag.TagIdentifier;
import com.timsu.astrid.data.tag.TagModelForView;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.data.task.TaskModelForXml;
public class TasksXmlExporter {
@ -97,7 +97,7 @@ public class TasksXmlExporter {
List<Date> alerts = alertController.getTaskAlerts(task);
for (Date alert : alerts) {
xml.startTag(null, ALERT_TAG);
xml.attribute(null, ALERT_ATTR_DATE, DateUtilities.getIso8601String(alert));
xml.attribute(null, ALERT_ATTR_DATE, BackupDateUtilities.getIso8601String(alert));
xml.endTag(null, ALERT_TAG);
}
}
@ -212,7 +212,7 @@ public class TasksXmlExporter {
} else {
fileName = EXPORT_FILE_NAME;
}
fileName = String.format(fileName, DateUtilities.getDateForExport());
fileName = String.format(fileName, BackupDateUtilities.getDateForExport());
setOutput(astridDir.getAbsolutePath() + "/" + fileName);
return true;
} else {

@ -1,4 +1,4 @@
package com.timsu.astrid.utilities;
package com.todoroo.astrid.backup;
import java.io.FileNotFoundException;
import java.io.FileReader;
@ -18,15 +18,15 @@ import android.util.Log;
import com.timsu.astrid.R;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.TaskController;
import com.timsu.astrid.data.TaskIdentifier;
import com.timsu.astrid.data.TaskModelForXml;
import com.timsu.astrid.data.alerts.AlertController;
import com.timsu.astrid.data.sync.SyncDataController;
import com.timsu.astrid.data.sync.SyncMapping;
import com.timsu.astrid.data.tag.TagController;
import com.timsu.astrid.data.tag.TagIdentifier;
import com.timsu.astrid.data.tag.TagModelForView;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.data.task.TaskModelForXml;
public class TasksXmlImporter {
public static final String TAG = "TasksXmlImporter";
@ -170,7 +170,7 @@ public class TasksXmlImporter {
private boolean parseAlert(TaskIdentifier taskId) {
String alert = xpp.getAttributeValue(null, ALERT_ATTR_DATE);
if (alert != null) {
Date alertDate = DateUtilities.getDateFromIso8601String(alert);
Date alertDate = BackupDateUtilities.getDateFromIso8601String(alert);
if (alertDate != null) {
if (! alertController.addAlert(taskId, alertDate)) {
return false;
@ -214,7 +214,7 @@ public class TasksXmlImporter {
Date creationDate = null;
String createdString = xpp.getAttributeValue(null, TASK_CREATION_DATE);
if (createdString != null) {
creationDate = DateUtilities.getDateFromIso8601String(createdString);
creationDate = BackupDateUtilities.getDateFromIso8601String(createdString);
}
// If the task's name and creation date match an existing task, skip it.
if (creationDate != null && taskName != null) {

@ -1,4 +1,4 @@
package com.timsu.astrid.activities;
package com.todoroo.astrid.locale;
import java.util.LinkedList;

@ -1,4 +1,4 @@
package com.timsu.astrid.utilities;
package com.todoroo.astrid.locale;
import java.util.HashSet;
import java.util.LinkedList;
@ -10,11 +10,10 @@ import android.content.res.Resources;
import android.util.Log;
import com.timsu.astrid.R;
import com.timsu.astrid.activities.LocaleEditAlerts;
import com.timsu.astrid.data.TaskController;
import com.timsu.astrid.data.TaskIdentifier;
import com.timsu.astrid.data.tag.TagController;
import com.timsu.astrid.data.tag.TagIdentifier;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier;
/**
* Receiver is activated when Locale conditions are triggered

@ -24,14 +24,14 @@ import com.google.ical.values.RRule;
import com.google.ical.values.Weekday;
import com.google.ical.values.WeekdayNum;
import com.timsu.astrid.R;
import com.timsu.astrid.widget.NumberPicker;
import com.timsu.astrid.widget.NumberPickerDialog;
import com.timsu.astrid.widget.NumberPickerDialog.OnNumberPickedListener;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.astrid.activity.TaskEditActivity.TaskEditControlSet;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.ui.NumberPicker;
import com.todoroo.astrid.ui.NumberPickerDialog;
import com.todoroo.astrid.ui.NumberPickerDialog.OnNumberPickedListener;
/**
* Control Set for managing repeats

@ -17,17 +17,25 @@
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip"
android:orientation="vertical">
<TimePicker android:id="@+id/timePicker"
<TimePicker android:id="@+id/timePicker"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<CheckBox android:id="@+id/hasTime"
<CheckBox android:id="@+id/hasTime"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TEA_urgency_specific_time"/>
</LinearLayout>
</LinearLayout>
</ScrollView>

@ -1,154 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.activities;
import android.app.Activity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.TextView;
import com.timsu.astrid.R;
import com.timsu.astrid.utilities.DialogUtilities;
/**
* This activity displays a <code>WebView</code> that allows users to log in to the
* synchronization provider requested. A callback method determines whether
* their login was successful and therefore whether to dismiss the dialog.
*
* @author timsu
*
*/
public class SyncLoginActivity extends Activity {
// --- bundle arguments
/**
* URL to display
*/
public static final String URL_TOKEN = "u";
/**
* Resource for the label to display at the top of the screen
*/
public static final String LABEL_TOKEN = "l";
// --- callback
/** Callback interface */
public interface SyncLoginCallback {
/**
* Verifies whether the user's login attempt was successful. Will be
* called off of the UI thread, use the handler to post messages.
*
* @return error string, or null if sync was successful
*/
public String verifyLogin(Handler handler);
}
private static SyncLoginCallback callback = null;
/** Sets callback method */
public static void setCallback(SyncLoginCallback newCallback) {
callback = newCallback;
}
// --- ui initialization
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sync_login);
String urlParam = getIntent().getStringExtra(URL_TOKEN);
int labelParam = getIntent().getIntExtra(LABEL_TOKEN, 0);
TextView label = (TextView)findViewById(R.id.login_label);
final WebView webView = (WebView)findViewById(R.id.browser);
Button done = (Button)findViewById(R.id.done);
Button cancel = (Button)findViewById(R.id.cancel);
if(labelParam != 0)
label.setText(labelParam);
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setSavePassword(false);
webView.getSettings().setSupportZoom(true);
webView.loadUrl(urlParam);
done.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
final Handler handler = new Handler();
if(callback == null) {
finish();
return;
}
new Thread(new Runnable() {
@Override
public void run() {
final String result = callback.verifyLogin(handler);
// TaskListSubActivity.syncPreferencesOpened = true;
if(result == null) {
// TaskList.synchronizeNow = true;
finish();
} else {
// display the error
handler.post(new Runnable() {
@Override
public void run() {
DialogUtilities.okDialog(SyncLoginActivity.this, result,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
// TaskListSubActivity.shouldRefreshTaskList = true;
finish();
}
});
}
});
}
}
}).start();
}
});
cancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
setResult(RESULT_CANCELED);
finish();
}
});
}
}

@ -1,146 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.activities;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;
import com.timsu.astrid.utilities.Constants;
import com.timsu.astrid.utilities.DialogUtilities;
import com.timsu.astrid.utilities.Preferences;
/**
* Displays synchronization preferences and an action panel so users can
* initiate actions from the menu.
*
* @author timsu
*
*/
public class SyncPreferences extends PreferenceActivity {
/** whether or not to synchronize with RTM */
private boolean oldRtmSyncPreference;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Resources r = getResources();
oldRtmSyncPreference = Preferences.shouldSyncRTM(this);
// addPreferencesFromResource(R.xml.sync_preferences);
// set up preferences
// findPreference(getString(R.string.p_sync_interval)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
// @Override
// public boolean onPreferenceChange(Preference preference, Object newValue) {
// if(Preferences.getSyncRTMToken(SyncPreferences.this) == null)
// setResult(Constants.RESULT_SYNCHRONIZE);
// return true;
// }
// });
// set up footer
getListView().addFooterView(getLayoutInflater().inflate(
R.layout.sync_footer, getListView(), false));
Button syncButton = ((Button)findViewById(R.id.sync));
syncButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
setResult(Constants.RESULT_SYNCHRONIZE);
finish();
}
});
((Button)findViewById(R.id.forget)).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
DialogUtilities.okCancelDialog(SyncPreferences.this,
getResources().getString(R.string.sync_forget_confirm),
new Dialog.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
// Synchronizer.clearUserData(SyncPreferences.this);
// force a synchronization if sync preference is still set
oldRtmSyncPreference = false;
}
}, null);
}
});
// set up labels
TextView lastSyncLabel = (TextView)findViewById(R.id.last_sync_label);
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd HH:mm");
String syncDate = r.getString(R.string.sync_date_never);
Date lastSyncDate = Preferences.getSyncLastSync(this);
if(lastSyncDate != null)
syncDate = formatter.format(lastSyncDate);
lastSyncLabel.setText(r.getString(R.string.sync_last_sync, syncDate));
syncDate = null;
TextView lastAutoSyncLabel = (TextView)findViewById(R.id.last_auto_sync_label);
Date lastAutoSyncDate = Preferences.getSyncLastSyncAttempt(this);
if(lastAutoSyncDate != null && (lastSyncDate == null ||
(lastAutoSyncDate.getTime() > lastSyncDate.getTime())))
syncDate = formatter.format(lastAutoSyncDate);
if(syncDate != null)
lastAutoSyncLabel.setText(r.getString(R.string.sync_last_auto_sync, syncDate));
else
lastAutoSyncLabel.setVisibility(View.GONE);
}
@Override
protected void onStart() {
super.onStart();
// set up flurry
FlurryAgent.onStartSession(this, Constants.FLURRY_KEY);
}
@Override
protected void onStop() {
super.onStop();
FlurryAgent.onEndSession(this);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK) {
boolean newRtmSyncPreference = Preferences.shouldSyncRTM(this);
if(newRtmSyncPreference != oldRtmSyncPreference && newRtmSyncPreference) {
setResult(Constants.RESULT_SYNCHRONIZE);
}
finish();
return true;
}
return false;
}
}

@ -1,112 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
/** Abstract controller class. Mostly contains some static fields */
abstract public class AbstractController {
protected Context context;
// special columns
public static final String KEY_ROWID = "_id";
// database and table names
@Autowired
protected String tasksTable;
@Autowired
protected String tagsTable;
@Autowired
protected String tagTaskTable;
@Autowired
protected String alertsTable;
@Autowired
protected String syncTable;
// stuff
public AbstractController(Context context) {
this.context = context;
DependencyInjectionService.getInstance().inject(this);
}
abstract public void open();
abstract public void close();
// cursor iterator
public static class CursorIterator<TYPE extends AbstractModel> implements Iterator<TYPE> {
Cursor cursor;
Class<TYPE> cls;
public CursorIterator(Cursor cursor, Class<TYPE> cls) {
this.cursor = cursor;
this.cls = cls;
}
public boolean hasNext() {
return !cursor.isLast();
}
public TYPE next() {
try {
TYPE model = cls.getConstructor(Cursor.class).newInstance(cursor);
cursor.moveToNext();
return model;
// ugh...
} catch (IllegalArgumentException e) {
Log.e("CursorIterator", e.toString());
} catch (SecurityException e) {
Log.e("CursorIterator", e.toString());
} catch (InstantiationException e) {
Log.e("CursorIterator", e.toString());
} catch (IllegalAccessException e) {
Log.e("CursorIterator", e.toString());
} catch (InvocationTargetException e) {
Log.e("CursorIterator", e.toString());
} catch (NoSuchMethodException e) {
Log.e("CursorIterator", e.toString());
}
return null;
}
public void remove() {
throw new UnsupportedOperationException("Can't remove this way");
}
}
}

@ -1,263 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data;
import java.util.Date;
import java.util.HashMap;
import android.content.ContentValues;
import android.database.Cursor;
/** A data object backed by a database */
public abstract class AbstractModel {
/* Data Source Ordering:
*
* In order to return the best data, we want to check first what the user
* has explicitly set (setValues), then the values we have read out of
* the database (values), the database itself (cursor), then defaults
* (getDefaultValues)
*/
/** User set values */
protected ContentValues setValues = new ContentValues();
/** Cached values from database */
private ContentValues values = new ContentValues();
/** Cursor into the database */
private Cursor cursor = null;
// --- constructors
/** Construct a model from scratch */
public AbstractModel() {
// ...
}
/** Construct a model from a database object */
public AbstractModel(Cursor cursor) {
this.cursor = cursor;
}
// --- data source getters
/** Get the user-set values for this object */
public ContentValues getSetValues() {
return setValues;
}
/** Get the default values for this object */
abstract public ContentValues getDefaultValues();
/** Get a list of all field/value pairs merged across data sources */
public ContentValues getMergedValues() {
ContentValues mergedValues = new ContentValues();
mergedValues.putAll(getDefaultValues());
mergedValues.putAll(values);
mergedValues.putAll(setValues);
return mergedValues;
}
/** Return the database cursor */
public Cursor getCursor() {
return cursor;
}
// --- checking against cached values
protected void putIfChangedFromDatabase(String field, String newValue) {
if(!setValues.containsKey(field) && values.containsKey(field)) {
String value = values.getAsString(field);
if(value == null) {
if(newValue == null)
return;
} else if(value.equals(newValue))
return;
}
setValues.put(field, newValue);
}
protected void putIfChangedFromDatabase(String field, Long newValue) {
if(!setValues.containsKey(field) && values.containsKey(field)) {
Long value = values.getAsLong(field);
if(value == null) {
if(newValue == null)
return;
} else if(value.equals(newValue))
return;
}
setValues.put(field, newValue);
}
protected void putIfChangedFromDatabase(String field, Integer newValue) {
if(!setValues.containsKey(field) && values.containsKey(field)) {
Integer value = values.getAsInteger(field);
if(value == null) {
if(newValue == null)
return;
} else if(value.equals(newValue))
return;
}
setValues.put(field, newValue);
}
protected void putIfChangedFromDatabase(String field, Double newValue) {
if(!setValues.containsKey(field) && values.containsKey(field)) {
Double value = values.getAsDouble(field);
if(value == null) {
if(newValue == null)
return;
} else if(value.equals(newValue))
return;
}
setValues.put(field, newValue);
}
protected static final HashMap<Class<?>, HashMap<String, Integer>>
columnIndexCache = new HashMap<Class<?>, HashMap<String, Integer>>();
private int getColumnIndex(String field) {
HashMap<String, Integer> classCache;
classCache = columnIndexCache.get(getClass());
if(classCache == null) {
classCache = new HashMap<String, Integer>();
columnIndexCache.put(getClass(), classCache);
}
Integer index = classCache.get(field);
if(index == null) {
index = cursor.getColumnIndexOrThrow(field);
classCache.put(field, index);
}
return index;
}
// --- data retrieval for the different object types
protected String retrieveString(String field) {
if(setValues.containsKey(field))
return setValues.getAsString(field);
if(values.containsKey(field))
return values.getAsString(field);
// if we have a database to hit, do that now
if(cursor != null) {
String value = cursor.getString(getColumnIndex(field));
values.put(field, value);
return value;
}
// do we have defaults?
ContentValues defaults = getDefaultValues();
if(defaults != null && defaults.containsKey(field))
return defaults.getAsString(field);
throw new UnsupportedOperationException("Could not read field " + field);
}
protected Integer retrieveInteger(String field) {
if(setValues.containsKey(field))
return setValues.getAsInteger(field);
if(values.containsKey(field))
return values.getAsInteger(field);
// if we have a database to hit, do that now
if(cursor != null) {
try {
Integer value = cursor.getInt(getColumnIndex(field));
values.put(field, value);
return value;
} catch (Exception e) {
// error reading from cursor, try to continue
}
}
// do we have defaults?
ContentValues defaults = getDefaultValues();
if(defaults != null && defaults.containsKey(field))
return defaults.getAsInteger(field);
throw new UnsupportedOperationException("Could not read field " + field);
}
protected Long retrieveLong(String field) {
if(setValues.containsKey(field))
return setValues.getAsLong(field);
if(values.containsKey(field))
return values.getAsLong(field);
// if we have a database to hit, do that now
if(cursor != null) {
Long value = cursor.getLong(getColumnIndex(field));
values.put(field, value);
return value;
}
// do we have defaults?
ContentValues defaults = getDefaultValues();
if(defaults != null && defaults.containsKey(field))
return defaults.getAsLong(field);
throw new UnsupportedOperationException("Could not read field " + field);
}
protected Double retrieveDouble(String field) {
if(setValues.containsKey(field))
return setValues.getAsDouble(field);
if(values.containsKey(field))
return values.getAsDouble(field);
// if we have a database to hit, do that now
if(cursor != null) {
Double value = cursor.getDouble(getColumnIndex(field));
values.put(field, value);
return value;
}
// do we have defaults?
ContentValues defaults = getDefaultValues();
if(defaults != null && defaults.containsKey(field))
return defaults.getAsDouble(field);
throw new UnsupportedOperationException("Could not read field " + field);
}
// --- retrieving composite objects
protected Date retrieveDate(String field) {
Long time;
try {
time = retrieveLong(field);
if(time == null || time == 0)
return null;
} catch (NullPointerException e) {
return null;
}
return new Date(time);
}
}

@ -1,55 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data;
/** Identifier of a single object. Extend this class to create your own */
public abstract class Identifier {
private long id;
public Identifier(long id) {
this.id = id;
}
public long getId() {
return id;
}
public String idAsString() {
return Long.toString(id);
}
@Override
public int hashCode() {
return (int)id;
}
@Override
public boolean equals(Object o) {
if(o == null || o.getClass() != getClass())
return false;
return ((Identifier)o).getId() == getId();
}
@Override
public String toString() {
return getClass().getSimpleName() + ": " + id;
}
}

@ -1,135 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.alerts;
import java.util.Date;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.AbstractModel;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.utilities.DialogUtilities;
/** A single alert on a task */
public class Alert extends AbstractModel {
/** Version number of this model */
static final int VERSION = 1;
// field names
public static final String TASK = "task";
public static final String DATE = "date";
/** Default values container */
private static final ContentValues defaultValues = new ContentValues();
@Override
public ContentValues getDefaultValues() {
return defaultValues;
}
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
TASK,
DATE,
};
// --- database helper
/** Database Helper manages creating new tables and updating old ones */
static class AlertDatabaseHelper extends SQLiteOpenHelper {
String tableName;
Context context;
AlertDatabaseHelper(Context context, String databaseName, String tableName) {
super(context, databaseName, null, VERSION);
this.tableName = tableName;
this.context = context;
}
@Override
public synchronized void onCreate(SQLiteDatabase db) {
String sql = new StringBuilder().
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
append(TASK).append(" integer not null,").
append(DATE).append(" integer not null,").
append("unique (").append(TASK).append(",").append(DATE).append(")").
append(");").toString();
db.execSQL(sql);
}
@Override
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
oldVersion + " to " + newVersion + ".");
switch(oldVersion) {
default:
// we don't know how to handle it... show an error
Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion);
DialogUtilities.okDialog(context, "There was a database error reading from Alerts. Data may have been corrupted.", null);
}
}
}
// --- constructor pass-through
Alert(TaskIdentifier task, Date date) {
super();
setTask(task);
setDate(date);
}
public Alert(Cursor cursor) {
super(cursor);
}
// --- getters and setters: expose them as you see fit
public boolean isNew() {
return getCursor() == null;
}
public TaskIdentifier getTask() {
return new TaskIdentifier(retrieveLong(TASK));
}
public Date getDate() {
return new Date(retrieveLong(DATE));
}
private void setTask(TaskIdentifier task) {
setValues.put(TASK, task.getId());
}
private void setDate(Date date) {
setValues.put(DATE, date.getTime());
}
}

@ -1,144 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.alerts;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.alerts.Alert.AlertDatabaseHelper;
import com.timsu.astrid.data.task.TaskIdentifier;
/** Controller for Tag-related operations */
public class AlertController extends AbstractController {
private SQLiteDatabase alertDatabase;
/** Get a cursor to tag identifiers */
public Cursor getTaskAlertsCursor(TaskIdentifier taskId) throws SQLException {
Cursor cursor = alertDatabase.query(alertsTable,
Alert.FIELD_LIST, Alert.TASK + " = ?",
new String[] { taskId.idAsString() }, null, null, null);
return cursor;
}
/** Get a list of alerts for the given task */
public List<Date> getTaskAlerts(TaskIdentifier
taskId) throws SQLException {
List<Date> list = new LinkedList<Date>();
Cursor cursor = alertDatabase.query(alertsTable,
Alert.FIELD_LIST, Alert.TASK + " = ?",
new String[] { taskId.idAsString() }, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new Alert(cursor).getDate());
} while(!cursor.isLast());
return list;
} finally {
cursor.close();
}
}
/** Get a list of alerts that are set for the future */
public Set<TaskIdentifier> getTasksWithActiveAlerts() throws SQLException {
Set<TaskIdentifier> list = new HashSet<TaskIdentifier>();
Cursor cursor = alertDatabase.query(alertsTable,
Alert.FIELD_LIST, Alert.DATE + " > ?",
new String[] { Long.toString(System.currentTimeMillis()) }, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new Alert(cursor).getTask());
} while(!cursor.isLast());
return list;
} finally {
cursor.close();
}
}
/** Remove all alerts from the task */
public boolean removeAlerts(TaskIdentifier taskId)
throws SQLException{
return alertDatabase.delete(alertsTable,
String.format("%s = ?",
Alert.TASK),
new String[] { taskId.idAsString() }) > 0;
}
/** Add the given tag to the task */
public boolean addAlert(TaskIdentifier taskId, Date date)
throws SQLException {
ContentValues values = new ContentValues();
values.put(Alert.DATE, date.getTime());
values.put(Alert.TASK, taskId.getId());
return alertDatabase.insert(alertsTable, Alert.TASK,
values) >= 0;
}
// --- boilerplate
/**
* Constructor - takes the context to allow the database to be
* opened/created
*/
public AlertController(Context context) {
super(context);
}
/**
* Open the notes database. If it cannot be opened, try to create a new
* instance of the database. If it cannot be created, throw an exception to
* signal the failure
*
* @return this (self reference, allowing this to be chained in an
* initialization call)
* @throws SQLException if the database could be neither opened or created
*/
@Override
public void open() throws SQLException {
alertDatabase = new AlertDatabaseHelper(context,
alertsTable, alertsTable).getWritableDatabase();
}
/** Closes database resource */
@Override
public void close() {
alertDatabase.close();
}
}

@ -1,66 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.enums;
import com.timsu.astrid.R;
public enum Importance {
// MOST IMPORTANT
LEVEL_1(R.string.importance_1,
R.color.importance_1,
R.color.task_list_importance_1),
LEVEL_2(R.string.importance_2,
R.color.importance_2,
R.color.task_list_importance_2),
LEVEL_3(R.string.importance_3,
R.color.importance_3,
R.color.task_list_importance_3),
LEVEL_4(R.string.importance_4,
R.color.importance_4,
R.color.task_list_importance_4),
// LEAST IMPORTANT
;
int label;
int color;
int taskListColor;
public static final Importance DEFAULT = LEVEL_3;
private Importance(int label, int color, int taskListColor) {
this.label = label;
this.color = color;
this.taskListColor = taskListColor;
}
public int getLabelResource() {
return label;
}
public int getColorResource() {
return color;
}
public int getTaskListColor() {
return taskListColor;
}
}

@ -1,77 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.enums;
import java.util.Date;
import android.content.res.Resources;
import com.timsu.astrid.R;
public enum RepeatInterval {
DAYS(R.string.repeat_days) {
@Override
public void offsetDateBy(Date input, int number) {
input.setDate(input.getDate() + number);
}
},
WEEKS(R.string.repeat_weeks) {
@Override
public void offsetDateBy(Date input, int number) {
input.setDate(input.getDate() + 7 * number);
}
},
MONTHS(R.string.repeat_months) {
@Override
public void offsetDateBy(Date input, int number) {
input.setMonth(input.getMonth() + number);
}
},
HOURS(R.string.repeat_hours) {
@Override
public void offsetDateBy(Date input, int number) {
input.setHours(input.getHours() + number);
}
},
;
int label;
private RepeatInterval(int label) {
this.label = label;
}
public int getLabelResource() {
return label;
}
abstract public void offsetDateBy(Date input, int number);
public static String[] getLabels(Resources r) {
int intervalCount = RepeatInterval.values().length;
String[] result = new String[intervalCount];
for(int i = 0; i < intervalCount; i++)
result[i] = r.getString(RepeatInterval.values()[i].getLabelResource());
return result;
}
}

@ -1,39 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.location;
public class GeoPoint {
private int latitude, longitude;
public GeoPoint(int latitude, int longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public int getLatitudeE6() {
return latitude;
}
public int getLongitudeE6() {
return longitude;
}
}

@ -1,196 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.sync;
import java.util.HashSet;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.sync.SyncMapping.SyncMappingDatabaseHelper;
import com.timsu.astrid.data.task.AbstractTaskModel;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.data.task.TaskModelForSync;
/** Controller for Tag-related operations */
public class SyncDataController extends AbstractController {
private SQLiteDatabase syncDatabase;
// --- updated tasks list
/** Mark all updated tasks as finished synchronizing */
public boolean clearUpdatedTaskList(int syncServiceId) throws SQLException {
ContentValues values = new ContentValues();
values.put(SyncMapping.UPDATED, 0);
return syncDatabase.update(syncTable, values,
SyncMapping.SYNC_SERVICE + " = " + syncServiceId, null) > 0;
}
/** Indicate that this task's properties were updated */
public boolean addToUpdatedList(TaskIdentifier taskId) throws SQLException {
ContentValues values = new ContentValues();
values.put(SyncMapping.UPDATED, 1);
return syncDatabase.update(syncTable, values,
SyncMapping.TASK + " = " + taskId.getId(), null) > 0;
}
public static void taskUpdated(Context context, AbstractTaskModel task) {
if(!(task instanceof TaskModelForSync)) {
SyncDataController syncController = new SyncDataController(context);
syncController.open();
syncController.addToUpdatedList(task.getTaskIdentifier());
syncController.close();
}
}
// --- sync mapping
/** Get all mappings for the given synchronization service */
public HashSet<SyncMapping> getSyncMappings(int syncServiceId) throws SQLException {
HashSet<SyncMapping> list = new HashSet<SyncMapping>();
Cursor cursor = syncDatabase.query(syncTable,
SyncMapping.FIELD_LIST,
SyncMapping.SYNC_SERVICE + " = " + syncServiceId,
null, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new SyncMapping(cursor));
} while(!cursor.isLast());
return list;
} finally {
cursor.close();
}
}
/** Get all mappings for specified task for all synchronization services */
public HashSet<SyncMapping> getSyncMappings(TaskIdentifier taskId)
throws SQLException {
HashSet<SyncMapping> list = new HashSet<SyncMapping>();
Cursor cursor = syncDatabase.query(syncTable,
SyncMapping.FIELD_LIST,
SyncMapping.TASK + " = ?",
new String[] { "" + taskId.getId() },
null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new SyncMapping(cursor));
} while(!cursor.isLast());
return list;
} finally {
cursor.close();
}
}
/** Get mapping for given task */
public SyncMapping getSyncMapping(int syncServiceId, TaskIdentifier taskId)
throws SQLException {
Cursor cursor = syncDatabase.query(syncTable,
SyncMapping.FIELD_LIST,
SyncMapping.SYNC_SERVICE + " = ? AND " +
SyncMapping.TASK + " = ?",
new String[] { "" + syncServiceId, "" + taskId.getId() },
null, null, null);
try {
if(cursor.getCount() == 0)
return null;
cursor.moveToNext();
return new SyncMapping(cursor);
} finally {
cursor.close();
}
}
/** Saves the given task to the database. Returns true on success. */
public boolean saveSyncMapping(SyncMapping mapping) {
long newRow = syncDatabase.insert(syncTable, SyncMapping.TASK,
mapping.getMergedValues());
mapping.setId(newRow);
return newRow >= 0;
}
/** Deletes the given mapping. Returns true on success */
public boolean deleteSyncMapping(SyncMapping mapping) {
// was never saved
if(mapping.getId() == 0)
return false;
return syncDatabase.delete(syncTable, KEY_ROWID + "=" +
mapping.getId(), null) > 0;
}
/** Deletes the given mapping. Returns true on success */
public boolean deleteAllMappings(int syncServiceId) {
return syncDatabase.delete(syncTable, SyncMapping.SYNC_SERVICE +
"=" + syncServiceId, null) > 0;
}
// --- boilerplate
/**
* Constructor - takes the context to allow the database to be
* opened/created
*/
public SyncDataController(Context context) {
super(context);
}
/**
* Open the notes database. If it cannot be opened, try to create a new
* instance of the database. If it cannot be created, throw an exception to
* signal the failure
*
* @return this (self reference, allowing this to be chained in an
* initialization call)
* @throws SQLException if the database could be neither opened or created
*/
@Override
public synchronized void open() throws SQLException {
SQLiteOpenHelper helper = new SyncMappingDatabaseHelper(context,
syncTable, syncTable);
syncDatabase = helper.getWritableDatabase();
}
/** Closes database resource */
@Override
public void close() {
if(syncDatabase != null)
syncDatabase.close();
}
}

@ -1,173 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.sync;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.AbstractModel;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.utilities.DialogUtilities;
/** A single tag on a task */
public class SyncMapping extends AbstractModel {
/** Version number of this model */
static final int VERSION = 1;
// field names
static final String TASK = "task";
static final String SYNC_SERVICE = "service";
static final String REMOTE_ID = "remoteId";
static final String UPDATED = "updated";
/** Default values container */
private static final ContentValues defaultValues = new ContentValues();
static {
defaultValues.put(UPDATED, 0);
}
@Override
public ContentValues getDefaultValues() {
return defaultValues;
}
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
TASK,
SYNC_SERVICE,
REMOTE_ID,
UPDATED,
};
// --- database helper
/** Database Helper manages creating new tables and updating old ones */
static class SyncMappingDatabaseHelper extends SQLiteOpenHelper {
String tableName;
Context context;
SyncMappingDatabaseHelper(Context context, String databaseName, String tableName) {
super(context, databaseName, null, VERSION);
this.tableName = tableName;
this.context = context;
}
@Override
public synchronized void onCreate(SQLiteDatabase db) {
String sql = new StringBuilder().
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
append(TASK).append(" integer not null,").
append(SYNC_SERVICE).append(" integer not null,").
append(REMOTE_ID).append(" text not null,").
append(UPDATED).append(" integer not null,").
append("unique (").append(TASK).append(",").append(SYNC_SERVICE).append(")").
append(");").toString();
db.execSQL(sql);
}
@Override
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
oldVersion + " to " + newVersion + ".");
switch(oldVersion) {
default:
// we don't know how to handle it... show an error
Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion);
DialogUtilities.okDialog(context, "There was a database error reading from Alerts. Data may have been corrupted.", null);
}
}
}
// --- constructor pass-through
//
// public SyncMapping(TaskIdentifier task, TaskProxy taskProxy) {
// this(task, taskProxy.getSyncServiceId(), taskProxy.getRemoteId());
// }
public SyncMapping(TaskIdentifier task, int syncServiceId, String remoteId) {
super();
setTask(task);
setSyncServiceId(syncServiceId);
setRemoteId(remoteId);
}
SyncMapping(Cursor cursor) {
super(cursor);
getId();
getTask();
getSyncServiceId();
getRemoteId();
isUpdated();
}
// --- getters and setters
public void setId(long id) {
putIfChangedFromDatabase(AbstractController.KEY_ROWID, id);
}
public long getId() {
try {
return retrieveLong(AbstractController.KEY_ROWID);
} catch (UnsupportedOperationException e) {
return 0;
}
}
public TaskIdentifier getTask() {
return new TaskIdentifier(retrieveLong(TASK));
}
public int getSyncServiceId() {
return retrieveInteger(SYNC_SERVICE);
}
public String getRemoteId() {
return retrieveString(REMOTE_ID);
}
public boolean isUpdated() {
return retrieveInteger(UPDATED) == 1;
}
private void setTask(TaskIdentifier task) {
setValues.put(TASK, task.getId());
}
private void setSyncServiceId(int id) {
setValues.put(SYNC_SERVICE, id);
}
private void setRemoteId(String remoteId) {
setValues.put(REMOTE_ID, remoteId);
}
}

@ -1,198 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.tag;
import java.util.Date;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.AbstractModel;
import com.timsu.astrid.utilities.DialogUtilities;
/** Abstract model of a task. Subclasses implement the getters and setters
* they are interested in.
*
* @author timsu
*
*/
public abstract class AbstractTagModel extends AbstractModel {
/** Version number of this model */
static final int VERSION = 1;
// field names
static final String NAME = "name";
static final String NOTES = "notes";
// reserved fields
static final String ICON = "icon";
static final String PARENT = "parent";
static final String FLAGS = "flags";
static final String LOCATION_LAT = "locationLat";
static final String LOCATION_LONG = "locationLong";
static final String NOTIFICATIONS = "notifications";
// end reserved fields
static final String CREATION_DATE = "creationDate";
/** Default values container */
private static final ContentValues defaultValues = new ContentValues();
static {
defaultValues.put(NAME, "");
defaultValues.put(NOTES, "");
defaultValues.put(ICON, 0);
defaultValues.put(PARENT, 0);
defaultValues.put(FLAGS, 0);
defaultValues.put(LOCATION_LAT, 0);
defaultValues.put(LOCATION_LONG, 0);
defaultValues.put(NOTIFICATIONS, 0);
}
@Override
public ContentValues getDefaultValues() {
return defaultValues;
}
// --- database helper
/** Database Helper manages creating new tables and updating old ones */
static class TagModelDatabaseHelper extends SQLiteOpenHelper {
String tableName;
Context context;
TagModelDatabaseHelper(Context context, String databaseName, String tableName) {
super(context, databaseName, null, VERSION);
this.tableName = tableName;
this.context = context;
}
@Override
public synchronized void onCreate(SQLiteDatabase db) {
String sql = new StringBuilder().
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
append(NAME).append(" text unique,").
append(NOTES).append(" text,").
append(ICON).append(" integer,").
append(PARENT).append(" integer,").
append(FLAGS).append(" integer,").
append(LOCATION_LAT).append(" integer,").
append(LOCATION_LONG).append(" integer,").
append(NOTIFICATIONS).append(" integer,").
append(CREATION_DATE).append(" integer").
append(");").toString();
db.execSQL(sql);
}
@Override
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
oldVersion + " to " + newVersion + ".");
switch(oldVersion) {
default:
// we don't know how to handle it... show an error
Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion);
DialogUtilities.okDialog(context, "There was a database error reading from Alerts. Data may have been corrupted.", null);
}
}
}
// --- utility methods
// --- identifier
private TagIdentifier identifier = null;
public TagIdentifier getTagIdentifier() {
return identifier;
}
void setTagIdentifier(TagIdentifier identifier) {
this.identifier = identifier;
}
// --- constructor pass-through
AbstractTagModel() {
super();
}
/** Read identifier from database */
AbstractTagModel(Cursor cursor) {
super(cursor);
Integer id = retrieveInteger(AbstractController.KEY_ROWID);
setTagIdentifier(new TagIdentifier(id));
}
/** Get identifier from argument */
AbstractTagModel(TagIdentifier identifier, Cursor cursor) {
super(cursor);
setTagIdentifier(identifier);
}
// --- getters and setters: expose them as you see fit
protected String getName() {
return retrieveString(NAME);
}
protected String getNotes() {
return retrieveString(NOTES);
}
protected Date getCreationDate() {
return retrieveDate(CREATION_DATE);
}
// --- setters
protected void setName(String name) {
setValues.put(NAME, name.trim());
}
protected void setNotes(String notes) {
setValues.put(NOTES, notes);
}
protected void setCreationDate(Date creationDate) {
putDate(setValues, CREATION_DATE, creationDate);
}
// --- utility methods
static void putDate(ContentValues cv, String fieldName, Date date) {
if(date == null)
cv.put(fieldName, (Long)null);
else
cv.put(fieldName, date.getTime());
}
}

@ -1,328 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.tag;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.tag.AbstractTagModel.TagModelDatabaseHelper;
import com.timsu.astrid.data.tag.TagToTaskMapping.TagToTaskMappingDatabaseHelper;
import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.provider.TasksProvider;
/** Controller for Tag-related operations */
public class TagController extends AbstractController {
private SQLiteDatabase tagDatabase, tagToTaskMapDatabase;
// --- tag batch operations
/** Get a list of all tags */
public LinkedList<TagModelForView> getAllTags()
throws SQLException {
LinkedList<TagModelForView> list = new LinkedList<TagModelForView>();
Cursor cursor = tagDatabase.query(tagsTable,
TagModelForView.FIELD_LIST, null, null, null, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new TagModelForView(cursor));
} while(!cursor.isLast());
} finally {
cursor.close();
}
return list;
}
// --- tag to task map batch operations
/** Get a list of all tags as an id => tag map */
public HashMap<TagIdentifier, TagModelForView> getAllTagsAsMap() throws SQLException {
HashMap<TagIdentifier, TagModelForView> map = new HashMap<TagIdentifier, TagModelForView>();
for(TagModelForView tag : getAllTags())
map.put(tag.getTagIdentifier(), tag);
return map;
}
/** Get a list of tag identifiers for the given task */
public LinkedList<TagIdentifier> getTaskTags(TaskIdentifier
taskId) throws SQLException {
LinkedList<TagIdentifier> list = new LinkedList<TagIdentifier>();
Cursor cursor = tagToTaskMapDatabase.query(tagTaskTable,
TagToTaskMapping.FIELD_LIST, TagToTaskMapping.TASK + " = ?",
new String[] { taskId.idAsString() }, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new TagToTaskMapping(cursor).getTag());
} while(!cursor.isLast());
} finally {
cursor.close();
}
return list;
}
/** Get a list of task identifiers for the given tag.
* This searches for TAGGED tasks only.
* Use getUntaggedTasks() to get a list of UNTAGGED tasks **/
public LinkedList<TaskIdentifier> getTaggedTasks(TagIdentifier tagId)
throws SQLException {
LinkedList<TaskIdentifier> list = new LinkedList<TaskIdentifier>();
Cursor cursor = tagToTaskMapDatabase.query(tagTaskTable,
TagToTaskMapping.FIELD_LIST, TagToTaskMapping.TAG + " = ?",
new String[] { tagId.idAsString() }, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new TagToTaskMapping(cursor).getTask());
} while(!cursor.isLast());
} finally {
cursor.close();
}
return list;
}
/** Returns a list of task identifiers in the provided set that are UNtagged.
*
* The calling SubActivity must provide the set of tasks, since
* TagController cannot access the appropriate instance of TaskController.
*
* The current implementation is not very efficient, because queries
* the TagToTask map once for each active task.
**/
public LinkedList<TaskIdentifier> getUntaggedTasks() throws SQLException {
HashSet<Long> ids = new HashSet<Long>();
String[] tagMapColumns = new String[] { TagToTaskMapping.TASK };
Cursor tagMapCursor = tagToTaskMapDatabase.query(tagTaskTable,
tagMapColumns, null, null, TagToTaskMapping.TASK, null,
TagToTaskMapping.TASK + " ASC");
SQLiteDatabase taskDatabase = new TaskModelDatabaseHelper(context,
tasksTable, tasksTable).getReadableDatabase();
String[] taskColumns = new String[] { KEY_ROWID };
Cursor taskCursor = taskDatabase.query(tasksTable, taskColumns,
null, null, null, null, KEY_ROWID + " ASC");
LinkedList<TaskIdentifier> list = new LinkedList<TaskIdentifier>();
try {
if(taskCursor.getCount() == 0)
return list;
do {
taskCursor.moveToNext();
ids.add(taskCursor.getLong(0));
} while(!taskCursor.isLast());
if(tagMapCursor.getCount() > 0) {
do {
tagMapCursor.moveToNext();
ids.remove(tagMapCursor.getLong(0));
} while(!tagMapCursor.isLast());
}
} finally {
taskCursor.close();
tagMapCursor.close();
taskDatabase.close();
}
for(Long id : ids)
list.add(new TaskIdentifier(id));
return list;
}
// --- single tag operations
public TagIdentifier createTag(String name) throws SQLException {
if(name == null)
throw new NullPointerException("Name can't be null");
TagModelForView newTag = new TagModelForView(name);
long row = tagDatabase.insertOrThrow(tagsTable, AbstractTagModel.NAME,
newTag.getMergedValues());
return new TagIdentifier(row);
}
/** Creates or saves the given tag */
public boolean saveTag(AbstractTagModel tag) throws SQLException {
boolean saveSucessful;
if(tag.getTagIdentifier() == null) {
long newRow = tagDatabase.insert(tagsTable, AbstractTagModel.NAME,
tag.getMergedValues());
tag.setTagIdentifier(new TagIdentifier(newRow));
saveSucessful = newRow >= 0;
} else {
long id = tag.getTagIdentifier().getId();
saveSucessful = tagDatabase.update(tagsTable, tag.getSetValues(),
KEY_ROWID + "=" + id, null) > 0;
}
return saveSucessful;
}
/** Returns a TaskModelForView corresponding to the given Tag Name */
public TagModelForView fetchTagFromName(String name) throws SQLException {
Cursor cursor = tagDatabase.query(true, tagsTable,
TagModelForView.FIELD_LIST,
AbstractTagModel.NAME + " = ?", new String[] {name}, null, null, null, null);
try {
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
TagModelForView model = new TagModelForView(cursor);
return model;
}
return null;
} finally {
if(cursor != null)
cursor.close();
}
}
/** Returns a TaskModelForView corresponding to the given TagIdentifier */
public TagModelForView fetchTagForView(TagIdentifier tagId) throws SQLException {
long id = tagId.getId();
Cursor cursor = tagDatabase.query(true, tagsTable,
TagModelForView.FIELD_LIST,
KEY_ROWID + "=" + id, null, null, null, null, null);
try {
if (cursor != null) {
cursor.moveToFirst();
TagModelForView model = new TagModelForView(cursor);
return model;
}
throw new SQLException("Returned empty set!");
} finally {
if(cursor != null)
cursor.close();
}
}
/** Deletes the tag and removes tag/task mappings */
public boolean deleteTag( TagIdentifier tagId)
throws SQLException{
if(tagToTaskMapDatabase.delete(tagTaskTable,
TagToTaskMapping.TAG + " = " + tagId.idAsString(), null) < 0)
return false;
int res = tagDatabase.delete(tagsTable,
KEY_ROWID + " = " + tagId.idAsString(), null);
// notify modification
TasksProvider.notifyDatabaseModification();
return res > 0;
}
// --- single tag to task operations
/** Remove the given tag from the task */
public boolean removeTag(TaskIdentifier taskId, TagIdentifier tagId)
throws SQLException{
int res = tagToTaskMapDatabase.delete(tagTaskTable,
String.format("%s = ? AND %s = ?",
TagToTaskMapping.TAG, TagToTaskMapping.TASK),
new String[] { tagId.idAsString(), taskId.idAsString() });
// notify modification
TasksProvider.notifyDatabaseModification();
return res > 0;
}
/** Add the given tag to the task */
public boolean addTag(TaskIdentifier taskId, TagIdentifier tagId)
throws SQLException {
ContentValues values = new ContentValues();
values.put(TagToTaskMapping.TAG, tagId.getId());
values.put(TagToTaskMapping.TASK, taskId.getId());
long res = tagToTaskMapDatabase.insert(tagTaskTable, TagToTaskMapping.TAG,
values);
// notify modification
TasksProvider.notifyDatabaseModification();
return res >= 0;
}
// --- boilerplate
/**
* Constructor - takes the context to allow the database to be
* opened/created
*/
public TagController(Context context) {
super(context);
}
/**
* Open the notes database. If it cannot be opened, try to create a new
* instance of the database. If it cannot be created, throw an exception to
* signal the failure
*
* @return this (self reference, allowing this to be chained in an
* initialization call)
* @throws SQLException if the database could be neither opened or created
*/
@Override
public synchronized void open() throws SQLException {
tagToTaskMapDatabase = new TagToTaskMappingDatabaseHelper(context,
tagTaskTable, tagTaskTable).getWritableDatabase();
tagDatabase = new TagModelDatabaseHelper(context,
tagsTable, tagsTable).getWritableDatabase();
}
/** Closes database resource */
@Override
public void close() {
if(tagDatabase != null)
tagDatabase.close();
if(tagToTaskMapDatabase != null)
tagToTaskMapDatabase.close();
}
}

@ -1,31 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.tag;
import com.timsu.astrid.data.Identifier;
public class TagIdentifier extends Identifier {
public TagIdentifier(long id) {
super(id);
}
}

@ -1,102 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.tag;
import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
/** Tag model for viewing purposes. Contains task name */
public class TagModelForView extends AbstractTagModel {
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
NAME,
};
// negative number, should not conflict with database row #'s
public static final TagIdentifier UNTAGGED_IDENTIFIER = new TagIdentifier(Long.MIN_VALUE);
public static final String UNTAGGED_DEFAULT_NAME = "[untagged]";
private static TagModelForView UNTAGGED_TASKS = new TagModelForView(UNTAGGED_DEFAULT_NAME);
public static final String HIDDEN_FROM_MAIN_LIST_PREFIX = "_";
/**
* Returns a TagModelForView object to represent "Untagged" tasks,
* whose Identifier is defined by the static final UNTAGGED_IDENTIFIER.
*
* Pass in a string to show the "Untagged" name in the desired language.
* @param untaggedLabel
* @return
*/
public static TagModelForView getUntaggedModel(String untaggedLabel) {
UNTAGGED_TASKS = new TagModelForView(untaggedLabel);
UNTAGGED_TASKS.setTagIdentifier(UNTAGGED_IDENTIFIER);
return UNTAGGED_TASKS;
}
/**
* Returns the default/last-used TagModelForView representing "Untagged"
* tasks. Set the localized name using getUntaggedModel(String...)
*/
public static TagModelForView getUntaggedModel() {
UNTAGGED_TASKS.setTagIdentifier(UNTAGGED_IDENTIFIER);
return UNTAGGED_TASKS;
}
// --- constructors
/** Constructor for creating a new model */
TagModelForView(String name) {
super();
setName(name);
}
/** Constructor for getting an existing model */
TagModelForView(Cursor cursor) {
super(cursor);
getName();
}
// --- getters and setters
@Override
public String getName() {
return super.getName();
}
@Override
public String toString() {
return getName();
}
public boolean shouldHideFromMainList() {
return getName().startsWith(HIDDEN_FROM_MAIN_LIST_PREFIX);
}
public void toggleHideFromMainList() {
if(shouldHideFromMainList())
setName(getName().substring(HIDDEN_FROM_MAIN_LIST_PREFIX.length()));
else
setName(HIDDEN_FROM_MAIN_LIST_PREFIX + getName());
}
}

@ -1,133 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.tag;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.AbstractModel;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.utilities.DialogUtilities;
/** A single tag on a task */
public class TagToTaskMapping extends AbstractModel {
/** Version number of this model */
static final int VERSION = 2;
// field names
public static final String TASK = "task";
public static final String TAG = "tag";
/** Default values container */
private static final ContentValues defaultValues = new ContentValues();
@Override
public ContentValues getDefaultValues() {
return defaultValues;
}
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
TASK,
TAG,
};
// --- database helper
/** Database Helper manages creating new tables and updating old ones */
static class TagToTaskMappingDatabaseHelper extends SQLiteOpenHelper {
String tableName;
Context context;
TagToTaskMappingDatabaseHelper(Context context, String databaseName, String tableName) {
super(context, databaseName, null, VERSION);
this.tableName = tableName;
this.context = context;
}
@Override
public synchronized void onCreate(SQLiteDatabase db) {
String sql = new StringBuilder().
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
append(TASK).append(" integer not null,").
append(TAG).append(" integer not null,").
append("unique (").append(TASK).append(",").append(TAG).append(")").
append(");").toString();
db.execSQL(sql);
}
@Override
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
oldVersion + " to " + newVersion + ".");
switch(oldVersion) {
default:
// we don't know how to handle it... show an error
Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion);
DialogUtilities.okDialog(context, "There was a database error reading from Tags. Data may have been corrupted.", null);
}
}
}
// --- constructor pass-through
TagToTaskMapping(TaskIdentifier task, TagIdentifier tag) {
super();
setTask(task);
setTag(tag);
}
TagToTaskMapping(Cursor cursor) {
super(cursor);
}
// --- getters and setters: expose them as you see fit
public boolean isNew() {
return getCursor() == null;
}
public TaskIdentifier getTask() {
return new TaskIdentifier(retrieveInteger(TASK));
}
public TagIdentifier getTag() {
return new TagIdentifier(retrieveInteger(TAG));
}
private void setTask(TaskIdentifier task) {
setValues.put(TASK, task.getId());
}
private void setTag(TagIdentifier tag) {
setValues.put(TAG, tag.getId());
}
}

@ -1,633 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import java.util.Date;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.timsu.astrid.R;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.AbstractModel;
import com.timsu.astrid.data.enums.Importance;
import com.timsu.astrid.data.enums.RepeatInterval;
import com.timsu.astrid.utilities.DialogUtilities;
import com.timsu.astrid.utilities.Preferences;
/** Abstract model of a task. Subclasses implement the getters and setters
* they are interested in.
*
* @author timsu
*
*/
public abstract class AbstractTaskModel extends AbstractModel {
/** Version number of this model */
static final int VERSION = 8;
public static final int COMPLETE_PERCENTAGE = 100;
// field names
public static final String NAME = "name";
public static final String NOTES = "notes";
public static final String PROGRESS_PERCENTAGE = "progressPercentage";
public static final String IMPORTANCE = "importance";
public static final String ESTIMATED_SECONDS = "estimatedSeconds";
public static final String ELAPSED_SECONDS = "elapsedSeconds";
public static final String TIMER_START = "timerStart";
public static final String DEFINITE_DUE_DATE = "definiteDueDate";
public static final String PREFERRED_DUE_DATE = "preferredDueDate";
public static final String HIDDEN_UNTIL = "hiddenUntil";
public static final String POSTPONE_COUNT = "postponeCount";
public static final String NOTIFICATIONS = "notifications";
public static final String NOTIFICATION_FLAGS = "notificationFlags";
public static final String LAST_NOTIFIED = "lastNotified";
public static final String REPEAT = "repeat";
public static final String CREATION_DATE = "creationDate";
public static final String COMPLETION_DATE = "completionDate";
public static final String CALENDAR_URI = "calendarUri";
public static final String FLAGS = "flags";
// reserved fields ---
public static final String BLOCKING_ON = "blockingOn";
// notification flags
public static final int NOTIFY_BEFORE_DEADLINE = 1 << 0;
public static final int NOTIFY_AT_DEADLINE = 1 << 1;
public static final int NOTIFY_AFTER_DEADLINE = 1 << 2;
public static final int NOTIFY_NONSTOP = 1 << 3;
// other flags
public static final int FLAG_SYNC_ON_COMPLETE = 1 << 0;
/** Number of bits to shift repeat value by */
public static final int REPEAT_VALUE_OFFSET = 3;
/** Default values container */
private static final ContentValues defaultValues = new ContentValues();
static {
defaultValues.put(NAME, "");
defaultValues.put(NOTES, "");
defaultValues.put(PROGRESS_PERCENTAGE, 0);
defaultValues.put(IMPORTANCE, Importance.DEFAULT.ordinal());
defaultValues.put(ESTIMATED_SECONDS, 0);
defaultValues.put(ELAPSED_SECONDS, 0);
defaultValues.put(TIMER_START, 0);
defaultValues.put(DEFINITE_DUE_DATE, 0);
defaultValues.put(PREFERRED_DUE_DATE, 0);
defaultValues.put(HIDDEN_UNTIL, 0);
defaultValues.put(BLOCKING_ON, 0);
defaultValues.put(POSTPONE_COUNT, 0);
defaultValues.put(NOTIFICATIONS, 0);
defaultValues.put(NOTIFICATION_FLAGS, NOTIFY_AT_DEADLINE);
defaultValues.put(LAST_NOTIFIED, 0);
defaultValues.put(REPEAT, 0);
defaultValues.put(COMPLETION_DATE, 0);
defaultValues.put(CALENDAR_URI, (String)null);
defaultValues.put(FLAGS, 0);
}
// --- database helper
/** Database Helper manages creating new tables and updating old ones */
public static class TaskModelDatabaseHelper extends SQLiteOpenHelper {
String tableName;
Context context;
public TaskModelDatabaseHelper(Context context, String databaseName, String tableName) {
super(context, databaseName, null, VERSION);
this.tableName = tableName;
this.context = context;
}
@Override
public synchronized void onCreate(SQLiteDatabase db) {
String sql = new StringBuilder().
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
append(NAME).append(" text not null,").
append(NOTES).append(" text not null,").
append(PROGRESS_PERCENTAGE).append(" integer not null,").
append(IMPORTANCE).append(" integer not null,").
append(ESTIMATED_SECONDS).append(" integer,").
append(ELAPSED_SECONDS).append(" integer,").
append(TIMER_START).append(" integer,").
append(DEFINITE_DUE_DATE).append(" integer,").
append(PREFERRED_DUE_DATE).append(" integer,").
append(HIDDEN_UNTIL).append(" integer,").
append(BLOCKING_ON).append(" integer,").
append(POSTPONE_COUNT).append(" integer,").
append(NOTIFICATIONS).append(" integer,").
append(NOTIFICATION_FLAGS).append(" integer,").
append(LAST_NOTIFIED).append(" integer,").
append(REPEAT).append(" integer,").
append(FLAGS).append(" integer,").
append(CREATION_DATE).append(" integer,").
append(COMPLETION_DATE).append(" integer,").
append(CALENDAR_URI).append(" text").
append(");").toString();
db.execSQL(sql);
}
@Override
@SuppressWarnings("fallthrough")
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
oldVersion + " to " + newVersion + ".");
String sql;
// note: we execute sql statements in their own try block to be more
// graceful if an upgrade dies halfway or something
switch(oldVersion) {
case 1:
sql = new StringBuilder().append("ALTER TABLE ").
append(tableName).append(" ADD COLUMN ").
append(LAST_NOTIFIED).append(" integer").toString();
try {
db.execSQL(sql);
} catch (Exception e) {
Log.e("astrid", "Error updating table!", e);
}
sql = new StringBuilder().append("ALTER TABLE ").
append(tableName).append(" ADD COLUMN ").
append(NOTIFICATION_FLAGS).append(" integer").toString();
try {
db.execSQL(sql);
} catch (Exception e) {
Log.e("astrid", "Error updating table!", e);
}
case 2:
sql = new StringBuilder().append("ALTER TABLE ").
append(tableName).append(" ADD COLUMN ").
append(REPEAT).append(" integer").toString();
try {
db.execSQL(sql);
} catch (Exception e) {
Log.e("astrid", "Error updating table!", e);
}
case 3:
sql = new StringBuilder().append("ALTER TABLE ").
append(tableName).append(" ADD COLUMN ").
append(CALENDAR_URI).append(" text").toString();
try {
db.execSQL(sql);
} catch (Exception e) {
Log.e("astrid", "Error updating table!", e);
}
case 4:
sql = new StringBuilder().append("ALTER TABLE ").
append(tableName).append(" ADD COLUMN ").
append(POSTPONE_COUNT).append(" integer").toString();
try {
db.execSQL(sql);
} catch (Exception e) {
Log.e("astrid", "Error updating table!", e);
}
case 5:
case 6:
// apparently some people didn't get the flags column
// from version 5 to version 6, so we try again
sql = new StringBuilder().append("ALTER TABLE ").
append(tableName).append(" ADD COLUMN ").
append(FLAGS).append(" integer").toString();
try {
db.execSQL(sql);
} catch (Exception e) {
Log.e("astrid", "Error updating table!", e);
}
case 7:
// not a real change, but make sure that columns that are null
// are converted into zeros, which was my previous assumption
for(String column : new String[] {
ESTIMATED_SECONDS,
ELAPSED_SECONDS,
TIMER_START,
DEFINITE_DUE_DATE,
PREFERRED_DUE_DATE,
HIDDEN_UNTIL,
POSTPONE_COUNT,
LAST_NOTIFIED,
REPEAT,
CREATION_DATE,
COMPLETION_DATE }) {
sql = String.format("UPDATE %s SET %s = 0 WHERE %s ISNULL",
tableName, column, column);
try {
db.execSQL(sql);
} catch (Exception e) {
Log.e("astrid", "Error updating table!", e);
}
}
// --- break point
break;
default:
// we don't know how to handle it... show an error
Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion);
DialogUtilities.okDialog(context, "There was a database error reading from Alerts. Data may have been corrupted.", null);
}
}
}
// --- utility methods
/** Gets task color. Requires definiteDueDate and importance */
protected int getTaskColorResource(Context context) {
if(getDefiniteDueDate() != null && getDefiniteDueDate().getTime() <
System.currentTimeMillis()) {
return R.color.task_list_overdue;
} else if(Preferences.isColorize(context)) {
return getImportance().getTaskListColor();
} else {
return R.color.task_list_normal;
}
}
/** Checks whether task is done. Requires progressPercentage */
protected boolean isTaskCompleted() {
return getProgressPercentage() >= COMPLETE_PERCENTAGE;
}
/** Stops the timer & increments elapsed time. Requires timerStart and
* elapsedSeconds */
protected void stopTimerAndUpdateElapsedTime() {
if(getTimerStart() == null)
return;
long start = getTimerStart().getTime();
setTimerStart(null);
long secondsElapsed = (System.currentTimeMillis() - start)/1000;
setElapsedSeconds((int) (getElapsedSeconds() + secondsElapsed));
}
protected void prefetchData(String[] fields) {
for(String field : fields) {
if(field.equals(NAME))
getName();
else if(field.equals(NOTES))
getNotes();
else if(field.equals(PROGRESS_PERCENTAGE))
getProgressPercentage();
else if(field.equals(IMPORTANCE))
getImportance();
else if(field.equals(ESTIMATED_SECONDS))
getEstimatedSeconds();
else if(field.equals(ELAPSED_SECONDS))
getElapsedSeconds();
else if(field.equals(TIMER_START))
getTimerStart();
else if(field.equals(DEFINITE_DUE_DATE))
getDefiniteDueDate();
else if(field.equals(PREFERRED_DUE_DATE))
getPreferredDueDate();
else if(field.equals(HIDDEN_UNTIL))
getHiddenUntil();
else if(field.equals(BLOCKING_ON))
getBlockingOn();
else if(field.equals(POSTPONE_COUNT))
getPostponeCount();
else if(field.equals(NOTIFICATIONS))
getNotificationIntervalSeconds();
else if(field.equals(CREATION_DATE))
getCreationDate();
else if(field.equals(COMPLETION_DATE))
getCompletionDate();
else if(field.equals(NOTIFICATION_FLAGS))
getNotificationFlags();
else if(field.equals(LAST_NOTIFIED))
getLastNotificationDate();
else if(field.equals(REPEAT))
getRepeat();
else if(field.equals(FLAGS))
getFlags();
}
}
// --- helper classes
public static class RepeatInfo {
private final RepeatInterval interval;
private final int value;
public RepeatInfo(RepeatInterval repeatInterval, int value) {
this.interval = repeatInterval;
this.value = value;
}
public Date shiftDate(Date input) {
Date newDate = (Date)input.clone();
interval.offsetDateBy(newDate, value);
return newDate;
}
public RepeatInterval getInterval() {
return interval;
}
public int getValue() {
return value;
}
public static int toSingleField(RepeatInfo repeatInfo) {
int repeat;
if(repeatInfo == null)
repeat = 0;
else
repeat = (repeatInfo.value << REPEAT_VALUE_OFFSET) +
repeatInfo.interval.ordinal();
return repeat;
}
public static RepeatInfo fromSingleField(int repeat) {
if(repeat == 0)
return null;
int value = repeat >> REPEAT_VALUE_OFFSET;
RepeatInterval interval = RepeatInterval.values()
[repeat - (value << REPEAT_VALUE_OFFSET)];
return new RepeatInfo(interval, value);
}
}
// --- task identifier
private TaskIdentifier identifier = null;
public TaskIdentifier getTaskIdentifier() {
return identifier;
}
void setTaskIdentifier(TaskIdentifier identifier) {
this.identifier = identifier;
}
// --- constructors and abstract methods
AbstractTaskModel() {
super();
}
/** Read identifier from database */
AbstractTaskModel(Cursor cursor) {
super(cursor);
Integer id = retrieveInteger(AbstractController.KEY_ROWID);
setTaskIdentifier(new TaskIdentifier(id));
}
/** Get identifier from argument */
AbstractTaskModel(TaskIdentifier identifier, Cursor cursor) {
super(cursor);
setTaskIdentifier(identifier);
}
@Override
public ContentValues getDefaultValues() {
return defaultValues;
}
// --- getters and setters: expose them as you see fit
protected String getName() {
return retrieveString(NAME);
}
protected String getNotes() {
return retrieveString(NOTES);
}
protected int getProgressPercentage() {
return retrieveInteger(PROGRESS_PERCENTAGE);
}
protected Importance getImportance() {
Integer value = retrieveInteger(IMPORTANCE);
if(value == null)
return null;
return Importance.values()[value];
}
protected Integer getEstimatedSeconds() {
return retrieveInteger(ESTIMATED_SECONDS);
}
protected Integer getElapsedSeconds() {
return retrieveInteger(ELAPSED_SECONDS);
}
protected Date getTimerStart() {
return retrieveDate(TIMER_START);
}
protected Date getDefiniteDueDate() {
return retrieveDate(DEFINITE_DUE_DATE);
}
protected Date getPreferredDueDate() {
return retrieveDate(PREFERRED_DUE_DATE);
}
protected Date getHiddenUntil() {
return retrieveDate(HIDDEN_UNTIL);
}
protected boolean isHidden() {
if(getHiddenUntil() == null)
return false;
return getHiddenUntil().getTime() > System.currentTimeMillis();
}
protected Date getCreationDate() {
return retrieveDate(CREATION_DATE);
}
protected Date getCompletionDate() {
return retrieveDate(COMPLETION_DATE);
}
protected TaskIdentifier getBlockingOn() {
Long value = retrieveLong(BLOCKING_ON);
if(value == null)
return null;
return new TaskIdentifier(value);
}
protected Integer getPostponeCount() {
return retrieveInteger(POSTPONE_COUNT);
}
protected Integer getNotificationIntervalSeconds() {
return retrieveInteger(NOTIFICATIONS);
}
protected int getNotificationFlags() {
return retrieveInteger(NOTIFICATION_FLAGS);
}
protected Date getLastNotificationDate() {
return retrieveDate(LAST_NOTIFIED);
}
protected RepeatInfo getRepeat() {
int repeat = retrieveInteger(REPEAT);
if(repeat == 0)
return null;
int value = repeat >> REPEAT_VALUE_OFFSET;
RepeatInterval interval = RepeatInterval.values()
[repeat - (value << REPEAT_VALUE_OFFSET)];
return new RepeatInfo(interval, value);
}
protected String getCalendarUri() {
String uri = retrieveString(CALENDAR_URI);
if(uri != null && uri.length() == 0)
return null;
else
return uri;
}
protected int getFlags() {
return retrieveInteger(FLAGS);
}
// --- setters
protected void setName(String name) {
putIfChangedFromDatabase(NAME, name);
}
protected void setNotes(String notes) {
putIfChangedFromDatabase(NOTES, notes);
}
protected void setProgressPercentage(int progressPercentage) {
putIfChangedFromDatabase(PROGRESS_PERCENTAGE, progressPercentage);
if(getProgressPercentage() != progressPercentage &&
progressPercentage == COMPLETE_PERCENTAGE)
setCompletionDate(new Date());
}
protected void setImportance(Importance importance) {
putIfChangedFromDatabase(IMPORTANCE, importance.ordinal());
}
protected void setEstimatedSeconds(Integer estimatedSeconds) {
putIfChangedFromDatabase(ESTIMATED_SECONDS, estimatedSeconds);
}
protected void setElapsedSeconds(int elapsedSeconds) {
putIfChangedFromDatabase(ELAPSED_SECONDS, elapsedSeconds);
}
protected void setTimerStart(Date timerStart) {
putDate(TIMER_START, timerStart);
}
protected void setDefiniteDueDate(Date definiteDueDate) {
putDate(DEFINITE_DUE_DATE, definiteDueDate);
}
protected void setPreferredDueDate(Date preferredDueDate) {
putDate(PREFERRED_DUE_DATE, preferredDueDate);
}
protected void setHiddenUntil(Date hiddenUntil) {
putDate(HIDDEN_UNTIL, hiddenUntil);
}
protected void setBlockingOn(TaskIdentifier blockingOn) {
if(blockingOn == null || blockingOn.equals(getTaskIdentifier()))
putIfChangedFromDatabase(BLOCKING_ON, (Integer)null);
else
putIfChangedFromDatabase(BLOCKING_ON, blockingOn.getId());
}
protected void setPostponeCount(int postponeCount) {
putIfChangedFromDatabase(POSTPONE_COUNT, postponeCount);
}
protected void setCreationDate(Date creationDate) {
putDate(CREATION_DATE, creationDate);
}
protected void setCompletionDate(Date completionDate) {
putDate(COMPLETION_DATE, completionDate);
}
protected void setNotificationIntervalSeconds(Integer intervalInSeconds) {
putIfChangedFromDatabase(NOTIFICATIONS, intervalInSeconds);
}
protected void setNotificationFlags(int flags) {
putIfChangedFromDatabase(NOTIFICATION_FLAGS, flags);
}
protected void setLastNotificationTime(Date date) {
putDate(LAST_NOTIFIED, date);
}
protected void setRepeat(RepeatInfo repeatInfo) {
int repeat;
if(repeatInfo == null)
repeat = 0;
else
repeat = (repeatInfo.value << REPEAT_VALUE_OFFSET) +
repeatInfo.interval.ordinal();
putIfChangedFromDatabase(REPEAT, repeat);
}
protected void setCalendarUri(String uri) {
putIfChangedFromDatabase(CALENDAR_URI, uri);
}
protected void setFlags(int flags) {
putIfChangedFromDatabase(FLAGS, flags);
}
// --- utility methods
protected void putDate(String fieldName, Date date) {
if(date == null)
putIfChangedFromDatabase(fieldName, 0);
else
putIfChangedFromDatabase(fieldName, date.getTime());
}
}

@ -1,656 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.util.Log;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.alerts.AlertController;
import com.timsu.astrid.data.sync.SyncDataController;
import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo;
import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper;
import com.timsu.astrid.provider.TasksProvider;
import com.todoroo.astrid.widget.TasksWidget.UpdateService;
/**
* Controller for task-related operations
*
* @author timsu
*
*/
public class TaskController extends AbstractController {
private SQLiteDatabase database;
// --- task list operations
/** Return a list of all active tasks with notifications */
public HashSet<TaskModelForNotify> getTasksWithNotifications() {
HashSet<TaskModelForNotify> list = new HashSet<TaskModelForNotify>();
Cursor cursor = database.query(tasksTable, TaskModelForNotify.FIELD_LIST,
String.format("%s < %d AND (%s != 0 OR %s != 0)",
AbstractTaskModel.PROGRESS_PERCENTAGE,
AbstractTaskModel.COMPLETE_PERCENTAGE,
AbstractTaskModel.NOTIFICATIONS,
AbstractTaskModel.NOTIFICATION_FLAGS), null, null, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new TaskModelForNotify(cursor));
} while(!cursor.isLast());
return list;
} finally {
cursor.close();
}
}
/** Return a list of all active tasks with deadlines */
public ArrayList<TaskModelForNotify> getTasksWithDeadlines() {
ArrayList<TaskModelForNotify> list = new ArrayList<TaskModelForNotify>();
Cursor cursor = database.query(tasksTable, TaskModelForNotify.FIELD_LIST,
String.format("%s < %d AND (%s != 0 OR %s != 0)",
AbstractTaskModel.PROGRESS_PERCENTAGE,
AbstractTaskModel.COMPLETE_PERCENTAGE,
AbstractTaskModel.DEFINITE_DUE_DATE,
AbstractTaskModel.PREFERRED_DUE_DATE), null, null, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new TaskModelForNotify(cursor));
} while(!cursor.isLast());
return list;
} finally {
cursor.close();
}
}
/** Return a list of all of the tasks with progress < COMPLETE_PERCENTAGE */
public Cursor getActiveTaskListCursor() {
return database.query(tasksTable, TaskModelForList.FIELD_LIST,
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
AbstractTaskModel.COMPLETE_PERCENTAGE, null, null, null,
null, null);
}
/** Return a list of all of the tasks matching selection */
public Cursor getMatchingTasksForProvider(String selection,
String[] selectionArgs) {
return database.query(tasksTable, TaskModelForProvider.FIELD_LIST,
selection, selectionArgs, null, null,
null, null);
}
/** Return a list of all tasks */
public Cursor getAllTaskListCursor() {
return database.query(tasksTable, TaskModelForList.FIELD_LIST,
null, null, null, null, null, null);
}
/** Return a list of all tasks */
public Cursor getBackupTaskListCursor() {
return database.query(tasksTable, TaskModelForXml.FIELD_LIST,
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
AbstractTaskModel.COMPLETE_PERCENTAGE, null, null, null,
null, null);
}
/** Delete all completed tasks with date < older than date */
public int deleteCompletedTasksOlderThan(Date olderThanDate) {
return database.delete(tasksTable, String.format("`%s` >= '%d' AND `%s` <= '%d'",
AbstractTaskModel.PROGRESS_PERCENTAGE, AbstractTaskModel.COMPLETE_PERCENTAGE,
AbstractTaskModel.COMPLETION_DATE, olderThanDate.getTime()), null);
}
/** Create a list of tasks from the db cursor given */
public ArrayList<TaskModelForList> createTaskListFromCursor(Cursor cursor) {
ArrayList<TaskModelForList> list = new ArrayList<TaskModelForList>();
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new TaskModelForList(cursor));
} while(!cursor.isLast());
return list;
}
/** Helper method to take a cursor pointing to a list of id's and generate
* a hashset */
private HashSet<TaskIdentifier> createTaskIdentifierSet(Cursor cursor) {
HashSet<TaskIdentifier> list = new HashSet<TaskIdentifier>();
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new TaskIdentifier(cursor.getInt(
cursor.getColumnIndexOrThrow(KEY_ROWID))));
} while(!cursor.isLast());
return list;
} finally {
cursor.close();
}
}
/** Get identifiers for all tasks */
public HashSet<TaskIdentifier> getAllTaskIdentifiers() {
Cursor cursor = database.query(tasksTable, new String[] { KEY_ROWID },
null, null, null, null, null, null);
return createTaskIdentifierSet(cursor);
}
/** Get identifiers for all non-completed tasks */
public HashSet<TaskIdentifier> getActiveTaskIdentifiers() {
Cursor cursor = database.query(tasksTable, new String[] { KEY_ROWID },
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
AbstractTaskModel.COMPLETE_PERCENTAGE, null, null, null, null, null);
return createTaskIdentifierSet(cursor);
}
/** Get identifiers for all non-completed, non-hidden tasks */
public HashSet<TaskIdentifier> getActiveVisibleTaskIdentifiers() {
Cursor cursor = database.query(tasksTable, new String[] { KEY_ROWID },
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
AbstractTaskModel.COMPLETE_PERCENTAGE + " AND (" +
AbstractTaskModel.HIDDEN_UNTIL + " ISNULL OR " + AbstractTaskModel.HIDDEN_UNTIL + " < " +
System.currentTimeMillis() + ")", null, null, null, null, null);
return createTaskIdentifierSet(cursor);
}
/** Create a weighted list of tasks from the db cursor given */
public Cursor getTaskListCursorById(List<TaskIdentifier> idList) {
StringBuilder where = new StringBuilder();
for(int i = 0; i < idList.size(); i++) {
where.append(KEY_ROWID);
where.append("=");
where.append(idList.get(i).idAsString());
if(i < idList.size()-1)
where.append(" OR ");
}
// hack for empty arrays
if(idList.size() == 0)
where.append("0");
return database.query(true, tasksTable,
TaskModelForList.FIELD_LIST, where.toString(), null, null,
null, null, null);
}
// --- single task operations
/** Delete the given task */
public boolean deleteTask(TaskIdentifier taskId) {
if(taskId == null)
throw new UnsupportedOperationException("Cannot delete uncreated task!");
long id = taskId.getId();
cleanupTask(taskId, false);
// notify modification
TasksProvider.notifyDatabaseModification();
return database.delete(tasksTable, KEY_ROWID + "=" + id, null) > 0;
}
/** Saves the given task to the database. Returns true on success.
*
* @param duringSync set to true when save is part of a synchronize
*/
public boolean saveTask(AbstractTaskModel task, boolean duringSync) {
boolean saveSucessful;
if(task.getTaskIdentifier() == null) {
long newRow = database.insert(tasksTable, AbstractTaskModel.NAME,
task.getMergedValues());
task.setTaskIdentifier(new TaskIdentifier(newRow));
saveSucessful = newRow >= 0;
} else {
long id = task.getTaskIdentifier().getId();
ContentValues values = task.getSetValues();
if(values.size() == 0) // nothing changed
return true;
onTaskSave(task, values, duringSync);
saveSucessful = database.update(tasksTable, values,
KEY_ROWID + "=" + id, null) > 0;
// task was completed
if(values.containsKey(AbstractTaskModel.PROGRESS_PERCENTAGE) &&
values.getAsInteger(AbstractTaskModel.PROGRESS_PERCENTAGE)
== AbstractTaskModel.COMPLETE_PERCENTAGE) {
onTaskCompleted(task, values, duringSync);
}
SyncDataController.taskUpdated(context, task);
}
// notify widget that something changed
if(saveSucessful) {
Intent intent = new Intent(context, UpdateService.class);
context.startService(intent);
}
// notify modification
TasksProvider.notifyDatabaseModification();
return saveSucessful;
}
/**
* Called when the task is saved. Perform some processing on the task.
*
* @param task
* @param values
*/
private void onTaskSave(AbstractTaskModel task, ContentValues values, boolean duringSync) {
// save task completed date
if(values.containsKey(AbstractTaskModel.PROGRESS_PERCENTAGE) &&
values.getAsInteger(AbstractTaskModel.PROGRESS_PERCENTAGE)
== AbstractTaskModel.COMPLETE_PERCENTAGE) {
values.put(AbstractTaskModel.COMPLETION_DATE, System.currentTimeMillis());
}
// task timer was updated, update notification bar
if(values.containsKey(AbstractTaskModel.TIMER_START)) {
// show notification bar if timer was started
// if(values.getAsLong(AbstractTaskModel.TIMER_START) != 0) {
// ReminderService.showTimingNotification(context,
// task.getTaskIdentifier(), task.getName());
// } else {
// ReminderService.clearAllNotifications(context, task.getTaskIdentifier());
// }
}
// due date was updated, update calendar event
if((values.containsKey(AbstractTaskModel.DEFINITE_DUE_DATE) ||
values.containsKey(AbstractTaskModel.PREFERRED_DUE_DATE)) &&
!values.containsKey(AbstractTaskModel.CALENDAR_URI)) {
try {
Cursor cursor = fetchTaskCursor(task.getTaskIdentifier(),
new String[] { AbstractTaskModel.CALENDAR_URI });
cursor.moveToFirst();
String uriAsString = cursor.getString(0);
cursor.close();
if(uriAsString != null && uriAsString.length() > 0) {
ContentResolver cr = context.getContentResolver();
Uri uri = Uri.parse(uriAsString);
Integer estimated = null;
if(values.containsKey(AbstractTaskModel.ESTIMATED_SECONDS))
estimated = values.getAsInteger(AbstractTaskModel.ESTIMATED_SECONDS);
else { // read from event
Cursor event = cr.query(uri, new String[] {"dtstart", "dtend"},
null, null, null);
event.moveToFirst();
estimated = (event.getInt(1) - event.getInt(0))/1000;
}
// create new start and end date for this event
ContentValues newValues = new ContentValues();
/*TaskEditActivity.createCalendarStartEndTimes(task.getPreferredDueDate(),
task.getDefiniteDueDate(), estimated, newValues); TODO */
cr.update(uri, newValues, null, null);
}
} catch (Exception e) {
// ignore calendar event - event could be deleted or whatever
Log.e("astrid", "Error moving calendar event", e);
}
}
}
/**
* Called when this task is set to completed.
*
* @param task task to process
* @param values mutable map of values to save
*/
private void onTaskCompleted(AbstractTaskModel task, ContentValues values, boolean duringSync) {
Cursor cursor = fetchTaskCursor(task.getTaskIdentifier(),
TaskModelForHandlers.FIELD_LIST);
TaskModelForHandlers model = new TaskModelForHandlers(cursor, values);
// handle repeat
RepeatInfo repeatInfo = model.getRepeat();
if(repeatInfo != null) {
model.repeatTaskBy(context, this, repeatInfo);
database.update(tasksTable, values, KEY_ROWID + "=" +
task.getTaskIdentifier().getId(), null);
}
// handle sync-on-complete
if((model.getFlags() & TaskModelForHandlers.FLAG_SYNC_ON_COMPLETE) > 0 &&
!duringSync) {
// Synchronizer synchronizer = new Synchronizer(model.getTaskIdentifier());
// synchronizer.synchronize(context, new SynchronizerListener() {
// public void onSynchronizerFinished(int numServicesSynced) {
//// TaskListSubActivity.shouldRefreshTaskList = true;
// }
// });
}
cursor.close();
cleanupTask(task.getTaskIdentifier(), repeatInfo != null);
}
/** Clean up state from a task. Called when deleting or completing it */
private void cleanupTask(TaskIdentifier taskId, boolean isRepeating) {
// delete notifications & alarms
// ReminderService.deleteAlarm(context, null, taskId.getId());
// delete calendar event if not repeating
if(!isRepeating) {
try {
Cursor cursor = fetchTaskCursor(taskId, new String[] {
AbstractTaskModel.CALENDAR_URI });
cursor.moveToFirst();
String uri = cursor.getString(0);
cursor.close();
if(uri != null && uri.length() > 0) {
ContentResolver cr = context.getContentResolver();
cr.delete(Uri.parse(uri), null, null);
ContentValues values = new ContentValues();
values.put(AbstractTaskModel.CALENDAR_URI, (String)null);
database.update(tasksTable, values, KEY_ROWID + "=" +
taskId.getId(), null);
}
} catch (Exception e) {
Log.e("astrid", "Error deleting calendar event", e);
}
}
}
/** Set last notification date */
public boolean setLastNotificationTime(TaskIdentifier taskId, Date date) {
ContentValues values = new ContentValues();
values.put(AbstractTaskModel.LAST_NOTIFIED, date.getTime());
return database.update(tasksTable, values,
KEY_ROWID + "=" + taskId.getId(), null) > 0;
}
// --- fetching different models
/** Creates a new task and returns the task identifier */
public TaskModelForEdit createNewTaskForEdit() {
TaskModelForEdit task = new TaskModelForEdit();
task.setTaskIdentifier(null);
return task;
}
/** Returns a TaskModelForEdit corresponding to the given TaskIdentifier */
public TaskModelForEdit fetchTaskForEdit(Activity activity, TaskIdentifier
taskId) throws SQLException {
Cursor cursor = fetchTaskCursor(taskId, TaskModelForEdit.FIELD_LIST);
if(cursor == null)
return null;
activity.startManagingCursor(cursor);
TaskModelForEdit model = new TaskModelForEdit(taskId, cursor);
return model;
}
/** Returns a TaskModelForList corresponding to the given TaskIdentifier */
public TaskModelForList fetchTaskForList(TaskIdentifier taskId) throws SQLException {
Cursor cursor = fetchTaskCursor(taskId, TaskModelForList.FIELD_LIST);
if(cursor == null)
return null;
TaskModelForList model = new TaskModelForList(cursor);
cursor.close();
return model;
}
/** Returns a TaskModelForXml corresponding to the given TaskIdentifier */
public TaskModelForXml fetchTaskForXml(TaskIdentifier taskId) throws SQLException {
Cursor cursor = fetchTaskCursor(taskId, TaskModelForXml.FIELD_LIST);
if(cursor == null)
return null;
TaskModelForXml model = new TaskModelForXml(cursor);
cursor.close();
return model;
}
/* Attempts to return a TaskModelForXml for the given name and creation date */
public TaskModelForXml fetchTaskForXml(String name, Date creationDate) {
Cursor cursor;
try {
cursor = fetchTaskCursor(name, creationDate.getTime(),
TaskModelForXml.FIELD_LIST);
} catch (SQLException e) {
return null;
}
if (cursor == null || cursor.getCount() == 0) {
return null;
}
TaskModelForXml model = new TaskModelForXml(cursor);
cursor.close();
return model;
}
/** Returns a TaskModelForReminder corresponding to the given TaskIdentifier */
public TaskModelForReminder fetchTaskForReminder(TaskIdentifier taskId) throws SQLException {
Cursor cursor = fetchTaskCursor(taskId, TaskModelForReminder.FIELD_LIST);
TaskModelForReminder model = new TaskModelForReminder(cursor);
cursor.close();
return model;
}
/** Returns a TaskModelForSync corresponding to the given TaskIdentifier */
public TaskModelForSync fetchTaskForSync(TaskIdentifier taskId) throws SQLException {
Cursor cursor = fetchTaskCursor(taskId, TaskModelForSync.FIELD_LIST);
TaskModelForSync model = new TaskModelForSync(cursor);
cursor.close();
return model;
}
/** Returns a TaskModelForView by name */
public TaskModelForSync searchForTaskForSync(String name) throws SQLException {
Cursor cursor = database.query(true, tasksTable, TaskModelForSync.FIELD_LIST,
AbstractTaskModel.NAME + " = ? AND " +
AbstractTaskModel.PROGRESS_PERCENTAGE + " < "+
AbstractTaskModel.COMPLETE_PERCENTAGE,
new String[] { name }, null, null, null, null);
try {
if (cursor == null || cursor.getCount() == 0)
return null;
cursor.moveToFirst();
TaskModelForSync model = new TaskModelForSync(cursor);
return model;
} finally {
if(cursor != null)
cursor.close();
}
}
/** Returns a TaskModelForView corresponding to the given TaskIdentifier */
public TaskModelForNotify fetchTaskForNotify(TaskIdentifier taskId) throws SQLException {
Cursor cursor = fetchTaskCursor(taskId, TaskModelForNotify.FIELD_LIST);
TaskModelForNotify model = new TaskModelForNotify(cursor);
cursor.close();
return model;
}
/** Moves cursor to the task.
* Don't forget to close the cursor when you're done. */
private Cursor fetchTaskCursor(TaskIdentifier taskId, String[] fieldList) {
long id = taskId.getId();
Cursor cursor = database.query(true, tasksTable, fieldList,
KEY_ROWID + "=" + id, null, null, null, null, null);
if (cursor == null)
throw new SQLException("Returned empty set!");
cursor.moveToFirst();
return cursor;
}
/** Returns null if unsuccessful, otherwise moves cursor to the task.
* Don't forget to close the cursor when you're done. */
private Cursor fetchTaskCursor(String name, long creationDate, String[] fieldList) {
// truncate millis
final String where = AbstractTaskModel.NAME + " = ? AND "
+ AbstractTaskModel.CREATION_DATE + " LIKE ?";
String approximateCreationDate = (creationDate / 1000) + "%";
Cursor cursor = database.query(true, tasksTable, fieldList,
where, new String[] {name, approximateCreationDate}, null, null, null, null);
if (cursor == null)
throw new SQLException("Returned empty set!");
if (cursor.moveToFirst()) {
return cursor;
}
cursor.close();
return null;
}
// --- methods supporting individual features
/** Returns a TaskModelForView corresponding to the given TaskIdentifier */
public int fetchTaskPostponeCount(TaskIdentifier taskId) throws SQLException {
Cursor cursor = fetchTaskCursor(taskId, new String[] {AbstractTaskModel.POSTPONE_COUNT});
try {
if (cursor == null || cursor.getCount() == 0)
return 0;
cursor.moveToFirst();
return cursor.getInt(0);
} catch (Exception e) {
return 0;
} finally {
if(cursor != null)
cursor.close();
}
}
/** Updates the alarm for the task identified by the given id */
public void updateAlarmForTask(TaskIdentifier taskId) throws SQLException {
TaskModelForNotify task = fetchTaskForNotify(taskId);
AlertController alertController = new AlertController(context);
alertController.open();
// ReminderService.updateAlarm(context, this, alertController, task);
alertController.close();
}
public ArrayList<TaskModelForWidget> getTasksForWidget(String limit) {
Cursor cursor = database.query(tasksTable, TaskModelForWidget.FIELD_LIST,
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
AbstractTaskModel.COMPLETE_PERCENTAGE + " AND (" +
AbstractTaskModel.HIDDEN_UNTIL + " ISNULL OR " + AbstractTaskModel.HIDDEN_UNTIL + " < " +
System.currentTimeMillis() + ")", null, null, null,
AbstractTaskModel.IMPORTANCE + " * " + (5 * 24 * 3600 * 1000L) +
" + CASE WHEN MAX(pdd, ddd) = 0 THEN " +
(System.currentTimeMillis() + (7 * 24 * 3600 * 1000L)) +
" ELSE (CASE WHEN pdd = 0 THEN ddd ELSE pdd END) END ASC", limit);
try {
ArrayList<TaskModelForWidget> list = new ArrayList<TaskModelForWidget>();
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext())
list.add(new TaskModelForWidget(cursor));
return list;
} finally {
cursor.close();
}
}
public ArrayList<TaskModelForProvider> getTasksForProvider(String limit) {
Cursor cursor = database.query(tasksTable, TaskModelForProvider.FIELD_LIST,
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
AbstractTaskModel.COMPLETE_PERCENTAGE + " AND (" +
AbstractTaskModel.HIDDEN_UNTIL + " ISNULL OR " + AbstractTaskModel.HIDDEN_UNTIL + " < " +
System.currentTimeMillis() + ")", null, null, null,
AbstractTaskModel.IMPORTANCE + " * " + (5 * 24 * 3600 * 1000L) +
" + CASE WHEN MAX(pdd, ddd) = 0 THEN " +
(System.currentTimeMillis() + (7 * 24 * 3600 * 1000L)) +
" ELSE (CASE WHEN pdd = 0 THEN ddd ELSE pdd END) END ASC", limit);
try {
ArrayList<TaskModelForProvider> list = new ArrayList<TaskModelForProvider>();
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext())
list.add(new TaskModelForProvider(cursor));
return list;
} finally {
cursor.close();
}
}
// --- boilerplate
/**
* Constructor - takes the context to allow the database to be
* opened/created
*/
public TaskController(Context context) {
super(context);
}
/**
* Open the notes database. If it cannot be opened, try to create a new
* instance of the database. If it cannot be created, throw an exception to
* signal the failure
*
* @return this (self reference, allowing this to be chained in an
* initialization call)
* @throws SQLException if the database could be neither opened or created
*/
@Override
public synchronized void open() throws SQLException {
SQLiteOpenHelper databaseHelper = new TaskModelDatabaseHelper(
context, tasksTable, tasksTable);
database = databaseHelper.getWritableDatabase();
}
/** Closes database resource */
@Override
public void close() {
database.close();
}
}

@ -1,30 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import com.timsu.astrid.data.Identifier;
public class TaskIdentifier extends Identifier {
public TaskIdentifier(long id) {
super(id);
}
}

@ -1,208 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import java.util.Date;
import android.database.Cursor;
import com.timsu.astrid.data.enums.Importance;
/** Fields that you would want to edit in the TaskModel */
public class TaskModelForEdit extends AbstractTaskModel {
static String[] FIELD_LIST = new String[] {
NAME,
IMPORTANCE,
ESTIMATED_SECONDS,
ELAPSED_SECONDS,
DEFINITE_DUE_DATE,
PREFERRED_DUE_DATE,
HIDDEN_UNTIL,
BLOCKING_ON,
NOTIFICATIONS,
NOTIFICATION_FLAGS,
LAST_NOTIFIED,
PROGRESS_PERCENTAGE,
NOTES,
REPEAT,
CALENDAR_URI,
};
// --- constructors
public TaskModelForEdit() {
super();
setCreationDate(new Date());
}
public TaskModelForEdit(TaskIdentifier identifier, Cursor cursor) {
super(identifier, cursor);
}
// --- getters and setters
@Override
public boolean isTaskCompleted() {
return super.isTaskCompleted();
}
@Override
public Integer getNotificationIntervalSeconds() {
return super.getNotificationIntervalSeconds();
}
@Override
public void setNotificationIntervalSeconds(Integer intervalInSeconds) {
super.setNotificationIntervalSeconds(intervalInSeconds);
}
@Override
public Date getDefiniteDueDate() {
return super.getDefiniteDueDate();
}
@Override
public Integer getEstimatedSeconds() {
return super.getEstimatedSeconds();
}
@Override
public Integer getElapsedSeconds() {
return super.getElapsedSeconds();
}
@Override
public Date getHiddenUntil() {
return super.getHiddenUntil();
}
@Override
public Importance getImportance() {
return super.getImportance();
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getNotes() {
return super.getNotes();
}
@Override
public Date getPreferredDueDate() {
return super.getPreferredDueDate();
}
@Override
public int getProgressPercentage() {
return super.getProgressPercentage();
}
@Override
public TaskIdentifier getBlockingOn() {
return super.getBlockingOn();
}
@Override
public int getNotificationFlags() {
return super.getNotificationFlags();
}
@Override
public Date getLastNotificationDate() {
return super.getLastNotificationDate();
}
@Override
public RepeatInfo getRepeat() {
return super.getRepeat();
}
@Override
public String getCalendarUri() {
return super.getCalendarUri();
}
@Override
public void setDefiniteDueDate(Date definiteDueDate) {
super.setDefiniteDueDate(definiteDueDate);
}
@Override
public void setEstimatedSeconds(Integer estimatedSeconds) {
super.setEstimatedSeconds(estimatedSeconds);
}
@Override
public void setElapsedSeconds(int elapsedSeconds) {
super.setElapsedSeconds(elapsedSeconds);
}
@Override
public void setHiddenUntil(Date hiddenUntil) {
super.setHiddenUntil(hiddenUntil);
}
@Override
public void setImportance(Importance importance) {
super.setImportance(importance);
}
@Override
public void setName(String name) {
super.setName(name);
}
@Override
public void setNotes(String notes) {
super.setNotes(notes);
}
@Override
public void setPreferredDueDate(Date preferredDueDate) {
super.setPreferredDueDate(preferredDueDate);
}
@Override
public void setBlockingOn(TaskIdentifier blockingOn) {
super.setBlockingOn(blockingOn);
}
@Override
public void setNotificationFlags(int flags) {
super.setNotificationFlags(flags);
}
@Override
public void setRepeat(RepeatInfo taskRepeat) {
super.setRepeat(taskRepeat);
}
@Override
public void setCalendarUri(String uri) {
super.setCalendarUri(uri);
}
}

@ -1,170 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import java.util.Date;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.alerts.AlertController;
/** Fields that you would want to read or edit in the onTaskSave and onTaskComplete
* event handlers */
public class TaskModelForHandlers extends AbstractTaskModel {
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
REPEAT,
DEFINITE_DUE_DATE,
PREFERRED_DUE_DATE,
HIDDEN_UNTIL,
PROGRESS_PERCENTAGE,
ESTIMATED_SECONDS,
LAST_NOTIFIED,
NOTIFICATIONS,
NOTIFICATION_FLAGS,
FLAGS,
};
/**
* This method updates the task to reflect a new repeat iteration. It moves
* back the due dates and updates other task properties accordingly.
*
* @param context
* @param taskController
* @param repeatInfo
*/
public void repeatTaskBy(Context context, TaskController taskController,
RepeatInfo repeatInfo) {
// move dates back
if(getDefiniteDueDate() != null)
setDefiniteDueDate(repeatInfo.shiftDate(getDefiniteDueDate()));
if(getHiddenUntil() != null)
setHiddenUntil(repeatInfo.shiftDate(getHiddenUntil()));
if(getPreferredDueDate() != null)
setPreferredDueDate(repeatInfo.shiftDate(getPreferredDueDate()));
setProgressPercentage(0);
// set elapsed time to 0... yes, we're losing data
setElapsedSeconds(0);
// if no deadlines set, create one (so users don't get confused)
if(getDefiniteDueDate() == null && getPreferredDueDate() == null)
setPreferredDueDate(repeatInfo.shiftDate(new Date()));
// shift fixed alerts
AlertController alertController = new AlertController(context);
alertController.open();
List<Date> alerts = alertController.getTaskAlerts(getTaskIdentifier());
alertController.removeAlerts(getTaskIdentifier());
for(int i = 0; i < alerts.size(); i++) {
Date newAlert = repeatInfo.shiftDate(alerts.get(i));
alertController.addAlert(getTaskIdentifier(), newAlert);
alerts.set(i, newAlert);
}
// reset periodic alerts
setLastNotificationTime(null);
// ReminderService.updateAlarm(context, taskController, alertController, this);
alertController.close();
}
// --- constructors
public TaskModelForHandlers(Cursor cursor, ContentValues setValues) {
super(cursor);
this.setValues = setValues;
}
// --- getters and setters
@Override
public RepeatInfo getRepeat() {
return super.getRepeat();
}
@Override
public Integer getNotificationIntervalSeconds() {
return super.getNotificationIntervalSeconds();
}
@Override
public boolean isTaskCompleted() {
return super.isTaskCompleted();
}
@Override
public Date getDefiniteDueDate() {
return super.getDefiniteDueDate();
}
@Override
public Integer getEstimatedSeconds() {
return super.getEstimatedSeconds();
}
@Override
public Date getHiddenUntil() {
return super.getHiddenUntil();
}
@Override
public Date getPreferredDueDate() {
return super.getPreferredDueDate();
}
@Override
public int getNotificationFlags() {
return super.getNotificationFlags();
}
@Override
public Date getLastNotificationDate() {
return super.getLastNotificationDate();
}
@Override
public int getFlags() {
return super.getFlags();
}
@Override
public void setDefiniteDueDate(Date definiteDueDate) {
super.setDefiniteDueDate(definiteDueDate);
}
@Override
public void setPreferredDueDate(Date preferredDueDate) {
super.setPreferredDueDate(preferredDueDate);
}
@Override
public void setHiddenUntil(Date hiddenUntil) {
super.setHiddenUntil(hiddenUntil);
}
}

@ -1,267 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import java.util.Date;
import java.util.HashMap;
import android.content.Context;
import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.enums.Importance;
/** Fields that you would want to edit in the TaskModel */
public class TaskModelForList extends AbstractTaskModel {
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
NAME,
IMPORTANCE,
ELAPSED_SECONDS,
ESTIMATED_SECONDS,
TIMER_START,
DEFINITE_DUE_DATE,
PREFERRED_DUE_DATE,
NOTIFICATIONS,
PROGRESS_PERCENTAGE,
COMPLETION_DATE,
CREATION_DATE,
HIDDEN_UNTIL,
NOTES,
REPEAT,
FLAGS,
};
// pre-load the cache for our column keys
static {
HashMap<String, Integer> indexCache = new HashMap<String, Integer>();
columnIndexCache.put(TaskModelForList.class, indexCache);
for(int i = 0; i < FIELD_LIST.length; i++)
indexCache.put(FIELD_LIST[i], i);
}
/** Get the weighted score for this task. Smaller is more important */
public int getTaskWeight() {
int weight = 0;
// bubble tasks with timers to the top
if(getTimerStart() != null)
weight -= 10000;
// importance
weight += getImportance().ordinal() * 80;
// looming absolute deadline
if(getDefiniteDueDate() != null) {
int hoursLeft = (int) ((getDefiniteDueDate().getTime() -
System.currentTimeMillis())/1000/3600);
if(hoursLeft < 5*24)
weight += (hoursLeft - 5*24);
weight -= 20;
}
// looming preferred deadline
if(getPreferredDueDate() != null) {
int hoursLeft = (int) ((getPreferredDueDate().getTime() -
System.currentTimeMillis())/1000/3600);
if(hoursLeft < 5*24)
weight += (hoursLeft - 5*24)/2;
weight -= 10;
}
// bubble completed tasks to the bottom
if(isTaskCompleted()) {
if(getCompletionDate() == null)
weight += 1e6;
else
weight = (int)Math.max(10000 + (System.currentTimeMillis() -
getCompletionDate().getTime()) / 1000, 10000);
return weight;
}
return weight;
}
@Override
public boolean isHidden() {
return super.isHidden();
}
/** map of cached display labels */
private final HashMap<Integer, String> displayLabels = new HashMap<Integer, String>();
public String getCachedLabel(int key) {
return displayLabels.get(key);
}
public void putCachedLabel(int key, String value) {
displayLabels.put(key, value);
}
public void clearCache() {
displayLabels.clear();
}
// --- constructors
public TaskModelForList(Cursor cursor) {
super(cursor);
prefetchData(FIELD_LIST);
}
// --- exposed getters and setters
@Override
public boolean isTaskCompleted() {
return super.isTaskCompleted();
}
@Override
public int getTaskColorResource(Context context) {
return super.getTaskColorResource(context);
}
@Override
public Integer getElapsedSeconds() {
return super.getElapsedSeconds();
}
public static int getCompletedPercentage() {
return COMPLETE_PERCENTAGE;
}
@Override
public Date getDefiniteDueDate() {
return super.getDefiniteDueDate();
}
@Override
public Integer getEstimatedSeconds() {
return super.getEstimatedSeconds();
}
@Override
public Date getHiddenUntil() {
return super.getHiddenUntil();
}
@Override
public Importance getImportance() {
return super.getImportance();
}
@Override
public String getName() {
return super.getName();
}
@Override
public Date getPreferredDueDate() {
return super.getPreferredDueDate();
}
@Override
public int getProgressPercentage() {
return super.getProgressPercentage();
}
@Override
public Date getTimerStart() {
return super.getTimerStart();
}
@Override
public Date getCompletionDate() {
return super.getCompletionDate();
}
@Override
public String getNotes() {
return super.getNotes();
}
@Override
public Integer getNotificationIntervalSeconds() {
return super.getNotificationIntervalSeconds();
}
@Override
public RepeatInfo getRepeat() {
return super.getRepeat();
}
@Override
public Date getCreationDate() {
return super.getCreationDate();
}
@Override
public int getFlags() {
return super.getFlags();
}
// --- setters
@Override
public void setProgressPercentage(int progressPercentage) {
super.setProgressPercentage(progressPercentage);
}
@Override
public void setTimerStart(Date timerStart) {
super.setTimerStart(timerStart);
}
@Override
public void stopTimerAndUpdateElapsedTime() {
super.stopTimerAndUpdateElapsedTime();
}
public static String getNameField() {
return NAME;
}
@Override
public void setPreferredDueDate(Date preferredDueDate) {
super.setPreferredDueDate(preferredDueDate);
}
@Override
public void setDefiniteDueDate(Date definiteDueDate) {
super.setDefiniteDueDate(definiteDueDate);
}
@Override
public void setImportance(Importance importance) {
super.setImportance(importance);
}
@Override
public void setHiddenUntil(Date hiddenUntil) {
super.setHiddenUntil(hiddenUntil);
}
@Override
public void setPostponeCount(int postponeCount) {
super.setPostponeCount(postponeCount);
}
}

@ -1,101 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import java.util.Date;
import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
/** Fields that you would want to see in the TaskView activity */
public class TaskModelForNotify extends AbstractTaskModel {
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
ESTIMATED_SECONDS,
NOTIFICATIONS,
NOTIFICATION_FLAGS,
LAST_NOTIFIED,
HIDDEN_UNTIL,
PROGRESS_PERCENTAGE,
DEFINITE_DUE_DATE,
PREFERRED_DUE_DATE,
};
// --- constructors
public TaskModelForNotify(Cursor cursor) {
super(cursor);
prefetchData(FIELD_LIST);
}
// --- getters
@Override
public Integer getEstimatedSeconds() {
return super.getEstimatedSeconds();
}
@Override
public boolean isTaskCompleted() {
return super.isTaskCompleted();
}
@Override
public Integer getNotificationIntervalSeconds() {
return super.getNotificationIntervalSeconds();
}
@Override
public Date getHiddenUntil() {
return super.getHiddenUntil();
}
@Override
public Date getDefiniteDueDate() {
return super.getDefiniteDueDate();
}
@Override
public Date getPreferredDueDate() {
return super.getPreferredDueDate();
}
@Override
public int getNotificationFlags() {
return super.getNotificationFlags();
}
@Override
public Date getLastNotificationDate() {
return super.getLastNotificationDate();
}
// --- setters
@Override
public void setLastNotificationTime(Date date) {
super.setLastNotificationTime(date);
}
}

@ -1,78 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Francois DESLANDES
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import java.util.Date;
import android.content.ContentValues;
import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.enums.Importance;
/** Fields that you would want to see in the TaskView activity */
public class TaskModelForProvider extends AbstractTaskModel {
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
NAME,
IMPORTANCE,
PREFERRED_DUE_DATE,
DEFINITE_DUE_DATE,
"COALESCE(" + PREFERRED_DUE_DATE + ", 0) as pdd",
"COALESCE(" + DEFINITE_DUE_DATE + ", 0) as ddd"
};
// --- constructors
public TaskModelForProvider(Cursor cursor) {
super(cursor);
prefetchData(FIELD_LIST);
}
// --- getters
@Override
public String getName() {
return super.getName();
}
@Override
public Importance getImportance() {
return super.getImportance();
}
@Override
public Date getPreferredDueDate() {
return super.getPreferredDueDate();
}
@Override
public Date getDefiniteDueDate() {
return super.getDefiniteDueDate();
}
public void update(ContentValues newValues) {
setValues.putAll(newValues);
}
}

@ -1,83 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import java.util.Date;
import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
/** Fields that you would want to see in the TaskView activity */
public class TaskModelForReminder extends AbstractTaskModel {
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
NAME,
NOTIFICATION_FLAGS,
HIDDEN_UNTIL,
TIMER_START,
PROGRESS_PERCENTAGE,
};
// --- constructors
public TaskModelForReminder(Cursor cursor) {
super(cursor);
prefetchData(FIELD_LIST);
}
// --- getters
@Override
public String getName() {
return super.getName();
}
@Override
public Date getTimerStart() {
return super.getTimerStart();
}
@Override
public boolean isTaskCompleted() {
return super.isTaskCompleted();
}
@Override
public Date getHiddenUntil() {
return super.getHiddenUntil();
}
@Override
public int getNotificationFlags() {
return super.getNotificationFlags();
}
// --- setters
@Override
public void setLastNotificationTime(Date date) {
super.setLastNotificationTime(date);
}
}

@ -1,236 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import java.util.Date;
import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.enums.Importance;
/** Fields that you would want to synchronize in the TaskModel */
public class TaskModelForSync extends AbstractTaskModel {
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
NAME,
IMPORTANCE,
ESTIMATED_SECONDS,
ELAPSED_SECONDS,
DEFINITE_DUE_DATE,
PREFERRED_DUE_DATE,
HIDDEN_UNTIL,
BLOCKING_ON,
PROGRESS_PERCENTAGE,
CREATION_DATE,
COMPLETION_DATE,
NOTES,
REPEAT,
LAST_NOTIFIED,
NOTIFICATIONS,
NOTIFICATION_FLAGS,
FLAGS,
};
// --- constructors
public TaskModelForSync() {
super();
setCreationDate(new Date());
}
public TaskModelForSync(Cursor cursor) {
super(cursor);
prefetchData(FIELD_LIST);
}
// --- getters and setters
@Override
public boolean isTaskCompleted() {
return super.isTaskCompleted();
}
@Override
public Date getDefiniteDueDate() {
return super.getDefiniteDueDate();
}
@Override
public Integer getEstimatedSeconds() {
return super.getEstimatedSeconds();
}
@Override
public int getProgressPercentage() {
return super.getProgressPercentage();
}
@Override
public Date getCreationDate() {
return super.getCreationDate();
}
@Override
public Date getCompletionDate() {
return super.getCompletionDate();
}
@Override
public Integer getElapsedSeconds() {
return super.getElapsedSeconds();
}
@Override
public Date getHiddenUntil() {
return super.getHiddenUntil();
}
@Override
public Importance getImportance() {
return super.getImportance();
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getNotes() {
return super.getNotes();
}
@Override
public Date getPreferredDueDate() {
return super.getPreferredDueDate();
}
@Override
public TaskIdentifier getBlockingOn() {
return super.getBlockingOn();
}
@Override
public RepeatInfo getRepeat() {
return super.getRepeat();
}
@Override
public Integer getNotificationIntervalSeconds() {
return super.getNotificationIntervalSeconds();
}
@Override
public int getNotificationFlags() {
return super.getNotificationFlags();
}
@Override
public Date getLastNotificationDate() {
return super.getLastNotificationDate();
}
@Override
public int getFlags() {
return super.getFlags();
}
// --- setters
@Override
public void setDefiniteDueDate(Date definiteDueDate) {
super.setDefiniteDueDate(definiteDueDate);
}
@Override
public void setEstimatedSeconds(Integer estimatedSeconds) {
super.setEstimatedSeconds(estimatedSeconds);
}
@Override
public void setElapsedSeconds(int elapsedSeconds) {
super.setElapsedSeconds(elapsedSeconds);
}
@Override
public void setHiddenUntil(Date hiddenUntil) {
super.setHiddenUntil(hiddenUntil);
}
@Override
public void setImportance(Importance importance) {
super.setImportance(importance);
}
@Override
public void setName(String name) {
super.setName(name);
}
@Override
public void setNotes(String notes) {
super.setNotes(notes);
}
@Override
public void setPreferredDueDate(Date preferredDueDate) {
super.setPreferredDueDate(preferredDueDate);
}
@Override
public void setBlockingOn(TaskIdentifier blockingOn) {
super.setBlockingOn(blockingOn);
}
@Override
public void setRepeat(RepeatInfo taskRepeat) {
super.setRepeat(taskRepeat);
}
@Override
public void setCompletionDate(Date completionDate) {
super.setCompletionDate(completionDate);
}
@Override
public void setCreationDate(Date creationDate) {
super.setCreationDate(creationDate);
}
@Override
public void setProgressPercentage(int progressPercentage) {
super.setProgressPercentage(progressPercentage);
}
@Override
public void setNotificationIntervalSeconds(Integer intervalInSeconds) {
super.setNotificationIntervalSeconds(intervalInSeconds);
}
@Override
public void setFlags(int flags) {
super.setFlags(flags);
}
}

@ -1,73 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.task;
import java.util.Date;
import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.enums.Importance;
/** Fields that you would want to see in the TaskView activity */
public class TaskModelForWidget extends AbstractTaskModel {
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
NAME,
IMPORTANCE,
PREFERRED_DUE_DATE,
DEFINITE_DUE_DATE,
"COALESCE(" + PREFERRED_DUE_DATE + ", 0) as pdd",
"COALESCE(" + DEFINITE_DUE_DATE + ", 0) as ddd"
};
// --- constructors
public TaskModelForWidget(Cursor cursor) {
super(cursor);
prefetchData(FIELD_LIST);
}
// --- getters
@Override
public String getName() {
return super.getName();
}
@Override
public Importance getImportance() {
return super.getImportance();
}
@Override
public Date getPreferredDueDate() {
return super.getPreferredDueDate();
}
@Override
public Date getDefiniteDueDate() {
return super.getDefiniteDueDate();
}
}

@ -1,217 +0,0 @@
package com.timsu.astrid.data.task;
import java.util.Date;
import java.util.HashMap;
import android.database.Cursor;
import android.util.Log;
import com.timsu.astrid.R;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.enums.Importance;
import com.timsu.astrid.data.enums.RepeatInterval;
import com.timsu.astrid.utilities.DateUtilities;
public class TaskModelForXml extends AbstractTaskModel {
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
NAME,
IMPORTANCE,
ELAPSED_SECONDS,
ESTIMATED_SECONDS,
TIMER_START,
DEFINITE_DUE_DATE,
PREFERRED_DUE_DATE,
NOTIFICATIONS,
PROGRESS_PERCENTAGE,
COMPLETION_DATE,
CREATION_DATE,
HIDDEN_UNTIL,
NOTES,
REPEAT,
FLAGS,
POSTPONE_COUNT,
BLOCKING_ON,
LAST_NOTIFIED,
NOTIFICATION_FLAGS,
CALENDAR_URI,
};
private HashMap<String, String> taskAttributesMap;
public static final String REPEAT_VALUE = "repeat_value";
public static final String REPEAT_INTERVAL = "repeat_interval";
private RepeatInterval repeatInterval = null;
private Integer repeatValue = null;
// --- constructors
public TaskModelForXml() {
super();
setCreationDate(new Date());
taskAttributesMap = new HashMap<String, String>(FIELD_LIST.length);
}
public TaskModelForXml(Cursor cursor) {
super(cursor);
prefetchData(FIELD_LIST);
taskAttributesMap = new HashMap<String, String>(FIELD_LIST.length);
}
/* Safely add a value from a date field (in case of null values) to the
taskAttributesMap.
*/
private void safePutDate(String field, Date value) {
if (value != null) {
taskAttributesMap.put(field, DateUtilities.getIso8601String(value));
}
}
// --- getters and setters
public Date getCreationDate() {
return super.getCreationDate();
}
/* Build a HashMap of task fields and associated values.
*/
public HashMap<String, String> getTaskAttributes() {
taskAttributesMap.put(AbstractController.KEY_ROWID, getTaskIdentifier().idAsString());
taskAttributesMap.put(NAME, getName());
taskAttributesMap.put(IMPORTANCE, getImportance().toString());
taskAttributesMap.put(ELAPSED_SECONDS, getElapsedSeconds().toString());
taskAttributesMap.put(ESTIMATED_SECONDS, getEstimatedSeconds().toString());
safePutDate(TIMER_START, getTimerStart());
safePutDate(DEFINITE_DUE_DATE, getDefiniteDueDate());
safePutDate(PREFERRED_DUE_DATE, getPreferredDueDate());
taskAttributesMap.put(NOTIFICATIONS, getNotificationIntervalSeconds().toString());
taskAttributesMap.put(PROGRESS_PERCENTAGE, Integer.toString(getProgressPercentage()));
safePutDate(COMPLETION_DATE, getCompletionDate());
safePutDate(CREATION_DATE, getCreationDate());
safePutDate(HIDDEN_UNTIL, getHiddenUntil());
taskAttributesMap.put(NOTES, getNotes());
RepeatInfo repeat = getRepeat();
if (repeat != null) {
taskAttributesMap.put(REPEAT_VALUE, Integer.toString(repeat.getValue()));
taskAttributesMap.put(REPEAT_INTERVAL, repeat.getInterval().toString());
}
taskAttributesMap.put(FLAGS, Integer.toString(getFlags()));
taskAttributesMap.put(POSTPONE_COUNT, getPostponeCount().toString());
taskAttributesMap.put(BLOCKING_ON, Long.toString(getBlockingOn().getId()));
safePutDate(LAST_NOTIFIED, getLastNotificationDate());
taskAttributesMap.put(NOTIFICATION_FLAGS, Integer.toString(getNotificationFlags()));
String calendarUri = getCalendarUri();
if (calendarUri != null) {
taskAttributesMap.put(CALENDAR_URI, calendarUri);
}
return taskAttributesMap;
}
// --- setters
public boolean setField(String field, String value) {
boolean success = true;
if(field.equals(NAME)) {
setName(value);
}
else if(field.equals(NOTES)) {
setNotes(value);
}
else if(field.equals(PROGRESS_PERCENTAGE)) {
setProgressPercentage(Integer.parseInt(value));
}
else if(field.equals(IMPORTANCE)) {
setImportance(Importance.valueOf(value));
}
else if(field.equals(ESTIMATED_SECONDS)) {
setEstimatedSeconds(Integer.parseInt(value));
}
else if(field.equals(ELAPSED_SECONDS)) {
setElapsedSeconds(Integer.parseInt(value));
}
else if(field.equals(TIMER_START)) {
setTimerStart(DateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(DEFINITE_DUE_DATE)) {
setDefiniteDueDate(DateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(PREFERRED_DUE_DATE)) {
setPreferredDueDate(DateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(HIDDEN_UNTIL)) {
setHiddenUntil(DateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(BLOCKING_ON)) {
setBlockingOn(new TaskIdentifier(Long.parseLong(value)));
}
else if(field.equals(POSTPONE_COUNT)) {
setPostponeCount(Integer.parseInt(value));
}
else if(field.equals(NOTIFICATIONS)) {
setNotificationIntervalSeconds(Integer.parseInt(value));
}
else if(field.equals(CREATION_DATE)) {
setCreationDate(DateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(COMPLETION_DATE)) {
setCompletionDate(DateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(NOTIFICATION_FLAGS)) {
setNotificationFlags(Integer.parseInt(value));
}
else if(field.equals(LAST_NOTIFIED)) {
setLastNotificationTime(DateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(REPEAT_INTERVAL)) {
try {
setRepeatInterval(RepeatInterval.valueOf(value));
} catch (Exception e) {
RepeatInterval repeatInterval;
switch (Integer.parseInt(value)) {
case R.string.repeat_days:
repeatInterval = RepeatInterval.DAYS;
break;
case R.string.repeat_weeks:
repeatInterval = RepeatInterval.WEEKS;
break;
case R.string.repeat_months:
repeatInterval = RepeatInterval.MONTHS;
break;
case R.string.repeat_hours:
repeatInterval = RepeatInterval.HOURS;
break;
default:
Log.e("XmlImport", "Unable to set repeat interval");
repeatInterval = RepeatInterval.DAYS;
break;
}
setRepeatInterval(repeatInterval);
}
}
else if(field.equals(REPEAT_VALUE)) {
setRepeatValue(Integer.parseInt(value));
}
else if(field.equals(FLAGS)) {
setFlags(Integer.parseInt(value));
}
else {
success = false;
}
return success;
}
public void setRepeatInterval(RepeatInterval repeatInterval) {
this.repeatInterval = repeatInterval;
if (repeatValue != null) {
setRepeat(new RepeatInfo(repeatInterval, repeatValue));
}
}
public void setRepeatValue(Integer repeatValue) {
this.repeatValue = repeatValue;
if (repeatInterval != null) {
setRepeat(new RepeatInfo(repeatInterval, repeatValue));
}
}
}

@ -12,11 +12,11 @@ import android.database.MatrixCursor;
import android.net.Uri;
import android.util.Log;
import com.timsu.astrid.data.TaskController;
import com.timsu.astrid.data.TaskModelForProvider;
import com.timsu.astrid.data.tag.TagController;
import com.timsu.astrid.data.tag.TagIdentifier;
import com.timsu.astrid.data.tag.TagModelForView;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskModelForProvider;
import com.todoroo.astrid.service.AstridDependencyInjector;
public class TasksProvider extends ContentProvider {

@ -1,92 +0,0 @@
package com.timsu.astrid.utilities;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import android.database.sqlite.SQLiteException;
import android.text.InputType;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView;
import com.flurry.android.FlurryAgent;
/**
* General purpose utilities for the Astrid project. Grab-bag of stuff.
*
* @author timsu
*
*/
public class AstridUtilities {
/** Suppress virtual keyboard until user's first tap */
public static void suppressVirtualKeyboard(final TextView editor) {
final int inputType = editor.getInputType();
editor.setInputType(InputType.TYPE_NULL);
editor.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
editor.setInputType(inputType);
editor.setOnTouchListener(null);
return false;
}
});
}
/**
* Converts a throwable's stack trace into a string
*
* @param input
* @return
*/
public static void reportFlurryError(String name, Throwable error) {
String message = error.toString();
StringWriter writer = new StringWriter();
PrintWriter writerPrinter = new PrintWriter(writer);
error.printStackTrace(writerPrinter);
writerPrinter.flush();
writerPrinter.close();
String trace = writer.toString();
// shorten the string
trace = trace.substring(message.length());
trace = trace.replaceAll("com.timsu.astrid", "!as");
trace = trace.replaceAll("com.mdt.rtm", "!rtm");
trace = trace.replaceAll("android.database.sqlite", "!sqlite");
trace = trace.replaceAll("android", "!A");
trace = trace.replaceAll("database", "!db");
trace = trace.replaceAll("org.apache.harmony.xml.parsers", "!xmlp");
trace = trace.replaceAll(IllegalStateException.class.getName(), "IlStEx");
trace = trace.replaceAll(ClassCastException.class.getName(), "ClCaEx");
trace = trace.replaceAll(NullPointerException.class.getName(), "NPEx");
trace = trace.replaceAll(SQLiteException.class.getName(), "SqLiEx");
trace = trace.replaceAll(".java:", ":");
FlurryAgent.onError(name, message, trace);
}
/**
* For reporting uncaught exceptions
*
* @author timsu
*
*/
public static class AstridUncaughtExceptionHandler implements UncaughtExceptionHandler {
private UncaughtExceptionHandler defaultUEH;
public AstridUncaughtExceptionHandler() {
defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
AstridUtilities.reportFlurryError("uncaught", ex);
defaultUEH.uncaughtException(thread, ex);
}
}
}

@ -1,181 +0,0 @@
package com.timsu.astrid.utilities;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.preference.ListPreference;
import android.preference.PreferenceManager;
import android.util.Log;
import com.timsu.astrid.R;
public class Calendars {
// Private SDK
private static final Uri CALENDAR_CONTENT_URI = Uri
.parse("content://calendar/calendars"); // Calendars.CONTENT_URI
private static final String ID_COLUMN_NAME = "_id";
private static final String DISPLAY_COLUMN_NAME = "displayName";
private static final String ACCES_LEVEL_COLUMN_NAME = "access_level";
private static final String[] CALENDARS_PROJECTION = new String[] {
ID_COLUMN_NAME, // Calendars._ID,
DISPLAY_COLUMN_NAME // Calendars.DISPLAY_NAME
};
// Only show calendars that the user can modify. Access level 500
// corresponds to Calendars.CONTRIBUTOR_ACCESS
private static final String CALENDARS_WHERE = ACCES_LEVEL_COLUMN_NAME + ">= 500";
private static final String CALENDARS_WHERE_ID = ACCES_LEVEL_COLUMN_NAME+
" >= 500 AND " + ID_COLUMN_NAME +"=?";
private static final String CALENDARS_SORT = "displayName ASC";
/**
* Ensures that the default calendar preference is pointing to
* user-modifiable calendar that exists. If the calendar does not exist
* anymore, the preference is reset to default value.
*
* @param context
* Context
*/
public static void ensureValidDefaultCalendarPreference(Context context) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
Resources r = context.getResources();
Editor editor = prefs.edit();
// We default the 'defaultCalendar' setting when it is undefined
// or when the calendar does not exist anymore
// if (!prefs.contains(r.getString(R.string.prefs_defaultCalendar))
// || !Calendars.isCalendarPresent(context, prefs.getString(r
// .getString(R.string.prefs_defaultCalendar), null))) {
// editor.putString(r.getString(R.string.prefs_defaultCalendar), r
// .getString(R.string.prefs_defaultCalendar_default));
// editor.commit();
// }
}
/**
* Appends all user-modifiable calendars to listPreference. Always includes
* entry called "Astrid default" with calendar id of
* prefs_defaultCalendar_default.
*
* @param context
* context
* @param listPreference
* preference to init
*/
public static void initCalendarsPreference(Context context,
ListPreference listPreference) {
ContentResolver cr = context.getContentResolver();
Resources r = context.getResources();
Cursor c = cr.query(CALENDAR_CONTENT_URI, CALENDARS_PROJECTION,
CALENDARS_WHERE, null, CALENDARS_SORT);
// Fetch the current setting. Invalid calendar id will
// be changed to default value.
String currentSetting = String.valueOf(Preferences
.getDefaultCalendarIDSafe(context));
int currentSettingIndex = -1;
if (c == null || c.getCount() == 0) {
// Something went wrong when querying calendars
// Let's keep the "Astrid default" only.
listPreference
.setEntries(new String[] { r
.getString(R.string.prefs_defaultCalendar_astrid_default) });
// listPreference.setEntryValues(new String[] { r
// .getString(R.string.prefs_defaultCalendar_default) });
listPreference.setValueIndex(0);
listPreference.setEnabled(true);
return;
}
int calendarCount = c.getCount();
String[] entries = new String[calendarCount];
String[] entryValues = new String[calendarCount];
// Iterate calendars one by one, and fill up the list preference
try {
int row = 0;
int idColumn = c.getColumnIndex(ID_COLUMN_NAME);
int nameColumn = c.getColumnIndex(DISPLAY_COLUMN_NAME);
while (c.moveToNext()) {
String id = c.getString(idColumn);
String name = c.getString(nameColumn);
entries[row] = name;
entryValues[row] = id;
// We found currently selected calendar
if (currentSetting.equals(id)) {
currentSettingIndex = row;
}
row++;
}
if (currentSettingIndex == -1) {
// Should not happen!
// Let's keep the "Astrid default" only.
Log.d("astrid", "initCalendarsPreference: Unknown calendar.");
listPreference
.setEntries(new String[] { r
.getString(R.string.prefs_defaultCalendar_astrid_default) });
// listPreference.setEntryValues(new String[] { r
// .getString(R.string.prefs_defaultCalendar_default) });
listPreference.setValueIndex(0);
listPreference.setEnabled(true);
} else if(currentSettingIndex >= entryValues.length) {
currentSettingIndex = 0;
}
listPreference.setEntries(entries);
listPreference.setEntryValues(entryValues);
listPreference.setValueIndex(currentSettingIndex);
listPreference.setEnabled(true);
} finally {
c.deactivate();
}
}
/**
* Checks whether user-modifiable calendar is present with a given id.
*
* @param context
* Context
* @param id
* Calendar ID to search for
* @return true, if user-modifiable calendar with the given id exists; false
* otherwise.
*/
private static boolean isCalendarPresent(Context context, String id) {
if (id == null)
return false;
ContentResolver cr = context.getContentResolver();
Cursor c = null;
try {
c = cr.query(CALENDAR_CONTENT_URI, CALENDARS_PROJECTION,
CALENDARS_WHERE_ID, new String[] { id }, CALENDARS_SORT);
} finally {
if (c != null) {
c.deactivate();
}
}
return (c != null) && (c.getCount() != 0);
}
}

@ -1,42 +0,0 @@
package com.timsu.astrid.utilities;
import android.app.Activity;
/** Astrid constants */
@Deprecated
public class Constants {
// application constants
/** URL of Astrid Help Page */
public static final String HELP_URL = "http://weloveastrid.com/?page_id=59";
/** Flurry API Key */
public static final String FLURRY_KEY = "T3JAY9TV2JFMJR4YTG16";
public static final boolean DEBUG = true;
public static final long WIDGET_UPDATE_INTERVAL = 30 * 60 * 1000L;
/**
* Whether this is an OEM preinstallation
*/
public static final boolean OEM = false;
/**
* Whether to display synchronization options
*/
public static final boolean SYNCHRONIZE = !OEM;
// result codes
/** Return to the task list view */
public static final int RESULT_GO_HOME = Activity.RESULT_FIRST_USER;
/** Discard changes */
public static final int RESULT_DISCARD = Activity.RESULT_FIRST_USER + 1;
/** Callback to force synchronization */
public static final int RESULT_SYNCHRONIZE = Activity.RESULT_FIRST_USER + 2;
}

@ -1,246 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.utilities;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
import com.timsu.astrid.R;
public class DateUtilities {
private static SimpleDateFormat format = null;
private static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ssz";
/** Format a time into a medium length absolute format */
public static String getFormattedDate(Context context, Date date) {
if(format == null)
format = Preferences.getDateFormat(context);
return format.format(date);
}
/**
* Convenience method for dropping the preopsition argument.
*/
public static String getDurationString(Resources r, int timeInSeconds,
int unitsToShow) {
return getDurationString(r, timeInSeconds, unitsToShow, false);
}
/**
* Format a time into the format: 5 days, 3 hours, 2 minutes
*
* @param r Resources to get strings from
* @param timeInSeconds
* @param unitsToShow number of units to show (i.e. if 2, then 5 hours
* 3 minutes 2 seconds is truncated to 5 hours 3 minutes)
* @param withPreposition whether there is a preceeding preposition
* @return
*/
public static String getDurationString(Resources r, int timeInSeconds,
int unitsToShow, boolean withPreposition) {
short days, hours, minutes, seconds;
short unitsDisplayed = 0;
if(timeInSeconds == 0)
return r.getQuantityString(R.plurals.Nseconds, 0, 0);
days = (short)(timeInSeconds / 24 / 3600);
timeInSeconds -= days*24*3600;
hours = (short)(timeInSeconds / 3600);
timeInSeconds -= hours * 3600;
minutes = (short)(timeInSeconds / 60);
timeInSeconds -= minutes * 60;
seconds = (short)timeInSeconds;
StringBuilder result = new StringBuilder();
if(days > 0) {
int daysPlural = withPreposition ? R.plurals.NdaysPreposition : R.plurals.Ndays;
result.append(r.getQuantityString(daysPlural, days, days)).
append(" ");
unitsDisplayed++;
}
if(unitsDisplayed < unitsToShow && hours > 0) {
result.append(r.getQuantityString(R.plurals.Nhours, hours,
hours)).
append(" ");
unitsDisplayed++;
}
if(unitsDisplayed < unitsToShow && minutes > 0) {
result.append(r.getQuantityString(R.plurals.Nminutes, minutes,
minutes)).append(" ");
unitsDisplayed++;
}
if(unitsDisplayed < unitsToShow && seconds > 0) {
result.append(r.getQuantityString(R.plurals.Nseconds, seconds,
seconds)).append(" ");
}
return result.toString().trim();
}
/**
* Format a time into the format: 5 days, 3 hrs, 2 min
*
* @param r Resources to get strings from
* @param timeInSeconds
* @param unitsToShow number of units to show (i.e. if 2, then 5 hours
* 3 minutes 2 seconds is truncated to 5 hours 3 minutes)
* @return
*/
public static String getAbbreviatedDurationString(Resources r, int timeInSeconds,
int unitsToShow) {
short days, hours, minutes, seconds;
short unitsDisplayed = 0;
if(timeInSeconds == 0)
return r.getQuantityString(R.plurals.Nseconds, 0, 0);
days = (short)(timeInSeconds / 24 / 3600);
timeInSeconds -= days*24*3600;
hours = (short)(timeInSeconds / 3600);
timeInSeconds -= hours * 3600;
minutes = (short)(timeInSeconds / 60);
timeInSeconds -= minutes * 60;
seconds = (short)timeInSeconds;
StringBuilder result = new StringBuilder();
if(days > 0) {
result.append(r.getQuantityString(R.plurals.Ndays, days, days)).
append(" ");
unitsDisplayed++;
}
if(unitsDisplayed < unitsToShow && hours > 0) {
result.append(r.getQuantityString(R.plurals.NhoursShort, hours,
hours)).
append(" ");
unitsDisplayed++;
}
if(unitsDisplayed < unitsToShow && minutes > 0) {
result.append(r.getQuantityString(R.plurals.NminutesShort, minutes,
minutes)).append(" ");
unitsDisplayed++;
}
if(unitsDisplayed < unitsToShow && seconds > 0) {
result.append(r.getQuantityString(R.plurals.NsecondsShort, seconds,
seconds)).append(" ");
}
return result.toString().trim();
}
/**
* Format a time into the format: 5 d, 3 h, 2 m
*
* @param r Resources to get strings from
* @param timeInSeconds
* @param unitsToShow number of units to show
* @return
*/
public static String getShortDurationString(Resources r, int timeInSeconds,
int unitsToShow) {
short days, hours, minutes, seconds;
short unitsDisplayed = 0;
if(timeInSeconds == 0)
return "0 s";
days = (short)(timeInSeconds / 24 / 3600);
timeInSeconds -= days*24*3600;
hours = (short)(timeInSeconds / 3600);
timeInSeconds -= hours * 3600;
minutes = (short)(timeInSeconds / 60);
timeInSeconds -= minutes * 60;
seconds = (short)timeInSeconds;
StringBuilder result = new StringBuilder();
if(days > 0) {
result.append(days).append(" d ");
unitsDisplayed++;
}
if(unitsDisplayed < unitsToShow && hours > 0) {
result.append(hours).append(" h ");
unitsDisplayed++;
}
if(unitsDisplayed < unitsToShow && minutes > 0) {
result.append(minutes).append(" m ");
unitsDisplayed++;
}
if(unitsDisplayed < unitsToShow && seconds > 0) {
result.append(seconds).append(" s ");
}
return result.toString();
}
/* Format a Date into ISO 8601 Compliant format.
*/
public static String getIso8601String(Date d) {
SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_FORMAT);
String result = "";
if (d != null) {
result = sdf.format(d);
}
return result;
}
/* Take an ISO 8601 string and return a Date object.
On failure, returns null.
*/
public static Date getDateFromIso8601String(String s) {
SimpleDateFormat df = new SimpleDateFormat(ISO_8601_FORMAT);
try {
return df.parse(s);
} catch (ParseException e) {
Log.e("DateUtilities", "Error parsing ISO 8601 date");
return null;
}
}
/* Get current date and time as a string.
Used in TasksXmlExporter
*/
public static String getDateForExport() {
DateFormat df = new SimpleDateFormat("yyMMdd-HHmm");
return df.format(new Date());
}
public static boolean wasCreatedBefore(String s, int daysAgo) {
DateFormat df = new SimpleDateFormat("yyMMdd");
Date date;
try {
date = df.parse(s);
} catch (ParseException e) {
return false;
}
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -daysAgo);
Date calDate = cal.getTime();
return date.before(calDate);
}
}

@ -1,102 +0,0 @@
package com.timsu.astrid.utilities;
import java.io.File;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import com.timsu.astrid.R;
import com.timsu.astrid.widget.FilePickerBuilder;
import com.timsu.astrid.widget.NNumberPickerDialog;
import com.timsu.astrid.widget.NNumberPickerDialog.OnNNumberPickedListener;
@Deprecated
public class DialogUtilities {
/**
* Displays a dialog box with an OK button
*
* @param context
* @param text
* @param okListener
*/
public static void okDialog(Context context, String text,
DialogInterface.OnClickListener okListener) {
try {
new AlertDialog.Builder(context)
.setTitle(R.string.information_title)
.setMessage(text)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok, okListener)
.show();
} catch (Exception e) {
AstridUtilities.reportFlurryError("show-dialog", e);
}
}
/**
* Displays a dialog box with OK and Cancel buttons
*
* @param context
* @param text
* @param okListener
* @param cancelListener
*/
public static void okCancelDialog(Context context, String text,
DialogInterface.OnClickListener okListener,
DialogInterface.OnClickListener cancelListener) {
try {
new AlertDialog.Builder(context)
.setTitle(R.string.information_title)
.setMessage(text)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok, okListener)
.setNegativeButton(android.R.string.cancel, cancelListener)
.show();
} catch (Exception e) {
AstridUtilities.reportFlurryError("show-dialog", e);
}
}
/**
* Displays a dialog box that lets users pick a day & hour value
*
* @param context
* @param title title of the dialog box
* @param listener what happens when users click ok
*/
public static void dayHourPicker(Context context, String title,
OnNNumberPickedListener listener) {
Resources r = context.getResources();
new NNumberPickerDialog(context, listener, title,
new int[] {0, 0}, new int[] {1, 1}, new int[] {0, 0},
new int[] {31, 23}, new String[] {
r.getString(R.string.daysVertical),
r.getString(R.string.hoursVertical)
}).show();
}
/**
* Displays a dialog box that lets users pick an hour & minute value.
*
* @param context
* @param title title of the dialog box
* @param listener what happens when users click ok
*/
public static void hourMinutePicker(Context context, String title,
OnNNumberPickedListener listener) {
new NNumberPickerDialog(context, listener, title,
new int[] {0, 0}, new int[] {1, 5}, new int[] {0, 0},
new int[] {99, 59}, new String[] {":", null}).show();
}
/** Display a dialog box with a list of files to pick.
*
*/
public static void filePicker(Context context, String title, File path,
FilePickerBuilder.OnFilePickedListener listener) {
new FilePickerBuilder(context, title, path, listener).show();
}
}

@ -0,0 +1,278 @@
package com.timsu.astrid.utilities;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import org.xmlpull.v1.XmlSerializer;
import android.content.Context;
import android.database.Cursor;
import android.os.Environment;
import android.util.Log;
import android.util.Xml;
import android.widget.Toast;
import com.timsu.astrid.R;
import com.timsu.astrid.data.TaskController;
import com.timsu.astrid.data.TaskIdentifier;
import com.timsu.astrid.data.TaskModelForXml;
import com.timsu.astrid.data.alerts.AlertController;
import com.timsu.astrid.data.sync.SyncDataController;
import com.timsu.astrid.data.sync.SyncMapping;
import com.timsu.astrid.data.tag.TagController;
import com.timsu.astrid.data.tag.TagIdentifier;
import com.timsu.astrid.data.tag.TagModelForView;
import com.todoroo.astrid.backup.BackupDateUtilities;
public class LegacyTasksXmlExporter {
private TaskController taskController;
private TagController tagController;
private AlertController alertController;
private SyncDataController syncDataController;
private Context ctx;
private String output;
private final boolean isService;
private int exportCount;
private XmlSerializer xml;
private HashMap<TagIdentifier, TagModelForView> tagMap;
public static final String ASTRID_TAG = "astrid";
public static final String ASTRID_ATTR_VERSION = "version";
public static final String TASK_TAG = "task";
public static final String TAG_TAG = "tag";
public static final String TAG_ATTR_NAME = "name";
public static final String ALERT_TAG = "alert";
public static final String ALERT_ATTR_DATE = "date";
public static final String SYNC_TAG = "sync";
public static final String SYNC_ATTR_SERVICE = "service";
public static final String SYNC_ATTR_REMOTE_ID = "remote_id";
public static final String XML_ENCODING = "utf-8";
public static final String ASTRID_DIR = "/astrid";
private static final String EXPORT_FILE_NAME = "user.%s.xml";
private static final String BACKUP_FILE_NAME = "auto.%s.xml";
public static final int FILENAME_DATE_BEGIN_INDEX = 5;
public static final int FILENAME_DATE_END_INDEX = 11;
public LegacyTasksXmlExporter(boolean isService) {
this.isService = isService;
this.exportCount = 0;
}
private void initTagMap() {
tagMap = tagController.getAllTagsAsMap();
}
private void serializeTags(TaskIdentifier task)
throws IOException {
LinkedList<TagIdentifier> tags = tagController.getTaskTags(task);
for (TagIdentifier tag : tags) {
if(!tagMap.containsKey(tag) || tagMap.get(tag) == null)
continue;
xml.startTag(null, TAG_TAG);
xml.attribute(null, TAG_ATTR_NAME, tagMap.get(tag).toString());
xml.endTag(null, TAG_TAG);
}
}
private void serializeSyncMappings(TaskIdentifier task)
throws IOException {
HashSet<SyncMapping> syncMappings = syncDataController.getSyncMappings(task);
for (SyncMapping sync : syncMappings) {
xml.startTag(null, SYNC_TAG);
xml.attribute(null, SYNC_ATTR_SERVICE,
Integer.toString(sync.getSyncServiceId()));
xml.attribute(null, SYNC_ATTR_REMOTE_ID, sync.getRemoteId());
xml.endTag(null, SYNC_TAG);
}
}
private void serializeAlerts(TaskIdentifier task)
throws IOException {
List<Date> alerts = alertController.getTaskAlerts(task);
for (Date alert : alerts) {
xml.startTag(null, ALERT_TAG);
xml.attribute(null, ALERT_ATTR_DATE, BackupDateUtilities.getIso8601String(alert));
xml.endTag(null, ALERT_TAG);
}
}
private void serializeTasks()
throws IOException {
Cursor c = taskController.getBackupTaskListCursor();
if (! c.moveToFirst()) {
return; // No tasks.
}
do {
TaskModelForXml task = new TaskModelForXml(c);
TaskIdentifier taskId = task.getTaskIdentifier();
xml.startTag(null, TASK_TAG);
HashMap<String, String> taskAttributes = task.getTaskAttributes();
for (String key : taskAttributes.keySet()) {
String value = taskAttributes.get(key);
xml.attribute(null, key, value);
}
serializeTags(taskId);
serializeAlerts(taskId);
serializeSyncMappings(taskId);
xml.endTag(null, TASK_TAG);
this.exportCount++;
} while (c.moveToNext());
c.close();
}
private void doTasksExport() throws IOException {
File xmlFile = new File(this.output);
xmlFile.createNewFile();
FileOutputStream fos = new FileOutputStream(xmlFile);
xml = Xml.newSerializer();
xml.setOutput(fos, XML_ENCODING);
xml.startDocument(null, null);
xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
xml.startTag(null, ASTRID_TAG);
xml.attribute(null, ASTRID_ATTR_VERSION,
Integer.toString(Preferences.getCurrentVersion(ctx)));
openControllers();
initTagMap();
serializeTasks();
closeControllers();
xml.endTag(null, ASTRID_TAG);
xml.endDocument();
xml.flush();
fos.close();
if (!isService) {
displayToast();
}
}
private void displayToast() {
CharSequence text = String.format(ctx.getString(R.string.export_toast),
ctx.getResources().getQuantityString(R.plurals.Ntasks, exportCount,
exportCount), output);
Toast.makeText(ctx, text, Toast.LENGTH_LONG).show();
}
private void displayErrorToast(String error) {
Toast.makeText(ctx, error, Toast.LENGTH_LONG).show();
}
private void closeControllers() {
tagController.close();
taskController.close();
alertController.close();
syncDataController.close();
}
private void openControllers() {
taskController.open();
tagController.open();
alertController.open();
syncDataController.open();
}
public void exportTasks(File directory) {
if (isService && !Preferences.isBackupEnabled(ctx)) {
// Automatic backups are disabled.
return;
}
if (setupFile(directory)) {
Thread thread = new Thread(doBackgroundExport);
thread.start();
}
}
public static File getExportDirectory() {
String storageState = Environment.getExternalStorageState();
if (storageState.equals(Environment.MEDIA_MOUNTED)) {
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
path = path + ASTRID_DIR;
return new File(path);
}
return null;
}
private boolean setupFile(File directory) {
File astridDir = directory;
if (astridDir != null) {
// Check for /sdcard/astrid directory. If it doesn't exist, make it.
if (astridDir.exists() || astridDir.mkdir()) {
String fileName;
if (isService) {
fileName = BACKUP_FILE_NAME;
} else {
fileName = EXPORT_FILE_NAME;
}
fileName = String.format(fileName, BackupDateUtilities.getDateForExport());
setOutput(astridDir.getAbsolutePath() + "/" + fileName);
return true;
} else {
// Unable to make the /sdcard/astrid directory.
String error = ctx.getString(R.string.error_sdcard, astridDir.getAbsolutePath());
Log.e("TasksXmlExporter", error);
if (!isService) {
displayErrorToast(error);
}
return false;
}
} else {
// Unable to access the sdcard because it's not in the mounted state.
String error = ctx.getString(R.string.error_sdcard_general);
Log.e("TasksXmlExporter", error);
if (!isService) {
displayErrorToast(error);
}
return false;
}
}
private void setOutput(String file) {
this.output = file;
}
private final Runnable doBackgroundExport = new Runnable() {
public void run() {
/*Looper.prepare();
try {
doTasksExport();
} catch (IOException e) {
Log.e("TasksXmlExporter", "IOException in doTasksExport " + e.getMessage());
}
Looper.loop();*/
}
};
public void setTaskController(TaskController taskController) {
this.taskController = taskController;
}
public void setTagController(TagController tagController) {
this.tagController = tagController;
}
public void setAlertController(AlertController alertController) {
this.alertController = alertController;
}
public void setSyncDataController(SyncDataController syncDataController) {
this.syncDataController = syncDataController;
}
public void setContext(Context ctx) {
this.ctx = ctx;
setTaskController(new TaskController(ctx));
setTagController(new TagController(ctx));
setAlertController(new AlertController(ctx));
setSyncDataController(new SyncDataController(ctx));
}
}

@ -1,583 +0,0 @@
package com.timsu.astrid.utilities;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Resources;
import android.net.Uri;
import android.preference.PreferenceManager;
import com.timsu.astrid.R;
@Deprecated
public class Preferences {
// pref keys
private static final String P_CURRENT_VERSION = "cv";
private static final String P_SHOW_REPEAT_HELP = "repeathelp";
private static final String P_TASK_LIST_SORT = "tlsort";
private static final String P_SYNC_RTM_TOKEN = "rtmtoken";
private static final String P_SYNC_RTM_LAST_SYNC = "rtmlastsync";
private static final String P_SYNC_LAST_SYNC = "lastsync";
private static final String P_SYNC_LAST_SYNC_ATTEMPT = "lastsyncattempt";
private static final String P_LOCALE_LAST_NOTIFY = "locnot";
private static final String P_DID_ANDROID_AND_ME_SURVEY = "aamsurvey";
private static final String P_TASK_KILLER_HELP = "taskkiller";
private static final String P_BACKUP_ERROR = "backupError";
// pref values
public static final int ICON_SET_PINK = 0;
public static final int ICON_SET_BORING = 1;
public static final int ICON_SET_ASTRID = 2;
// default values
private static final boolean DEFAULT_PERSISTENCE_MODE = true;
private static final boolean DEFAULT_COLORIZE = false;
/** Set preference defaults, if unset. called at startup */
public static void setPreferenceDefaults(Context context) {
SharedPreferences prefs = getPrefs(context);
Resources r = context.getResources();
Editor editor = prefs.edit();
// if(!prefs.contains(r.getString(R.string.p_notif_annoy))) {
// editor.putBoolean(r.getString(R.string.p_notif_annoy),
// DEFAULT_PERSISTENCE_MODE);
// }
if(!prefs.contains(r.getString(R.string.p_fontSize))) {
editor.putString(r.getString(R.string.p_fontSize), "20");
}
// if(!prefs.contains(r.getString(R.string.p_deadlineTime))) {
// editor.putString(r.getString(R.string.p_deadlineTime), "1");
// }
// if(!prefs.contains(r.getString(R.string.p_notif_defaultRemind))) {
// editor.putString(r.getString(R.string.p_notif_defaultRemind), "0");
// }
if(!prefs.contains(r.getString(R.string.p_colorize))) {
editor.putBoolean(r.getString(R.string.p_colorize), DEFAULT_COLORIZE);
}
// if(!prefs.contains(r.getString(R.string.p_notif_vibrate))) {
// editor.putBoolean(r.getString(R.string.p_notif_vibrate), true);
// }
if (!prefs.contains(r.getString(R.string.p_backup))) {
editor.putBoolean(r.getString(R.string.p_backup), true);
}
if (!prefs.contains(P_BACKUP_ERROR)) {
editor.putString(P_BACKUP_ERROR, null);
}
Calendars.ensureValidDefaultCalendarPreference(context);
setVisibilityPreferences(prefs, editor, r);
editor.commit();
}
private static void setVisibilityPreferences(SharedPreferences p, Editor e, Resources r) {
// if(!p.contains(r.getString(R.string.prefs_titleVisible))) {
// e.putBoolean(r.getString(R.string.prefs_titleVisible),
// Boolean.parseBoolean(r.getString(R.string.prefs_titleVisible_default)));
// }
// if(!p.contains(r.getString(R.string.prefs_timeVisible))) {
// e.putBoolean(r.getString(R.string.prefs_timeVisible),
// Boolean.parseBoolean(r.getString(R.string.prefs_timeVisible_default)));
// }
// if(!p.contains(r.getString(R.string.prefs_deadlineVisible))) {
// e.putBoolean(r.getString(R.string.prefs_deadlineVisible),
// Boolean.parseBoolean(r.getString(R.string.prefs_deadlineVisible_default)));
// }
// if(!p.contains(r.getString(R.string.prefs_importanceVisible))) {
// e.putBoolean(r.getString(R.string.prefs_importanceVisible),
// Boolean.parseBoolean(r.getString(R.string.prefs_importanceVisible_default)));
// }
// if(!p.contains(r.getString(R.string.prefs_reminderVisible))) {
// e.putBoolean(r.getString(R.string.prefs_reminderVisible),
// Boolean.parseBoolean(r.getString(R.string.prefs_reminderVisible_default)));
// }
// if(!p.contains(r.getString(R.string.prefs_repeatVisible))) {
// e.putBoolean(r.getString(R.string.prefs_repeatVisible),
// Boolean.parseBoolean(r.getString(R.string.prefs_repeatVisible_default)));
// }
// if(!p.contains(r.getString(R.string.prefs_tagsVisible))) {
// e.putBoolean(r.getString(R.string.prefs_tagsVisible),
// Boolean.parseBoolean(r.getString(R.string.prefs_tagsVisible_default)));
// }
// if(!p.contains(r.getString(R.string.prefs_notesVisible))) {
// e.putBoolean(r.getString(R.string.prefs_notesVisible),
// Boolean.parseBoolean(r.getString(R.string.prefs_notesVisible_default)));
// }
}
// --- system preferences
/** CurrentVersion: the currently installed version of Astrid */
public static int getCurrentVersion(Context context) {
return getPrefs(context).getInt(P_CURRENT_VERSION, 0);
}
/** CurrentVersion: the currently installed version of Astrid */
public static void setCurrentVersion(Context context, int version) {
Editor editor = getPrefs(context).edit();
editor.putInt(P_CURRENT_VERSION, version);
editor.commit();
}
/** TaskKillerHelp: whether we should show task killer help */
public static boolean shouldShowTaskKillerHelp(Context context) {
return getPrefs(context).getBoolean(P_TASK_KILLER_HELP, true);
}
/** TaskKillerHelp: whether we should show task killer help */
public static void disableTaskKillerHelp(Context context) {
Editor editor = getPrefs(context).edit();
editor.putBoolean(P_TASK_KILLER_HELP, false);
editor.commit();
}
/** ShowRepeatHelp: whether help dialog should be shown about repeats */
public static boolean shouldShowRepeatHelp(Context context) {
return getPrefs(context).getBoolean(P_SHOW_REPEAT_HELP, true);
}
public static void setShowRepeatHelp(Context context, boolean setting) {
Editor editor = getPrefs(context).edit();
editor.putBoolean(P_SHOW_REPEAT_HELP, setting);
editor.commit();
}
// --- date time strings and formatters
@SuppressWarnings("nls")
public static boolean is24HourFormat(Context context) {
String value = android.provider.Settings.System.getString(context.getContentResolver(),
android.provider.Settings.System.TIME_12_24);
boolean b24 = !(value == null || value.equals("12"));
return b24;
}
/**
* @return time format (hours and minutes)
*/
public static SimpleDateFormat getTimeFormat(Context context) {
String value = getTimeFormatString(context);
return new SimpleDateFormat(value);
}
/**
* @return string used for time formatting
*/
@SuppressWarnings("nls")
private static String getTimeFormatString(Context context) {
String value;
if (is24HourFormat(context)) {
value = "H:mm";
} else {
value = "h:mm a";
}
return value;
}
/**
* @return string used for date formatting
*/
@SuppressWarnings("nls")
private static String getDateFormatString(Context context) {
String value = android.provider.Settings.System.getString(context.getContentResolver(),
android.provider.Settings.System.DATE_FORMAT);
if (value == null) {
// united states, you are special
if (Locale.US.equals(Locale.getDefault())
|| Locale.CANADA.equals(Locale.getDefault()))
value = "MMM d yyyy";
else
value = "d MMM yyyy";
}
return value;
}
/**
* @return date format (month, day, year)
*/
public static SimpleDateFormat getDateFormat(Context context) {
return new SimpleDateFormat(getDateFormatString(context));
}
/**
* @return date format as getDateFormat with weekday
*/
@SuppressWarnings("nls")
public static SimpleDateFormat getDateFormatWithWeekday(Context context) {
return new SimpleDateFormat("EEE, " + getDateFormatString(context));
}
/**
* @return date with time at the end
*/
@SuppressWarnings("nls")
public static SimpleDateFormat getDateWithTimeFormat(Context context) {
return new SimpleDateFormat(getDateFormatString(context) + " " +
getTimeFormatString(context));
}
// --- notification settings
/** returns hour at which quiet hours start, or null if not set */
public static Integer getQuietHourStart(Context context) {
// return getIntegerValue(context, R.string.p_notif_quietStart);
return 0;
}
/** returns hour at which quiet hours start, or null if not set */
public static Integer getQuietHourEnd(Context context) {
// return getIntegerValue(context, R.string.p_notif_quietEnd);
return 0;
}
/** returns hour at which quiet hours start, or null if not set */
public static int getNotificationIconTheme(Context context) {
// Integer index = getIntegerValue(context, R.string.p_notif_icon);
// if(index == null)
// index = 0;
// return index;
return 0;
}
/** Get notification ring tone, or null if not set */
public static Uri getNotificationRingtone(Context context) {
Resources r = context.getResources();
// String value = getPrefs(context).getString(r.getString(
// R.string.p_notification_ringtone), "");
//
// try {
// return Uri.parse(value);
// } catch (RuntimeException e) {
// return null;
// }
return null;
}
/** Get perstence mode setting */
public static boolean isPersistenceMode(Context context) {
Resources r = context.getResources();
// return getPrefs(context).getBoolean(r.getString(
// R.string.p_notif_annoy), DEFAULT_PERSISTENCE_MODE);
return false;
}
/** Get vibration mode setting */
public static boolean shouldVibrate(Context context) {
Resources r = context.getResources();
// return getPrefs(context).getBoolean(r.getString(
// R.string.p_notif_vibrate), true);
return false;
}
/** Return # of days to remind by default */
public static Integer getDefaultReminder(Context context) {
// return getIntegerValue(context, R.string.p_notif_defaultRemind);
return 0;
}
// --- postpone count & settings
/** whether nags for postponing and other things should be shown */
public static boolean shouldShowNags(Context context) {
// return getPrefs(context).getBoolean(context.getResources().
// getString(R.string.p_nagging), true);
return false;
}
// --- appearance settings
/** returns the font size user wants on the front page */
public static Integer getTaskListFontSize(Context context) {
return getIntegerValue(context, R.string.p_fontSize);
}
/** Return # of days from now to set deadlines by default */
public static Integer getDefaultDeadlineDays(Context context) {
// return getIntegerValue(context, R.string.p_deadlineTime);
return 0;
}
/** Get perstence mode setting */
public static boolean isColorize(Context context) {
Resources r = context.getResources();
return getPrefs(context).getBoolean(r.getString(
R.string.p_colorize), DEFAULT_COLORIZE);
}
/** TaskListSort: the sorting method for the task list */
public static int getTaskListSort(Context context) {
return getPrefs(context).getInt(P_TASK_LIST_SORT, 0);
}
/** TaskListSort: the sorting method for the task list */
public static void setTaskListSort(Context context, int value) {
Editor editor = getPrefs(context).edit();
editor.putInt(P_TASK_LIST_SORT, value);
editor.commit();
}
/** TagListSort: the sorting method for the tag list */
public static int getTagListSort(Context context) {
return getPrefs(context).getInt(P_TASK_LIST_SORT, 0);
}
/** TagListSort: the sorting method for the tag list */
public static void setTagListSort(Context context, int value) {
Editor editor = getPrefs(context).edit();
editor.putInt(P_TASK_LIST_SORT, value);
editor.commit();
}
// --- backup preferences
public static boolean isBackupEnabled(Context context) {
Resources r = context.getResources();
return getPrefs(context).getBoolean(r.getString(R.string.p_backup), true);
}
public static void setBackupEnabled(Context context, boolean setting) {
Resources r = context.getResources();
Editor editor = getPrefs(context).edit();
editor.putBoolean(r.getString(R.string.p_backup), setting);
editor.commit();
}
/**
* @return error when doing backup, empty string if successful, or null
* if no backup has been attempted
*/
public static String getBackupSummary(Context context) {
return getPrefs(context).getString(P_BACKUP_ERROR, null);
}
public static void setBackupSummary(Context context, String newValue) {
Editor editor = getPrefs(context).edit();
editor.putString(P_BACKUP_ERROR, newValue);
editor.commit();
}
// --- synchronization preferences
/** RTM authentication token, or null if doesn't exist */
public static String getSyncRTMToken(Context context) {
return getPrefs(context).getString(P_SYNC_RTM_TOKEN, null);
}
/** Sets the RTM authentication token. Set to null to clear. */
public static void setSyncRTMToken(Context context, String setting) {
Editor editor = getPrefs(context).edit();
editor.putString(P_SYNC_RTM_TOKEN, setting);
editor.commit();
}
/** RTM Last Successful Sync Date, or null */
public static Date getSyncRTMLastSync(Context context) {
Long value = getPrefs(context).getLong(P_SYNC_RTM_LAST_SYNC, 0);
if(value == 0)
return null;
return new Date(value);
}
/** Set RTM Last Successful Sync Date */
public static void setSyncRTMLastSync(Context context, Date date) {
if(date == null) {
clearPref(context, P_SYNC_RTM_LAST_SYNC);
return;
}
Editor editor = getPrefs(context).edit();
editor.putLong(P_SYNC_RTM_LAST_SYNC, date.getTime());
editor.commit();
}
/** Should sync with RTM? */
public static boolean shouldSyncRTM(Context context) {
Resources r = context.getResources();
// return getPrefs(context).getBoolean(r.getString(
// R.string.p_sync_rtm), false);
return false;
}
/** Should display sync shortcut? */
public static boolean shouldDisplaySyncButton(Context context) {
Resources r = context.getResources();
// return getPrefs(context).getBoolean(r.getString(
// R.string.p_sync_button), false);
return false;
}
/** Should hide sync dialog boxes? */
public static boolean shouldSuppressSyncDialogs(Context context) {
// Resources r = context.getResources();
// return getPrefs(context).getBoolean(r.getString(
// R.string.p_sync_quiet), false);
return false;
}
/** Reads the frequency, in seconds, auto-sync should occur.
* @return seconds duration, or null if not desired */
public static Integer getSyncAutoSyncFrequency(Context context) {
Integer time = 0;
// Integer time = getIntegerValue(context, R.string.p_sync_interval);
if(time != null && time == 0)
time = null;
return time;
}
/** Sets the auto-sync frequency to the desired value */
public static void setSyncAutoSyncFrequency(Context context, int value) {
// Editor editor = getPrefs(context).edit();
// editor.putString(context.getResources().getString(R.string.p_sync_interval),
// Integer.toString(value));
// editor.commit();
}
/** Last Auto-Sync Date, or null */
public static Date getSyncLastSync(Context context) {
Long value = getPrefs(context).getLong(P_SYNC_LAST_SYNC, 0);
if(value == 0)
return null;
return new Date(value);
}
/** Last Successful Auto-Sync Date, or null */
public static Date getSyncLastSyncAttempt(Context context) {
Long value = getPrefs(context).getLong(P_SYNC_LAST_SYNC_ATTEMPT, 0);
if(value == 0)
return null;
return new Date(value);
}
/** Set Last Sync Date */
public static void setSyncLastSync(Context context, Date date) {
if(date == null) {
clearPref(context, P_SYNC_LAST_SYNC);
return;
}
Editor editor = getPrefs(context).edit();
editor.putLong(P_SYNC_LAST_SYNC, date.getTime());
editor.commit();
}
/** Set Last Auto-Sync Attempt Date */
public static void setSyncLastSyncAttempt(Context context, Date date) {
Editor editor = getPrefs(context).edit();
editor.putLong(P_SYNC_LAST_SYNC_ATTEMPT, date.getTime());
editor.commit();
}
// --- locale
public static void setLocaleLastAlertTime(Context context, long tag, long time) {
Editor editor = getPrefs(context).edit();
editor.putLong(P_LOCALE_LAST_NOTIFY + tag, time);
editor.commit();
}
public static long getLocaleLastAlertTime(Context context, long tag) {
return getPrefs(context).getLong(P_LOCALE_LAST_NOTIFY + tag, 0);
}
// --- misc
/** Get setting */
public static boolean didAAMSurvey(Context context) {
return getPrefs(context).getBoolean(P_DID_ANDROID_AND_ME_SURVEY, false);
}
/** Set setting */
public static void setDidAAMSurvey(Context context, boolean value) {
Editor editor = getPrefs(context).edit();
editor.putBoolean(P_DID_ANDROID_AND_ME_SURVEY, value);
editor.commit();
}
/** Get default calendar id. */
public static String getDefaultCalendarID(Context context) {
Resources r = context.getResources();
// return getPrefs(context).getString(
// r.getString(R.string.prefs_defaultCalendar),
// r.getString(R.string.prefs_defaultCalendar_default));
return null;
}
/** Get default calendar id. Returns default value if the calendar does not exist anymore.*/
public static String getDefaultCalendarIDSafe(Context context) {
Calendars.ensureValidDefaultCalendarPreference(context);
return getDefaultCalendarID(context);
}
/** Set default calendar id */
public static void setDefaultCalendarID(Context context, String value) {
Resources r = context.getResources();
Editor editor = getPrefs(context).edit();
// editor.putString(r.getString(R.string.prefs_defaultCalendar), value);
editor.commit();
}
// --- helper methods
/** Clear the given preference */
private static void clearPref(Context context, String key) {
Editor editor = getPrefs(context).edit();
editor.remove(key);
editor.commit();
}
/** Get preferences object from the context */
private static SharedPreferences getPrefs(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
/** Gets an integer value from a string resource id. Returns null
* if the value is not set or not an integer.
*
* @param context
* @param keyResource resource from string.xml
* @return integer value, or null on error
*/
private static Integer getIntegerValue(Context context, int keyResource) {
Resources r = context.getResources();
String value = getPrefs(context).getString(r.getString(keyResource), "");
try {
return Integer.parseInt(value);
} catch (Exception e) {
return null;
}
}
/** Gets an float value from a string resource id. Returns null
* if the value is not set or not an flat.
*
* @param context
* @param keyResource resource from string.xml
* @return
*/
private static Float getFloatValue(Context context, int keyResource) {
Resources r = context.getResources();
String value = getPrefs(context).getString(r.getString(keyResource), "");
try {
return Float.parseFloat(value);
} catch (Exception e) {
return null;
}
}
public static TaskFieldsVisibility getTaskFieldsVisibility(Context context) {
return TaskFieldsVisibility.getFromPreferences(context, getPrefs(context));
}
}

@ -1,53 +0,0 @@
package com.timsu.astrid.utilities;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
/** Helper struct to store preferences for field visibility */
public class TaskFieldsVisibility {
// --- they're like constants... except mutable =/
public boolean TITLE;
public boolean TIMES;
public boolean IMPORTANCE;
public boolean DEADLINE;
public boolean REMINDERS;
public boolean REPEATS;
public boolean TAGS;
public boolean NOTES;
private static class PrefReader {
SharedPreferences prefs;
Resources r;
public PrefReader(SharedPreferences prefs, Resources r) {
this.prefs = prefs;
this.r = r;
}
private boolean get(int key, int defValue) {
return prefs.getBoolean(r.getString(key),
Boolean.parseBoolean(r.getString(defValue)));
}
}
public static TaskFieldsVisibility getFromPreferences(Context context,
SharedPreferences prefs) {
TaskFieldsVisibility tf = new TaskFieldsVisibility();
Resources r = context.getResources();
PrefReader pr = new PrefReader(prefs, r);
tf.TITLE = true;
tf.TIMES = true;
tf.IMPORTANCE = true;
tf.DEADLINE = true;
tf.REMINDERS = true;
tf.REPEATS = true;
tf.TAGS = true;
tf.NOTES = true;
return tf;
}
}

@ -1,128 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.widget;
import java.text.Format;
import java.util.Date;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TimePicker;
import com.timsu.astrid.utilities.Preferences;
public class DateControlSet implements OnTimeSetListener,
OnDateSetListener, View.OnClickListener {
private Format dateFormatter = null;
private Format timeFormatter = null;
protected final Activity activity;
protected Button dateButton;
protected Button timeButton;
protected Date date;
protected DateControlSet(Activity activity) {
this.activity = activity;
this.dateFormatter = Preferences.getDateFormatWithWeekday(this.activity);
this.timeFormatter = Preferences.getTimeFormat(this.activity);
}
public DateControlSet(Activity activity, Button dateButton, Button timeButton) {
this(activity);
this.dateButton = dateButton;
this.timeButton = timeButton;
dateButton.setOnClickListener(this);
timeButton.setOnClickListener(this);
setDate(null);
}
public Date getDate() {
return date;
}
public long getMillis() {
if(date == null)
return 0;
return date.getTime();
}
/** Initialize the components for the given date field */
public void setDate(Date newDate) {
if(newDate == null) {
date = new Date();
Integer days = Preferences.getDefaultDeadlineDays(activity);
if(days == null)
days = 1;
date.setTime(date.getTime() + days*24L*3600*1000);
date.setMinutes(0);
} else
this.date = new Date(newDate.getTime());
updateDate();
updateTime();
}
public void setDate(long newDate) {
if(newDate == 0L)
setDate(null);
else
setDate(new Date(newDate));
}
public void onDateSet(DatePicker view, int year, int month, int monthDay) {
date.setYear(year - 1900);
date.setMonth(month);
date.setDate(monthDay);
updateDate();
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
date.setHours(hourOfDay);
date.setMinutes(minute);
updateTime();
}
public void updateDate() {
dateButton.setText(dateFormatter.format(date));
}
public void updateTime() {
timeButton.setText(timeFormatter.format(date));
}
public void onClick(View v) {
if(v == timeButton)
new TimePickerDialog(activity, this, date.getHours(),
date.getMinutes(), Preferences.is24HourFormat(activity)).show();
else
new DatePickerDialog(activity, this, 1900 +
date.getYear(), date.getMonth(), date.getDate()).show();
}
}

@ -1,69 +0,0 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.widget;
import java.util.Date;
import android.app.Activity;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
/** Date Control Set with an "enabled" checkbox" to toggle date / null */
public class DateWithNullControlSet extends DateControlSet {
private CheckBox activatedCheckBox;
public DateWithNullControlSet(Activity activity, int checkBoxId, int dateButtonId, int timeButtonId) {
super(activity);
activatedCheckBox = (CheckBox)activity.findViewById(checkBoxId);
dateButton = (Button)activity.findViewById(dateButtonId);
timeButton = (Button)activity.findViewById(timeButtonId);
activatedCheckBox.setOnCheckedChangeListener(
new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
dateButton.setEnabled(isChecked);
timeButton.setEnabled(isChecked);
}
});
dateButton.setOnClickListener(this);
timeButton.setOnClickListener(this);
}
@Override
public Date getDate() {
if(!activatedCheckBox.isChecked())
return null;
return super.getDate();
}
/** Initialize the components for the given date field */
@Override
public void setDate(Date newDate) {
activatedCheckBox.setChecked(newDate != null);
dateButton.setEnabled(newDate != null);
timeButton.setEnabled(newDate != null);
super.setDate(newDate);
}
}

@ -1,28 +0,0 @@
package com.timsu.astrid.widget;
import android.content.Context;
import android.util.AttributeSet;
/**
* This class exists solely to suppress an Android 2.1 error
* @author Tim Su <tim@todoroo.com>
*
*/
public class ViewFlipper extends android.widget.ViewFlipper {
public ViewFlipper(Context context) {
super(context);
}
public ViewFlipper(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDetachedFromWindow() {
try {
super.onDetachedFromWindow();
} catch (Exception e) {
// stupid Android 2.1 exception
}
}
}

@ -27,8 +27,8 @@ import java.util.List;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.TabActivity;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.TabActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@ -42,6 +42,7 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@ -55,19 +56,15 @@ import android.widget.TabHost;
import android.widget.TimePicker;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.AdapterView.OnItemSelectedListener;
import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;
import com.timsu.astrid.data.task.TaskModelForEdit;
import com.timsu.astrid.utilities.AstridUtilities;
import com.timsu.astrid.widget.TimeDurationControlSet;
import com.timsu.astrid.widget.TimeDurationControlSet.TimeDurationType;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.dao.Database;
@ -77,9 +74,11 @@ import com.todoroo.astrid.repeats.RepeatControlSet;
import com.todoroo.astrid.service.StartupService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagsControlSet;
import com.todoroo.astrid.ui.DeadlineTimePickerDialog;
import com.todoroo.astrid.ui.TimeDurationControlSet;
import com.todoroo.astrid.ui.DeadlineTimePickerDialog.OnDeadlineTimeSetListener;
import com.todoroo.astrid.ui.TimeDurationControlSet.TimeDurationType;
import com.todoroo.astrid.utility.Constants;
import com.todoroo.astrid.widget.DeadlineTimePickerDialog;
import com.todoroo.astrid.widget.DeadlineTimePickerDialog.OnDeadlineTimeSetListener;
/**
* This activity is responsible for creating new tasks and editing existing
@ -162,7 +161,7 @@ public final class TaskEditActivity extends TabActivity {
setUpUIComponents();
// disable keyboard until user requests it
AstridUtilities.suppressVirtualKeyboard(title);
AndroidUtilities.suppressVirtualKeyboard(title);
}
/* ======================================================================
@ -1030,7 +1029,7 @@ public final class TaskEditActivity extends TabActivity {
after.setChecked((flags &
Task.NOTIFY_AFTER_DEADLINE) > 0);
mode.setSelection((flags &
TaskModelForEdit.NOTIFY_NONSTOP) > 0 ? 1 : 0);
Task.NOTIFY_NONSTOP) > 0 ? 1 : 0);
}
public int getValue() {

@ -21,11 +21,6 @@ import android.util.Log;
import com.google.ical.values.Frequency;
import com.google.ical.values.RRule;
import com.timsu.astrid.R;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.alerts.Alert;
import com.timsu.astrid.data.enums.RepeatInterval;
import com.timsu.astrid.data.task.AbstractTaskModel;
import com.timsu.astrid.utilities.TasksXmlExporter;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.GenericDao;
import com.todoroo.andlib.data.Property;
@ -37,6 +32,7 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.alarms.Alarm;
import com.todoroo.astrid.alarms.AlarmDatabase;
import com.todoroo.astrid.backup.TasksXmlExporter;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao;
@ -136,10 +132,10 @@ public class Astrid2To3UpgradeHelper {
// --- upgrade tasks table
HashMap<String, Property<?>> propertyMap =
new HashMap<String, Property<?>>();
propertyMap.put(AbstractController.KEY_ROWID, Task.ID);
propertyMap.put("_id", Task.ID); //$NON-NLS-1$
propertyMap.put(AbstractTaskModel.NAME, Task.TITLE);
propertyMap.put(AbstractTaskModel.NOTES, Task.NOTES);
// don't update progress percentage, we don't use this anymore
// (don't update progress percentage, we don't use this anymore)
propertyMap.put(AbstractTaskModel.IMPORTANCE, Task.IMPORTANCE);
propertyMap.put(AbstractTaskModel.ESTIMATED_SECONDS, Task.ESTIMATED_SECONDS);
propertyMap.put(AbstractTaskModel.ELAPSED_SECONDS, Task.ELAPSED_SECONDS);
@ -165,7 +161,7 @@ public class Astrid2To3UpgradeHelper {
AlarmDatabase alarmsDatabase = new AlarmDatabase();
alarmsDatabase.openForWriting();
propertyMap.clear();
propertyMap.put(AbstractController.KEY_ROWID, Alarm.ID);
propertyMap.put("_id", Alarm.ID); //$NON-NLS-1$
propertyMap.put(Alert.TASK, Alarm.TASK);
propertyMap.put(Alert.DATE, Alarm.TIME);
upgradeTable(context, alertsTable, propertyMap, new Alarm(),
@ -203,38 +199,6 @@ public class Astrid2To3UpgradeHelper {
public StringBuilder upgradeNotes;
}
/** Legacy repeatInfo class */
private static class RepeatInfo {
public static final int REPEAT_VALUE_OFFSET = 3;
private final RepeatInterval interval;
private final int value;
public RepeatInfo(RepeatInterval repeatInterval, int value) {
this.interval = repeatInterval;
this.value = value;
}
public RepeatInterval getInterval() {
return interval;
}
public int getValue() {
return value;
}
public static RepeatInfo fromSingleField(int repeat) {
if(repeat == 0)
return null;
int value = repeat >> REPEAT_VALUE_OFFSET;
RepeatInterval interval = RepeatInterval.values()
[repeat - (value << REPEAT_VALUE_OFFSET)];
return new RepeatInfo(interval, value);
}
}
/**
* Visitor that reads from a visitor container and writes to the model
* @author Tim Su <tim@todoroo.com>
@ -477,5 +441,76 @@ public class Astrid2To3UpgradeHelper {
}
}
// --- legacy data structures
/** Legacy repeatInfo class */
private static class RepeatInfo {
public static final int REPEAT_VALUE_OFFSET = 3;
private final RepeatInterval interval;
private final int value;
public RepeatInfo(RepeatInterval repeatInterval, int value) {
this.interval = repeatInterval;
this.value = value;
}
public RepeatInterval getInterval() {
return interval;
}
public int getValue() {
return value;
}
public static RepeatInfo fromSingleField(int repeat) {
if(repeat == 0)
return null;
int value = repeat >> REPEAT_VALUE_OFFSET;
RepeatInterval interval = RepeatInterval.values()
[repeat - (value << REPEAT_VALUE_OFFSET)];
return new RepeatInfo(interval, value);
}
}
/** Legacy repeat interval class */
private enum RepeatInterval {
DAYS,
WEEKS,
MONTHS,
HOURS
}
/** Legacy task class */
@SuppressWarnings("nls")
private abstract class AbstractTaskModel {
public static final String NAME = "name";
public static final String NOTES = "notes";
public static final String IMPORTANCE = "importance";
public static final String ESTIMATED_SECONDS = "estimatedSeconds";
public static final String ELAPSED_SECONDS = "elapsedSeconds";
public static final String TIMER_START = "timerStart";
public static final String DEFINITE_DUE_DATE = "definiteDueDate";
public static final String PREFERRED_DUE_DATE = "preferredDueDate";
public static final String HIDDEN_UNTIL = "hiddenUntil";
public static final String POSTPONE_COUNT = "postponeCount";
public static final String NOTIFICATIONS = "notifications";
public static final String NOTIFICATION_FLAGS = "notificationFlags";
public static final String LAST_NOTIFIED = "lastNotified";
public static final String REPEAT = "repeat";
public static final String CREATION_DATE = "creationDate";
public static final String COMPLETION_DATE = "completionDate";
public static final String CALENDAR_URI = "calendarUri";
public static final String FLAGS = "flags";
}
/** Legacy alert class */
@SuppressWarnings("nls")
private class Alert {
static final String TASK = "task";
static final String DATE = "date";
}
}

@ -14,12 +14,12 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import com.timsu.astrid.R;
import com.timsu.astrid.utilities.BackupService;
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.astrid.backup.BackupService;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.reminders.ReminderService;
import com.todoroo.astrid.utility.Constants;

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.todoroo.astrid.widget;
package com.todoroo.astrid.ui;
import java.util.Calendar;

@ -1,4 +1,4 @@
package com.timsu.astrid.widget;
package com.todoroo.astrid.ui;
import java.io.File;
import java.io.FilenameFilter;
@ -13,6 +13,7 @@ import android.util.Log;
import com.timsu.astrid.R;
@SuppressWarnings("nls")
public class FilePickerBuilder extends AlertDialog.Builder implements DialogInterface.OnClickListener {
public interface OnFilePickedListener {

@ -17,7 +17,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.widget;
package com.todoroo.astrid.ui;
import java.util.LinkedList;
import java.util.List;

@ -17,7 +17,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.widget;
package com.todoroo.astrid.ui;
import android.content.Context;
import android.os.Handler;
@ -37,8 +37,9 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.timsu.astrid.R;
import com.timsu.astrid.utilities.AstridUtilities;
import com.todoroo.andlib.utility.AndroidUtilities;
@SuppressWarnings({"nls","unused"})
public class NumberPicker extends LinearLayout implements OnClickListener,
OnFocusChangeListener, OnLongClickListener {
@ -139,7 +140,7 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
mText.setFilters(new InputFilter[] { mInputFilter });
// disable keyboard until user requests it
AstridUtilities.suppressVirtualKeyboard(mText);
AndroidUtilities.suppressVirtualKeyboard(mText);
mSlideUpOutAnimation = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
@ -347,8 +348,8 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
private static final char[] DIGIT_CHARACTERS = new char[] { '0', '1', '2',
'3', '4', '5', '6', '7', '8', '9' };
private NumberPickerButton mIncrementButton;
private NumberPickerButton mDecrementButton;
private final NumberPickerButton mIncrementButton;
private final NumberPickerButton mDecrementButton;
class NumberPickerInputFilter implements InputFilter {
public CharSequence filter(CharSequence source, int start, int end,

@ -17,7 +17,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.widget;
package com.todoroo.astrid.ui;
import android.content.Context;
import android.util.AttributeSet;

@ -17,7 +17,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.widget;
package com.todoroo.astrid.ui;
import android.app.AlertDialog;
import android.content.Context;

@ -17,7 +17,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.widget;
package com.todoroo.astrid.ui;
import android.app.Activity;
import android.content.res.Resources;
@ -25,12 +25,18 @@ import android.view.View;
import android.widget.Button;
import com.timsu.astrid.R;
import com.timsu.astrid.utilities.DateUtilities;
import com.timsu.astrid.widget.NNumberPickerDialog.OnNNumberPickedListener;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.ui.NNumberPickerDialog.OnNNumberPickedListener;
@SuppressWarnings("nls")
public class TimeDurationControlSet implements OnNNumberPickedListener,
View.OnClickListener {
@Autowired
DateUtilities dateUtilities;
public enum TimeDurationType {
DAYS_HOURS,
HOURS_MINUTES;
@ -46,6 +52,7 @@ public class TimeDurationControlSet implements OnNNumberPickedListener,
public TimeDurationControlSet(Activity activity, int timeButtonId,
int prefixResource, int titleResource, TimeDurationType type) {
Resources r = activity.getResources();
DependencyInjectionService.getInstance().inject(this);
this.activity = activity;
this.prefixResource = prefixResource;
@ -93,8 +100,8 @@ public class TimeDurationControlSet implements OnNNumberPickedListener,
String prefix = "";
if(prefixResource != 0)
prefix = r.getString(prefixResource);
timeButton.setText(prefix + " " + DateUtilities.getDurationString(r,
timeDurationInSeconds, 2));
timeButton.setText(prefix + " " + dateUtilities.getDurationString(
timeDurationInSeconds * 1000L, 2));
switch(type) {
case DAYS_HOURS:
int days = timeDuration / 24 / 3600;

@ -28,7 +28,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo;
import com.timsu.astrid.data.AbstractTaskModel.RepeatInfo;
import com.todoroo.astrid.legacy.data.AbstractController;
import com.todoroo.astrid.legacy.data.AbstractModel;
import com.todoroo.astrid.legacy.data.enums.Importance;

@ -7,7 +7,7 @@ import android.database.Cursor;
import android.util.Log;
import com.timsu.astrid.R;
import com.timsu.astrid.utilities.DateUtilities;
import com.timsu.astrid.utilities.BackupDateUtilities;
import com.todoroo.astrid.legacy.data.AbstractController;
import com.todoroo.astrid.legacy.data.enums.Importance;
import com.todoroo.astrid.legacy.data.enums.RepeatInterval;
@ -64,7 +64,7 @@ public class TaskModelForXml extends AbstractTaskModel {
*/
private void safePutDate(String field, Date value) {
if (value != null) {
taskAttributesMap.put(field, DateUtilities.getIso8601String(value));
taskAttributesMap.put(field, BackupDateUtilities.getIso8601String(value));
}
}
@ -132,16 +132,16 @@ public class TaskModelForXml extends AbstractTaskModel {
setElapsedSeconds(Integer.parseInt(value));
}
else if(field.equals(TIMER_START)) {
setTimerStart(DateUtilities.getDateFromIso8601String(value));
setTimerStart(BackupDateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(DEFINITE_DUE_DATE)) {
setDefiniteDueDate(DateUtilities.getDateFromIso8601String(value));
setDefiniteDueDate(BackupDateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(PREFERRED_DUE_DATE)) {
setPreferredDueDate(DateUtilities.getDateFromIso8601String(value));
setPreferredDueDate(BackupDateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(HIDDEN_UNTIL)) {
setHiddenUntil(DateUtilities.getDateFromIso8601String(value));
setHiddenUntil(BackupDateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(BLOCKING_ON)) {
setBlockingOn(new TaskIdentifier(Long.parseLong(value)));
@ -153,16 +153,16 @@ public class TaskModelForXml extends AbstractTaskModel {
setNotificationIntervalSeconds(Integer.parseInt(value));
}
else if(field.equals(CREATION_DATE)) {
setCreationDate(DateUtilities.getDateFromIso8601String(value));
setCreationDate(BackupDateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(COMPLETION_DATE)) {
setCompletionDate(DateUtilities.getDateFromIso8601String(value));
setCompletionDate(BackupDateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(NOTIFICATION_FLAGS)) {
setNotificationFlags(Integer.parseInt(value));
}
else if(field.equals(LAST_NOTIFIED)) {
setLastNotificationTime(DateUtilities.getDateFromIso8601String(value));
setLastNotificationTime(BackupDateUtilities.getDateFromIso8601String(value));
}
else if(field.equals(REPEAT_INTERVAL)) {
try {

@ -5,9 +5,9 @@ import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskModelForEdit;
import com.timsu.astrid.data.task.TaskModelForList;
import com.timsu.astrid.data.TaskController;
import com.timsu.astrid.data.TaskModelForEdit;
import com.timsu.astrid.data.TaskModelForList;
import com.timsu.astrid.provider.TasksProvider;
import com.todoroo.astrid.test.DatabaseTestCase;

@ -6,10 +6,10 @@ import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.timsu.astrid.utilities.BackupService;
import com.timsu.astrid.utilities.Preferences;
import com.timsu.astrid.utilities.BackupService.BackupDirectorySetting;
import com.todoroo.andlib.test.TodorooTestCase;
import com.todoroo.astrid.backup.BackupService;
import com.todoroo.astrid.backup.BackupService.BackupDirectorySetting;
public class BackupServiceTests extends TodorooTestCase {

Loading…
Cancel
Save