com.twolinessoftware.authentication.AuthenticationManager.java Source code

Java tutorial

Introduction

Here is the source code for com.twolinessoftware.authentication.AuthenticationManager.java

Source

/*
 * Copyright 2016 2LinesSoftware Inc
 * 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 com.twolinessoftware.authentication;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.OnAccountsUpdateListener;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;

import com.twolinessoftware.BaseApplication;
import com.twolinessoftware.Config;
import com.twolinessoftware.PreferencesHelper;

import org.joda.time.DateTime;

import java.util.concurrent.TimeUnit;

import javax.inject.Inject;

import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import timber.log.Timber;

/**
 *
 */
public class AuthenticationManager implements OnAccountsUpdateListener, AuthChangedListener {

    public static final String EXTRA_IS_ADDING = "EXTRA_IS_ADDING";
    public static final String KEY_ACCOUNT_PASSWORD = "KEY_PASSWORD";
    public static final String KEY_AUTH_TOKEN_EXPIRY = "KEY_AUTH_TOKEN_EXPIRY";

    private UserManager mUserManager;
    private PreferencesHelper mPreferencesHelper;
    private Context mContext;
    private AccountManager mAccountManager;

    @Inject
    public AuthenticationManager(Context context, AccountManager accountManager,
            PreferencesHelper preferencesHelper, UserManager userManager) {
        mContext = context;
        mAccountManager = accountManager;
        mPreferencesHelper = preferencesHelper;
        mUserManager = userManager;
    }

    /**
     * I wanted to make this static, but mocking the test is a nightmare.
     *
     * @param accessToken
     * @param username
     * @param password
     * @return
     */
    public Intent generateAuthIntent(Token accessToken, String username, String password) {
        Bundle data = new Bundle();
        data.putString(AccountManager.KEY_ACCOUNT_NAME, username);
        data.putString(AccountManager.KEY_ACCOUNT_TYPE, Config.BASE_ACCOUNT_TYPE);
        data.putString(AccountManager.KEY_AUTHTOKEN, accessToken.getAccessToken());
        data.putLong(AuthenticationManager.KEY_AUTH_TOKEN_EXPIRY, accessToken.getExpiresIn());
        data.putBoolean(AuthenticationManager.EXTRA_IS_ADDING, true);
        data.putString(AuthenticationManager.KEY_ACCOUNT_PASSWORD, password);

        return new Intent().putExtras(data);
    }

    public void completeLogin(Intent intent) {
        String accountName = intent.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);

        final Account account = new Account(accountName, Config.BASE_ACCOUNT_TYPE);

        String authtoken = intent.getStringExtra(AccountManager.KEY_AUTHTOKEN);

        String authtokenType = Config.BASE_ACCOUNT_TYPE;

        ContentResolver.setSyncAutomatically(account, Config.BASE_ACCOUNT_TYPE, true);
        ContentResolver.setIsSyncable(account, Config.BASE_ACCOUNT_TYPE, 1);

        mAccountManager.addAccountExplicitly(account, null, null);

        mAccountManager.setAuthToken(account, authtokenType, authtoken);

        String password = intent.getStringExtra(AuthenticationManager.KEY_ACCOUNT_PASSWORD);
        mAccountManager.setPassword(account, password);

        long expirySec = intent.getLongExtra(AuthenticationManager.KEY_AUTH_TOKEN_EXPIRY,
                TimeUnit.DAYS.toSeconds(1));

        DateTime expiry = DateTime.now().plusSeconds((int) expirySec);

        mAccountManager.setUserData(account, AuthenticationManager.KEY_AUTH_TOKEN_EXPIRY,
                String.valueOf(expiry.getMillis()));

        mUserManager.registerAuthListener(this);

    }

    public void backgroundLogout() {
        Timber.v("Logging out");

        BaseApplication application = BaseApplication.get(mContext);

        removeAccount().observeOn(Schedulers.newThread()).subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(pass -> {
                    mPreferencesHelper.clear();
                    Timber.v("Data Cleaned");
                    mUserManager.unregisterAuthListener(this);
                    mUserManager.logout();

                }, error -> {
                    Timber.e("Unable to logout:Cause:" + Log.getStackTraceString(error));
                    restartMainActivity(application);
                }, () -> restartMainActivity(application));
    }

    public void logout(Activity activity) {
        Timber.v("Logging out");

        removeAccount().observeOn(Schedulers.newThread()).subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(pass -> {
                    mPreferencesHelper.clear();
                    Timber.v("Data Cleaned");
                    mUserManager.unregisterAuthListener(this);
                    mUserManager.logout();

                }, error -> {
                    Timber.e("Unable to logout:Cause:" + Log.getStackTraceString(error));
                    activity.finish();
                    restartMainActivity(activity);
                }, () -> {
                    activity.finish();
                    restartMainActivity(activity);
                });
    }

    private void restartMainActivity(Context activity) {
        Timber.v("Restarting Main Activity");

        Intent i = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName());
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        activity.startActivity(i);
    }

    public void refreshAuthToken() {

        mAccountManager.getAuthToken(getAccount(), Config.BASE_ACCOUNT_TYPE, null, false, future -> {
            try {
                Bundle accountDetails = future.getResult();
                if (accountDetails.containsKey(AccountManager.KEY_INTENT)) {
                    // Credentials failed
                    Timber.v("Unable to login to get token");
                    backgroundLogout();
                }
            } catch (Exception e) {
                Timber.e("Unable to validate token:Not sure what to do:" + Log.getStackTraceString(e));
            }
        }, new Handler());
    }

    public String getAuthToken() {
        Account account = getAccount();
        if (account == null) {
            throw new AccountNotFoundException();
        }

        return mAccountManager.peekAuthToken(getAccount(), Config.BASE_ACCOUNT_TYPE);
    }

    public boolean isLoggedIn() {
        return getAccount() != null;
    }

    public Account getAccount() {
        Account[] accounts = mAccountManager.getAccountsByType(Config.BASE_ACCOUNT_TYPE);
        return accounts.length > 0 ? accounts[0] : null;
    }

    public Observable<Boolean> removeAccount() {
        Timber.v("Removing account");

        return Observable.create(new Observable.OnSubscribe<Boolean>() {
            @Override
            public void call(Subscriber<? super Boolean> subscriber) {
                Account account = getAccount();
                mAccountManager.invalidateAuthToken(Config.BASE_ACCOUNT_TYPE, getAuthToken());
                mAccountManager.removeAccount(account, future -> {
                    try {
                        if (future.getResult()) {
                            subscriber.onNext(true);
                            subscriber.onCompleted();
                        }
                    } catch (Exception e) {
                        subscriber.onError(e);
                    }
                }, null);
            }
        });

    }

    @Override
    public void onAccountsUpdated(Account[] accounts) {
    }

    @Override
    public void onLoggedOut() {
        Timber.v("Received Logout from provider, attempting to log back in");
        // Retry
        refreshAuthToken();

    }
}