Home | History | Annotate | Download | only in authenticator
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package com.example.android.samplesync.authenticator;
     18 
     19 import android.accounts.Account;
     20 import android.accounts.AccountAuthenticatorActivity;
     21 import android.accounts.AccountManager;
     22 import android.app.Dialog;
     23 import android.app.ProgressDialog;
     24 import android.content.ContentResolver;
     25 import android.content.DialogInterface;
     26 import android.content.Intent;
     27 import android.os.Bundle;
     28 import android.os.Handler;
     29 import android.provider.ContactsContract;
     30 import android.text.TextUtils;
     31 import android.util.Log;
     32 import android.view.View;
     33 import android.view.Window;
     34 import android.widget.EditText;
     35 import android.widget.TextView;
     36 
     37 import com.example.android.samplesync.Constants;
     38 import com.example.android.samplesync.R;
     39 import com.example.android.samplesync.client.NetworkUtilities;
     40 
     41 /**
     42  * Activity which displays login screen to the user.
     43  */
     44 public class AuthenticatorActivity extends AccountAuthenticatorActivity {
     45     public static final String PARAM_CONFIRMCREDENTIALS = "confirmCredentials";
     46     public static final String PARAM_PASSWORD = "password";
     47     public static final String PARAM_USERNAME = "username";
     48     public static final String PARAM_AUTHTOKEN_TYPE = "authtokenType";
     49 
     50     private static final String TAG = "AuthenticatorActivity";
     51 
     52     private AccountManager mAccountManager;
     53     private Thread mAuthThread;
     54     private String mAuthtoken;
     55     private String mAuthtokenType;
     56 
     57     /**
     58      * If set we are just checking that the user knows their credentials; this
     59      * doesn't cause the user's password to be changed on the device.
     60      */
     61     private Boolean mConfirmCredentials = false;
     62 
     63     /** for posting authentication attempts back to UI thread */
     64     private final Handler mHandler = new Handler();
     65     private TextView mMessage;
     66     private String mPassword;
     67     private EditText mPasswordEdit;
     68 
     69     /** Was the original caller asking for an entirely new account? */
     70     protected boolean mRequestNewAccount = false;
     71 
     72     private String mUsername;
     73     private EditText mUsernameEdit;
     74 
     75     /**
     76      * {@inheritDoc}
     77      */
     78     @Override
     79     public void onCreate(Bundle icicle) {
     80         Log.i(TAG, "onCreate(" + icicle + ")");
     81         super.onCreate(icicle);
     82         mAccountManager = AccountManager.get(this);
     83         Log.i(TAG, "loading data from Intent");
     84         final Intent intent = getIntent();
     85         mUsername = intent.getStringExtra(PARAM_USERNAME);
     86         mAuthtokenType = intent.getStringExtra(PARAM_AUTHTOKEN_TYPE);
     87         mRequestNewAccount = mUsername == null;
     88         mConfirmCredentials =
     89             intent.getBooleanExtra(PARAM_CONFIRMCREDENTIALS, false);
     90 
     91         Log.i(TAG, "    request new: " + mRequestNewAccount);
     92         requestWindowFeature(Window.FEATURE_LEFT_ICON);
     93         setContentView(R.layout.login_activity);
     94         getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
     95             android.R.drawable.ic_dialog_alert);
     96 
     97         mMessage = (TextView) findViewById(R.id.message);
     98         mUsernameEdit = (EditText) findViewById(R.id.username_edit);
     99         mPasswordEdit = (EditText) findViewById(R.id.password_edit);
    100 
    101         mUsernameEdit.setText(mUsername);
    102         mMessage.setText(getMessage());
    103     }
    104 
    105     /*
    106      * {@inheritDoc}
    107      */
    108     @Override
    109     protected Dialog onCreateDialog(int id) {
    110         final ProgressDialog dialog = new ProgressDialog(this);
    111         dialog.setMessage(getText(R.string.ui_activity_authenticating));
    112         dialog.setIndeterminate(true);
    113         dialog.setCancelable(true);
    114         dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
    115             public void onCancel(DialogInterface dialog) {
    116                 Log.i(TAG, "dialog cancel has been invoked");
    117                 if (mAuthThread != null) {
    118                     mAuthThread.interrupt();
    119                     finish();
    120                 }
    121             }
    122         });
    123         return dialog;
    124     }
    125 
    126     /**
    127      * Handles onClick event on the Submit button. Sends username/password to
    128      * the server for authentication.
    129      *
    130      * @param view The Submit button for which this method is invoked
    131      */
    132     public void handleLogin(View view) {
    133         if (mRequestNewAccount) {
    134             mUsername = mUsernameEdit.getText().toString();
    135         }
    136         mPassword = mPasswordEdit.getText().toString();
    137         if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword)) {
    138             mMessage.setText(getMessage());
    139         } else {
    140             showProgress();
    141             // Start authenticating...
    142             mAuthThread =
    143                 NetworkUtilities.attemptAuth(mUsername, mPassword, mHandler,
    144                     AuthenticatorActivity.this);
    145         }
    146     }
    147 
    148     /**
    149      * Called when response is received from the server for confirm credentials
    150      * request. See onAuthenticationResult(). Sets the
    151      * AccountAuthenticatorResult which is sent back to the caller.
    152      *
    153      * @param the confirmCredentials result.
    154      */
    155     protected void finishConfirmCredentials(boolean result) {
    156         Log.i(TAG, "finishConfirmCredentials()");
    157         final Account account = new Account(mUsername, Constants.ACCOUNT_TYPE);
    158         mAccountManager.setPassword(account, mPassword);
    159         final Intent intent = new Intent();
    160         intent.putExtra(AccountManager.KEY_BOOLEAN_RESULT, result);
    161         setAccountAuthenticatorResult(intent.getExtras());
    162         setResult(RESULT_OK, intent);
    163         finish();
    164     }
    165 
    166     /**
    167      *
    168      * Called when response is received from the server for authentication
    169      * request. See onAuthenticationResult(). Sets the
    170      * AccountAuthenticatorResult which is sent back to the caller. Also sets
    171      * the authToken in AccountManager for this account.
    172      *
    173      * @param the confirmCredentials result.
    174      */
    175 
    176     protected void finishLogin() {
    177         Log.i(TAG, "finishLogin()");
    178         final Account account = new Account(mUsername, Constants.ACCOUNT_TYPE);
    179 
    180         if (mRequestNewAccount) {
    181             mAccountManager.addAccountExplicitly(account, mPassword, null);
    182             // Set contacts sync for this account.
    183             ContentResolver.setSyncAutomatically(account,
    184                 ContactsContract.AUTHORITY, true);
    185         } else {
    186             mAccountManager.setPassword(account, mPassword);
    187         }
    188         final Intent intent = new Intent();
    189         mAuthtoken = mPassword;
    190         intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername);
    191         intent
    192             .putExtra(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
    193         if (mAuthtokenType != null
    194             && mAuthtokenType.equals(Constants.AUTHTOKEN_TYPE)) {
    195             intent.putExtra(AccountManager.KEY_AUTHTOKEN, mAuthtoken);
    196         }
    197         setAccountAuthenticatorResult(intent.getExtras());
    198         setResult(RESULT_OK, intent);
    199         finish();
    200     }
    201 
    202     /**
    203      * Hides the progress UI for a lengthy operation.
    204      */
    205     protected void hideProgress() {
    206         dismissDialog(0);
    207     }
    208 
    209     /**
    210      * Called when the authentication process completes (see attemptLogin()).
    211      */
    212     public void onAuthenticationResult(boolean result) {
    213         Log.i(TAG, "onAuthenticationResult(" + result + ")");
    214         // Hide the progress dialog
    215         hideProgress();
    216         if (result) {
    217             if (!mConfirmCredentials) {
    218                 finishLogin();
    219             } else {
    220                 finishConfirmCredentials(true);
    221             }
    222         } else {
    223             Log.e(TAG, "onAuthenticationResult: failed to authenticate");
    224             if (mRequestNewAccount) {
    225                 // "Please enter a valid username/password.
    226                 mMessage
    227                     .setText(getText(R.string.login_activity_loginfail_text_both));
    228             } else {
    229                 // "Please enter a valid password." (Used when the
    230                 // account is already in the database but the password
    231                 // doesn't work.)
    232                 mMessage
    233                     .setText(getText(R.string.login_activity_loginfail_text_pwonly));
    234             }
    235         }
    236     }
    237 
    238     /**
    239      * Returns the message to be displayed at the top of the login dialog box.
    240      */
    241     private CharSequence getMessage() {
    242         getString(R.string.label);
    243         if (TextUtils.isEmpty(mUsername)) {
    244             // If no username, then we ask the user to log in using an
    245             // appropriate service.
    246             final CharSequence msg =
    247                 getText(R.string.login_activity_newaccount_text);
    248             return msg;
    249         }
    250         if (TextUtils.isEmpty(mPassword)) {
    251             // We have an account but no password
    252             return getText(R.string.login_activity_loginfail_text_pwmissing);
    253         }
    254         return null;
    255     }
    256 
    257     /**
    258      * Shows the progress UI for a lengthy operation.
    259      */
    260     protected void showProgress() {
    261         showDialog(0);
    262     }
    263 }
    264