package com.redditandroiddevelopers.googletasksclient; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import com.google.api.client.extensions.android2.AndroidHttp; import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager; import com.google.api.client.googleapis.json.GoogleJsonResponseException; import com.google.api.client.http.HttpTransport; import com.google.api.client.http.apache.ApacheHttpTransport; import com.google.api.client.http.json.JsonHttpRequest; import com.google.api.client.http.json.JsonHttpRequestInitializer; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson.JacksonFactory; import com.google.api.services.tasks.Tasks; import com.google.api.services.tasks.Tasks.TasksOperations.Insert; import com.google.api.services.tasks.TasksRequest; import com.google.api.services.tasks.model.Task; 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.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.widget.SimpleCursorAdapter; import android.text.format.DateUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.SherlockActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.MenuInflater; import com.redditandroiddevelopers.googletasksclient.ClientCredentials; public class GoogleTasksClientActivity extends SherlockActivity{ /** Logging level for HTTP requests/responses. */ private static final Level LOGGING_LEVEL = Level.OFF; private static final String TAG = "TasksSample"; // This must be the exact string, and is a special for alias OAuth 2 scope // "https://www.googleapis.com/auth/tasks" private static final String AUTH_TOKEN_TYPE = "Manage your tasks"; private static final int MENU_ACCOUNTS = 0; private static final int REQUEST_AUTHENTICATE = 0; final HttpTransport transport = AndroidHttp.newCompatibleTransport(); final JsonFactory jsonFactory = new JacksonFactory(); static final String PREF_ACCOUNT_NAME = "accountName"; static final String PREF_AUTH_TOKEN = "authToken"; GoogleAccountManager accountManager; SharedPreferences settings; String accountName; GoogleCredential credential = new GoogleCredential(); com.google.api.services.tasks.Tasks service; TasksData newTask; ArrayList<TasksData> taskTitles = new ArrayList<TasksData>(); ListView listView; ProgressBar progressView; @Override public boolean onCreateOptionsMenu(Menu menu) { //add menu items to the action bar. look on onOptionsItemSelected to action code. menu.add(0,0,0,"Add New Task"); menu.add(0,1,0,"Search"); menu.add(0,2,0,"Settings"); menu.add(0,3,0,"Refresh"); return true; } //to Download All List and add items to listview. class RetreiveTask extends AsyncTask<String, Void, ArrayList<TasksData>> { @Override protected ArrayList<TasksData> doInBackground(String... args) { //show progressbar progressView.setVisibility(ProgressBar.VISIBLE); //hide listview //listView.setVisibility(View.INVISIBLE); ArrayList<TasksData> tasksData = new ArrayList<TasksData>(); try { List<Task> tasks = service.tasks().list("@default").execute().getItems(); if (tasks != null) { for (Task task : tasks) { long positionLong = Long.parseLong(task.getPosition()); TasksData taskNew = new TasksData(task.getEtag(), task.getId(), task.getKind(), positionLong, task.getSelfLink(), task.getStatus(), task.getTitle(), task.getUpdated()); Log.v(TAG, "TASK DATA = " + task.toString()); tasksData.add(taskNew); } } else { //taskTitles.add("No tasks."); } } catch (IOException e) { handleGoogleException(e); } return tasksData; } protected void onPostExecute(ArrayList<TasksData> result) { taskListAdaptor adaptor = new taskListAdaptor(GoogleTasksClientActivity.this,R.layout.list_item, result); //hide progressbar progressView.setVisibility(ProgressBar.GONE); //show listview // listView.setVisibility(View.INVISIBLE); listView = (ListView) findViewById(R.id.mylist); listView.setAdapter(adaptor); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> a, View v, int position, long id) { Object o = listView.getItemAtPosition(position); TasksData fullObject = (TasksData)o; Bundle bundle = new Bundle(); bundle.putString("title", fullObject.getTitle()); bundle.putString("taskID", fullObject.getId()); Intent newIntent = new Intent(getApplicationContext(), detailTasks.class); newIntent.putExtras(bundle); startActivityForResult(newIntent, 0); } }); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case 0: { //Open AddTaskActivity to add new task. Intent myIntent = new Intent(GoogleTasksClientActivity.this, AddTaskActivity.class); GoogleTasksClientActivity.this.startActivity(myIntent); return true; } case 1: { Toast.makeText(this, "Search selected", Toast.LENGTH_SHORT).show(); return true; } case 2: { Toast.makeText(this, "Settings selected", Toast.LENGTH_SHORT).show(); return true; } case 3: { Toast.makeText(this, "refreshing task list", Toast.LENGTH_SHORT).show(); refresh(); return true; } default: return super.onOptionsItemSelected(item); } } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); settings = PreferenceManager.getDefaultSharedPreferences(this); setContentView(R.layout.main); progressView = (ProgressBar)findViewById(R.id.marker_progress); service = com.google.api.services.tasks.Tasks.builder(transport, jsonFactory) .setApplicationName("RedditGoogleTasks/1.0") .setHttpRequestInitializer(credential) .setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() { @Override public void initialize(JsonHttpRequest request) throws IOException { TasksRequest tasksRequest = (TasksRequest) request; tasksRequest.setKey(ClientCredentials.KEY); } }) .build(); //settings = getPreferences(MODE_PRIVATE); accountName = settings.getString(PREF_ACCOUNT_NAME, null); credential.setAccessToken(settings.getString(PREF_AUTH_TOKEN, null)); Logger.getLogger("com.google.api.client").setLevel(LOGGING_LEVEL); accountManager = new GoogleAccountManager(getApplicationContext()); gotAccount(); } //Put oauthToken on sharedPreferences void setAuthToken(String authToken) { SharedPreferences.Editor editor = settings.edit(); editor.putString(PREF_AUTH_TOKEN, authToken); editor.commit(); credential.setAccessToken(authToken); } void gotAccount() { Account account = accountManager.getAccountByName(accountName); if (account == null) { chooseAccount(); return; } if (credential.getAccessToken() != null) { //download task list new RetreiveTask().execute(); return; } accountManager.manager.getAuthToken( account, AUTH_TOKEN_TYPE, true, new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> future) { try { Bundle bundle = future.getResult(); if (bundle.containsKey(AccountManager.KEY_INTENT)) { Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT); intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); startActivityForResult(intent, REQUEST_AUTHENTICATE); } else if (bundle.containsKey(AccountManager.KEY_AUTHTOKEN)) { setAuthToken(bundle.getString(AccountManager.KEY_AUTHTOKEN)); new RetreiveTask().execute(); } } catch (Exception e) { Log.e(TAG, e.getMessage(), e); } } }, null); } private void chooseAccount() { accountManager.manager.getAuthTokenByFeatures(GoogleAccountManager.ACCOUNT_TYPE, AUTH_TOKEN_TYPE, null, GoogleTasksClientActivity.this, null, null, new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> future) { Bundle bundle; try { bundle = future.getResult(); setAccountName(bundle.getString(AccountManager.KEY_ACCOUNT_NAME)); setAuthToken(bundle.getString(AccountManager.KEY_AUTHTOKEN)); //download task list new RetreiveTask().execute(); } catch (OperationCanceledException e) { // user canceled } catch (AuthenticatorException e) { Log.e(TAG, e.getMessage(), e); } catch (IOException e) { Log.e(TAG, e.getMessage(), e); } } }, null); } //Put account name on sharedPreferences void setAccountName(String accountName) { SharedPreferences.Editor editor = settings.edit(); editor.putString(PREF_ACCOUNT_NAME, accountName); editor.commit(); this.accountName = accountName; } void handleGoogleException(IOException e) { if (e instanceof GoogleJsonResponseException) { GoogleJsonResponseException exception = (GoogleJsonResponseException) e; // TODO(yanivi): should only try this once to avoid infinite loop if (exception.getStatusCode() == 401) { accountManager.invalidateAuthToken(credential.getAccessToken()); credential.setAccessToken(null); SharedPreferences.Editor editor2 = settings.edit(); editor2.remove(PREF_AUTH_TOKEN); editor2.commit(); gotAccount(); return; } } Log.e(TAG, e.getMessage(), e); } //Currently to refresh listView, we need to restart the main activity. this will be temporary fix. ||rheza public void refresh() { Intent intent = getIntent(); overridePendingTransition(0, 0); intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); finish(); overridePendingTransition(0, 0); startActivity(intent); } private class taskListAdaptor extends ArrayAdapter<TasksData> { private ArrayList<TasksData> tasks; public taskListAdaptor(Context retreiveTask, int listItem, ArrayList<TasksData> taskTitles2) { super(retreiveTask, listItem, taskTitles2); this.tasks = taskTitles2; } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.list_item, null); } TasksData o = tasks.get(position); TextView titleView = (TextView) v.findViewById(R.id.titleTask); TextView dateView = (TextView) v.findViewById(R.id.createdAtText); //use timeAgo twitter style date long longDate=o.getUpdated().getValue(); CharSequence timeago = DateUtils.getRelativeTimeSpanString(longDate); String timeagoString = timeago.toString(); titleView.setText(o.getTitle()); dateView.setText(timeagoString); return v; } } }