package com.blandware.android.atleap.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 android.util.Log; /** * It is Account Authenticator. You can extend this class and register it in AndroidManifest.xml in the following way: * * <pre> * {@code * <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" /> * <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> * * <service android:name="com.youcompany.yourapp.authenticator.DefaultAuthenticatorService"> * <intent-filter> * <action android:name="android.accounts.AccountAuthenticator" /> * </intent-filter> * <meta-data * android:name="android.accounts.AccountAuthenticator" * android:resource="@xml/authenticator" /> * </service> * } * * </pre> * * the content of @xml/authenticator could looks like * * <pre> * {@code * <?xml version="1.0" encoding="utf-8"?> * <account-authenticator xmlns:android="http://schemas.android.com/apk/res/android" * android:accountType="com.youcompany.yourapp.account_type" * android:icon="@drawable/ic_launcher" * android:smallIcon="@drawable/ic_launcher" * android:label="@string/app_name" * /> * } * </pre> * * than you should create service * * <pre> * {@code * public class DefaultAuthenticatorService extends Service { * @Override * public IBinder onBind(Intent intent) { * DefaultAuthenticator authenticator = new DefaultAuthenticator(this); * return authenticator.getIBinder(); * } * } * </pre> */ public abstract class BaseAuthenticator extends AbstractAccountAuthenticator { private static final String TAG = BaseAuthenticator.class.getSimpleName(); private final Context mContext; public BaseAuthenticator(Context context) { super(context); this.mContext = context; } public Context getContext() { return mContext; } /** * This method should return instance of your login Activity which extends {@link com.blandware.android.atleap.auth.BaseAuthActivity}. * @return */ protected abstract Class<? extends BaseAuthActivity> getAuthActivityClass(); /** * {@inheritDoc} */ @Override public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { Log.v(TAG, "Adding account: type=" + accountType); return createAuthActivityIntentBundle(response, null, accountType, authTokenType, null, options); } protected Bundle createAccountManagerResult(Account account, String authToken) { Bundle result = new Bundle(); result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); result.putString(AccountManager.KEY_AUTHTOKEN, authToken); return result; } protected Bundle createAuthActivityIntentBundle(AccountAuthenticatorResponse response, String accountName, String accountType, String authTokenType, String password, Bundle options) { final Intent intent = createAuthActivityIntent(response, accountName, accountType, authTokenType, password, options); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } protected Intent createAuthActivityIntent(AccountAuthenticatorResponse response, String accountName, String accountType, String authTokenType, String password, Bundle options) { Intent intent = new Intent(mContext, getAuthActivityClass()); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); intent.putExtra(BaseAuthActivity.ARG_ACCOUNT_TYPE, accountType); intent.putExtra(BaseAuthActivity.ARG_AUTH_TOKEN_TYPE, authTokenType); intent.putExtra(BaseAuthActivity.ARG_ACCOUNT_NAME, accountName); intent.putExtra(BaseAuthActivity.ARG_PASSWORD, password); intent.putExtra(BaseAuthActivity.ARG_OPTIONS, options); return intent; } /** * {@inheritDoc} */ @Override public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { Log.v(TAG, "getAuthToken for account=" + account + " and tokenType=" + authTokenType); final AccountManager am = AccountManager.get(mContext); String authToken = am.peekAuthToken(account, authTokenType); if (!TextUtils.isEmpty(authToken)) { Log.v(TAG, "Auth token is in the cache. Retuning."); return createAccountManagerResult(account, authToken); } Log.v(TAG, "Trying to get password from cache"); final String password = am.getPassword(account); if (TextUtils.isEmpty(authToken)) { if (password != null) { Log.v(TAG, "Password is in cache. Trying to authenticate again."); try { authToken = authenticateOnServer(account, password, authTokenType, options, response); } catch (Exception e) { Log.w(TAG, "Cannot authenticate on the server", e); } } } if (!TextUtils.isEmpty(authToken)) { Log.v(TAG, "Auth token was received from the server"); return createAccountManagerResult(account, authToken); } Log.v(TAG, "Auth token was not received. Starting auth activity."); return createAuthActivityIntentBundle(response, account.name, account.type, authTokenType, password, options); } /** * Implement this method if you would like to re-authenticate automatically while getting authToken in case of the token * was invalidated. * Authentication will be with stored password. * * @param account account * @param password password * @param authTokenType authTokenType * @param options options * @param response response * @return authToken */ protected String authenticateOnServer(Account account, String password, String authTokenType, Bundle options, AccountAuthenticatorResponse response) { return null; } /** * {@inheritDoc} */ @Override public String getAuthTokenLabel(String authTokenType) { return authTokenType; } /** * {@inheritDoc} */ @Override public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, Account account) throws NetworkErrorException { Bundle result = new Bundle(); boolean allowed = true; result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, allowed); return result; } /** * {@inheritDoc} */ @Override public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { final Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); return result; } /** * {@inheritDoc} */ @Override public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { return null; } /** * {@inheritDoc} */ @Override public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { return null; } /** * {@inheritDoc} */ @Override public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { return createAuthActivityIntentBundle(response, account.name, account.type, authTokenType, null, options); } }