Remove unused classes

pull/46/head
Alex Baker 11 years ago
parent 6c97d5c501
commit 09eef62645

@ -1,379 +0,0 @@
/***
Copyright (c) 2008-2009 CommonsWare, LLC
Portions (c) 2009 Google, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.commonsware.cwac.merge;
import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.SectionIndexer;
import java.util.ArrayList;
import java.util.List;
import com.commonsware.cwac.sacklist.SackOfViewsAdapter;
/**
* Adapter that merges multiple child adapters and views
* into a single contiguous whole.
*
* Adapters used as pieces within MergeAdapter must
* have view type IDs monotonically increasing from 0. Ideally,
* adapters also have distinct ranges for their row ids, as
* returned by getItemId().
*
*/
public class MergeAdapter extends BaseAdapter implements SectionIndexer {
protected ArrayList<ListAdapter> pieces=new ArrayList<ListAdapter>();
/**
* Stock constructor, simply chaining to the superclass.
*/
public MergeAdapter() {
super();
}
/**
* Adds a new adapter to the roster of things to appear
* in the aggregate list.
* @param adapter Source for row views for this section
*/
public void addAdapter(ListAdapter adapter) {
pieces.add(adapter);
adapter.registerDataSetObserver(new CascadeDataSetObserver());
}
/**
* Adds a new View to the roster of things to appear
* in the aggregate list.
* @param view Single view to add
*/
public void addView(View view) {
addView(view, false);
}
/**
* Adds a new View to the roster of things to appear
* in the aggregate list.
* @param view Single view to add
* @param enabled false if views are disabled, true if enabled
*/
public void addView(View view, boolean enabled) {
ArrayList<View> list=new ArrayList<View>(1);
list.add(view);
addViews(list, enabled);
}
/**
* Adds a list of views to the roster of things to appear
* in the aggregate list.
* @param views List of views to add
*/
public void addViews(List<View> views) {
addViews(views, false);
}
/**
* Adds a list of views to the roster of things to appear
* in the aggregate list.
* @param views List of views to add
* @param enabled false if views are disabled, true if enabled
*/
public void addViews(List<View> views, boolean enabled) {
if (enabled) {
addAdapter(new EnabledSackAdapter(views));
}
else {
addAdapter(new SackOfViewsAdapter(views));
}
}
/**
* Get the data item associated with the specified
* position in the data set.
* @param position Position of the item whose data we want
*/
@Override
public Object getItem(int position) {
for (ListAdapter piece : pieces) {
int size=piece.getCount();
if (position<size) {
return(piece.getItem(position));
}
position-=size;
}
return(null);
}
/**
* Get the adapter associated with the specified
* position in the data set.
* @param position Position of the item whose adapter we want
*/
public ListAdapter getAdapter(int position) {
for (ListAdapter piece : pieces) {
int size=piece.getCount();
if (position<size) {
return(piece);
}
position-=size;
}
return(null);
}
/**
* How many items are in the data set represented by this
* Adapter.
*/
@Override
public int getCount() {
int total=0;
for (ListAdapter piece : pieces) {
total+=piece.getCount();
}
return(total);
}
/**
* Returns the number of types of Views that will be
* created by getView().
*/
@Override
public int getViewTypeCount() {
int total=0;
for (ListAdapter piece : pieces) {
total+=piece.getViewTypeCount();
}
return(Math.max(total, 1)); // needed for setListAdapter() before content add'
}
/**
* Get the type of View that will be created by getView()
* for the specified item.
* @param position Position of the item whose data we want
*/
@Override
public int getItemViewType(int position) {
int typeOffset=0;
int result=-1;
for (ListAdapter piece : pieces) {
int size=piece.getCount();
if (position<size) {
result=typeOffset+piece.getItemViewType(position);
break;
}
position-=size;
typeOffset+=piece.getViewTypeCount();
}
return(result);
}
/**
* Are all items in this ListAdapter enabled? If yes it
* means all items are selectable and clickable.
*/
@Override
public boolean areAllItemsEnabled() {
return(false);
}
/**
* Returns true if the item at the specified position is
* not a separator.
* @param position Position of the item whose data we want
*/
@Override
public boolean isEnabled(int position) {
for (ListAdapter piece : pieces) {
int size=piece.getCount();
if (position<size) {
return(piece.isEnabled(position));
}
position-=size;
}
return(false);
}
/**
* Get a View that displays the data at the specified
* position in the data set.
* @param position Position of the item whose data we want
* @param convertView View to recycle, if not null
* @param parent ViewGroup containing the returned View
*/
@Override
public View getView(int position, View convertView,
ViewGroup parent) {
for (ListAdapter piece : pieces) {
int size=piece.getCount();
if (position<size) {
return(piece.getView(position, convertView, parent));
}
position-=size;
}
return(null);
}
/**
* Get the row id associated with the specified position
* in the list.
* @param position Position of the item whose data we want
*/
@Override
public long getItemId(int position) {
for (ListAdapter piece : pieces) {
int size=piece.getCount();
if (position<size) {
return(piece.getItemId(position));
}
position-=size;
}
return(-1);
}
@Override
public int getPositionForSection(int section) {
int position=0;
for (ListAdapter piece : pieces) {
if (piece instanceof SectionIndexer) {
Object[] sections=((SectionIndexer)piece).getSections();
int numSections=0;
if (sections!=null) {
numSections=sections.length;
}
if (section<numSections) {
return(position+((SectionIndexer)piece).getPositionForSection(section));
}
else if (sections!=null) {
section-=numSections;
}
}
position+=piece.getCount();
}
return(0);
}
@Override
public int getSectionForPosition(int position) {
int section=0;
for (ListAdapter piece : pieces) {
int size=piece.getCount();
if (position<size) {
if (piece instanceof SectionIndexer) {
return(section+((SectionIndexer)piece).getSectionForPosition(position));
}
return(0);
}
else {
if (piece instanceof SectionIndexer) {
Object[] sections=((SectionIndexer)piece).getSections();
if (sections!=null) {
section+=sections.length;
}
}
}
position-=size;
}
return(0);
}
@Override
public Object[] getSections() {
ArrayList<Object> sections=new ArrayList<Object>();
for (ListAdapter piece : pieces) {
if (piece instanceof SectionIndexer) {
Object[] curSections=((SectionIndexer)piece).getSections();
if (curSections!=null) {
for (Object section : curSections) {
sections.add(section);
}
}
}
}
if (sections.size()==0) {
return(null);
}
return(sections.toArray(new Object[0]));
}
private static class EnabledSackAdapter extends SackOfViewsAdapter {
public EnabledSackAdapter(List<View> views) {
super(views);
}
@Override
public boolean areAllItemsEnabled() {
return(true);
}
@Override
public boolean isEnabled(int position) {
return(true);
}
}
private class CascadeDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
notifyDataSetChanged();
}
@Override
public void onInvalidated() {
notifyDataSetInvalidated();
}
}
}

