package io.codetail.client.auth;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.NetworkErrorException;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import java.util.List;
import hugo.weaving.DebugLog;
import io.codetail.WatchMeApplication;
import io.codetail.sources.Source;
import static android.accounts.AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE;
import static android.accounts.AccountManager.KEY_ACCOUNT_NAME;
import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE;
import static android.accounts.AccountManager.KEY_AUTHTOKEN;
import static android.accounts.AccountManager.KEY_ERROR_CODE;
import static android.accounts.AccountManager.KEY_INTENT;
import static android.accounts.AccountManager.get;
import static io.codetail.fragments.NavigationFragment.USER_PICTURE_URL;
public class BasicAccountAuthenticator extends AbstractAccountAuthenticator{
public final static String ACCOUNT_TYPE = "codetail.auth.WATCH_ME";
public final static int ERROR_CODE_INVALID_USER_DATA = 100;
/**
* Given authTokenType is not found in {@link io.codetail.WatchMeApplication#getSources()}
*/
public final static int INVALID_AUTH_TOKEN_TYPE = 404;
/**
* Activity Action: Display form to authenticate user. Used by
* {@link android.accounts.AccountManager#addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback, android.os.Handler)}
* to authorize user into service
*/
public final static String ACTION_AUTHENTICATE = "codetail.intent.action.AUTHENTICATE";
/**
* Activity Action: Provide user to edit account properties. Used by
* {@link android.accounts.AccountManager#editProperties(String, android.app.Activity, android.accounts.AccountManagerCallback, android.os.Handler)}
*/
public final static String ACTION_EDIT_ACCOUNT_PROPERTIES = "codetail.intent.action.EDIT_ACCOUNT_PROPERTIES";
/**
* Activity Action: Let user check his credentials
*/
public final static String ACTION_CONFIRM_CREDENTIALS = "codetail.intent.action.CONFIRM_CREDENTIALS";
/**
* Parcelable data {@link android.accounts.Account}
*/
public final static String EXTRA_ACCOUNT = "codetail.intent.extra.ACCOUNT";
/**
* String data used with {@link #ACTION_AUTHENTICATE} contains authorize service name
*/
public final static String EXTRA_AUTH_TOKEN_TYPE = "codetail.intent.extra.AUTH_TOKEN_TYPE";
/**
* a String array of authenticator specific features that added account must support
* may be null
*/
public final static String EXTRA_REQUIRED_FEATURES = "codetail.intent.extra.REQUIRED_FEATURES";
AccountManager mAccountManager;
Bundle mExtras;
public BasicAccountAuthenticator(Context context) {
super(context);
mExtras = new Bundle();
mAccountManager = get(context);
}
@Override
@DebugLog
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
mExtras.clear();
mExtras.putParcelable(KEY_INTENT, new Intent(ACTION_EDIT_ACCOUNT_PROPERTIES));
return mExtras;
}
@Override
@DebugLog
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
mExtras.clear();
Intent intent = new Intent(ACTION_AUTHENTICATE)
.putExtra(KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
.putExtra(KEY_ACCOUNT_TYPE, accountType)
.putExtra(EXTRA_AUTH_TOKEN_TYPE, authTokenType)
.putExtra(EXTRA_REQUIRED_FEATURES, requiredFeatures)
.putExtras(options);
mExtras.putParcelable(KEY_INTENT, intent);
return mExtras;
}
@Override
@DebugLog
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
Intent intent = new Intent(ACTION_CONFIRM_CREDENTIALS)
.putExtra(EXTRA_ACCOUNT, account)
.putExtra(KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
.putExtras(options);
mExtras.clear();
mExtras.putParcelable(KEY_INTENT, intent);
return mExtras;
}
@Override
@DebugLog
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
mExtras.clear();
Source source = getSource(authTokenType);
if(source == null){
mExtras.putInt(KEY_ERROR_CODE, INVALID_AUTH_TOKEN_TYPE);
return mExtras;
}
AccountManager manager = mAccountManager;
String authToken = mAccountManager.peekAuthToken(account, authTokenType);
if(!source.isValidAuthToken(authToken)){
Bundle bundle = source.getAuthenticator().getAuthToken(manager, account);
authToken = bundle.getString(KEY_AUTHTOKEN);
if(bundle.containsKey(USER_PICTURE_URL)){
manager.setUserData(account, USER_PICTURE_URL, bundle.getString(USER_PICTURE_URL));
}
}
if(TextUtils.isEmpty(authToken)){
Intent intent = new Intent(ACTION_AUTHENTICATE)
.putExtra(EXTRA_ACCOUNT, account)
.putExtra(EXTRA_AUTH_TOKEN_TYPE, authTokenType)
.putExtra(KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
.putExtras(options);
mExtras.putParcelable(KEY_INTENT, intent);
}else{
mExtras.putString(KEY_AUTHTOKEN, authToken);
mExtras.putString(KEY_ACCOUNT_NAME, account.name);
mExtras.putString(KEY_ACCOUNT_TYPE, account.type);
mExtras.putString(EXTRA_AUTH_TOKEN_TYPE, authTokenType);
}
return mExtras;
}
@Override
@DebugLog
public String getAuthTokenLabel(String authTokenType) {
return getSource(authTokenType).getLabel();
}
@Override
@DebugLog
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
return null;
}
@Override
@DebugLog
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
return null;
}
Source getSource(String accountType){
List<Source> sources = WatchMeApplication.getApplication().getSources();
for(Source source: sources){
if(source.getSourceId().equals(accountType)){
return source;
}
}
return null;
}
}