com.samknows.measurement.AppSettings.java Source code

Java tutorial

Introduction

Here is the source code for com.samknows.measurement.AppSettings.java

Source

/*
2013 Measuring Broadband America Program
Mobile Measurement Android Application
Copyright (C) 2012  SamKnows Ltd.
    
The FCC Measuring Broadband America (MBA) Program's Mobile Measurement Effort developed in cooperation with SamKnows Ltd. and diverse stakeholders employs an client-server based anonymized data collection approach to gather broadband performance data in an open and transparent manner with the highest commitment to protecting participants privacy.  All data collected is thoroughly analyzed and processed prior to public release to ensure that subscribers privacy interests are protected.
    
Data related to the radio characteristics of the handset, information about the handset type and operating system (OS) version, the GPS coordinates available from the handset at the time each test is run, the date and time of the observation, and the results of active test results are recorded on the handset in JSON(JavaScript Object Notation) nested data elements within flat files.  These JSON files are then transmitted to storage servers at periodic intervals after the completion of active test measurements.
    
This Android application source code is made available under the GNU GPL2 for testing purposes only and intended for participants in the SamKnows/FCC Measuring Broadband American program.  It is not intended for general release and this repository may be disabled at any time.
    
    
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package com.samknows.measurement;

import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TimeZone;

import org.apache.commons.io.IOUtils;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;

import com.samknows.measurement.schedule.ScheduleConfig;
import com.samknows.measurement.schedule.ScheduleConfig.LocationType;
import com.samknows.measurement.statemachine.State;
import com.samknows.measurement.util.OtherUtils;
import com.samknows.measurement.util.TimeUtils;

public class AppSettings {
    private static final String TAG = AppSettings.class.getName();
    private Context ctx;

    //json fields to be included to each submission
    public static final String JSON_UNIT_ID = "unit_id";
    public static final String JSON_APP_VERSION_CODE = "app_version_code";
    public static final String JSON_APP_VERSION_NAME = "app_version_name";
    public static final String JSON_SCHEDULE_CONFIG_VERSION = "schedule_config_version";
    public static final String JSON_TIMEZONE = "timezone";
    public static final String JSON_TIMESTAMP = "timestamp";
    public static final String JSON_DATETIME = "datetime";
    public static final String JSON_ENTERPRISE_ID = "enterprise_id";
    public static final String JSON_SIMOPERATORCODE = "sim_operator_code";
    public static final String JSON_USER_SELF_ID = "user_self_id";

    //used for first step to obtain dcs base url
    public String dCSInitUrl;

    public String reportingServerPath;
    public long rescheduleTime;

    //used to restart service after being killed by manager
    public long rescheduleServiceTime;
    public long testStartWindow;
    public long testStartWindowWakeup;

    //used to deploy different brand of the application
    public String brand;

    //Used to know if the app needs to collect identifiers 
    public boolean anonymous;

    //protocol scheme used for comunicating with the dcs
    public String protocol_scheme;

    //submit path used to send the results to the dcs
    public String submit_path;

    //true if the config file has to be downloaded and the schedule updated 
    public boolean force_download = false;

    //download config file path
    public String download_config_path;

    //application version code and application version name read from the androidmanifest.xml file
    public String app_version_code;
    public String app_version_name;

    //Enterprise id read from the properties file
    public String enterprise_id;

    //User self identifier preference enabled
    public boolean user_self_id;

    //static instance and initialisation
    private static AppSettings instance;

    public static AppSettings getInstance() {
        return instance;
    }

    //to be called when the app starts
    public static void create(Context c) {
        instance = new AppSettings(c);
    }

    //Initialise the AppSettings reading from the properties file located in res/raw
    private AppSettings(Context c) {
        ctx = c;
        InputStream is = c.getResources().openRawResource(R.raw.properties);
        Properties p = new Properties();
        try {
            p.load(is);
            dCSInitUrl = p.getProperty(Constants.PROP_DCS_URL);
            reportingServerPath = p.getProperty(Constants.PROP_REPORTING_PATH);
            rescheduleTime = Long.valueOf(p.getProperty(Constants.PROP_RESCHEDULE_TIME));
            testStartWindow = Long.valueOf(p.getProperty(Constants.PROP_TEST_START_WINDOW_RTC));
            testStartWindowWakeup = Long.valueOf(p.getProperty(Constants.PROP_TEST_START_WINDOW_RTC_WAKEUP));
            rescheduleServiceTime = Long
                    .valueOf(p.getProperty(Constants.PROP_KILLED_SERVICE_RESTART_TIME_IN_MILLIS));
            brand = p.getProperty(Constants.PROP_BRAND);
            anonymous = Boolean.valueOf(p.getProperty(Constants.PROP_ANONYMOUS));
            protocol_scheme = p.getProperty(Constants.PROP_PROTOCOL_SCHEME);
            submit_path = p.getProperty(Constants.PROP_SUBMIT_PATH);
            download_config_path = p.getProperty(Constants.PROP_DOWNLOAD_CONFIG_PATH);
            PackageInfo pInfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0);
            app_version_code = pInfo.versionCode + "";
            app_version_name = pInfo.versionName;
            enterprise_id = p.getProperty(Constants.PROP_ENTERPRISE_ID);
            user_self_id = Boolean.parseBoolean(p.getProperty(Constants.PROP_USER_SELF_IDENTIFIER));

        } catch (IOException e) {
            Logger.e(TAG, "failed to load properies!");
        } catch (NameNotFoundException nnfe) {
            Logger.e(TAG, "failed to read manifest file: " + nnfe.getMessage());
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    //Methods for managing the testStartWindow
    public long getTestStartWindow() {
        return isWakeUpEnabled() ? testStartWindowWakeup : testStartWindow;
    }

    //methods for managing the shared preferences

    public void saveString(String key, String value) {
        Editor editor = ctx.getSharedPreferences(Constants.PREF_FILE_NAME, Context.MODE_PRIVATE).edit();
        editor.putString(key, value);
        editor.commit();
    }

    public String getString(String key) {
        return ctx.getSharedPreferences(Constants.PREF_FILE_NAME, Context.MODE_PRIVATE).getString(key, null);
    }

    public String getString(String key, String default_value) {
        return ctx.getSharedPreferences(Constants.PREF_FILE_NAME, Context.MODE_PRIVATE).getString(key,
                default_value);
    }

    public void saveBoolean(String key, boolean value) {
        Editor editor = ctx.getSharedPreferences(Constants.PREF_FILE_NAME, Context.MODE_PRIVATE).edit();
        editor.putBoolean(key, value);
        editor.commit();
    }

    public boolean getBoolean(String key, boolean def) {
        return ctx.getSharedPreferences(Constants.PREF_FILE_NAME, Context.MODE_PRIVATE).getBoolean(key, def);
    }

    public void saveLong(String key, long value) {
        Editor editor = ctx.getSharedPreferences(Constants.PREF_FILE_NAME, Context.MODE_PRIVATE).edit();
        editor.putLong(key, value);
        editor.commit();
    }

    public long getLong(String key, long defValue) {
        return ctx.getSharedPreferences(Constants.PREF_FILE_NAME, Context.MODE_PRIVATE).getLong(key, defValue);
    }

    public String getUnitId() {
        return getString(Constants.PREF_KEY_UNIT_ID);
    }

    public void saveUnitId(String unitId) {
        saveString(Constants.PREF_KEY_UNIT_ID, unitId);
    }

    public String getServerBaseUrl() {
        return getString(Constants.PREF_KEY_SERVER_BASE_URL);
    }

    public void saveServerBaseUrl(String url) {
        saveString(Constants.PREF_KEY_SERVER_BASE_URL, url);
    }

    public State getState() {
        State ret = State.NONE;
        String state = getString(Constants.PREF_KEY_STATE);
        if (state != null) {
            for (State s : State.values()) {
                if (state.equalsIgnoreCase(String.valueOf(s))) {
                    ret = s;
                    break;
                }
            }
        }
        return ret;
    }

    public boolean isServiceActivated() {
        return getBoolean(Constants.PREF_KEY_SERVICE_ACTIVATED, false);
    }

    public void setServiceActivated(boolean activated) {
        saveBoolean(Constants.PREF_KEY_SERVICE_ACTIVATED, activated);
    }

    public void saveState(State state) {
        saveString(Constants.PREF_KEY_STATE, String.valueOf(state));
    }

    public boolean isServiceEnabled() {
        return PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean(Constants.PREF_SERVICE_ENABLED, true);
    }

    public void setServiceEnabled(boolean enabled) {
        Editor editor = PreferenceManager.getDefaultSharedPreferences(ctx).edit();
        editor.putBoolean(Constants.PREF_SERVICE_ENABLED, enabled);
        editor.commit();
    }

    //if the state machine fails and the user want to run some test we ask for the activation
    public void stateMachineFailure() {
        saveBoolean(Constants.STATE_MACHINE_STATUS, false);

    }

    public void stateMachineSuccess() {
        saveBoolean(Constants.STATE_MACHINE_STATUS, true);

    }

    public boolean stateMachineStatus() {
        return getBoolean(Constants.STATE_MACHINE_STATUS, true);
    }

    public void appendUsedBytes(long bytes) {
        if (OtherUtils.isWifi(ctx)) {
            return;
        }
        resetDataUsageIfTime();
        long newBytes = getUsedBytes() + bytes;
        saveLong(Constants.PREF_KEY_USED_BYTES, newBytes);
        long newTime = System.currentTimeMillis();
        saveLong(Constants.PREF_KEY_USED_BYTES_LAST_TIME, newTime);
        Logger.d(TAG, "saved used bytes " + newBytes + " at time " + newTime);
    }

    public long getUsedBytes() {
        return getLong(Constants.PREF_KEY_USED_BYTES, 0);
    }

    public void saveDataCapFromConfig(long bytes) {
        saveLong(Constants.PREF_DATA_CAP, bytes);
    }

    /**
     * data cap in bytes
     * if preference has been defined use it
     * otherwise use the datacap from config file
     * if none of them is defined use Long.MAX_VALUE
     *      
     */
    public long getDataCap() {
        long ret = Long.MAX_VALUE;
        long configDataCap = getLong(Constants.PREF_DATA_CAP, -1);

        long preferenceDataCap = Long.valueOf(
                PreferenceManager.getDefaultSharedPreferences(ctx).getString(Constants.PREF_DATA_CAP, "-1")); //in megs
        if (preferenceDataCap > 0) {
            ret = preferenceDataCap * 1024 * 1024;
        } else if (configDataCap > 0) {
            ret = configDataCap * 1024 * 1024;
        }
        return ret;
    }

    public void resetDataUsage() {
        saveLong(Constants.PREF_KEY_USED_BYTES, 0);
    }

    private void resetDataUsageIfTime() {
        Calendar c = GregorianCalendar.getInstance();
        long startToday = TimeUtils.getStartDayTime();
        long startDayLastTime = TimeUtils
                .getStartDayTime(getLong(Constants.PREF_KEY_USED_BYTES_LAST_TIME, System.currentTimeMillis()));
        int currDayReset = PreferenceManager.getDefaultSharedPreferences(ctx)
                .getInt(Constants.PREF_KEY_DATA_CAP_DAY_IN_MONTH_RESET, 1);
        long timeReset = TimeUtils.getPreviousDayInMonth(currDayReset);
        if (startDayLastTime < timeReset && startToday >= timeReset) {
            Logger.d(this, "Data usage has been reset to 0 for the month useage. Reset time: " + timeReset
                    + " last time: " + startDayLastTime + " now: " + startToday);
            resetDataUsage();
        }
    }

    public boolean isDataCapReached(long bytesToBeUsed) {
        if (OtherUtils.isWifi(ctx)) {
            return false;
        }
        resetDataUsageIfTime();
        long usedBytes = getUsedBytes();
        long dataCap = getDataCap();
        return usedBytes + bytesToBeUsed >= dataCap;

    }

    public boolean isDataCapReached() {
        return isDataCapReached(0);
    }

    public boolean isWakeUpEnabled() {
        return PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean(Constants.PREF_ENABLE_WAKEUP, true);
    }

    public void setWakeUpEnabledIfNull(boolean enabled) {
        if (!PreferenceManager.getDefaultSharedPreferences(ctx).contains(Constants.PREF_ENABLE_WAKEUP)) {
            PreferenceManager.getDefaultSharedPreferences(ctx).edit()
                    .putBoolean(Constants.PREF_ENABLE_WAKEUP, enabled).commit();
        }
    }

    public LocationType getLocationServiceType() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        if (prefs.contains(Constants.PREF_LOCATION_TYPE)) {
            String pref = prefs.getString(Constants.PREF_LOCATION_TYPE, null);
            if (pref == null) {
                return null;
            }
            if (pref == ctx.getString(R.string.GPS)) {
                return LocationType.gps;
            }
            return LocationType.network;
        }
        return LocationType.gps;
    }

    public void setLocationTypeIfNull(LocationType type) {
        if (!PreferenceManager.getDefaultSharedPreferences(ctx).contains(Constants.PREF_LOCATION_TYPE)) {
            String value = type == LocationType.gps ? ctx.getString(R.string.GPS)
                    : ctx.getString(R.string.MobileNetwork);
            PreferenceManager.getDefaultSharedPreferences(ctx).edit().putString(Constants.PREF_LOCATION_TYPE, value)
                    .commit();
        }
    }

    public void saveNextRunTime(long time) {
        Editor editor = ctx.getSharedPreferences(Constants.PREF_FILE_NAME, Context.MODE_PRIVATE).edit();
        editor.putLong(Constants.PREF_NEXT_RUN_TIME, time);
        editor.commit();
    }

    public long getNextRunTime() {
        return getLong(Constants.PREF_NEXT_RUN_TIME, Constants.NO_NEXT_RUN_TIME);
    }

    public String getConfigVersion() {
        return getString(Constants.PREF_KEY_CONFIG_VERSION);
    }

    public void saveConfigVersion(String v) {
        saveString(Constants.PREF_KEY_CONFIG_VERSION, v);
    }

    public String getConfigPath() {
        return getString(Constants.PREF_KEY_CONFIG_PATH);
    }

    public void setForceDownload() {
        force_download = true;
    }

    public boolean forceDownload() {
        boolean ret = force_download;
        force_download = false;
        return ret;
    }

    public boolean updateConfig(ScheduleConfig newConfig) {
        boolean ret = false;
        ScheduleConfig savedConfig = CachingStorage.getInstance().loadScheduleConfig();
        if (savedConfig == null) {
            Logger.d(this, "Saved Config is null");
            ret = true;
        } else if (savedConfig.toUpdate(newConfig)) {
            Logger.d(this, "Config versions don't match");
            ret = true;
        } else if (forceDownload()) {
            Logger.d(this, "Force update config");
            ret = true;
        }
        return ret;
    }

    public void saveConfigPath(String path) {
        saveString(Constants.PREF_KEY_CONFIG_PATH, path);
    }

    public boolean wasIntroShown() {
        return getBoolean(Constants.PREF_WAS_INTRO_SHOWN, false);
    }

    public void saveIntroShown(boolean wasShown) {
        saveBoolean(Constants.PREF_FILE_NAME, wasShown);
    }

    public String getUsername() {
        return getString(Constants.PREF_KEY_USERNAME);
    }

    public String getPassword() {
        return getString(Constants.PREF_KEY_PASSWORD);
    }

    public List<DeviceDescription> getDevices() {
        String devices = getString(Constants.PREF_KEY_DEVICES);
        return DeviceDescription.parce(devices);
    }

    public void saveUsername(String username) {
        saveString(Constants.PREF_KEY_USERNAME, username);
    }

    public void savePassword(String password) {
        saveString(Constants.PREF_KEY_PASSWORD, password);
    }

    public void saveDevices(String device) {
        saveString(Constants.PREF_KEY_DEVICES, device);
    }

    public void clearAll() {
        Editor editor = ctx.getSharedPreferences(Constants.PREF_FILE_NAME, Context.MODE_PRIVATE).edit();
        editor.clear();
        editor.commit();
    }

    //Returns a Map containing all the json entry to be added when submitting the results
    public Map<String, String> getJSONExtra() {
        Map<String, String> ret = new HashMap<String, String>();
        if (!anonymous) {
            ret.put(JSON_UNIT_ID, getUnitId());
        }
        ret.put(JSON_APP_VERSION_NAME, app_version_name);
        ret.put(JSON_APP_VERSION_CODE, app_version_code);
        ScheduleConfig config = CachingStorage.getInstance().loadScheduleConfig();
        if (config != null) {
            ret.put(JSON_SCHEDULE_CONFIG_VERSION, config.version);
        } else {
            ret.put(JSON_SCHEDULE_CONFIG_VERSION, "no_schedule_config");
        }
        long time = System.currentTimeMillis();
        ret.put(JSON_TIMESTAMP, (time / 1000) + "");
        ret.put(JSON_DATETIME, new java.util.Date(time).toString());
        ret.put(JSON_TIMEZONE, TimeUtils.millisToHours(TimeZone.getDefault().getRawOffset()) + "");
        if (enterprise_id != null) {
            ret.put(JSON_ENTERPRISE_ID, enterprise_id);
        }
        String user_self_id = PreferenceManager.getDefaultSharedPreferences(ctx)
                .getString(Constants.PREF_USER_SELF_ID, null);
        if (user_self_id != null) {
            ret.put(JSON_USER_SELF_ID, user_self_id);
        }
        TelephonyManager manager = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
        String simOperatorCode = "";
        if (manager != null) {
            simOperatorCode = manager.getSimOperator();
        }
        ret.put(JSON_SIMOPERATORCODE, simOperatorCode);

        return ret;
    }

    public String getResourceString(int id) {
        return ctx.getString(id);
    }
}