@ -1,112 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.commonsware.cwac.merge;
import java.util.List;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.SpinnerAdapter;
/**
* Adapter that merges multiple child adapters into a single
* contiguous whole to be consumed by a Spinner.
*
* Adapters used as pieces within MergeSpinnerAdapter must
* have view type IDs monotonically increasing from 0.
* Ideally, adapters also have distinct ranges for their row
* ids, as returned by getItemId().
*
* All Adapters used as pieces within MergeSpinnerAdapter
* must be properly-configured implementations of
* SpinnerAdapter (e.g., ArrayAdapter, CursorAdapter).
*/
public class MergeSpinnerAdapter extends MergeAdapter {
/**
* Stock constructor, simply chaining to the superclass.
*/
public MergeSpinnerAdapter() {
super();
}
/*
* Returns the drop-down View for a given position, by
* iterating over the pieces. Assumes that all pieces are
* implementations of SpinnerAdapter.
*
* @see android.widget.BaseAdapter#getDropDownView(int,
* android.view.View, android.view.ViewGroup)
*/
@Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
for (ListAdapter piece : pieces) {
int size=piece.getCount();
if (position<size) {
return(((SpinnerAdapter)piece).getDropDownView(position,
convertView,
parent));
}
position-=size;
}
return(null);
}
/**
* Adds a new View to the roster of things to appear in
* the aggregate list.
*
* @param view
* Single view to add
*/
@Override
public void addView(View view) {
throw new RuntimeException("Not supported with MergeSpinnerAdapter");
}
/**
* Adds a new View to the roster of things to appear in
* the aggregate list.
*
* @param view
* Single view to add
* @param enabled
* false if views are disabled, true if enabled
*/
@Override
public void addView(View view, boolean enabled) {
throw new RuntimeException("Not supported with MergeSpinnerAdapter");
}
/**
* Adds a list of views to the roster of things to appear
* in the aggregate list.
*
* @param views
* List of views to add
*/
@Override
public void addViews(List<View> views) {
throw new RuntimeException("Not supported with MergeSpinnerAdapter");
}
/**
* Adds a list of views to the roster of things to appear
* in the aggregate list.
*
* @param views
* List of views to add
* @param enabled
* false if views are disabled, true if enabled
*/
@Override
public void addViews(List<View> views, boolean enabled) {
throw new RuntimeException("Not supported with MergeSpinnerAdapter");
}
}

@ -1,26 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import org.apache.http.entity.mime.MultipartEntity;
import org.json.JSONException;
import org.json.JSONObject;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.data.RemoteModel;
public class RequestDoubleCheck<TYPE extends RemoteModel> extends ClientToServerMessage<TYPE> {
public RequestDoubleCheck(long id, Class<TYPE> modelClass, RemoteModelDao<TYPE> modelDao) {
super(id, modelClass, modelDao);
}
@Override
protected boolean serializeExtrasToJSON(JSONObject serializeTo, MultipartEntity entity) throws JSONException {
// No extras
return true;
}
@Override
protected String getTypeString() {
return "RequestDoubleCheck"; //$NON-NLS-1$
}
}

@ -1,360 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.FrameLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class ExpandableListFragment extends Fragment
implements OnCreateContextMenuListener,
ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
ExpandableListView.OnGroupExpandListener
{
static final int INTERNAL_EMPTY_ID = 0x00ff0001;
final private Handler mHandler = new Handler();
final private Runnable mRequestFocus = new Runnable() {
@Override
public void run() {
mList.focusableViewAvailable(mList);
}
};
final private AdapterView.OnItemClickListener mOnClickListener
= new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
onListItemClick((ListView)parent, v, position, id);
}
};
ExpandableListAdapter mAdapter;
ExpandableListView mList;
View mEmptyView;
TextView mStandardEmptyView;
boolean mSetEmptyText;
boolean mListShown;
boolean mFinishedStart = false;
/**
* Provide default implementation to return a simple list view. Subclasses
* can override to replace with their own layout. If doing so, the
* returned view hierarchy <em>must</em> have a ListView whose id
* is {@link android.R.id#list android.R.id.list} and can optionally
* have a sibling view id {@link android.R.id#empty android.R.id.empty}
* that is to be shown when the list is empty.
*
* <p>If you are overriding this method with your own custom content,
* consider including the standard layout {@link android.R.layout#list_content}
* in your layout file, so that you continue to retain all of the standard
* behavior of ListFragment. In particular, this is currently the only
* way to have the built-in indeterminant progress state be shown.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
FrameLayout root = new FrameLayout(getActivity());
TextView tv = new TextView(getActivity());
tv.setId(INTERNAL_EMPTY_ID);
tv.setGravity(Gravity.CENTER);
root.addView(tv, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
ExpandableListView lv = new ExpandableListView(getActivity());
lv.setId(android.R.id.list);
lv.setDrawSelectorOnTop(false);
root.addView(lv, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
ListView.LayoutParams lp = new ListView.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
root.setLayoutParams(lp);
return root;
}
/**
* Attach to list view once Fragment is ready to run.
*/
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ensureList();
}
/**
* Detach from list view.
*/
@Override
public void onDestroyView() {
mHandler.removeCallbacks(mRequestFocus);
mList = null;
super.onDestroyView();
}
/**
* This method will be called when an item in the list is selected.
* Subclasses should override. Subclasses can call
* getListView().getItemAtPosition(position) if they need to access the
* data associated with the selected item.
*
* @param l The ListView where the click happened
* @param v The view that was clicked within the ListView
* @param position The position of the view in the list
* @param id The row id of the item that was clicked
*/
public void onListItemClick(ListView l, View v, int position, long id) {
// override me
}
/**
* Provide the cursor for the list view.
*/
public void setListAdapter(ExpandableListAdapter adapter) {
boolean hadAdapter = mAdapter != null;
mAdapter = adapter;
if (mList != null) {
mList.setAdapter(adapter);
if (!mListShown && !hadAdapter) {
// The list was hidden, and previously didn't have an
// adapter. It is now time to show it.
setListShown(true, getView().getWindowToken() != null);
}
}
}
/**
* Set the currently selected list item to the specified
* position with the adapter's data
*
* @param position
*/
public void setSelection(int position) {
ensureList();
mList.setSelection(position);
}
public long getSelectedPosition() {
ensureList();
return mList.getSelectedPosition();
}
/**
* Sets the selection to the specified child. If the child is in a collapsed
* group, the group will only be expanded and child subsequently selected if
* shouldExpandGroup is set to true, otherwise the method will return false.
*
* @param groupPosition The position of the group that contains the child.
* @param childPosition The position of the child within the group.
* @param shouldExpandGroup Whether the child's group should be expanded if
* it is collapsed.
* @return Whether the selection was successfully set on the child.
*/
public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) {
ensureList();
return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup);
}
public void setItemChecked(int position, boolean value) {
ensureList();
mList.setItemChecked(position, value);
}
/**
* Sets the selection to the specified group.
* @param groupPosition The position of the group that should be selected.
*/
public void setSelectedGroup(int groupPosition) {
mList.setSelectedGroup(groupPosition);
}
public long getSelectedId() {
ensureList();
return mList.getSelectedId();
}
public ExpandableListView getExpandableListView() {
ensureList();
return mList;
}
/**
* The default content for a ListFragment has a TextView that can
* be shown when the list is empty. If you would like to have it
* shown, call this method to supply the text it should use.
*/
public void setEmptyText(CharSequence text) {
ensureList();
if (mStandardEmptyView == null) {
throw new IllegalStateException("Can't be used with a custom content view");
}
mStandardEmptyView.setText(text);
if (!mSetEmptyText) {
mList.setEmptyView(mStandardEmptyView);
mSetEmptyText = true;
}
}
/**
* Control whether the list is being displayed. You can make it not
* displayed if you are waiting for the initial data to show in it. During
* this time an indeterminant progress indicator will be shown instead.
*
* <p>Applications do not normally need to use this themselves. The default
* behavior of ListFragment is to start with the list not being shown, only
* showing it once an adapter is given with {@link #setListAdapter(ListAdapter)}.
* If the list at that point had not been shown, when it does get shown
* it will be do without the user ever seeing the hidden state.
*
* @param shown If true, the list view is shown; if false, the progress
* indicator. The initial value is true.
*/
public void setListShown(boolean shown) {
setListShown(shown, true);
}
/**
* Like {@link #setListShown(boolean)}, but no animation is used when
* transitioning from the previous state.
*/
public void setListShownNoAnimation(boolean shown) {
setListShown(shown, false);
}
/**
* Control whether the list is being displayed. You can make it not
* displayed if you are waiting for the initial data to show in it. During
* this time an indeterminant progress indicator will be shown instead.
*
* @param shown If true, the list view is shown; if false, the progress
* indicator. The initial value is true.
* @param animate If true, an animation will be used to transition to the
* new state.
*/
private void setListShown(boolean shown, boolean animate) {
ensureList();
if (mListShown == shown) {
return;
}
mListShown = shown;
if (shown) {
if (animate) {
mList.startAnimation(AnimationUtils.loadAnimation(
getActivity(), android.R.anim.fade_in));
}
mList.setVisibility(View.VISIBLE);
} else {
if (animate) {
mList.startAnimation(AnimationUtils.loadAnimation(
getActivity(), android.R.anim.fade_out));
}
mList.setVisibility(View.GONE);
}
}
/**
* Get the ListAdapter associated with this activity's ListView.
*/
public ExpandableListAdapter getExpandableListAdapter() {
return mAdapter;
}
private void ensureList() {
if (mList != null) {
return;
}
View root = getView();
if (root == null) {
throw new IllegalStateException("Content view not yet created");
}
if (root instanceof ExpandableListView) {
mList = (ExpandableListView)root;
} else {
mStandardEmptyView = (TextView)root.findViewById(INTERNAL_EMPTY_ID);
if (mStandardEmptyView == null) {
mEmptyView = root.findViewById(android.R.id.empty);
}
View rawListView = root.findViewById(android.R.id.list);
if (!(rawListView instanceof ExpandableListView)) {
if (rawListView == null) {
throw new RuntimeException(
"Your content must have a ExpandableListView whose id attribute is " +
"'android.R.id.list'");
}
throw new RuntimeException(
"Content has view with id attribute 'android.R.id.list' "
+ "that is not a ExpandableListView class");
}
mList = (ExpandableListView)rawListView;
if (mEmptyView != null) {
mList.setEmptyView(mEmptyView);
}
}
mListShown = true;
mList.setOnItemClickListener(mOnClickListener);
if (mAdapter != null) {
setListAdapter(mAdapter);
} else {
// We are starting without an adapter, so assume we won't
// have our data right away and start with the progress indicator.
setListShown(false, false);
}
mHandler.post(mRequestFocus);
}
public void onContentChanged() {
View emptyView = getView().findViewById(android.R.id.empty);
mList = (ExpandableListView)getView().findViewById(android.R.id.list);
if (mList == null) {
throw new RuntimeException(
"Your content must have a ExpandableListView whose id attribute is " +
"'android.R.id.list'");
}
if (emptyView != null) {
mList.setEmptyView(emptyView);
}
mList.setOnChildClickListener(this);
mList.setOnGroupExpandListener(this);
mList.setOnGroupCollapseListener(this);
if (mFinishedStart) {
setListAdapter(mAdapter);
}
mFinishedStart = true;
}
@Override
public void onGroupExpand(int groupPosition) {
// override me
}
@Override
public void onGroupCollapse(int groupPosition) {
// override me
}
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
return false;
}
}

