// Path: AndroidApp/src/ca/psiphon/ploggy/widgets/TimePickerPreference.java
// public class TimePickerPreference extends DialogPreference implements
//                 TimePicker.OnTimeChangedListener {
// 
//         /**
//          * The validation expression for this preference
//          */
//         private static final String VALIDATION_EXPRESSION = "[0-2]*[0-9]:[0-5]*[0-9]";
// 
//         /**
//          * The default value for this preference
//          */
//         private final String defaultValue;
//         private String result;
//         private TimePicker tp;
// 
//         /**
//          * @param context
//          * @param attrs
//          */
//         public TimePickerPreference(Context context, AttributeSet attrs) {
//                 super(context, attrs);
//                 defaultValue = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "defaultValue");
//                 initialize();
//         }
// 
//         /**
//          * @param context
//          * @param attrs
//          * @param defStyle
//          */
//         public TimePickerPreference(Context context, AttributeSet attrs,
//                         int defStyle) {
//                 super(context, attrs, defStyle);
//                 defaultValue = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "defaultValue");
//                 initialize();
//         }
// 
//         /**
//          * Initialize this preference
//          */
//         private void initialize() {
//                 setPersistent(true);
//         }
// 
//         /*
//          * (non-Javadoc)
//          *
//          * @see android.preference.DialogPreference#onCreateDialogView()
//          */
//         @Override
//         protected View onCreateDialogView() {
// 
//                 tp = new TimePicker(getContext());
//                 tp.setOnTimeChangedListener(this);
// 
//                 String value = getPersistedString(this.defaultValue);
//                 int h = getHour(value);
//                 int m = getMinute(value);
//                 if (h >= 0 && m >= 0) {
//                         tp.setCurrentHour(h);
//                         tp.setCurrentMinute(m);
//                 }
//                 tp.setIs24HourView(DateFormat.is24HourFormat(getContext()));
// 
//                 return tp;
//         }
// 
//         /*
//          * (non-Javadoc)
//          *
//          * @see
//          * android.widget.TimePicker.OnTimeChangedListener#onTimeChanged(android
//          * .widget.TimePicker, int, int)
//          */
// 
//         @Override
//         public void onTimeChanged(TimePicker view, int hour, int minute) {
//                 result = hour + ":" + minute;
//         }
// 
//         /*
//          * (non-Javadoc)
//          *
//          * @see
//          * android.preference.DialogPreference#onDismiss(android.content.DialogInterface
//          * )
//          */
//         @Override
//         public void onDismiss(DialogInterface dialog) {
//                 super.onDismiss(dialog);
//         }
// 
//         /*
//          * (non-Javadoc)
//          *
//          * @see android.preference.DialogPreference#onDialogClosed(boolean)
//          */
//         @Override
//         protected void onDialogClosed(boolean positiveResult) {
//                 super.onDialogClosed(positiveResult);
//                 if (positiveResult) {
//                         tp.clearFocus();        // to get value of number if edited in text field, and clicking OK without clicking outside the field first (bug in NumberPicker)
//                         result = tp.getCurrentHour() + ":" + tp.getCurrentMinute();
//                         persistString(result);
//                         callChangeListener(result);
//                 }
//         }
// 
//         /**
//          * Get the hour value (in 24 hour time)
//          *
//          * @return The hour value, will be 0 to 23 (inclusive)
//          */
//         public static int getHour(String value) {
//                 if (value == null || !value.matches(VALIDATION_EXPRESSION)) {
//                         return -1;
//                 }
// 
//                 return Integer.valueOf(value.split(":|/")[0]);
//         }
// 
//         /**
//          * Get the minute value
//          *
//          * @return the minute value, will be 0 to 59 (inclusive)
//          */
//         public static int getMinute(String value) {
//                 if (value == null || !value.matches(VALIDATION_EXPRESSION)) {
//                         return -1;
//                 }
// 
//                 return Integer.valueOf(value.split(":|/")[1]);
//         }
// }


