/* * 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.example.android.samplesync.authenticator; import android.accounts.Account; import android.accounts.AccountAuthenticatorActivity; import android.accounts.AccountManager; import android.app.Dialog; import android.app.ProgressDialog; import android.content.ContentResolver; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.provider.ContactsContract; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.Window; import android.widget.EditText; import android.widget.TextView; import com.example.android.samplesync.Constants; import com.example.android.samplesync.R; import com.example.android.samplesync.client.NetworkUtilities; /** * Activity which displays login screen to the user. */ public class AuthenticatorActivity extends AccountAuthenticatorActivity { public static final String PARAM_CONFIRMCREDENTIALS = "confirmCredentials"; public static final String PARAM_PASSWORD = "password"; public static final String PARAM_USERNAME = "username"; public static final String PARAM_AUTHTOKEN_TYPE = "authtokenType"; private static final String TAG = "AuthenticatorActivity"; private AccountManager mAccountManager; private Thread mAuthThread; private String mAuthtoken; private String mAuthtokenType; /** * If set we are just checking that the user knows their credentials; this * doesn't cause the user's password to be changed on the device. */ private Boolean mConfirmCredentials = false; /** for posting authentication attempts back to UI thread */ private final Handler mHandler = new Handler(); private TextView mMessage; private String mPassword; private EditText mPasswordEdit; /** Was the original caller asking for an entirely new account? */ protected boolean mRequestNewAccount = false; private String mUsername; private EditText mUsernameEdit; /** * {@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); mAuthtokenType = intent.getStringExtra(PARAM_AUTHTOKEN_TYPE); mRequestNewAccount = mUsername == null; mConfirmCredentials = intent.getBooleanExtra(PARAM_CONFIRMCREDENTIALS, false); Log.i(TAG, " request new: " + mRequestNewAccount); 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); mUsernameEdit.setText(mUsername); mMessage.setText(getMessage()); } /* * {@inheritDoc} */ @Override protected Dialog onCreateDialog(int id) { final ProgressDialog dialog = new ProgressDialog(this); dialog.setMessage(getText(R.string.ui_activity_authenticating)); dialog.setIndeterminate(true); dialog.setCancelable(true); dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { Log.i(TAG, "dialog cancel has been invoked"); if (mAuthThread != null) { mAuthThread.interrupt(); finish(); } } }); return dialog; } /** * Handles onClick event on the Submit button. Sends username/password to * the server for authentication. * * @param view The Submit button for which this method is invoked */ public void handleLogin(View view) { if (mRequestNewAccount) { mUsername = mUsernameEdit.getText().toString(); } mPassword = mPasswordEdit.getText().toString(); if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword)) { mMessage.setText(getMessage()); } else { showProgress(); // Start authenticating... mAuthThread = NetworkUtilities.attemptAuth(mUsername, mPassword, mHandler, AuthenticatorActivity.this); } } /** * 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 the confirmCredentials result. */ protected void finishConfirmCredentials(boolean result) { Log.i(TAG, "finishConfirmCredentials()"); final Account account = new Account(mUsername, Constants.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. Also sets * the authToken in AccountManager for this account. * * @param the confirmCredentials result. */ protected void finishLogin() { Log.i(TAG, "finishLogin()"); final Account account = new Account(mUsername, Constants.ACCOUNT_TYPE); if (mRequestNewAccount) { mAccountManager.addAccountExplicitly(account, mPassword, null); // Set contacts sync for this account. ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true); } else { mAccountManager.setPassword(account, mPassword); } final Intent intent = new Intent(); mAuthtoken = mPassword; intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername); intent .putExtra(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE); if (mAuthtokenType != null && mAuthtokenType.equals(Constants.AUTHTOKEN_TYPE)) { intent.putExtra(AccountManager.KEY_AUTHTOKEN, mAuthtoken); } setAccountAuthenticatorResult(intent.getExtras()); setResult(RESULT_OK, intent); finish(); } /** * Hides the progress UI for a lengthy operation. */ protected void hideProgress() { dismissDialog(0); } /** * Called when the authentication process completes (see attemptLogin()). */ public void onAuthenticationResult(boolean result) { Log.i(TAG, "onAuthenticationResult(" + result + ")"); // Hide the progress dialog hideProgress(); if (result) { if (!mConfirmCredentials) { finishLogin(); } else { finishConfirmCredentials(true); } } else { Log.e(TAG, "onAuthenticationResult: failed to authenticate"); if (mRequestNewAccount) { // "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)); } } } /** * 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. */ protected void showProgress() { showDialog(0); } }