@ -1,55 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.gtasks;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.tasks.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.SyncAction;
import com.todoroo.astrid.service.AstridDependencyInjector;
/**
* Exposes sync action
*
*/
public class GtasksSyncActionExposer extends BroadcastReceiver {
@Autowired private GtasksPreferenceService gtasksPreferenceService;
static {
AstridDependencyInjector.initialize();
}
@Override
public void onReceive(Context context, Intent intent) {
ContextManager.setContext(context);
DependencyInjectionService.getInstance().inject(this);
// if we aren't logged in, don't expose sync action
if(!gtasksPreferenceService.isLoggedIn()) {
return;
}
Intent syncIntent = new Intent(null, null,
context, GtasksBackgroundService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, syncIntent, PendingIntent.FLAG_UPDATE_CURRENT);
SyncAction syncAction = new SyncAction(context.getString(R.string.gtasks_GPr_header),
pendingIntent);
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_SYNC_ACTIONS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, GtasksPreferenceService.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, syncAction);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
}

@ -1,72 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.gtasks.api;
import java.io.IOException;
import com.google.api.services.tasks.model.Task;
/**
* Encapsulates a request to the api to move a task from one list to another
* @author Sam Bosley
*
*/
public class MoveListRequest extends PushRequest {
private String idTaskToMove;
private String dstList;
private final String newParent;
public MoveListRequest(GtasksInvoker service, String idTask, String srcList, String dstList, String newParent) {
super(service, srcList, new Task());
this.idTaskToMove = idTask;
this.dstList = dstList;
this.newParent = newParent;
}
@Override
public Task executePush() throws IOException {
Task localSave = service.getGtask(super.getListId(), idTaskToMove);
service.deleteGtask(super.getListId(), idTaskToMove);
transferProperties(localSave);
return service.createGtask(dstList, toPush);
}
@Override
protected void recover() {
//If there's a good way to recover, put it here
//Since MoveListRequest isn't actually used at the moment, it's probably fine for now
}
private void transferProperties(Task local) {
toPush.setCompleted(local.getCompleted());
toPush.setDeleted(local.getDeleted());
toPush.setDue(local.getDue());
toPush.setHidden(local.getHidden());
toPush.setNotes(local.getNotes());
toPush.setStatus(local.getStatus());
toPush.setTitle(local.getTitle());
toPush.setParent(newParent);
}
public String getIdTaskToMove() {
return idTaskToMove;
}
public void setIdTaskToMove(String idTaskToMove) {
this.idTaskToMove = idTaskToMove;
}
public String getDstList() {
return dstList;
}
public void setDstList(String dstList) {
this.dstList = dstList;
}
}

@ -1,33 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.gtasks.api;
import java.io.IOException;
import com.google.api.services.tasks.model.Task;
/**
* Encapsulates a request to the api to update a task on the remote server
* @author Sam Bosley
*
*/
public class UpdateRequest extends PushRequest {
public UpdateRequest(GtasksInvoker service, String listId, Task toUpdate) {
super(service, listId, toUpdate);
}
@Override
public Task executePush() throws IOException {
return service.updateGtask(listId, toPush);
}
@Override
protected void recover() {
//Figure out a good way to recover!
}
}

