Java tutorial
/* The List powered by Creative Commons Copyright (C) 2014, 2015 Creative Commons This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.creativecommons.thelist.utils; 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.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.widget.ArrayAdapter; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; import org.creativecommons.thelist.R; import org.creativecommons.thelist.authentication.AccountGeneral; import org.creativecommons.thelist.authentication.ServerAuthenticate; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class ListUser implements ServerAuthenticate { public static final String TAG = ListUser.class.getSimpleName(); private MessageHelper mMessageHelper; private SharedPreferencesMethods mSharedPref; private Context mContext; private Activity mActivity; private AccountManager am; public AlertDialog mAlertDialog; public ListUser(Context mc) { mContext = mc; mSharedPref = new SharedPreferencesMethods(mContext); mMessageHelper = new MessageHelper(mContext); am = AccountManager.get(mContext); } public ListUser(Activity a) { mActivity = a; mContext = a; mSharedPref = new SharedPreferencesMethods(mContext); mMessageHelper = new MessageHelper(mContext); am = AccountManager.get(mContext); } //Callback for account signin/login public interface AuthCallback { void onSuccess(final String authtoken); } public boolean isTempUser() { //TODO: Check if User account exists in AccountManager <== Do we need this? SharedPreferences sharedPref = mContext.getSharedPreferences(SharedPreferencesMethods.APP_PREFERENCES_KEY, Context.MODE_PRIVATE); if (mSharedPref.getUserId() == null) { return true; } else { return false; } } //isTempUser public String getUserID() { return mSharedPref.getUserId(); } //getUserID // -------------------------------------------------------- // ACCOUNT HELPER METHODS // -------------------------------------------------------- public String getUserIDFromAccount(Account ac) { return am.getUserData(ac, AccountGeneral.USER_ID); } //getUserIDFromAccount public Boolean getAnalyticsOptOut() { Account ac = getAccount(); return Boolean.valueOf(am.getUserData(ac, AccountGeneral.ANALYTICS_OPTOUT)); } public void setAnalyticsOptOut(Boolean bol) { Account ac = getAccount(); am.setUserData(ac, AccountGeneral.ANALYTICS_OPTOUT, bol.toString()); } public Account getAccount() { Account matchingAccount = null; Account availableAccounts[] = am.getAccountsByType(AccountGeneral.ACCOUNT_TYPE); //Check if account matches ID String userID = mSharedPref.getUserId(); for (Account currentAccount : availableAccounts) { String testID = getUserIDFromAccount(currentAccount); if (testID.equals(userID)) { matchingAccount = currentAccount; Log.v(TAG, "getAccount: Account Match Found"); break; } } return matchingAccount; } //getAccount matching userID public int getAccountCount() { Account availableAccounts[] = am.getAccountsByType(AccountGeneral.ACCOUNT_TYPE); return availableAccounts.length; } public String getAccountName() { Account account = getAccount(); if (account != null) { return account.name; } else { return mContext.getString(R.string.drawer_account_name_not_found); } } /** * Get auth token for existing account, if the account doesnt exist, create new CCID account * You must already have a valid ID */ public void getAuthed(final AuthCallback callback) { Log.d(TAG, "Getting session token"); //sessionComplete = false; if (isTempUser()) { addNewAccount(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, new AuthCallback() { @Override public void onSuccess(String authtoken) { Log.v(TAG, "> getAuthed > addNewAccount token: " + authtoken); callback.onSuccess(authtoken); } }); } else { Account account = getAccount(); if (account == null) { Log.v(TAG, "getToken > getAccount > account is null"); return; } am.getAuthToken(account, AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, null, mActivity, new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> future) { try { Bundle bundle = future.getResult(); String authtoken = bundle.getString(AccountManager.KEY_AUTHTOKEN); Log.v(TAG, "> getAuthed > getAuthToken from existing account: " + authtoken); callback.onSuccess(authtoken); } catch (OperationCanceledException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (AuthenticatorException e) { e.printStackTrace(); } } }, null); } } //GetAuthed /** * Get auth token for existing account (assumes pre-existing account) */ public void getToken(final AuthCallback callback) { Log.d(TAG, "getToken > getting session token"); //sessionComplete = false; //TODO: match userID to account with the same userID store in AccountManager Account account = getAccount(); if (account == null) { Log.v(TAG, "getToken > getAccount > account is null"); return; } am.getAuthToken(account, AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, null, mActivity, new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> future) { try { Bundle bundle = future.getResult(); String authtoken = bundle.getString(AccountManager.KEY_AUTHTOKEN); Log.v(TAG, "> getToken, token received: " + authtoken); callback.onSuccess(authtoken); } catch (OperationCanceledException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (AuthenticatorException e) { e.printStackTrace(); } } }, null); } //getToken /** * Show all the accounts registered on the account manager. Request an auth token upon user select. */ public void showAccountPicker(final AuthCallback callback) { //@param final boolean invalidate, final String authTokenType // mInvalidate = invalidate; final Account availableAccounts[] = am.getAccountsByType(AccountGeneral.ACCOUNT_TYPE); if (availableAccounts.length == 0) { //TODO: Show other dialog to add account addNewAccount(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, new AuthCallback() { @Override public void onSuccess(String authtoken) { Log.d(TAG, " > showAccountPicker (no accounts) > addNewAccount, " + "token received: " + authtoken); } }); } else { String name[] = new String[availableAccounts.length]; for (int i = 0; i < availableAccounts.length; i++) { name[i] = availableAccounts[i].name; } // Account picker mAlertDialog = new AlertDialog.Builder(mContext).setTitle("Pick Account").setCancelable(true) .setPositiveButton("Add New", new OkOnClickListener()) .setNegativeButton("Cancel", new CancelOnClickListener()) .setAdapter(new ArrayAdapter<String>(mContext, android.R.layout.simple_list_item_1, name), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO: do we need this? // if(invalidate) // invalidateAuthToken(availableAccounts[which], authTokenType); // else // getExistingAccountAuthToken(availableAccounts[which], authTokenType); am.getAuthToken(availableAccounts[which], AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, null, mActivity, new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> future) { try { Bundle bundle = future.getResult(); String authtoken = bundle .getString(AccountManager.KEY_AUTHTOKEN); Log.v(TAG, " > showAccountPicker > getAuthToken from existing account: " + authtoken); callback.onSuccess(authtoken); } catch (OperationCanceledException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (AuthenticatorException e) { e.printStackTrace(); } } }, null); } }) .create(); mAlertDialog.show(); } } //showAccountPicker //Listeners for AccountPicker Dialog private final class CancelOnClickListener implements DialogInterface.OnClickListener { public void onClick(DialogInterface dialog, int which) { mAlertDialog.dismiss(); } } //for account picker private final class OkOnClickListener implements DialogInterface.OnClickListener { public void onClick(DialogInterface dialog, int which) { addNewAccount(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, new AuthCallback() { @Override public void onSuccess(String authtoken) { Log.d(TAG, " > showAccountPicker DialogInterface > addNewAccount, token received: " + authtoken); } }); } } //for account picker //AddNewAccount public void addNewAccount(String accountType, String authTokenType, final AuthCallback callback) { final AccountManagerFuture<Bundle> future = am.addAccount(accountType, authTokenType, null, null, mActivity, new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> future) { try { Bundle bnd = future.getResult(); //TODO: does this addAccountExplicitly //addSavedItemsToUserList(); Log.d(TAG, " > addNewAccount Bundle received: " + bnd); callback.onSuccess(bnd.getString(AccountManager.KEY_AUTHTOKEN)); } catch (Exception e) { //Log.d(TAG, e.getMessage()); Log.d(TAG, "addNewAccount > Error adding new account"); } } }, null); } //Helper for testing (TODO: remove in public releases) public void removeAccounts(final AuthCallback callback) { Account[] availableAccounts = am.getAccountsByType(AccountGeneral.ACCOUNT_TYPE); for (Account account : availableAccounts) { am.removeAccount(account, new AccountManagerCallback<Boolean>() { @Override public void run(AccountManagerFuture<Boolean> future) { Log.d(TAG, " > removeAccounts, accounts removed"); callback.onSuccess("removedAccounts"); } }, null); } } //removeAccounts (for testing) // -------------------------------------------------------- // LOG REQUESTS // -------------------------------------------------------- //LOG IN USER @Override public void userSignIn(final String email, final String pass, String authType, final AuthCallback callback) { if (!(RequestMethods.isNetworkAvailable(mContext))) { mMessageHelper.networkFailMessage(); return; } RequestQueue queue = Volley.newRequestQueue(mContext); String url = ApiConstants.LOGIN_USER; StringRequest userSignInRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() { @Override public void onResponse(String response) { //Get Response if (response == null || response.equals("null")) { Log.v("RESPONSE NULL HERE: ", response); mMessageHelper.showDialog(mContext, "YOU SHALL NOT PASS", "Sure you got your email/password combo right?"); } else { Log.v("RESPONSE FOR LOGIN: ", response); try { JSONObject res = new JSONObject(response); String sessionToken = res.getString(ApiConstants.USER_TOKEN); String userID = res.getString(ApiConstants.USER_ID); //Save userID in sharedPreferences Log.d(TAG, " > USER SIGN IN > setting userid: " + userID); mSharedPref.setUserID(userID); //Pass authtoken back to activity callback.onSuccess(sessionToken); } catch (JSONException e) { Log.v(TAG, e.getMessage()); //TODO: add proper error message mMessageHelper.showDialog(mContext, mContext.getString(R.string.login_error_exception_title), mContext.getString(R.string.login_error_exception_message)); } } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { mMessageHelper.showDialog(mContext, mContext.getString(R.string.login_error_title), mContext.getString(R.string.login_error_message)); } }) { @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<String, String>(); params.put("username", email); params.put(ApiConstants.USER_PASSWORD, pass); return params; } }; queue.add(userSignInRequest); } //userSignIn //TODO: SIGN UP USER @Override public void userSignUp(String email, String pass, String authType, final AuthCallback callback) throws Exception { if (!(RequestMethods.isNetworkAvailable(mContext))) { mMessageHelper.showDialog(mContext, mActivity.getString(R.string.error_network_title), mActivity.getString(R.string.error_network_message)); return; } //TODO: actually register user } // -------------------------------------------------------- // USER LIST REQUESTS // -------------------------------------------------------- //Add all list items to userlist (previously temp stored items) public void addSavedItemsToUserList() { Log.v(TAG, " > addSavedItemsToUserList, started"); JSONArray listItemPref; listItemPref = mSharedPref.getUserItemPreference(); try { if (listItemPref != null && listItemPref.length() > 0) { Log.v("LIST ITEM PREF: ", listItemPref.toString()); for (int i = 0; i < listItemPref.length(); i++) { Log.v("ITEMS", "ARE BEING ADDED"); addItemToUserList(listItemPref.getString(i)); } } } catch (JSONException e) { Log.d(TAG, "> addSavedItemsToUserList: " + e.getMessage()); } } //addSavedItemsToUserList //Add SINGLE random item to user list public void addItemToUserList(final String itemID) { if (!(RequestMethods.isNetworkAvailable(mContext))) { mMessageHelper.networkFailMessage(); return; } //Get sessionToken getToken(new AuthCallback() { @Override public void onSuccess(final String authtoken) { RequestQueue queue = Volley.newRequestQueue(mContext); String url = ApiConstants.ADD_ITEM + getUserID() + "/" + itemID; //Add single item to user list StringRequest postItemRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() { @Override public void onResponse(String response) { Log.v(TAG, "> addItemToUserList > OnResponse: " + response); Log.v(TAG, "AN ITEM IS BEING ADDED"); //TODO: on success remove the item from the sharedPreferences mSharedPref.deleteUserItemPreference(itemID); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { //TODO: Add not successful toast mMessageHelper.showDialog(mContext, mContext.getString(R.string.error_title), mContext.getString(R.string.error_message)); Log.d(TAG, " > addItemToUserList > onErrorResponse: " + error.getMessage()); } }) { @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<String, String>(); params.put(ApiConstants.USER_TOKEN, authtoken); return params; } }; queue.add(postItemRequest); } }); } //addItemToUserList //REMOVE SINGLE item from user list //TODO: move to RequestMethods + add callbacks public void removeItemFromUserList(final String itemID) { if (isTempUser()) { //If not logged in, remove item from sharedPreferences mSharedPref.deleteUserItemPreference(itemID); } else { //If logged in, remove from DB if (!(RequestMethods.isNetworkAvailable(mContext))) { mMessageHelper.showDialog(mContext, mActivity.getString(R.string.error_network_title), mActivity.getString(R.string.error_network_message)); return; } //Get sessionToken getToken(new AuthCallback() { @Override public void onSuccess(final String authtoken) { //getToken and then start request RequestQueue queue = Volley.newRequestQueue(mContext); String url = ApiConstants.REMOVE_ITEM + getUserID() + "/" + itemID; StringRequest deleteItemRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() { @Override public void onResponse(String response) { //get Response Log.v(TAG, "> removeItemFromUserList > OnResponse: " + response); Log.v(TAG, "AN ITEM IS BEING REMOVED"); //TODO: do something with response? } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.d(TAG, "> removeItemFromUserList > OnErrorResponse: " + error.getMessage()); mMessageHelper.showDialog(mContext, mContext.getString(R.string.error_title), "There was a problem deleting your item."); } }) { @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<String, String>(); params.put(ApiConstants.USER_TOKEN, authtoken); return params; } }; queue.add(deleteItemRequest); } }); } } //removeItemFromUserList } //ListUser