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

changeset 0
fb9019fb1bf7
child 8
ec8af0e3fbc2
equal deleted inserted replaced
-1:000000000000 0:083b54c95d9d
1 /**
2 * Copyright (c) 2012-2013, Gerald Garcia
3 *
4 * This file is part of Andoid Caldav Sync Adapter Free.
5 *
6 * Andoid Caldav Sync Adapter Free is free software: you can redistribute
7 * it and/or modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation, either version 3 of the
9 * License, or at your option any later version.
10 *
11 * Andoid Caldav Sync Adapter Free is distributed in the hope that
12 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
13 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Andoid Caldav Sync Adapter Free.
18 * If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 package org.gege.caldavsyncadapter.authenticator;
23
24 import java.io.IOException;
25 import java.io.UnsupportedEncodingException;
26 import java.net.MalformedURLException;
27 import java.net.URISyntaxException;
28
29 import javax.xml.parsers.ParserConfigurationException;
30
31 import org.apache.http.conn.HttpHostConnectException;
32 import org.gege.caldavsyncadapter.R;
33 import org.gege.caldavsyncadapter.caldav.CaldavFacade;
34 import org.gege.caldavsyncadapter.caldav.CaldavFacade.TestConnectionResult;
35 import org.xml.sax.SAXException;
36
37 import android.accounts.Account;
38 import android.accounts.AccountManager;
39 import android.animation.Animator;
40 import android.animation.AnimatorListenerAdapter;
41 import android.annotation.TargetApi;
42 import android.app.Activity;
43 import android.content.Context;
44 import android.content.pm.PackageManager.NameNotFoundException;
45 import android.os.AsyncTask;
46 import android.os.Build;
47 import android.os.Bundle;
48 import android.text.TextUtils;
49 import android.util.Log;
50 import android.view.KeyEvent;
51 import android.view.Menu;
52 import android.view.View;
53 import android.view.inputmethod.EditorInfo;
54 import android.widget.EditText;
55 import android.widget.TextView;
56 import android.widget.Toast;
57
58 /**
59 * Activity which displays a login screen to the user, offering registration as
60 * well.
61 */
62 public class AuthenticatorActivity extends Activity {
63
64 private static final String TAG = "AuthenticatorActivity";
65
66 private static final String ACCOUNT_TYPE = "org.gege.caldavsyncadapter.account";
67
68 public static final String USER_DATA_URL_KEY = "USER_DATA_URL_KEY";
69 public static final String USER_DATA_USERNAME = "USER_DATA_USERNAME";
70 public static final String USER_DATA_VERSION = "USER_DATA_VERSION";
71 public static final String CURRENT_USER_DATA_VERSION = "1";
72
73 public static final String ACCOUNT_NAME_SPLITTER = "@";
74
75 /**
76 * The default email to populate the email field with.
77 */
78 public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL";
79
80 /**
81 * Keep track of the login task to ensure we can cancel it if requested.
82 */
83 private UserLoginTask mAuthTask = null;
84
85 // Values for email and password at the time of the login attempt.
86 private String mUser;
87 private String mPassword;
88 private Context mContext;
89
90 // UI references.
91 private EditText mUserView;
92 private EditText mPasswordView;
93 private View mLoginFormView;
94 private View mLoginStatusView;
95 private TextView mLoginStatusMessageView;
96
97 private AccountManager mAccountManager;
98
99 private String mURL;
100 private EditText mURLView;
101
102 private String mAccountname;
103 private EditText mAccountnameView;
104
105 public AuthenticatorActivity() {
106 super();
107
108 }
109
110 @Override
111 protected void onCreate(Bundle savedInstanceState) {
112 super.onCreate(savedInstanceState);
113
114 mAccountManager = AccountManager.get(this);
115
116 setContentView(R.layout.activity_authenticator);
117
118 // Set up the login form.
119 mUser = getIntent().getStringExtra(EXTRA_EMAIL);
120 mUserView = (EditText) findViewById(R.id.user);
121 mUserView.setText(mUser);
122
123 mContext = getBaseContext();
124
125 mPasswordView = (EditText) findViewById(R.id.password);
126 mPasswordView
127 .setOnEditorActionListener(new TextView.OnEditorActionListener() {
128 @Override
129 public boolean onEditorAction(TextView textView, int id,
130 KeyEvent keyEvent) {
131 if (id == R.id.login || id == EditorInfo.IME_NULL) {
132 attemptLogin();
133 return true;
134 }
135 return false;
136 }
137 });
138
139
140 mURLView = (EditText) findViewById(R.id.url);
141
142 mAccountnameView = (EditText) findViewById(R.id.accountname);
143
144 mLoginFormView = findViewById(R.id.login_form);
145 mLoginStatusView = findViewById(R.id.login_status);
146 mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);
147
148 findViewById(R.id.sign_in_button).setOnClickListener(
149 new View.OnClickListener() {
150 @Override
151 public void onClick(View view) {
152 attemptLogin();
153 }
154 });
155
156
157 }
158
159 @Override
160 public boolean onCreateOptionsMenu(Menu menu) {
161 super.onCreateOptionsMenu(menu);
162 getMenuInflater().inflate(R.menu.activity_authenticator, menu);
163 return true;
164 }
165
166 /**
167 * Attempts to sign in or register the account specified by the login form.
168 * If there are form errors (invalid email, missing fields, etc.), the
169 * errors are presented and no actual login attempt is made.
170 */
171 public void attemptLogin() {
172 if (mAuthTask != null) {
173 return;
174 }
175
176 // Reset errors.
177 mUserView.setError(null);
178 mPasswordView.setError(null);
179
180 // Store values at the time of the login attempt.
181 mUser = mUserView.getText().toString();
182 mPassword = mPasswordView.getText().toString();
183 mURL = mURLView.getText().toString();
184 mAccountname = mAccountnameView.getText().toString();
185
186 boolean cancel = false;
187 View focusView = null;
188
189 if (!mAccountname.equals("")) {
190 Account TestAccount = new Account(mAccountname, ACCOUNT_TYPE);
191 String TestUrl = mAccountManager.getUserData(TestAccount, AuthenticatorActivity.USER_DATA_URL_KEY);
192 if (TestUrl != null) {
193 mAccountnameView.setError(getString(R.string.error_account_already_in_use));
194 focusView = mAccountnameView;
195 cancel = true;
196 }
197 }
198
199 // Check for a valid password.
200 if (TextUtils.isEmpty(mPassword)) {
201 mPasswordView.setError(getString(R.string.error_field_required));
202 focusView = mPasswordView;
203 cancel = true;
204 } else if (mPassword.length() < 4) {
205 mPasswordView.setError(getString(R.string.error_invalid_password));
206 focusView = mPasswordView;
207 cancel = true;
208 }
209
210 // Check for a valid email address.
211 if (TextUtils.isEmpty(mUser)) {
212 mUserView.setError(getString(R.string.error_field_required));
213 focusView = mUserView;
214 cancel = true;
215 }
216 //else if (!mUser.contains("@")) {
217 // mUserView.setError(getString(R.string.error_invalid_email));
218 // focusView = mUserView;
219 // cancel = true;
220 //}
221
222 if (cancel) {
223 // There was an error; don't attempt login and focus the first
224 // form field with an error.
225 focusView.requestFocus();
226 } else {
227 // Show a progress spinner, and kick off a background task to
228 // perform the user login attempt.
229 mLoginStatusMessageView.setText(R.string.login_progress_signing_in);
230 showProgress(true);
231 mAuthTask = new UserLoginTask();
232 mAuthTask.execute((Void) null);
233 }
234 }
235
236 /**
237 * Shows the progress UI and hides the login form.
238 */
239 @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
240 private void showProgress(final boolean show) {
241 // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
242 // for very easy animations. If available, use these APIs to fade-in
243 // the progress spinner.
244 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
245 int shortAnimTime = getResources().getInteger(
246 android.R.integer.config_shortAnimTime);
247
248 mLoginStatusView.setVisibility(View.VISIBLE);
249 mLoginStatusView.animate().setDuration(shortAnimTime)
250 .alpha(show ? 1 : 0)
251 .setListener(new AnimatorListenerAdapter() {
252 @Override
253 public void onAnimationEnd(Animator animation) {
254 mLoginStatusView.setVisibility(show ? View.VISIBLE
255 : View.GONE);
256 }
257 });
258
259 mLoginFormView.setVisibility(View.VISIBLE);
260 mLoginFormView.animate().setDuration(shortAnimTime)
261 .alpha(show ? 0 : 1)
262 .setListener(new AnimatorListenerAdapter() {
263 @Override
264 public void onAnimationEnd(Animator animation) {
265 mLoginFormView.setVisibility(show ? View.GONE
266 : View.VISIBLE);
267 }
268 });
269 } else {
270 // The ViewPropertyAnimator APIs are not available, so simply show
271 // and hide the relevant UI components.
272 mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
273 mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
274 }
275 }
276
277
278 protected enum LoginResult {
279 MalformedURLException,
280 GeneralSecurityException,
281 UnkonwnException,
282 WrongCredentials,
283 InvalidResponse,
284 WrongUrl,
285 ConnectionRefused,
286 Success_Calendar,
287 Success_Collection,
288 Account_Already_In_Use
289 }
290
291
292 /**
293 * Represents an asynchronous login/registration task used to authenticate
294 * the user.
295 */
296 public class UserLoginTask extends AsyncTask<Void, Void, LoginResult> {
297
298 @Override
299 protected LoginResult doInBackground(Void... params) {
300
301 TestConnectionResult result = null;
302
303 try {
304 CaldavFacade facade = new CaldavFacade(mUser, mPassword, mURL);
305 String version = "";
306 try {
307 version = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName;
308 } catch (NameNotFoundException e) {
309 version = "unknown";
310 e.printStackTrace();
311 }
312 facade.setVersion(version);
313 result = facade.testConnection();
314 Log.i(TAG, "testConnection status="+result);
315 } catch (HttpHostConnectException e) {
316 Log.w(TAG,"testConnection", e);
317 return LoginResult.ConnectionRefused;
318 } catch (MalformedURLException e) {
319 Log.w(TAG,"testConnection", e);
320 return LoginResult.MalformedURLException;
321 } catch (UnsupportedEncodingException e) {
322 Log.w(TAG,"testConnection", e);
323 return LoginResult.UnkonwnException;
324 } catch (ParserConfigurationException e) {
325 Log.w(TAG,"testConnection", e);
326 return LoginResult.UnkonwnException;
327 } catch (SAXException e) {
328 Log.w(TAG,"testConnection", e);
329 return LoginResult.InvalidResponse;
330 } catch (IOException e) {
331 Log.w(TAG,"testConnection", e);
332 return LoginResult.UnkonwnException;
333 } catch (URISyntaxException e) {
334 Log.w(TAG,"testConnection", e);
335 return LoginResult.MalformedURLException;
336 }
337
338 if (result == null) {
339 return LoginResult.UnkonwnException;
340 }
341
342 switch (result) {
343
344 case SUCCESS:
345 boolean OldAccount = false;
346 LoginResult Result = LoginResult.Success_Calendar;
347
348 if (OldAccount) {
349 final Account account = new Account(mUser, ACCOUNT_TYPE);
350 if (mAccountManager.addAccountExplicitly(account, mPassword, null)) {
351 Log.v(TAG,"new account created");
352 mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL);
353 } else {
354 Log.v(TAG,"no new account created");
355 Result = LoginResult.Account_Already_In_Use;
356 }
357 } else {
358 final Account account;
359 if (mAccountname.equals("")) {
360 account = new Account(mUser + ACCOUNT_NAME_SPLITTER + mURL, ACCOUNT_TYPE);
361 } else {
362 account = new Account(mAccountname, ACCOUNT_TYPE);
363 }
364 if (mAccountManager.addAccountExplicitly(account, mPassword, null)) {
365 Log.v(TAG,"new account created");
366 mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL);
367 mAccountManager.setUserData(account, USER_DATA_USERNAME, mUser);
368 mAccountManager.setUserData(account, USER_DATA_VERSION, CURRENT_USER_DATA_VERSION);
369 } else {
370 Log.v(TAG,"no new account created");
371 Result = LoginResult.Account_Already_In_Use;
372 }
373 }
374
375 return Result;
376
377 case WRONG_CREDENTIAL:
378 return LoginResult.WrongCredentials;
379
380 case WRONG_SERVER_STATUS:
381 return LoginResult.InvalidResponse;
382
383 case WRONG_URL:
384 return LoginResult.WrongUrl;
385
386 case WRONG_ANSWER:
387 return LoginResult.InvalidResponse;
388
389 default:
390 return LoginResult.UnkonwnException;
391
392 }
393
394 }
395
396
397 @Override
398 protected void onPostExecute(final LoginResult result) {
399 mAuthTask = null;
400 showProgress(false);
401
402 int duration = Toast.LENGTH_SHORT;
403 Toast toast = null;
404
405 switch (result) {
406 case Success_Calendar:
407 toast = Toast.makeText(getApplicationContext(), R.string.success_calendar, duration);
408 toast.show();
409 finish();
410 break;
411
412 case Success_Collection:
413 toast = Toast.makeText(getApplicationContext(), R.string.success_collection, duration);
414 toast.show();
415 finish();
416 break;
417
418 case MalformedURLException:
419
420 toast = Toast.makeText(getApplicationContext(), R.string.error_incorrect_url_format, duration);
421 toast.show();
422 mURLView.setError(getString(R.string.error_incorrect_url_format));
423 mURLView.requestFocus();
424 break;
425 case InvalidResponse:
426 toast = Toast.makeText(getApplicationContext(), R.string.error_invalid_server_answer, duration);
427 toast.show();
428 mURLView.setError(getString(R.string.error_invalid_server_answer));
429 mURLView.requestFocus();
430 break;
431 case WrongUrl:
432 toast = Toast.makeText(getApplicationContext(), R.string.error_wrong_url, duration);
433 toast.show();
434 mURLView.setError(getString(R.string.error_wrong_url));
435 mURLView.requestFocus();
436 break;
437
438 case WrongCredentials:
439 mPasswordView.setError(getString(R.string.error_incorrect_password));
440 mPasswordView.requestFocus();
441 break;
442
443 case ConnectionRefused:
444 toast = Toast.makeText(getApplicationContext(), R.string.error_connection_refused, duration);
445 toast.show();
446 mURLView.setError(getString(R.string.error_connection_refused));
447 mURLView.requestFocus();
448 break;
449 case Account_Already_In_Use:
450 toast = Toast.makeText(getApplicationContext(), R.string.error_account_already_in_use, duration);
451 toast.show();
452 mURLView.setError(getString(R.string.error_account_already_in_use));
453 mURLView.requestFocus();
454 break;
455 default:
456 toast = Toast.makeText(getApplicationContext(), R.string.error_unkown_error, duration);
457 toast.show();
458 mURLView.setError(getString(R.string.error_unkown_error));
459 mURLView.requestFocus();
460 break;
461 }
462
463
464
465
466 }
467
468 @Override
469 protected void onCancelled() {
470 mAuthTask = null;
471 showProgress(false);
472 }
473 }
474 }

mercurial