1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.example.android.samplesync.authenticator; 18 19 import android.accounts.Account; 20 import android.accounts.AccountAuthenticatorActivity; 21 import android.accounts.AccountManager; 22 import android.app.Dialog; 23 import android.app.ProgressDialog; 24 import android.content.ContentResolver; 25 import android.content.DialogInterface; 26 import android.content.Intent; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.provider.ContactsContract; 30 import android.text.TextUtils; 31 import android.util.Log; 32 import android.view.View; 33 import android.view.Window; 34 import android.widget.EditText; 35 import android.widget.TextView; 36 37 import com.example.android.samplesync.Constants; 38 import com.example.android.samplesync.R; 39 import com.example.android.samplesync.client.NetworkUtilities; 40 41 /** 42 * Activity which displays login screen to the user. 43 */ 44 public class AuthenticatorActivity extends AccountAuthenticatorActivity { 45 public static final String PARAM_CONFIRMCREDENTIALS = "confirmCredentials"; 46 public static final String PARAM_PASSWORD = "password"; 47 public static final String PARAM_USERNAME = "username"; 48 public static final String PARAM_AUTHTOKEN_TYPE = "authtokenType"; 49 50 private static final String TAG = "AuthenticatorActivity"; 51 52 private AccountManager mAccountManager; 53 private Thread mAuthThread; 54 private String mAuthtoken; 55 private String mAuthtokenType; 56 57 /** 58 * If set we are just checking that the user knows their credentials; this 59 * doesn't cause the user's password to be changed on the device. 60 */ 61 private Boolean mConfirmCredentials = false; 62 63 /** for posting authentication attempts back to UI thread */ 64 private final Handler mHandler = new Handler(); 65 private TextView mMessage; 66 private String mPassword; 67 private EditText mPasswordEdit; 68 69 /** Was the original caller asking for an entirely new account? */ 70 protected boolean mRequestNewAccount = false; 71 72 private String mUsername; 73 private EditText mUsernameEdit; 74 75 /** 76 * {@inheritDoc} 77 */ 78 @Override 79 public void onCreate(Bundle icicle) { 80 Log.i(TAG, "onCreate(" + icicle + ")"); 81 super.onCreate(icicle); 82 mAccountManager = AccountManager.get(this); 83 Log.i(TAG, "loading data from Intent"); 84 final Intent intent = getIntent(); 85 mUsername = intent.getStringExtra(PARAM_USERNAME); 86 mAuthtokenType = intent.getStringExtra(PARAM_AUTHTOKEN_TYPE); 87 mRequestNewAccount = mUsername == null; 88 mConfirmCredentials = 89 intent.getBooleanExtra(PARAM_CONFIRMCREDENTIALS, false); 90 91 Log.i(TAG, " request new: " + mRequestNewAccount); 92 requestWindowFeature(Window.FEATURE_LEFT_ICON); 93 setContentView(R.layout.login_activity); 94 getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, 95 android.R.drawable.ic_dialog_alert); 96 97 mMessage = (TextView) findViewById(R.id.message); 98 mUsernameEdit = (EditText) findViewById(R.id.username_edit); 99 mPasswordEdit = (EditText) findViewById(R.id.password_edit); 100 101 mUsernameEdit.setText(mUsername); 102 mMessage.setText(getMessage()); 103 } 104 105 /* 106 * {@inheritDoc} 107 */ 108 @Override 109 protected Dialog onCreateDialog(int id) { 110 final ProgressDialog dialog = new ProgressDialog(this); 111 dialog.setMessage(getText(R.string.ui_activity_authenticating)); 112 dialog.setIndeterminate(true); 113 dialog.setCancelable(true); 114 dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { 115 public void onCancel(DialogInterface dialog) { 116 Log.i(TAG, "dialog cancel has been invoked"); 117 if (mAuthThread != null) { 118 mAuthThread.interrupt(); 119 finish(); 120 } 121 } 122 }); 123 return dialog; 124 } 125 126 /** 127 * Handles onClick event on the Submit button. Sends username/password to 128 * the server for authentication. 129 * 130 * @param view The Submit button for which this method is invoked 131 */ 132 public void handleLogin(View view) { 133 if (mRequestNewAccount) { 134 mUsername = mUsernameEdit.getText().toString(); 135 } 136 mPassword = mPasswordEdit.getText().toString(); 137 if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword)) { 138 mMessage.setText(getMessage()); 139 } else { 140 showProgress(); 141 // Start authenticating... 142 mAuthThread = 143 NetworkUtilities.attemptAuth(mUsername, mPassword, mHandler, 144 AuthenticatorActivity.this); 145 } 146 } 147 148 /** 149 * Called when response is received from the server for confirm credentials 150 * request. See onAuthenticationResult(). Sets the 151 * AccountAuthenticatorResult which is sent back to the caller. 152 * 153 * @param the confirmCredentials result. 154 */ 155 protected void finishConfirmCredentials(boolean result) { 156 Log.i(TAG, "finishConfirmCredentials()"); 157 final Account account = new Account(mUsername, Constants.ACCOUNT_TYPE); 158 mAccountManager.setPassword(account, mPassword); 159 final Intent intent = new Intent(); 160 intent.putExtra(AccountManager.KEY_BOOLEAN_RESULT, result); 161 setAccountAuthenticatorResult(intent.getExtras()); 162 setResult(RESULT_OK, intent); 163 finish(); 164 } 165 166 /** 167 * 168 * Called when response is received from the server for authentication 169 * request. See onAuthenticationResult(). Sets the 170 * AccountAuthenticatorResult which is sent back to the caller. Also sets 171 * the authToken in AccountManager for this account. 172 * 173 * @param the confirmCredentials result. 174 */ 175 176 protected void finishLogin() { 177 Log.i(TAG, "finishLogin()"); 178 final Account account = new Account(mUsername, Constants.ACCOUNT_TYPE); 179 180 if (mRequestNewAccount) { 181 mAccountManager.addAccountExplicitly(account, mPassword, null); 182 // Set contacts sync for this account. 183 ContentResolver.setSyncAutomatically(account, 184 ContactsContract.AUTHORITY, true); 185 } else { 186 mAccountManager.setPassword(account, mPassword); 187 } 188 final Intent intent = new Intent(); 189 mAuthtoken = mPassword; 190 intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername); 191 intent 192 .putExtra(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE); 193 if (mAuthtokenType != null 194 && mAuthtokenType.equals(Constants.AUTHTOKEN_TYPE)) { 195 intent.putExtra(AccountManager.KEY_AUTHTOKEN, mAuthtoken); 196 } 197 setAccountAuthenticatorResult(intent.getExtras()); 198 setResult(RESULT_OK, intent); 199 finish(); 200 } 201 202 /** 203 * Hides the progress UI for a lengthy operation. 204 */ 205 protected void hideProgress() { 206 dismissDialog(0); 207 } 208 209 /** 210 * Called when the authentication process completes (see attemptLogin()). 211 */ 212 public void onAuthenticationResult(boolean result) { 213 Log.i(TAG, "onAuthenticationResult(" + result + ")"); 214 // Hide the progress dialog 215 hideProgress(); 216 if (result) { 217 if (!mConfirmCredentials) { 218 finishLogin(); 219 } else { 220 finishConfirmCredentials(true); 221 } 222 } else { 223 Log.e(TAG, "onAuthenticationResult: failed to authenticate"); 224 if (mRequestNewAccount) { 225 // "Please enter a valid username/password. 226 mMessage 227 .setText(getText(R.string.login_activity_loginfail_text_both)); 228 } else { 229 // "Please enter a valid password." (Used when the 230 // account is already in the database but the password 231 // doesn't work.) 232 mMessage 233 .setText(getText(R.string.login_activity_loginfail_text_pwonly)); 234 } 235 } 236 } 237 238 /** 239 * Returns the message to be displayed at the top of the login dialog box. 240 */ 241 private CharSequence getMessage() { 242 getString(R.string.label); 243 if (TextUtils.isEmpty(mUsername)) { 244 // If no username, then we ask the user to log in using an 245 // appropriate service. 246 final CharSequence msg = 247 getText(R.string.login_activity_newaccount_text); 248 return msg; 249 } 250 if (TextUtils.isEmpty(mPassword)) { 251 // We have an account but no password 252 return getText(R.string.login_activity_loginfail_text_pwmissing); 253 } 254 return null; 255 } 256 257 /** 258 * Shows the progress UI for a lengthy operation. 259 */ 260 protected void showProgress() { 261 showDialog(0); 262 } 263 } 264