com.rukman.emde.smsgroups.authenticator.GMSAuthenticatorActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.rukman.emde.smsgroups.authenticator.GMSAuthenticatorActivity.java

Source

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * 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.rukman.emde.smsgroups.authenticator;

import org.json.JSONObject;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.ContentResolver;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.rukman.emde.smsgroups.GMSApplication;
import com.rukman.emde.smsgroups.R;
import com.rukman.emde.smsgroups.client.NetworkUtilities;
import com.rukman.emde.smsgroups.data.GMSProvider;
import com.rukman.emde.smsgroups.fragments.ProgressDialogFragment;

/**
 * Activity which displays login screen to the user.
 */
public class GMSAuthenticatorActivity extends AccountAuthenticatorFragmentActivity {
    /** The Intent flag to confirm credentials. */
    public static final String PARAM_CONFIRM_CREDENTIALS = "confirmCredentials";

    /** The Intent extra to store password. */
    public static final String PARAM_PASSWORD = "password";

    /** The Intent extra to store username. */
    public static final String PARAM_USERNAME = "username";

    /** The Intent extra to store password. */
    public static final String PARAM_EMAIL = "email";

    /** The Intent extra to store username. */
    public static final String PARAM_PHONE = "phone";

    /** The Intent extra to store authtoken type. */
    public static final String PARAM_AUTHTOKEN_TYPE = "authtokenType";

    /** The tag used to log to adb console. */
    private static final String TAG = "AuthenticatorActivity";
    private AccountManager mAccountManager;

    /** Keep track of the login task so can cancel it if requested */
    private AsyncTask<Void, Void, String> mAuthTask = null;

    /**
     * If set we are just checking that the user knows their credentials; this
     * doesn't cause the user's password or authToken to be changed on the
     * device.
     */
    private Boolean mConfirmCredentials = false;

    private TextView mMessage;

    private EditText mPasswordEdit;

    /** Was the original caller did not know the user name */
    protected boolean mIsUnknownAccountName = false;

    private String mUsername;

    private String mPassword;

    private String mEmail;

    private String mPhone;

    private EditText mUsernameEdit;

    private EditText mEmailEdit;

    private EditText mPhoneEdit;

    private static final String PROGRESS = "authenticating_progress";

