package org.fitchfamily.android.gsmlocation; import android.content.Context; import android.content.SharedPreferences; import android.os.Environment; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.text.TextUtils; import java.io.File; import java.util.Collections; import java.util.HashSet; import java.util.Set; public class Settings { private static final String DB_NAME = "lacells.db"; private static final String DB_BAK_NAME = DB_NAME + ".bak"; private static final String DB_NEW_NAME = DB_NAME + ".new"; private static final String LOG_NAME = "lacells_gen.log"; private static final String[] FILE_NAMES = new String[] { DB_NAME, DB_BAK_NAME, DB_NEW_NAME, LOG_NAME }; private static final File DATABASE_DIRECTORY_OLD = new File(Environment.getExternalStorageDirectory(), ".nogapps"); private static final boolean USE_LACELLS_DEFAULT = false; private static final String USE_LACELLS = "lacells_preference"; private static final String USE_MOZILLA_LOCATION_SERVICE = "mls_preference"; private static final String USE_OPEN_CELL_ID = "oci_preference"; private static final String OPEN_CELL_ID_API_KEY = "oci_key_preference"; private static final String MNC_FILTER = "mnc_filter_preference"; private static final String MCC_FILTER = "mcc_filter_preference"; private static final String EXTERNAL_DATABASE_LOCATION = "ext_db_preference"; private static final Object lock = new Object(); private static Settings instance; private final SharedPreferences preferences; private final Context context; private Settings(Context context) { this.context = context; preferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()); moveFilesToNewDirectory(FILE_NAMES); } private void moveFilesToNewDirectory(String... filenames) { for(String filename : filenames) { moveFileToNewDirectory(filename); } } private void moveFileToNewDirectory(String filename) { File oldFile = new File(DATABASE_DIRECTORY_OLD, filename); if(oldFile.exists() && oldFile.canWrite()) { /* * This will work because "/sdcard/.nogapps/" and * "/sdcard/Android/data/org.fitchfamily.android-gsmlocation/files" are on the * same mount point "/sdcard/" (The new directory is the external files directory, not * the internal one so that both are on the emulated sdcard (internal memory) or an real sdcard) */ oldFile.renameTo(new File(databaseDirectory(), filename)); } } public static Settings with(Fragment fragment) { return with(fragment.getContext()); } public static Settings with(Context context) { if(context == null) { throw new NullPointerException(); } if(instance == null) { synchronized (lock) { if(instance == null) { instance = new Settings(context); } } } return instance; } public String mccFilters() { return preferences.getString(MCC_FILTER, ""); } public String mncFilters() { return preferences.getString(MNC_FILTER, ""); } public String openCellIdApiKey() { return preferences.getString(OPEN_CELL_ID_API_KEY, ""); } public boolean useLacells() { return preferences.getBoolean(USE_LACELLS, USE_LACELLS_DEFAULT); } public boolean useOpenCellId() { return preferences.getBoolean(USE_OPEN_CELL_ID, false); } public boolean useMozillaLocationService() { return preferences.getBoolean(USE_MOZILLA_LOCATION_SERVICE, false); } public File databaseDirectory() { File extDir = new File(preferences.getString(EXTERNAL_DATABASE_LOCATION, "")); if (extDir.exists() && extDir.isDirectory() && extDir.canRead() && extDir.canWrite()) { return extDir; } return context.getExternalFilesDir(null); } public File newDatabaseFile() { return new File(databaseDirectory(), DB_NEW_NAME); } public File currentDatabaseFile() { return new File(databaseDirectory(), DB_NAME); } public File bakDatabaseFile() { return new File(databaseDirectory(), DB_BAK_NAME); } public File logfile() { return new File(databaseDirectory(), LOG_NAME); } /** * Use this function to get the current database file * * @return the current database file or null if not found */ public File databaseFile() { if (newDatabaseFile().exists()) { return newDatabaseFile(); } else if (currentDatabaseFile().exists()) { return currentDatabaseFile(); } else { return null; } } /** * Use this function to get the time of the last update of the database * * @return unix timestamp in milliseconds or 0 */ public long databaseLastModified() { File databaseFile = databaseFile(); return (databaseFile != null && databaseFile.canRead()) ? databaseFile.lastModified() : 0; } public Settings useLacells(boolean enable) { if (enable != useLacells()) { preferences.edit() .putBoolean(USE_LACELLS, enable) .commit(); } return this; } public Settings useOpenCellId(boolean enable) { if (enable != useOpenCellId()) { preferences.edit() .putBoolean(USE_OPEN_CELL_ID, enable) .commit(); } return this; } public Settings useMozillaLocationService(boolean enable) { if (enable != useMozillaLocationService()) { preferences.edit() .putBoolean(USE_MOZILLA_LOCATION_SERVICE, enable) .commit(); } return this; } public Settings openCellIdApiKey(String key) { if (!TextUtils.equals(key, openCellIdApiKey())) { preferences.edit() .putString(OPEN_CELL_ID_API_KEY, key) .commit(); } return this; } public Settings externalDatabaseLocation(String key) { if (!TextUtils.equals(key, openCellIdApiKey())) { preferences.edit() .putString(EXTERNAL_DATABASE_LOCATION, key) .commit(); } return this; } /** * Use this function to get the entered MMC numbers. * If there is nothing chosen, an empty list is returned. This should be handled as all areas (when downloading). * * @return the selected MCC numbers */ public Set<Integer> mccFilterSet() { Set<Integer> result = new HashSet<>(); String mccList = mccFilters(); if (!TextUtils.isEmpty(mccList)) { for (String number : mccList.split(",")) { try { result.add(Integer.valueOf(number)); } catch (NumberFormatException ex) { // ignore } } } return Collections.unmodifiableSet(result); } public Settings mccFilterSet(Set<Integer> numbers) { preferences.edit() .putString(MCC_FILTER, TextUtils.join(",", numbers.toArray())) .commit(); return this; } }