package com.teamluper.luper; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.TargetApi; import android.app.Activity; import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import android.widget.TextView; import com.googlecode.androidannotations.annotations.Background; import com.googlecode.androidannotations.annotations.EFragment; import com.googlecode.androidannotations.annotations.UiThread; import com.googlecode.androidannotations.annotations.rest.RestService; import com.teamluper.luper.rest.LuperRestClient; import org.json.JSONException; import org.json.JSONObject; import java.security.MessageDigest; @EFragment public class TabRegisterFragment extends Fragment { @RestService LuperRestClient rest; @Override public View onCreateView(LayoutInflater infl, ViewGroup vg, Bundle state) { if(vg == null) return null; View v = infl.inflate(R.layout.tab_register_layout, vg, false); v.findViewById(R.id.register_button).setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { attemptRegistration(); } }); return v; } @Override public void onResume() { super.onResume(); showProgress(false); } @UiThread public void alert(String title, String message) { DialogFactory.alert(getActivity(), title, message); } @UiThread public void attemptRegistration() { Activity a = getActivity(); if(!LuperMainActivity.deviceIsOnline(a)) { DialogFactory.alert(a, "Registration Failed!", "You are not connected to the internet! " + "You must be online to register or log in. Once logged in, however, you can use Luper while offline."); } EditText editEmail = (EditText) a.findViewById(R.id.register_email); EditText editPassword = (EditText) a.findViewById(R.id.register_password); EditText editPassword2 = (EditText) a.findViewById(R.id.register_password2); EditText editUsername = (EditText) a.findViewById(R.id.register_username); editEmail.setError(null); editPassword.setError(null); editPassword2.setError(null); editUsername.setError(null); String email = editEmail.getText().toString(); String password = editPassword.getText().toString(); String password2 = editPassword2.getText().toString(); String username = editUsername.getText().toString(); boolean cancel = false; View focusView = null; // Check that the passwords match and are valid. if(!password.equals(password2)) { editPassword.setError("Passwords do not match!"); focusView = editPassword; cancel = true; } else if(password.length() < 4) { editPassword.setError("Password must be greater than 4 characters."); focusView = editPassword; cancel = true; } // Check that the email is valid. if(TextUtils.isEmpty(email)) { editEmail.setError("A valid email address is required!"); focusView = editEmail; cancel = true; } else if(!email.contains("@")) { editEmail.setError("This email address is invalid!"); focusView = editEmail; cancel = true; } // Check that the username is specified if(TextUtils.isEmpty(username) || username.length() < 4) { editUsername.setError("A display name of at least 4 characters is required."); focusView = editUsername; cancel = true; } if(cancel) { focusView.requestFocus(); return; } completeRegistration(email, password, username); } @Background public void completeRegistration(String email, String password, String username) { JSONObject request = new JSONObject(); try { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(password.getBytes("UTF-8")); // Change this to "UTF-16" if needed byte[] digest = md.digest(); String passwordHash = bytesToHex(digest); request.put("passwordHash",passwordHash); request.put("username",username); request.put("email",email); } catch(Exception e) { Log.e("luper","=== Exception while trying to hash password for JSON request ===", e); } String requestJSON = request.toString(); showProgress(true); String responseJSON = rest.registerNewAccount(requestJSON); JSONObject response = null; try { response = new JSONObject(responseJSON); } catch(JSONException e) { Log.e("luper","=== FAILED TO PARSE RESPONSE JSON FROM /api/auth/register", e); Log.e("luper","=== RESPONSE (which failed to parse as JSON) WAS:"); Log.e("luper","=== "+responseJSON); } showProgress(false); try { if(isResponseSuccessful(response)) { registrationSuccess(response.getLong("insertId"), email); } else { registrationFailure(response.getString("message")); } } catch(JSONException e) { Log.e("luper", "=== POST-PARSE JSON EXCEPTION: ", e); } } @UiThread public void registrationSuccess(long userId, String email) { showProgress(false); Activity activity = getActivity(); EditText editEmail = (EditText) activity.findViewById(R.id.register_email); EditText editPassword = (EditText) activity.findViewById(R.id.register_password); EditText editPassword2 = (EditText) activity.findViewById(R.id.register_password2); EditText editUsername = (EditText) activity.findViewById(R.id.register_username); editEmail.setText(""); editPassword.setText(""); editPassword2.setText(""); editUsername.setText(""); final LuperLoginActivity a = (LuperLoginActivity) activity; final String e = email; DialogFactory.alert(activity, "Registration Complete!", "Your new account has been registered! Please re-enter your password to log in.", new Lambda.VoidCallback() { public void go() { a.prefillLoginForm(e); } }); } @UiThread public void registrationFailure(String errorMessage) { showProgress(false); DialogFactory.alert(getActivity(), "Registration Failed!", errorMessage); } public boolean isResponseSuccessful(JSONObject response) { try { return response.getBoolean("success"); } catch(Exception e) { Log.e("luper","=== A REGISTRATION API RESPONSE WAS UNSUCCESSFUL === Exception: ", e); return false; } } public static String bytesToHex(byte[] bytes) { final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; char[] hexChars = new char[bytes.length * 2]; int v; for ( int j = 0; j < bytes.length; j++ ) { v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new String(hexChars); } /** * Shows the progress UI and hides the register form. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) @UiThread public void showProgress(final boolean show) { Activity a = getActivity(); final View mRegisterFormView = a.findViewById(R.id.register_form); final View mRegisterStatusView = a.findViewById(R.id.register_status); final TextView mRegisterStatusMessageView = (TextView) a.findViewById(R.id.register_status_message); // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow // for very easy animations. If available, use these APIs to fade-in // the progress spinner. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { int shortAnimTime = getResources().getInteger( android.R.integer.config_shortAnimTime); mRegisterStatusView.setVisibility(View.VISIBLE); mRegisterStatusView.animate().setDuration(shortAnimTime).alpha(show ? 1 : 0) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mRegisterStatusView.setVisibility(show ? View.VISIBLE : View.GONE); } }); mRegisterFormView.setVisibility(View.VISIBLE); mRegisterFormView.animate().setDuration(shortAnimTime).alpha(show ? 0 : 1) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mRegisterFormView.setVisibility(show ? View.GONE : View.VISIBLE); } }); } else { // The ViewPropertyAnimator APIs are not available, so simply show // and hide the relevant UI components. mRegisterStatusView.setVisibility(show ? View.VISIBLE : View.GONE); mRegisterFormView.setVisibility(show ? View.GONE : View.VISIBLE); } } }