public class SensePrefs {
    /**
     * Keys for the authentication-related preferences of the Sense Platform
     */
    public static class Auth {
        /**
         * Key for login preference for session cookie.
         * 
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String LOGIN_COOKIE = "login_cookie";
        /**
         *Key for login preference for session id.
         *  
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String LOGIN_SESSION_ID = "session_id";
        /**
         * Key for login preference for email address.
         * 
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String LOGIN_USERNAME = "login_mail";
        /**
         * Key for login preference for hashed password.
         * 
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String LOGIN_PASS = "login_pass";
        /**
         * Key for storing the online sensor list for this device (type of JSONArray).
         * 
         * @see #SENSOR_LIST_COMPLETE
         * @see SensePrefs#AUTH_PREFS
         * @deprecated
         */
        public static final String SENSOR_LIST = "sensor_list";
        /**
         * Key for storing the online sensor list for this user (type of JSONArray).
         * 
         * @see #SENSOR_LIST
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String SENSOR_LIST_COMPLETE = "sensor_list_complete";
        /**
         * Key for storing the retrieval time of device's online sensor list.
         * 
         * @see #SENSOR_LIST_COMPLETE_TIME
         * @see SensePrefs#AUTH_PREFS
         * @deprecated
         */
        public static final String SENSOR_LIST_TIME = "sensor_list_timestamp";
        /**
         * Key for storing the retrieval time of complete online sensor list.
         * 
         * @see #SENSOR_LIST_TIME
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String SENSOR_LIST_COMPLETE_TIME = "sensor_list_complete_timestamp";
        /**
         * Key for storing the online device id.
         * 
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String DEVICE_ID = "device_id";
        /**
         * Key for storing the retrieval time of the online device id.
         * 
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String DEVICE_ID_TIME = "device_id_timestamp";
        /**
         * Key for storing the online device type.
         * 
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String DEVICE_TYPE = "device_type";
        /**
         * Key for storing the IMEI of the phone.
         * 
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String PHONE_IMEI = "phone_imei";
        /**
         * Key for storing the type of the phone.
         * 
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String PHONE_TYPE = "phone_type";
        /**
         * Key for storing if gcm registration_id
         * 
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String GCM_REGISTRATION_ID = "gcm_registration_id";

    }

    /**
     * Keys for the main Sense Platform service preferences
     */
    public static class Main {

        public static class Advanced {
            /**
             * Key to use the development version of CommonSense.
             * 
             * @see SensePrefs#AUTH_PREFS
             */
            public static final String DEV_MODE = "devmode";
            /**
             * Key for preference that toggles use of compression for transmission. Default is true.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String COMPRESS = "compression";
            /**
             * Key for preference that enables local storage, making the sensor data available to
             * other apps through a ContentProvider. Default is true.
             * 
             * @see SensePrefs#MAIN_PREFS
             * @deprecated Local storage is always on.
             */
            public static final String LOCAL_STORAGE = "local_storage";
            /**
             * Key for preference that enables communication with CommonSense. Disable this to work
             * in local-only mode. Default is true.
             */
            public static final String USE_COMMONSENSE = "use_commonsense";
            /**
             * Key for preference that enables the location feedback sensor. Enable this to
             * participate in Pim's location feedback test. Default is false.
             */
            public static final String LOCATION_FEEDBACK = "location_feedback";
            /**
             * Key for preference that enables Agostino mode. Enable this to participate in
             * Agostino's saliency test. Default is false.
             */
            public static final String AGOSTINO = "agostino_mode";
            /**
             * Key for preference that enables energy saving mode when using mobile Internet. 
             * When energy saving mode is on data will be uploaded every half an hour.
             * Default is true.
             * @see SensePrefs#MAIN_PREFS
             */            
            public static final String  MOBILE_INTERNET_ENERGY_SAVING_MODE = "mobile_internet_energy_saving_mode";
            /**
             * Key for preference that enables data upload on wifi only.
             * Default is false.
             * @see SensePrefs#MAIN_PREFS
             */            
            public static final String  WIFI_UPLOAD_ONLY = "wifi_upload_only";
            /**
             * Key for value of cache duration for local data in hours.
             * Default is 24.
             * @see SensePrefs#MAIN_PREFS
             */            
            public static final String  RETENTION_HOURS = "retention_hours";
            /**
             * Key for preference that enable database encryption.
             * Default is false.
             * @see SensePrefs#MAIN_PREFS
             */            
            public static final String  ENCRYPT_DATABASE = "encrypt_database";
            /**
             * Key for value of salt for database encryption
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String  ENCRYPT_DATABASE_SALT = "encrypt_database_salt";
            /**
             * Key for preference that enables encryption for credential data.
             * Default is false.
             * @see SensePrefs#MAIN_PREFS
             */            
            public static final String  ENCRYPT_CREDENTIAL = "encrypt_credential";
            /**
             * Key for value of salt for credential encryption.
             * @see SensePrefs#MAIN_PREFS
             */            
            public static final String  ENCRYPT_CREDENTIAL_SALT = "encrypt_credential_salt";
        }
        

