From 086b4c9f293472e9f69dcd122270618bcd4ae2aa Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Thu, 24 Jan 2013 13:14:40 -0800 Subject: [PATCH] Load task actions on main thread, don't read notes into cursor --- api/src/com/todoroo/andlib/data/Property.java | 5 + .../astrid/core/LinkActionExposer.java | 30 ++- .../astrid/activity/TaskListFragment.java | 12 +- .../todoroo/astrid/adapter/TaskAdapter.java | 183 ++++++++++-------- 4 files changed, 128 insertions(+), 102 deletions(-) diff --git a/api/src/com/todoroo/andlib/data/Property.java b/api/src/com/todoroo/andlib/data/Property.java index 358995c71..f0da9cff8 100644 --- a/api/src/com/todoroo/andlib/data/Property.java +++ b/api/src/com/todoroo/andlib/data/Property.java @@ -130,6 +130,11 @@ public abstract class Property extends Field implements Cloneable { PropertyVisitor visitor, PARAMETER data) { return visitor.visitInteger(this, data); } + + @Override + public IntegerProperty as(String newAlias) { + return (IntegerProperty) super.as(newAlias); + } } /** diff --git a/astrid/plugin-src/com/todoroo/astrid/core/LinkActionExposer.java b/astrid/plugin-src/com/todoroo/astrid/core/LinkActionExposer.java index b691ce51f..b95e38245 100644 --- a/astrid/plugin-src/com/todoroo/astrid/core/LinkActionExposer.java +++ b/astrid/plugin-src/com/todoroo/astrid/core/LinkActionExposer.java @@ -5,7 +5,6 @@ */ package com.todoroo.astrid.core; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -19,7 +18,6 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.text.Spannable; -import android.text.TextUtils; import android.text.style.URLSpan; import android.text.util.Linkify; @@ -39,51 +37,47 @@ import com.todoroo.astrid.notes.NotesAction; */ public class LinkActionExposer { - private PackageManager pm; + public static TaskAction getActionsForTask(Context context, Task task, boolean hasAttachments, boolean hasNotes) { + if (task == null) return null; - public List getActionsForTask(Context context, Task task, boolean hasAttachments) { - List result = new ArrayList(); - if (task == null) return result; - - String notes = task.getValue(Task.NOTES); Spannable titleSpan = Spannable.Factory.getInstance().newSpannable(task.getValue(Task.TITLE)); Linkify.addLinks(titleSpan, Linkify.ALL); URLSpan[] urlSpans = titleSpan.getSpans(0, titleSpan.length(), URLSpan.class); - if(urlSpans.length == 0 && TextUtils.isEmpty(notes) && + if(urlSpans.length == 0 && !hasNotes && !hasAttachments) - return result; + return null; - pm = context.getPackageManager(); + PackageManager pm = context.getPackageManager(); for(URLSpan urlSpan : urlSpans) { String url = urlSpan.getURL(); int start = titleSpan.getSpanStart(urlSpan); int end = titleSpan.getSpanEnd(urlSpan); String text = titleSpan.subSequence(start, end).toString(); - TaskAction taskAction = createLinkAction(context, task.getId(), url, text); + TaskAction taskAction = createLinkAction(context, task.getId(), url, text, pm); if (taskAction != null) - result.add(taskAction); + return taskAction; } Resources r = context.getResources(); if (hasAttachments) { BitmapDrawable icon = getBitmapDrawable(R.drawable.action_attachments, r); FilesAction filesAction = new FilesAction("", null, icon); //$NON-NLS-1$ - result.add(filesAction); + return filesAction; } - if (!TextUtils.isEmpty(notes) && !Preferences.getBoolean(R.string.p_showNotes, false)) { + if (hasNotes && !Preferences.getBoolean(R.string.p_showNotes, false)) { BitmapDrawable icon = getBitmapDrawable(R.drawable.action_notes, r); NotesAction notesAction = new NotesAction("", null, icon); //$NON-NLS-1$ - result.add(notesAction); + return notesAction; } - return result; + return null; } @SuppressWarnings("nls") - private TaskAction createLinkAction(Context context, long id, String url, String text) { + private static TaskAction createLinkAction(Context context, long id, String url, String text, PackageManager pm) { Intent itemIntent = new Intent(Intent.ACTION_VIEW); itemIntent.setData(Uri.parse(url)); List resolveInfoList = pm.queryIntentActivities(itemIntent, 0); diff --git a/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java b/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java index 0d11dbc93..d377e14b0 100644 --- a/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java +++ b/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java @@ -87,6 +87,7 @@ import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.files.FileMetadata; import com.todoroo.astrid.helper.SyncActionHelper; import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader; import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader.ContextMenuItem; @@ -912,6 +913,8 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, public static final String TAGS_METADATA_JOIN = "for_tags"; //$NON-NLS-1$ + public static final String FILE_METADATA_JOIN = "for_actions"; //$NON-NLS-1$ + /** * Fill in the Task List with current items * @@ -966,10 +969,13 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, // Eventually, we might consider restructuring things so that this query is constructed elsewhere. String joinedQuery = Join.left(Metadata.TABLE.as(TR_METADATA_JOIN), - Criterion.and(Field.field(TR_METADATA_JOIN + "." + Metadata.KEY.name).eq(TaskRabbitMetadata.METADATA_KEY), //$NON-NLS-1$ - Task.ID.eq(Field.field(TR_METADATA_JOIN + "." + Metadata.TASK.name)))).toString() //$NON-NLS-1$ + Criterion.and(Field.field(TR_METADATA_JOIN + "." + Metadata.KEY.name).eq(TaskRabbitMetadata.METADATA_KEY), + Task.ID.eq(Field.field(TR_METADATA_JOIN + "." + Metadata.TASK.name)))).toString() + Join.left(Metadata.TABLE.as(TAGS_METADATA_JOIN), - tagsJoinCriterion).toString() //$NON-NLS-1$ + tagsJoinCriterion).toString() + +Join.left(Metadata.TABLE.as(FILE_METADATA_JOIN), + Criterion.and(Field.field(FILE_METADATA_JOIN + "." + Metadata.KEY.name).eq(FileMetadata.METADATA_KEY), + Task.ID.eq(Field.field(FILE_METADATA_JOIN + "." + Metadata.TASK.name)))) + filter.getSqlQuery(); sqlQueryTemplate.set(SortHelper.adjustQueryForFlagsAndSort( diff --git a/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java b/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java index 762fcf300..2a1a8bad2 100644 --- a/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java +++ b/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java @@ -9,7 +9,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicReference; @@ -59,30 +58,25 @@ import android.widget.TextView; import com.timsu.astrid.R; import com.todoroo.andlib.data.Property; +import com.todoroo.andlib.data.Property.IntegerProperty; import com.todoroo.andlib.data.Property.LongProperty; import com.todoroo.andlib.data.Property.StringProperty; import com.todoroo.andlib.data.TodorooCursor; 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.sql.Field; -import com.todoroo.andlib.sql.Join; -import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.Pair; import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.activity.TaskListFragment; import com.todoroo.astrid.api.AstridApiConstants; -import com.todoroo.astrid.api.PermaSql; import com.todoroo.astrid.api.TaskAction; import com.todoroo.astrid.api.TaskDecoration; import com.todoroo.astrid.api.TaskDecorationExposer; import com.todoroo.astrid.core.LinkActionExposer; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.files.FileMetadata; import com.todoroo.astrid.files.FilesAction; import com.todoroo.astrid.files.FilesControlSet; import com.todoroo.astrid.helper.AsyncImageView; @@ -118,6 +112,9 @@ public class TaskAdapter extends CursorAdapter implements Filterable { @SuppressWarnings("nls") private static final StringProperty TAGS = new StringProperty(null, "group_concat(" + TaskListFragment.TAGS_METADATA_JOIN + "." + TagService.TAG.name + ", ' | ')").as("tags"); + @SuppressWarnings("nls") + private static final LongProperty FILE_ID_PROPERTY = new LongProperty(Metadata.TABLE.as(TaskListFragment.FILE_METADATA_JOIN), Metadata.ID.name).as("fileId"); + private static final IntegerProperty HAS_NOTES_PROPERTY = new IntegerProperty(null, "length(" + Task.NOTES + ") > 0").as("hasNotes"); // --- other constants @@ -136,13 +133,14 @@ public class TaskAdapter extends CursorAdapter implements Filterable { Task.ELAPSED_SECONDS, Task.TIMER_START, Task.RECURRENCE, - Task.NOTES, Task.USER_ID, Task.USER, Task.REMINDER_LAST, Task.SOCIAL_REMINDER, + HAS_NOTES_PROPERTY, // Whether or not the task has notes TASK_RABBIT_ID, // Task rabbit metadata id (non-zero means it exists) - TAGS // Concatenated list of tags + TAGS, // Concatenated list of tags + FILE_ID_PROPERTY // File id }; public static final Property[] BASIC_PROPERTIES = new Property[] { @@ -206,6 +204,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable { public static int APPLY_LISTENERS_ROW_BODY= 1; public static int APPLY_LISTENERS_NONE = 2; + protected final Context context; protected final TaskListFragment fragment; protected final Resources resources; protected final HashMap completedItems = new HashMap(0); @@ -214,7 +213,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable { protected final int resource; protected final LayoutInflater inflater; private DetailLoaderThread detailLoader; - private ActionsLoaderThread actionsLoader; +// private ActionsLoaderThread actionsLoader; private int fontSize; protected int applyListeners = APPLY_LISTENERS_PARENT; private long mostRecentlyMade = -1; @@ -254,6 +253,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable { super(ContextManager.getContext(), c, autoRequery); DependencyInjectionService.getInstance().inject(this); + this.context = ContextManager.getContext(); this.query = query; this.resource = resource; this.titleOnlyLayout = resource == R.layout.task_adapter_row_title_only; @@ -272,7 +272,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable { this.minRowHeight = computeMinRowHeight(); startDetailThread(); - startTaskActionsThread(); +// startTaskActionsThread(); decorationManager = new DecorationManager(); @@ -323,12 +323,12 @@ public class TaskAdapter extends CursorAdapter implements Filterable { } } - private void startTaskActionsThread() { - if (!titleOnlyLayout) { - actionsLoader = new ActionsLoaderThread(); - actionsLoader.start(); - } - } +// private void startTaskActionsThread() { +// if (!titleOnlyLayout) { +// actionsLoader = new ActionsLoaderThread(); +// actionsLoader.start(); +// } +// } /* ====================================================================== * =========================================================== filterable @@ -415,6 +415,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable { if (!titleOnlyLayout) { viewHolder.isTaskRabbit = (cursor.get(TASK_RABBIT_ID) > 0); viewHolder.tagsString = cursor.get(TAGS); + viewHolder.hasFiles = cursor.get(FILE_ID_PROPERTY) > 0; + viewHolder.hasNotes = cursor.get(HAS_NOTES_PROPERTY) > 0; } Task task = viewHolder.task; @@ -447,6 +449,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable { public ImageView taskActionIcon; public boolean isTaskRabbit; // From join query, not part of the task model public String tagsString; // From join query, not part of the task model + public boolean hasFiles; // From join query, not part of the task model + public boolean hasNotes; public View[] decorations; } @@ -511,13 +515,11 @@ public class TaskAdapter extends CursorAdapter implements Filterable { // Task action ImageView taskAction = viewHolder.taskActionIcon; if (taskAction != null) { - if (taskActionLoader.containsKey(task.getId())) { + TaskAction action = getTaskAction(task, viewHolder.hasFiles, viewHolder.hasNotes); + if (action != null) { taskAction.setVisibility(View.VISIBLE); - TaskAction action = taskActionLoader.get(task.getId()); - if (action != null) { - taskAction.setImageDrawable(action.icon); - taskAction.setTag(action); - } + taskAction.setImageDrawable(action.icon); + taskAction.setTag(action); } else { taskAction.setVisibility(View.GONE); taskAction.setTag(null); @@ -529,6 +531,18 @@ public class TaskAdapter extends CursorAdapter implements Filterable { } + private TaskAction getTaskAction(Task task, boolean hasFiles, boolean hasNotes) { + if (titleOnlyLayout || task.isCompleted() || !task.isEditable()) + return null; + if (taskActionLoader.containsKey(task.getId())) { + return taskActionLoader.get(task.getId()); + } else { + TaskAction action = LinkActionExposer.getActionsForTask(context, task, hasFiles, hasNotes); + taskActionLoader.put(task.getId(), action); + return action; + } + } + @SuppressWarnings("nls") private void drawDetails(ViewHolder viewHolder, String details, float rightWidth) { SpannableStringBuilder prospective = new SpannableStringBuilder(); @@ -623,6 +637,13 @@ public class TaskAdapter extends CursorAdapter implements Filterable { } private void showEditNotesDialog(final Task task) { + String notes = null; + Task t = taskService.fetchById(task.getId(), Task.NOTES); + if (t != null) + notes = t.getValue(Task.NOTES); + if (TextUtils.isEmpty(notes)) + return; + int theme = ThemeService.getEditDialogTheme(); final Dialog dialog = new Dialog(fragment.getActivity(), theme); dialog.setTitle(R.string.TEA_note_label); @@ -637,7 +658,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable { }); final TextView notesField = (TextView) notesView.findViewById(R.id.notes); - notesField.setText(task.getValue(Task.NOTES)); + notesField.setText(notes); LayoutParams params = dialog.getWindow().getAttributes(); params.width = LayoutParams.FILL_PARENT; @@ -785,62 +806,62 @@ public class TaskAdapter extends CursorAdapter implements Filterable { private final Map taskActionLoader = Collections.synchronizedMap(new HashMap()); - @SuppressWarnings("nls") - public class ActionsLoaderThread extends Thread { - public static final String FILE_COLUMN = "fileId"; - private static final String METADATA_JOIN = "for_actions"; - - private final LongProperty fileIdProperty = new LongProperty(Metadata.TABLE.as(METADATA_JOIN), - Metadata.ID.name).as(FILE_COLUMN); - - @Override - public void run() { - AndroidUtilities.sleepDeep(500L); - String groupedQuery = query.get(); - - groupedQuery = PermaSql.replacePlaceholders(groupedQuery); - - Query q = Query.select(Task.ID, Task.TITLE, Task.NOTES, Task.COMPLETION_DATE, Task.FLAGS, Task.USER_ID, - fileIdProperty) - .join(Join.left(Metadata.TABLE.as(METADATA_JOIN), - Criterion.and(Field.field(METADATA_JOIN + "." + Metadata.KEY.name).eq(FileMetadata.METADATA_KEY), - Task.ID.eq(Field.field(METADATA_JOIN + "." + Metadata.TASK.name))))).withQueryTemplate(groupedQuery); - final TodorooCursor fetchCursor = taskService.query(q); - - try { - Task task = new Task(); - LinkActionExposer linkActionExposer = new LinkActionExposer(); - - for(fetchCursor.moveToFirst(); !fetchCursor.isAfterLast(); fetchCursor.moveToNext()) { - task.clear(); - task.readFromCursor(fetchCursor); - if(task.isCompleted() || !task.isEditable()) - continue; - - boolean hasAttachments = (fetchCursor.get(fileIdProperty) > 0); - List actions = linkActionExposer. - getActionsForTask(ContextManager.getContext(), task, hasAttachments); - if (actions.size() > 0) - taskActionLoader.put(task.getId(), actions.get(0)); - else - taskActionLoader.remove(task.getId()); - } - } finally { - fetchCursor.close(); - } - final Activity activity = fragment.getActivity(); - if (activity != null) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - if(taskActionLoader.size() > 0) { - notifyDataSetChanged(); - } - } - }); - } - } - } +// @SuppressWarnings("nls") +// public class ActionsLoaderThread extends Thread { +// public static final String FILE_COLUMN = "fileId"; +// private static final String METADATA_JOIN = "for_actions"; +// +// private final LongProperty fileIdProperty = new LongProperty(Metadata.TABLE.as(METADATA_JOIN), +// Metadata.ID.name).as(FILE_COLUMN); +// +// @Override +// public void run() { +// AndroidUtilities.sleepDeep(500L); +// String groupedQuery = query.get(); +// +// groupedQuery = PermaSql.replacePlaceholders(groupedQuery); +// +// Query q = Query.select(Task.ID, Task.TITLE, Task.NOTES, Task.COMPLETION_DATE, Task.FLAGS, Task.USER_ID, +// fileIdProperty) +// .join(Join.left(Metadata.TABLE.as(METADATA_JOIN), +// Criterion.and(Field.field(METADATA_JOIN + "." + Metadata.KEY.name).eq(FileMetadata.METADATA_KEY), +// Task.ID.eq(Field.field(METADATA_JOIN + "." + Metadata.TASK.name))))).withQueryTemplate(groupedQuery); +// final TodorooCursor fetchCursor = taskService.query(q); +// +// try { +// Task task = new Task(); +// LinkActionExposer linkActionExposer = new LinkActionExposer(); +// +// for(fetchCursor.moveToFirst(); !fetchCursor.isAfterLast(); fetchCursor.moveToNext()) { +// task.clear(); +// task.readFromCursor(fetchCursor); +// if(task.isCompleted() || !task.isEditable()) +// continue; +// +// boolean hasAttachments = (fetchCursor.get(fileIdProperty) > 0); +// List actions = linkActionExposer. +// getActionsForTask(ContextManager.getContext(), task, hasAttachments); +// if (actions.size() > 0) +// taskActionLoader.put(task.getId(), actions.get(0)); +// else +// taskActionLoader.remove(task.getId()); +// } +// } finally { +// fetchCursor.close(); +// } +// final Activity activity = fragment.getActivity(); +// if (activity != null) { +// activity.runOnUiThread(new Runnable() { +// @Override +// public void run() { +// if(taskActionLoader.size() > 0) { +// notifyDataSetChanged(); +// } +// } +// }); +// } +// } +// } /** * Add detail to a task @@ -918,7 +939,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable { decorationManager.clearCache(); taskDetailLoader.clear(); startDetailThread(); - startTaskActionsThread(); +// startTaskActionsThread(); } /**