package com.gettingmobile.goodnews.account; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; import android.accounts.AccountManagerFuture; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; import android.util.Log; import com.gettingmobile.android.app.DialogFactory; import com.gettingmobile.android.app.actions.ActionContext; import com.gettingmobile.goodnews.Application; import com.gettingmobile.goodnews.R; public final class AccountManagerHandler extends AbstractAccountHandler { private static final String LOG_TAG = "goodnews.AccountManagerHandler"; protected static final String ACCOUNT_TYPE = AccountManagerHandler.class.getSimpleName(); private static final String MANAGED_ACCOUNT_TYPE = "com.google"; private static final String AUTH_TOKEN_TYPE = "reader"; private final AccountManager accountManager; private final AccountHandler credentialsAccountHandler; public AccountManagerHandler(Application app) { super(app); accountManager = AccountManager.get(app); credentialsAccountHandler = new CredentialsAccountHandler(app); } /* * login handling */ private Account[] getAccounts() { return accountManager.getAccountsByType(MANAGED_ACCOUNT_TYPE); } private Account getAccount() { final String accountName = getSettings().getAccountName(); if (accountName != null) { final Account[] accounts = getAccounts(); /* * check whether account does still exist */ for (Account account : accounts) { if (accountName.equals(account.name)) { return account; } } } /* * no account has been specified or the specified account is no long existing */ return null; } private boolean wasLastLoginWithCredentials() { final String lastLoginAccountType = getSettings().getAccountType(); return lastLoginAccountType != null && lastLoginAccountType.equals(CredentialsAccountHandler.ACCOUNT_TYPE); } @Override public boolean hasAccount() { return wasLastLoginWithCredentials() ? credentialsAccountHandler.hasAccount() : getAccount() != null; } @Override public void login(LoginCallback callback) { /* * check type of the last login */ if (wasLastLoginWithCredentials()) { /* * login using the credentials account manager */ Log.d(LOG_TAG, "Last login was done using credentials account handler. So forward request to this one."); credentialsAccountHandler.login(callback); } else { /* * get managed account used the last time */ Log.d(LOG_TAG, "Last login was done using account manager handler."); final Account account = getAccount(); if (account == null) throw new IllegalStateException("An account needs to be selected at first. Call promptAccount()."); authenticate(callback, account, null); } } private void authenticate(final LoginCallback loginCallback, Account account, Activity activity) { fireOnLoginStarted(loginCallback); if (!account.name.equals(getSettings().getAccountName())) { /* * we are changing the user, so lets swipe our data (tags and items, etc.) as it will not be valid for the * new user */ invalidateCache(); } invalidateSession(); getSettings().setAccountType(ACCOUNT_TYPE); getSettings().setAccountName(account.name); final AccountManagerCallback<Bundle> c = new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> result) { onAuthenticationFinished(loginCallback, result); } }; if (activity != null) { accountManager.getAuthToken(account, AUTH_TOKEN_TYPE, null, activity, c, null); } else { accountManager.getAuthToken(account, AUTH_TOKEN_TYPE, true, c, null); } } private void onAuthenticationFinished( final LoginCallback loginCallback, AccountManagerFuture<Bundle> result) { assert result.isDone(); try { final String authToken = result.getResult().getString(AccountManager.KEY_AUTHTOKEN); onAuthenticationFinished(loginCallback, null, authToken); } catch (Exception ex) { onAuthenticationFinished(loginCallback, ex, null); } } private void invalidateSession() { final String authToken = getSettings().getAuthToken(); if (authToken != null) { accountManager.invalidateAuthToken(MANAGED_ACCOUNT_TYPE, authToken); } getSettings().setAccountName(null); getApp().authenticate(null); } /* * prompt account handling */ @Override public void promptAccount(final ActionContext actionContext, final LoginCallback callback) { super.promptAccount(actionContext, callback); final Account[] accounts = getAccounts(); final String[] accountNames = new String[accounts.length + 2]; for (int i = 0; i < accounts.length; ++i) { accountNames[i] = accounts[i].name; } accountNames[accounts.length] = getString(R.string.account_create); accountNames[accounts.length + 1] = getString(R.string.account_manual); promptDialog = new AlertDialog.Builder(actionContext.getActivity()) .setTitle(R.string.account_select_title) .setItems(accountNames, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { onAccountSelection(actionContext, callback, dialog, accounts, which); } }).show(); promptDialog.setOwnerActivity(actionContext.getActivity()); } private void onAccountSelection(final ActionContext actionContext, final LoginCallback loginCallback, final DialogInterface dialog, Account[] accounts, int which) { DialogFactory.dismissDialogSafely(dialog); assert accounts != null; assert which >= 0 && which <= accounts.length; if (which < accounts.length) { if (wasLastLoginWithCredentials()) { invalidateCache(); } authenticate(loginCallback, accounts[which], actionContext.getActivity()); } else if (which == accounts.length) { final AccountManagerCallback<Bundle> c = new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> result) { onAccountCreationFinished(actionContext, loginCallback, result); } }; accountManager.addAccount(MANAGED_ACCOUNT_TYPE, AUTH_TOKEN_TYPE, null, null, actionContext.getActivity(), c, null); } else { if (!wasLastLoginWithCredentials()) { invalidateCache(); } credentialsAccountHandler.promptAccount(actionContext, loginCallback); } } private void onAccountCreationFinished(final ActionContext actionContext, LoginCallback loginCallback, AccountManagerFuture<Bundle> result) { assert result.isDone(); try { final Bundle b = result.getResult(); authenticate(loginCallback, new Account( b.getString(AccountManager.KEY_ACCOUNT_NAME), b.getString(AccountManager.KEY_ACCOUNT_TYPE)), actionContext.getActivity()); } catch (Exception ex) { promptAccount(actionContext, loginCallback); } } }