Java tutorial
/* * This file is part of the Do it later! Android application. * * Copyright 2011-2012 Dirk Grappendorf, www.grappendorf.net * * 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 net.grappendorf.doitlater; import android.accounts.*; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.util.Log; 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.googleapis.services.GoogleKeyInitializer; import com.google.api.client.http.HttpTransport; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.gson.GsonFactory; import com.google.api.client.util.DateTime; import com.google.api.services.tasks.Tasks; import com.google.api.services.tasks.model.Task; import com.google.api.services.tasks.model.TaskList; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; public class TaskManagerImpl implements TaskManager { private static final String PREF_NAME = "taskManager"; private static final String AUTH_TOKEN_TYPE = "Manage your tasks"; private static final String PREF_AUTH_TOKEN = "authToken"; private static final String PREF_ACCOUNT_NAME = "accountName"; private GoogleCredential credential; private Tasks tasksService; private GoogleAccountManager accountManager; private Map<Activity, AsyncTask<Void, Void, ?>> asyncTaskByActivity; private SharedPreferences preferences; private String accountName; private boolean received401; public TaskManagerImpl(Context context) { SharedPreferences globalPrefs = PreferenceManager.getDefaultSharedPreferences(context); String apiKey = globalPrefs.getString("api_key", ""); this.credential = new GoogleCredential(); this.accountManager = new GoogleAccountManager(context); HttpTransport transport = AndroidHttp.newCompatibleTransport(); JsonFactory jsonFactory = new GsonFactory(); this.tasksService = new Tasks.Builder(transport, jsonFactory, credential) .setApplicationName(DoItLaterApplication.NAME) .setJsonHttpRequestInitializer(new GoogleKeyInitializer(apiKey)).build(); asyncTaskByActivity = new HashMap<Activity, AsyncTask<Void, Void, ?>>(); preferences = context.getSharedPreferences(PREF_NAME, Activity.MODE_PRIVATE); credential.setAccessToken(preferences.getString(PREF_AUTH_TOKEN, null)); accountName = preferences.getString(PREF_ACCOUNT_NAME, null); received401 = false; } private void executeAsyncTaskWhenAuthenticated(final Activity activity) { Account account = accountManager.getAccountByName(accountName); if (account == null) { chooseAccount(activity); return; } if (credential.getAccessToken() != null) { onAuthToken(activity); return; } accountManager.getAccountManager().getAuthToken(account, AUTH_TOKEN_TYPE, true, new AccountManagerCallback<Bundle>() { 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); activity.startActivityForResult(intent, GlobalActivityCodes.TASK_MANAGER_REQUEST_AUTHENTICATE); } else if (bundle.containsKey(AccountManager.KEY_AUTHTOKEN)) { setAuthToken(bundle.getString(AccountManager.KEY_AUTHTOKEN)); onAuthToken(activity); } } catch (Exception e) { Log.e(DoItLaterApplication.LOG_TAG, e.getMessage(), e); onRequestAborted(activity); } } }, null); } @Override public void chooseAccount(final Activity activity) { accountManager.getAccountManager().getAuthTokenByFeatures(GoogleAccountManager.ACCOUNT_TYPE, AUTH_TOKEN_TYPE, null, activity, null, null, new AccountManagerCallback<Bundle>() { public void run(AccountManagerFuture<Bundle> future) { try { Bundle bundle = future.getResult(); setAccountName(bundle.getString(AccountManager.KEY_ACCOUNT_NAME)); setAuthToken(bundle.getString(AccountManager.KEY_AUTHTOKEN)); onAuthToken(activity); } catch (OperationCanceledException e) { onRequestAborted(activity); } catch (AuthenticatorException e) { Log.e(DoItLaterApplication.NAME, e.getMessage(), e); onRequestAborted(activity); } catch (IOException e) { Log.e(DoItLaterApplication.NAME, e.getMessage(), e); onRequestAborted(activity); } } }, null); } private void setAccountName(String accountName) { SharedPreferences.Editor editor = preferences.edit(); editor.putString(PREF_ACCOUNT_NAME, accountName); editor.commit(); this.accountName = accountName; } private void setAuthToken(String authToken) { SharedPreferences.Editor editor = preferences.edit(); editor.putString(PREF_AUTH_TOKEN, authToken); editor.commit(); credential.setAccessToken(authToken); } private void onRequestCompleted() { received401 = false; } private void onRequestAborted(Activity activity) { asyncTaskByActivity.remove(activity); } private void handleApiException(Activity activity, Handler callback, IOException e) { if (e instanceof GoogleJsonResponseException) { GoogleJsonResponseException exception = (GoogleJsonResponseException) e; if (exception.getStatusCode() == 401 && !received401) { received401 = true; accountManager.invalidateAuthToken(credential.getAccessToken()); credential.setAccessToken(null); SharedPreferences.Editor editor2 = preferences.edit(); editor2.remove(PREF_AUTH_TOKEN); editor2.commit(); executeAsyncTaskWhenAuthenticated(activity); return; } } Log.e(DoItLaterApplication.LOG_TAG, e.getMessage(), e); onRequestAborted(activity); callback.sendMessage(callback.obtainMessage(0, null)); } void onAuthToken(Activity activity) { asyncTaskByActivity.get(activity).execute((Void) null); } @Override public void onRequestAuthenticateResult(Activity activity, int requestCode) { if (requestCode == Activity.RESULT_OK) { executeAsyncTaskWhenAuthenticated(activity); } else { chooseAccount(activity); } } @Override public String getDefaultTaskListId() { return "@default"; } @Override public void listTaskLists(final Activity activity, final Handler callback) { AsyncTask<Void, Void, Void> asyncTask = new AsyncTaskWithProgressDialog<Void, Void, Void>(activity, R.string.loading) { @Override protected Void doInBackground(Void... voids) { try { List<TaskList> taskLists = tasksService.tasklists().list().execute().getItems(); callback.sendMessage(callback.obtainMessage(0, taskLists)); asyncTaskByActivity.remove(activity); onRequestCompleted(); } catch (IOException e) { handleApiException(activity, callback, e); } return null; } }; asyncTaskByActivity.put(activity, asyncTask); executeAsyncTaskWhenAuthenticated(activity); } @Override public void getTaskList(final String taskListId, final Activity activity, final Handler callback) { AsyncTask<Void, Void, Void> asyncTask = new AsyncTaskWithProgressDialog<Void, Void, Void>(activity, R.string.loading) { @Override protected Void doInBackground(Void... voids) { try { TaskList taskList = tasksService.tasklists().get(taskListId).execute(); callback.sendMessage(callback.obtainMessage(0, taskList)); asyncTaskByActivity.remove(activity); onRequestCompleted(); } catch (IOException e) { handleApiException(activity, callback, e); } return null; } }; asyncTaskByActivity.put(activity, asyncTask); executeAsyncTaskWhenAuthenticated(activity); } @Override public void listTasks(final String taskListId, final String[] fields, final FilterOptions filter, final Activity activity, final Handler callback) { AsyncTask<Void, Void, Void> asyncTask = new AsyncTaskWithProgressDialog<Void, Void, Void>(activity, R.string.loading) { @Override protected Void doInBackground(Void... voids) { try { StringBuilder fieldsSpec = new StringBuilder("items(id"); for (String field : fields) { fieldsSpec.append(","); fieldsSpec.append(field); } fieldsSpec.append(")"); List<Task> tasks = tasksService.tasks().list(taskListId).setFields(fieldsSpec.toString()) .setShowDeleted(false).setShowCompleted(filter.showCompleted).execute().getItems(); callback.sendMessage(callback.obtainMessage(0, tasks)); asyncTaskByActivity.remove(activity); onRequestCompleted(); } catch (IOException e) { handleApiException(activity, callback, e); } return null; } }; asyncTaskByActivity.put(activity, asyncTask); executeAsyncTaskWhenAuthenticated(activity); } @Override public void getTask(final String taskListId, final String taskId, final Activity activity, final Handler callback) { AsyncTask<Void, Void, Void> asyncTask = new AsyncTaskWithProgressDialog<Void, Void, Void>(activity, R.string.loading) { @Override protected Void doInBackground(Void... voids) { try { Task task = tasksService.tasks().get(taskListId, taskId).execute(); callback.sendMessage(callback.obtainMessage(0, task)); asyncTaskByActivity.remove(activity); onRequestCompleted(); } catch (IOException e) { handleApiException(activity, callback, e); } return null; } }; asyncTaskByActivity.put(activity, asyncTask); executeAsyncTaskWhenAuthenticated(activity); } @Override public void updateTask(final String taskListId, final Task task, final Activity activity, final Handler callback) { AsyncTask<Void, Void, Void> asyncTask = new AsyncTaskWithProgressDialog<Void, Void, Void>(activity, R.string.saving) { @Override protected Void doInBackground(Void... voids) { try { Task result = tasksService.tasks().update(taskListId, task.getId(), task).execute(); callback.sendMessage(callback.obtainMessage(0, result)); asyncTaskByActivity.remove(activity); onRequestCompleted(); } catch (IOException e) { handleApiException(activity, callback, e); } return null; } }; asyncTaskByActivity.put(activity, asyncTask); executeAsyncTaskWhenAuthenticated(activity); } @Override public void deleteTask(final String taskListId, final String taskId, final Activity activity, final Handler callback) { AsyncTask<Void, Void, Void> asyncTask = new AsyncTaskWithProgressDialog<Void, Void, Void>(activity, R.string.deleting) { @Override protected Void doInBackground(Void... voids) { try { // To really delete a task, we first need to clear all it's fields. // Otherwise the task would only be marked as deleted (in the Google // Task web application the task then shows up under the 'Trash' view). Task task = tasksService.tasks().get(taskListId, taskId).execute(); task.setTitle(""); task.setNotes(""); task.setDue(null); tasksService.tasks().update(taskListId, taskId, task).execute(); tasksService.tasks().delete(taskListId, taskId).execute(); callback.sendMessage(callback.obtainMessage(0, taskId)); asyncTaskByActivity.remove(activity); onRequestCompleted(); } catch (IOException e) { handleApiException(activity, callback, e); } return null; } }; asyncTaskByActivity.put(activity, asyncTask); executeAsyncTaskWhenAuthenticated(activity); } @Override public void completeTask(final String taskListId, final String taskId, final Activity activity, final Handler callback) { AsyncTask<Void, Void, Void> asyncTask = new AsyncTaskWithProgressDialog<Void, Void, Void>(activity, R.string.completing) { @Override protected Void doInBackground(Void... voids) { try { Task task = tasksService.tasks().get(taskListId, taskId).execute(); task.setCompleted(new DateTime(System.currentTimeMillis(), 0)); task.setStatus("completed"); Task result = tasksService.tasks().update(taskListId, task.getId(), task).execute(); callback.sendMessage(callback.obtainMessage(0, result)); asyncTaskByActivity.remove(activity); onRequestCompleted(); } catch (IOException e) { handleApiException(activity, callback, e); } return null; } }; asyncTaskByActivity.put(activity, asyncTask); executeAsyncTaskWhenAuthenticated(activity); } @Override public void createTask(final String taskListId, final Task task, final String previousTaskId, final Activity activity, final Handler callback) { AsyncTask<Void, Void, Void> asyncTask = new AsyncTaskWithProgressDialog<Void, Void, Void>(activity, R.string.creating) { @Override protected Void doInBackground(Void... voids) { try { Tasks.TasksOperations.Insert insert = tasksService.tasks().insert(taskListId, task); insert.setPrevious(previousTaskId); Task result = insert.execute(); callback.sendMessage(callback.obtainMessage(0, result)); asyncTaskByActivity.remove(activity); onRequestCompleted(); } catch (IOException e) { handleApiException(activity, callback, e); } return null; } }; asyncTaskByActivity.put(activity, asyncTask); executeAsyncTaskWhenAuthenticated(activity); } @Override public void moveTask(final String taskListId, final Task task, final String previousTaskId, final Activity activity, final Handler callback) { AsyncTask<Void, Void, Void> asyncTask = new AsyncTaskWithProgressDialog<Void, Void, Void>(activity, R.string.moving) { @Override protected Void doInBackground(Void... voids) { try { Tasks.TasksOperations.Move move = tasksService.tasks().move(taskListId, task.getId()); move.setPrevious(previousTaskId); Task result = move.execute(); callback.sendMessage(callback.obtainMessage(0, result)); asyncTaskByActivity.remove(activity); onRequestCompleted(); } catch (IOException e) { handleApiException(activity, callback, e); } return null; } }; asyncTaskByActivity.put(activity, asyncTask); executeAsyncTaskWhenAuthenticated(activity); } @Override public void debugDump() { Log.d(DoItLaterApplication.LOG_TAG, "TaskManager debug dump:"); Log.d(DoItLaterApplication.LOG_TAG, "\tAsync tasks by activity:"); if (asyncTaskByActivity.size() > 0) { for (Map.Entry<Activity, AsyncTask<Void, Void, ?>> entry : asyncTaskByActivity.entrySet()) { Log.d(DoItLaterApplication.LOG_TAG, "\t\t" + entry.getKey().getLocalClassName() + " => " + entry.getValue().toString()); } } else { Log.d(DoItLaterApplication.LOG_TAG, "\t\tNone"); } } }