/*
* Copyright 2013 Dmitry Monakhov.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package monakhv.android.samlib.data;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.backup.BackupManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.os.Environment;
import android.text.TextUtils;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.net.Uri;
import java.io.File;
import java.util.*;
import monakhv.android.samlib.R;
import monakhv.android.samlib.SamlibApplication;
import monakhv.android.samlib.receiver.UpdateReceiver;
import monakhv.samlib.data.AbstractSettings;
import monakhv.samlib.db.SQLController;
import monakhv.samlib.db.entity.Book;
import monakhv.samlib.db.entity.SamLibConfig;
import monakhv.samlib.http.ProxyData;
import monakhv.samlib.log.Log;
/**
* @author monakhv
*/
public class SettingsHelper extends AbstractSettings implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String DATA_DIR = "/SamLib-Info/";
public final static String PREFS_NAME = "samlib_prefs";
private Context mContext = null;
private static final String DEBUG_TAG = "SettingsHelper";
private boolean updateService = false;
private final SharedPreferences prefs;
private static final String DARK = "DARK";
private static final String LIGHT = "LIGHT";
static final String DEBUG_FILE = SQLController.DB_NAME + ".log";
public SettingsHelper(Context context) {
this.mContext = context;
this.prefs = context.getSharedPreferences(PREFS_NAME, 0);
}
public Context getContext(){
return mContext;
}
/**
* unconditionally request backup data
*/
public void requestBackup() {
BackupManager bmr = new BackupManager(mContext);
bmr.dataChanged();
}
/**
* Request backup the first time after upgrade only
* Call from update manager
*/
public void requestFirstBackup() {
String str = prefs.getString(mContext.getString(R.string.pref_key_version_name), null);
if (str == null || !str.equals(getVersionName())) {
SharedPreferences.Editor editor = prefs.edit();
editor.putString(mContext.getString(R.string.pref_key_version_name), getVersionName());
editor.commit();
Log.d(DEBUG_TAG, "SettingsHelper: requestBackup");
requestBackup();
} else {
Log.d(DEBUG_TAG, "SettingsHelper: IGNORE first time requestBackup");
}
}
public String getVersionName() {
String res = "";
try {
PackageInfo pInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
res = pInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return res;
}
public void registerListener() {
Log.d(DEBUG_TAG, "Register Listener");
prefs.registerOnSharedPreferenceChangeListener(this);
}
public void unRegisterListener() {
Log.d(DEBUG_TAG, "Unregister Listener");
prefs.unregisterOnSharedPreferenceChangeListener(this);
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
requestBackup();
Log.d(DEBUG_TAG, "Preference change, key is " + key);
if (key.equals(mContext.getString(R.string.pref_key_flag_background_update))
|| key.equals(mContext.getString(R.string.pref_key_update_Period))) {
updateService = true;
}
if (key.equals(mContext.getString(R.string.pref_key_mirror))) {
String mirror = sharedPreferences.getString(mContext.getString(R.string.pref_key_mirror), null);
Log.i(DEBUG_TAG, "Set the first mirror to: " + mirror);
SamLibConfig sc = SamLibConfig.getInstance(this);
sc.refreshData();
}
if (key.equals(mContext.getString(R.string.pref_key_debug_options))){
SamlibApplication.initLogger();
}
}
/**
* Set or cancel Recurring Task using updated preferences into Alarm Manager
*/
public void updateService() {
if (!updateService) {
return;
}
updateServiceForce();
}
public void updateServiceForce() {
if (getBackgroundUpdateFlag()) {
setRecurringAlarm();
} else {
cancelRecurringAlarm();
}
}
/**
* Cancel recurring Task
*/
private void cancelRecurringAlarm() {
Log.i(DEBUG_TAG, "Cancel Updater service call");
/**
* We are using receiver here to avoid possible interference with the Pending intend in ProgressNotification
*/
Intent intent = new Intent(mContext, UpdateReceiver.class);
PendingIntent recurringUpdate = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarms.cancel(recurringUpdate);
}
/**
* Set recurring Task in Alarm Manager
*/
private void setRecurringAlarm() {
Log.i(DEBUG_TAG, "Update Updater service call");
//the fist time will be only after updatePeriod
long updatePeriod = getUpdatePeriod();
//temp
//long startTime = Calendar.getInstance().getTimeInMillis() + 10000;
long startTime = Calendar.getInstance().getTimeInMillis() + updatePeriod;
/**
* We are using receiver here to avoid possible interference with the Pending intend in ProgressNotification
*/
Intent intent = new Intent(mContext, UpdateReceiver.class);
PendingIntent recurringUpdate = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, startTime, updatePeriod, recurringUpdate);
}
private boolean getBackgroundUpdateFlag() {
return prefs.getBoolean(
mContext.getString(R.string.pref_key_flag_background_update),
false);
}
/**
* Get whether the application in debug mode or not
*
* @return true if application in debug mode
*/
public boolean getDebugFlag() {
return prefs.getBoolean(
mContext.getString(R.string.pref_key_debug_options),
false);
}
public String getGoogleAccount() {
return prefs.getString(mContext.getString(R.string.pref_key_google_account), null);
}
public void setGoogleAccount(String account) {
SharedPreferences.Editor edit = prefs.edit();
edit.putString(mContext.getString(R.string.pref_key_google_account), account);
edit.commit();
}
/**
* Get Ringtone URI used for notification constructions
*
* @return URI selected by user or default notification ringtone URI
*/
public Uri getNotificationRingToneURI() {
String sUri = prefs.getString(mContext.getString(R.string.pref_key_notification_ringtone), mContext.getString(R.string.pref_default_notification_ringtone));
return Uri.parse(sUri);
}
/**
* Get auto-mark Flag - whether clean new Mark or not on open bookmark
*
* @return auto-mark Flag
*/
public boolean getAutoMarkFlag() {
return prefs.getBoolean(
mContext.getString(R.string.pref_key_flag_automark),
true);
}
/**
* get whether we ignore connection error notification or not
*
* @return true if we do not provide connection error notification
*/
public boolean getIgnoreErrorFlag() {
return prefs.getBoolean(
mContext.getString(R.string.pref_key_ignore_connect_error),
true);
}
/**
* get whether we make automatic update using wifi only
*
* @return true if we do update using wifi
*/
public boolean getWifiOnlyFlag() {
return prefs.getBoolean(
mContext.getString(R.string.pref_key_flag_wihi_only),
false);
}
@Override
public boolean getAutoLoadFlag() {
return prefs.getBoolean(
mContext.getString(R.string.pref_key_flag_background_update_autoload),
false) ;
}
@Override
public boolean getLimitBookLifeTimeFlag() {
return prefs.getBoolean(
mContext.getString(R.string.pref_key_flag_limit_booke_lifetime),
true) && getBackgroundUpdateFlag();
}
public String getUpdatePeriodString() {
return prefs.getString(mContext.getString(R.string.pref_key_update_Period), mContext.getString(R.string.pref_default_update_Period));
}
public String getAuthorSortOrderString() {
String str = prefs.getString(
mContext.getString(R.string.pref_key_author_order),
mContext.getString(R.string.pref_default_author_order));
return str;
}
public String getBookSortOrderString() {
String str = prefs.getString(
mContext.getString(R.string.pref_key_book_order),
mContext.getString(R.string.pref_default_book_order));
return str;
}
public FileType getFileType() {
String str = prefs.getString(
mContext.getString(R.string.pref_key_file_format),
mContext.getString(R.string.pref_default_file_format)
);
return FileType.valueOf(str);
}
private long getUpdatePeriod() {
String str = getUpdatePeriodString();
Log.i(DEBUG_TAG, "Update interval: " + str);
if (str.equals("1HOUR")) {
return AlarmManager.INTERVAL_HOUR;
}
if (str.equals("3HOUR")) {
return 3 * AlarmManager.INTERVAL_HOUR;
}
if (str.equals("6HOUR")) {
return 6 * AlarmManager.INTERVAL_HOUR;
}
if (str.equals("12HOUR")) {
return AlarmManager.INTERVAL_HALF_DAY;
}
if (str.equals("DAY")) {
return AlarmManager.INTERVAL_DAY;
}
if (str.equals("15MINUTES")) {
return AlarmManager.INTERVAL_FIFTEEN_MINUTES;
}
Log.e(DEBUG_TAG, "Period Format error us default one");
return 3 * AlarmManager.INTERVAL_HOUR;
}
public ProxyData getProxy(){
boolean useProxy = prefs.getBoolean(mContext.getString(R.string.pref_key_use_proxy_flag), false);
if (! useProxy){
return null;
}
boolean wifiProxyFlag = prefs.getBoolean(mContext.getString(R.string.pref_key_use_proxy_wifi_flag), false);
if (wifiProxyFlag && !isWiFi()){
return null;//we have active flag but have not wifi, so do not use proxy
}
if (prefs.getBoolean(mContext.getString(R.string.pref_key_use_google_proxy_flag),false)){
return ProxyData.GOOGLE_HTTP;
}
String user = prefs.getString(mContext.getString(R.string.pref_key_proxy_user), "");
String password = prefs.getString(mContext.getString(R.string.pref_key_proxy_password), "");
String host = prefs.getString(mContext.getString(R.string.pref_key_proxy_host), "localhost");
String proxyPort = prefs.getString(mContext.getString(R.string.pref_key_proxy_port), "3128");
int pp;
try {
pp = Integer.parseInt(proxyPort);
} catch (NumberFormatException ex) {
Log.e(DEBUG_TAG, "Parse proxy port exception: " + proxyPort);
pp = 3128;
}
ProxyData proxy=new ProxyData(host,pp,user,password);
return proxy;
}
/**
* Checks if we have a valid Internet Connection on the device.
*
*
* @return True if device has internet
* <p/>
* Code from: http://www.androidsnippets.org/snippets/131/
*/
public boolean haveInternetWIFI() {
NetworkInfo info = ((ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
if (info == null || !info.isConnected()) {
return false;
}
boolean workRoaming = prefs.getBoolean(mContext.getString(R.string.pref_key_flag_roaming_work), false);
if (info.isRoaming() && !workRoaming) {
// here is the roaming option you can change it if you want to
// disable internet while roaming if user check do not work in Roaming
return false;
}
if (getWifiOnlyFlag()) {
return isWiFi();
}
return true;
}
/**
* Check if we have WIFI active or not
*
* @return
*/
private boolean isWiFi(){
ConnectivityManager conMan = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo inf = conMan.getNetworkInfo(1);
State wifi;
if (inf != null) {
wifi = inf.getState();
} else {
return false;
}
return wifi == NetworkInfo.State.CONNECTED || wifi == NetworkInfo.State.CONNECTING;
}
/**
* Test whether we have internet or not
* Use of manual update from Activity. Here we do not care about roaming
*
* @param ctx Context
* @return true if we have internet connection
*/
public static boolean haveInternet(Context ctx) {
NetworkInfo info = ((ConnectivityManager) ctx
.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
return !(info == null || !info.isConnected());
}
/**
* Test whether we need download book during update procedure True if we are
* inside size limit
*
* @param book Book object
* @return true if we need load the book
*/
public boolean testAutoLoadLimit(Book book) {
String str = prefs.getString(mContext.getString(R.string.pref_key_update_autoload_limit), mContext.getString(R.string.pref_default_update_atutoload_limit));
int limit;
try {
limit = Integer.parseInt(str);
} catch (NumberFormatException ex) {
Log.e(DEBUG_TAG, "Error parse Auto-load limit: " + str, ex);
return false;
}
if (limit == 0) {
return true;//download in any way
}
long lLimit = (long) limit;
return book.getSize() < lLimit;
}
public int getTheme() {
String str = prefs.getString(mContext.getString(R.string.pref_key_theme),
mContext.getString(R.string.pref_default_theme));
if (str.equals(LIGHT)) {
return R.style.MyThemeLight;
}
return R.style.MyTheme;
}
public int getSelectedIcon() {
TypedArray a = mContext.getTheme().obtainStyledAttributes(getTheme(), new int[]{R.attr.iconSelected});
return a.getResourceId(0, 0);
}
public int getLockIcon(){
TypedArray a = mContext.getTheme().obtainStyledAttributes(getTheme(), new int[]{R.attr.iconLock});
return a.getResourceId(0, 0);
}
public int getSortIcon() {
String str = prefs.getString(mContext.getString(R.string.pref_key_theme),
mContext.getString(R.string.pref_default_theme));
if (str.equals(LIGHT)) {
return R.drawable.collections_sort_by_size_l;
}
return R.drawable.collections_sort_by_size;
}
@Override
public String getFirstMirror() {
return prefs.getString(mContext.getString(R.string.pref_key_mirror), mContext.getString(R.string.pref_default_mirror));
}
@Override
public String getBookLifeTime(){
return prefs.getString(mContext.getString(R.string.pref_key_book_lifetime), mContext.getString(R.string.pref_default_book_lifetime));
}
/**
* Prepare for backup
* Copy all preferences into external object
*
* @param tot Special SharedPreferences to copy settings to
*/
public void backup(SharedPreferences tot) {
Log.d(DEBUG_TAG, "begin settings backup");
SharedPreferences.Editor editor = tot.edit();
for (Map.Entry<String, ?> entry : prefs.getAll().entrySet()) {
Object v = entry.getValue();
String key = entry.getKey();
Log.d(DEBUG_TAG, "copy key: " + key + " value: " + v);
if (v instanceof Boolean)
editor.putBoolean(key, (Boolean) v);
else if (v instanceof Float)
editor.putFloat(key, (Float) v);
else if (v instanceof Integer)
editor.putInt(key, (Integer) v);
else if (v instanceof Long)
editor.putLong(key, (Long) v);
else if (v instanceof String)
editor.putString(key, ((String) v));
}
editor.commit();
}
/**
* Restore settings from external object
*
* @param map external data to restore data from
*/
public void restore(Map<String, ?> map) {
Log.d(DEBUG_TAG, "begin setting restore");
SharedPreferences.Editor editor = prefs.edit();
for (Map.Entry<String, ?> entry : map.entrySet()) {
String key = entry.getKey();
Object v = entry.getValue();
if (key.startsWith("pref_key_")) {
Log.d(DEBUG_TAG, "restore key: " + key + " with value: " + v);
if (v instanceof Boolean)
editor.putBoolean(key, (Boolean) v);
else if (v instanceof Float)
editor.putFloat(key, (Float) v);
else if (v instanceof Integer)
editor.putInt(key, (Integer) v);
else if (v instanceof Long)
editor.putLong(key, (Long) v);
else if (v instanceof String)
editor.putString(key, ((String) v));
}
}
editor.commit();
updateServiceForce();
Log.d(DEBUG_TAG, "end setting restore");
}
public boolean isDirectoryWritable(String newValue) {
File ff = new File(newValue + DATA_DIR);
ff.mkdirs();
return ff.canWrite();
// if (ff.canWrite()){
// Log.d(DEBUG_TAG,"Directory is Valid!!");
// return true;
//
// }
// else {
// Log.d(DEBUG_TAG,"WRONG Directory!!");
// return false;
// }
}
public File getDataDirectory() {
String SdPath = prefs.getString(mContext.getString(R.string.pref_key_directory), null);
if (TextUtils.isEmpty(SdPath)) {
SdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
Log.d(DEBUG_TAG, "Data dir default set to: " + SdPath);
SharedPreferences.Editor edit = prefs.edit();
edit.putString(mContext.getString(R.string.pref_key_directory), SdPath);
edit.commit();
}
File ff = new File(SdPath + DATA_DIR);
if (ff.isDirectory()) {
return ff;
}
ff.mkdirs();
return ff;
}
@Override
public String getCollationRule() {
return SamLibConfig.COLLATION_RULES_NEW;
}
public String getUpdateTag() {
return prefs.getString(mContext.getString(R.string.pref_key_update_tag),
Integer.toString(SamLibConfig.TAG_AUTHOR_ALL));
}
public boolean isAnimation() {
return prefs.getBoolean(mContext.getString(R.string.pref_key_flag_anim), false);
}
public boolean isNotifyTickerEnable() {
return prefs.getBoolean(mContext.getString(R.string.pref_key_flag_update_ticker), true);
}
public void setGoogleAuto(boolean googleAuto) {
prefs.edit().putBoolean(mContext.getString(R.string.pref_key_google_auto), googleAuto).commit();
}
public boolean isGoogleAuto() {
return prefs.getBoolean(mContext.getString(R.string.pref_key_google_auto), false);
}
public boolean isGoogleAutoEnable() {
return prefs.getBoolean(mContext.getString(R.string.pref_key_google_auto_enable), false);
}
public void setGoogleAutoEnable(boolean enable) {
prefs.edit().putBoolean(mContext.getString(R.string.pref_key_google_auto_enable), enable).commit();
if (!enable) {
setGoogleAuto(false);
}
}
@Override
public boolean isUpdateDelay(){
return prefs.getBoolean(mContext.getString(R.string.pref_key_update_delay), false);
}
public boolean isShowBookDate(){
return prefs.getBoolean(mContext.getString(R.string.pref_key_book_date),false);
}
}