@ -1,124 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.todoroo.astrid.gtasks.auth;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
/**
* Choose which account to upload track information to.
* @author Sandor Dornbush
*/
public class AccountChooser {
/**
* The last selected account.
*/
private int selectedAccountIndex = -1;
private Account selectedAccount = null;
/**
* An interface for receiving updates once the user has selected the account.
*/
public interface AccountHandler {
/**
* Handle the account being selected.
* @param account The selected account or null if none could be found
*/
public void handleAccountSelected(Account account);
}
/**
* Chooses the best account to upload to.
* If no account is found the user will be alerted.
* If only one account is found that will be used.
* If multiple accounts are found the user will be allowed to choose.
*
* @param activity The parent activity
* @param handler The handler to be notified when an account has been selected
*/
public void chooseAccount(final Activity activity,
final AccountHandler handler) {
final Account[] accounts = AccountManager.get(activity)
.getAccountsByType("com.google"); //$NON-NLS-1$
if (accounts.length < 1) {
alertNoAccounts(activity, handler);
return;
}
if (accounts.length == 1) {
handler.handleAccountSelected(accounts[0]);
return;
}
// TODO This should be read out of a preference.
if (selectedAccount != null) {
handler.handleAccountSelected(selectedAccount);
return;
}
// Let the user choose.
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setCancelable(false);
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
selectedAccount = accounts[selectedAccountIndex];
handler.handleAccountSelected(selectedAccount);
}
});
builder.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
handler.handleAccountSelected(null);
}
});
String[] choices = new String[accounts.length];
for (int i = 0; i < accounts.length; i++) {
choices[i] = accounts[i].name;
}
builder.setSingleChoiceItems(choices, selectedAccountIndex,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
selectedAccountIndex = which;
}
});
builder.show();
}
/**
* Puts up a dialog alerting the user that no suitable account was found.
*/
private void alertNoAccounts(final Activity activity,
final AccountHandler handler) {
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage("No Accounts Found."); //$NON-NLS-1$
builder.setCancelable(true);
builder.setNegativeButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
handler.handleAccountSelected(null);
}
});
builder.show();
}
}

@ -1,77 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.todoroo.astrid.gtasks.auth;
import android.content.Intent;
/**
* This interface describes a class that will fetch and maintain a Google
* authentication token.
*
* @author Sandor Dornbush
*/
public interface AuthManager {
/**
* Initializes the login process. The user should be asked to login if they
* haven't already. The {@link Runnable} provided will be executed when the
* auth token is successfully fetched.
*
* @param whenFinished A {@link Runnable} to execute when the auth token
* has been successfully fetched and is available via
* {@link #getAuthToken()}
*/
public abstract void doLogin(Runnable whenFinished, Object o);
/**
* The {@link android.app.Activity} owner of this class should call this
* function when it gets {@link android.app.Activity#onActivityResult} with
* the request code passed into the constructor. The resultCode and results
* should come directly from the {@link android.app.Activity#onActivityResult}
* function. This function will return true if an auth token was successfully
* fetched or the process is not finished.
*
* @param resultCode The result code passed in to the
* {@link android.app.Activity}'s
* {@link android.app.Activity#onActivityResult} function
* @param results The data passed in to the {@link android.app.Activity}'s
* {@link android.app.Activity#onActivityResult} function
* @return True if the auth token was fetched or we aren't done fetching
* the auth token, or False if there was an error or the request was
* canceled
*/
public abstract boolean authResult(int resultCode, Intent results);
/**
* Returns the current auth token. Response may be null if no valid auth
* token has been fetched.
*
* @return The current auth token or null if no auth token has been
* fetched
*/
public abstract String getAuthToken();
/**
* Invalidates the existing auth token and request a new one. The
* {@link Runnable} provided will be executed when the new auth token is
* successfully fetched.
*
* @param whenFinished A {@link Runnable} to execute when a new auth token
* is successfully fetched
*/
public abstract void invalidateAndRefresh(Runnable whenFinished);
}

@ -1,231 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.todoroo.astrid.gtasks.auth;
import java.io.IOException;
import java.util.ArrayList;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager;
/**
* AuthManager keeps track of the current auth token for a user. The advantage
* over just passing around a String is that this class can renew the auth
* token if necessary, and it will change for all classes using this
* AuthManager.
*/
public class ModernAuthManager implements AuthManager {
protected static final int GET_LOGIN_REQUEST = 1;
/** The activity that will handle auth result callbacks. */
private final Activity activity;
/** The name of the service to authorize for. */
private final String service;
/** The most recently fetched auth token or null if none is available. */
private String authToken;
private final AccountManager accountManager;
private Runnable whenFinished;
/**
* AuthManager requires many of the same parameters as
* {@link com.google.android.googlelogindist.GoogleLoginServiceHelper
* #getCredentials(Activity, int, Bundle, boolean, String, boolean)}.
* The activity must have a handler in {@link Activity#onActivityResult} that
* calls {@link #authResult(int, Intent)} if the request code is the code
* given here.
*
* @param activity An activity with a handler in
* {@link Activity#onActivityResult} that calls
* {@link #authResult(int, Intent)} when {@literal code} is the request
* code
* @param code The request code to pass to
* {@link Activity#onActivityResult} when
* {@link #authResult(int, Intent)} should be called
* @param extras A {@link Bundle} of extras for
* {@link com.google.android.googlelogindist.GoogleLoginServiceHelper}
* @param requireGoogle True if the account must be a Google account
* @param service The name of the service to authenticate as
*/
public ModernAuthManager(Activity activity, int code, Bundle extras,
boolean requireGoogle, String service) {
this.activity = activity;
this.service = service;
this.accountManager = AccountManager.get(activity);
}
/**
* Call this to do the initial login. The user will be asked to login if
* they haven't already. The {@link Runnable} provided will be executed
* when the auth token is successfully fetched.
*
* @param runnable A {@link Runnable} to execute when the auth token
* has been successfully fetched and is available via
* {@link #getAuthToken()}
*/
@Override
public void doLogin(final Runnable runnable, Object o) {
this.whenFinished = runnable;
if (!(o instanceof Account)) {
throw new IllegalArgumentException("FroyoAuthManager requires an account.");
}
Account account = (Account) o;
accountManager.getAuthToken(account, service, true,
new AccountManagerCallback<Bundle>() {
@Override
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle result = future.getResult();
// AccountManager needs user to grant permission
if (result.containsKey(AccountManager.KEY_INTENT)) {
Intent intent = (Intent) result.get(AccountManager.KEY_INTENT);
clearNewTaskFlag(intent);
activity.startActivityForResult(intent, GET_LOGIN_REQUEST);
return;
}
authToken = result.getString(
AccountManager.KEY_AUTHTOKEN);
Log.e("gtasks-auth", "Got auth token.");
runWhenFinished();
} catch (OperationCanceledException e) {
Log.e("gtasks-auth", "Operation Canceled", e);
} catch (IOException e) {
Log.e("gtasks-auth", "IOException", e);
} catch (AuthenticatorException e) {
Log.e("gtasks-auth", "Authentication Failed", e);
}
}
}, null /* handler */);
}
private static void clearNewTaskFlag(Intent intent) {
int flags = intent.getFlags();
flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
intent.setFlags(flags);
}
/**
* The {@link Activity} passed into the constructor should call this
* function when it gets {@link Activity#onActivityResult} with the request
* code passed into the constructor. The resultCode and results should
* come directly from the {@link Activity#onActivityResult} function. This
* function will return true if an auth token was successfully fetched or
* the process is not finished.
*
* @param resultCode The result code passed in to the {@link Activity}'s
* {@link Activity#onActivityResult} function
* @param results The data passed in to the {@link Activity}'s
* {@link Activity#onActivityResult} function
* @return True if the auth token was fetched or we aren't done fetching
* the auth token, or False if there was an error or the request was
* canceled
*/
@Override
public boolean authResult(int resultCode, Intent results) {
if (results != null) {
authToken = results.getStringExtra(
AccountManager.KEY_AUTHTOKEN);
Log.w("google-auth", "authResult: " + authToken);
} else {
Log.e("google-auth", "No auth result results!!");
}
runWhenFinished();
return authToken != null;
}
/**
* Returns the current auth token. Response may be null if no valid auth
* token has been fetched.
*
* @return The current auth token or null if no auth token has been
* fetched
*/
@Override
public String getAuthToken() {
return authToken;
}
/**
* Invalidates the existing auth token and request a new one. The
* {@link Runnable} provided will be executed when the new auth token is
* successfully fetched.
*
* @param runnable A {@link Runnable} to execute when a new auth token
* is successfully fetched
*/
@Override
public void invalidateAndRefresh(final Runnable runnable) {
this.whenFinished = runnable;
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
accountManager.invalidateAuthToken("com.google", authToken); //$NON-NLS-1$
new AccountChooser().chooseAccount(activity,
new AccountChooser.AccountHandler() {
@Override
public void handleAccountSelected(Account account) {
if (account != null) {
doLogin(whenFinished, account);
} else {
runWhenFinished();
}
}
});
}
});
}
private void runWhenFinished() {
if (whenFinished != null) {
(new Thread() {
@Override
public void run() {
whenFinished.run();
}
}).start();
}
}
public static String[] getAccounts(Activity activity) {
try {
GoogleAccountManager accountManager = new GoogleAccountManager(activity);
Account[] accounts = accountManager.getAccounts();
ArrayList<String> accountNames = new ArrayList<String>();
for (Account a : accounts) {
accountNames.add(a.name);
}
return accountNames.toArray(new String[accountNames.size()]);
} catch (Exception e) {
return new String[] {}; // Empty array on failure
}
}
}

