Java tutorial
/* * 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.rukman.emde.smsgroups.authenticator; import org.json.JSONObject; import android.accounts.Account; import android.accounts.AccountManager; import android.content.ContentResolver; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.Window; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.rukman.emde.smsgroups.GMSApplication; import com.rukman.emde.smsgroups.R; import com.rukman.emde.smsgroups.client.NetworkUtilities; import com.rukman.emde.smsgroups.data.GMSProvider; import com.rukman.emde.smsgroups.fragments.ProgressDialogFragment; /** * Activity which displays login screen to the user. */ public class GMSAuthenticatorActivity extends AccountAuthenticatorFragmentActivity { /** 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 password. */ public static final String PARAM_EMAIL = "email"; /** The Intent extra to store username. */ public static final String PARAM_PHONE = "phone"; /** 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; /** Keep track of the login task so can cancel it if requested */ private AsyncTask<Void, Void, String> mAuthTask = null; /** * If set we are just checking that the user knows their credentials; this * doesn't cause the user's password or authToken to be changed on the * device. */ private Boolean mConfirmCredentials = false; private TextView mMessage; private EditText mPasswordEdit; /** Was the original caller did not know the user name */ protected boolean mIsUnknownAccountName = false; private String mUsername; private String mPassword; private String mEmail; private String mPhone; private EditText mUsernameEdit; private EditText mEmailEdit; private EditText mPhoneEdit; private static final String PROGRESS = "authenticating_progress"; /** * {@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); mIsUnknownAccountName = mUsername == null; mConfirmCredentials = intent.getBooleanExtra(PARAM_CONFIRM_CREDENTIALS, false); Log.i(TAG, "IsUnknownAccount? : " + mIsUnknownAccountName); 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); mEmailEdit = (EditText) findViewById(R.id.email_edit); mPhoneEdit = (EditText) findViewById(R.id.phone_edit); ((CheckBox) findViewById(R.id.new_account_box)).setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { findViewById(R.id.registration_layout).setVisibility(isChecked ? View.VISIBLE : View.GONE); } }); if (!TextUtils.isEmpty(mUsername)) { mUsernameEdit.setText(mUsername); } mMessage.setText(getMessage()); } /** * Handles onClick event on the Submit button. Sends username/password to * the server for authentication. The button is configured to call * handleLogin() in the layout XML. * * @param view The Submit button for which this method is invoked */ public void handleLogin(View view) { if (mIsUnknownAccountName) { mUsername = mUsernameEdit.getText().toString(); } mEmail = mEmailEdit.getText().toString(); mPhone = mPhoneEdit.getText().toString(); mPassword = mPasswordEdit.getText().toString(); // Simple validation if (((CheckBox) findViewById(R.id.new_account_box)).isChecked()) { // Check all the fields if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword) || TextUtils.isEmpty(mEmail) || TextUtils.isEmpty(mPhone)) { mMessage.setText(getMessage()); } else { // Show a progress dialog, and kick off a background task to perform // the user login attempt. showProgress(); mAuthTask = new UserRegistrationTask(); mAuthTask.execute(); } } else { if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword)) { mMessage.setText(getMessage()); } else { // Show a progress dialog, and kick off a background task to perform // the user login attempt. showProgress(); mAuthTask = new UserLoginTask(); mAuthTask.execute(); } } } /** * 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 result the confirmCredentials result. */ private void finishConfirmCredentials(boolean result) { Log.i(TAG, "finishConfirmCredentials()"); final Account account = new Account(mUsername, GMSApplication.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. We store the * authToken that's returned from the server as the 'password' for this * account - so we're never storing the user's actual password locally. * * @param result the confirmCredentials result. */ private void finishLogin(String authToken) { Log.i(TAG, "finishLogin()"); final Account account = new Account(mUsername, GMSApplication.ACCOUNT_TYPE); if (mIsUnknownAccountName) { mAccountManager.addAccountExplicitly(account, mPassword, null); // Set contacts sync for this account. ContentResolver.setIsSyncable(account, GMSProvider.AUTHORITY, 1); ContentResolver.setSyncAutomatically(account, GMSProvider.AUTHORITY, true); } else { mAccountManager.setPassword(account, mPassword); } final Intent intent = new Intent(); intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername); intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, GMSApplication.ACCOUNT_TYPE); setAccountAuthenticatorResult(intent.getExtras()); setResult(RESULT_OK, intent); finish(); } /** * Called when the authentication process completes (see attemptLogin()). * * @param authToken the authentication token returned by the server, or NULL if * authentication failed. */ public void onAuthenticationResult(String authToken) { boolean success = ((authToken != null) && (authToken.length() > 0)); Log.i(TAG, "onAuthenticationResult(" + success + ")"); // Our task is complete, so clear it out mAuthTask = null; // Hide the progress dialog hideProgress(); if (success) { if (!mConfirmCredentials) { finishLogin(authToken); } else { finishConfirmCredentials(success); } } else { Log.e(TAG, "onAuthenticationResult: failed to authenticate"); if (mIsUnknownAccountName) { // "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)); } } } public void onAuthenticationCancel() { Log.i(TAG, "onAuthenticationCancel()"); // Our task is complete, so clear it out mAuthTask = null; // Hide the progress dialog hideProgress(); } /** * 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() { final ProgressDialogFragment dialog = ProgressDialogFragment .newInstance(R.string.ui_activity_authenticating, R.string.ui_activity_authenticating); dialog.show(getSupportFragmentManager(), PROGRESS); } /** * Hides the progress UI for a lengthy operation. */ private void hideProgress() { DialogFragment dialog = (DialogFragment) getSupportFragmentManager().findFragmentByTag(PROGRESS); if (dialog != null) { dialog.dismiss(); } } /** * Called when the authentication process completes (see attemptLogin()). * * @param authToken the authentication token returned by the server, or NULL if * authentication failed. */ public void onRegistrationResult(JSONObject object) { // Our task is complete, so clear it out mAuthTask = null; // Hide the progress dialog hideProgress(); if (object != null) { Log.e(TAG, "onRegistrationResult: Registration succeeded"); Toast.makeText(this, R.string.login_activity_registration_success_text, Toast.LENGTH_SHORT).show(); } else { Log.e(TAG, "onRegistrationResult: failed register"); mMessage.setText(getText(R.string.login_activity_registration_fail_text)); } } public void onRegistrationCancel() { Log.i(TAG, "onAuthenticationCancel()"); // Our task is complete, so clear it out mAuthTask = null; // Hide the progress dialog hideProgress(); } /** * Represents an asynchronous task used to register a user with the GMS service */ private class UserRegistrationTask extends AsyncTask<Void, Void, String> { @Override protected String doInBackground(Void... params) { String result = null; try { result = NetworkUtilities.register(mUsername, mPassword, mEmail, mPhone); if (result != null) { result = NetworkUtilities.authenticate(mUsername, mPassword); } } catch (Exception ex) { Log.e(TAG, "UserRegistrationTask.doInBackground: Failure in network layer"); Log.i(TAG, ex.toString()); } return result; } @Override protected void onPostExecute(final String authToken) { // On a successful authentication, call back into the Activity to // communicate the authToken (or null for an error). onAuthenticationResult(authToken); } @Override protected void onCancelled() { // If the action was canceled (by the user clicking the cancel // button in the progress dialog), then call back into the // activity to let it know. onAuthenticationCancel(); } } /** * Represents an asynchronous task used to authenticate a user against the * SampleSync Service */ public class UserLoginTask extends AsyncTask<Void, Void, String> { @Override protected String doInBackground(Void... params) { // We do the actual work of authenticating the user // in the NetworkUtilities class. try { return NetworkUtilities.authenticate(mUsername, mPassword); } catch (Exception ex) { Log.e(TAG, "UserLoginTask.doInBackground: failed to authenticate"); Log.i(TAG, ex.toString()); return null; } } @Override protected void onPostExecute(final String authToken) { // On a successful authentication, call back into the Activity to // communicate the authToken (or null for an error). onAuthenticationResult(authToken); } @Override protected void onCancelled() { // If the action was canceled (by the user clicking the cancel // button in the progress dialog), then call back into the // activity to let it know. onAuthenticationCancel(); } } }