com.wit.and.dialog.LoginDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.wit.and.dialog.LoginDialog.java

Source

/*
 * =================================================================================
 * Copyright (C) 2013 Martin Albedinsky [Wolf-ITechnologies]
 * =================================================================================
 * Licensed under the Apache License, Version 2.0 or later (further "License" only);
 * ---------------------------------------------------------------------------------
 * You may use this file only in compliance with the License. More details and copy
 * of this License you may obtain at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 * You can redistribute, modify or publish any part of the code written in this
 * file but as it is described in the License, the software distributed under the 
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF
 * ANY KIND.
 * 
 * See the License for the specific language governing permissions and limitations
 * under the License.
 * =================================================================================
 */
package com.wit.and.dialog;

import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Parcel;
import android.support.v4.app.Fragment;
import android.text.InputType;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.wit.and.dialog.internal.widget.DialogDivider;
import com.wit.and.dialog.manage.DialogOptions;
import com.wit.and.style.styler.WidgetStyler;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <h4>Class Overview</h4>
 * <p>
 * Contains two {@link EditText}s for <i>user name</i> and <i>password</i> and loading
 * layout to show while authentication process is running.
 * </p>
 * <h3>Dialog styling:</h3>
 * <p>
 * This dialog implementation parses its style from main <b>dialogTheme</b>
 * where <b>loginDialogStyle</b> is obtained to apply styles to specific
 * view elements for login dialog.
 * </p>
 * 
 * @author Martin Albedinsky
 * @see Dialog
 */
public class LoginDialog extends Dialog implements ILoginDialog {

    /**
     * Constants =============================
     */

    /**
     * Log TAG.
     */
    private static final String TAG = LoginDialog.class.getSimpleName();

    /**
     * Indicates if debug private output trough log-cat is enabled.
     */
    private static final boolean DEBUG = false;

    /**
     * Indicates if logging for user output trough log-cat is enabled.
     */
    // private static final boolean USER_LOG = true;

    /**
     * <p>
     * Error due to invalid user name. User name doesn't match the reg-exp
     * pattern.
     * </p>
     */
    public static final int ERROR_INVALID_USER_NAME = 0x10;

    /**
     * <p>
     * Error due to invalid password. Password doesn't match the reg-exp
     * pattern.
     * </p>
     */
    public static final int ERROR_INVALID_PASSWORD = 0x11;

    /**
     * Bundle/Arguments identifiers.
     */

    /**
     */
    protected static final String BUNDLE_USERNAME = "com.wit.and.dialog.LoginDialog.Bundle.Username";
    protected static final String BUNDLE_USERNAME_PATTERN = "com.wit.and.dialog.LoginDialog.Bundle.Username.Matcher";
    protected static final String BUNDLE_PASSWORD = "com.wit.and.dialog.LoginDialog.Bundle.Password";
    protected static final String BUNDLE_PASSWORD_PATTERN = "com.wit.and.dialog.LoginDialog.Bundle.Password.Matcher";
    protected static final String BUNDLE_AUTHENTICATION_RUNNING = "com.wit.and.dialog.LoginDialog.Bundle.AuthenticationRunning";

    /**
     * Duration for show loading view animation.
     */
    private static final int ANIM_SHOW_DURATION = 500;

    /**
     * Duration for hide loading view animation.
     */
    private static final int ANIM_HIDE_DURATION = 200;

    /**
     * Enums =================================
     */

    /**
     * Static members ========================
     */

    /**
     * Members ===============================
     */