        public static class Ambience {
            /**
             * Key for preference that toggles use of light sensor in ambience sensing.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String LIGHT = "ambience_light";
            /**
             * Key for preference that toggles use of camera light sensor in ambience sensing.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String CAMERA_LIGHT = "ambience_camera_light";
            /**
             * Key for preference that toggles use of the microphone in ambience sensing.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String MIC = "ambience_mic";
            /**
             * Key for preference that toggles audio recording ambience sensing.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String RECORD_AUDIO = "ambience_record_audio";
            /**
             * Key for preference that toggles use of the audio spectrum in ambience sensing.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String AUDIO_SPECTRUM = "ambience_audio_spectrum";
            /**
             * Key for preference that toggles use of the pressure sensor in ambience sensing.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String PRESSURE = "ambience_pressure";
            /**
             * Key for preference that toggles use of the temperature sensor in ambience sensing.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String TEMPERATURE = "ambience_temperature";
            /**
             * Key for preference that toggles use of the magnetic field sensor in ambience sensing.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String MAGNETIC_FIELD = "ambience_magnetic_field";
            /**
             * Key for preference that toggles use of the relative humidity sensor in ambience
             * sensing.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String HUMIDITY = "ambience_humidity";
            /**
             * Key for preference that toggles "burst-mode" for the noise sensor
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String BURSTMODE = "ambience_burstmode";
            /**
             * Key for preference that toggles whether to upload and store burst samples.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String DONT_UPLOAD_BURSTS = "ambience_dont_upload_bursts";
            /**
             * Key for preference that toggles whether to record one sided or two sided voice calls 
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String RECORD_TWO_SIDED_VOICE_CALL = "record_two_sided_voice_call";
        }

        public static class DevProx {
            /**
             * Key for preference that toggles use of Bluetooth in the Device Proximity sensor.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String BLUETOOTH = "proximity_bt";
            /**
             * Key for preference that toggles use of Wi-Fi in the Device Proximity sensor.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String WIFI = "proximity_wifi";
            /**
             * Key for preference that toggles use of NFC in the Device Proximity sensor.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String NFC = "proximity_nfc";
        }

        public static class External {

            public static class MyGlucoHealth {
                /**
                 * Key for preference that toggles use of the MyGlucohealth sensor.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String MAIN = "myglucohealth";
            }

            public static class TanitaScale {
                /**
                 * Key for preference that toggles use of the Tanita scale sensor.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String MAIN = "tanita_scale";
            }

            public static class ZephyrBioHarness {

                /**
                 * Key for preference that toggles use of the Zephyr BioHarness.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String MAIN = "zephyrBioHarness";
                /**
                 * Key for preference that toggles use of the Zephyr BioHarness Accelerometer.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String ACC = "zephyrBioHarness_acc";
                /**
                 * Key for preference that toggles use of the Zephyr BioHarness Heart rate.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String HEART_RATE = "zephyrBioHarness_heartRate";
                /**
                 * Key for preference that toggles use of the Zephyr BioHarness Temperature.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String TEMP = "zephyrBioHarness_temp";
                /**
                 * Key for preference that toggles use of the Zephyr BioHarness Respiration rate.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String RESP = "zephyrBioHarness_resp";
                /**
                 * Key for preference that toggles use of the Zephyr BioHarness worn status.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String WORN_STATUS = "zephyrBioHarness_wornStatus";
                /**
                 * Key for preference that toggles use of the Zephyr BioHarness battery level.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String BATTERY = "zephyrBioHarness_battery";
            }

            public static class ZephyrHxM {
                /**
                 * Key for preference that toggles use of the Zephyr HxM.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String MAIN = "zephyrHxM";
                /**
                 * Key for preference that toggles use of the Zephyr HxM speed.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String SPEED = "zephyrHxM_speed";
                /**
                 * Key for preference that toggles use of the Zephyr HxM heart rate.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String HEART_RATE = "zephyrHxM_heartRate";
                /**
                 * Key for preference that toggles use of the Zephyr HxM battery.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String BATTERY = "zephyrHxM_battery";
                /**
                 * Key for preference that toggles use of the Zephyr HxM distance.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String DISTANCE = "zephyrHxM_distance";
                /**
                 * Key for preference that toggles use of the Zephyr HxM strides.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String STRIDES = "zephyrHxM_strides";
            }

            public static class OBD2Sensor {
                /**
                 * Key for preference that toggles use of the OBD-II sensor.
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String MAIN = "obd2sensor";
            }
        }

        public static class Location {
            /**
             * Key for preference that toggles use of GPS in location sensor.
             * 
             * @see SensePrefs#MAIN_PREFS
             * @deprecated Selecting the location provider manually will replaced by the fused location provider.
             */
            @Deprecated
            public static final String GPS = "location_gps";
            /**
             * Key for preference that toggles use of Network in location sensor.
             * 
             * @see SensePrefs#MAIN_PREFS
             * @deprecated Selecting the location provider manually will replaced by the fused location provider.
             */
            @Deprecated
            public static final String NETWORK = "location_network";
            /**
             * Key for preference that toggles use of sensor fusion to toggle the GPS usage.
             * 
             * @see SensePrefs#MAIN_PREFS
             * @deprecated Selecting the GPS as provider automatically will be replaced by the fused location provider.
             */
            @Deprecated
            public static final String AUTO_GPS = "automatic_gps";
            /**
             * Key for preference that toggles use of the time zone sensor
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String TIME_ZONE = "time_zone";
            /**
             * Key for preference that toggles the use of the fused location provider.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String FUSED_PROVIDER = "location_fused";
            /**
             * Key for preference that sets the priority for the fused location provider.
             * By default the BALANCED priority is used.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String FUSED_PROVIDER_PRIORITY = "location_fused_priority";

            public static class FusedProviderPriority
            {
                /**
                 * Key for preference that toggles the use of the fused location provider with a high power consumption and accuracy.
                 * Accuracy: 1m (most precise location possible)
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String ACCURATE = "location_fused_accurate";
                /**
                 * Key for preference that toggles the use of the fused location provider with a balance between power consumption and accuracy.
                 * Accuracy: 100 (city block)
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String BALANCED = "location_fused_balanced";
                /**
                 * Key for preference that toggles the use of the fused location provider with low power consumption and accuracy.
                 * Accuracy: 10km (city level)
                 * 
                 * @see SensePrefs#MAIN_PREFS
                 */
                public static final String LOW_POWER = "location_fused_low_power";
            }
        }

        public static class Motion {
            /**
             * Key for preference that toggles use of Bluetooth in the DeviceProximity sensor.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String FALL_DETECT = "motion_fall_detector";
            /**
             * Key for preference that toggles use of Bluetooth in the DeviceProximity sensor.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String FALL_DETECT_DEMO = "motion_fall_detector_demo";
            /**
             * Key for preference that toggles "epi-mode", drastically changing motion sensing
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String EPIMODE = "epimode";
            /**
             * Key for preference that toggles "burst-mode", drastically changing motion sensing
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String BURSTMODE = "burstmode";
            /**
             * Key for preference that determines whether to unregister the motion sensor between
             * samples. Nota bene: unregistering the sensor breaks the screen rotation on some
             * phones (e.g. Nexus S).
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            
            /**
             * Key for preference that toggles whether to upload and store burst samples.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String DONT_UPLOAD_BURSTS = "dont upload bursts";
            
            /**
             * Key for preference that determines the burst duration. Duration is in milliseconds.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String BURST_DURATION = "burst_duration";
            
            public static final String UNREG = "motion_unregister";
            /**
             * Key for preference that toggles motion energy sensing, which measures average kinetic
             * energy over a sample period.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String MOTION_ENERGY = "motion_energy";
            /**
             * Key for preference that enables fix that re-registers the motion sensor when the
             * screen turns off.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String SCREENOFF_FIX = "screenoff_fix";
            /**
             * Key for preference that toggles the use of the gyroscope
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String GYROSCOPE = "gyroscope";
            /**
             * Key for preference that toggles the use of the accelerometer
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String ACCELEROMETER = "accelerometer";
            /**
             * Key for preference that toggles the use of the orientation sensor
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String ORIENTATION = "orientation";
            /**
             * Key for preference that toggles the use of the linear acceleration sensor
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String LINEAR_ACCELERATION = "linear_acceleration";
        }

        public static class PhoneState {
            /**
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String BATTERY = "phonestate_battery";
            /**
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String SCREEN_ACTIVITY = "phonestate_screen_activity";
            /**
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String PROXIMITY = "phonestate_proximity";
            /**
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String IP_ADDRESS = "phonestate_ip";
            /**
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String DATA_CONNECTION = "phonestate_data_connection";
            /**
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String UNREAD_MSG = "phonestate_unread_msg";
            /**
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String SERVICE_STATE = "phonestate_service_state";
            /**
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String SIGNAL_STRENGTH = "phonestate_signal_strength";
            /**
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String CALL_STATE = "phonestate_call_state";
            /**
             * @see SensePrefs#MAIN_PREFS
             *              */
            public static final String FOREGROUND_APP = "foreground_app";
            /**
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String INSTALLED_APPS = "installed_apps";
            
            /**
             * @see SensePrefs#MAIN_PREFS
             */
			public static final String APP_INFO = "app_info";
        }

        public static class Quiz {
            /**
             * Key for preference that sets the interval between pop quizzes.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String RATE = "popquiz_rate";
            /**
             * Key for preference that sets the silent mode for pop quizzes.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String SILENT_MODE = "popquiz_silent_mode";
            /**
             * Key for generic preference that starts an update of the quiz questions when clicked.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String SYNC = "popquiz_sync";
            /**
             * Key for preference that holds the last update time of the quiz questions with
             * CommonSense.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String SYNC_TIME = "popquiz_sync_time";
        }

        public static class SampleRate {
            /**
             * Key for the preference that sets the sample interval to every 15 minutes.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String RARELY = "1";

            /**
             * Key for the preference that sets the sample interval to every 3 minutes.
             * For the Location sensors this is 5 minutes.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String BALANCED = "2";

            /**
             * Key for the preference that sets the sample interval to every minute.
             * For the Location sensors this is 5 minutes.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String NORMAL = "0";

            /**
             * Key for the preference that sets the sample interval to every 10 seconds.
             * For the Location sensors this is every 30 seconds.
             * For the External sensors this is every 5 seconds.
             * For the Motion sensors this is every 5 seconds.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String OFTEN = "-1";

            /**
             * Key for the preference that sets the sample interval to every second.
             * For the Ambience sensors this is as fast as possible.
             * For the Noise sensor this enabled the recording of audio files.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String REAL_TIME = "-2";
        }

        public static class SyncRate {
            /**
             * Key for the preference that enables data buffering and sets the upload interval to every 15 minutes.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String RARELY = "2";
            /**
             * Key for the preference that enables data buffering and sets the upload interval to every 30 minutes.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String ECO_MODE = "1";

            /**
             * Key for the preference that enables data buffering and sets the upload interval to every 5 minutes.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String NORMAL = "0";

            /**
             * Key for the preference that enables data buffering and sets the upload interval to every minute.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String OFTEN = "-1";

            /**
             * Key for the preference that disables data buffering and uploads every data point immediately.
             * 
             * @see SensePrefs#MAIN_PREFS
             */
            public static final String REAL_TIME = "-2";
        }