@ -1,167 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.gtasks.sync;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import com.google.api.services.tasks.model.TaskList;
import com.google.api.services.tasks.model.TaskLists;
import com.google.api.services.tasks.model.Tasks;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksListService;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.GtasksMetadataService;
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.api.GtasksInvoker;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.TaskService;
/**
* Class to handle migration of legacy metadata (old remote ids) to new
* metadata based on the official remote ids returned by the api.
* @author Sam Bosley
*
*/
public class GtasksLegacyMigrator {
@Autowired GtasksMetadataService gtasksMetadataService;
@Autowired TaskService taskService;
@Autowired MetadataService metadataService;
@Autowired GtasksListService gtasksListService;
@Autowired GtasksPreferenceService gtasksPreferenceService;
private final GtasksInvoker gtasksService;
private final GtasksListService listService;
private final TaskLists allLists;
static {
AstridDependencyInjector.initialize();
}
public GtasksLegacyMigrator(GtasksInvoker service,GtasksListService listService, TaskLists allLists) {
DependencyInjectionService.getInstance().inject(this);
this.gtasksService = service;
this.listService = listService;
this.allLists = allLists;
}
public void checkAndMigrateLegacy() throws IOException {
if (!gtasksPreferenceService.migrationHasOccurred()) {
//Fetch all tasks that have associated gtask metadata
String defaultListTitle = gtasksListService.getListName(Preferences.getStringValue(GtasksPreferenceService.PREF_DEFAULT_LIST));
String defaultListId = null;
TodorooCursor<Task> allTasksWithGtaskData = taskService.query(Query.select(Task.PROPERTIES).
where(Task.ID.in(
Query.select(Metadata.TASK).from(Metadata.TABLE).
where(Metadata.KEY.eq(GtasksMetadata.METADATA_KEY)))));
try {
if (allTasksWithGtaskData.getCount() > 0) {
//Fetch all remote tasks from all remote lists (this may be an expensive operation)
//and map their titles to their real remote ids
HashMap<String, String> taskAndListTitlesToRemoteTaskIds = new HashMap<String, String>();
List<TaskList> items = allLists.getItems();
for (TaskList list : items) {
if (list.getTitle().equals(defaultListTitle)) {
defaultListId = list.getId();
}
Tasks allTasks = gtasksService.getAllGtasksFromListId(list.getId(), false, false, 0);
List<com.google.api.services.tasks.model.Task> tasksItems = allTasks.getItems();
if (tasksItems != null) {
for (com.google.api.services.tasks.model.Task t : tasksItems) {
String key = constructKeyFromTitles(t.getTitle(), list.getTitle());
taskAndListTitlesToRemoteTaskIds.put(key, t.getId());
}
}
}
if (defaultListId == null) {
com.google.api.services.tasks.model.TaskList defaultList = gtasksService.getGtaskList("@default"); //$NON-NLS-1$
defaultListId = defaultList.getId();
}
Preferences.setString(GtasksPreferenceService.PREF_DEFAULT_LIST, defaultListId);
//For each local task, check to see if its title paired with any list title has a match in the map
for (allTasksWithGtaskData.moveToFirst(); !allTasksWithGtaskData.isAfterLast(); allTasksWithGtaskData.moveToNext()) {
GtasksTaskContainer container = gtasksMetadataService.readTaskAndMetadata(allTasksWithGtaskData);
// memorize the original listname for the case that the task is not matched,
// then it should at least be recreated in the correct list
String originalListName = gtasksListService.getListName(
container.gtaskMetadata.getValue(GtasksMetadata.LIST_ID));
String originalListId = null;
//Search through lists to see if one of them has match
String taskTitle = container.task.getValue(Task.TITLE);
boolean foundMatch = false;
items = allLists.getItems();
for (TaskList list : items) {
String expectedKey = constructKeyFromTitles(taskTitle, list.getTitle());
// save the new id of the current list
// if it matches the listname of the current task
if (list.getTitle() != null && list.getTitle().equals(originalListName)) {
originalListId = list.getId();
}
if (taskAndListTitlesToRemoteTaskIds.containsKey(expectedKey)) {
foundMatch = true;
String newRemoteTaskId = taskAndListTitlesToRemoteTaskIds.get(expectedKey);
String newRemoteListId = list.getId();
container.gtaskMetadata.setValue(GtasksMetadata.ID, newRemoteTaskId);
container.gtaskMetadata.setValue(GtasksMetadata.LIST_ID, newRemoteListId);
gtasksMetadataService.saveTaskAndMetadata(container);
break;
}
}
if (!foundMatch) {
//For non-matches, make the task look newly created
container.gtaskMetadata = GtasksMetadata.createEmptyMetadata(container.task.getId());
container.gtaskMetadata.setValue(GtasksMetadata.ID, ""); //$NON-NLS-1$
if (originalListId != null) {
// set the list-id based on the original listname, saved above during for-loop
container.gtaskMetadata.setValue(GtasksMetadata.LIST_ID, originalListId);
} else {
// remote list or local list was renamed, so put this unmatched task in the default list
container.gtaskMetadata.setValue(GtasksMetadata.LIST_ID, defaultListId);
}
gtasksMetadataService.saveTaskAndMetadata(container);
break;
}
}
}
// migrate the list-id's afterwards, so that we can put the non-matched tasks in their original lists
// if the listnames didnt change before migration (defaultlist otherwise)
listService.migrateListIds(allLists);
} finally {
allTasksWithGtaskData.close();
}
Preferences.setBoolean(GtasksPreferenceService.PREF_MIGRATION_HAS_OCCURRED, true); //Record successful migration
}
}
private String constructKeyFromTitles(String taskTitle, String listTitle) {
return taskTitle + "//" + listTitle; //$NON-NLS-1$
}
}

