package com.radicaldynamic.groupinform.activities; import java.util.ArrayList; import java.util.List; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.radicaldynamic.groupinform.R; import com.radicaldynamic.groupinform.application.Collect; import com.radicaldynamic.groupinform.logic.InformOnlineState; import com.radicaldynamic.groupinform.utilities.HttpUtils; public class ClientRegistrationActivity extends Activity { private static final String t = "ClientRegistrationActivity: "; private static final int DIALOG_BEGIN_REGISTRATION = 1; private static final int DIALOG_DEVICE_REGISTRATION_METHOD = 2; private static final int DIALOG_ACCOUNT_CREATED = 3; private static final int DIALOG_ACCOUNT_EXISTS = 4; private static final int DIALOG_DEVICE_REGISTERED = 5; private static final int DIALOG_DEVICE_ACTIVE = 6; private static final int DIALOG_REACTIVATE_DEVICE = 7; private static final int DIALOG_REGISTER_DEVICE = 8; private static final int DIALOG_REGISTER_EXISTING_ACCOUNT = 9; private static final int DIALOG_REGISTER_NEW_ACCOUNT = 10; private static final int DIALOG_REQUEST_REMINDER = 11; private static final int DIALOG_SEAT_LIMIT_REACHED = 12; private static final int DIALOG_SYSTEM_ERROR = 13; private static final int DIALOG_BETA_PREVIEW = 14; // verifyDeviceRegistration exit codes private static final int DEVICE_REGISTRATION_VERIFIED = 0; // Generic "registration ok" private static final int DEVICE_REGISTRATION_FAILED = 1; // Generic "registration failed" private static final int DEVICE_REGISTRATION_LIMITED = 2; // Licence seat limit // Constants used to match server responses public static final String REASON_INVALID_EMAIL = "invalid email address"; // New account/device failure public static final String REASON_EMAIL_ASSIGNED = "email address assigned"; // New account/device failure public static final String REASON_UNKNOWN = "unknown reason"; // Unknown failure (default only) private static final String REASON_LICENCE_LIMIT = "seat licence limit reached"; // New device failure private static final String REASON_INVALID_PIN = "invalid pin"; // Reactivation failure private static final String REASON_DEVICE_ACTIVE = "device active"; // Reactivation failure private static final String REASON_REACTIVATION_DELAYED = "activation delayed"; // Reactivation failure private static final String REASON_UNKNOWN_ACCOUNT_CONTACT = "unknown account owner email"; // Remind failure // Keys for saving and restoring activity state private static final String KEY_ACCOUNT_NUMBER = "key_account_number"; private static final String KEY_ACCOUNT_KEY = "key_account_key"; private static final String KEY_DEVICE_PIN = "key_device_pin"; private static final String KEY_CONTACT_EMAIL = "key_contact_email"; private static final String KEY_LICENCE_PLAN_TYPE = "key_licence_plan_type"; private static final String KEY_LICENCE_SEAT_LIMIT = "key_licence_seat_limit"; private String mAccountNumber = ""; // Licence number private String mAccountKey = ""; // Licence key private String mDevicePin = ""; private String mContactEmail = ""; private String mLicencePlanType = ""; private String mLicenceSeatLimit = ""; // Alternate notification logic used when attempting to reactivate a device profile that is already active private boolean mOptionToNotifyDeviceUser = false; private TextWatcher mAutoFormat = new TextWatcher() { @Override public void afterTextChanged(Editable s) { char dash = '-'; try { if ((int) s.charAt(s.length() - 1) != (int) dash) if (s.length() == 5 || s.length() == 10) s.insert(s.length() - 1, "-"); } catch (IndexOutOfBoundsException e) { // Do nothing } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setTitle(getString(R.string.app_name) + " > " + getString(R.string.tf_registration)); setContentView(R.layout.client_registration); Button register = (Button) findViewById(R.id.register); register.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // "This app is in beta" dialog no longer needed // showDialog(DIALOG_BETA_PREVIEW); showDialog(DIALOG_BEGIN_REGISTRATION); } }); } protected Dialog onCreateDialog(int id) { AlertDialog.Builder builder = new AlertDialog.Builder(this); LayoutInflater inflater; View view; switch (id) { case DIALOG_BEGIN_REGISTRATION: builder .setCancelable(false) .setTitle(R.string.tf_do_you_have_an_account) .setMessage(R.string.tf_do_you_have_an_account_msg) .setPositiveButton(R.string.tf_yes, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_BEGIN_REGISTRATION); showDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); } }) .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_BEGIN_REGISTRATION); showDialog(DIALOG_REGISTER_NEW_ACCOUNT); } }); break; case DIALOG_DEVICE_REGISTRATION_METHOD: builder .setCancelable(false) .setMessage(R.string.tf_device_registration_method_msg) .setPositiveButton(R.string.tf_device_registration_method_register_new, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_DEVICE_REGISTRATION_METHOD); showDialog(DIALOG_REGISTER_DEVICE); } }) .setNegativeButton(R.string.tf_device_registration_method_reactivate, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_DEVICE_REGISTRATION_METHOD); showDialog(DIALOG_REACTIVATE_DEVICE); } }); break; case DIALOG_ACCOUNT_CREATED: builder .setCancelable(false) .setIcon(R.drawable.ic_dialog_info) .setTitle(R.string.tf_account_created) .setMessage(getString(R.string.tf_account_created_msg, mContactEmail)) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Return user to the main screen (application will be reinitialized with this information) Intent i = new Intent(getApplicationContext(), LauncherActivity.class); startActivity(i); finish(); } }); break; case DIALOG_ACCOUNT_EXISTS: builder .setCancelable(false) .setIcon(R.drawable.ic_dialog_info) .setTitle(R.string.tf_account_exists_dialog) .setMessage(getString(R.string.tf_account_exists_dialog_msg)) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_ACCOUNT_EXISTS); showDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); } }); break; case DIALOG_DEVICE_REGISTERED: builder .setCancelable(false) .setIcon(R.drawable.ic_dialog_info) .setTitle(R.string.tf_device_registered) .setMessage(R.string.tf_device_registered_msg) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Return user to the main screen (application will be reinitialized with this information) startActivity(new Intent(getApplicationContext(), LauncherActivity.class)); finish(); } }); break; case DIALOG_DEVICE_ACTIVE: builder .setCancelable(false) .setTitle(R.string.tf_unable_to_reactivate_while_in_use_dialog) .setMessage(R.string.tf_unable_to_reactivate_while_in_use_dialog_msg) .setPositiveButton(R.string.tf_notify_device_owner, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { notifyActiveProfile(); removeDialog(DIALOG_DEVICE_ACTIVE); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_DEVICE_ACTIVE); } }); break; case DIALOG_REACTIVATE_DEVICE: inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.reactivate_device, null); final EditText devicePin = (EditText) view.findViewById(R.id.devicePin); devicePin.addTextChangedListener(mAutoFormat); devicePin.setText(mDevicePin); builder .setCancelable(false) .setInverseBackgroundForced(true) .setView(view) .setPositiveButton(R.string.tf_continue, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String pin = devicePin.getText().toString().trim(); // Save for later mDevicePin = pin; if (pin.length() == 0 || !pin.matches("^[0-9]{4,4}-[0-9]{4,4}$")) { Toast.makeText(getApplicationContext(), getString(R.string.tf_device_pin_required), Toast.LENGTH_LONG).show(); removeDialog(DIALOG_REACTIVATE_DEVICE); showDialog(DIALOG_REACTIVATE_DEVICE); } else { if (verifyDeviceReactivation(pin)) { removeDialog(DIALOG_REACTIVATE_DEVICE); showDialog(DIALOG_DEVICE_REGISTERED); } else { if (mOptionToNotifyDeviceUser) { mOptionToNotifyDeviceUser = false; } else { removeDialog(DIALOG_REACTIVATE_DEVICE); showDialog(DIALOG_REACTIVATE_DEVICE); } } } } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_REACTIVATE_DEVICE); showDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); } }); break; case DIALOG_REGISTER_DEVICE: inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.register_device, null); final EditText emailAddress = (EditText) view.findViewById(R.id.emailAddress); emailAddress.setText(mContactEmail); builder .setCancelable(false) .setInverseBackgroundForced(true) .setView(view) .setPositiveButton(R.string.tf_continue, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String email = emailAddress.getText().toString().trim(); if (email.length() == 0) { Toast.makeText( getApplicationContext(), getString(R.string.tf_email_address_required), Toast.LENGTH_LONG).show(); removeDialog(DIALOG_REGISTER_DEVICE); showDialog(DIALOG_REGISTER_DEVICE); } else { switch (verifyDeviceRegistration(email)) { case DEVICE_REGISTRATION_VERIFIED: removeDialog(DIALOG_REGISTER_DEVICE); showDialog(DIALOG_DEVICE_REGISTERED); break; case DEVICE_REGISTRATION_FAILED: // Error message communicated via Toast removeDialog(DIALOG_REGISTER_DEVICE); showDialog(DIALOG_REGISTER_DEVICE); break; case DEVICE_REGISTRATION_LIMITED: removeDialog(DIALOG_REGISTER_DEVICE); showDialog(DIALOG_SEAT_LIMIT_REACHED); } } } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_REGISTER_DEVICE); showDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); } }); break; case DIALOG_REGISTER_EXISTING_ACCOUNT: inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.register_existing_account, null); final EditText licenceNumber = (EditText) view.findViewById(R.id.accountNumber); final EditText licenceKey = (EditText) view.findViewById(R.id.accountKey); licenceNumber.addTextChangedListener(mAutoFormat); licenceKey.addTextChangedListener(mAutoFormat); licenceNumber.setText(mAccountNumber); licenceKey.setText(mAccountKey); builder .setCancelable(false) .setInverseBackgroundForced(true) .setTitle(getString(R.string.tf_supply_account_details)) .setView(view) .setPositiveButton(R.string.tf_continue, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String number = licenceNumber.getText().toString().trim(); String key = licenceKey.getText().toString().trim(); if (verifyAccountLicence(number, key)) { removeDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); showDialog(DIALOG_DEVICE_REGISTRATION_METHOD); } else { removeDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); showDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); } } }) .setNeutralButton(R.string.tf_remind, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); showDialog(DIALOG_REQUEST_REMINDER); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { dialog.dismiss(); } }); break; case DIALOG_REGISTER_NEW_ACCOUNT: inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.register_new_account, null); final EditText accountOwnerEmail = (EditText) view.findViewById(R.id.emailAddress); accountOwnerEmail.setText(mContactEmail); builder .setCancelable(false) .setInverseBackgroundForced(true) .setTitle(R.string.tf_new_account) .setView(view) .setPositiveButton(R.string.tf_continue, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String email = accountOwnerEmail.getText().toString().trim(); if (email.length() == 0) { Toast.makeText( getApplicationContext(), getString(R.string.tf_email_address_required), Toast.LENGTH_LONG).show(); removeDialog(DIALOG_REGISTER_NEW_ACCOUNT); showDialog(DIALOG_REGISTER_NEW_ACCOUNT); } else { if (verifyNewAccount(email)) { showDialog(DIALOG_ACCOUNT_CREATED); } else { /* * If account existed, mContactEmail would contain the account owner email * and we wouldn't want to show this dialog (instead, the user would see * a notice and be redirected to DIALOG_REGISTER_EXISTING_ACCOUNT. */ if (mContactEmail.length() == 0) { removeDialog(DIALOG_REGISTER_NEW_ACCOUNT); showDialog(DIALOG_REGISTER_NEW_ACCOUNT); } } } } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { dialog.dismiss(); } }); break; case DIALOG_REQUEST_REMINDER: inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.account_reminder, null); final EditText contactEmail = (EditText) view.findViewById(R.id.emailAddress); contactEmail.setText(mContactEmail); builder .setCancelable(false) .setInverseBackgroundForced(true) .setTitle(R.string.tf_request_account_reminder) .setView(view) .setPositiveButton(R.string.tf_continue, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String email = contactEmail.getText().toString().trim(); if (email.length() == 0) { Toast.makeText( getApplicationContext(), getString(R.string.tf_email_address_required), Toast.LENGTH_LONG).show(); removeDialog(DIALOG_REQUEST_REMINDER); showDialog(DIALOG_REQUEST_REMINDER); } else { if (sendAccountReminder(email)) { mContactEmail = ""; removeDialog(DIALOG_REQUEST_REMINDER); showDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); } else { removeDialog(DIALOG_REQUEST_REMINDER); showDialog(DIALOG_REQUEST_REMINDER); } } } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_REQUEST_REMINDER); showDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); } }); break; case DIALOG_SEAT_LIMIT_REACHED: builder .setCancelable(false) .setIcon(R.drawable.ic_dialog_info) .setTitle(R.string.tf_licence_limit_reached_dialog) .setMessage(getString(R.string.tf_licence_limit_reached_dialog_msg, mLicenceSeatLimit, mLicencePlanType)) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_SEAT_LIMIT_REACHED); showDialog(DIALOG_REGISTER_EXISTING_ACCOUNT); } }); break; case DIALOG_SYSTEM_ERROR: builder .setCancelable(false) .setIcon(R.drawable.ic_dialog_alert) .setTitle(R.string.tf_system_error_dialog) .setMessage(R.string.tf_system_error_dialog_msg) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Do something? } }); break; case DIALOG_BETA_PREVIEW: builder .setCancelable(false) .setIcon(R.drawable.splash_beta_blue) .setTitle("Technology Preview") .setMessage(R.string.tf_beta_release_msg) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(DIALOG_BETA_PREVIEW); showDialog(DIALOG_BEGIN_REGISTRATION); } }); break; } return builder.create(); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); mAccountNumber = savedInstanceState.getString(KEY_ACCOUNT_NUMBER); mAccountKey = savedInstanceState.getString(KEY_ACCOUNT_KEY); mDevicePin = savedInstanceState.getString(KEY_DEVICE_PIN); mContactEmail = savedInstanceState.getString(KEY_CONTACT_EMAIL); mLicencePlanType = savedInstanceState.getString(KEY_LICENCE_PLAN_TYPE); mLicenceSeatLimit = savedInstanceState.getString(KEY_LICENCE_SEAT_LIMIT); } @Override public void onSaveInstanceState(Bundle savedInstanceState) { savedInstanceState.putString(KEY_ACCOUNT_NUMBER, mAccountNumber); savedInstanceState.putString(KEY_ACCOUNT_KEY, mAccountKey); savedInstanceState.putString(KEY_DEVICE_PIN, mDevicePin); savedInstanceState.putString(KEY_CONTACT_EMAIL, mContactEmail); savedInstanceState.putString(KEY_LICENCE_PLAN_TYPE, mLicencePlanType); savedInstanceState.putString(KEY_LICENCE_SEAT_LIMIT, mLicenceSeatLimit); super.onSaveInstanceState(savedInstanceState); } private boolean notifyActiveProfile() { // Data to POST List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("licenceNumber", mAccountNumber)); params.add(new BasicNameValuePair("licenceKey", mAccountKey)); params.add(new BasicNameValuePair("devicePin", mDevicePin)); params.add(new BasicNameValuePair("fingerprint", Collect.getInstance().getInformOnlineState().getDeviceFingerprint())); String verifyUrl = Collect.getInstance().getInformOnlineState().getServerUrl() + "/send/notice"; String postResult = HttpUtils.postUrlData(verifyUrl, params); JSONObject verify; try { verify = (JSONObject) new JSONTokener(postResult).nextValue(); String result = verify.optString(InformOnlineState.RESULT, InformOnlineState.FAILURE); if (result.equals(InformOnlineState.OK)) { Toast.makeText(getApplicationContext(), getString(R.string.tf_device_owner_notified_of_pin_use), Toast.LENGTH_LONG).show(); return true; } else if (result.equals(InformOnlineState.FAILURE)) { Toast.makeText(getApplicationContext(), getString(R.string.tf_unable_to_notify_device_user), Toast.LENGTH_LONG).show(); String reason = verify.optString(InformOnlineState.REASON, REASON_UNKNOWN); if (Collect.Log.WARN) Log.w(Collect.LOGTAG, t + "unable to notify device user: " + reason); return false; } else { // Something bad happened if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "system error while processing postResult"); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); return false; } } catch (NullPointerException e) { // Communication error if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "no postResult to parse. Communication error with node.js server?"); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); e.printStackTrace(); return false; } catch (JSONException e) { // Parse error (malformed result) if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "failed to parse postResult " + postResult); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); e.printStackTrace(); return false; } } /* * Request that Inform Online send an email to the account owner containing * account reminder information (licence number and key). Return a boolean * indicating whether the request to send an email was successful. */ private boolean sendAccountReminder(String email) { // Data to POST List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("email", email.toLowerCase())); String verifyUrl = Collect.getInstance().getInformOnlineState().getServerUrl() + "/send/reminder"; String postResult = HttpUtils.postUrlData(verifyUrl, params); JSONObject verify; try { verify = (JSONObject) new JSONTokener(postResult).nextValue(); String result = verify.optString(InformOnlineState.RESULT, InformOnlineState.FAILURE); if (result.equals(InformOnlineState.OK)) { Toast.makeText(getApplicationContext(), getString(R.string.tf_reminder_sent), Toast.LENGTH_LONG).show(); return true; } else if (result.equals(InformOnlineState.FAILURE)) { String reason = verify.optString(InformOnlineState.REASON, REASON_UNKNOWN); if (reason.equals(REASON_INVALID_EMAIL)) { Toast.makeText(getApplicationContext(), getString(R.string.tf_invalid_email), Toast.LENGTH_LONG).show(); } else if (reason.equals(REASON_UNKNOWN_ACCOUNT_CONTACT)) { Toast.makeText(getApplicationContext(), getString(R.string.tf_unknown_contact_email), Toast.LENGTH_LONG).show(); } else { // Unhandled response Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "system error while processing postResult"); } return false; } else { // Something bad happened Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "system error while processing postResult"); return false; } } catch (NullPointerException e) { // Communication error if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "no postResult to parse. Communication error with node.js server?"); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); e.printStackTrace(); return false; } catch (JSONException e) { // Parse error (malformed result) if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "failed to parse postResult " + postResult); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); e.printStackTrace(); return false; } } /* * Set information about the associated account/device registration to the installation preferences */ private void setRegistrationInformation(JSONObject container) throws JSONException { Collect.getInstance().getInformOnlineState().setAccountKey(container.getString("accountKey")); Collect.getInstance().getInformOnlineState().setAccountNumber(container.getString("accountNumber")); Collect.getInstance().getInformOnlineState().setAccountOwner(container.getBoolean("accountOwner")); Collect.getInstance().getInformOnlineState().setDefaultDatabase(container.getString("defaultDb")); Collect.getInstance().getInformOnlineState().setDeviceId(container.getString("deviceId")); Collect.getInstance().getInformOnlineState().setDeviceKey(container.getString("deviceKey")); Collect.getInstance().getInformOnlineState().setDevicePin(container.getString("devicePin")); } private boolean verifyAccountLicence(String number, String key) { // Make sure abcd-ef12-3456 gets translated to ABCD-EF12-3456 key = key.toUpperCase(); // Store for reuse mAccountNumber = number; mAccountKey = key; // Both the licence number and key are required to proceed if (number.length() == 0 || key.length() == 0) { Toast.makeText(getApplicationContext(), getString(R.string.tf_unable_to_proceed_without_licence_number_and_key), Toast.LENGTH_LONG).show(); return false; } Boolean error = false; // Ensure the licence number is formatted NNNN-NNNN-NNNN if (!number.matches("^[0-9]{4,4}-[0-9]{4,4}-[0-9]{4,4}$")) { Toast.makeText(getApplicationContext(), getString(R.string.tf_improperly_formatted_licence_number), Toast.LENGTH_LONG).show(); error = true; } // Ensure the licence key is formatted XXXX-XXXX-XXXX if (!key.matches("(?i)^[a-f0-9]{4,4}-[a-f0-9]{4,4}-[a-f0-9]{4,4}$")) { Toast.makeText(getApplicationContext(), getString(R.string.tf_improperly_formatted_licence_key), Toast.LENGTH_LONG).show(); error = true; } if (error) { return false; } else { // Data to POST List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("licenceNumber", number)); params.add(new BasicNameValuePair("licenceKey", key)); String verifyUrl = Collect.getInstance().getInformOnlineState().getServerUrl() + "/verify/licence"; String postResult = HttpUtils.postUrlData(verifyUrl, params); JSONObject verify; try { verify = (JSONObject) new JSONTokener(postResult).nextValue(); String result = verify.optString(InformOnlineState.RESULT, InformOnlineState.FAILURE); // Match if (result.equals(InformOnlineState.OK)) { Toast.makeText(getApplicationContext(), getString(R.string.tf_licence_validation_succeeded), Toast.LENGTH_SHORT).show(); // Clear email address in case it was saved after user requested new account with existing email address mContactEmail = ""; return true; } else if (result.equals(InformOnlineState.FAILURE)) { // No match Toast.makeText(getApplicationContext(), getString(R.string.tf_licence_validation_failed), Toast.LENGTH_LONG).show(); return false; } else { // Something bad happened if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "system error while processing postResult"); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); return false; } } catch (NullPointerException e) { // Communication error if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "no postResult to parse. Communication error with node.js server?"); Toast.makeText(getApplicationContext(), getString(R.string.tf_communication_error_try_again), Toast.LENGTH_LONG).show(); e.printStackTrace(); return false; } catch (JSONException e) { // Parse error (malformed result) if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "failed to parse postResult " + postResult); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); e.printStackTrace(); return false; } } } // End verifyAccountLicence() private int verifyDeviceRegistration(String email) { // Data to POST List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("licenceNumber", mAccountNumber)); params.add(new BasicNameValuePair("licenceKey", mAccountKey)); params.add(new BasicNameValuePair("email", email.toLowerCase())); params.add(new BasicNameValuePair("fingerprint", Collect.getInstance().getInformOnlineState().getDeviceFingerprint())); String registerDeviceUrl = Collect.getInstance().getInformOnlineState().getServerUrl() + "/register/device"; String postResult = HttpUtils.postUrlData(registerDeviceUrl, params); JSONObject verify; try { verify = (JSONObject) new JSONTokener(postResult).nextValue(); String result = verify.optString(InformOnlineState.RESULT, InformOnlineState.FAILURE); if (result.equals(InformOnlineState.OK)) { // Store account information to preferences mContactEmail = email; setRegistrationInformation(verify); return DEVICE_REGISTRATION_VERIFIED; } else if (result.equals(InformOnlineState.FAILURE)) { String reason = verify.optString(InformOnlineState.REASON, REASON_UNKNOWN); if (reason.equals(REASON_INVALID_EMAIL)) { Toast.makeText(getApplicationContext(), getString(R.string.tf_invalid_email), Toast.LENGTH_LONG).show(); } else if (reason.equals(REASON_EMAIL_ASSIGNED)) { Toast.makeText(getApplicationContext(), getString(R.string.tf_registration_error_email_in_use), Toast.LENGTH_LONG).show(); } else if (reason.equals(REASON_LICENCE_LIMIT)) { mLicenceSeatLimit = verify.optString("licencedSeats", "?"); mLicencePlanType = verify.optString("planType", "?"); return DEVICE_REGISTRATION_LIMITED; } else { // Unhandled response Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "system error while processing postResult"); } } else { // Something bad happened Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "system error while processing postResult"); } } catch (NullPointerException e) { // Communication error if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "no postResult to parse. Communication error with node.js server?"); Toast.makeText(getApplicationContext(), getString(R.string.tf_communication_error_try_again), Toast.LENGTH_LONG).show(); e.printStackTrace(); } catch (JSONException e) { // Parse error (malformed result) if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "failed to parse postResult " + postResult); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); e.printStackTrace(); } // Generic "something went wrong" (announced via a toast) return DEVICE_REGISTRATION_FAILED; } // End verifyDeviceRegistration() private boolean verifyDeviceReactivation(String devicePin) { // Data to POST List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("licenceNumber", mAccountNumber)); params.add(new BasicNameValuePair("licenceKey", mAccountKey)); params.add(new BasicNameValuePair("devicePin", devicePin)); params.add(new BasicNameValuePair("fingerprint", Collect.getInstance().getInformOnlineState().getDeviceFingerprint())); String registerReactivateUrl = Collect.getInstance().getInformOnlineState().getServerUrl() + "/register/reactivate"; String postResult = HttpUtils.postUrlData(registerReactivateUrl, params); JSONObject reactivation; try { reactivation = (JSONObject) new JSONTokener(postResult).nextValue(); String result = reactivation.optString(InformOnlineState.RESULT, InformOnlineState.FAILURE); if (result.equals(InformOnlineState.OK)) { setRegistrationInformation(reactivation); return true; } else if (result.equals(InformOnlineState.FAILURE)) { String reason = reactivation.optString(InformOnlineState.REASON, REASON_UNKNOWN); if (reason.equals(REASON_INVALID_PIN)) { Toast.makeText(getApplicationContext(), getString(R.string.tf_invalid_pin), Toast.LENGTH_LONG).show(); } else if (reason.equals(REASON_DEVICE_ACTIVE)) { mOptionToNotifyDeviceUser = true; showDialog(DIALOG_DEVICE_ACTIVE); } else if (reason.equals(REASON_REACTIVATION_DELAYED)) { String approximation = " "; String period = ""; String unit = ""; // The delay time is returned in milliseconds Integer delayMilliseconds = reactivation.getInt("delay"); if (delayMilliseconds / 1000 / 60 > 0) { approximation = " about "; period = Integer.toString(delayMilliseconds / 1000 / 60); unit = "minutes"; } else if (delayMilliseconds / 1000 > 0) { period = Integer.toString(delayMilliseconds / 1000); unit = "seconds"; } else { period = "a few"; unit = "seconds"; } // Hack to turn "minutes" into "minute" or whatever if (period.equals("1")) { unit = unit.substring(0, unit.length() - 1); } Toast.makeText(getApplicationContext(), getString(R.string.tf_reactivation_delayed_reason), Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), getString(R.string.tf_reactivation_delayed_wait, approximation, period, unit), Toast.LENGTH_LONG).show(); } else { // Unhandled response Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "system error while processing postResult"); } return false; } else { // Something bad happened Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "system error while processing postResult"); return false; } } catch (NullPointerException e) { // Communication error if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "no postResult to parse. Communication error with node.js server?"); Toast.makeText(getApplicationContext(), getString(R.string.tf_communication_error_try_again), Toast.LENGTH_LONG).show(); e.printStackTrace(); return false; } catch (JSONException e) { // Parse error (malformed result) if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "failed to parse postResult " + postResult); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); e.printStackTrace(); return false; } } // End verifyDeviceReactivation() private boolean verifyNewAccount(String email) { // Data to POST List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("email", email.toLowerCase())); params.add(new BasicNameValuePair("fingerprint", Collect.getInstance().getInformOnlineState().getDeviceFingerprint())); String verifyUrl = Collect.getInstance().getInformOnlineState().getServerUrl() + "/register/account"; String postResult = HttpUtils.postUrlData(verifyUrl, params); JSONObject verify; try { verify = (JSONObject) new JSONTokener(postResult).nextValue(); String result = verify.optString(InformOnlineState.RESULT, InformOnlineState.FAILURE); if (result.equals(InformOnlineState.OK)) { // Used by DIALOG_ACCOUNT_CREATED mContactEmail = email; // Store account information to preferences setRegistrationInformation(verify); return true; } else if (result.equals(InformOnlineState.FAILURE)) { String reason = verify.optString(InformOnlineState.REASON, REASON_UNKNOWN); if (reason.equals(REASON_INVALID_EMAIL)) { Toast.makeText(getApplicationContext(), getString(R.string.tf_invalid_email), Toast.LENGTH_LONG).show(); } else if (reason.equals(REASON_EMAIL_ASSIGNED)) { // Share email address with reminder and explanation dialogs mContactEmail = email; showDialog(DIALOG_ACCOUNT_EXISTS); } else { // Unhandled response Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "system error while processing postResult"); } return false; } else { // Something bad happened if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "system error while processing postResult"); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); return false; } } catch (NullPointerException e) { // Communication error if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "no postResult to parse. Communication error with node.js server?"); Toast.makeText(getApplicationContext(), getString(R.string.tf_communication_error_try_again), Toast.LENGTH_LONG).show(); e.printStackTrace(); return false; } catch (JSONException e) { // Parse error (malformed result) if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + "failed to parse postResult " + postResult); Toast.makeText(getApplicationContext(), getString(R.string.tf_system_error_dialog_msg), Toast.LENGTH_LONG).show(); e.printStackTrace(); return false; } } // End verifyNewAccount() }