import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Pair;
import ca.psiphon.ploggy.widgets.TimePickerPreference;
import com.squareup.otto.Subscribe;

    public synchronized boolean getBooleanPreference(int keyResID) throws Utils.ApplicationError {
        String key = mContext.getString(keyResID);
        // Defaults which are "false" are not present in the preferences file
        // if (!mSharedPreferences.contains(key)) {...}
        // TODO: this is ambiguous: there's now no test for failure to initialize defaults
        return mSharedPreferences.getBoolean(key, false);
    }

    public synchronized int getIntPreference(int keyResID) throws Utils.ApplicationError {
        String key = mContext.getString(keyResID);
        if (!mSharedPreferences.contains(key)) {
            throw new Utils.ApplicationError(LOG_TAG, "missing preference default: " + key);
        }
        return mSharedPreferences.getInt(key, 0);
    }

    public synchronized boolean currentlySharingLocation() throws Utils.ApplicationError {
        if (!getBooleanPreference(R.string.preferenceAutomaticLocationSharing)) {
            return false;
        }

        Calendar now = Calendar.getInstance();

        if (getBooleanPreference(R.string.preferenceLimitLocationSharingTime)) {
            int currentHour = now.get(Calendar.HOUR_OF_DAY);
            int currentMinute = now.get(Calendar.MINUTE);

            String sharingTimeNotBefore = mSharedPreferences.getString(
                    mContext.getString(R.string.preferenceLimitLocationSharingTimeNotBefore), "");
// Path: AndroidApp/src/ca/psiphon/ploggy/widgets/TimePickerPreference.java
// public class TimePickerPreference extends DialogPreference implements
//                 TimePicker.OnTimeChangedListener {
// 
//         /**
//          * The validation expression for this preference
//          */
//         private static final String VALIDATION_EXPRESSION = "[0-2]*[0-9]:[0-5]*[0-9]";
// 
//         /**
//          * The default value for this preference
//          */
//         private final String defaultValue;
//         private String result;
//         private TimePicker tp;
// 
//         /**
//          * @param context
//          * @param attrs
//          */
//         public TimePickerPreference(Context context, AttributeSet attrs) {
//                 super(context, attrs);
//                 defaultValue = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "defaultValue");
//                 initialize();
//         }
// 
//         /**
//          * @param context
//          * @param attrs
//          * @param defStyle
//          */
//         public TimePickerPreference(Context context, AttributeSet attrs,
//                         int defStyle) {
//                 super(context, attrs, defStyle);
//                 defaultValue = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "defaultValue");
//                 initialize();
//         }
// 
//         /**
//          * Initialize this preference
//          */
//         private void initialize() {
//                 setPersistent(true);
//         }
// 
//         /*
//          * (non-Javadoc)
//          *
//          * @see android.preference.DialogPreference#onCreateDialogView()
//          */
//         @Override
//         protected View onCreateDialogView() {
// 
//                 tp = new TimePicker(getContext());
//                 tp.setOnTimeChangedListener(this);
// 
//                 String value = getPersistedString(this.defaultValue);
//                 int h = getHour(value);
//                 int m = getMinute(value);
//                 if (h >= 0 && m >= 0) {
//                         tp.setCurrentHour(h);
//                         tp.setCurrentMinute(m);
//                 }
//                 tp.setIs24HourView(DateFormat.is24HourFormat(getContext()));
// 
//                 return tp;
//         }
// 
//         /*
//          * (non-Javadoc)
//          *
//          * @see
//          * android.widget.TimePicker.OnTimeChangedListener#onTimeChanged(android
//          * .widget.TimePicker, int, int)
//          */
// 
//         @Override
//         public void onTimeChanged(TimePicker view, int hour, int minute) {
//                 result = hour + ":" + minute;
//         }
// 
//         /*
//          * (non-Javadoc)
//          *
//          * @see
//          * android.preference.DialogPreference#onDismiss(android.content.DialogInterface
//          * )
//          */
//         @Override
//         public void onDismiss(DialogInterface dialog) {
//                 super.onDismiss(dialog);
//         }
// 
//         /*
//          * (non-Javadoc)
//          *
//          * @see android.preference.DialogPreference#onDialogClosed(boolean)
//          */
//         @Override
//         protected void onDialogClosed(boolean positiveResult) {
//                 super.onDialogClosed(positiveResult);
//                 if (positiveResult) {
//                         tp.clearFocus();        // to get value of number if edited in text field, and clicking OK without clicking outside the field first (bug in NumberPicker)
//                         result = tp.getCurrentHour() + ":" + tp.getCurrentMinute();
//                         persistString(result);
//                         callChangeListener(result);
//                 }
//         }
// 
//         /**
//          * Get the hour value (in 24 hour time)
//          *
//          * @return The hour value, will be 0 to 23 (inclusive)
//          */
//         public static int getHour(String value) {
//                 if (value == null || !value.matches(VALIDATION_EXPRESSION)) {
//                         return -1;
//                 }
// 
//                 return Integer.valueOf(value.split(":|/")[0]);
//         }
// 
//         /**
//          * Get the minute value
//          *
//          * @return the minute value, will be 0 to 59 (inclusive)
//          */
//         public static int getMinute(String value) {
//                 if (value == null || !value.matches(VALIDATION_EXPRESSION)) {
//                         return -1;
//                 }
// 
//                 return Integer.valueOf(value.split(":|/")[1]);
//         }
// }


// Path: AndroidApp/src/ca/psiphon/ploggy/Engine.java
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Pair;
import ca.psiphon.ploggy.widgets.TimePickerPreference;
import com.squareup.otto.Subscribe;


    public synchronized boolean getBooleanPreference(int keyResID) throws Utils.ApplicationError {
        String key = mContext.getString(keyResID);
        // Defaults which are "false" are not present in the preferences file
        // if (!mSharedPreferences.contains(key)) {...}
        // TODO: this is ambiguous: there's now no test for failure to initialize defaults
        return mSharedPreferences.getBoolean(key, false);
    }

    public synchronized int getIntPreference(int keyResID) throws Utils.ApplicationError {
        String key = mContext.getString(keyResID);
        if (!mSharedPreferences.contains(key)) {
            throw new Utils.ApplicationError(LOG_TAG, "missing preference default: " + key);
        }
        return mSharedPreferences.getInt(key, 0);
    }

    public synchronized boolean currentlySharingLocation() throws Utils.ApplicationError {
        if (!getBooleanPreference(R.string.preferenceAutomaticLocationSharing)) {
            return false;
        }

        Calendar now = Calendar.getInstance();

        if (getBooleanPreference(R.string.preferenceLimitLocationSharingTime)) {
            int currentHour = now.get(Calendar.HOUR_OF_DAY);
            int currentMinute = now.get(Calendar.MINUTE);

            String sharingTimeNotBefore = mSharedPreferences.getString(
                    mContext.getString(R.string.preferenceLimitLocationSharingTimeNotBefore), "");
            int notBeforeHour = TimePickerPreference.getHour(sharingTimeNotBefore);