package org.sana.android.activity; import org.sana.R; import org.sana.android.activity.settings.BasicSettings; import org.sana.android.app.Locales; import org.sana.android.content.Intents; import org.sana.android.content.Uris; import org.sana.android.provider.Observers; import org.sana.android.service.ISessionCallback; import org.sana.android.service.ISessionService; import org.sana.android.service.impl.SessionService; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import android.widget.TextView; /** * Activity that handles user authentication. When finishing with RESULT_OK, * will return a valid session key String or * {@link org.sana.android.service.impl.SessionService#INVALID INVALID} * as an Intent extra String keyed to {@link BaseActivity#SESSION_KEY}. * * @author Sana Dev Team */ public class AuthenticationActivity extends BaseActivity { public static final String TAG = AuthenticationActivity.class.getSimpleName(); // Session Related // Number of allowed authentication attempts private int loginsRemaining = 0; private int loginAttempts = 0; private final int maxLogins = 3; private boolean loginSuccessful = false; protected boolean mBound = false; protected ISessionService mService = null; // The callback to get data from the asynchronous calls private ISessionCallback mCallback = new ISessionCallback.Stub() { @Override public void onValueChanged(int arg0, String arg1, String arg2) throws RemoteException { Log.d(TAG, ".mCallback.onValueChanged( " +arg0 +", "+arg1+ ", " + arg2+ " )"); Bundle data = new Bundle(); data.putString(Intents.EXTRA_INSTANCE, arg1); data.putString(Intents.EXTRA_OBSERVER, arg2); Message response = Message.obtain(mHandler); response.setData(data); response.what = arg0; response.sendToTarget(); } }; // connector to the session service protected ServiceConnection mConnection = new ServiceConnection(){ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG, "ServiceConnection.onServiceConnected()"); mService = ISessionService.Stub.asInterface(service); mBound = true; registerCallback(); } @Override public void onServiceDisconnected(ComponentName name) { Log.i(TAG, "ServiceConnection.onServiceDisconnected()"); mService = null; mBound = false; } }; // This is the handler which responds to the SessionService // It expects a Message with msg.what = FAILURE or SUCCESS // and a Bundle with the new session key if successful. private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { Log.i(TAG, "handleMessage(): " + ((msg != null)?((msg.what == 1)? "success":"failure"):"null")); int state = msg.what; Intent data = null; cancelProgressDialogFragment(); switch(state){ case SessionService.FAILURE: loginsRemaining--; enableInput(); // TODO use a string resource Toast.makeText(AuthenticationActivity.this, String.format("%s. %s: %d", getString(R.string.msg_login_failed), getString(R.string.authentication_logins_remaining), loginsRemaining), Toast.LENGTH_SHORT).show(); break; case SessionService.SUCCESS: loginsRemaining = 0; loginSuccessful = true; Bundle b = msg.getData(); //(Bundle)msg.obj; Log.i(TAG,"...handleMessage(...) SUCCESS: "); for(String key:b.keySet()) Log.d(TAG+".handleMessage(...)", "...."+key +":"+ String.valueOf(b.get(key))); String uuid = b.getString(Intents.EXTRA_OBSERVER); Log.i(TAG,"...handleMessage(...) SUCCESS: observer=" + uuid); Uri uri = Uris.withAppendedUuid(Observers.CONTENT_URI, uuid); Log.i(TAG, uri.toString()); b.remove(Intents.EXTRA_OBSERVER); b.putParcelable(Intents.EXTRA_OBSERVER, uri); onUpdateAppState(b); data = new Intent(); data.setData(uri); data.putExtras(b); onSaveAppState(data); setResult(RESULT_OK,data); break; default: Log.e(TAG, "Should never get here"); } // Finish if remaining logins => 0 Log.i(TAG, "handleMessage(): logins remaining: " + loginsRemaining); if(loginsRemaining == 0){ if(!loginSuccessful){ setResult(RESULT_CANCELED); } finish(); } } }; // Views EditText mInputUsername; EditText mInputPassword; Button mBtnLogin; Button mBtnExit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentViewLocalized(R.layout.activity_authentication); showBuildString(R.id.text_local_version); mInputUsername = (EditText) findViewById(R.id.input_username); mInputPassword = (EditText) findViewById(R.id.input_password); loginsRemaining = getResources().getInteger(R.integer.max_login_attempts); loadCredentials(); } /* Loads the debug credentials from res/values/debug.xml if debug_credentials = true */ private final void loadCredentials(){ if(getResources().getBoolean(R.bool.debug_credentials)){ mInputUsername.setText(getString(R.string.debug_user)); mInputPassword.setText(getString(R.string.debug_password)); } } protected void showBuildString(int id){ TextView tv = (TextView) findViewById(id); // TODO Fix the getBuildString to read from the manifest correctly tv.setText(getBuildString()); //tv.setText(getString(R.string.display_version)); } private void disableInput(){ mInputUsername.setEnabled(false); mInputPassword.setEnabled(false); ((Button) findViewById(R.id.btn_login)).setEnabled(false); ((Button) findViewById(R.id.btn_configure)).setEnabled(false); } private void enableInput(){ mInputUsername.setEnabled(true); mInputPassword.setEnabled(true); ((Button) findViewById(R.id.btn_login)).setEnabled(true); ((Button) findViewById(R.id.btn_configure)).setEnabled(true); } // Attempts a log-in private void logIn() { loginAttempts++; // disable input until we get a result back from the service disableInput(); // get the data String username = mInputUsername.getText().toString(); String password = mInputPassword.getText().toString(); if(mBound && validUsernameAndPasswordFormat(username, password)){ Log.d(TAG, "login(): user name and password format valid"); Locales.updateLocale(this, getString(R.string.force_locale)); showProgressDialogFragment(getString(R.string.dialog_logging_in)); try { mService.create(getInstanceKey(), username,password);// register the callback to the username //cache the credentials setCurrentCredentials(username, password); } catch (RemoteException e) { Log.e(TAG, "login()" + e.toString()); e.printStackTrace(); } } } /** * Validates that the credentials are valid. * * @param username The username credential. * @param password The password credential. * @return */ protected boolean validUsernameAndPasswordFormat(String username, String password){ return !(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)); } /* * (non-Javadoc) * @see android.app.Activity#onStart() */ @Override protected void onStart(){ Log.i(TAG, "onStart()"); super.onStart(); bindSessionService(); } @Override protected void onStop() { Log.i(TAG, "onStop()"); super.onStop(); unbindSessionService(); } // handles initiating the session service binding private void bindSessionService(){ Log.i(TAG, "bindSessionService()"); if(!mBound){ bindService(new Intent(SessionService.ACTION_START), mConnection, Context.BIND_AUTO_CREATE); } } // handles disconnecting from the session service bindings private void unbindSessionService(){ // Unbind from the service if (mBound){ if(mService != null) try{ mService.unregisterCallback(mCallback); } catch(Exception e){ Log.e(TAG, "Failure unbinding Sessionservice",e); } // Detach unbindService(mConnection); mBound = false; } } // Registers the callback using the instance key private void registerCallback(){ try { mService.registerCallback(mCallback, getInstanceKey()); } catch (RemoteException e) { e.printStackTrace(); } } public void submit(View v){ switch(v.getId()){ case R.id.btn_login: logIn(); break; case R.id.btn_exit: setResult(RESULT_CANCELED); finish(); break; case R.id.btn_configure: Intent configure = new Intent(this, BasicSettings.class); startActivity(configure); break; default: } } }