@ -1,14 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.legacy;
/** Legacy alert class */
abstract public class LegacyAlertModel {
public static final String TASK = "task";
public static final String DATE = "date";
}

@ -1,26 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.reminders;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class ReminderPlugin extends BroadcastReceiver {
static final String IDENTIFIER = "reminders"; //$NON-NLS-1$
@Override
public void onReceive(Context context, Intent intent) {
/*Plugin plugin = new Plugin(IDENTIFIER, "Reminders", "Todoroo",
"Provides notification reminders for tasks");
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_PLUGINS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_PLUGIN, plugin);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);*/
}
}

@ -1,70 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.ui;
import java.util.Date;
import android.app.Dialog;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.widget.Button;
import org.tasks.R;
import com.todoroo.astrid.ui.CalendarView.OnSelectedDateListener;
public class CalendarDialog extends Dialog implements OnClickListener, OnSelectedDateListener {
private final Button cancelButton;
private Date calendarDate;
private final CalendarView calendarView;
public CalendarDialog(Context context, Date calendarDate) {
super(context);
this.calendarDate = calendarDate;
/** 'Window.FEATURE_NO_TITLE' - Used to hide the title */
requestWindowFeature(Window.FEATURE_NO_TITLE);
/** Design the dialog in main.xml file */
setContentView(R.layout.calendar);
LayoutParams params = getWindow().getAttributes();
params.height = LayoutParams.FILL_PARENT;
params.width = LayoutParams.FILL_PARENT;
getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
cancelButton = (Button) findViewById(R.id.CancelButton);
calendarView = (CalendarView) findViewById(R.id.CalendarView);
calendarView.setCalendarDate(calendarDate);
calendarView.setOnSelectedDateListener(this);
cancelButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == cancelButton) {
cancel();
}
}
@Override
public void onSelectedDate(Date date) {
calendarDate = date;
dismiss();
}
public Date getCalendarDate() {
return calendarDate;
}
public void setCalendarDate(Date calendarDate) {
this.calendarDate = calendarDate;
}
}

@ -1,194 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.todoroo.astrid.ui;
import java.util.Calendar;
import android.app.AlertDialog;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TimePicker;
import android.widget.TimePicker.OnTimeChangedListener;
import org.tasks.R;
/**
* A dialog that prompts the user for the time of day using a {@link TimePicker}.
* This is similar to the Android {@link TimePickerDialog} class
* except allows users to specify "no specific time".
*/
public class DeadlineTimePickerDialog extends AlertDialog implements OnClickListener,
OnTimeChangedListener {
/**
* The callback interface used to indicate the user is done filling in
* the time (they clicked on the 'Set' button).
*/
public interface OnDeadlineTimeSetListener {
/**
* @param view The view associated with this listener.
* @param hasTime whether time is set
* @param hourOfDay The hour that was set.
* @param minute The minute that was set.
*/
void onTimeSet(TimePicker view, boolean hasTime, int hourOfDay, int minute);
}
private static final String HOUR = "hour";
private static final String MINUTE = "minute";
private static final String IS_24_HOUR = "is24hour";
private final TimePicker mTimePicker;
private final CheckBox mHasTime;
private final OnDeadlineTimeSetListener mCallback;
private final Calendar mCalendar;
private final java.text.DateFormat mDateFormat;
int mInitialHourOfDay;
int mInitialMinute;
boolean mIs24HourView;
/**
* @param context Parent.
* @param callBack How parent is notified.
* @param hourOfDay The initial hour.
* @param minute The initial minute.
* @param is24HourView Whether this is a 24 hour view, or AM/PM.
*/
public DeadlineTimePickerDialog(Context context,
OnDeadlineTimeSetListener callBack,
int hourOfDay, int minute, boolean is24HourView, boolean hasTime) {
this(context, android.R.style.Theme_Dialog,
callBack, hourOfDay, minute, is24HourView, hasTime);
}
/**
* @param context Parent.
* @param theme the theme to apply to this dialog
* @param callBack How parent is notified.
* @param hourOfDay The initial hour.
* @param minute The initial minute.
* @param is24HourView Whether this is a 24 hour view, or AM/PM.
*/
public DeadlineTimePickerDialog(Context context,
int theme,
OnDeadlineTimeSetListener callBack,
int hourOfDay, int minute, boolean is24HourView, boolean hasTime) {
super(context, theme);
mCallback = callBack;
mInitialHourOfDay = hourOfDay;
mInitialMinute = minute;
mIs24HourView = is24HourView;
mDateFormat = DateFormat.getTimeFormat(context);
mCalendar = Calendar.getInstance();
setButton(context.getText(android.R.string.ok), this);
setButton2(context.getText(android.R.string.cancel), (OnClickListener) null);
setIcon(R.drawable.ic_dialog_time);
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.time_picker_dialog, null);
setView(view);
mTimePicker = (TimePicker) view.findViewById(R.id.timePicker);
mHasTime = (CheckBox) view.findViewById(R.id.hasTime);
OnCheckedChangeListener listener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
mTimePicker.setEnabled(isChecked);
if(isChecked) {
updateTitle();
} else {
setTitle(R.string.TEA_urgency_none);
}
}
};
mHasTime.setOnCheckedChangeListener(listener);
mHasTime.setChecked(hasTime);
listener.onCheckedChanged(null, hasTime);
// initialize state
mTimePicker.setCurrentHour(mInitialHourOfDay);
mTimePicker.setCurrentMinute(mInitialMinute);
mTimePicker.setIs24HourView(mIs24HourView);
mTimePicker.setOnTimeChangedListener(this);
updateTitle();
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (mCallback != null) {
mTimePicker.clearFocus();
mCallback.onTimeSet(mTimePicker,
mHasTime.isChecked(),
mTimePicker.getCurrentHour(),
mTimePicker.getCurrentMinute());
}
}
@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
updateTitle();
}
public void updateTime(int hourOfDay, int minutOfHour) {
mTimePicker.setCurrentHour(hourOfDay);
mTimePicker.setCurrentMinute(minutOfHour);
}
private void updateTitle() {
int hour = mTimePicker.getCurrentHour();
int minute = mTimePicker.getCurrentMinute();
mCalendar.set(Calendar.HOUR_OF_DAY, hour);
mCalendar.set(Calendar.MINUTE, minute);
setTitle(mDateFormat.format(mCalendar.getTime()));
}
@Override
public Bundle onSaveInstanceState() {
Bundle state = super.onSaveInstanceState();
state.putInt(HOUR, mTimePicker.getCurrentHour());
state.putInt(MINUTE, mTimePicker.getCurrentMinute());
state.putBoolean(IS_24_HOUR, mTimePicker.is24HourView());
return state;
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
int hour = savedInstanceState.getInt(HOUR);
int minute = savedInstanceState.getInt(MINUTE);
mTimePicker.setCurrentHour(hour);
mTimePicker.setCurrentMinute(minute);
mTimePicker.setIs24HourView(savedInstanceState.getBoolean(IS_24_HOUR));
mTimePicker.setOnTimeChangedListener(this);
updateTitle();
}
}