    /**
     * Animations.
     */
    /**
     */
    private final Animation.AnimationListener HIDE_LOADING_LISTENER = new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            mLoadingView.setVisibility(View.GONE);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    };
    private final Animation.AnimationListener HIDE_LOGIN_LISTENER = new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            mEditView.setVisibility(View.GONE);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    };

    private final Animation ANIM_SLIDE_UP_FROM_TOP = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT,
            0.0f, TranslateAnimation.RELATIVE_TO_PARENT, 0.0f, TranslateAnimation.RELATIVE_TO_PARENT, 0.0f,
            TranslateAnimation.RELATIVE_TO_PARENT, -1.0f);

    private final Animation ANIM_SLIDE_UP_FROM_BOTTOM = new TranslateAnimation(
            TranslateAnimation.RELATIVE_TO_PARENT, 0.0f, TranslateAnimation.RELATIVE_TO_PARENT, 0.0f,
            TranslateAnimation.RELATIVE_TO_PARENT, 1.0f, TranslateAnimation.RELATIVE_TO_PARENT, 0.0f);

    private final Animation ANIM_SLIDE_DOWN_FROM_TOP = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT,
            0.0f, TranslateAnimation.RELATIVE_TO_PARENT, 0.0f, TranslateAnimation.RELATIVE_TO_PARENT, -1.0f,
            TranslateAnimation.RELATIVE_TO_PARENT, 0.0f);

    private final Animation ANIM_SLIDE_DOWN_FROM_BOTTOM = new TranslateAnimation(
            TranslateAnimation.RELATIVE_TO_PARENT, 0.0f, TranslateAnimation.RELATIVE_TO_PARENT, 0.0f,
            TranslateAnimation.RELATIVE_TO_PARENT, 0.0f, TranslateAnimation.RELATIVE_TO_PARENT, 1.0f);

    /**
     * Widget stylers.
     */
    private final DialogDivider.DividerStyler DIVIDER_STYLER = new DialogDivider.DividerStyler(0);
    private final WidgetStyler.EditTextStyler EDIT_STYLER = new WidgetStyler.EditTextStyler(0);
    private final WidgetStyler.ProgressBarStyler PROGRESS_STYLER = new WidgetStyler.ProgressBarStyler(0);

    /**
    * Edit texts for user name and password input.
    */
    private EditText mUsername, mPassword;

    /**
     * Custom view below the edit texts.
     */
    private View mCustomView;

    /**
     * View with the progress bar and text view.
     */
    private View mLoadingView;

    /**
     * View with the edit texts and error text.
     */
    private View mEditView;

    /**
     * Edit text hints.
     */
    private String mUserHint, mPassHint;

    /**
      * Pattern for user name.
     */
    private Pattern mUserPattern = Pattern.compile("[a-zA-Z0-9\\+\\._%\\-\\+]{1,256}@"
            + "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" + "(\\.[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25})+");
    private Matcher mUserMatcher = mUserPattern.matcher("");

    /**
     * Pattern for password.
     */
    private Matcher mPassMatcher = null;

    /**
     * Current user credentials.
     */
    private Credentials mCredentials;

    /**
     * Listeners -----------------------------
     */

    /**
     * On login dialog listener.
     */
    private OnAuthenticationListener iListener = null;

    /**
     * Parent on login dialog listener.
     */
    private OnAuthenticationListener iParentListener = new OnAuthenticationListener() {

        @Override
        public void onAuthenticationError(int error, ILoginDialog loginDialog) {
        }

        @Override
        public void onAuthenticationSubmit(Credentials credentials, ILoginDialog loginDialog) {
        }
    };

    /**
     * Arrays --------------------------------
     */

    /**
     * Booleans ------------------------------
     */

    /**
     * Indicates if authentication is running.
     */
    private boolean bAuthRunning = false;

    /**
     * Constructors ==========================
     */

    /**
     * Methods ===============================
     */

    /**
     * Public --------------------------------
     */

    /**
     * <p>
     * Creates new instance of login dialog fragment.
     * </p>
     * 
      * @param loginOptions
      *          Specific dialog options for login dialog.
     * @return New instance of login dialog fragment.
     */
    public static LoginDialog newInstance(LoginOptions loginOptions) {
        final LoginDialog dialog = new LoginDialog();
        dialog.setCancelable(loginOptions.isCancelable());
        // Set up dialog arguments.
        dialog.setArguments(createArguments(loginOptions));
        return dialog;
    }

    /**
     * 
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Default hints.
        this.mUserHint = getString(R.string.And_Dialog_Edit_Hint_Username);
        this.mPassHint = getString(R.string.And_Dialog_Edit_Hint_Password);

        if (savedInstanceState == null) {
            LoginOptions options = getOptions();

            Bundle args = getArguments();
            if (args != null) {
                // Compile custom patterns.
                final String userRegExp = options.getUserRegExp();
                if (userRegExp != null) {
                    this.mUserPattern = Pattern.compile(userRegExp);
                }
                final String passRegExp = options.getPassRegExp();
                if (passRegExp == null) {
                    throw new IllegalArgumentException("Regular expression for password is required.");
                } else {
                    this.mUserMatcher = Pattern.compile(passRegExp).matcher("");
                }

                // Get hints.
                final String userHint = options.getUserHint();
                if (userHint != null) {
                    this.mUserHint = userHint;
                }
                final String passHint = options.getPassHint();
                if (passHint != null) {
                    this.mPassHint = passHint;
                }
            }
        }

        // Set-up animations.
        ANIM_SLIDE_UP_FROM_TOP.setAnimationListener(HIDE_LOADING_LISTENER);
        ANIM_SLIDE_DOWN_FROM_BOTTOM.setAnimationListener(HIDE_LOGIN_LISTENER);
        // Hide animations.
        ANIM_SLIDE_UP_FROM_TOP.setDuration(ANIM_HIDE_DURATION);
        ANIM_SLIDE_UP_FROM_BOTTOM.setDuration(ANIM_HIDE_DURATION);
        // Show animations.
        ANIM_SLIDE_DOWN_FROM_TOP.setDuration(ANIM_SHOW_DURATION);
        ANIM_SLIDE_DOWN_FROM_BOTTOM.setDuration(ANIM_SHOW_DURATION);
    }

    /**
     */
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This is handling dialog listener even when any listener was set, but
        // if this dialog was showed in the activity which is implementing
        // OnAuthenticationListener we invoke its methods.
        Fragment fragment = getCurrentFragment();

        // Resolve parent listener.
        boolean resolved = false;
        if (fragment != null) {
            if (fragment instanceof OnAuthenticationListener) {
                this.iParentListener = (OnAuthenticationListener) fragment;
                resolved = true;
            }
        }
        if (!resolved && activity != null) {
            if (activity instanceof OnAuthenticationListener) {
                this.iParentListener = (OnAuthenticationListener) activity;
            }
        }
    }

    /**
     * 
     */
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        // Save all data provided in the body view.
        if (mUsername != null && mPassword != null) {
            outState.putString(BUNDLE_USERNAME,
                    (mUsername.getText() == null) ? "" : mUsername.getText().toString());
            outState.putString(BUNDLE_PASSWORD,
                    (mPassword.getText() == null) ? "" : mPassword.getText().toString());
        }

        // Save patterns.
        outState.putSerializable(BUNDLE_USERNAME_PATTERN, mUserMatcher.pattern());
        outState.putSerializable(BUNDLE_PASSWORD_PATTERN, mPassMatcher.pattern());

        // Save if authentication is running.
        outState.putBoolean(BUNDLE_AUTHENTICATION_RUNNING, bAuthRunning);
    }

    /**
     */
    @Override
    public void setUsernameError(String errorText) {
        if (!this.isVisible())
            return;

        if (mUsername != null) {
            mUsername.setError(errorText);
        }

        // Hide loading.
        if (bAuthRunning) {
            this.hideLoading(true);
            this.bAuthRunning = false;
        }
    }

    /**
     */
    @Override
    public void setPasswordError(String errorText) {
        if (!this.isVisible())
            return;

        if (mPassword != null) {
            mPassword.setError(errorText);
        }

        // Hide loading.
        if (bAuthRunning) {
            this.hideLoading(true);
            this.bAuthRunning = false;
        }
    }

    /**
    * <p>
    * Sets the new message text visible in the dialog body (when the loading is
    * visible). Use this when you want dynamically change the message text.
    * Supported only when the dialog is visible.
    * </p>
    * 
    * @param message
     *          Message to show at the right side of progress bar.
    */
    public void setMessage(String message) {
        TextView text = (TextView) findViewByID(R.id.And_Dialog_TextView_Message);
        if (text != null && this.isVisible()) {
            text.setText(message);
        }
    }

    /**
     * <p>
     * Registers callback to be invoked when authentication is submitted or some
     * authentication error occurred.
     * </p>
     *
     * @param listener
     *          Listener callback.
     */
    public void setOnAuthenticationListener(OnAuthenticationListener listener) {
        this.iListener = listener;
    }

    /**
     * Getters + Setters ---------------------
     */

    /**
     */
    @Override
    public Credentials getCredentials() {
        return mCredentials;
    }

    /**
     */
    @Override
    public LoginOptions getOptions() {
        return (LoginOptions) super.getOptions();
    }

    /**
     * Protected -----------------------------
     */

    /**
     * 
     */
    @Override
    protected View onCreateBodyView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final Context context = inflater.getContext();

        RelativeLayout layout = new RelativeLayout(context);
        // Apply neutral layout params.
        layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));
        // Do not allow to apply style to body view.
        // layout.setId(R.id.Dialog_Layout_Body);

        // Create layout for loading view.
        LinearLayout loadingLayout = new LinearLayout(context);
        loadingLayout.setOrientation(LinearLayout.HORIZONTAL);
        loadingLayout.setGravity(Gravity.CENTER_VERTICAL);
        // Allow styling of loading layout as body layout.
        loadingLayout.setId(R.id.And_Dialog_Layout_Body);

        // Create text view for message.
        TextView msgTextView = new TextView(context);
        msgTextView.setId(R.id.And_Dialog_TextView_Message);

        // Create circle progress bar.
        ProgressBar circleProgressBar = new ProgressBar(context);
        circleProgressBar.setId(R.id.And_Dialog_ProgressBar);

        // Build loading view.
        loadingLayout.addView(circleProgressBar, new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
        loadingLayout.addView(msgTextView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));
        loadingLayout.setVisibility(View.GONE);

        // Insert loading layout into main body layout.
        RelativeLayout.LayoutParams loadingLayoutParams = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        loadingLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
        layout.addView(loadingLayout, loadingLayoutParams);

        // Create layout for edit texts.
        LinearLayout editLayout = new LinearLayout(context);
        editLayout.setOrientation(LinearLayout.VERTICAL);
        editLayout.setId(R.id.And_Dialog_Layout_LoginDialog_EditView);

        // Create edit texts for username and password.
        EditText userEdit = new EditText(context);
        userEdit.setId(R.id.And_Dialog_EditText_Username);
        userEdit.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
        EditText passEdit = new EditText(context);
        passEdit.setId(R.id.And_Dialog_EditText_Password);
        passEdit.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);

        // Create edit texts divider.
        DialogDivider divider = new DialogDivider(context);
        divider.setId(R.id.And_Dialog_Divider_LoginDialog_EditTexts);

        // Build edit layout.
        editLayout.addView(userEdit, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));
        editLayout.addView(divider, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));
        editLayout.addView(passEdit, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));

        // Add custom layout.
        View customView = onCreateCustomView(inflater, editLayout, savedInstanceState);
        if (customView != null) {
            editLayout.addView(this.mCustomView = customView);
        }

        // Insert edit layout into main body layout.
        RelativeLayout.LayoutParams editLayoutParams = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        editLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
        layout.addView(editLayout, editLayoutParams);

        return layout;
    }

    /**
     * <p>
     * Invoked to create view which will be placed below the edit texts in the
     * body view.
     * </p>
     * 
     * @param inflater
      *          Layout inflater.
     * @param container
      *          Layout with edit texts.
     * @param savedInstanceState
      *          Saved instance state.
     * @return Custom view.
     */
    protected View onCreateCustomView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return null;
    }

    /**
     */
    @Override
    protected void onInitViews(View dialogView) {
        super.onInitViews(dialogView);

        this.mUsername = (EditText) findViewByID(R.id.And_Dialog_EditText_Username);
        this.mPassword = (EditText) findViewByID(R.id.And_Dialog_EditText_Password);

        if (mPassword == null || mUsername == null) {
            throw new IllegalStateException("Missing required edit text for username or password.");
        }

        this.mEditView = dialogView.findViewById(R.id.And_Dialog_Layout_LoginDialog_EditView);
        this.mLoadingView = dialogView.findViewById(R.id.And_Dialog_Layout_Body);

        if (mEditView == null || mLoadingView == null) {
            throw new IllegalStateException(
                    "Missing required login main view or loading view in the LoginDialog body layout.");
        }
    }

    /**
     * 
     */
    @Override
    protected void onStyleDialog(View dialogView, TypedArray parsedArray) {
        final Context context = getActivity();

        final int loginDialogStyle = parsedArray.getResourceId(R.styleable.And_Theme_Dialog_loginDialogStyle,
                R.style.And_Dialog_LoginDialog);
        final TypedArray dialogArray = context.obtainStyledAttributes(loginDialogStyle,
                R.styleable.And_Theme_Dialog_LoginDialog);
        if (dialogArray != null) {
            final int n = dialogArray.getIndexCount();
            for (int i = 0; i < n; i++) {
                int attr = dialogArray.getIndex(i);
                /**
                 * Obtain login dialog sub-dialog style.
                 */
                if (attr == R.styleable.And_Theme_Dialog_LoginDialog_dialogStyle) {
                    /**
                     * Let super to process login dialog sub-dialog style.
                     */
                    super.onStyleDialog(dialogView, dialogArray.getResourceId(attr, R.style.And_Dialog_Dialog));
                }
                // Set up login dialog edit texts divider style.
                else if (attr == R.styleable.And_Theme_Dialog_LoginDialog_dialogDividerStyle) {
                    final DialogDivider divider = (DialogDivider) findViewByID(
                            R.id.And_Dialog_Divider_LoginDialog_EditTexts);
                    if (divider != null) {
                        DIVIDER_STYLER.performStyling(
                                dialogArray.getResourceId(attr, R.style.And_Dialog_Divider_EditText), divider);
                        // Remove any custom orientation, only horizontal divider is allowed.
                        divider.setOrientation(DialogDivider.HORIZONTAL);
                    }
                }
                /**
                 * Set up login dialog edit style.
                 */
                else if (attr == R.styleable.And_Theme_Dialog_LoginDialog_android_editTextStyle) {
                    final int editStyle = dialogArray.getResourceId(attr, R.style.And_Dialog_EditText);
                    EDIT_STYLER.performStyling(editStyle, mUsername);
                    EDIT_STYLER.performStyling(editStyle, mPassword);
                }
                /**
                 * Set up empty circle progress bar style.
                 */
                else if (attr == R.styleable.And_Theme_Dialog_LoginDialog_android_progressBarStyle) {
                    final ProgressBar progressBar = (ProgressBar) findViewByID(R.id.And_Dialog_ProgressBar);
                    if (progressBar != null) {
                        PROGRESS_STYLER.performStyling(
                                dialogArray.getResourceId(attr, R.style.And_Dialog_ProgressBar), progressBar);
                    }
                }
            }
            dialogArray.recycle();
        }

        /**
         * Set type face to text views.
         */
        Typeface typeface = obtainTypeface(loginDialogStyle);
        if (typeface != null) {
            applyTypeface(typeface, mUsername);
            applyTypeface(typeface, mPassword);
        }
    }

    /**
    * 
    */
    @Override
    protected void onBindDialog(View dialogView, Bundle bundle) {
        super.onBindDialog(dialogView, bundle);

        // Set up edit texts hint.
        mUsername.setHint(mUserHint);
        mPassword.setHint(mPassHint);

        // Restore body data.
        if (bundle != null) {
            final String userText = bundle.getString(BUNDLE_USERNAME);
            final String passText = bundle.getString(BUNDLE_PASSWORD);

            if (userText != null && userText.length() != 0) {
                mUsername.setText(userText);
            }
            if (passText != null && passText.length() != 0) {
                mPassword.setText(passText);
            }

            this.mCredentials = new Credentials(userText, passText);
        }

        if (bAuthRunning) {
            this.showLoading(false);
        } else {
            this.hideLoading(false);
        }
    }

    /**
     * 
     */
    @Override
    protected void onButtonClick(final DialogButton button) {
        super.onButtonClick(button);

        switch (button) {
        case POSITIVE:
        case NEUTRAL:
            onCheckData();
            break;
        default:
        }
    }

    /**
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);

        // Restore hints.
        this.mUserHint = getOptions().getUserHint();
        this.mPassHint = getOptions().getPassHint();

        // Restore patterns.
        this.mUserMatcher = ((Pattern) savedInstanceState.getSerializable(BUNDLE_USERNAME_PATTERN)).matcher("");
        this.mPassMatcher = ((Pattern) savedInstanceState.getSerializable(BUNDLE_PASSWORD_PATTERN)).matcher("");

        this.bAuthRunning = savedInstanceState.getBoolean(BUNDLE_AUTHENTICATION_RUNNING, false);
    }

    /**
     * <p>
     * Invoked to check user's entered data. If check succeed the authentication
     * process will be started otherwise listener's callback
     * <code>onAuthenticationError()</code> will be invoked.
     * </p>
     */
    protected void onCheckData() {
        boolean ok;

        // Obtain data from edit texts.
        final String user = (mUsername.getText() == null) ? "" : mUsername.getText().toString();
        final String pass = (mPassword.getText() == null) ? "" : mPassword.getText().toString();

        if (DEBUG)
            Log.d(TAG, "onCheckData() user('" + user + "'), pass('" + pass + "')");

        // Clear errors.
        mUsername.setError(null);
        mPassword.setError(null);

        // Check user name.
        if (!(ok = mUserMatcher.reset(user).matches())) {
            this.invokeError(ERROR_INVALID_USER_NAME);
        }

        if (DEBUG)
            Log.d(TAG, "onCheckData() userMatches(" + ok + ") with('" + mUserPattern.pattern() + "')");

        // Check password.
        boolean userError = ok;
        if (!(ok = mPassMatcher.reset(pass).matches())) {
            this.invokeError(ERROR_INVALID_PASSWORD);
        }
        if (DEBUG)
            Log.d(TAG, "onCheckData() passMatches(" + ok + ") with('" + mUserPattern.pattern() + "')");

        if (userError && ok) {
            this.startAuthentication(mCredentials = new Credentials(user, pass));
        }
    }

    /**
     * <p>
     * Hides the soft keyboard using token of the given focused view.
     * </p>
     *
     * @param focusedView
     *            The view which currently has focus.
     * @return True if hiding was successful otherwise false.
     */
    protected synchronized boolean hideSoftKeyboard(View focusedView) {
        // Check valid view
        if (focusedView == null || focusedView.getContext() == null)
            return false;

        // Get input method manager.
        InputMethodManager imm = (InputMethodManager) focusedView.getContext()
                .getSystemService(Context.INPUT_METHOD_SERVICE);

        // Now hide Keyboard from screen.
        imm.hideSoftInputFromWindow(focusedView.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);

        // Success.
        return true;
    }

    /**
     * <p>
     * Returns custom view placed in the edit layout below both edit texts.
     * </p>
     * 
     * @return Custom view created in
      *         {@link #onCreateButtonsView(Dialog.Buttons, android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)}.
     */
    protected View getCustomView() {
        return mCustomView;
    }

    /**
     * <p>
     * Starts the authentication process. Shows loading view and invoke
     * listener's callback <code>onAuthenticationSubmit()</code>.
     * </p>
     * 
     * @param credentials
     *            Current credentials from the edit texts.
     */
    protected final void startAuthentication(Credentials credentials) {
        // Perform only if the authentication isn't already running.
        if (!bAuthRunning) {
            this.bAuthRunning = true;
            this.showLoading(true);

            // Invoke listeners.
            if (iListener != null) {
                iListener.onAuthenticationSubmit(credentials, this);
            }
            iParentListener.onAuthenticationSubmit(credentials, this);
        }
    }

    /**
     * Private -------------------------------
     */

    /**
     * Invokes callback to listeners that error with given code occur.
     * 
     * @param errorCode
      *          Code of error.
     */
    private void invokeError(int errorCode) {
        if (DEBUG)
            Log.d(TAG, "invokeError(" + errorCode + ") listener(" + iListener + "), parentListener("
                    + iParentListener + ")");

        if (iListener != null) {
            iListener.onAuthenticationError(errorCode, this);
        }
        iParentListener.onAuthenticationError(errorCode, this);

    }

    /**
     * Shows the view with the progress bar and hides the main edit view.
     * 
     * @param animated
      *          <code>True</code> if showing should be animated, <code>false</code> otherwise.
     */
    private void showLoading(boolean animated) {
        // Perform only if the loading view isn't already visible.
        if (mLoadingView.getVisibility() == View.VISIBLE)
            return;

        // Don't allow to dismiss dialog.
        setCancelable(false);

        // Hide keyboard.
        View focusedView = null;
        if (mUsername.hasFocus()) {
            focusedView = mUsername;
        } else if (mPassword.hasFocus()) {
            focusedView = mPassword;
        }
        hideSoftKeyboard(focusedView);

        mLoadingView.setVisibility(View.VISIBLE);
        if (animated) {
            mLoadingView.startAnimation(ANIM_SLIDE_DOWN_FROM_TOP);
            mEditView.startAnimation(ANIM_SLIDE_DOWN_FROM_BOTTOM);
        } else {
            mEditView.setVisibility(View.GONE);
        }

        // Hide buttons view.
        View buttons = findViewByID(R.id.And_Dialog_Layout_Buttons);
        if (buttons != null) {
            buttons.setVisibility(View.GONE);
        }
    }

    /**
     * Hides the view with the progress bar and shows the main login view.
     * 
     * @param animated
      *          <code>True</code> if hiding should be animated, <code>false</code> otherwise.
     */
    private void hideLoading(boolean animated) {
        View loading = this.mLoadingView;
        View login = this.mEditView;
        View buttons = findViewByID(R.id.And_Dialog_Layout_Buttons);

        // Perform only if the loading view isn't already hided.
        if (loading.getVisibility() != View.VISIBLE)
            return;

        // Allow to dismiss dialog.
        setCancelable(true);

        login.setVisibility(View.VISIBLE);
        if (animated) {
            loading.startAnimation(ANIM_SLIDE_UP_FROM_TOP);
            login.startAnimation(ANIM_SLIDE_UP_FROM_BOTTOM);
        } else {
            loading.setVisibility(View.GONE);
        }

        // Show buttons view.
        if (buttons != null) {
            buttons.setVisibility(View.VISIBLE);
        }
    }

    /**
     * Abstract methods ----------------------
     */

    /**
     * Inner classes =========================
     */

    /**
     * <h4>Class Overview</h4>
     * <p>
     * Specific dialog options for {@link LoginDialog}.
     * </p>
     *
     * @author Martin Albedinsky
     * @see LoginDialog
     * @see DialogOptions
     */
    public static class LoginOptions extends DialogOptions<LoginOptions> {

        /**
         * Members ===============================
         */

        /**
         * Edit hints.
         */
        String userHint, passHint;

        /**
         * Regular expressions.
         */
        String userRegExp, passRegExp;

        /**
         * Constructors ==========================
         */

        /**
         * <p>
         * Same as {@link com.wit.and.dialog.manage.DialogOptions#DialogOptions()}.
         * </p>
         */
        public LoginOptions() {
            super();
        }

        /**
         * <p>
         * Same as {@link com.wit.and.dialog.manage.DialogOptions#DialogOptions(android.content.res.Resources)}.
         * </p>
         *
         * @param resources
         */
        public LoginOptions(Resources resources) {
            super(resources);
        }

        /**
         * <p>
         * Same as {@link com.wit.and.dialog.manage.DialogOptions#DialogOptions(android.os.Parcel)}.
         * </p>
         *
         * @param input
         */
        protected LoginOptions(Parcel input) {
            super(input);
            this.userHint = input.readString();
            this.passHint = input.readString();
            this.userRegExp = input.readString();
            this.passRegExp = input.readString();
        }

        /**
         * Methods ===============================
         */

        /**
         * Public --------------------------------
         */

        /**
         */
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeString(userHint);
            dest.writeString(passHint);
            dest.writeString(userRegExp);
            dest.writeString(passRegExp);
        }

        /**
         * Getters + Setters ---------------------
         */

        /**
         * <p>
         * </p>
         *
         * @param hintRes
         * @return
         * @throws java.lang.NullPointerException
         */
        public LoginOptions userHint(int hintRes) {
            return userHint(getString(hintRes));
        }

        /**
         * <p>
         * Sets text which will be visible as hint in the edit text for username.
         * </p>
         *
         * @param hint
         *          Hint text.
         * @return This options.
         */
        public LoginOptions userHint(String hint) {
            this.userHint = hint;
            return this;
        }

        /**
         * <p>
         * </p>
         *
         * @return
         */
        public String getUserHint() {
            return userHint;
        }

        /**
         * <p>
         * </p>
         *
         * @param regExpRes
         * @return This options.
         * @throws java.lang.NullPointerException
         */
        public LoginOptions userRegExp(int regExpRes) {
            return userRegExp(getString(regExpRes));
        }

        /**
         * <p>
         * Sets regular expression which will be used to validation of entered
         * value inside the edit text for username.
         * </p>
         *
         * @param regExp
         *          Valid regular expression.
         * @return This options.
         */
        public LoginOptions userRegExp(String regExp) {
            this.userRegExp = regExp;
            return this;
        }

        /**
         * <p>
         * </p>
         *
         * @return
         */
        public String getUserRegExp() {
            return userRegExp;
        }

        /**
         * <p>
         * </p>
         *
         * @param hintRes
         * @return This options.
         * @throws java.lang.NullPointerException
         */
        public LoginOptions passHint(int hintRes) {
            return passHint(getString(hintRes));
        }

        /**
         * <p>
         * Sets text which will be visible as hint in the edit text for password.
         * </p>
         *
         * @param hint
         *          Hint text.
         * @return This options.
         */
        public LoginOptions passHint(String hint) {
            this.passHint = hint;
            return this;
        }

        /**
         * <p>
         * </p>
         *
         * @return
         */
        public String getPassHint() {
            return passHint;
        }

        /**
         * <p>
         * </p>
         *
         * @param regExpRes
         * @return This options.
         * @throws java.lang.NullPointerException
         */
        public LoginOptions passRegExp(int regExpRes) {
            return passRegExp(getString(regExpRes));
        }

        /**
         * <p>
         * Sets regular expression which will be used to validation of entered
         * value inside the edit text for password.
         * </p>
         *
         * @param regExp
         *          Valid regular expression.
         * @return This options.
         */
        public LoginOptions passRegExp(String regExp) {
            this.passRegExp = regExp;
            return this;
        }

        /**
         * <p>
         * </p>
         *
         * @return
         */
        public String getPassRegExp() {
            return passRegExp;
        }
    }

    /**
     * Interface =============================
     */
}