/**
* Copyright 2009 Joe LaPenna
*/
package com.joelapenna.foursquared;
import com.joelapenna.foursquare.Foursquare;
import com.joelapenna.foursquare.error.FoursquareException;
import com.joelapenna.foursquared.location.LocationUtils;
import com.joelapenna.foursquared.preferences.Preferences;
import com.joelapenna.foursquared.util.NotificationsUtil;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
/**
* @author Joe LaPenna (joe@joelapenna.com)
*/
public class LoginActivity extends Activity {
public static final String TAG = "LoginActivity";
public static final String PARAM_PHONENUMBER = "phoneNumber";
public static final String PARAM_SETAUTHTOKEN = "setAuthToken";
public static final String PARAM_CONFIRMCREDENTIALS = "confirmCredentials";
public static final String PARAM_LAUNCHMAIN = "launchMain";
public static final boolean DEBUG = FoursquaredSettings.DEBUG;
private static final String PARAM_DESTINATIONINTENT = "destinationIntent";
private static class AuthenticatorHelper {
private AccountAuthenticatorResponse mResponse = null;
private Bundle mResultBundle = null;
final private Context context;
final private Intent intent;
final private String phoneNumber;
final private String password;
final private boolean loggedIn;
public AuthenticatorHelper(Context context, Intent intent, String phoneNumber, String password, boolean loggedIn) {
this.context = context;
this.intent = intent;
this.phoneNumber = phoneNumber;
this.password = password;
this.loggedIn = loggedIn;
}
private Intent getIntent() {
return intent;
}
Intent getResult() {
onCreate();
Account account = new Account(phoneNumber, AuthenticatorService.ACCOUNT_TYPE);
AccountManager am = AccountManager.get(context);
final Intent intent = new Intent();
if (getIntent().getBooleanExtra(PARAM_CONFIRMCREDENTIALS, false)){
am.setPassword(account, password);
intent.putExtra(AccountManager.KEY_BOOLEAN_RESULT, loggedIn);
setAccountAuthenticatorResult(intent.getExtras());
} else if (getIntent().getBooleanExtra(PARAM_SETAUTHTOKEN, false)) {
if ( phoneNumber.equalsIgnoreCase(getIntent().getStringExtra(PARAM_PHONENUMBER))) {
am.setPassword(account, password);
} else {
am.addAccountExplicitly(account, password, null);
ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
}
intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, phoneNumber);
intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AuthenticatorService.ACCOUNT_TYPE);
intent.putExtra(AccountManager.KEY_AUTHTOKEN, password);
setAccountAuthenticatorResult(intent.getExtras());
}
return intent;
}
// lifted from AccountAuthenticatorActivity
void onCreate() {
mResponse = getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
if (mResponse != null) {
mResponse.onRequestContinued();
}
}
// lifted from AccountAuthenticatorActivity
public final void setAccountAuthenticatorResult(Bundle result) {
mResultBundle = result;
}
// lifted from AccountAuthenticatorActivity
public void finish() {
if (mResponse != null) {
// send the result bundle back if set, otherwise send an error.
if (mResultBundle != null) {
mResponse.onResult(mResultBundle);
} else {
mResponse.onError(AccountManager.ERROR_CODE_CANCELED,
"canceled");
}
mResponse = null;
}
}
}
private static class AuthenticatorLoginHelper {
}
static Intent loginAndProceedTo(Context context, Intent destination) {
Intent intent = new Intent(context, LoginActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.setFlags(
Intent.FLAG_ACTIVITY_NO_HISTORY |
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.getExtras().putParcelable(PARAM_DESTINATIONINTENT, destination);
return intent;
}
private AsyncTask<Void, Void, Boolean> mLoginTask;
private TextView mNewAccountTextView;
private EditText mPhoneUsernameEditText;
private EditText mPasswordEditText;
private ProgressDialog mProgressDialog;
private AuthenticatorHelper authenticatorHelper;
private AuthenticatorLoginHelper authLoginHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (DEBUG) Log.d(TAG, "onCreate()");
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.login_activity);
Preferences.logoutUser( //
((Foursquared) getApplication()).getFoursquare(), //
PreferenceManager.getDefaultSharedPreferences(this).edit());
// Set up the UI.
ensureUi();
// Re-task if the request was cancelled.
mLoginTask = (LoginTask) getLastNonConfigurationInstance();
if (mLoginTask != null && mLoginTask.isCancelled()) {
if (DEBUG) Log.d(TAG, "LoginTask previously cancelled, trying again.");
mLoginTask = new LoginTask(this).execute();
}
}
@Override
public void onResume() {
super.onResume();
((Foursquared) getApplication()).requestLocationUpdates(false);
}
@Override
public void onPause() {
super.onPause();
((Foursquared) getApplication()).removeLocationUpdates();
}
@Override
public Object onRetainNonConfigurationInstance() {
if (DEBUG) Log.d(TAG, "onRetainNonConfigurationInstance()");
if (mLoginTask != null) {
mLoginTask.cancel(true);
}
return mLoginTask;
}
private ProgressDialog showProgressDialog() {
if (mProgressDialog == null) {
ProgressDialog dialog = new ProgressDialog(this);
dialog.setTitle(R.string.login_dialog_title);
dialog.setMessage(getString(R.string.login_dialog_message));
dialog.setIndeterminate(true);
dialog.setCancelable(true);
mProgressDialog = dialog;
}
mProgressDialog.show();
return mProgressDialog;
}
private void dismissProgressDialog() {
try {
mProgressDialog.dismiss();
} catch (IllegalArgumentException e) {
// We don't mind. android cleared it for us.
}
}
private void ensureUi() {
final Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mLoginTask = new LoginTask(LoginActivity.this).execute();
}
});
mNewAccountTextView = (TextView) findViewById(R.id.newAccountTextView);
mNewAccountTextView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(
Intent.ACTION_VIEW, Uri.parse(Foursquare.FOURSQUARE_MOBILE_SIGNUP)));
}
});
mPhoneUsernameEditText = ((EditText) findViewById(R.id.phoneEditText));
mPasswordEditText = ((EditText) findViewById(R.id.passwordEditText));
TextWatcher fieldValidatorTextWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
button.setEnabled(phoneNumberEditTextFieldIsValid()
&& passwordEditTextFieldIsValid());
}
private boolean phoneNumberEditTextFieldIsValid() {
// This can be either a phone number or username so we don't
// care too much about the
// format.
return !TextUtils.isEmpty(mPhoneUsernameEditText.getText());
}
private boolean passwordEditTextFieldIsValid() {
return !TextUtils.isEmpty(mPasswordEditText.getText());
}
};
mPhoneUsernameEditText.addTextChangedListener(fieldValidatorTextWatcher);
mPasswordEditText.addTextChangedListener(fieldValidatorTextWatcher);
}
@Override
public void finish() {
if ( authenticatorHelper != null ) {
authenticatorHelper.finish();
}
super.finish();
}
private class LoginTask extends AsyncTask<Void, Void, Boolean> {
private static final String TAG = "LoginTask";
private static final boolean DEBUG = FoursquaredSettings.DEBUG;
final private Context mContext;
private Exception mReason;
LoginTask(Context context) {
mContext = context;
}
@Override
protected void onPreExecute() {
if (DEBUG) Log.d(TAG, "onPreExecute()");
showProgressDialog();
}
@Override
protected Boolean doInBackground(Void... params) {
if (DEBUG) Log.d(TAG, "doInBackground()");
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(LoginActivity.this);
Editor editor = prefs.edit();
Foursquared foursquared = (Foursquared) getApplication();
Foursquare foursquare = foursquared.getFoursquare();
try {
String phoneNumber = mPhoneUsernameEditText.getText().toString();
String password = mPasswordEditText.getText().toString();
Foursquare.Location location = null;
location = LocationUtils.createFoursquareLocation(
foursquared.getLastKnownLocation());
boolean loggedIn = Preferences.loginUser(foursquare, phoneNumber, password,
location, editor);
// Make sure prefs make a round trip.
String userId = Preferences.getUserId(prefs);
if (TextUtils.isEmpty(userId)) {
if (DEBUG) Log.d(TAG, "Preference store calls failed");
throw new FoursquareException(getResources().getString(
R.string.login_failed_login_toast));
} else if ( getIntent().getBooleanExtra(PARAM_CONFIRMCREDENTIALS, false)
|| getIntent().getBooleanExtra(PARAM_SETAUTHTOKEN, false) ) {
authenticatorHelper = new AuthenticatorHelper(mContext, getIntent(), phoneNumber, password, loggedIn);
setResult(RESULT_OK, authenticatorHelper.getResult());
finish();
}
return loggedIn;
} catch (Exception e) {
if (DEBUG) Log.d(TAG, "Caught Exception logging in.", e);
mReason = e;
Preferences.logoutUser(foursquare, editor);
return false;
}
}
@Override
protected void onPostExecute(Boolean loggedIn) {
if (DEBUG) Log.d(TAG, "onPostExecute(): " + loggedIn);
Foursquared foursquared = (Foursquared) getApplication();
if (loggedIn) {
sendBroadcast(new Intent(Foursquared.INTENT_ACTION_LOGGED_IN));
Toast.makeText(LoginActivity.this, getString(R.string.login_welcome_toast),
Toast.LENGTH_LONG).show();
// Launch the service to update any widgets, etc.
foursquared.requestStartService();
Intent dest = getIntent().getParcelableExtra(PARAM_DESTINATIONINTENT);
if ( dest != null ) {
startActivity(dest);
} else if ( getIntent().getBooleanExtra(PARAM_LAUNCHMAIN, true) ) {
// Launch the main activity to let the user do anything.
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
// Be done with the activity.
finish();
} else {
sendBroadcast(new Intent(Foursquared.INTENT_ACTION_LOGGED_OUT));
NotificationsUtil.ToastReasonForFailure(LoginActivity.this, mReason);
}
dismissProgressDialog();
}
@Override
protected void onCancelled() {
dismissProgressDialog();
}
}
}