package net.wigle.wigleandroid.background;
import java.io.IOException;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import net.wigle.wigleandroid.DatabaseHelper;
import net.wigle.wigleandroid.ListFragment;
import net.wigle.wigleandroid.MainActivity;
import net.wigle.wigleandroid.TokenAccess;
import net.wigle.wigleandroid.WiGLEAuthException;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
public abstract class AbstractBackgroundTask extends Thread implements AlertSettable {
private static final int THREAD_PRIORITY = Process.THREAD_PRIORITY_BACKGROUND;
protected FragmentActivity context;
protected final DatabaseHelper dbHelper;
private final BackgroundGuiHandler handler;
private final AtomicBoolean interrupt = new AtomicBoolean( false );
private final Object lock = new Object();
private final String name;
private ProgressDialogFragment pd;
private int lastSentPercent = -1;
private static AbstractBackgroundTask latestTask = null;
static final String PROGRESS_TAG = "background-task-progress";
public AbstractBackgroundTask(final FragmentActivity context, final DatabaseHelper dbHelper, final String name,
final boolean createDialog) {
if ( context == null ) {
throw new IllegalArgumentException( "context is null" );
}
if ( dbHelper == null ) {
throw new IllegalArgumentException( "dbHelper is null" );
}
if ( name == null ) {
throw new IllegalArgumentException( "name is null" );
}
this.context = context;
this.dbHelper = dbHelper;
this.name = name;
if (createDialog) createProgressDialog( context );
this.handler = new BackgroundGuiHandler(context, lock, pd, this);
latestTask = this;
}
@Override
public final void clearProgressDialog() {
pd = null;
}
@Override
public final void run() {
// set thread name
setName( name + "-" + getName() );
try {
MainActivity.info( "setting background thread priority (-20 highest, 19 lowest) to: " + THREAD_PRIORITY );
Process.setThreadPriority( THREAD_PRIORITY );
subRun();
}
catch ( InterruptedException ex ) {
MainActivity.info( name + " interrupted: " + ex );
}
catch ( final WiGLEAuthException waex) {
//DEBUG: MainActivity.info("auth error", waex);
Bundle errorBundle = new Bundle();
errorBundle.putCharSequence("AUTH_ERROR", waex.getMessage());
sendBundledMessage(BackgroundGuiHandler.AUTHENTICATION_ERROR, errorBundle);
}
catch ( final Exception ex ) {
dbHelper.deathDialog(name, ex);
}
}
protected final void sendPercentTimesTen(final int percentDone, final Bundle bundle) {
// only send up to 1000 times
if ( percentDone > lastSentPercent && percentDone >= 0 ) {
sendBundledMessage( BackgroundGuiHandler.WRITING_PERCENT_START + percentDone, bundle );
lastSentPercent = percentDone;
}
}
protected final void sendBundledMessage(final int what, final Bundle bundle) {
final Message msg = new Message();
msg.what = what;
msg.setData(bundle);
handler.sendMessage(msg);
}
protected abstract void subRun() throws IOException, InterruptedException, WiGLEAuthException;
/** interrupt this task */
public final void setInterrupted() {
interrupt.set( true );
}
protected final boolean wasInterrupted() {
return interrupt.get();
}
public final Handler getHandler() {
return handler;
}
private void createProgressDialog(final FragmentActivity context) {
// make an interruptable progress dialog
pd = ProgressDialogFragment.newInstance();
pd.show(context.getSupportFragmentManager(), PROGRESS_TAG);
}
public static class ProgressDialogFragment extends DialogFragment {
public static ProgressDialogFragment newInstance() {
return new ProgressDialogFragment ();
}
@Override
@NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
final ProgressDialog dialog = new ProgressDialog(getActivity());
dialog.setTitle(getString(Status.WRITING.getTitle()));
dialog.setMessage(getString(Status.WRITING.getMessage()));
dialog.setIndeterminate(true);
dialog.setCancelable(true);
dialog.setCanceledOnTouchOutside(false);
return dialog;
}
@Override
public void onCancel(DialogInterface dialog) {
MainActivity.info("Cancelling dialog for task: " + latestTask);
if (latestTask != null) {
latestTask.setInterrupted();
}
}
private ProgressDialog getDialog(final FragmentManager manager) {
final ProgressDialogFragment dialog = (ProgressDialogFragment) manager.findFragmentByTag(PROGRESS_TAG);
if (dialog != null) {
return (ProgressDialog) dialog.getDialog();
}
MainActivity.info("No progress dialog");
return null;
}
public void setMessage(final FragmentManager manager, final String message) {
final ProgressDialog dialog = getDialog(manager);
if (dialog != null)
{
dialog.setMessage(message);
}
}
/**
* Sets the progress of the dialog, we need to make sure we get the right dialog reference here
* which is why we obtain the dialog fragment manually from the fragment manager
* @param manager fragment manager
* @param progress how much progress has been made
*/
public void setProgress(final FragmentManager manager, final int progress)
{
final ProgressDialog dialog = getDialog(manager);
if (dialog != null)
{
dialog.setProgress(progress);
}
}
}
public final void setContext( final FragmentActivity context ) {
synchronized ( lock ) {
this.context = context;
}
handler.setContext(context);
}
protected final boolean validAuth() {
final SharedPreferences prefs = context.getSharedPreferences( ListFragment.SHARED_PREFS, 0);
if ( (!prefs.getString(ListFragment.PREF_AUTHNAME,"").isEmpty()) && (TokenAccess.hasApiToken(prefs))) {
return true;
}
return false;
}
protected final String getUsername() {
final SharedPreferences prefs = context.getSharedPreferences( ListFragment.SHARED_PREFS, 0);
String username = prefs.getString( ListFragment.PREF_USERNAME, "" );
if ( prefs.getBoolean( ListFragment.PREF_BE_ANONYMOUS, false) ) {
username = ListFragment.ANONYMOUS;
}
return username;
}
protected final String getPassword() {
final SharedPreferences prefs = context.getSharedPreferences( ListFragment.SHARED_PREFS, 0);
String password = prefs.getString( ListFragment.PREF_PASSWORD, "" );
if ( prefs.getBoolean( ListFragment.PREF_BE_ANONYMOUS, false) ) {
password = "";
}
return password;
}
protected final String getToken() {
final SharedPreferences prefs = context.getSharedPreferences( ListFragment.SHARED_PREFS, 0);
String token = TokenAccess.getApiToken(prefs);
if ( prefs.getBoolean( ListFragment.PREF_BE_ANONYMOUS, false) ) {
token = "";
}
return token;
}
/**
* @return null if ok, else an error status
*/
protected final Status validateUserPass(final String username, final String password) {
Status status = null;
if ( "".equals( username ) ) {
MainActivity.error( "username not defined" );
status = Status.BAD_USERNAME;
}
else if ( "".equals( password ) && ! ListFragment.ANONYMOUS.equals( username.toLowerCase(Locale.US) ) ) {
MainActivity.error( "password not defined and username isn't 'anonymous'" );
status = Status.BAD_PASSWORD;
}
return status;
}
}