blob: 4e1ee2a7519c6a01063da7e2a21c47bf86473204 [file] [log] [blame]
/*
* 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 {
/** 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 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;
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_CONFIRM_CREDENTIALS, 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.
*/
private 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.
*/
private 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.
*/
private 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.
*/
private void showProgress() {
showDialog(0);
}
}