package com.rapidftr.activity; import android.app.Activity; import android.app.AlertDialog; import android.content.*; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.os.Looper; import android.os.Process; import android.util.Log; import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Key; import com.rapidftr.R; import com.rapidftr.RapidFtrApplication; import com.rapidftr.features.FEATURE; import com.rapidftr.features.FeatureToggle; import com.rapidftr.model.*; import com.rapidftr.service.LogOutService; import com.rapidftr.task.SynchronisationAsyncTask; import com.rapidftr.view.fields.TextField; import lombok.Getter; import lombok.Setter; import org.json.JSONException; import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO; import static com.google.common.base.Strings.isNullOrEmpty; import static com.rapidftr.RapidFtrApplication.APP_IDENTIFIER; import static com.rapidftr.RapidFtrApplication.SERVER_URL_PREF; public abstract class RapidFtrActivity extends Activity { public static final String LOGOUT_INTENT_FILTER = "com.rapidftr.LOGOUT_INTENT"; protected @Getter @Setter Menu menu; @Inject protected FeatureToggle featureToggle; private BroadcastReceiver networkChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (!((NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO)).isConnected() && getContext().cleanSyncTask()) { makeToast(R.string.network_down); } } }; private BroadcastReceiver logoutReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d(APP_IDENTIFIER, "Logout event received"); finish(); } }; public interface ResultListener { void onActivityResult(int requestCode, int resultCode, Intent data); } protected Multimap<Integer, ResultListener> activityResultListeners = HashMultimap.create(); public RapidFtrApplication getContext() { return (RapidFtrApplication) getApplication(); } protected void startActivityOn(int viewResId, final Class<? extends RapidFtrActivity> activityClass) { findViewById(viewResId).setOnClickListener(new View.OnClickListener() { public void onClick(View view) { startActivity(new Intent(RapidFtrActivity.this, activityClass)); } }); } public void searchChildrenTabListener(View view) { saveAlertListener(SearchActivity.class); } public void createEnquiryTabListener(View view) { saveAlertListener(CreateEnquiryActivity.class); } public void viewAllEnquiryTabListener(View view) { saveAlertListener(ViewAllEnquiryActivity.class); } public void registerChildTabListener(View view) { saveAlertListener(RegisterChildActivity.class); } public void viewAllChildrenListener(View view) { saveAlertListener(ViewAllChildrenActivity.class); } protected void logError(String message) { if (message != null) { Log.e(APP_IDENTIFIER, message); } } protected void makeToast(int resId) { makeToast(getText(resId).toString()); } protected void makeToast(String text) { Toast toast = Toast.makeText(getContext(), text, Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER_HORIZONTAL, 0, 0); toast.show(); } protected Injector getInjector() { return getContext().getInjector(); } protected <T> T inject(Class<T> clazz) { return getInjector().getInstance(clazz); } public void addResultListener(int requestCode, ResultListener listener) { activityResultListeners.put(requestCode, listener); } protected void saveOrDiscardOrCancelChild(DialogInterface.OnClickListener listener) { AlertDialog.Builder saveOrDiscard = new AlertDialog.Builder(this); saveOrDiscard.setTitle(getString(R.string.choose_action)).setCancelable(false); saveOrDiscard.setItems(new String[]{getString(R.string.save), getString(R.string.discard), getString(R.string.cancel)}, listener); saveOrDiscard.create().show(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); for (ResultListener listener : activityResultListeners.get(requestCode)) { listener.onActivityResult(requestCode, resultCode, data); } } @Override public boolean onCreateOptionsMenu(Menu menu) { if (getContext().isLoggedIn()) { getMenuInflater().inflate(R.menu.options_menu, menu); setMenu(menu); toggleChangePassword(menu); toggleSync(menu); setContextToSyncTask(); } return getContext().isLoggedIn(); } private void toggleChangePassword(Menu menu) { menu.findItem(R.id.change_password).setVisible((this.getClass() == ChangePasswordActivity.class) ? false : getContext().getCurrentUser().isVerified()); } private void setContextToSyncTask() { SynchronisationAsyncTask syncTask = getContext().getSyncTask(); if (syncTask != null) syncTask.setContext(this); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.change_password: if (this.getClass() == RegisterChildActivity.class || this.getClass() == EditChildActivity.class) { saveAlertListener(ChangePasswordActivity.class); } else { startActivity(new Intent(this, ChangePasswordActivity.class)); } return true; case R.id.synchronize_all: if (isNullOrEmpty(getCurrentUser().getServerUrl())) { getServerAndSync(); } else { synchronise(); } return true; case R.id.cancel_synchronize_all: getContext().cleanSyncTask(); return true; case R.id.logout: if (this.getClass() == RegisterChildActivity.class || this.getClass() == EditChildActivity.class) { saveAlertListenerForLogout(); } else { inject(LogOutService.class).attemptLogOut(this); } return true; case R.id.info: startActivity(new Intent(this, InfoActivity.class)); return true; } return false; } protected void synchronise() { if (!this.getContext().isOnline()) { makeToast(R.string.connection_off); } else { try { if(featureToggle.isEnabled(FEATURE.ENQUIRIES)) { SynchronisationAsyncTask<Child> syncChildTask = getSynchronisationTask(new Key<SynchronisationAsyncTask<Child>>() { }); syncChildTask.setSuccessMessage(getString(R.string.child_records_sync_success)); executeTask(syncChildTask); SynchronisationAsyncTask<Enquiry> syncEnquiryTask = getSynchronisationTask(new Key<SynchronisationAsyncTask<Enquiry>>() { }); syncEnquiryTask.setSuccessMessage(getString(R.string.enquiry_records_sync_success)); executeTask(syncEnquiryTask); SynchronisationAsyncTask<PotentialMatch> syncPotentialMatchesTask = getSynchronisationTask(new Key<SynchronisationAsyncTask<PotentialMatch>>() { }); syncPotentialMatchesTask.setSuccessMessage(getString(R.string.potential_match_records_sync_success)); executeTask(syncPotentialMatchesTask); } else { SynchronisationAsyncTask<Child> syncChildTask = getSynchronisationTask(new Key<SynchronisationAsyncTask<Child>>() { }); syncChildTask.setSuccessMessage(getString(R.string.child_records_sync_success)); executeTask(syncChildTask); } } catch (JSONException e) { e.printStackTrace(); } } } private void executeTask(SynchronisationAsyncTask<? extends BaseModel> syncTask) { this.getContext().setSyncTask(syncTask); syncTask.setContext(this); syncTask.execute(); } private <T> T getSynchronisationTask(Key<T> key) { return getInjector().getInstance(key); } protected User getCurrentUser() { return getContext().getCurrentUser(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); registerReceiver(networkChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); initializeExceptionHandler(); initializeLogoutHandler(); getInjector().injectMembers(this); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceivers(); } private void unregisterReceivers() { try { unregisterReceiver(logoutReceiver); } catch (IllegalArgumentException e) { logError(e.getMessage()); } try { unregisterReceiver(networkChangeReceiver); } catch (IllegalArgumentException e) { logError(e.getMessage()); } } protected void initializeLogoutHandler() { if (shouldEnsureLoggedIn()) { IntentFilter intentFilter = new IntentFilter(LOGOUT_INTENT_FILTER); registerReceiver(logoutReceiver, intentFilter); } } protected boolean shouldEnsureLoggedIn() { return true; } @Override protected void onResume() { super.onResume(); if (shouldEnsureLoggedIn() && !getContext().isLoggedIn()) { finish(); } } @Override protected void onStop() { super.onStop(); unregisterReceivers(); } protected void initializeExceptionHandler() { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(final Thread thread, final Throwable throwable) { Log.e(APP_IDENTIFIER, throwable.getMessage(), throwable); new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Toast.makeText(getContext(), getContext().getString(R.string.internal_error), Toast.LENGTH_LONG).show(); Looper.loop(); } }).start(); try { Thread.sleep(4000); } catch (InterruptedException e) { } Process.killProcess(Process.myPid()); System.exit(10); } }); } protected void toggleSync(Menu menu) { menu.getItem(0).setVisible(getContext().getSyncTask() == null); menu.getItem(1).setVisible(getContext().getSyncTask() != null); } protected boolean validateTextFieldNotEmpty(int id, int messageId) { View view = findViewById(id); view = (view instanceof TextField) ? view.findViewById(R.id.value) : view; return validateTextFieldNotEmpty((EditText) view, messageId); } protected boolean validateTextFieldNotEmpty(EditText editText, int messageId) { String value = getEditText(editText.getId()); if (value == null || "".equals(value)) { editText.setError(getString(messageId)); return false; } else { return true; } } protected String getEditText(int resId) { return getText((EditText) findViewById(resId)); } protected String getText(EditText editText) { CharSequence value = editText.getText(); return value == null ? null : value.toString().trim(); } protected void saveAlertListener(final Class cls) { if ((this instanceof RegisterChildActivity && ((RegisterChildActivity) this).child.isValid()) || this instanceof EditChildActivity) { final BaseChildActivity activity = (BaseChildActivity) this; DialogInterface.OnClickListener listener = createAlertDialog(cls, activity); saveOrDiscardOrCancelChild(listener); } else { startActivity(new Intent(RapidFtrActivity.this, cls)); } } protected DialogInterface.OnClickListener createAlertDialog(final Class cls, final BaseChildActivity activity) { return new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int selectedItem) { switch (selectedItem) { case 0: activity.saveChild(); break; case 1: startActivity(new Intent(RapidFtrActivity.this, cls)); case 2: break; } } }; } protected void saveAlertListenerForLogout() { final BaseChildActivity activity = (BaseChildActivity) this; DialogInterface.OnClickListener listener = createAlertDialogForLogout(activity); if (activity.child.isValid()) { saveOrDiscardOrCancelChild(listener); } else { inject(LogOutService.class).attemptLogOut(activity); } } protected DialogInterface.OnClickListener createAlertDialogForLogout(final BaseChildActivity activity) { return new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int selectedItem) { switch (selectedItem) { case 0: activity.saveChild(); break; case 1: inject(LogOutService.class).attemptLogOut(activity); case 2: break; } } }; } public void getServerAndSync() { AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle("Enter sync location"); alert.setMessage("Please enter the the location you wish to synchronise with"); final EditText input = new EditText(this); alert.setView(input); alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { getContext().getSharedPreferences().edit().putString(SERVER_URL_PREF, input.getText().toString()).commit(); synchronise(); } }); alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { finish(); startActivity(new Intent(getContext(), ViewAllChildrenActivity.class)); } }); alert.create().show(); } protected BroadcastReceiver getBroadcastReceiver() { return networkChangeReceiver; } private void hideEnquiryTab() { Button enquiryTab = (Button) findViewById(R.id.enquiry_tab); enquiryTab.setVisibility(View.GONE); } public void hideEnquiriesTabIfRapidReg() throws JSONException { featureToggle = inject(FeatureToggle.class); if (!featureToggle.isEnabled(FEATURE.ENQUIRIES)) { hideEnquiryTab(); } } }