/*
* Copyright (C) 2011 - 2013 Michi Gysel <michael.gysel@gmail.com>
*
* This file is part of the HSR Timetable.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.scythe.hsr.authenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorActivity;
import android.accounts.AccountManager;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import ch.scythe.hsr.Constants;
import ch.scythe.hsr.R;
import ch.scythe.hsr.api.TimeTableAPI;
import ch.scythe.hsr.error.ServerConnectionException;
/** 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 boolean firstLoginAttempt = true;
private AccountManager accountManager;
private String mAuthtoken;
private String mAuthtokenType;
/** for posting authentication attempts back to UI thread */
private TextView mMessage;
private String mPassword;
private EditText mPasswordEdit;
private String mUsername;
private EditText mUsernameEdit;
private AsyncTask<String, Object, Boolean> authTask;
/** {@inheritDoc} */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
accountManager = AccountManager.get(this);
final Intent intent = getIntent();
mUsername = intent.getStringExtra(PARAM_USERNAME);
mAuthtokenType = intent.getStringExtra(PARAM_AUTHTOKEN_TYPE);
firstLoginAttempt = TextUtils.isEmpty(mUsername) && TextUtils.isEmpty(mAuthtoken);
setContentView(R.layout.login_activity);
mMessage = (TextView) findViewById(R.id.message_bottom);
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 (authTask != null) {
authTask.cancel(true);
}
}
});
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) {
mUsername = mUsernameEdit.getText().toString();
mPassword = mPasswordEdit.getText().toString();
if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword)) {
mMessage.setText(getMessage());
} else {
showProgress();
authTask = new AttemptAuthTask(new TimeTableAPI(getApplicationContext()));
authTask.execute(mUsername, mPassword);
}
}
private class AttemptAuthTask extends AsyncTask<String, Object, Boolean> {
private final TimeTableAPI api;
public AttemptAuthTask(TimeTableAPI api) {
this.api = api;
}
@Override
protected Boolean doInBackground(String... params) {
String username = params[0];
String password = params[1];
Boolean result = null;
try {
result = api.validateCredentials(username, password);
} catch (ServerConnectionException e) {
// TODO handle error message
// for now: result = null means error
}
return result;
}
@Override
protected void onPostExecute(Boolean success) {
onAuthenticationResult(success);
}
}
/** Called when the authentication process completes. */
public void onAuthenticationResult(Boolean result) {
Log.i(TAG, "Authentication " + (result ? "succeeded" : "failed") + ".");
hideProgress();
if (Boolean.TRUE == result) {
finishLogin();
} else {
if (Boolean.FALSE == result) {
mMessage.setText(getText(R.string.login_activity_loginfail_text_both));
} else {
mMessage.setText(getText(R.string.message_error_while_connecting));
}
}
}
/** 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() {
final Account account = new Account(mUsername, Constants.ACCOUNT_TYPE);
if (firstLoginAttempt) {
accountManager.addAccountExplicitly(account, mPassword, null);
// Set contacts sync for this account.
// ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
} else {
accountManager.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);
}
/** Shows the progress UI for a lengthy operation. */
protected void showProgress() {
showDialog(0);
}
/** Returns the message to be displayed at the top of the login dialog box. */
private CharSequence getMessage() {
getString(R.string.app_name);
if (TextUtils.isEmpty(mUsername) && TextUtils.isEmpty(mPassword)) {
return "";
} else if (TextUtils.isEmpty(mUsername)) {
return getText(R.string.login_activity_login_missing);
} else if (TextUtils.isEmpty(mPassword)) {
return getText(R.string.login_activity_pw_missing);
}
return null;
}
}