src/org/gege/caldavsyncadapter/authenticator/AuthenticatorActivity.java

changeset 0
fb9019fb1bf7
child 8
ec8af0e3fbc2
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/org/gege/caldavsyncadapter/authenticator/AuthenticatorActivity.java	Tue Feb 10 18:12:00 2015 +0100
     1.3 @@ -0,0 +1,474 @@
     1.4 +/**
     1.5 + * Copyright (c) 2012-2013, Gerald Garcia
     1.6 + * 
     1.7 + * This file is part of Andoid Caldav Sync Adapter Free.
     1.8 + *
     1.9 + * Andoid Caldav Sync Adapter Free is free software: you can redistribute 
    1.10 + * it and/or modify it under the terms of the GNU General Public License 
    1.11 + * as published by the Free Software Foundation, either version 3 of the 
    1.12 + * License, or at your option any later version.
    1.13 + *
    1.14 + * Andoid Caldav Sync Adapter Free is distributed in the hope that 
    1.15 + * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
    1.16 + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.17 + * GNU General Public License for more details.
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License
    1.20 + * along with Andoid Caldav Sync Adapter Free.  
    1.21 + * If not, see <http://www.gnu.org/licenses/>.
    1.22 + * 
    1.23 + */
    1.24 +
    1.25 +package org.gege.caldavsyncadapter.authenticator;
    1.26 +
    1.27 +import java.io.IOException;
    1.28 +import java.io.UnsupportedEncodingException;
    1.29 +import java.net.MalformedURLException;
    1.30 +import java.net.URISyntaxException;
    1.31 +
    1.32 +import javax.xml.parsers.ParserConfigurationException;
    1.33 +
    1.34 +import org.apache.http.conn.HttpHostConnectException;
    1.35 +import org.gege.caldavsyncadapter.R;
    1.36 +import org.gege.caldavsyncadapter.caldav.CaldavFacade;
    1.37 +import org.gege.caldavsyncadapter.caldav.CaldavFacade.TestConnectionResult;
    1.38 +import org.xml.sax.SAXException;
    1.39 +
    1.40 +import android.accounts.Account;
    1.41 +import android.accounts.AccountManager;
    1.42 +import android.animation.Animator;
    1.43 +import android.animation.AnimatorListenerAdapter;
    1.44 +import android.annotation.TargetApi;
    1.45 +import android.app.Activity;
    1.46 +import android.content.Context;
    1.47 +import android.content.pm.PackageManager.NameNotFoundException;
    1.48 +import android.os.AsyncTask;
    1.49 +import android.os.Build;
    1.50 +import android.os.Bundle;
    1.51 +import android.text.TextUtils;
    1.52 +import android.util.Log;
    1.53 +import android.view.KeyEvent;
    1.54 +import android.view.Menu;
    1.55 +import android.view.View;
    1.56 +import android.view.inputmethod.EditorInfo;
    1.57 +import android.widget.EditText;
    1.58 +import android.widget.TextView;
    1.59 +import android.widget.Toast;
    1.60 +
    1.61 +/**
    1.62 + * Activity which displays a login screen to the user, offering registration as
    1.63 + * well.
    1.64 + */
    1.65 +public class AuthenticatorActivity extends Activity {
    1.66 +	
    1.67 +	private static final String TAG = "AuthenticatorActivity";
    1.68 +
    1.69 +	private static final String ACCOUNT_TYPE = "org.gege.caldavsyncadapter.account";
    1.70 +
    1.71 +	public static final String USER_DATA_URL_KEY = "USER_DATA_URL_KEY";
    1.72 +	public static final String USER_DATA_USERNAME = "USER_DATA_USERNAME";
    1.73 +	public static final String USER_DATA_VERSION = "USER_DATA_VERSION";
    1.74 +	public static final String CURRENT_USER_DATA_VERSION = "1";
    1.75 +	
    1.76 +	public static final String ACCOUNT_NAME_SPLITTER = "@";
    1.77 +	
    1.78 +	/**
    1.79 +	 * The default email to populate the email field with.
    1.80 +	 */
    1.81 +	public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL";
    1.82 +
    1.83 +	/**
    1.84 +	 * Keep track of the login task to ensure we can cancel it if requested.
    1.85 +	 */
    1.86 +	private UserLoginTask mAuthTask = null;
    1.87 +
    1.88 +	// Values for email and password at the time of the login attempt.
    1.89 +	private String mUser;
    1.90 +	private String mPassword;
    1.91 +	private Context mContext;
    1.92 +
    1.93 +	// UI references.
    1.94 +	private EditText mUserView;
    1.95 +	private EditText mPasswordView;
    1.96 +	private View mLoginFormView;
    1.97 +	private View mLoginStatusView;
    1.98 +	private TextView mLoginStatusMessageView;
    1.99 +
   1.100 +	private AccountManager mAccountManager;
   1.101 +
   1.102 +	private String mURL;
   1.103 +	private EditText mURLView;
   1.104 +	
   1.105 +	private String mAccountname;
   1.106 +	private EditText mAccountnameView;
   1.107 +	
   1.108 +	public AuthenticatorActivity() {
   1.109 +		super();
   1.110 +		
   1.111 +	}
   1.112 +	
   1.113 +	@Override
   1.114 +	protected void onCreate(Bundle savedInstanceState) {
   1.115 +		super.onCreate(savedInstanceState);
   1.116 +		
   1.117 +		mAccountManager = AccountManager.get(this);
   1.118 +
   1.119 +		setContentView(R.layout.activity_authenticator);
   1.120 +
   1.121 +		// Set up the login form.
   1.122 +		mUser = getIntent().getStringExtra(EXTRA_EMAIL);
   1.123 +		mUserView = (EditText) findViewById(R.id.user);
   1.124 +		mUserView.setText(mUser);
   1.125 +		
   1.126 +		mContext = getBaseContext();
   1.127 +
   1.128 +		mPasswordView = (EditText) findViewById(R.id.password);
   1.129 +		mPasswordView
   1.130 +				.setOnEditorActionListener(new TextView.OnEditorActionListener() {
   1.131 +					@Override
   1.132 +					public boolean onEditorAction(TextView textView, int id,
   1.133 +							KeyEvent keyEvent) {
   1.134 +						if (id == R.id.login || id == EditorInfo.IME_NULL) {
   1.135 +							attemptLogin();
   1.136 +							return true;
   1.137 +						}
   1.138 +						return false;
   1.139 +					}
   1.140 +				});
   1.141 +
   1.142 +		
   1.143 +		mURLView = (EditText) findViewById(R.id.url);
   1.144 +		
   1.145 +		mAccountnameView = (EditText) findViewById(R.id.accountname);
   1.146 +		
   1.147 +		mLoginFormView = findViewById(R.id.login_form);
   1.148 +		mLoginStatusView = findViewById(R.id.login_status);
   1.149 +		mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);
   1.150 +
   1.151 +		findViewById(R.id.sign_in_button).setOnClickListener(
   1.152 +				new View.OnClickListener() {
   1.153 +					@Override
   1.154 +					public void onClick(View view) {
   1.155 +						attemptLogin();
   1.156 +					}
   1.157 +				});
   1.158 +		
   1.159 +		
   1.160 +	}
   1.161 +
   1.162 +	@Override
   1.163 +	public boolean onCreateOptionsMenu(Menu menu) {
   1.164 +		super.onCreateOptionsMenu(menu);
   1.165 +		getMenuInflater().inflate(R.menu.activity_authenticator, menu);
   1.166 +		return true;
   1.167 +	}
   1.168 +
   1.169 +	/**
   1.170 +	 * Attempts to sign in or register the account specified by the login form.
   1.171 +	 * If there are form errors (invalid email, missing fields, etc.), the
   1.172 +	 * errors are presented and no actual login attempt is made.
   1.173 +	 */
   1.174 +	public void attemptLogin() {
   1.175 +		if (mAuthTask != null) {
   1.176 +			return;
   1.177 +		}
   1.178 +
   1.179 +		// Reset errors.
   1.180 +		mUserView.setError(null);
   1.181 +		mPasswordView.setError(null);
   1.182 +
   1.183 +		// Store values at the time of the login attempt.
   1.184 +		mUser = mUserView.getText().toString();
   1.185 +		mPassword = mPasswordView.getText().toString();
   1.186 +		mURL = mURLView.getText().toString();
   1.187 +		mAccountname = mAccountnameView.getText().toString();
   1.188 +
   1.189 +		boolean cancel = false;
   1.190 +		View focusView = null;
   1.191 +		
   1.192 +		if (!mAccountname.equals("")) {
   1.193 +			Account TestAccount = new Account(mAccountname, ACCOUNT_TYPE);
   1.194 +			String TestUrl = mAccountManager.getUserData(TestAccount, AuthenticatorActivity.USER_DATA_URL_KEY);
   1.195 +			if (TestUrl != null) {
   1.196 +				mAccountnameView.setError(getString(R.string.error_account_already_in_use));
   1.197 +				focusView = mAccountnameView;
   1.198 +				cancel = true;
   1.199 +			}
   1.200 +		}
   1.201 +
   1.202 +		// Check for a valid password.
   1.203 +		if (TextUtils.isEmpty(mPassword)) {
   1.204 +			mPasswordView.setError(getString(R.string.error_field_required));
   1.205 +			focusView = mPasswordView;
   1.206 +			cancel = true;
   1.207 +		} else if (mPassword.length() < 4) {
   1.208 +			mPasswordView.setError(getString(R.string.error_invalid_password));
   1.209 +			focusView = mPasswordView;
   1.210 +			cancel = true;
   1.211 +		}
   1.212 +
   1.213 +		// Check for a valid email address.
   1.214 +		if (TextUtils.isEmpty(mUser)) {
   1.215 +			mUserView.setError(getString(R.string.error_field_required));
   1.216 +			focusView = mUserView;
   1.217 +			cancel = true;
   1.218 +		} 
   1.219 +		//else if (!mUser.contains("@")) {
   1.220 +		//	mUserView.setError(getString(R.string.error_invalid_email));
   1.221 +		//	focusView = mUserView;
   1.222 +		//	cancel = true;
   1.223 +		//}
   1.224 +
   1.225 +		if (cancel) {
   1.226 +			// There was an error; don't attempt login and focus the first
   1.227 +			// form field with an error.
   1.228 +			focusView.requestFocus();
   1.229 +		} else {
   1.230 +			// Show a progress spinner, and kick off a background task to
   1.231 +			// perform the user login attempt.
   1.232 +			mLoginStatusMessageView.setText(R.string.login_progress_signing_in);
   1.233 +			showProgress(true);
   1.234 +			mAuthTask = new UserLoginTask();
   1.235 +			mAuthTask.execute((Void) null);
   1.236 +		}
   1.237 +	}
   1.238 +
   1.239 +	/**
   1.240 +	 * Shows the progress UI and hides the login form.
   1.241 +	 */
   1.242 +	@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
   1.243 +	private void showProgress(final boolean show) {
   1.244 +		// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
   1.245 +		// for very easy animations. If available, use these APIs to fade-in
   1.246 +		// the progress spinner.
   1.247 +		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
   1.248 +			int shortAnimTime = getResources().getInteger(
   1.249 +					android.R.integer.config_shortAnimTime);
   1.250 +
   1.251 +			mLoginStatusView.setVisibility(View.VISIBLE);
   1.252 +			mLoginStatusView.animate().setDuration(shortAnimTime)
   1.253 +					.alpha(show ? 1 : 0)
   1.254 +					.setListener(new AnimatorListenerAdapter() {
   1.255 +						@Override
   1.256 +						public void onAnimationEnd(Animator animation) {
   1.257 +							mLoginStatusView.setVisibility(show ? View.VISIBLE
   1.258 +									: View.GONE);
   1.259 +						}
   1.260 +					});
   1.261 +
   1.262 +			mLoginFormView.setVisibility(View.VISIBLE);
   1.263 +			mLoginFormView.animate().setDuration(shortAnimTime)
   1.264 +					.alpha(show ? 0 : 1)
   1.265 +					.setListener(new AnimatorListenerAdapter() {
   1.266 +						@Override
   1.267 +						public void onAnimationEnd(Animator animation) {
   1.268 +							mLoginFormView.setVisibility(show ? View.GONE
   1.269 +									: View.VISIBLE);
   1.270 +						}
   1.271 +					});
   1.272 +		} else {
   1.273 +			// The ViewPropertyAnimator APIs are not available, so simply show
   1.274 +			// and hide the relevant UI components.
   1.275 +			mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
   1.276 +			mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
   1.277 +		}
   1.278 +	}
   1.279 +
   1.280 +	
   1.281 +	protected enum LoginResult {
   1.282 +		 MalformedURLException, 
   1.283 +		 GeneralSecurityException, 
   1.284 +		 UnkonwnException, 
   1.285 +		 WrongCredentials, 
   1.286 +		 InvalidResponse, 
   1.287 +		 WrongUrl, 
   1.288 +		 ConnectionRefused, 
   1.289 +		 Success_Calendar, 
   1.290 +		 Success_Collection, 
   1.291 +		 Account_Already_In_Use
   1.292 +	}
   1.293 +	
   1.294 +	
   1.295 +	/**
   1.296 +	 * Represents an asynchronous login/registration task used to authenticate
   1.297 +	 * the user.
   1.298 +	 */
   1.299 +	public class UserLoginTask extends AsyncTask<Void, Void, LoginResult> {
   1.300 +
   1.301 +		@Override
   1.302 +		protected LoginResult doInBackground(Void... params) {
   1.303 +
   1.304 +			TestConnectionResult result = null;
   1.305 +			
   1.306 +			try {
   1.307 +				CaldavFacade facade = new CaldavFacade(mUser, mPassword, mURL);
   1.308 +				String version = "";
   1.309 +				try {
   1.310 +					version = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName;
   1.311 +				} catch (NameNotFoundException e) {
   1.312 +					version = "unknown";
   1.313 +					e.printStackTrace();
   1.314 +				}
   1.315 +				facade.setVersion(version);
   1.316 +				result = facade.testConnection();
   1.317 +				Log.i(TAG, "testConnection status="+result);
   1.318 +			} catch (HttpHostConnectException e) {
   1.319 +				Log.w(TAG,"testConnection", e);
   1.320 +				return LoginResult.ConnectionRefused;
   1.321 +			} catch (MalformedURLException e) {				
   1.322 +				Log.w(TAG,"testConnection", e);
   1.323 +				return LoginResult.MalformedURLException;
   1.324 +			} catch (UnsupportedEncodingException e) {
   1.325 +				Log.w(TAG,"testConnection", e);
   1.326 +				return LoginResult.UnkonwnException;
   1.327 +			} catch (ParserConfigurationException e) {
   1.328 +				Log.w(TAG,"testConnection", e);
   1.329 +				return LoginResult.UnkonwnException;
   1.330 +			} catch (SAXException e) {
   1.331 +				Log.w(TAG,"testConnection", e);
   1.332 +				return LoginResult.InvalidResponse;
   1.333 +			} catch (IOException e) {
   1.334 +				Log.w(TAG,"testConnection", e);
   1.335 +				return LoginResult.UnkonwnException;
   1.336 +			} catch (URISyntaxException e) {
   1.337 +				Log.w(TAG,"testConnection", e);
   1.338 +				return LoginResult.MalformedURLException;
   1.339 +			}
   1.340 +
   1.341 +			if (result == null) {
   1.342 +				return LoginResult.UnkonwnException;
   1.343 +			}
   1.344 +			
   1.345 +			switch (result) {
   1.346 +			
   1.347 +			case SUCCESS:
   1.348 +				boolean OldAccount = false;
   1.349 +				LoginResult Result = LoginResult.Success_Calendar; 
   1.350 +
   1.351 +				if (OldAccount) {
   1.352 +					final Account account = new Account(mUser, ACCOUNT_TYPE);			
   1.353 +					if (mAccountManager.addAccountExplicitly(account, mPassword, null)) {
   1.354 +						Log.v(TAG,"new account created");
   1.355 +						mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL);
   1.356 +					} else {
   1.357 +						Log.v(TAG,"no new account created");
   1.358 +						Result = LoginResult.Account_Already_In_Use;
   1.359 +					}
   1.360 +				} else {
   1.361 +					final Account account; 
   1.362 +					if (mAccountname.equals("")) {
   1.363 +						account = new Account(mUser + ACCOUNT_NAME_SPLITTER + mURL, ACCOUNT_TYPE);
   1.364 +					} else {
   1.365 +						account = new Account(mAccountname, ACCOUNT_TYPE);
   1.366 +					}
   1.367 +					if (mAccountManager.addAccountExplicitly(account, mPassword, null)) {
   1.368 +						Log.v(TAG,"new account created");
   1.369 +						mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL);
   1.370 +						mAccountManager.setUserData(account, USER_DATA_USERNAME, mUser);
   1.371 +						mAccountManager.setUserData(account, USER_DATA_VERSION, CURRENT_USER_DATA_VERSION);
   1.372 +					} else {
   1.373 +						Log.v(TAG,"no new account created");
   1.374 +						Result = LoginResult.Account_Already_In_Use;
   1.375 +					}
   1.376 +				}
   1.377 +			
   1.378 +				return Result;
   1.379 +
   1.380 +			case WRONG_CREDENTIAL:
   1.381 +				return LoginResult.WrongCredentials;
   1.382 +				
   1.383 +			case WRONG_SERVER_STATUS:
   1.384 +				return LoginResult.InvalidResponse;
   1.385 +				
   1.386 +			case WRONG_URL:
   1.387 +				return LoginResult.WrongUrl;
   1.388 +				
   1.389 +			case WRONG_ANSWER:
   1.390 +				return LoginResult.InvalidResponse;
   1.391 +				
   1.392 +			default:
   1.393 +				return LoginResult.UnkonwnException;
   1.394 +				
   1.395 +			}
   1.396 +			
   1.397 +		}
   1.398 +		
   1.399 +
   1.400 +		@Override
   1.401 +		protected void onPostExecute(final LoginResult result) {
   1.402 +			mAuthTask = null;
   1.403 +			showProgress(false);
   1.404 +
   1.405 +			int duration = Toast.LENGTH_SHORT;
   1.406 +			Toast toast = null;
   1.407 +			
   1.408 +			switch (result) {
   1.409 +				case Success_Calendar:
   1.410 +					toast = Toast.makeText(getApplicationContext(), R.string.success_calendar, duration);
   1.411 +					toast.show();
   1.412 +					finish();
   1.413 +					break;
   1.414 +					
   1.415 +				case Success_Collection:
   1.416 +					toast = Toast.makeText(getApplicationContext(), R.string.success_collection, duration);
   1.417 +					toast.show();
   1.418 +					finish();
   1.419 +					break;
   1.420 +					
   1.421 +				case MalformedURLException:
   1.422 +					
   1.423 +					toast = Toast.makeText(getApplicationContext(), R.string.error_incorrect_url_format, duration);
   1.424 +					toast.show();
   1.425 +					mURLView.setError(getString(R.string.error_incorrect_url_format));
   1.426 +					mURLView.requestFocus();
   1.427 +					break;
   1.428 +				case InvalidResponse:
   1.429 +					toast =  Toast.makeText(getApplicationContext(), R.string.error_invalid_server_answer, duration);
   1.430 +					toast.show();
   1.431 +					mURLView.setError(getString(R.string.error_invalid_server_answer));
   1.432 +					mURLView.requestFocus();
   1.433 +					break;
   1.434 +				case WrongUrl:
   1.435 +					toast =  Toast.makeText(getApplicationContext(), R.string.error_wrong_url, duration);
   1.436 +					toast.show();
   1.437 +					mURLView.setError(getString(R.string.error_wrong_url));
   1.438 +					mURLView.requestFocus();
   1.439 +					break;
   1.440 +					
   1.441 +				case WrongCredentials:
   1.442 +					mPasswordView.setError(getString(R.string.error_incorrect_password));
   1.443 +					mPasswordView.requestFocus();
   1.444 +					break;
   1.445 +					
   1.446 +				case ConnectionRefused:
   1.447 +					toast =  Toast.makeText(getApplicationContext(), R.string.error_connection_refused, duration);
   1.448 +					toast.show();
   1.449 +					mURLView.setError(getString(R.string.error_connection_refused));
   1.450 +					mURLView.requestFocus();
   1.451 +					break;
   1.452 +				case Account_Already_In_Use:
   1.453 +					toast =  Toast.makeText(getApplicationContext(), R.string.error_account_already_in_use, duration);
   1.454 +					toast.show();
   1.455 +					mURLView.setError(getString(R.string.error_account_already_in_use));
   1.456 +					mURLView.requestFocus();
   1.457 +					break;
   1.458 +				default:
   1.459 +					toast =  Toast.makeText(getApplicationContext(), R.string.error_unkown_error, duration);
   1.460 +					toast.show();
   1.461 +					mURLView.setError(getString(R.string.error_unkown_error));
   1.462 +					mURLView.requestFocus();
   1.463 +					break;
   1.464 +				}
   1.465 +				
   1.466 +				
   1.467 +				
   1.468 +			
   1.469 +		}
   1.470 +
   1.471 +		@Override
   1.472 +		protected void onCancelled() {
   1.473 +			mAuthTask = null;
   1.474 +			showProgress(false);
   1.475 +		}
   1.476 +	}
   1.477 +}

mercurial