package net.bible.service.device; import android.content.ContentResolver; import android.content.SharedPreferences; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.Log; import net.bible.android.BibleApplication; import net.bible.android.activity.R; import net.bible.android.control.event.apptobackground.AppToBackgroundEvent; import net.bible.service.common.CommonUtils; import org.apache.commons.lang3.StringUtils; import de.greenrobot.event.EventBus; /** * Manage local Window timeout (Sleep) time which is different to the default/system Sleep time * * @author Martin Denham [mjdenham at gmail dot com] * @see gnu.lgpl.License for license details.<br> * The copyright to this program is held by it's author. */ public class ScreenTimeoutSettings { public static final String SCREEN_TIMEOUT_PREF = "screen_timeout_pref"; // persist the system screen timeout otherwise it could potentially be lost if not reset and app is terminated public static final String SYSTEM_SCREEN_TIMEOUT_KEY = "system_screen_timeout"; // Offset custom timeout by 27 milliseconds to ensure custom timeouts are recognisable - all standard timeouts will be whole seconds // This is a safety measure to allow custom timeouts to be recognised and not permanently override system timeout private static final int CUSTOM_TIMEOUT_OFFSET_MARKER_MILLIS = 17; public static final int NOT_SET = -999; public static final int DEFAULT_VALUE = -998; private static final int ONE_MINUTE_MILLIS = 60*1000; private static final String TAG = "BibleApplication"; /** * Add fore/background event hook to manage screen timeout setting */ public void overrideScreenTimeout() { // listen for app to come and go to override screen timeout value EventBus.getDefault().register(this); } /** * Set/reset app/standard screen timeout values */ public void onEvent(AppToBackgroundEvent event) { if (event.isMovedToBackground()) { try { restoreSystemTimeout(); } catch (Exception e) { // Avoid occasional exception in setScreenTimeout when restoring system timeout: // java.lang.SecurityException: Permission Denial: writing com.android.providers.settings.OverlaySettingsProvider uri content://settings/system from pid=9176, uid=10076 requires android.permission.WRITE_SETTINGS // Bad, but cannot allow app to crash on exit - system timeout may not be set if crash occurs in above method // It only occurred twice among thousands of users in first few days of release Log.e(TAG, "Error restoring system timeout", e); } } else { // Now in foreground // save the, possibly changed, system timeout saveSystemTimeout(); // set And Bible screen timeout setScreenTimeout(); } } /** * Default, 2, 10, 30 minutes * @return */ public String[] getPreferenceEntries() { String[] entries = new String[4]; entries[0] = CommonUtils.getResourceString(R.string.default_value); entries[1] = CommonUtils.getResourceString(R.string.x_minutes, 2); entries[2] = CommonUtils.getResourceString(R.string.x_minutes, 10); entries[3] = CommonUtils.getResourceString(R.string.x_minutes, 30); return entries; } /** Must be array of String not int[] or Integer[] because of deficiency in Android Preference handling */ public String[] getPreferenceEntryValues() { String[] entryValues = new String[4]; entryValues[0] = Integer.toString(DEFAULT_VALUE); entryValues[1] = Integer.toString((2*ONE_MINUTE_MILLIS)+CUSTOM_TIMEOUT_OFFSET_MARKER_MILLIS); entryValues[2] = Integer.toString((10*ONE_MINUTE_MILLIS)+CUSTOM_TIMEOUT_OFFSET_MARKER_MILLIS); entryValues[3] = Integer.toString((30*ONE_MINUTE_MILLIS)+CUSTOM_TIMEOUT_OFFSET_MARKER_MILLIS); return entryValues; } public void saveSystemTimeout() { try { // save old timeout ready for restore when app goes to background int currentTimeoutTime = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT); // must avoid saving an And Bible specific custom timeout as the systemTimeout because this would cause And Bible to overwrite the default timeout value // we use the OFFSET_MARKER to distinguish system and custom timeouts because all system timeouts should be a whole number of seconds boolean isCurrentTimeoutCustom = ((currentTimeoutTime % 1000)==CUSTOM_TIMEOUT_OFFSET_MARKER_MILLIS); if (!isCurrentTimeoutCustom) { CommonUtils.getSharedPreferences().edit() .putInt(SYSTEM_SCREEN_TIMEOUT_KEY, currentTimeoutTime) .commit(); } } catch (SettingNotFoundException snfe) { Log.e(TAG, "Error setting Window timeout", snfe); } } private static int getSystemTimeoutTimeMillis() { return CommonUtils.getSharedPreferences().getInt(SYSTEM_SCREEN_TIMEOUT_KEY, NOT_SET); } public void restoreSystemTimeout() { setScreenTimeout(getSystemTimeoutTimeMillis()); } public void setScreenTimeout() { int newTimeout = getScreenTimeoutPreferenceValue(); setScreenTimeout(newTimeout); } public static void setScreenTimeout(int newScreenTimeout) { // default value is whatever is set as the Android Sleep time in the main Android settings screen if (newScreenTimeout==DEFAULT_VALUE) { newScreenTimeout = getSystemTimeoutTimeMillis(); } if (newScreenTimeout!=NOT_SET) { Log.d(TAG, "Set screen timeout:"+newScreenTimeout); //override screen timeout // Set screen timeout to 10 minutes... Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, newScreenTimeout); } } private int getScreenTimeoutPreferenceValue() { int screenTimeoutPref = NOT_SET; try { SharedPreferences preferences = CommonUtils.getSharedPreferences(); if (preferences!=null) { String prefString = preferences.getString(SCREEN_TIMEOUT_PREF, Integer.toString(NOT_SET)); if (StringUtils.isNotEmpty(prefString)) { screenTimeoutPref = Integer.parseInt(prefString); } } } catch (Exception e) { // just allow return of NOT_SET Log.e(TAG, "Error getting screen timeout preference setting", e); } return screenTimeoutPref; } private static ContentResolver getContentResolver() { return BibleApplication.getApplication().getContentResolver(); } }