diff --git a/README.md b/README.md index 9cb523948..4696a6b58 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,12 @@ Getting Started With Development 9. Sign a [Contributors License Agreement](https://github.com/downloads/todoroo/astrid/Contributors%20Licensing%20Agreement.pdf) and send it to astrid AT todoroo.com +Testing on a device - debugging +--------------- +If you have trouble running Astrid on your device, it is recommended to: +1. Fully uninstall Astrid from the device: adb uninstall com.timsu.astrid +2. Restart Eclipse + Contributors workflow --------------- diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index 7a3502b3b..6de167651 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -8,7 +8,7 @@ - + @@ -56,7 +56,7 @@ android:minSdkVersion="3" /> - + diff --git a/astrid/plugin-src/com/todoroo/astrid/core/CustomFilterAdapter.java b/astrid/plugin-src/com/todoroo/astrid/core/CustomFilterAdapter.java index 14148baf4..07676f8fc 100644 --- a/astrid/plugin-src/com/todoroo/astrid/core/CustomFilterAdapter.java +++ b/astrid/plugin-src/com/todoroo/astrid/core/CustomFilterAdapter.java @@ -31,7 +31,7 @@ import com.todoroo.astrid.data.AddOn; * * @author Tim Su * - */ + */ public class CustomFilterAdapter extends ArrayAdapter { private final CustomFilterActivity activity; diff --git a/astrid/src/com/todoroo/astrid/activity/EditPreferences.java b/astrid/src/com/todoroo/astrid/activity/EditPreferences.java index 0bb80280c..cd32cbae5 100644 --- a/astrid/src/com/todoroo/astrid/activity/EditPreferences.java +++ b/astrid/src/com/todoroo/astrid/activity/EditPreferences.java @@ -13,8 +13,8 @@ import org.weloveastrid.rmilk.MilkUtilities; import android.content.ActivityNotFoundException; import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; import android.content.Intent; +import android.content.DialogInterface.OnClickListener; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; @@ -22,9 +22,9 @@ import android.net.Uri; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen; +import android.preference.Preference.OnPreferenceClickListener; import android.widget.Toast; import com.timsu.astrid.R; @@ -39,6 +39,7 @@ import com.todoroo.andlib.widget.TodorooPreferences; import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.helper.MetadataHelper; import com.todoroo.astrid.service.AddOnService; import com.todoroo.astrid.service.StartupService; import com.todoroo.astrid.service.TaskService; @@ -104,6 +105,9 @@ public class EditPreferences extends TodorooPreferences { int length = resolveInfoList.size(); LinkedHashMap> categoryPreferences = new LinkedHashMap>(); + + // Loop through a list of all packages (including plugins, addons) + // that have a settings action for(int i = 0; i < length; i++) { ResolveInfo resolveInfo = resolveInfoList.get(i); Intent intent = new Intent(AstridApiConstants.ACTION_SETTINGS); @@ -118,23 +122,7 @@ public class EditPreferences extends TodorooPreferences { preference.setTitle(resolveInfo.activityInfo.loadLabel(pm)); preference.setIntent(intent); - // category - either from metadata, or the application name - String category = null; - if(resolveInfo.activityInfo.metaData != null && - resolveInfo.activityInfo.metaData.containsKey(METADATA_CATEGORY)) { - int resource = resolveInfo.activityInfo.metaData.getInt(METADATA_CATEGORY, -1); - if(resource > -1) { - try { - category = pm.getResourcesForApplication(resolveInfo.activityInfo.applicationInfo).getString(resource); - } catch (Exception e) { - // - } - } else { - category = resolveInfo.activityInfo.metaData.getString(METADATA_CATEGORY); - } - } - if(category == null) - category = resolveInfo.activityInfo.applicationInfo.loadLabel(pm).toString(); + String category = MetadataHelper.resolveActivityCategoryName(resolveInfo, pm); if(!categoryPreferences.containsKey(category)) categoryPreferences.put(category, new ArrayList()); diff --git a/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java b/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java index 30d9b82d6..e2741a4c9 100644 --- a/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java +++ b/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java @@ -1,11 +1,12 @@ package com.todoroo.astrid.activity; +import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashSet; import java.util.List; -import java.util.Map.Entry; import java.util.Timer; import java.util.TimerTask; +import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicReference; import android.app.AlertDialog; @@ -29,28 +30,28 @@ import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnKeyListener; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.View.OnClickListener; +import android.view.View.OnKeyListener; import android.view.inputmethod.EditorInfo; import android.widget.AbsListView; -import android.widget.AbsListView.OnScrollListener; -import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; +import android.widget.AbsListView.OnScrollListener; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.TextView.OnEditorActionListener; import com.timsu.astrid.R; import com.todoroo.andlib.data.Property; @@ -78,6 +79,7 @@ import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.dao.TaskDao.TaskCriteria; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.helper.MetadataHelper; import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader; import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader.ContextMenuItem; import com.todoroo.astrid.reminders.Notifications; @@ -258,11 +260,9 @@ public class TaskListActivity extends ListActivity implements OnScrollListener, item.setIcon(android.R.drawable.ic_menu_sort_by_size); } - if(syncActions.size() > 0) { - item = menu.add(Menu.NONE, MENU_SYNC_ID, Menu.NONE, - R.string.TLA_menu_sync); - item.setIcon(R.drawable.ic_menu_refresh); - } + item = menu.add(Menu.NONE, MENU_SYNC_ID, Menu.NONE, + R.string.TLA_menu_sync); + item.setIcon(R.drawable.ic_menu_refresh); item = menu.add(Menu.NONE, MENU_HELP_ID, Menu.NONE, R.string.TLA_menu_help); @@ -348,6 +348,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener, } }); + // set listener for showing quick add button if text not empty quickAddButton = ((ImageButton)findViewById(R.id.quickAddButton)); quickAddBox.addTextChangedListener(new TextWatcher() { @@ -841,10 +842,62 @@ public class TaskListActivity extends ListActivity implements OnScrollListener, .show(); } + /** + * Intent object with custom label returned by toString. + * @author joshuagross + */ + private class IntentWithLabel extends Intent { + private final String label; + public IntentWithLabel (Intent in, String labelIn) { + super(in); + label = labelIn; + } + @Override + public String toString () { + return label; + } + } + private void performSyncAction() { - if(syncActions.size() == 0) - return; - if(syncActions.size() == 1) { + if (syncActions.size() == 0) { + String desiredCategory = getString(R.string.SyP_label); + + // Get a list of all sync plugins and bring user to the prefs pane + // for one of them + Intent queryIntent = new Intent(AstridApiConstants.ACTION_SETTINGS); + PackageManager pm = getPackageManager(); + List resolveInfoList = pm.queryIntentActivities( + queryIntent, PackageManager.GET_META_DATA); + int length = resolveInfoList.size(); + ArrayList syncIntents = new ArrayList(); + + // Loop through a list of all packages (including plugins, addons) + // that have a settings action: filter to sync actions + 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); + + String category = MetadataHelper.resolveActivityCategoryName(resolveInfo, pm); + + if (category.equals(desiredCategory)) { + syncIntents.add(new IntentWithLabel(intent, + resolveInfo.activityInfo.loadLabel(pm).toString())); + } + } + + final Intent[] actions = syncIntents.toArray(new Intent[syncIntents.size()]); + DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface click, int which) { + startActivity(actions[which]); + } + }; + + showSyncOptionMenu(actions, listener); + } + else if(syncActions.size() == 1) { SyncAction syncAction = syncActions.iterator().next(); try { syncAction.intent.send(); @@ -854,9 +907,9 @@ public class TaskListActivity extends ListActivity implements OnScrollListener, // } } else { + // We have >1 sync actions, pop up a dialogue so the user can + // select just one of them (only sync one at a time) final SyncAction[] actions = syncActions.toArray(new SyncAction[syncActions.size()]); - ArrayAdapter adapter = new ArrayAdapter(this, - android.R.layout.simple_spinner_dropdown_item, actions); DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface click, int which) { @@ -869,16 +922,28 @@ public class TaskListActivity extends ListActivity implements OnScrollListener, } } }; - - // show a menu of available options - new AlertDialog.Builder(this) - .setTitle(R.string.SyP_label) - .setAdapter(adapter, listener) - .show().setOwnerActivity(this); - + showSyncOptionMenu(actions, listener); } } + /** + * Show menu of sync options. This is shown when you're not logged into any services, or logged into + * more than one. + * @param + * @param items + * @param listener + */ + private void showSyncOptionMenu(TYPE[] items, DialogInterface.OnClickListener listener) { + ArrayAdapter adapter = new ArrayAdapter(this, + android.R.layout.simple_spinner_dropdown_item, items); + + // show a menu of available options + new AlertDialog.Builder(this) + .setTitle(R.string.SyP_label) + .setAdapter(adapter, listener) + .show().setOwnerActivity(this); + } + @Override public boolean onMenuItemSelected(int featureId, final MenuItem item) { Intent intent; @@ -904,7 +969,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener, return true; case MENU_HELP_ID: intent = new Intent(Intent.ACTION_VIEW, - Uri.parse("http://weloveastrid.com/help-user-guide-astrid-v3/active-tasks/")); //$NON-NLS-1$ + Uri.parse("http://weloveastrid.com/help-user-guide-astrid-v3/active-tasks/")); startActivity(intent); return true; case MENU_ADDON_INTENT_ID: @@ -966,21 +1031,21 @@ public class TaskListActivity extends ListActivity implements OnScrollListener, if(time == 0 || time == Long.MAX_VALUE) return; - Toast.makeText(TaskListActivity.this, "Scheduled Alarm: " + //$NON-NLS-1$ + Toast.makeText(TaskListActivity.this, "Scheduled Alarm: " + new Date(time), Toast.LENGTH_LONG).show(); ReminderService.getInstance().setScheduler(null); } }); ReminderService.getInstance().scheduleAlarm(task); if(ReminderService.getInstance().getScheduler() != null) - Toast.makeText(this, "No alarms", Toast.LENGTH_LONG).show(); //$NON-NLS-1$ + Toast.makeText(this, "No alarms", Toast.LENGTH_LONG).show(); ReminderService.getInstance().setScheduler(original); return true; } case CONTEXT_MENU_DEBUG + 1: { itemId = item.getGroupId(); - new Notifications().showTaskNotification(itemId, 0, "test reminder"); //$NON-NLS-1$ + new Notifications().showTaskNotification(itemId, 0, "test reminder"); return true; } diff --git a/astrid/src/com/todoroo/astrid/helper/MetadataHelper.java b/astrid/src/com/todoroo/astrid/helper/MetadataHelper.java new file mode 100644 index 000000000..830830827 --- /dev/null +++ b/astrid/src/com/todoroo/astrid/helper/MetadataHelper.java @@ -0,0 +1,38 @@ +package com.todoroo.astrid.helper; + +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; + +/** + * @author joshuagross + */ +public class MetadataHelper { + public static String resolveActivityCategoryName (ResolveInfo resolveInfo, PackageManager pm) { + // category - either from metadata, or the application name + String category = null; + String categoryKey = "category"; + if (resolveInfo.activityInfo.metaData != null && resolveInfo.activityInfo.metaData.containsKey(categoryKey)) { + int resource = resolveInfo.activityInfo.metaData.getInt( + categoryKey, -1); + if (resource > -1) { + // category stored as integer in Manifest + try { + category = pm.getResourcesForApplication( + resolveInfo.activityInfo.applicationInfo).getString( + resource); + } catch (Exception e) { + // + } + } else { + // category stored as String in Manifest + category = resolveInfo.activityInfo.metaData.getString(categoryKey); + } + } + // If category is null at this point, we use the name of the application this activity is found in + if (category == null) { + category = resolveInfo.activityInfo.applicationInfo.loadLabel(pm).toString(); + } + + return category; + } +}