Java tutorial
// ClearOS Mobile Demo: Example Android Application // Copyright (C) 2012 ClearFoundation <http://www.clearfoundation.com> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. package com.clearcenter.mobile_demo; import com.clearcenter.mobile_demo.mdConstants; import com.clearcenter.mobile_demo.mdRest; import com.clearcenter.mobile_demo.mdSSLUtil; import com.clearcenter.mobile_demo.providers.mdContentProvider; import com.clearcenter.mobile_demo.R; import android.accounts.Account; import android.accounts.AccountAuthenticatorActivity; import android.accounts.AccountManager; import android.app.Dialog; import android.app.NotificationManager; import android.app.ProgressDialog; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.Window; import android.widget.EditText; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; import java.security.GeneralSecurityException; import org.json.JSONException; public class mdAuthenticatorActivity extends AccountAuthenticatorActivity { // The tag used to log to adb console. private static final String TAG = "mdAuthenticatorActivity"; // The Intent flag to confirm credentials. public static final String PARAM_CONFIRM_CREDENTIALS = "confirmCredentials"; // The Intent extra to store nickname. public static final String PARAM_NICKNAME = "nickname"; // The Intent extra to store hostname. public static final String PARAM_HOSTNAME = "hostname"; // The Intent extra to store username. public static final String PARAM_USERNAME = "username"; // The Intent extra to store password. public static final String PARAM_PASSWORD = "password"; // The Intent extra to store authtoken type. public static final String PARAM_AUTHTOKEN_TYPE = "authtokenType"; // The account manager. private AccountManager account_manager; // Keep track of the login task so can cancel it if requested private UserLoginTask auth_task = null; // Keep track of the progress dialog so we can dismiss it private ProgressDialog progress_dialog = 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 confirm_credentials = false; // Was the original caller asking for an entirely new account? protected boolean request_new_account = false; // For posting authentication attempts back to UI thread. private final Handler handler = new Handler(); private ScrollView scroll_view; private TextView message; private String nickname; private TextView nickname_label; private EditText nickname_edit; private String hostname; private TextView hostname_label; private EditText hostname_edit; private String username; private TextView username_label; private EditText username_edit; private String password; private EditText password_edit; public void onCreate(Bundle bundle) { Log.i(TAG, "onCreate(" + bundle + ")"); super.onCreate(bundle); setContentView(R.layout.login_activity); account_manager = AccountManager.get(this); Log.i(TAG, "loading data from Intent"); final Intent intent = getIntent(); nickname = intent.getStringExtra(PARAM_NICKNAME); username = intent.getStringExtra(PARAM_USERNAME); hostname = intent.getStringExtra(PARAM_HOSTNAME); request_new_account = nickname == null; confirm_credentials = intent.getBooleanExtra(PARAM_CONFIRM_CREDENTIALS, false); Log.i(TAG, "new account? " + request_new_account + ", confirm credentials? " + confirm_credentials); scroll_view = (ScrollView) findViewById(R.id.scroll_view); message = (TextView) findViewById(R.id.message); nickname_label = (TextView) findViewById(R.id.nickname_label); nickname_edit = (EditText) findViewById(R.id.nickname_edit); nickname_label.setVisibility(request_new_account ? View.VISIBLE : View.GONE); nickname_edit.setVisibility(request_new_account ? View.VISIBLE : View.GONE); if (nickname != null) nickname_edit.setText(nickname); hostname_label = (TextView) findViewById(R.id.hostname_label); hostname_edit = (EditText) findViewById(R.id.hostname_edit); hostname_label.setVisibility(request_new_account ? View.VISIBLE : View.GONE); hostname_edit.setVisibility(request_new_account ? View.VISIBLE : View.GONE); if (hostname != null) hostname_edit.setText(hostname); username_label = (TextView) findViewById(R.id.username_label); username_edit = (EditText) findViewById(R.id.username_edit); username_label.setVisibility(request_new_account ? View.VISIBLE : View.GONE); username_edit.setVisibility(request_new_account ? View.VISIBLE : View.GONE); if (username != null) username_edit.setText(username); password_edit = (EditText) findViewById(R.id.password_edit); if (confirm_credentials) { String ns = Context.NOTIFICATION_SERVICE; NotificationManager notification_manager; notification_manager = (NotificationManager) getApplicationContext().getSystemService(ns); notification_manager.cancelAll(); Log.i(TAG, "TODO: Cancel all notifications?"); } if (!TextUtils.isEmpty(nickname)) nickname_edit.setText(nickname); if (request_new_account) message.setText(getText(R.string.login_activity_new_account)); else if (confirm_credentials) { message.setText(getText(R.string.login_activity_confirm_credentials)); } try { mdSSLUtil.DisableSecurity(); } catch (GeneralSecurityException e) { Toast.makeText(getApplicationContext(), e.getMessage(), 4).show(); } } //protected Dialog onCreateDialog(int id, Bundle args) protected Dialog onCreateDialog(int id) { final ProgressDialog dialog = new ProgressDialog(this); dialog.setMessage(getText(R.string.login_activity_authenticating)); dialog.setIndeterminate(true); dialog.setCancelable(true); dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { Log.i(TAG, "user cancelling authentication"); if (auth_task != null) { auth_task.cancel(true); } } }); // We save off the progress dialog in a field so that we can dismiss // it later. We can't just call dismissDialog(0) because the system // can lose track of our dialog if there's an orientation change. progress_dialog = dialog; return dialog; } // 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. public void handleLogin(View view) { if (request_new_account) Log.i(TAG, "handleLogin: new account"); else Log.i(TAG, "handleLogin: existing account"); nickname = nickname_edit.getText().toString(); hostname = hostname_edit.getText().toString(); username = username_edit.getText().toString(); password = password_edit.getText().toString(); final Account accounts[] = account_manager.getAccountsByType(mdConstants.ACCOUNT_TYPE); for (Account account : accounts) { if (request_new_account && TextUtils.equals(account.name, nickname)) { message.setText(getText(R.string.login_activity_duplicate_account)); scroll_view.smoothScrollTo(0, 0); nickname_edit.requestFocus(); nickname_edit.setSelected(true); return; } Log.i(TAG, account.name + " != " + nickname); } if (request_new_account) { if (TextUtils.isEmpty(nickname)) { message.setText(getText(R.string.login_activity_null_nickname)); scroll_view.smoothScrollTo(0, 0); nickname_edit.requestFocus(); nickname_edit.setSelected(true); return; } if (TextUtils.isEmpty(hostname)) { message.setText(getText(R.string.login_activity_null_hostname)); scroll_view.smoothScrollTo(0, 0); hostname_edit.requestFocus(); hostname_edit.setSelected(true); return; } if (TextUtils.isEmpty(username)) { message.setText(getText(R.string.login_activity_null_username)); scroll_view.smoothScrollTo(0, 0); username_edit.requestFocus(); username_edit.setSelected(true); return; } } if (TextUtils.isEmpty(password)) { message.setText(getText(R.string.login_activity_null_password)); scroll_view.smoothScrollTo(0, 0); password_edit.requestFocus(); password_edit.setSelected(true); return; } // Show a progress dialog, and kick off a background task to perform // the user login attempt. showProgress(); auth_task = new UserLoginTask(); auth_task.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. private void finishConfirmCredentials(boolean result, String authToken) { Log.i(TAG, "finishConfirmCredentials()"); final Account account = new Account(nickname, mdConstants.ACCOUNT_TYPE); if (result) account_manager.setPassword(account, authToken); 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. private void finishLogin(String authToken) { Log.i(TAG, "finishLogin()"); final Account account = new Account(nickname, mdConstants.ACCOUNT_TYPE); if (request_new_account) { account_manager.addAccountExplicitly(account, authToken, null); account_manager.setUserData(account, "hostname", hostname); account_manager.setUserData(account, "username", username); // Set system info sync for this account. final Bundle extras = new Bundle(); ContentResolver.setSyncAutomatically(account, mdContentProvider.AUTHORITY, true); if (android.os.Build.VERSION.SDK_INT >= 8) { ContentResolver.addPeriodicSync(account, mdContentProvider.AUTHORITY, extras, 10); } } else account_manager.setPassword(account, authToken); final Intent intent = new Intent(); intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, nickname); intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, mdConstants.ACCOUNT_TYPE); setAccountAuthenticatorResult(intent.getExtras()); setResult(RESULT_OK, intent); ContentResolver.requestSync(account, mdContentProvider.AUTHORITY, new Bundle()); finish(); } // Called when the authentication process completes (see attemptLogin()). 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 auth_task = null; // Hide the progress dialog hideProgress(); if (success) { if (!confirm_credentials) finishLogin(authToken); else finishConfirmCredentials(success, authToken); } else { Log.e(TAG, "onAuthenticationResult: failed to authenticate"); if (request_new_account) { // "Please enter a valid username/password. message.setText(getText(R.string.login_activity_bad_account)); scroll_view.smoothScrollTo(0, 0); username_edit.requestFocus(); username_edit.setSelected(true); } else { // "Please enter a valid password." (Used when the // account is already in the database but the password // doesn't work.) message.setText(getText(R.string.login_activity_bad_password)); scroll_view.smoothScrollTo(0, 0); password_edit.requestFocus(); password_edit.setSelected(true); } } } public void onAuthenticationCancel() { Log.i(TAG, "onAuthenticationCancel()"); // Our task is complete, so clear it out auth_task = null; // Hide the progress dialog hideProgress(); } // Shows the progress UI for a lengthy operation. private void showProgress() { showDialog(0); } // Hides the progress UI for a lengthy operation. private void hideProgress() { if (progress_dialog != null) { progress_dialog.dismiss(); progress_dialog = null; } } // Represents an asynchronous task used to authenticate a user against the // ClearOS Server public class UserLoginTask extends AsyncTask<Void, Void, String> { protected String doInBackground(Void... params) { // We do the actual work of authenticating the user // in the mdRest class. try { return mdRest.Login(hostname, username, password, null); } catch (Exception e) { Log.e(TAG, "UserLoginTask.doInBackground: failed to authenticate", e); return null; } } 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); } 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(); } } } // vi: expandtab shiftwidth=4 softtabstop=4 tabstop=4