From 917cb8f7c4d95f5a768e5e8c90aa22606c5b99d7 Mon Sep 17 00:00:00 2001 From: Tim Su Date: Wed, 30 Jun 2010 16:04:27 -0700 Subject: [PATCH] Fixed up start up service, moved it out of legacy, deleted home activity, and fixed various bugs --- astrid/AndroidManifest.xml | 19 +- .../com/todoroo/andlib/sql/Criterion.java | 7 + .../andlib/utility/AndroidUtilities.java | 13 + .../activity/AbstractModelActivity.java | 92 ------- .../activity/AbstractModelTabActivity.java | 104 -------- .../astrid/activity/AstridActivity.java | 46 ---- .../astrid/activity/EditPreferences.java | 225 ++++++++++++++++++ .../astrid/activity/FilterListActivity.java | 9 +- .../todoroo/astrid/activity/HomeActivity.java | 82 ------- .../astrid/activity/TaskEditActivity.java | 91 +++++-- .../astrid/activity/TaskListActivity.java | 13 +- .../astrid/service/StartupService.java | 162 +++++++++++++ .../com/todoroo/astrid/utility/Constants.java | 21 ++ 13 files changed, 515 insertions(+), 369 deletions(-) delete mode 100644 astrid/src/com/todoroo/astrid/activity/AbstractModelActivity.java delete mode 100644 astrid/src/com/todoroo/astrid/activity/AbstractModelTabActivity.java delete mode 100644 astrid/src/com/todoroo/astrid/activity/AstridActivity.java create mode 100644 astrid/src/com/todoroo/astrid/activity/EditPreferences.java delete mode 100644 astrid/src/com/todoroo/astrid/activity/HomeActivity.java create mode 100644 astrid/src/com/todoroo/astrid/service/StartupService.java diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index 4ae57f730..901fc9a09 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -54,16 +54,13 @@ - - + + - - - @@ -79,9 +76,6 @@ - - - + @@ -122,7 +116,7 @@ - + @@ -153,6 +147,7 @@ + @@ -166,6 +161,7 @@ + @@ -179,6 +175,7 @@ + diff --git a/astrid/common-src/com/todoroo/andlib/sql/Criterion.java b/astrid/common-src/com/todoroo/andlib/sql/Criterion.java index fcd3be158..9de7d828b 100644 --- a/astrid/common-src/com/todoroo/andlib/sql/Criterion.java +++ b/astrid/common-src/com/todoroo/andlib/sql/Criterion.java @@ -15,6 +15,13 @@ public abstract class Criterion { this.operator = operator; } + public static Criterion all = new Criterion(Operator.exists) { + @Override + protected void populate(StringBuilder sb) { + sb.append(true); + } + }; + public static Criterion and(final Criterion criterion, final Criterion... criterions) { return new Criterion(Operator.and) { diff --git a/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java b/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java index 0d3ac90c5..974977776 100644 --- a/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java +++ b/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java @@ -127,4 +127,17 @@ public class AndroidUtilities { value.getClass()); } + /** + * Return index of value in array + * @param array array to search + * @param value value to look for + * @return + */ + public static int indexOf(TYPE[] array, TYPE value) { + for(int i = 0; i < array.length; i++) + if(array[i].equals(value)) + return i; + return -1; + } + } diff --git a/astrid/src/com/todoroo/astrid/activity/AbstractModelActivity.java b/astrid/src/com/todoroo/astrid/activity/AbstractModelActivity.java deleted file mode 100644 index 8896f6732..000000000 --- a/astrid/src/com/todoroo/astrid/activity/AbstractModelActivity.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.activity; - -import android.content.Intent; -import android.os.Bundle; - -import com.todoroo.andlib.data.AbstractModel; -import com.todoroo.andlib.service.Autowired; -import com.todoroo.andlib.service.DependencyInjectionService; -import com.todoroo.andlib.service.ExceptionService; -import com.todoroo.astrid.dao.Database; -import com.todoroo.astrid.service.AstridDependencyInjector; - -/** - * This activity displays a WebView 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 Tim Su - * - */ -abstract public class AbstractModelActivity extends AstridActivity { - - // --- bundle arguments - - /** - * Action Item ID - */ - public static final String ID_TOKEN = "i"; //$NON-NLS-1$ - - // --- instance variables - - @Autowired - protected ExceptionService exceptionService; - - @Autowired - protected Database database; - - protected TYPE model = null; - - // --- abstract methods - - abstract protected TYPE fetchModel(long id); - - /** - * Load Bente Dependency Injector - */ - static { - AstridDependencyInjector.initialize(); - } - - public AbstractModelActivity() { - DependencyInjectionService.getInstance().inject(this); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - loadItem(getIntent()); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - loadItem(intent); - } - - /** - * Loads action item from the given intent - * @param intent - */ - protected void loadItem(Intent intent) { - long idParam = intent.getLongExtra(ID_TOKEN, -1L); - if(idParam == -1) { - exceptionService.reportError("AMA-no-token", null); //$NON-NLS-1$ - finish(); - return; - } - - database.openForReading(); - model = fetchModel(idParam); - - if(model == null) { - exceptionService.reportError("AMA-no-task", new NullPointerException("model")); //$NON-NLS-1$ //$NON-NLS-2$ - finish(); - return; - } - } - -} \ No newline at end of file diff --git a/astrid/src/com/todoroo/astrid/activity/AbstractModelTabActivity.java b/astrid/src/com/todoroo/astrid/activity/AbstractModelTabActivity.java deleted file mode 100644 index 0cccf2255..000000000 --- a/astrid/src/com/todoroo/astrid/activity/AbstractModelTabActivity.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.todoroo.astrid.activity; - -import android.app.TabActivity; -import android.content.Intent; -import android.os.Bundle; - -import com.flurry.android.FlurryAgent; -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.astrid.dao.Database; -import com.todoroo.astrid.service.AstridDependencyInjector; -import com.todoroo.astrid.utility.Constants; - -abstract public class AbstractModelTabActivity extends TabActivity { - - // from AstridActivity - - static { - AstridDependencyInjector.initialize(); - } - - @Override - protected void onStart() { - super.onStart(); - FlurryAgent.onStartSession(this, Constants.FLURRY_KEY); - } - - @Override - protected void onStop() { - super.onStop(); - FlurryAgent.onEndSession(this); - } - - // from AbstractModelActivity - - // --- bundle arguments - - /** - * Action Item ID - */ - public static final String ID_TOKEN = "i"; //$NON-NLS-1$ - - // --- instance variables - - @Autowired - protected ExceptionService exceptionService; - - @Autowired - protected Database database; - - protected TYPE model = null; - - // --- abstract methods - - abstract protected TYPE fetchModel(long id); - - /** - * Load Bente Dependency Injector - */ - static { - AstridDependencyInjector.initialize(); - } - - public AbstractModelTabActivity() { - DependencyInjectionService.getInstance().inject(this); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - ContextManager.setContext(this); - loadItem(getIntent()); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - loadItem(intent); - } - - /** - * Loads action item from the given intent - * @param intent - */ - protected void loadItem(Intent intent) { - long idParam = intent.getLongExtra(ID_TOKEN, -1L); - if(idParam == -1) { - exceptionService.reportError("AMA-no-token", null); //$NON-NLS-1$ - finish(); - return; - } - - database.openForReading(); - model = fetchModel(idParam); - - if(model == null) { - exceptionService.reportError("AMA-no-task", new NullPointerException("model")); //$NON-NLS-1$ //$NON-NLS-2$ - finish(); - return; - } - } -} diff --git a/astrid/src/com/todoroo/astrid/activity/AstridActivity.java b/astrid/src/com/todoroo/astrid/activity/AstridActivity.java deleted file mode 100644 index 899f315a9..000000000 --- a/astrid/src/com/todoroo/astrid/activity/AstridActivity.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.activity; - -import android.app.Activity; -import android.os.Bundle; - -import com.flurry.android.FlurryAgent; -import com.todoroo.andlib.service.ContextManager; -import com.todoroo.andlib.service.DependencyInjectionService; -import com.todoroo.astrid.service.AstridDependencyInjector; -import com.todoroo.astrid.utility.Constants; - -/** - * General helpers for Astrid activities - */ -abstract public class AstridActivity extends Activity { - - static { - AstridDependencyInjector.initialize(); - } - - public AstridActivity() { - DependencyInjectionService.getInstance().inject(this); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - ContextManager.setContext(this); - } - - @Override - protected void onStart() { - super.onStart(); - FlurryAgent.onStartSession(this, Constants.FLURRY_KEY); - } - - @Override - protected void onStop() { - super.onStop(); - FlurryAgent.onEndSession(this); - } - -} \ No newline at end of file diff --git a/astrid/src/com/todoroo/astrid/activity/EditPreferences.java b/astrid/src/com/todoroo/astrid/activity/EditPreferences.java new file mode 100644 index 000000000..e292ac442 --- /dev/null +++ b/astrid/src/com/todoroo/astrid/activity/EditPreferences.java @@ -0,0 +1,225 @@ +/** + * See the file "LICENSE" for the full license governing this code. + */ +package com.todoroo.astrid.activity; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map.Entry; + +import android.content.Intent; +import android.content.SharedPreferences.Editor; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceCategory; +import android.preference.PreferenceGroup; +import android.preference.PreferenceScreen; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.Preference.OnPreferenceClickListener; + +import com.timsu.astrid.R; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.ContextManager; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.andlib.sql.Criterion; +import com.todoroo.andlib.utility.AndroidUtilities; +import com.todoroo.andlib.utility.DialogUtilities; +import com.todoroo.astrid.api.AstridApiConstants; +import com.todoroo.astrid.dao.Database; +import com.todoroo.astrid.dao.TaskDao; +import com.todoroo.astrid.model.Task; +import com.todoroo.astrid.service.StartupService; +import com.todoroo.astrid.service.TaskService; +import com.todoroo.astrid.utility.Preferences; + +/** + * Displays the preference screen for users to edit their preferences + * + * @author Tim Su + * + */ +public class EditPreferences extends PreferenceActivity { + + @Autowired + TaskService taskService; // for debugging + + @Autowired + TaskDao taskDao; + + @Autowired + Database database; + + @Autowired + DialogUtilities dialogUtilities; + + public EditPreferences() { + DependencyInjectionService.getInstance().inject(this); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + new StartupService().onStartupApplication(this); + ContextManager.setContext(this); + + setTitle(R.string.EPr_title); + addPreferencesFromResource(R.xml.preferences); + + PreferenceScreen screen = getPreferenceScreen(); + initializePreference(screen); + + // debugging preferences + addDebugPreferences(); + + // load plug-ins + Intent queryIntent = new Intent(AstridApiConstants.ACTION_SETTINGS); + PackageManager pm = getPackageManager(); + List resolveInfoList = pm.queryIntentActivities(queryIntent, 0); + int length = resolveInfoList.size(); + LinkedHashMap> applicationPreferences = + new LinkedHashMap>(); + for(int i = 0; i < length; i++) { + ResolveInfo resolveInfo = resolveInfoList.get(i); + Intent intent = new Intent(AstridApiConstants.ACTION_SETTINGS); + intent.setClassName(resolveInfo.activityInfo.packageName, + resolveInfo.activityInfo.name); + + Preference preference = new Preference(this); + preference.setTitle(resolveInfo.loadLabel(pm)); + preference.setIntent(intent); + + String application = resolveInfo.activityInfo.applicationInfo.loadLabel(pm).toString(); + if(!applicationPreferences.containsKey(application)) + applicationPreferences.put(application, new ArrayList()); + ArrayList arrayList = applicationPreferences.get(application); + arrayList.add(preference); + } + + for(Entry> entry : applicationPreferences.entrySet()) { + Preference header = new Preference(this); + header.setLayoutResource(android.R.layout.preference_category); + header.setTitle(entry.getKey()); + screen.addPreference(header); + + for(Preference preference : entry.getValue()) + screen.addPreference(preference); + + } + + } + + @SuppressWarnings("nls") + private void addDebugPreferences() { + PreferenceCategory group = new PreferenceCategory(this); + group.setTitle("DEBUG"); + getPreferenceScreen().addPreference(group); + + Preference preference = new Preference(this); + preference.setTitle("Make Lots of Tasks"); + preference.setOnPreferenceClickListener(new OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference p) { + database.openForWriting(); + Task task = new Task(); + for(int i = 0; i < 100; i++) { + task.setId(Task.NO_ID); + task.setValue(Task.TITLE, Integer.toString(i)); + taskService.save(task, false); + } + dialogUtilities.okDialog(EditPreferences.this, "done", null); + return false; + } + }); + group.addPreference(preference); + + preference = new Preference(this); + preference.setTitle("Delete all tasks"); + preference.setOnPreferenceClickListener(new OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference p) { + database.openForWriting(); + taskDao.deleteWhere(Criterion.all); + dialogUtilities.okDialog(EditPreferences.this, "done", null); + return false; + } + }); + group.addPreference(preference); + } + + private void initializePreference(Preference preference) { + if(preference instanceof PreferenceGroup) { + PreferenceGroup group = (PreferenceGroup)preference; + for(int i = 0; i < group.getPreferenceCount(); i++) { + initializePreference(group.getPreference(i)); + } + } else { + Object value = null; + if(preference instanceof ListPreference) + value = ((ListPreference)preference).getValue(); + else if(preference instanceof CheckBoxPreference) + value = ((CheckBoxPreference)preference).isChecked(); + else if(preference instanceof EditTextPreference) + value = ((EditTextPreference)preference).getText(); + + if(value != null) + updatePreferences(preference, value); + + preference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference myPreference, Object newValue) { + return updatePreferences(myPreference, newValue); + } + }); + } + } + + @Override + protected void onStart() { + super.onStart(); + } + + @Override + protected void onStop() { + super.onStop(); + } + + /** + * + * @param resource if null, updates all resources + */ + protected boolean updatePreferences(Preference preference, Object value) { + Resources r = getResources(); + + // defaults options + /*if(r.getString(R.string.EPr_default_urgency_key).equals(preference.getKey())) { + updateTaskListPreference(preference, value, r, R.array.EPr_default_urgency, + R.array.EPr_default_urgency_values, R.string.EPr_default_urgency_desc); + } else if(r.getString(R.string.EPr_default_importance_key).equals(preference.getKey())) { + updateTaskListPreference(preference, value, r, R.array.EPr_default_importance, + R.array.EPr_default_importance_values, R.string.EPr_default_importance_desc); + }*/ + + return true; + } + + private void updateTaskListPreference(Preference preference, Object value, + Resources r, int keyArray, int valueArray, int summaryResource) { + int index = AndroidUtilities.indexOf(r.getStringArray(valueArray), (String)value); + String setting = r.getStringArray(keyArray)[index]; + preference.setSummary(r.getString(summaryResource, + setting)); + + // if user changed the value, refresh task defaults + if(!value.equals(Preferences.getStringValue(preference.getKey()))) { + Editor editor = Preferences.getPrefs(this).edit(); + editor.putString(preference.getKey(), (String)value); + editor.commit(); + Task.refreshDefaultValues(); + } + } +} \ No newline at end of file diff --git a/astrid/src/com/todoroo/astrid/activity/FilterListActivity.java b/astrid/src/com/todoroo/astrid/activity/FilterListActivity.java index 361832a48..c9401a3b4 100644 --- a/astrid/src/com/todoroo/astrid/activity/FilterListActivity.java +++ b/astrid/src/com/todoroo/astrid/activity/FilterListActivity.java @@ -26,7 +26,6 @@ import android.widget.ExpandableListView.ExpandableListContextMenuInfo; import com.flurry.android.FlurryAgent; import com.timsu.astrid.R; import com.todoroo.andlib.service.Autowired; -import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.service.ExceptionService; import com.todoroo.andlib.utility.DialogUtilities; @@ -34,7 +33,7 @@ import com.todoroo.astrid.adapter.FilterAdapter; import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.FilterListItem; -import com.todoroo.astrid.service.AstridDependencyInjector; +import com.todoroo.astrid.service.StartupService; import com.todoroo.astrid.utility.Constants; /** @@ -70,10 +69,6 @@ public class FilterListActivity extends ExpandableListActivity { * ======================================================= initialization * ====================================================================== */ - static { - AstridDependencyInjector.initialize(); - } - public FilterListActivity() { DependencyInjectionService.getInstance().inject(this); } @@ -82,7 +77,7 @@ public class FilterListActivity extends ExpandableListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ContextManager.setContext(this); + new StartupService().onStartupApplication(this); setContentView(R.layout.filter_list_activity); setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); diff --git a/astrid/src/com/todoroo/astrid/activity/HomeActivity.java b/astrid/src/com/todoroo/astrid/activity/HomeActivity.java deleted file mode 100644 index 299f534e3..000000000 --- a/astrid/src/com/todoroo/astrid/activity/HomeActivity.java +++ /dev/null @@ -1,82 +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.todoroo.astrid.activity; - -import android.content.Intent; -import android.os.Bundle; - -import com.timsu.astrid.utilities.StartupReceiver; -import com.todoroo.andlib.service.ExceptionService.TodorooUncaughtExceptionHandler; -import com.todoroo.astrid.filters.CoreFilterExposer; - -/** - * HomeActivity is the primary activity for Astrid and determines which activity - * to launch next. - *

- * If the user is completely new, it launches {@link IntroductionActivity}. - *

- * If the user needs to sign in, it launches {@link SignInActivity}. - *

- * If the user has no coaches nd no tasks, it launches - * {@link CoachSelectorActivity} - *

- * Otherwise, it launches {@link TaskListActivity}. - * - * @author Tim Su - * - */ -public class HomeActivity extends AstridActivity { - - public static final int REQUEST_SIGN_IN = 1; - public static final int REQUEST_INTRODUCTION = 2; - - /* ====================================================================== - * ======================================================= initialization - * ====================================================================== */ - - /** Called when loading up the activity */ - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // set uncaught exception handler - Thread.setDefaultUncaughtExceptionHandler(new TodorooUncaughtExceptionHandler()); - - // open controllers & perform application startup rituals - StartupReceiver.onStartupApplication(this); - - performRedirection(); - } - - /* ====================================================================== - * ======================================================= event handlers - * ====================================================================== */ - - /** - * Perform redirection to next activity - */ - private void performRedirection() { - Intent intent = new Intent(this, TaskListActivity.class); - intent.putExtra(TaskListActivity.TOKEN_FILTER, CoreFilterExposer.buildInboxFilter(getResources())); - startActivity(intent); - finish(); - } - -} \ No newline at end of file diff --git a/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java b/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java index 74fe52085..96ebb7731 100644 --- a/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java +++ b/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java @@ -25,8 +25,10 @@ import java.util.LinkedList; import java.util.List; import android.app.AlertDialog; +import android.app.TabActivity; import android.content.ContentValues; import android.content.DialogInterface; +import android.content.Intent; import android.content.res.Resources; import android.os.Bundle; import android.text.Editable; @@ -67,11 +69,15 @@ import com.timsu.astrid.widget.NumberPickerDialog.OnNumberPickedListener; import com.timsu.astrid.widget.TimeDurationControlSet.TimeDurationType; import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.andlib.service.ExceptionService; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.alarms.Alarm; import com.todoroo.astrid.alarms.AlarmService; +import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Task; +import com.todoroo.astrid.service.StartupService; import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.tags.TagService.Tag; @@ -84,7 +90,14 @@ import com.todoroo.astrid.tags.TagService.Tag; * @author timsu * */ -public final class TaskEditActivity extends AbstractModelTabActivity { +public final class TaskEditActivity extends TabActivity { + + // --- bundle tokens + + /** + * Task ID + */ + public static final String ID_TOKEN = "i"; //$NON-NLS-1$ // --- request codes @@ -114,6 +127,12 @@ public final class TaskEditActivity extends AbstractModelTabActivity { // --- services + @Autowired + ExceptionService exceptionService; + + @Autowired + Database database; + @Autowired TaskService taskService; @@ -143,6 +162,9 @@ public final class TaskEditActivity extends AbstractModelTabActivity { // --- other instance variables + /** task model */ + protected Task model = null; + /** whether task should be saved when this activity exits */ boolean shouldSaveState = true; @@ -156,24 +178,14 @@ public final class TaskEditActivity extends AbstractModelTabActivity { * ======================================================= initialization * ====================================================================== */ - @Override - protected Task fetchModel(long id) { - database.openForWriting(); - - if(id == Task.NO_ID) { - FlurryAgent.onEvent("create-task"); //$NON-NLS-1$ - Task task = new Task(); - taskService.save(task, false); - return task; - } - - FlurryAgent.onEvent("edit-task"); //$NON-NLS-1$ - return taskService.fetchById(id, Task.PROPERTIES); + public TaskEditActivity() { + DependencyInjectionService.getInstance().inject(this); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + new StartupService().onStartupApplication(this); TabHost tabHost = getTabHost(); tabHost.setPadding(0, 4, 0, 0); @@ -188,10 +200,6 @@ public final class TaskEditActivity extends AbstractModelTabActivity { tabHost.addTab(tabHost.newTabSpec(TAB_ALERTS).setIndicator(r.getString(R.string.taskEdit_tab_alerts), r.getDrawable(R.drawable.ic_dialog_alert_c)).setContent(R.id.tab_notification)); - // weird case that has been hit before. - if(model == null) - model = new Task(); - setUpUIComponents(); setUpListeners(); @@ -359,10 +367,45 @@ public final class TaskEditActivity extends AbstractModelTabActivity { * =============================================== model reading / saving * ====================================================================== */ + /** + * Loads action item from the given intent + * @param intent + */ + @SuppressWarnings("nls") + protected void loadItem(Intent intent) { + long idParam = intent.getLongExtra(ID_TOKEN, -1L); + if(idParam == -1) { + exceptionService.reportError("task-edit-no-token", null); + finish(); + return; + } + + database.openForReading(); + if(idParam == Task.NO_ID) { + model = new Task(); + taskService.save(model, false); + } else { + model = taskService.fetchById(idParam, Task.PROPERTIES); + } + + if(model.getValue(Task.TITLE).length() == 0) + FlurryAgent.onEvent("create-task"); + FlurryAgent.onEvent("edit-task"); + + if(model == null) { + exceptionService.reportError("task-edit-no-task", + new NullPointerException("model")); + finish(); + return; + } + } + /** Populate UI component values from the model */ private void populateFields() { Resources r = getResources(); + loadItem(getIntent()); + title.setText(model.getValue(Task.TITLE)); if(title.getText().length() > 0) { setTitle(new StringBuilder(). @@ -754,6 +797,18 @@ public final class TaskEditActivity extends AbstractModelTabActivity { // populateFields(); } + @Override + protected void onStart() { + super.onStart(); + FlurryAgent.onStartSession(this, Constants.FLURRY_KEY); + } + + @Override + protected void onStop() { + super.onStop(); + FlurryAgent.onEndSession(this); + } + /* ====================================================================== * ========================================== UI component helper classes * ====================================================================== */ diff --git a/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java b/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java index b062d1386..8066077db 100644 --- a/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java +++ b/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java @@ -50,8 +50,8 @@ import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.filters.CoreFilterExposer; import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Task; -import com.todoroo.astrid.service.AstridDependencyInjector; import com.todoroo.astrid.service.MetadataService; +import com.todoroo.astrid.service.StartupService; import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.utility.Constants; @@ -112,13 +112,6 @@ public class TaskListActivity extends ListActivity implements OnScrollListener { * ======================================================= initialization * ====================================================================== */ - /** - * Load Bente Dependency Injector - */ - static { - AstridDependencyInjector.initialize(); - } - public TaskListActivity() { DependencyInjectionService.getInstance().inject(this); } @@ -128,10 +121,12 @@ public class TaskListActivity extends ListActivity implements OnScrollListener { protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); + + new StartupService().onStartupApplication(this); setContentView(R.layout.task_list_activity); Bundle extras = getIntent().getExtras(); - if(extras.containsKey(TOKEN_FILTER)) { + if(extras != null && extras.containsKey(TOKEN_FILTER)) { filter = extras.getParcelable(TOKEN_FILTER); } else { filter = CoreFilterExposer.buildInboxFilter(getResources()); diff --git a/astrid/src/com/todoroo/astrid/service/StartupService.java b/astrid/src/com/todoroo/astrid/service/StartupService.java new file mode 100644 index 000000000..dd2aab7e1 --- /dev/null +++ b/astrid/src/com/todoroo/astrid/service/StartupService.java @@ -0,0 +1,162 @@ +package com.todoroo.astrid.service; + +import java.util.List; + +import android.Manifest; +import android.app.AlarmManager; +import android.app.AlertDialog; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.DialogInterface.OnClickListener; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; + +import com.timsu.astrid.R; +import com.timsu.astrid.appwidget.AstridAppWidgetProvider.UpdateService; +import com.timsu.astrid.sync.SynchronizationService; +import com.timsu.astrid.utilities.BackupService; +import com.timsu.astrid.utilities.Notifications; +import com.timsu.astrid.utilities.Preferences; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.ContextManager; +import com.todoroo.andlib.service.ExceptionService; +import com.todoroo.andlib.service.ExceptionService.TodorooUncaughtExceptionHandler; +import com.todoroo.astrid.utility.Constants; + +/** + * Service which handles jobs that need to be run when user's phone or Astrid + * starts up. + * + * @author Tim Su + * + */ +public class StartupService extends BroadcastReceiver { + + static { + AstridDependencyInjector.initialize(); + } + + // --- system startup + + @Override + /** Called when the system is started up */ + public void onReceive(Context context, Intent intent) { + ContextManager.setContext(context); + Notifications.scheduleAllAlarms(context); + } + + // --- application startup + + @Autowired + ExceptionService exceptionService; + + @Autowired + UpgradeService upgradeService; + + /** + * bit to prevent multiple initializations + */ + private static boolean hasStartedUp = false; + + /** Called when this application is started up */ + public synchronized void onStartupApplication(final Context context) { + if(hasStartedUp) + return; + + // set uncaught exception handler + Thread.setDefaultUncaughtExceptionHandler(new TodorooUncaughtExceptionHandler()); + + // sets up context manager + ContextManager.setContext(context); + + // read current version + int latestSetVersion = Preferences.getCurrentVersion(context); + int version = 0; + try { + PackageManager pm = context.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(Constants.PACKAGE, 0); + version = pi.versionCode; + } catch (Exception e) { + exceptionService.reportError("astrid-startup-package-read", e); //$NON-NLS-1$ + } + + // invoke upgrade service + boolean justUpgraded = latestSetVersion != version; + if(justUpgraded) { + upgradeService.performUpgrade(latestSetVersion); + Preferences.setCurrentVersion(context, version); + } + + // perform startup activities in a background thread + new Thread(new Runnable() { + public void run() { + // schedule alarms + Notifications.scheduleAllAlarms(context); + + // start widget updating alarm + AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); + Intent intent = new Intent(context, UpdateService.class); + PendingIntent pendingIntent = PendingIntent.getService(context, + 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + am.setInexactRepeating(AlarmManager.RTC, 0, + Constants.WIDGET_UPDATE_INTERVAL, pendingIntent); + + // start synchronization service + if(Constants.SYNCHRONIZE) + SynchronizationService.scheduleService(context); + + // start backup service + BackupService.scheduleService(context); + } + }).start(); + + Preferences.setPreferenceDefaults(context); + + // check for task killers + if(!Constants.OEM) + showTaskKillerHelp(context); + + hasStartedUp = true; + } + + private static void showTaskKillerHelp(final Context context) { + if(!Preferences.shouldShowTaskKillerHelp(context)) + return; + + // search for task killers. if they exist, show the help! + PackageManager pm = context.getPackageManager(); + List apps = pm + .getInstalledPackages(PackageManager.GET_PERMISSIONS); + outer: for (PackageInfo app : apps) { + if(app == null || app.requestedPermissions == null) + continue; + if(app.packageName.startsWith("com.android")) //$NON-NLS-1$ + continue; + for (String permission : app.requestedPermissions) { + if (Manifest.permission.RESTART_PACKAGES.equals(permission)) { + CharSequence appName = app.applicationInfo.loadLabel(pm); + OnClickListener listener = new OnClickListener() { + @Override + public void onClick(DialogInterface arg0, + int arg1) { + Preferences.disableTaskKillerHelp(context); + } + }; + + new AlertDialog.Builder(context) + .setTitle(R.string.information_title) + .setMessage(context.getString(R.string.task_killer_help, + appName)) + .setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(R.string.task_killer_help_ok, listener) + .show(); + + break outer; + } + } + } + } +} diff --git a/astrid/src/com/todoroo/astrid/utility/Constants.java b/astrid/src/com/todoroo/astrid/utility/Constants.java index f0d6ee054..70fc9fdc3 100644 --- a/astrid/src/com/todoroo/astrid/utility/Constants.java +++ b/astrid/src/com/todoroo/astrid/utility/Constants.java @@ -7,4 +7,25 @@ public final class Constants { */ public static final String FLURRY_KEY = "T3JAY9TV2JFMJR4YTG16"; //$NON-NLS-1$ + /** + * Application Package + */ + public static final String PACKAGE = "com.timsu.astrid"; //$NON-NLS-1$ + + /** + * Whether this is an OEM installation + */ + public static final boolean OEM = false; + + /** + * Whether to display synchronization options + */ + public static final boolean SYNCHRONIZE = !OEM; + + /** + * Interval to update the widget (in order to detect hidden tasks + * becoming visible) + */ + public static final long WIDGET_UPDATE_INTERVAL = 30 * 60 * 1000L; + }