    /**
     * {@inheritDoc}
     */
    @Override
    public void onCreate(Bundle icicle) {

        Log.i(TAG, "onCreate(" + icicle + ")");
        super.onCreate(icicle);
        mAccountManager = AccountManager.get(this);
        Log.i(TAG, "loading data from Intent");
        final Intent intent = getIntent();
        mUsername = intent.getStringExtra(PARAM_USERNAME);
        mIsUnknownAccountName = mUsername == null;
        mConfirmCredentials = intent.getBooleanExtra(PARAM_CONFIRM_CREDENTIALS, false);
        Log.i(TAG, "IsUnknownAccount? : " + mIsUnknownAccountName);
        requestWindowFeature(Window.FEATURE_LEFT_ICON);
        setContentView(R.layout.login_activity);
        getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, android.R.drawable.ic_dialog_alert);
        mMessage = (TextView) findViewById(R.id.message);
        mUsernameEdit = (EditText) findViewById(R.id.username_edit);
        mPasswordEdit = (EditText) findViewById(R.id.password_edit);
        mEmailEdit = (EditText) findViewById(R.id.email_edit);
        mPhoneEdit = (EditText) findViewById(R.id.phone_edit);
        ((CheckBox) findViewById(R.id.new_account_box)).setOnCheckedChangeListener(new OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                findViewById(R.id.registration_layout).setVisibility(isChecked ? View.VISIBLE : View.GONE);
            }

        });
        if (!TextUtils.isEmpty(mUsername)) {
            mUsernameEdit.setText(mUsername);
        }
        mMessage.setText(getMessage());
    }

    /**
     * Handles onClick event on the Submit button. Sends username/password to
     * the server for authentication. The button is configured to call
     * handleLogin() in the layout XML.
     *
     * @param view The Submit button for which this method is invoked
     */
    public void handleLogin(View view) {
        if (mIsUnknownAccountName) {
            mUsername = mUsernameEdit.getText().toString();
        }
        mEmail = mEmailEdit.getText().toString();
        mPhone = mPhoneEdit.getText().toString();
        mPassword = mPasswordEdit.getText().toString();
        // Simple validation
        if (((CheckBox) findViewById(R.id.new_account_box)).isChecked()) {
            // Check all the fields
            if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword) || TextUtils.isEmpty(mEmail)
                    || TextUtils.isEmpty(mPhone)) {
                mMessage.setText(getMessage());
            } else {
                // Show a progress dialog, and kick off a background task to perform
                // the user login attempt.
                showProgress();
                mAuthTask = new UserRegistrationTask();
                mAuthTask.execute();
            }
        } else {
            if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword)) {
                mMessage.setText(getMessage());
            } else {
                // Show a progress dialog, and kick off a background task to perform
                // the user login attempt.
                showProgress();
                mAuthTask = new UserLoginTask();
                mAuthTask.execute();
            }
        }
    }

    /**
     * Called when response is received from the server for confirm credentials
     * request. See onAuthenticationResult(). Sets the
     * AccountAuthenticatorResult which is sent back to the caller.
     *
     * @param result the confirmCredentials result.
     */
    private void finishConfirmCredentials(boolean result) {
        Log.i(TAG, "finishConfirmCredentials()");
        final Account account = new Account(mUsername, GMSApplication.ACCOUNT_TYPE);
        mAccountManager.setPassword(account, mPassword);
        final Intent intent = new Intent();
        intent.putExtra(AccountManager.KEY_BOOLEAN_RESULT, result);
        setAccountAuthenticatorResult(intent.getExtras());
        setResult(RESULT_OK, intent);
        finish();
    }

    /**
     * Called when response is received from the server for authentication
     * request. See onAuthenticationResult(). Sets the
     * AccountAuthenticatorResult which is sent back to the caller. We store the
     * authToken that's returned from the server as the 'password' for this
     * account - so we're never storing the user's actual password locally.
     *
     * @param result the confirmCredentials result.
     */
    private void finishLogin(String authToken) {

        Log.i(TAG, "finishLogin()");
        final Account account = new Account(mUsername, GMSApplication.ACCOUNT_TYPE);
        if (mIsUnknownAccountName) {
            mAccountManager.addAccountExplicitly(account, mPassword, null);
            // Set contacts sync for this account.
            ContentResolver.setIsSyncable(account, GMSProvider.AUTHORITY, 1);
            ContentResolver.setSyncAutomatically(account, GMSProvider.AUTHORITY, true);
        } else {
            mAccountManager.setPassword(account, mPassword);
        }
        final Intent intent = new Intent();
        intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername);
        intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, GMSApplication.ACCOUNT_TYPE);
        setAccountAuthenticatorResult(intent.getExtras());
        setResult(RESULT_OK, intent);
        finish();
    }

    /**
     * Called when the authentication process completes (see attemptLogin()).
     *
     * @param authToken the authentication token returned by the server, or NULL if
     *            authentication failed.
     */
    public void onAuthenticationResult(String authToken) {

        boolean success = ((authToken != null) && (authToken.length() > 0));
        Log.i(TAG, "onAuthenticationResult(" + success + ")");

        // Our task is complete, so clear it out
        mAuthTask = null;

        // Hide the progress dialog
        hideProgress();

        if (success) {
            if (!mConfirmCredentials) {
                finishLogin(authToken);
            } else {
                finishConfirmCredentials(success);
            }
        } else {
            Log.e(TAG, "onAuthenticationResult: failed to authenticate");
            if (mIsUnknownAccountName) {
                // "Please enter a valid username/password.
                mMessage.setText(getText(R.string.login_activity_loginfail_text_both));
            } else {
                // "Please enter a valid password." (Used when the
                // account is already in the database but the password
                // doesn't work.)
                mMessage.setText(getText(R.string.login_activity_loginfail_text_pwonly));
            }
        }
    }

    public void onAuthenticationCancel() {
        Log.i(TAG, "onAuthenticationCancel()");

        // Our task is complete, so clear it out
        mAuthTask = null;

        // Hide the progress dialog
        hideProgress();
    }

    /**
     * Returns the message to be displayed at the top of the login dialog box.
     */
    private CharSequence getMessage() {
        getString(R.string.label);
        if (TextUtils.isEmpty(mUsername)) {
            // If no username, then we ask the user to log in using an
            // appropriate service.
            final CharSequence msg = getText(R.string.login_activity_newaccount_text);
            return msg;
        }
        if (TextUtils.isEmpty(mPassword)) {
            // We have an account but no password
            return getText(R.string.login_activity_loginfail_text_pwmissing);
        }
        return null;
    }

    /**
     * Shows the progress UI for a lengthy operation.
     */
    private void showProgress() {
        final ProgressDialogFragment dialog = ProgressDialogFragment
                .newInstance(R.string.ui_activity_authenticating, R.string.ui_activity_authenticating);
        dialog.show(getSupportFragmentManager(), PROGRESS);
    }

    /**
     * Hides the progress UI for a lengthy operation.
     */
    private void hideProgress() {
        DialogFragment dialog = (DialogFragment) getSupportFragmentManager().findFragmentByTag(PROGRESS);
        if (dialog != null) {
            dialog.dismiss();
        }
    }

    /**
     * Called when the authentication process completes (see attemptLogin()).
     *
     * @param authToken the authentication token returned by the server, or NULL if
     *            authentication failed.
     */
    public void onRegistrationResult(JSONObject object) {
        // Our task is complete, so clear it out
        mAuthTask = null;

        // Hide the progress dialog
        hideProgress();

        if (object != null) {
            Log.e(TAG, "onRegistrationResult: Registration succeeded");
            Toast.makeText(this, R.string.login_activity_registration_success_text, Toast.LENGTH_SHORT).show();
        } else {
            Log.e(TAG, "onRegistrationResult: failed register");
            mMessage.setText(getText(R.string.login_activity_registration_fail_text));
        }
    }

    public void onRegistrationCancel() {
        Log.i(TAG, "onAuthenticationCancel()");

        // Our task is complete, so clear it out
        mAuthTask = null;

        // Hide the progress dialog
        hideProgress();
    }

    /**
     * Represents an asynchronous task used to register a user with the GMS service
     */
    private class UserRegistrationTask extends AsyncTask<Void, Void, String> {

        @Override
        protected String doInBackground(Void... params) {
            String result = null;
            try {
                result = NetworkUtilities.register(mUsername, mPassword, mEmail, mPhone);
                if (result != null) {
                    result = NetworkUtilities.authenticate(mUsername, mPassword);
                }
            } catch (Exception ex) {
                Log.e(TAG, "UserRegistrationTask.doInBackground: Failure in network layer");
                Log.i(TAG, ex.toString());
            }
            return result;
        }

        @Override
        protected void onPostExecute(final String authToken) {
            // On a successful authentication, call back into the Activity to
            // communicate the authToken (or null for an error).
            onAuthenticationResult(authToken);
        }

        @Override
        protected void onCancelled() {
            // If the action was canceled (by the user clicking the cancel
            // button in the progress dialog), then call back into the
            // activity to let it know.
            onAuthenticationCancel();
        }
    }

    /**
     * Represents an asynchronous task used to authenticate a user against the
     * SampleSync Service
     */
    public class UserLoginTask extends AsyncTask<Void, Void, String> {

        @Override
        protected String doInBackground(Void... params) {
            // We do the actual work of authenticating the user
            // in the NetworkUtilities class.
            try {
                return NetworkUtilities.authenticate(mUsername, mPassword);
            } catch (Exception ex) {
                Log.e(TAG, "UserLoginTask.doInBackground: failed to authenticate");
                Log.i(TAG, ex.toString());
                return null;
            }
        }

        @Override
        protected void onPostExecute(final String authToken) {
            // On a successful authentication, call back into the Activity to
            // communicate the authToken (or null for an error).
            onAuthenticationResult(authToken);
        }

        @Override
        protected void onCancelled() {
            // If the action was canceled (by the user clicking the cancel
            // button in the progress dialog), then call back into the
            // activity to let it know.
            onAuthenticationCancel();
        }
    }
}