        /**
         * Key for preference that controls sample frequency of the sensors.
         * 
         * @see SensePrefs#MAIN_PREFS
         */
        public static final String SAMPLE_RATE = "commonsense_rate";
        /**
         * Key for preference that controls sync frequency with CommonSense.
         * 
         * @see SensePrefs#MAIN_PREFS
         */
        public static final String SYNC_RATE = "sync_rate";
        /**
         * Key for preference that saves the last running services.
         * 
         * @see SensePrefs#MAIN_PREFS
         */
        public static final String LAST_STATUS = "last_status";
        /**
         * Key for preference that stores a flag for first login.
         * 
         * @see SensePrefs#MAIN_PREFS
         */
        public static final String LAST_LOGGED_IN = "never_logged_in";
        /**
         * Key for preference that stores a timestamp for last time the sensors registration was
         * verified
         * 
         * @see SensePrefs#MAIN_PREFS
         */
        public static final String LAST_VERIFIED_SENSORS = "verified_sensors";
        /**
         * Key for storing the application key
         * 
         * @see SensePrefs#AUTH_PREFS
         */
        public static final String APPLICATION_KEY = "application_key";
    }

    /**
     * Keys for the status preferences of the Sense Platform service
     */
    public static class Status {
        /**
         * Key for the main status of the sensors. Set to <code>false</code> to disable all the
         * sensing components.
         * 
         * @see SensePrefs#STATUS_PREFS
         */
        public static final String MAIN = "main service status";
        /**
         * Key for the status of the "ambience" sensors. Set to <code>true</code> to enable sensing.
         * 
         * @see SensePrefs#STATUS_PREFS
         */
        public static final String AMBIENCE = "ambience component status";
        /**
         * Key for the status of the "device proximity" sensors. Set to <code>true</code> to enable
         * sensing.
         * 
         * @see SensePrefs#STATUS_PREFS
         */
        public static final String DEV_PROX = "device proximity component status";
        /**
         * Key for the status of the external Bluetooth sensors. Set to <code>true</code> to enable
         * sensing.
         * 
         * @see SensePrefs#STATUS_PREFS
         */
        public static final String EXTERNAL = "external services component status";
        /**
         * Key for the status of the location sensors. Set to <code>true</code> to enable sensing.
         * 
         * @see SensePrefs#STATUS_PREFS
         */
        public static final String LOCATION = "location component status";
        /**
         * Key for the status of the motion sensors. Set to <code>true</code> to enable sensing.
         * 
         * @see SensePrefs#STATUS_PREFS
         */
        public static final String MOTION = "motion component status";
        /**
         * Key for the status of the "phone state" sensors. Set to <code>true</code> to enable
         * sensing.
         * 
         * @see SensePrefs#STATUS_PREFS
         */
        public static final String PHONESTATE = "phone state component status";
        /**
         * Key for the status of the questionnaire. Set to <code>true</code> to enable it.
         * 
         * @see SensePrefs#STATUS_PREFS
         * @deprecated Sense does not support the questionnaire anymore
         */
        public static final String POPQUIZ = "pop quiz component status";
        /**
         * Key for preference to automatically start the Sense service on boot.
         * 
         * @see SensePrefs#STATUS_PREFS
         */
        public static final String AUTOSTART = "autostart";
        /**
        * Key for preference to pause sensing until the next charge.
        * 
        * @see SensePrefs#STATUS_PREFS
        */
        public static final String PAUSED_UNTIL_NEXT_CHARGE = "paused until next charge status";
    }

    public static class SensorSpecifics {
        public static class Loudness {
            /**
             * Key for learned value of total silence..
             */
            public static final String TOTAL_SILENCE = "total_silence";
            /**
             * Key for learned value of highest loudness.
             */
            public static final String LOUDEST = "loudest";
        }

        public static class AutoCalibratedNoise {
            /**
             * Key for learned value of total silence..
             */
            public static final String TOTAL_SILENCE = "AutoCalibratedNoise.total_silence";
            /**
             * Key for learned value of highest loudness.
             */
            public static final String LOUDEST = "AutoCalibratedNoise.loudest";
        }
    }

    /**
     * Name of the shared preferences file used for storing CommonSense authentication data. Use
     * {@link Context#MODE_PRIVATE}.
     * 
     * @see #MAIN_PREFS_PREFS
     * @see #STATUS_PREFS
     */
    public static final String AUTH_PREFS = "authentication";// "login";
    /**
     * Name of the main preference file, used for storing the settings for the Sense service.
     * 
     * @see #AUTH_PREFS
     * @see #STATUS_PREFS
     */
    public static final String MAIN_PREFS = "main";
    /**
     * Name of shared preferences file holding the desired status of the Sense service.
     * 
     * @see #AUTH_PREFS
     * @see #MAIN_PREFS
     */
    public static final String STATUS_PREFS = "service_status_prefs";
    /**
     * Name of the sensor specifics file, used for storing the settings for the Sense service.
     * 
     * @see #AUTH_PREFS
     * @see #STATUS_PREFS
     */
    public static final String SENSOR_SPECIFICS = "sensor_specifics";

