diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/TagViewFragment.java b/astrid/plugin-src/com/todoroo/astrid/actfm/TagViewFragment.java index 5ea1de6ee..d3baaf004 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/TagViewFragment.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/TagViewFragment.java @@ -50,6 +50,7 @@ import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Update; import com.todoroo.astrid.helper.ProgressBarSyncResultCallback; +import com.todoroo.astrid.service.SyncV2Service; import com.todoroo.astrid.service.TagDataService; import com.todoroo.astrid.tags.TagFilterExposer; import com.todoroo.astrid.tags.TagService.Tag; @@ -80,6 +81,8 @@ public class TagViewFragment extends TaskListFragment { @Autowired ActFmPreferenceService actFmPreferenceService; + @Autowired SyncV2Service syncService; + private View taskListView; private boolean dataLoaded = false; @@ -210,7 +213,7 @@ public class TagViewFragment extends TaskListFragment { } @Override - protected TagData getTagDataForUpdates() { + protected TagData getActiveTagData() { return tagData; } diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksListFragment.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksListFragment.java index 47f5d50f8..ab993182c 100644 --- a/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksListFragment.java +++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/GtasksListFragment.java @@ -24,6 +24,7 @@ import com.todoroo.astrid.dao.StoreObjectDao; import com.todoroo.astrid.data.StoreObject; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.gtasks.sync.GtasksSyncService; +import com.todoroo.astrid.service.SyncV2Service; public class GtasksListFragment extends DraggableTaskListFragment { @@ -45,6 +46,8 @@ public class GtasksListFragment extends DraggableTaskListFragment { @Autowired private GtasksPreferenceService gtasksPreferenceService; + @Autowired private SyncV2Service syncService; + private StoreObject list; @Override @@ -123,7 +126,7 @@ public class GtasksListFragment extends DraggableTaskListFragment { @Override protected void initiateAutomaticSync() { if (list != null && DateUtilities.now() - list.getValue(GtasksList.LAST_SYNC) > DateUtilities.ONE_HOUR) { - syncService.synchronizeList(list, false, syncResultCallback); + syncService.synchronizeList(list, false, syncActionHelper.syncResultCallback); } } @@ -139,7 +142,7 @@ public class GtasksListFragment extends DraggableTaskListFragment { // handle my own menus switch (item.getItemId()) { case MENU_REFRESH_ID: - syncService.synchronizeList(list, true, syncResultCallback); + syncService.synchronizeList(list, true, syncActionHelper.syncResultCallback); return true; case MENU_CLEAR_COMPLETED_ID: clearCompletedTasks(); diff --git a/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java b/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java index 96169815f..bd41da34d 100644 --- a/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java +++ b/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java @@ -1,20 +1,14 @@ package com.todoroo.astrid.activity; -import java.util.ArrayList; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map.Entry; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicReference; -import org.weloveastrid.rmilk.MilkPreferences; -import org.weloveastrid.rmilk.MilkUtilities; - import android.app.Activity; import android.app.AlertDialog; -import android.app.PendingIntent.CanceledException; import android.app.SearchManager; import android.content.BroadcastReceiver; import android.content.ContentValues; @@ -27,7 +21,6 @@ import android.content.SharedPreferences.Editor; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.Cursor; -import android.graphics.PixelFormat; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.ActionBar; @@ -51,20 +44,17 @@ import android.view.View.OnLongClickListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; -import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; 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.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; -import android.widget.Toast; import com.crittercism.NewFeedbackSpringboardActivity; import com.timsu.astrid.R; @@ -77,11 +67,8 @@ import com.todoroo.andlib.service.ExceptionService; import com.todoroo.andlib.sql.Functions; import com.todoroo.andlib.sql.QueryTemplate; import com.todoroo.andlib.utility.AndroidUtilities; -import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.andlib.utility.Preferences; -import com.todoroo.andlib.widget.GestureService; -import com.todoroo.andlib.widget.GestureService.GestureInterface; import com.todoroo.astrid.actfm.ActFmLoginActivity; import com.todoroo.astrid.actfm.EditPeopleControlSet; import com.todoroo.astrid.actfm.TagUpdatesActivity; @@ -94,7 +81,6 @@ import com.todoroo.astrid.adapter.TaskAdapter.ViewHolder; import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.PermaSql; -import com.todoroo.astrid.api.SyncAction; import com.todoroo.astrid.api.TaskContextActionExposer; import com.todoroo.astrid.api.TaskDecoration; import com.todoroo.astrid.core.CoreFilterExposer; @@ -106,8 +92,7 @@ import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.gcal.GCalControlSet; import com.todoroo.astrid.gcal.GCalHelper; -import com.todoroo.astrid.helper.MetadataHelper; -import com.todoroo.astrid.helper.ProgressBarSyncResultCallback; +import com.todoroo.astrid.helper.SyncActionHelper; import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader; import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader.ContextMenuItem; import com.todoroo.astrid.reminders.ReminderDebugContextActions; @@ -117,12 +102,9 @@ import com.todoroo.astrid.service.AstridDependencyInjector; import com.todoroo.astrid.service.MetadataService; import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsService; -import com.todoroo.astrid.service.SyncV2Service; import com.todoroo.astrid.service.TagDataService; import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.service.UpgradeService; -import com.todoroo.astrid.sync.SyncResultCallback; -import com.todoroo.astrid.sync.SyncV2Provider; import com.todoroo.astrid.ui.DateChangedAlerts; import com.todoroo.astrid.ui.DeadlineControlSet; import com.todoroo.astrid.utility.AstridPreferences; @@ -141,7 +123,7 @@ import com.todoroo.astrid.widget.TasksWidget; * */ public class TaskListFragment extends ListFragment implements OnScrollListener, - GestureInterface, OnSortSelectedListener { + OnSortSelectedListener { public static final String TAG_TASKLIST_FRAGMENT = "tasklist_fragment"; //$NON-NLS-1$ @@ -186,41 +168,33 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, // --- instance variables @Autowired - ExceptionService exceptionService; + protected ExceptionService exceptionService; @Autowired protected TaskService taskService; - @Autowired - MetadataService metadataService; + @Autowired MetadataService metadataService; - @Autowired - Database database; + @Autowired Database database; - @Autowired - AddOnService addOnService; + @Autowired AddOnService addOnService; - @Autowired - UpgradeService upgradeService; + @Autowired UpgradeService upgradeService; - @Autowired - protected SyncV2Service syncService; - - @Autowired - TagDataService tagDataService; + @Autowired TagDataService tagDataService; - @Autowired - ActFmPreferenceService actFmPreferenceService; + @Autowired ActFmPreferenceService actFmPreferenceService; private final TaskContextActionExposer[] contextItemExposers = new TaskContextActionExposer[] { new ReminderDebugContextActions.MakeNotification(), - new ReminderDebugContextActions.WhenReminder(), }; + new ReminderDebugContextActions.WhenReminder(), + }; protected TaskAdapter taskAdapter = null; protected DetailReceiver detailReceiver = new DetailReceiver(); protected RefreshReceiver refreshReceiver = new RefreshReceiver(); - protected SyncActionReceiver syncActionReceiver = new SyncActionReceiver(); protected final AtomicReference sqlQueryTemplate = new AtomicReference(); + protected SyncActionHelper syncActionHelper; protected Filter filter; protected int sortFlags; protected int sortSort; @@ -232,12 +206,10 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, private LinearLayout quickAddControls; private View quickAddControlsContainer; private Timer backgroundTimer; - private final LinkedHashSet syncActions = new LinkedHashSet(); private boolean isFilter; private final TaskListContextMenuExtensionLoader contextMenuExtensionLoader = new TaskListContextMenuExtensionLoader(); - protected SyncResultCallback syncResultCallback; private VoiceInputAssistant voiceInputAssistant; // --- fragment handling variables @@ -338,31 +310,12 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, getListView().setItemsCanFocus(false); } - if (Preferences.getInt(AstridPreferences.P_UPGRADE_FROM, -1) > -1) upgradeService.showChangeLog(getActivity(), Preferences.getInt(AstridPreferences.P_UPGRADE_FROM, -1)); if (getActivity().getIntent().hasExtra(TOKEN_SOURCE)) { - switch (getActivity().getIntent().getIntExtra(TOKEN_SOURCE, - Constants.SOURCE_DEFAULT)) { - case Constants.SOURCE_NOTIFICATION: - StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_NOTIFICATION); - break; - case Constants.SOURCE_OTHER: - StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_OTHER); - break; - case Constants.SOURCE_PPWIDGET: - StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_PPW); - break; - case Constants.SOURCE_WIDGET: - StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_WIDGET); - break; - case Constants.SOURCE_C2DM: - StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_C2DM); - break; - } - getActivity().getIntent().putExtra(TOKEN_SOURCE, Constants.SOURCE_DEFAULT); // Only report source once + trackActivitySource(); } getActivity().runOnUiThread(new Runnable() { @@ -372,7 +325,35 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, }); } - protected TagData getTagDataForUpdates() { + /** + * Report who launched this activity + */ + protected void trackActivitySource() { + switch (getActivity().getIntent().getIntExtra(TOKEN_SOURCE, + Constants.SOURCE_DEFAULT)) { + case Constants.SOURCE_NOTIFICATION: + StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_NOTIFICATION); + break; + case Constants.SOURCE_OTHER: + StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_OTHER); + break; + case Constants.SOURCE_PPWIDGET: + StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_PPW); + break; + case Constants.SOURCE_WIDGET: + StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_WIDGET); + break; + case Constants.SOURCE_C2DM: + StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_C2DM); + break; + } + getActivity().getIntent().putExtra(TOKEN_SOURCE, Constants.SOURCE_DEFAULT); // Only report source once + } + + /** + * @return the current tag you are viewing, or null if you're not viewing a tag + */ + protected TagData getActiveTagData() { return null; } @@ -410,7 +391,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, } setUpTaskList(); - ((AstridActivity) getActivity()).setupActivityFragment(getTagDataForUpdates()); + ((AstridActivity) getActivity()).setupActivityFragment(getActiveTagData()); setUpQuickAddControlSets(); contextMenuExtensionLoader.loadInNewThread(getActivity()); @@ -598,32 +579,11 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, } }); - // gestures / animation - try { - GestureService.registerGestureDetector(getActivity(), - R.id.gestures, R.raw.gestures, this); - } catch (VerifyError e) { - // failed check, no gestures :P - } - + // animation SharedPreferences publicPrefs = AstridPreferences.getPublicPrefs(getActivity()); sortFlags = publicPrefs.getInt(SortHelper.PREF_SORT_FLAGS, 0); sortSort = publicPrefs.getInt(SortHelper.PREF_SORT_SORT, 0); - // dithering - getActivity().getWindow().setFormat(PixelFormat.RGBA_8888); - getActivity().getWindow().addFlags( - WindowManager.LayoutParams.FLAG_DITHER); - - syncResultCallback = new ProgressBarSyncResultCallback(getActivity(), - R.id.progressBar, new Runnable() { - @Override - public void run() { - ContextManager.getContext().sendBroadcast( - new Intent( - AstridApiConstants.BROADCAST_EVENT_REFRESH)); - } - }); getView().findViewById(R.id.progressBar).setVisibility(View.GONE); } @@ -659,7 +619,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, private void resetControlSets() { Task empty = new Task(); - TagData tagData = getTagDataForUpdates(); + TagData tagData = getActiveTagData(); if (tagData != null) { HashSet tagsTransitory = new HashSet(); tagsTransitory.add(tagData.getValue(TagData.NAME)); @@ -668,7 +628,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, repeatControl.readFromTask(empty); gcalControl.readFromTask(empty); deadlineControl.readFromTask(empty); - peopleControl.setUpData(empty, getTagDataForUpdates()); + peopleControl.setUpData(empty, getActiveTagData()); peopleControl.assignToMe(); peopleControl.setTask(null); } @@ -745,9 +705,8 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, new IntentFilter(AstridApiConstants.BROADCAST_SEND_DECORATIONS)); getActivity().registerReceiver(refreshReceiver, new IntentFilter(AstridApiConstants.BROADCAST_EVENT_REFRESH)); - getActivity().registerReceiver( - syncActionReceiver, - new IntentFilter(AstridApiConstants.BROADCAST_SEND_SYNC_ACTIONS)); + syncActionHelper.register(); + setUpBackgroundJobs(); if (!Preferences.getBoolean( @@ -772,6 +731,10 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, initiateAutomaticSync(); } + protected void initiateAutomaticSync() { + syncActionHelper.initiateAutomaticSync(filter); + } + @Override public void onPause() { super.onPause(); @@ -779,7 +742,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, try { getActivity().unregisterReceiver(detailReceiver); getActivity().unregisterReceiver(refreshReceiver); - getActivity().unregisterReceiver(syncActionReceiver); + syncActionHelper.unregister(); } catch (IllegalArgumentException e) { // might not have fully initialized } @@ -821,31 +784,6 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, taskService.cleanup(); } - /** - * Receiver which receives sync provider intents - * - * @author Tim Su - * - */ - protected class SyncActionReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (intent == null - || !AstridApiConstants.BROADCAST_SEND_SYNC_ACTIONS.equals(intent.getAction())) - return; - - try { - Bundle extras = intent.getExtras(); - SyncAction syncAction = extras.getParcelable(AstridApiConstants.EXTRAS_RESPONSE); - syncActions.add(syncAction); - } catch (Exception e) { - exceptionService.reportError("receive-sync-action-" + //$NON-NLS-1$ - intent.getStringExtra(AstridApiConstants.EXTRAS_ADDON), - e); - } - } - } - /** * Receiver which receives detail or decoration intents * @@ -987,11 +925,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, getListView().setSelection(oldListItemSelected); // also load sync actions - syncActions.clear(); - Intent broadcastIntent = new Intent( - AstridApiConstants.BROADCAST_REQUEST_SYNC_ACTIONS); - getActivity().sendOrderedBroadcast(broadcastIntent, - AstridApiConstants.PERMISSION_READ); + syncActionHelper.request(); } /** @@ -1024,6 +958,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, setListAdapter(taskAdapter); getListView().setOnScrollListener(this); registerForContextMenu(getListView()); + syncActionHelper = new SyncActionHelper(getActivity()); loadTaskListContent(true); } @@ -1291,7 +1226,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, */ protected void handleCommentsButtonClicked() { Intent intent = new Intent(getActivity(), TagUpdatesActivity.class); - intent.putExtra(TagViewFragment.EXTRA_TAG_DATA, getTagDataForUpdates()); + intent.putExtra(TagViewFragment.EXTRA_TAG_DATA, getActiveTagData()); startActivity(intent); AndroidUtilities.callOverridePendingTransition(getActivity(), R.anim.slide_left_in, R.anim.slide_left_out); } @@ -1367,153 +1302,6 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, }).setNegativeButton(android.R.string.cancel, null).show(); } - /** - * Intent object with custom label returned by toString. - * - * @author joshuagross - */ - protected static 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 static final String PREF_LAST_AUTO_SYNC = "taskListLastAutoSync"; //$NON-NLS-1$ - - protected void initiateAutomaticSync() { - if (filter == null || filter.title == null - || !filter.title.equals(getString(R.string.BFE_Active))) - return; - - long lastAutoSync = Preferences.getLong(PREF_LAST_AUTO_SYNC, 0); - if (DateUtilities.now() - lastAutoSync > DateUtilities.ONE_HOUR) { - performSyncServiceV2Sync(false); - } - } - - protected void performSyncServiceV2Sync(boolean manual) { - syncService.synchronizeActiveTasks(manual, syncResultCallback); - Preferences.setLong(PREF_LAST_AUTO_SYNC, DateUtilities.now()); - } - - protected void performSyncAction() { - List activeV2Providers = syncService.activeProviders(); - int activeSyncs = syncActions.size() + activeV2Providers.size(); - - if (activeSyncs == 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 = getActivity().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 (MilkPreferences.class.getName().equals( - resolveInfo.activityInfo.name) - && !MilkUtilities.INSTANCE.isLoggedIn()) - continue; - - 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 { - // We have sync actions, pop up a dialogue so the user can - // select just one of them (only sync one at a time) - final Object[] actions = new Object[activeSyncs]; - - int i; - for (i = 0; i < activeV2Providers.size(); i++) - actions[i] = activeV2Providers.get(i); - for (SyncAction syncAction : syncActions) - actions[i++] = syncAction; - - DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface click, int which) { - if (actions[which] instanceof SyncAction) { - try { - ((SyncAction) actions[which]).intent.send(); - Toast.makeText(getActivity(), - R.string.SyP_progress_toast, - Toast.LENGTH_LONG).show(); - } catch (CanceledException e) { - // - } - } else { - ((SyncV2Provider) actions[which]).synchronizeActiveTasks( - true, syncResultCallback); - } - } - }; - 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) { - if (items.length == 1) { - listener.onClick(null, 0); - return; - } - - ArrayAdapter adapter = new ArrayAdapter(getActivity(), - android.R.layout.simple_spinner_dropdown_item, items); - - // show a menu of available options - new AlertDialog.Builder(getActivity()).setTitle(R.string.SyP_label).setAdapter( - adapter, listener).show().setOwnerActivity(getActivity()); - } - - /* - * (non-Javadoc) - * - * @see - * android.support.v4.app.ListFragment#onListItemClick(android.widget.ListView - * , android.view.View, int, long) - */ @Override public void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); @@ -1523,7 +1311,6 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, @Override public boolean onContextItemSelected(MenuItem item) { - // called when context menu appears return onOptionsItemSelected(item); } @@ -1550,7 +1337,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, return true; case MENU_SYNC_ID: StatisticsService.reportEvent(StatisticsConstants.TLA_MENU_SYNC); - performSyncAction(); + syncActionHelper.performSyncAction(); return true; case MENU_SUPPORT_ID: showSupport(); @@ -1561,45 +1348,23 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, ACTIVITY_MENU_EXTERNAL); return true; - // --- context menu items + // --- context menu items case CONTEXT_MENU_BROADCAST_INTENT_ID: { intent = item.getIntent(); getActivity().sendBroadcast(intent); return true; } - case CONTEXT_MENU_EDIT_TASK_ID: { itemId = item.getGroupId(); mListener.onTaskListItemClicked(itemId); return true; } - case CONTEXT_MENU_COPY_TASK_ID: { itemId = item.getGroupId(); - Task original = new Task(); - original.setId(itemId); - - Flags.set(Flags.ACTFM_SUPPRESS_SYNC); - Flags.set(Flags.GTASKS_SUPPRESS_SYNC); - Task clone = taskService.clone(original); - clone.setValue(Task.CREATION_DATE, DateUtilities.now()); - clone.setValue(Task.COMPLETION_DATE, 0L); - clone.setValue(Task.DELETION_DATE, 0L); - - clone.setValue(Task.CALENDAR_URI, ""); //$NON-NLS-1$ - GCalHelper.createTaskEventIfEnabled(clone); - taskService.save(clone); - - intent = new Intent(getActivity(), TaskEditActivity.class); - intent.putExtra(TaskEditFragment.TOKEN_ID, clone.getId()); - intent.putExtra(TOKEN_FILTER, filter); - getActivity().startActivityForResult(intent, ACTIVITY_EDIT_TASK); - transitionForTaskEdit(); - + duplicateTask(itemId); return true; } - case CONTEXT_MENU_DELETE_TASK_ID: { itemId = item.getGroupId(); Task task = new Task(); @@ -1607,7 +1372,6 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, deleteTask(task); return true; } - case CONTEXT_MENU_UNDELETE_TASK_ID: { itemId = item.getGroupId(); Task task = new Task(); @@ -1617,14 +1381,12 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, loadTaskListContent(true); return true; } - case CONTEXT_MENU_PURGE_TASK_ID: { itemId = item.getGroupId(); taskService.purge(itemId); loadTaskListContent(true); return true; } - default: { if (item.getItemId() < CONTEXT_MENU_PLUGIN_ID_FIRST) return false; @@ -1637,10 +1399,19 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, return true; } - } } + protected void duplicateTask(long itemId) { + long cloneId = taskService.duplicateTask(itemId); + + Intent intent = new Intent(getActivity(), TaskEditActivity.class); + intent.putExtra(TaskEditFragment.TOKEN_ID, cloneId); + intent.putExtra(TOKEN_FILTER, filter); + getActivity().startActivityForResult(intent, ACTIVITY_EDIT_TASK); + transitionForTaskEdit(); + } + public void showSupport() { StatisticsService.reportEvent(StatisticsConstants.TLA_MENU_HELP); Intent intent = new Intent(getActivity(), NewFeedbackSpringboardActivity.class); @@ -1657,14 +1428,6 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, mListener.onTaskListItemClicked(taskId); } - @SuppressWarnings("nls") - @Override - public void gesturePerformed(String gesture) { - if ("nav_right".equals(gesture)) { - // showFilterListActivity(); - } - } - @Override public void onSortSelected(boolean always, int flags, int sort) { sortFlags = flags; diff --git a/astrid/src/com/todoroo/astrid/helper/SyncActionHelper.java b/astrid/src/com/todoroo/astrid/helper/SyncActionHelper.java new file mode 100644 index 000000000..8641db909 --- /dev/null +++ b/astrid/src/com/todoroo/astrid/helper/SyncActionHelper.java @@ -0,0 +1,268 @@ +package com.todoroo.astrid.helper; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; + +import org.weloveastrid.rmilk.MilkPreferences; +import org.weloveastrid.rmilk.MilkUtilities; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.PendingIntent.CanceledException; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.widget.ArrayAdapter; +import android.widget.Toast; + +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.DateUtilities; +import com.todoroo.andlib.utility.Preferences; +import com.todoroo.astrid.api.AstridApiConstants; +import com.todoroo.astrid.api.Filter; +import com.todoroo.astrid.api.SyncAction; +import com.todoroo.astrid.service.SyncV2Service; +import com.todoroo.astrid.sync.SyncResultCallback; +import com.todoroo.astrid.sync.SyncV2Provider; + +/** + * SyncActionHelper is a helper class for encapsulating UI actions + * responsible for performing sync and prompting user to sign up for a new + * sync service. + * + * In order to make this work you need to call register() and unregister() in + * onResume and onPause, respectively. + * + * @author Tim Su + * + */ +public class SyncActionHelper { + + private static final String PREF_LAST_AUTO_SYNC = "taskListLastAutoSync"; //$NON-NLS-1$ + + private final LinkedHashSet syncActions = new LinkedHashSet(); + + public final SyncResultCallback syncResultCallback; + + private final Activity activity; + + protected SyncActionReceiver syncActionReceiver = new SyncActionReceiver(); + + @Autowired SyncV2Service syncService; + @Autowired ExceptionService exceptionService; + + // --- boilerplate + + public SyncActionHelper(Activity activity) { + DependencyInjectionService.getInstance().inject(this); + + this.activity = activity; + syncResultCallback = new ProgressBarSyncResultCallback(activity, + R.id.progressBar, new Runnable() { + @Override + public void run() { + ContextManager.getContext().sendBroadcast( + new Intent( + AstridApiConstants.BROADCAST_EVENT_REFRESH)); + } + }); + } + + // --- automatic sync logic + + public void initiateAutomaticSync(Filter filter) { + if (filter == null || filter.title == null + || !filter.title.equals(activity.getString(R.string.BFE_Active))) + return; + + long lastAutoSync = Preferences.getLong(PREF_LAST_AUTO_SYNC, 0); + if (DateUtilities.now() - lastAutoSync > DateUtilities.ONE_HOUR) { + performSyncServiceV2Sync(false); + } + } + + // --- sync action receiver logic + + /** + * Receiver which receives sync provider intents + * + */ + protected class SyncActionReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null + || !AstridApiConstants.BROADCAST_SEND_SYNC_ACTIONS.equals(intent.getAction())) + return; + + try { + Bundle extras = intent.getExtras(); + SyncAction syncAction = extras.getParcelable(AstridApiConstants.EXTRAS_RESPONSE); + syncActions.add(syncAction); + } catch (Exception e) { + exceptionService.reportError("receive-sync-action-" + //$NON-NLS-1$ + intent.getStringExtra(AstridApiConstants.EXTRAS_ADDON), + e); + } + } + } + + public void register() { + activity.registerReceiver( + syncActionReceiver, + new IntentFilter(AstridApiConstants.BROADCAST_SEND_SYNC_ACTIONS)); + } + + public void unregister() { + activity.unregisterReceiver(syncActionReceiver); + } + + public void request() { + syncActions.clear(); + Intent broadcastIntent = new Intent( + AstridApiConstants.BROADCAST_REQUEST_SYNC_ACTIONS); + activity.sendOrderedBroadcast(broadcastIntent, + AstridApiConstants.PERMISSION_READ); + } + + // --- sync logic + + protected void performSyncServiceV2Sync(boolean manual) { + syncService.synchronizeActiveTasks(manual, syncResultCallback); + Preferences.setLong(PREF_LAST_AUTO_SYNC, DateUtilities.now()); + } + + /** + * Intent object with custom label returned by toString. + * + * @author joshuagross + */ + protected static class IntentWithLabel extends Intent { + private final String label; + + public IntentWithLabel(Intent in, String labelIn) { + super(in); + label = labelIn; + } + + @Override + public String toString() { + return label; + } + } + + public void performSyncAction() { + List activeV2Providers = syncService.activeProviders(); + int activeSyncs = syncActions.size() + activeV2Providers.size(); + + if (activeSyncs == 0) { + String desiredCategory = activity.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 = activity.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 (MilkPreferences.class.getName().equals( + resolveInfo.activityInfo.name) + && !MilkUtilities.INSTANCE.isLoggedIn()) + continue; + + 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) { + activity.startActivity(actions[which]); + } + }; + + showSyncOptionMenu(actions, listener); + + } else { + // We have sync actions, pop up a dialogue so the user can + // select just one of them (only sync one at a time) + final Object[] actions = new Object[activeSyncs]; + + int i; + for (i = 0; i < activeV2Providers.size(); i++) + actions[i] = activeV2Providers.get(i); + for (SyncAction syncAction : syncActions) + actions[i++] = syncAction; + + DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface click, int which) { + if (actions[which] instanceof SyncAction) { + try { + ((SyncAction) actions[which]).intent.send(); + Toast.makeText(activity, + R.string.SyP_progress_toast, + Toast.LENGTH_LONG).show(); + } catch (CanceledException e) { + // + } + } else { + ((SyncV2Provider) actions[which]).synchronizeActiveTasks( + true, syncResultCallback); + } + } + }; + 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) { + if (items.length == 1) { + listener.onClick(null, 0); + return; + } + + ArrayAdapter adapter = new ArrayAdapter(activity, + android.R.layout.simple_spinner_dropdown_item, items); + + // show a menu of available options + new AlertDialog.Builder(activity).setTitle(R.string.SyP_label).setAdapter( + adapter, listener).show().setOwnerActivity(activity); + } + +} + + diff --git a/astrid/src/com/todoroo/astrid/service/TaskService.java b/astrid/src/com/todoroo/astrid/service/TaskService.java index f9be85880..35e396af5 100644 --- a/astrid/src/com/todoroo/astrid/service/TaskService.java +++ b/astrid/src/com/todoroo/astrid/service/TaskService.java @@ -28,6 +28,7 @@ import com.todoroo.astrid.gtasks.GtasksMetadata; import com.todoroo.astrid.opencrx.OpencrxCoreUtils; import com.todoroo.astrid.producteev.sync.ProducteevTask; import com.todoroo.astrid.tags.TagService; +import com.todoroo.astrid.utility.Flags; import com.todoroo.astrid.utility.TitleParser; @@ -356,10 +357,35 @@ public class TaskService { return quickAddMarkup; } + /** + * Parse quick add markup for the given task + * @param task + * @param tags an empty array to apply tags to + * @return + */ public static boolean parseQuickAddMarkup(Task task, ArrayList tags) { return new TitleParser(task, tags).parse(); } - + /** + * Create an uncompleted copy of this task and edit it + * @param itemId + * @return cloned item id + */ + public long duplicateTask(long itemId) { + Task original = new Task(); + original.setId(itemId); + Task clone = clone(original); + clone.setValue(Task.CREATION_DATE, DateUtilities.now()); + clone.setValue(Task.COMPLETION_DATE, 0L); + clone.setValue(Task.DELETION_DATE, 0L); + clone.setValue(Task.CALENDAR_URI, ""); //$NON-NLS-1$ + GCalHelper.createTaskEventIfEnabled(clone); + + Flags.set(Flags.ACTFM_SUPPRESS_SYNC); + Flags.set(Flags.GTASKS_SUPPRESS_SYNC); + save(clone); + return clone.getId(); + } }