@ -1,353 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.ui;
import java.util.HashSet;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import org.tasks.R;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.helper.AsyncImageView;
import com.todoroo.astrid.utility.ResourceDrawableCache;
public class PeopleContainer extends LinearLayout {
private boolean completeTags = false;
protected OnAddNewPersonListener onAddNewPerson = null;
protected Resources resources;
// --- accessors and boilerplate
public PeopleContainer(Context arg0, AttributeSet attrs) {
super(arg0, attrs);
resources = arg0.getResources();
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.ContactsAutoComplete);
completeTags = a.getBoolean(R.styleable.ContactsAutoComplete_completeTags, false);
}
public PeopleContainer(Context context) {
super(context);
}
public interface OnAddNewPersonListener {
public void textChanged(String text);
}
public void setOnAddNewPerson(OnAddNewPersonListener onAddNewPerson) {
this.onAddNewPerson = onAddNewPerson;
}
// --- methods
public TextView addPerson() {
return addPerson("", "", false); //$NON-NLS-1$ //$NON-NLS-2$
}
/** Adds a tag to the tag field */
public TextView addPerson(String person, String image, boolean hideRemove) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// check if already exists
for(int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
TextView matching = (TextView) view.findViewById(R.id.text1);
if(matching.getText().equals(person)) {
return matching;
}
}
final View tagItem = inflater.inflate(R.layout.contact_edit_row, null);
if(person.length() == 0) {
addView(tagItem, getChildCount());
} else {
addView(tagItem);
}
final ContactsAutoComplete textView = (ContactsAutoComplete)tagItem.
findViewById(R.id.text1);
textView.setText(person);
textView.setHint(R.string.actfm_person_hint);
if(completeTags) {
textView.setCompleteSharedTags(true);
textView.setHint(R.string.actfm_person_or_tag_hint);
}
final ImageButton removeButton = (ImageButton)tagItem.findViewById(R.id.button1);
if (hideRemove) {
removeButton.setVisibility(View.GONE);
} else {
removeButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
TextView lastView = getLastTextView();
if (lastView == textView && textView.getText().length() == 0) {
return;
}
if (getChildCount() > 1) {
removeView(tagItem);
} else {
textView.setText(""); //$NON-NLS-1$
textView.setEnabled(true);
}
}
});
}
final AsyncImageView imageView = (AsyncImageView)tagItem.
findViewById(R.id.icon);
imageView.setUrl(image);
if (TextUtils.isEmpty(textView.getText())) {
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_add_contact));
removeButton.setVisibility(View.GONE);
} else {
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
if (!hideRemove) {
removeButton.setVisibility(View.VISIBLE);
}
}
textView.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
//
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
//
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
if(count > 0 && getLastTextView() == textView) {
addPerson("", "", false);
}
if (TextUtils.isEmpty(textView.getText())) {
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_add_contact));
removeButton.setVisibility(View.GONE);
}
else {
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
removeButton.setVisibility(View.VISIBLE);
}
if(onAddNewPerson != null) {
onAddNewPerson.textChanged(s.toString());
}
}
});
textView.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView arg0, int actionId, KeyEvent arg2) {
if(actionId != EditorInfo.IME_NULL) {
return false;
}
if(getLastTextView().getText().length() != 0) {
addPerson("", "", false);
}
return true;
}
});
return textView;
}
/**
* Get tags container last text view. might be null
* @return
*/
private TextView getLastTextView() {
for(int i = getChildCount() - 1; i >= 0; i--) {
View lastItem = getChildAt(i);
TextView lastText = (TextView) lastItem.findViewById(R.id.text1);
if(lastText.isEnabled()) {
return lastText;
}
}
return null;
}
public TextView getTextView(int index) {
View item = getChildAt(index);
return (TextView) item.findViewById(R.id.text1);
}
/**
*
* @return json array of people
*/
public JSONArray toJSONArray() {
JSONArray people = new JSONArray();
for(int i = 0; i < getChildCount(); i++) {
TextView textView = getTextView(i);
JSONObject person = PeopleContainer.createUserJson(textView);
if(person != null) {
String email = person.optString("email"); //$NON-NLS-1$
if (email.indexOf('@') != -1) {
people.put(person);
}
}
}
return people;
}
public JSONObject parseSharedWithAndTags(Activity activity, boolean peopleAsJSON) throws
JSONException, ParseSharedException {
JSONObject sharedWith = new JSONObject();
HashSet<String> addedEmails = new HashSet<String>();
HashSet<Long> addedIds = new HashSet<Long>();
JSONArray peopleList = new JSONArray();
for(int i = 0; i < getChildCount(); i++) {
TextView textView = getTextView(i);
String text = textView.getText().toString();
if(text.length() == 0) {
continue;
}
if(text.indexOf('@') == -1 && textView.isEnabled()) {
throw new ParseSharedException(textView,
activity.getString(R.string.actfm_EPA_invalid_email, text));
}
if (peopleAsJSON) {
JSONObject person = PeopleContainer.createUserJson(textView);
if (person != null) {
if (person.optBoolean("owner")) //$NON-NLS-1$
{
continue;
}
String email = person.optString("email");
Long id = person.optLong("id", -1);
if (!TextUtils.isEmpty(email) && !addedEmails.contains(email)) {
addedEmails.add(email);
if (id > 0) {
addedIds.add(id);
}
peopleList.put(person);
} else if (id > 0 && !addedIds.contains(id)) {
addedIds.add(id);
peopleList.put(person);
}
}
} else if (!addedEmails.contains(text)) {
addedEmails.add(text);
peopleList.put(text);
}
}
if(peopleList.length() > 0) {
sharedWith.put("p", peopleList);
}
return sharedWith;
}
public static class ParseSharedException extends Exception {
private static final long serialVersionUID = -4135848250086302970L;
public TextView view;
public String message;
public ParseSharedException(TextView view, String message) {
this.view = view;
this.message = message;
}
}
/**
* Add people from JSON Array
* @param people
*/
public void fromJSONArray(JSONArray people) throws JSONException {
for(int i = 0; i < people.length(); i++) {
JSONObject person = people.getJSONObject(i);
TextView textView = null;
String imageURL = person.optString("picture", "");
boolean owner = person.optBoolean("owner");
boolean hideRemove = owner;
String name = "";
if(person.has("id") && ActFmPreferenceService.userId().equals(person.getString("id"))) {
name = Preferences.getStringValue(ActFmPreferenceService.PREF_NAME);
hideRemove = true;
} else if(!TextUtils.isEmpty(person.optString("name")) && !"null".equals(person.optString("name"))) {
name = person.getString("name");
} else if(!TextUtils.isEmpty(person.optString("email")) && !"null".equals(person.optString("email"))) {
name = person.getString("email");
}
if (owner) {
name = name + " " + ContextManager.getString(R.string.actfm_list_owner);
}
textView = addPerson(name, imageURL, hideRemove);
if(textView != null) {
textView.setTag(person);
textView.setEnabled(false);
}
}
}
/**
* Warning: user json may not have a valid email address.
* @param textView
* @return
*/
public static JSONObject createUserJson(TextView textView) {
if(textView.isEnabled() == false) {
return (JSONObject) textView.getTag();
}
String text = textView.getText().toString().trim();
if(text.length() == 0) {
return null;
}
JSONObject user = new JSONObject();
int bracket = text.lastIndexOf('<');
try {
if(bracket > -1) {
user.put("name", text.substring(0, bracket - 1).trim());
user.put("email", text.substring(bracket + 1, text.length() - 1).trim());
} else {
user.put("email", text);
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
return user;
}
}

@ -1,40 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.ui;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public class TextViewWithMeasureListener extends TextView {
public interface OnTextMeasureListener {
public void onTextSizeChanged();
}
private OnTextMeasureListener listener;
public TextViewWithMeasureListener(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (listener != null) {
listener.onTextSizeChanged();
}
}
public OnTextMeasureListener getOnTextSizeChangedListener() {
return listener;
}
public void setOnTextSizeChangedListener(OnTextMeasureListener listener) {
this.listener = listener;
}
}

@ -1,116 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.todoroo.astrid.utility;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
/**
* <p>Escapes and unescapes <code>String</code>s for
* Java, Java Script, HTML, XML, and SQL.</p>
*
* @author Apache Jakarta Turbine
* @author Purple Technology
* @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a>
* @author Antony Riley
* @author Helge Tesgaard
* @author <a href="sean@boohai.com">Sean Brown</a>
* @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
* @author Phil Steitz
* @author Pete Gieser
* @since 2.0
* @version $Id: StringEscapeUtils.java 2696 2007-06-20 13:24:53Z damencho $
*/
public class StringEscapeUtils {
/**
* <p><code>StringEscapeUtils</code> instances should NOT be constructed in
* standard programming.</p>
*
* <p>Instead, the class should be used as:
* <pre>StringEscapeUtils.escapeJava("foo");</pre></p>
*
* <p>This constructor is public to permit tools that require a JavaBean
* instance to operate.</p>
*/
public StringEscapeUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* <p>Unescapes a string containing entity escapes to a string
* containing the actual Unicode characters corresponding to the
* escapes. Supports HTML 4.0 entities.</p>
*
* <p>For example, the string "&amp;lt;Fran&amp;ccedil;ais&amp;gt;"
* will become "&lt;Fran&ccedil;ais&gt;"</p>
*
* <p>If an entity is unrecognized, it is left alone, and inserted
* verbatim into the result string. e.g. "&amp;gt;&amp;zzzz;x" will
* become "&gt;&amp;zzzz;x".</p>
*
* @param str the <code>String</code> to unescape, may be null
* @return a new unescaped <code>String</code>, <code>null</code> if null string input
* @see #escapeHtml(Writer, String)
*/
public static String unescapeHtml(String str) {
if (str == null) {
return null;
}
try {
StringWriter writer = new StringWriter ((int)(str.length() * 1.5));
unescapeHtml(writer, str);
return writer.toString();
} catch (IOException e) {
//assert false;
//should be impossible
e.printStackTrace();
return null;
}
}
/**
* <p>Unescapes a string containing entity escapes to a string
* containing the actual Unicode characters corresponding to the
* escapes. Supports HTML 4.0 entities.</p>
*
* <p>For example, the string "&amp;lt;Fran&amp;ccedil;ais&amp;gt;"
* will become "&lt;Fran&ccedil;ais&gt;"</p>
*
* <p>If an entity is unrecognized, it is left alone, and inserted
* verbatim into the result string. e.g. "&amp;gt;&amp;zzzz;x" will
* become "&gt;&amp;zzzz;x".</p>
*
* @param writer the writer receiving the unescaped string, not null
* @param string the <code>String</code> to unescape, may be null
* @throws IllegalArgumentException if the writer is null
* @throws IOException if an IOException occurs
* @see #escapeHtml(String)
*/
public static void unescapeHtml(Writer writer, String string) throws IOException {
if (writer == null ) {
throw new IllegalArgumentException ("The Writer must not be null.");
}
if (string == null) {
return;
}
Entities.HTML40.unescape(writer, string);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:astrid="http://schemas.android.com/apk/res/org.tasks"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<com.todoroo.astrid.helper.AsyncImageView
android:id="@+id/icon"
android:layout_width="31dip"
android:layout_height="35dip"
android:layout_margin="5dip"
astrid:defaultSrc="@drawable/icn_default_person_image"
android:gravity="center"
android:scaleType="fitCenter" />
<com.todoroo.astrid.ui.ContactsAutoComplete
android:id="@+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dip"
android:layout_weight="1"
android:background="#00000000"
android:hint="@string/actfm_person_hint"
style="@style/TextAppearance"
android:textCursorDrawable="@null"
android:textSize="15sp" />
<ImageButton
android:id="@+id/button1"
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_gravity="center"
android:layout_margin="4dip"
android:background="@drawable/btn_dismiss" />
</LinearLayout>
<View
android:id="@+id/divider"
style="@style/TEA_Separator"
android:layout_width="fill_parent"
android:layout_height="1dip" />
</LinearLayout>

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip"
android:orientation="vertical">
<TimePicker android:id="@+id/timePicker"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<CheckBox android:id="@+id/hasTime"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TEA_urgency_specific_time"/>
</LinearLayout>
</ScrollView>

@ -3,18 +3,6 @@
<!-- ================================================== general terms == -->
<!-- People Editing Activity -->
<!-- slide 18b/ 25e/ 27c: task sharing dialog: assigned hint -->
<string name="actfm_person_hint">Contact or Email</string>
<!-- task sharing dialog: shared with hint -->
<string name="actfm_person_or_tag_hint">Contact or Shared List</string>
<!-- toast on transmit success -->
<!-- can't rename or delete shared tag message -->
<!-- warning before deleting a list you're the owner of -->
<string name="actfm_tag_operation_owner_delete">You are the owner of this shared list! If you delete it, it will be deleted for all list members. Are you sure you want to continue?</string>
@ -96,9 +84,6 @@
<!-- ============================================ edit people dialog == -->
<!-- task sharing dialog: invalid email (%s => email) -->
<string name="actfm_EPA_invalid_email">Invalid E-mail: %s</string>
<string name="actfm_EPA_add_person_to_list_title">Task assigned</string>
<string name="actfm_EPA_add_person_to_list">%1$s is not shared on this list. Would you like to add %2$s to this list?</string>
@ -107,8 +92,6 @@
<string name="actfm_EPA_add_person_to_list_cancel">Don\'t add</string>
<string name="actfm_list_owner">(owner)</string>
<!-- ========================================= sharing login activity == -->
<!-- share login: Google Auth title -->

@ -247,12 +247,6 @@
<!-- Task due date hint -->
<string name="TEA_deadline_hint">Set due date</string>
<!-- Task urgency specific time checkbox -->
<string name="TEA_urgency_specific_time">At specific time?</string>
<!-- Task urgency specific time title when specific time false -->
<string name="TEA_urgency_none">None</string>
<!-- Task hide until label -->
<string name="TEA_hideUntil_label">Hide until</string>

Loading…
Cancel
Save