    private SensePrefs() {
        // private constructor to prevent instantiation
    }
}
 public static class Motion {
    /**
     * Key for preference that toggles use of Bluetooth in the DeviceProximity sensor.
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String FALL_DETECT = "motion_fall_detector";
    /**
     * Key for preference that toggles use of Bluetooth in the DeviceProximity sensor.
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String FALL_DETECT_DEMO = "motion_fall_detector_demo";
    /**
     * Key for preference that toggles "epi-mode", drastically changing motion sensing
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String EPIMODE = "epimode";
    /**
     * Key for preference that toggles "burst-mode", drastically changing motion sensing
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String BURSTMODE = "burstmode";
    /**
     * Key for preference that determines whether to unregister the motion sensor between
     * samples. Nota bene: unregistering the sensor breaks the screen rotation on some
     * phones (e.g. Nexus S).
     * 
     * @see SensePrefs#MAIN_PREFS
     */
            
    /**
     * Key for preference that toggles whether to upload and store burst samples.
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String DONT_UPLOAD_BURSTS = "dont upload bursts";
            
    /**
     * Key for preference that determines the burst duration. Duration is in milliseconds.
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String BURST_DURATION = "burst_duration";
            
    public static final String UNREG = "motion_unregister";
    /**
     * Key for preference that toggles motion energy sensing, which measures average kinetic
     * energy over a sample period.
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String MOTION_ENERGY = "motion_energy";
    /**
     * Key for preference that enables fix that re-registers the motion sensor when the
     * screen turns off.
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String SCREENOFF_FIX = "screenoff_fix";
    /**
     * Key for preference that toggles the use of the gyroscope
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String GYROSCOPE = "gyroscope";
    /**
     * Key for preference that toggles the use of the accelerometer
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String ACCELEROMETER = "accelerometer";
    /**
     * Key for preference that toggles the use of the orientation sensor
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String ORIENTATION = "orientation";
    /**
     * Key for preference that toggles the use of the linear acceleration sensor
     * 
     * @see SensePrefs#MAIN_PREFS
     */
    public static final String LINEAR_ACCELERATION = "linear_acceleration";
}
 public static class SensorNames {

    /**
     * Fall detector sensor. Can be a real fall or a regular free fall for demo's. Part of the
     * Motion sensors.
     */
    public static final String FALL_DETECTOR = "fall_detector";

    /** Noise level sensor. Part of the Ambience sensors. */
    public static final String NOISE = "noise_sensor";

    /** Noise level sensor (Burst-mode). Part of the Ambience sensors. */
    public static final String NOISE_BURST = "noise_sensor (burst-mode)";

    /** Audio spectrum sensor. Part of the Ambience sensors. */
    public static final String AUDIO_SPECTRUM = "audio_spectrum";

    /** Microphone output. Part of the Ambience sensors (real-time mode only). */
    public static final String MIC = "microphone";

    /** Light sensor. Part of the Ambience sensors. */
    public static final String LIGHT = "light";

    /** Camera Light sensor. Part of the Ambience sensors. */
    public static final String CAMERA_LIGHT = "camera_light";

    /** Bluetooth discovery sensor. Part of the Neighboring Devices sensors. */
    public static final String BLUETOOTH_DISCOVERY = "bluetooth_discovery";

    /** Wi-Fi scan sensor. Part of the Neighboring Devices sensors. */
    public static final String WIFI_SCAN = "wifi scan";

    /** NFC sensor. Part of the Neighboring Devices sensors. */
    public static final String NFC_SCAN = "nfc_scan";

    /** Acceleration sensor. Part of the Motion sensors, also used in Zephyr BioHarness */
    public static final String ACCELEROMETER = "accelerometer";

    /** Motion sensor. The basis for the other Motion sensors. */
    public static final String MOTION = "motion";

    /** Linear acceleration sensor name. Part of the Motion sensors. */
    public static final String LIN_ACCELERATION = "linear acceleration";

    /** Gyroscope sensor name. Part of the Motion sensors. */
    public static final String GYRO = "gyroscope";

    /** Magnetic field sensor name. Part of the Ambience sensors. */
    public static final String MAGNETIC_FIELD = "magnetic field";

    /** Orientation sensor name. Part of the Motion sensors. */
    public static final String ORIENT = "orientation";

    /** Epi-mode accelerometer sensor. Special part of the Motion sensors. */
    public static final String ACCELEROMETER_EPI = "accelerometer (epi-mode)";

    /** Burst-mode accelerometer sensor. Special part of the Motion sensors. */
    public static final String ACCELEROMETER_BURST = "accelerometer (burst-mode)";

    /** Burst-mode gyroscope sensor. Special part of the Motion sensors. */
    public static final String GYRO_BURST = "gyroscope (burst-mode)";

    /** Burst-mode linear acceleration sensor. Special part of the Motion sensors. */
    public static final String LINEAR_BURST = "linear acceleration (burst-mode)";

    /** Motion energy sensor name. Special part of the Motion sensors. */
    public static final String MOTION_ENERGY = "motion energy";

    /*** battery sensor for Zephyr BioHarness external sensor */
    public static final String BATTERY_LEVEL = "battery level";

    /** heart rate sensor for Zephyr BioHarness and HxM external sensors */
    public static final String HEART_RATE = "heart rate";

    /** respiration rate sensor for Zephyr BioHarness external sensor */
    public static final String RESPIRATION = "respiration rate";

    /** temperature sensor for Zephyr BioHarness external sensor */
    public static final String TEMPERATURE = "temperature";

    /** worn status for Zephyr BioHarness external sensor */
    public static final String WORN_STATUS = "worn status";

    /** blood pressure sensor */
    public static final String BLOOD_PRESSURE = "blood_pressure";

    /** reaction time sensor */
    public static final String REACTION_TIME = "reaction_time";

    /** speed sensor for Zephyr HxM external sensor */
    public static final String SPEED = "speed";

    /** distance sensor for Zephyr HxM external sensor */
    public static final String DISTANCE = "distance";

    /** battery sensor for Zephyr HxM external sensor */
    public static final String BATTERY_CHARGE = "battery charge";

    /** strides sensor (stappenteller) for Zephyr HxM external sensor */
    public static final String STRIDES = "strides";

    /** Location sensor. */
    public static final String LOCATION = "position";

    /** TimeZone sensor. */
    public static final String TIME_ZONE = "time_zone";

    /** Battery sensor. Part of the Phone State sensors. */
    public static final String BATTERY_SENSOR = "battery sensor";
        
    /** App info sensor. Part of the Phone State sensors. */
    public static final String APP_INFO_SENSOR = "app_info";

    /** Screen activity sensor. Part of the Phone State sensors. */
    public static final String SCREEN_ACTIVITY = "screen activity";

    /** Pressure sensor. Part of the Phone State sensors. */
    public static final String PRESSURE = "pressure";

    /** Proximity sensor. Part of the Phone State sensors. */
    public static final String PROXIMITY = "proximity";

    /** Call state sensor. Part of the Phone State sensors. */
    public static final String CALL_STATE = "call state";

    /** Data connection state sensor. Part of the Phone State sensors. */
    public static final String DATA_CONN = "data connection";

    /** IP address sensor. Part of the Phone State sensors. */
    public static final String IP_ADDRESS = "ip address";

    /** Mobile service state sensor. Part of the Phone State sensors. */
    public static final String SERVICE_STATE = "service state";

    /** Mobile signal strength sensor. Part of the Phone State sensors. */
    public static final String SIGNAL_STRENGTH = "signal strength";

    /** Unread messages sensor. Part of the Phone State sensors. */
    public static final String UNREAD_MSG = "unread msg";

    /** Data connection type sensor. Part of the Phone State sensors. */
    public static final String CONN_TYPE = "connection type";

    /** Monitor status since DTCs cleared. Part of the OBD-II sensors. */
    public static final String MONITOR_STATUS = "monitor status";

    /** Fuel system status. Part of the OBD-II sensors. */
    public static final String FUEL_SYSTEM_STATUS = "fuel system status";

    /** Calculated engine load. Part of the OBD-II sensors. */
    public static final String ENGINE_LOAD = "calculated engine load value";

    /** Engine coolant. Part of the OBD-II sensors. */
    public static final String ENGINE_COOLANT = "engine coolant";

    /** Short/Long term fuel trim bank 1 & 2. Part of the OBD-II sensors. */
    public static final String FUEL_TRIM = "fuel trim";

    /** Fuel Pressure. Part of the OBD-II sensors. */
    public static final String FUEL_PRESSURE = "fuel pressure";

    /** Intake manifold absolute pressure. Part of the OBD-II sensors. */
    public static final String INTAKE_PRESSURE = "intake manifold absolute pressure";

    /** Engine RPM. Part of the OBD-II sensors. */
    public static final String ENGINE_RPM = "engine RPM";

    /** Vehicle speed. Part of the OBD-II sensors. */
    public static final String VEHICLE_SPEED = "vehicle speed";

    /** Timing advance. Part of the OBD-II sensors. */
    public static final String TIMING_ADVANCE = "timing advance";

    /** Intake air temperature. Part of the OBD-II sensors. */
    public static final String INTAKE_TEMPERATURE = "intake air temperature";

    /** MAF air flow rate. Part of the OBD-II sensors. */
    public static final String MAF_AIRFLOW = "MAF air flow rate";

    /** Throttle position. Part of the OBD-II sensors. */
    public static final String THROTTLE_POSITION = "throttle position";

    /** Commanded secondary air status. Part of the OBD-II sensors. */
    public static final String AIR_STATUS = "commanded secondary air status";

    /** Oxygen sensors. Part of the OBD-II sensors. */
    public static final String OXYGEN_SENSORS = "oxygen sensors";

    /** OBD standards. Part of the OBD-II sensors. */
    public static final String OBD_STANDARDS = "OBD standards";

    /** Auxiliary input status. Part of the OBD-II sensors. */
    public static final String AUXILIARY_INPUT = "auxiliary input status";

    /** Run time since engine start. Part of the OBD-II sensors. */
    public static final String RUN_TIME = "run time";

    /** Ambient temperature sensor. Part of the ambience sensors. From API >= 14 only */
    public static final String AMBIENT_TEMPERATURE = "ambient_temperature";

    /** Relative humidity sensor. Part of the ambience sensors. From API >= 14 only */
    public static final String RELATIVE_HUMIDITY = "relative_humidity";

    /** Bluetooth number of neighbours, count sensor */
    public static final String BLUETOOTH_NEIGHBOURS_COUNT = "bluetooth neighbours count";

    /** Traveled distance for each day */
    public static final String TRAVELED_DISTANCE_24H = "traveled distance 24h";

    /** Traveled distance for each hour */
    public static final String TRAVELED_DISTANCE_1H = "traveled distance 1h";

    public static final String LOUDNESS = "loudness";

    public static final String ATTACHED_TO_MYRIANODE = "attachedToMyriaNode";

    public static final String APP_INSTALLED = "installed_apps";

    public static final String APP_FOREGROUND = "foreground_app";

    private SensorNames() {
        // class should not be instantiated
    }
} public class SNTP {
    private static final String TAG = "SNTP";

    private static final int ORIGINATE_TIME_OFFSET = 24;
    private static final int RECEIVE_TIME_OFFSET = 32;
    private static final int TRANSMIT_TIME_OFFSET = 40;
    private static final int NTP_PACKET_SIZE = 48;

    private static final int NTP_PORT = 123;
    private static final int NTP_MODE_CLIENT = 3;
    private static final int NTP_VERSION = 3;
    public static final String HOST_WORLDWIDE = "pool.ntp.org";
    public static final String HOST_ASIA = "asia.pool.ntp.org";
    public static final String HOST_EUROPE = "europe.pool.ntp.org";
    public static final String HOST_NORTH_AMERICA = "north-america.pool.ntp.org";
    public static final String HOST_SOUTH_AMERICA = "south-america.pool.ntp.org";
    public static final String HOST_OCEANIA = "oceania.pool.ntp.org";
    private boolean useSimulateTime = false;

    // Number of seconds between Jan 1, 1900 and Jan 1, 1970
    // 70 years plus 17 leap days
    private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;

    // system time computed from NTP server response
    private long mNtpTime;

    // value of SystemClock.elapsedRealtime() corresponding to mNtpTime
    private long mNtpTimeReference;

    // round trip time in milliseconds
    private long mRoundTripTime;

    private long clockOffset = -1;

    private static SNTP sntp = null;

    /**
     * Returns whether time simulation is used
     * @return True is simulate time is being used
     */
    public boolean isSimulatingTime()
    {
        return useSimulateTime;
    }

    /**
     * Sets the current simulation time
     *
     * Will set the clock to the provided simulation time.<br>
     * #getTime will give the updated time based on this simulation time<br>
     * @param time The epoch time in ms to use as current time
     */
    public void setCurrentSimulationTime(long time)
    {
        clockOffset = time - System.currentTimeMillis();
        useSimulateTime = true;
    }

    /**
     * Disables the time simulation
     */
    public void disableTimeSimulation()
    {
        if(!useSimulateTime)
            return;
        clockOffset = -1;
        useSimulateTime = false;
    }
    /*
     * Nice singleton :)
     */
    public synchronized static SNTP getInstance() {
        if (sntp == null)
            sntp = new SNTP();
        return sntp;
    }

    /**
     * Sends an SNTP request to the given host and processes the response.
     * 
     * @param host
     *            host name of the server.
     * @param timeout
     *            network timeout in milliseconds.
     * @return true if the transaction was successful.
     */
    public boolean requestTime(String host, int timeout) {
	try {
	    DatagramSocket socket = new DatagramSocket();
	    socket.setSoTimeout(timeout);
	    InetAddress address = InetAddress.getByName(host);
	    byte[] buffer = new byte[NTP_PACKET_SIZE];
	    DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);

	    // set mode = 3 (client) and version = 3
	    // mode is in low 3 bits of first byte
	    // version is in bits 3-5 of first byte
	    buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);

	    // get current time and write it to the request packet
	    long requestTime = System.currentTimeMillis();
	    long requestTicks = SystemClock.elapsedRealtime();
	    writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);

	    socket.send(request);

	    // read the response
	    DatagramPacket response = new DatagramPacket(buffer, buffer.length);
	    socket.receive(response);
	    long responseTicks = SystemClock.elapsedRealtime();
	    long responseTime = requestTime + (responseTicks - requestTicks);
	    socket.close();

	    // extract the results
	    long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
	    long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
	    long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
	    long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);
	    // receiveTime = originateTime + transit + skew
	    // responseTime = transmitTime + transit - skew
	    // clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2
	    // = ((originateTime + transit + skew - originateTime) +
	    // (transmitTime - (transmitTime + transit - skew)))/2
	    // = ((transit + skew) + (transmitTime - transmitTime - transit + skew))/2
	    // = (transit + skew - transit + skew)/2
	    // = (2 * skew)/2 = skew
	    clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime)) / 2;
	    // if (Config.LOGD) Log.d(TAG, "round trip: " + roundTripTime + " ms");
	    // if (Config.LOGD) Log.d(TAG, "clock offset: " + clockOffset + " ms");

	    // save our results - use the times on this side of the network latency
	    // (response rather than request time)
	    mNtpTime = responseTime + clockOffset;
	    mNtpTimeReference = responseTicks;
	    mRoundTripTime = roundTripTime;
	} catch (Exception e) {
	    Log.w(TAG, "Request time failed: " + e);
	    return false;
	}

	return true;
    }

    /**
     * Get the current time, based on NTP clockOffset if or System time
     * 
     * @return the ntp time from the worldwide pool if available else the system time
     */
    public long getTime() {
	// get the clock offset
	if (clockOffset == -1) {
	    if (requestTime(HOST_WORLDWIDE, 1000)) {
		return getNtpTime();
	    } else {
		clockOffset = 0;
	    }
	}

	return System.currentTimeMillis() + clockOffset;
    }

    /**
     * Returns the time computed from the NTP transaction.
     * 
     * @return time value computed from NTP server response.
     */
    public long getNtpTime() {
    	//Log.d(TAG,"SNTP time requested");
    	//return 1412175540000l;
    	return mNtpTime;
    }

    /**
     * Returns the reference clock value (value of SystemClock.elapsedRealtime()) corresponding to
     * the NTP time.
     * 
     * @return reference clock corresponding to the NTP time.
     */
    public long getNtpTimeReference() {
	return mNtpTimeReference;
    }

    /**
     * Returns the round trip time of the NTP transaction
     * 
     * @return round trip time in milliseconds.
     */
    public long getRoundTripTime() {
	return mRoundTripTime;
    }

    /**
     * Reads an unsigned 32 bit big endian number from the given offset in the buffer.
     */
    private long read32(byte[] buffer, int offset) {
	byte b0 = buffer[offset];
	byte b1 = buffer[offset + 1];
	byte b2 = buffer[offset + 2];
	byte b3 = buffer[offset + 3];

	// convert signed bytes to unsigned values
	int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
	int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
	int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
	int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);

	return ((long) i0 << 24) + ((long) i1 << 16) + ((long) i2 << 8) + (long) i3;
    }

    /**
     * Reads the NTP time stamp at the given offset in the buffer and returns it as a system time
     * (milliseconds since January 1, 1970).
     */
    private long readTimeStamp(byte[] buffer, int offset) {
	long seconds = read32(buffer, offset);
	long fraction = read32(buffer, offset + 4);
	return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);
    }

    /**
     * Writes system time (milliseconds since January 1, 1970) as an NTP time stamp at the given
     * offset in the buffer.
     */
    private void writeTimeStamp(byte[] buffer, int offset, long time) {
	long seconds = time / 1000L;
	long milliseconds = time - seconds * 1000L;
	seconds += OFFSET_1900_TO_1970;

	// write seconds in big endian format
	buffer[offset++] = (byte) (seconds >> 24);
	buffer[offset++] = (byte) (seconds >> 16);
	buffer[offset++] = (byte) (seconds >> 8);
	buffer[offset++] = (byte) (seconds >> 0);

	long fraction = milliseconds * 0x100000000L / 1000L;
	// write fraction in big endian format
	buffer[offset++] = (byte) (fraction >> 24);
	buffer[offset++] = (byte) (fraction >> 16);
	buffer[offset++] = (byte) (fraction >> 8);
	// low order bits should be random data
	buffer[offset++] = (byte) (Math.random() * 255.0);
    }
} public class PeriodicPollAlarmReceiver implements Runnable {

    private final PeriodicPollingSensor sensor;

    public PeriodicPollAlarmReceiver(PeriodicPollingSensor sensor) {
        this.sensor = sensor;
    }

    @Override
    public void run() {
        sensor.doSample();
    }

    /**
     * Starts periodically calling {@link BasePeriodicPollingSensor#doSample()}. Schedules a
     * periodic alarm, and registers itself as alarm receiver.
     * 
     * @param context
     *            Application context, used to register as BroadcastReceiver, and to schedule alarms
     */
    public void start(Context context) {

        // schedule alarm broadcasts
        long interval = sensor.getSampleRate();
        Scheduler.getInstance(context).register(this, interval, (long) (interval * 0.2));
    }

    /**
     * Stops the periodic polling. Unregisters as BroadcastReceiver and stops the periodic alarm
     * broadcasts.
     * 
     * @param context
     *            Application context, used to modify broadcast registration and alarm schedule
     */
    public void stop(Context context) {

        // stop alarm broadcasts
        Scheduler.getInstance(context).unregister(this);
    }
} public interface PeriodicPollingSensor extends SenseSensor {

    /**
     * Called by the {@link PeriodicPollAlarmReceiver} to check if the sensor is still active.
     * 
     * @return true if the sensor is active
     */
    public abstract boolean isActive();

    /**
     * Performs a sample. Called by the {@link PeriodicPollAlarmReceiver}.
     */
    public abstract void doSample();

} public class SensorDataPoint {

    public enum DataType {
        INT, FLOAT, BOOL, DOUBLE, STRING, ARRAYLIST, JSON, JSONSTRING, FILE, SENSOREVENT
    };

    /**
     * Name of the sensor that produced the data point.
     */
    public String sensorName;
    /**
     * Description of the sensor that produces the data point. Corresponds to the "sensor_type"
     * field in the CommonSense API.
     */
    public String sensorDescription;
    /**
     * Time stamp of the data point.
     */
    public long timeStamp;
    private DataType dataType;
    private Object value;

    /**
     * @see #SensorDataPoint(int)
     */
    public SensorDataPoint(Object value) {       
        this.value = value;
    }
    
    /**
     * @see #SensorDataPoint(int)
     */
    public SensorDataPoint(ArrayList<SensorDataPoint> value) {
        dataType = DataType.ARRAYLIST;
        this.value = value;
    }

    /**
     * @see #SensorDataPoint(int)
     */
    public SensorDataPoint(Boolean value) {
        dataType = DataType.BOOL;
        this.value = value;
    }

    /**
     * @see #SensorDataPoint(int)
     */
    public SensorDataPoint(double value) {
        dataType = DataType.DOUBLE;
        this.value = value;
    }

    /**
     * @see #SensorDataPoint(int)
     */
    public SensorDataPoint(float value) {
        dataType = DataType.FLOAT;
        this.value = value;
    }

    /**
     * Sets the value of the SensorDataPoint based on the input value the dataType. The dataType can
     * be changed by {@link #setDataType(DataType)}.
     * 
     * @param value
     *            The input value which is stored in the SensorDataPoint
     */
    public SensorDataPoint(int value) {
        dataType = DataType.INT;
        this.value = value;
    }

    /**
     * @see #setValue(int)
     */
    public SensorDataPoint(JSONObject value) {
        dataType = DataType.JSON;
        this.value = value;
    }

    /**
     * @see #setValue(int)
     */
    public SensorDataPoint(SensorEvent value) {
        dataType = DataType.SENSOREVENT;
        this.value = value;
    }

    /**
     * @see #setValue(int)
     */
    public SensorDataPoint(String value) {
        dataType = DataType.STRING;
        this.value = value;
    }

    /**
     * @see #getIntValue()
     */
    @SuppressWarnings("unchecked")
    public ArrayList<SensorDataPoint> getArrayValue() {
        return (ArrayList<SensorDataPoint>) value;
    }

    /**
     * @see #getIntValue()
     */
    public Boolean getBoolValue() {
        return (Boolean) value;
    }

    /**
     * Returns the dataType of the SensorDataPoint
     * 
     * @return DataTypes
     */
    public DataType getDataType() {
        return dataType;
    }

    /**
     * @see #getIntValue()
     */
    public double getDoubleValue() {
        return (Double) value;
    }

    /**
     * @see #getIntValue()
     */
    public float getFloatValue() {
        return (Float) value;
    }

    /**
     * Return the value of the SensorDataPoint
     * 
     * @return value
     */
    public int getIntValue() {
        return (Integer) value;
    }

    /**
     * @see #getIntValue()
     */
    public JSONObject getJSONValue() {
        return (JSONObject) value;
    }

    /**
     * @see #getIntValue()
     */
    public SensorEvent getSensorEventValue() {
        return (SensorEvent) value;
    }

    /**
     * @see #getIntValue()
     */
    public String getStringValue() {
        return (String) value;
    }

    /**
     * Sets the data type.
     * 
     * This method overrides the dataType which has been set automatically. This method can be used
     * when a more precise dataType like FILE is needed.
     * 
     * @param dataType
     *            The dataType of the SensorDataPoint
     */
    public void setDataType(DataType dataType) {
        this.dataType = dataType;
    }
} public class EpiStateMonitor extends AbstractStateMonitor {

    private static final long TIME_RANGE = 5000;
    private static final String ACTION_UPDATE_STATE = "nl.sense_os.states.EpiStateUpdate";
    private static final String TAG = "EpiStateMonitor";
    private long lastAnalyzed;

    /**
     * Updates the epi-state by analyzing the local data points.
     */
    @Override
    protected void updateState() {
        // Log.d(TAG, "update state");

        Cursor fallData = null;
        Cursor epiData = null;
        try {
            LocalStorage storage = LocalStorage.getInstance(this);

            // query fall detector
            Uri contentUri = Uri.parse("content://" + getString(R.string.local_storage_authority)
                    + DataPoint.CONTENT_URI_PATH);
            String[] projection = new String[] { DataPoint._ID, DataPoint.SENSOR_NAME,
                    DataPoint.VALUE, DataPoint.TIMESTAMP };
            String where = DataPoint.SENSOR_NAME + "='" + SensorData.SensorNames.FALL_DETECTOR
                    + "'" + " AND " + DataPoint.TIMESTAMP + ">"
                    + (SNTP.getInstance().getTime() - TIME_RANGE);
            fallData = storage.query(contentUri, projection, where, null, null);

            if (null != fallData && fallData.moveToFirst()) {
                int result = analyzeFallData(fallData);
                // Log.d(TAG, "Fall analysis result: " + result);
                if (result > 0) {
                    sendAlert(fallData);
                    return;
                }
            } else {
                // Log.d(TAG, "No recent fall data to analyze");
            }

            // query epi acceleration
            projection = new String[] { DataPoint._ID, DataPoint.SENSOR_NAME, DataPoint.VALUE,
                    DataPoint.TIMESTAMP };
            where = DataPoint.SENSOR_NAME + "='" + SensorData.SensorNames.ACCELEROMETER_EPI + "'"
                    + " AND " + DataPoint.TIMESTAMP + ">"
                    + (SNTP.getInstance().getTime() - (TIME_RANGE << 1));
            epiData = storage.query(contentUri, projection, where, null, null);

            if (null != epiData && epiData.moveToFirst()) {
                int result = analyzeEpiData(epiData);
                // Log.d(TAG, "Epi analysis result: " + result);
                if (result > 0) {
                    sendAlert(epiData);
                    return;
                }
            } else {
                // Log.d(TAG, "No recent epi data to analyze");
            }

        } catch (JSONException e) {
            Log.e(TAG, "Failed to parse data");
            return;

        } finally {
            if (null != fallData) {
                fallData.close();
                fallData = null;
            }
            if (null != epiData) {
                epiData.close();
                epiData = null;
            }
        }
    }

    private void sendAlert(Cursor data) {
        Log.w(TAG, "ALERT ALERT!!!! SEIZURE DETECTED!!!");

        Intent alert = new Intent("nl.ask.paige.receiver.IntentRx");
        alert.putExtra("sensorName", "epi state");
        alert.putExtra("value", "SEIZURE!!!");
        alert.putExtra("timestamp", "" + SNTP.getInstance().getTime());
        sendBroadcast(alert);
    }

    private int analyzeEpiData(Cursor data) throws JSONException {

        data.moveToLast();

        // parse the value
        long timestamp = data.getLong(data.getColumnIndex(DataPoint.TIMESTAMP));
        if (lastAnalyzed < timestamp) {
            lastAnalyzed = timestamp;
        } else {
            // Log.d(TAG, "Already analyzed this one");
            return 0;
        }
        String rawValue = data.getString(data.getColumnIndex(DataPoint.VALUE));
        JSONObject value = new JSONObject(rawValue);
        JSONArray array = value.getJSONArray("data");

        // Log.d(TAG, "Found " + array.length() + " epi data points, interval: " + interval +
        // " ms");

        // analyze the array of data points
        double total = 0;
        for (int i = 0; i < array.length(); i++) {
            JSONObject dataPoint = array.getJSONObject(i);
            double x = dataPoint.getDouble("x-axis");
            double y = dataPoint.getDouble("y-axis");
            double z = dataPoint.getDouble("z-axis");
            double length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));

            total += length;
        }

        double avg = total / array.length();
        // Log.d(TAG, "Average acceleration: " + avg);
        if (avg > 12) {
            return 1;
        } else {
            return 0;
        }
    }

    private int analyzeFallData(Cursor data) throws JSONException {
        data.moveToLast();

        // parse the value
        long timestamp = data.getLong(data.getColumnIndex(DataPoint.TIMESTAMP));
        if (lastAnalyzed < timestamp) {
            lastAnalyzed = timestamp;
            if (data.getString(data.getColumnIndex(DataPoint.VALUE)).equals("true")) {
                return 1;
            } else {
                // Log.d(TAG, "No fall");
                return 0;
            }
        } else {
            // Log.d(TAG, "Already analyzed this one");
            return 0;
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startMonitoring(ACTION_UPDATE_STATE, TIME_RANGE >> 1);
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopMonitoring();
    }
} public abstract class BaseSensor extends BaseDataProducer implements DataProducer, SenseSensor {

	/** The delay value for the sample rate */
    private long sampleDelay = 0;

    @Override
    public long getSampleRate() {
    	return sampleDelay;
    }

    @Override
    public void setSampleRate(long sampleDelay) {
    	this.sampleDelay = sampleDelay;
    }

} public class SubscriptionManager {

    /** Singleton instance */
    private static SubscriptionManager sInstance;

    /**
     * Factory method for singleton pattern
     * 
     * @return The singleton instance of the subscription manager
     */
    public static SubscriptionManager getInstance() {
        if (null == sInstance) {
            sInstance = new SubscriptionManager();
        }
        return sInstance;
    }

    /** All DataConsumers, mapped by the name of the producer they are subscribed to. */
    private Map<String, List<DataConsumer>> mConsumers;

    /** All registered DataProducers, mapped by their name. */
    private Map<String, List<DataProducer>> mProducers;

    /**
     * Constructor.
     * 
     * @param context
     * @see #getInstance()
     */
    protected SubscriptionManager() {
        mConsumers = new HashMap<String, List<DataConsumer>>();
        mProducers = new HashMap<String, List<DataProducer>>();
    }

    /**
     * @param name
     *            The name of the DataProducer
     * @return A List of data producers that are registered under the given sensor name
     */
    public List<DataProducer> getRegisteredProducers(String name) {
        List<DataProducer> original = mProducers.get(name);
        if (null != original) {
            // return a copy of the list
            return new ArrayList<DataProducer>(original);
        } else {
            return null;
        }
    }

    /**
     * @param name
     *            The name of the DataConsumer
     * @return A List of data consumers that are subscribed to the given sensor name
     */
    public List<DataConsumer> getSubscribedConsumers(String name) {
        List<DataConsumer> original = mConsumers.get(name);
        if (null != original) {
            // return a copy of the list
            return new ArrayList<DataConsumer>(original);
        } else {
            return null;
        }
    }

    /**
     * @param name
     *            The name of the DataProducer
     * @param consumer
     *            The data consumer instance to check for
     * @return <code>true</code> if this consumer is already subscribed for producers with this name
     */
    public boolean isConsumerSubscribed(String name, DataConsumer consumer) {

        if(consumer == null)
            return false;

        // check if data consumer is in the list of subscribed consumers
        List<DataConsumer> consumers = getSubscribedConsumers(name);
        if (null != consumers) {
            for (DataConsumer registeredConsumer : consumers) {
                if (registeredConsumer != null && registeredConsumer.equals(consumer)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * @param name
     *            The name of the DataProducer
     * @return true if any data producer is already registered under this sensor name
     */
    public boolean isProducerRegistered(String name) {
        return mProducers.containsKey(name);
    }

    /**
     * @param name
     *            The name of the DataProducer
     * @param producer
     *            The DataProducer instance to check for
     * @return true if the data producer is already registered under this sensor name
     */
    public boolean isProducerRegistered(String name, DataProducer producer) {

        if(producer == null)
            return false;

        // check if producer is already in the list of registered producers
        List<DataProducer> producers = getRegisteredProducers(name);
        if (null != producers) {
            for (DataProducer registeredProducer : producers) {
                if (registeredProducer!= null && registeredProducer.equals(producer)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * <p>
     * Registers a DataProducer with the given name at the SenseService.
     * </p>
     * <p>
     * When a data producer is registered, data consumers can subscribe to its sensor data.
     * Registering a data producer with an existing name will add the new data producer only if this
     * data producer is a different instance from the other data producer.
     * </p>
     * 
     * @param name
     *            The name of the data producer
     * @param producer
     *            The data producer
     */
    public synchronized void registerProducer(String name, DataProducer producer) {

        if (isProducerRegistered(name, producer)) {
            // data producer is already registered
            return;
        }

        if(producer == null)
            return;

        // add the producer to the list of registered producers
        List<DataProducer> producers = getRegisteredProducers(name);
        if (null == producers) {
            producers = new ArrayList<DataProducer>();
        }
        producers.add(producer);
        mProducers.put(name, producers);

        // see if there are any data consumers subscribed to this sensor name
        List<DataConsumer> subscribers = getSubscribedConsumers(name);
        if (null != subscribers) {
            // subscribe existing DataProcessors to the new DataProducer
            for (DataConsumer subscriber : subscribers) {
                if(subscriber != null)
                    producer.addSubscriber(subscriber);
            }
        }
    }

    /**
     * <p>
     * Subscribes a DataConsumer to a DataProducer
     * </p>
     * <p>
     * This method subscribes a DataProcessor to receive SensorDataPoints from a DataProducer. If
     * the DataProducer with name to subscribe to is not registered yet then the data processor will
     * be put in the queue and will be subscribed to the DataProducer when it is registered.
     * </p>
     * 
     * @param name
     *            The name of the registered DataProducer
     * @param consumer
     *            The DataConsumer that receives the sensor data
     * @return true if the DataConsumer successfully subscribed to the DataProducer.
     */
    public synchronized boolean subscribeConsumer(String name, DataConsumer consumer) {

        if (isConsumerSubscribed(name, consumer)) {
            // consumer is already subscribed
            return true;
        }

        if(consumer == null)
            return false;

        // add the consumer to the list of subscribed consumers
        List<DataConsumer> consumers = getSubscribedConsumers(name);
        if (null == consumers) {
            consumers = new ArrayList<DataConsumer>();
        }
        consumers.add(consumer);
        mConsumers.put(name, consumers);

        // see if there are any producers for this sensor name
        List<DataProducer> producers = getRegisteredProducers(name);
        if (producers == null) {
            // nothing to subscribe to (yet)
            return true;
        } else {
            // subscribe the new processor to the existing producers
            boolean subscribed = false;
            for (DataProducer producer : producers) {
                if(producer != null)
                    subscribed |= producer.addSubscriber(consumer);
            }
            return subscribed;
        }
    }

    /**
     * Unregisters a DataProducer.<br/>
     * <br/>
     * No new data consumers can subscribe to the DataProducer anymore, but DataConsumer which have
     * already subscribed to the DataProducer will remain subscribed.
     * 
     * @param name
     *            The name that the DataProducer is registered under
     * @param producer
     *            The DataProducer to unregister
     */
    public synchronized void unregisterProducer(String name, DataProducer producer) {

        if (!mProducers.containsKey(name)) {
            // this producer is not registered under this name
            return;
        }

        // remove the producer from the list of registered producers for this sensor name
        List<DataProducer> dataProducers = getRegisteredProducers(name);
        if (null == dataProducers) {
            // apparently the list is already gone
            return;
        }
        dataProducers.remove(producer);

        // update the map of registered producers
        if (dataProducers.size() == 0) {
            mProducers.remove(name);
        } else {
            mProducers.put(name, dataProducers);
        }
    }

    /**
     * Unsubscribes a data consumer from a data producer.
     * 
     * @param name
     *            The name of the DataProducer that the consumer registered for
     * @param consumer
     *            The DataConsumer that receives the sensor data
     */
    public synchronized void unsubscribeConsumer(String name, DataConsumer consumer) {

        if (!mConsumers.containsKey(name)) {
            // there are no consumers registered for this name (?)
            return;
        }

        // remove the consumer from the list of subscribed consumer
        List<DataConsumer> consumers = getSubscribedConsumers(name);
        if (null == consumers) {
            // apparently the list is already gone
            return;
        }
        consumers.remove(consumer);

        // update the map of consumers
        if (consumers.size() == 0) {
            mConsumers.remove(name);
        } else {
            mConsumers.put(name, consumers);
        }

        // unsubscribe the consumer from the producers for this sensor name
        List<DataProducer> producers = getRegisteredProducers(name);
        if (null != producers) {
            for (DataProducer registeredProducer : producers) {
                if(registeredProducer != null)
                    registeredProducer.removeSubscriber(consumer);
            }
        }
    }
}
import java.util.ArrayList;
import java.util.List;
import nl.sense_os.service.constants.SensePrefs;
import nl.sense_os.service.constants.SensePrefs.Main.Motion;
import nl.sense_os.service.constants.SensorData.SensorNames;
import nl.sense_os.service.provider.SNTP;
import nl.sense_os.service.shared.PeriodicPollAlarmReceiver;
import nl.sense_os.service.shared.PeriodicPollingSensor;
import nl.sense_os.service.shared.SensorDataPoint;
import nl.sense_os.service.states.EpiStateMonitor;
import nl.sense_os.service.subscription.BaseSensor;
import nl.sense_os.service.subscription.SubscriptionManager;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
/**************************************************************************************************
 * Copyright (C) 2010 Sense Observation Systems, Rotterdam, the Netherlands. All rights reserved. *
 *************************************************************************************************/
package nl.sense_os.service.motion;



/**
 * <p>
 * Represents the main motion sensor. Listens for events from the Android SensorManager and parses
 * the results.
 * </p>
 * <p>
 * The resulting data is divided over several separate sensors in CommonSense:
 * <ul>
 * <li>accelerometer</li>
 * <li>gyroscope</li>
 * <li>motion energy</li>
 * <li>linear acceleration</li>
 * </ul>
 * Besides these basic sensors, the sensor can also gather data for high-speed epilepsy detection
 * and fall detection.
 * </p>
 * 
 * @author Ted Schmidt <ted@sense-os.nl>
 * @author Steven Mulder <steven@sense-os.nl>
 */
public class MotionSensor extends BaseSensor implements SensorEventListener, PeriodicPollingSensor {

    /**
     * BroadcastReceiver that listens for screen state changes. Re-registers the motion sensor when
     * the screen turns off.
     */
    private class ScreenOffListener extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            // Check action just to be on the safe side.
            if (false == intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                return;
            }

            SharedPreferences prefs = context.getSharedPreferences(SensePrefs.MAIN_PREFS,
                    Context.MODE_PRIVATE);
            boolean useFix = prefs.getBoolean(Motion.SCREENOFF_FIX, false);
            if (useFix) {
                // wait half a second and re-register
                Runnable restartSensing = new Runnable() {

                    @Override
                    public void run() {
                        // Unregisters the motion listener and registers it again.
                        stopSensing();
                        startSensing(getSampleRate());
                    };
                };
                new Handler().postDelayed(restartSensing, 500);
            }
        }
    }

    private static final long DELAY_AFTER_REGISTRATION = 500;
    private static final String TAG = "Sense Motion";

    private static MotionSensor instance = null;

    /**
     * Factory method to get the singleton instance.
     * 
     * @param context
     * @return instance
     */
    public static MotionSensor getInstance(Context context) {
        if (instance == null) {
            instance = new MotionSensor(context);
        }
        return instance;
    }

    private final BroadcastReceiver screenOffListener = new ScreenOffListener();
    private final Context context;
    private boolean isFallDetectMode;
    private boolean isEnergyMode;
    private boolean isEpiMode;
    private boolean isBurstMode;
    private boolean isUnregisterWhenIdle;
    private boolean firstStart = true;
    private List<Sensor> sensors;
    private boolean active = false;
    private WakeLock wakeLock;
    private boolean registered;
    private PeriodicPollAlarmReceiver alarmReceiver;
    // TODO:
    // Should be moved to the service where all the sensors are registered
    // and added as data processor when the preference is selected
    // or at least out of startSensing, does not need to create this coupling at startSensing
    private EpilepsySensor epi;
    private FallDetector fall;
    private MotionEnergySensor energy;
    private StandardMotionSensor standard = null;
    private MotionBurstSensor accelerometerBurstSensor;
    private MotionBurstSensor gyroBurstSensor;
    private MotionBurstSensor linearBurstSensor;
    private SubscriptionManager mSubscrMgr;

    /**
     * Constructor.
     * 
     * @param context
     * @see #getInstance(Context)
     */
    protected MotionSensor(Context context) {
        this.context = context;
        alarmReceiver = new PeriodicPollAlarmReceiver(this);
        mSubscrMgr = SubscriptionManager.getInstance();
    }

    @Override
    public void doSample() {
        //Log.v(TAG, "Do sample");

        // get wake lock
        if (null == wakeLock) {
            PowerManager powerMgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
            wakeLock = powerMgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
        }
        if (!wakeLock.isHeld()) {
            //Log.i(TAG, "Acquire wake lock");
            wakeLock.acquire();
        } else {
            // Log.v(TAG, "Wake lock already held");
        }

        // notify all special sensors
        notifySubscribers();

        registerSensors();
    }

    private void enableScreenOffListener(boolean enable) {
        if (enable) {
            // Register the receiver for SCREEN OFF events
            IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
            context.registerReceiver(screenOffListener, filter);
        } else {
            // Unregister the receiver for SCREEN OFF events
            try {
                context.unregisterReceiver(screenOffListener);
            } catch (IllegalArgumentException e) {
                // Log.v(TAG, "Ignoring exception when unregistering screen off listener");
            }
        }
    }

    /**
     * Initializes the burst-mode data processors.
     */
    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    private void initBurstDataProcessors() {
        final SharedPreferences mainPrefs = context.getSharedPreferences(SensePrefs.MAIN_PREFS,
                Context.MODE_PRIVATE);

        if (mainPrefs.getBoolean(Motion.ACCELEROMETER, true)) {
            accelerometerBurstSensor = new MotionBurstSensor(context, Sensor.TYPE_ACCELEROMETER,
                    SensorNames.ACCELEROMETER_BURST);