OmniGears: add doze settings editor view

based on https://github.com/p0isonra1n/Doze-Settings-Editor

Change-Id: I72c2dd1c21097ce37d30bfc2e5175007bf7abb46
diff --git a/res/drawable/ic_info.xml b/res/drawable/ic_info.xml
new file mode 100644
index 0000000..4fdc347
--- /dev/null
+++ b/res/drawable/ic_info.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportHeight="24.0"
+        android:viewportWidth="24.0">
+    <path
+        android:fillColor="?android:attr/colorAccent"
+        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z" />
+</vector>
diff --git a/res/drawable/ic_menu_filter.xml b/res/drawable/ic_menu_filter.xml
new file mode 100644
index 0000000..1b346d8
--- /dev/null
+++ b/res/drawable/ic_menu_filter.xml
@@ -0,0 +1,7 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path android:fillColor="#fff" android:pathData="M6,13H18V11H6M3,6V8H21V6M10,18H14V16H10V18Z" />
+</vector>
diff --git a/res/drawable/ic_menu_save.xml b/res/drawable/ic_menu_save.xml
new file mode 100644
index 0000000..8bc0624
--- /dev/null
+++ b/res/drawable/ic_menu_save.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#fff"
+        android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
+</vector>
diff --git a/res/layout/doze_item.xml b/res/layout/doze_item.xml
new file mode 100644
index 0000000..beb4d68
--- /dev/null
+++ b/res/layout/doze_item.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--  Copyright (C) 2017 The OmniROM Project
+
+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, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <RelativeLayout
+        android:id="@+id/idle_config"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <ImageView
+            android:id="@+id/idle_config_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_info"
+            android:layout_alignParentLeft="true"
+            android:layout_centerVertical="true"/>
+
+        <TextView
+            android:id="@+id/idle_config_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_toRightOf="@id/idle_config_image"
+            android:paddingLeft="5dp"
+            android:layout_centerVertical="true" />
+
+        <EditText
+            android:id="@+id/idle_config_edit"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true"
+            android:inputType="number"
+            android:layout_centerVertical="true"/>
+
+    </RelativeLayout>
+</LinearLayout>
diff --git a/res/layout/doze_settings.xml b/res/layout/doze_settings.xml
new file mode 100644
index 0000000..7692652
--- /dev/null
+++ b/res/layout/doze_settings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--  Copyright (C) 2017 The OmniROM Project
+
+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, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingStart="10dp"
+    android:paddingEnd="10dp" >
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:scrollbarStyle="insideInset" >
+
+        <LinearLayout
+            android:id="@+id/idle_config_container"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical">
+        </LinearLayout>
+    </ScrollView>
+</LinearLayout>
diff --git a/res/menu/doze_settings_menu.xml b/res/menu/doze_settings_menu.xml
new file mode 100644
index 0000000..f37e1ea
--- /dev/null
+++ b/res/menu/doze_settings_menu.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/action_save"
+        android:orderInCategory="1"
+        android:title="@string/action_save"
+        android:icon="@drawable/ic_menu_save"
+        android:showAsAction="always" />
+    <item
+        android:id="@+id/action_filter"
+        android:orderInCategory="2"
+        android:title="@string/action_filter"
+        android:icon="@drawable/ic_menu_filter"
+        android:showAsAction="always" />
+    <item
+        android:id="@+id/action_profile"
+        android:orderInCategory="3"
+        android:title="@string/action_profile"
+        android:showAsAction="never" />
+    <item
+        android:id="@+id/action_save_as_profile"
+        android:orderInCategory="4"
+        android:title="@string/action_save_as_profile"
+        android:showAsAction="never" />
+    <item
+        android:id="@+id/action_restoredefault"
+        android:orderInCategory="5"
+        android:title="@string/action_restoredefault"
+        android:showAsAction="never" />
+</menu>
diff --git a/res/values/custom_arrays.xml b/res/values/custom_arrays.xml
index cc226db..414a4c2 100644
--- a/res/values/custom_arrays.xml
+++ b/res/values/custom_arrays.xml
@@ -343,4 +343,104 @@
         <item>@string/total_time</item>
         <item>@string/wakelock_time</item>
     </string-array>
+
+    <!-- Doze settings editor -->
+    <string-array name="idle_config_keys" translatable="false">
+        <item>light_after_inactive_to</item>
+        <item>light_pre_idle_to</item>
+        <item>light_idle_to</item>
+        <item>light_idle_factor</item>
+        <item>light_max_idle_to</item>
+        <item>light_idle_maintenance_min_budget</item>
+        <item>light_idle_maintenance_max_budget</item>
+        <item>min_light_maintenance_time</item>
+        <item>min_deep_maintenance_time</item>
+        <item>inactive_to</item>
+        <item>sensing_to</item>
+        <item>locating_to</item>
+        <item>location_accuracy</item>
+        <item>motion_inactive_to</item>
+        <item>idle_after_inactive_to</item>
+        <item>idle_pending_to</item>
+        <item>max_idle_pending_to</item>
+        <item>idle_pending_factor</item>
+        <item>idle_to</item>
+        <item>max_idle_to</item>
+        <item>idle_factor</item>
+        <item>min_time_to_alarm</item>
+        <item>max_temp_app_whitelist_duration</item>
+        <item>mms_temp_app_whitelist_duration</item>
+        <item>sms_temp_app_whitelist_duration</item>
+    </string-array>
+
+    <string-array name="idle_config_keys_basic" translatable="false">
+        <item>light_after_inactive_to</item>
+        <item>light_pre_idle_to</item>
+        <item>light_idle_to</item>
+        <item>inactive_to</item>
+        <item>sensing_to</item>
+        <item>locating_to</item>
+        <item>motion_inactive_to</item>
+        <item>idle_after_inactive_to</item>
+        <item>idle_pending_to</item>
+        <item>idle_to</item>
+        <item>min_time_to_alarm</item>
+        <item>max_temp_app_whitelist_duration</item>
+    </string-array>
+
+    <string-array name="idle_config_desc" translatable="false">
+        <item>@string/DESC_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT</item>
+        <item>@string/DESC_LIGHT_PRE_IDLE_TIMEOUT</item>
+        <item>@string/DESC_LIGHT_IDLE_TIMEOUT</item>
+        <item>@string/DESC_LIGHT_IDLE_FACTOR</item>
+        <item>@string/DESC_LIGHT_MAX_IDLE_TIMEOUT</item>
+        <item>@string/DESC_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET</item>
+        <item>@string/DESC_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET</item>
+        <item>@string/DESC_MIN_LIGHT_MAINTENANCE_TIME</item>
+        <item>@string/DESC_MIN_DEEP_MAINTENANCE_TIME</item>
+        <item>@string/DESC_INACTIVE_TIMEOUT</item>
+        <item>@string/DESC_SENSING_TIMEOUT</item>
+        <item>@string/DESC_LOCATING_TIMEOUT</item>
+        <item>@string/DESC_LOCATION_ACCURACY</item>
+        <item>@string/DESC_MOTION_INACTIVE_TIMEOUT</item>
+        <item>@string/DESC_IDLE_AFTER_INACTIVE_TIMEOUT</item>
+        <item>@string/DESC_IDLE_PENDING_TIMEOUT</item>
+        <item>@string/DESC_MAX_IDLE_PENDING_TIMEOUT</item>
+        <item>@string/DESC_IDLE_PENDING_FACTOR</item>
+        <item>@string/DESC_IDLE_TIMEOUT</item>
+        <item>@string/DESC_MAX_IDLE_TIMEOUT</item>
+        <item>@string/DESC_IDLE_FACTOR</item>
+        <item>@string/DESC_MIN_TIME_TO_ALARM</item>
+        <item>@string/DESC_MAX_TEMP_APP_WHITELIST_DURATION</item>
+        <item>@string/DESC_MMS_TEMP_APP_WHITELIST_DURATION</item>
+        <item>@string/DESC_SMS_TEMP_APP_WHITELIST_DURATION</item>
+    </string-array>
+
+    <string-array name="idle_config_short" translatable="false">
+        <item>@string/SHORT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT</item>
+        <item>@string/SHORT_LIGHT_PRE_IDLE_TIMEOUT</item>
+        <item>@string/SHORT_LIGHT_IDLE_TIMEOUT</item>
+        <item>@string/SHORT_LIGHT_IDLE_FACTOR</item>
+        <item>@string/SHORT_LIGHT_MAX_IDLE_TIMEOUT</item>
+        <item>@string/SHORT_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET</item>
+        <item>@string/SHORT_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET</item>
+        <item>@string/SHORT_MIN_LIGHT_MAINTENANCE_TIME</item>
+        <item>@string/SHORT_MIN_DEEP_MAINTENANCE_TIME</item>
+        <item>@string/SHORT_INACTIVE_TIMEOUT</item>
+        <item>@string/SHORT_SENSING_TIMEOUT</item>
+        <item>@string/SHORT_LOCATING_TIMEOUT</item>
+        <item>@string/SHORT_LOCATION_ACCURACY</item>
+        <item>@string/SHORT_MOTION_INACTIVE_TIMEOUT</item>
+        <item>@string/SHORT_IDLE_AFTER_INACTIVE_TIMEOUT</item>
+        <item>@string/SHORT_IDLE_PENDING_TIMEOUT</item>
+        <item>@string/SHORT_MAX_IDLE_PENDING_TIMEOUT</item>
+        <item>@string/SHORT_IDLE_PENDING_FACTOR</item>
+        <item>@string/SHORT_IDLE_TIMEOUT</item>
+        <item>@string/SHORT_MAX_IDLE_TIMEOUT</item>
+        <item>@string/SHORT_IDLE_FACTOR</item>
+        <item>@string/SHORT_MIN_TIME_TO_ALARM</item>
+        <item>@string/SHORT_MAX_TEMP_APP_WHITELIST_DURATION</item>
+        <item>@string/SHORT_MMS_TEMP_APP_WHITELIST_DURATION</item>
+        <item>@string/SHORT_SMS_TEMP_APP_WHITELIST_DURATION</item>
+    </string-array>
 </resources>
diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml
index 9e68f0a..f7b0ee1 100644
--- a/res/values/custom_strings.xml
+++ b/res/values/custom_strings.xml
@@ -514,4 +514,70 @@
 
     <string name="lockscreen_hide_status_bar_title">Hide status bar</string>
     <string name="lockscreen_hide_status_bar_summary">Touch status bar to toggle visibility</string>
+
+    <!-- Doze settings editor -->
+    <string name="doze_settings_title">Doze settings</string>
+    <string name="doze_settings_summary">Edit doze config settings</string>
+    <string name="action_save">Save</string>
+    <string name="action_restoredefault">Restore defaults</string>
+    <string name="action_profile">Profiles</string>
+    <string name="action_save_as_profile">Save as profile</string>
+    <string name="delete_profile">Delete profile</string>
+    <string name="profile_name">Name</string>
+    <string name="string_seconds">seconds</string>
+    <string name="string_default">Default</string>
+    <string name="action_filter">Filter</string>
+
+    <string name="DESC_INACTIVE_TIMEOUT">This is the time, after becoming inactive, at which we start looking at the motion sensor to determine if the device is being left alone. We don\'t do this immediately after going inactive just because we don\'t want to be continually running the significant motion sensor whenever the screen is off</string>
+    <string name="DESC_SENSING_TIMEOUT">If we don\'t receive a callback from AnyMotion in this amount of time + locating_to, we will change from STATE_SENSING to STATE_INACTIVE, and any AnyMotion callbacks while not in STATE_SENSING will be ignored</string>
+    <string name="DESC_LOCATING_TIMEOUT">This is how long we will wait to try to get a good location fix before going in to idle mode</string>
+    <string name="DESC_LOCATION_ACCURACY">The desired maximum accuracy (in meters) we consider the location to be good enough to go on to idle. We will be trying to get an accuracy fix at least this good or until locating_to expires</string>
+    <string name="DESC_MOTION_INACTIVE_TIMEOUT">This is the time, after seeing motion, that we wait after becoming inactive from that until we start looking for motion again</string>
+    <string name="DESC_IDLE_AFTER_INACTIVE_TIMEOUT">This is the time, after the inactive timeout elapses, that we will wait looking for significant motion until we truly consider the device to be idle</string>
+    <string name="DESC_IDLE_PENDING_TIMEOUT">This is the initial time, after being idle, that we will allow ourself to be back in the IDLE_PENDING state allowing the system to run normally until we return to idle</string>
+    <string name="DESC_MAX_IDLE_PENDING_TIMEOUT">Maximum pending idle timeout (time spent running) we will be allowed to use</string>
+    <string name="DESC_IDLE_PENDING_FACTOR">Scaling factor to apply to current pending idle timeout each time we cycle through that state</string>
+    <string name="DESC_IDLE_TIMEOUT">This is the initial time that we want to sit in the idle state before waking up again to return to pending idle and allowing normal work to run</string>
+    <string name="DESC_MAX_IDLE_TIMEOUT">Maximum idle duration we will be allowed to use</string>
+    <string name="DESC_IDLE_FACTOR">Scaling factor to apply to current idle timeout each time we cycle through that state</string>
+    <string name="DESC_MIN_TIME_TO_ALARM">This is the minimum time we will allow until the next upcoming alarm for us to actually go in to idle mode</string>
+    <string name="DESC_MAX_TEMP_APP_WHITELIST_DURATION">Max amount of time to temporarily whitelist an app when it receives a high tickle</string>
+    <string name="DESC_MMS_TEMP_APP_WHITELIST_DURATION">Amount of time we would like to whitelist an app that is receiving an MMS</string>
+    <string name="DESC_SMS_TEMP_APP_WHITELIST_DURATION">Amount of time we would like to whitelist an app that is receiving an SMS</string>
+    <string name="DESC_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT">This is the time, after becoming inactive, that we go in to the first light-weight idle mode</string>
+    <string name="DESC_LIGHT_PRE_IDLE_TIMEOUT">This is amount of time we will wait from the point where we decide we would like to go idle until we actually do, while waiting for jobs and other current activity to finish</string>
+    <string name="DESC_LIGHT_IDLE_TIMEOUT">This is the initial time that we will run in idle maintenance mode</string>
+    <string name="DESC_LIGHT_IDLE_FACTOR">Scaling factor to apply to the light idle mode time each time we complete a cycle</string>
+    <string name="DESC_LIGHT_MAX_IDLE_TIMEOUT">This is the maximum time we will run in idle maintenence mode</string>
+    <string name="DESC_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET">This is the minimum amount of time we want to make available for maintenance mode when lightly idling</string>
+    <string name="DESC_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET">This is the maximum amount of time we want to make available for maintenance mode when lightly idling</string>
+    <string name="DESC_MIN_LIGHT_MAINTENANCE_TIME">This is the minimum amount of time that we will stay in maintenance mode after a light doze</string>
+    <string name="DESC_MIN_DEEP_MAINTENANCE_TIME">This is the minimum amount of time that we will stay in maintenance mode after a full doze</string>
+
+    <string name="SHORT_INACTIVE_TIMEOUT">Inactive timeout</string>
+    <string name="SHORT_SENSING_TIMEOUT">Sensing timeout</string>
+    <string name="SHORT_LOCATING_TIMEOUT">Locating timeout</string>
+    <string name="SHORT_LOCATION_ACCURACY">Location accuracy</string>
+    <string name="SHORT_MOTION_INACTIVE_TIMEOUT">Motion inactive timeout</string>
+    <string name="SHORT_IDLE_AFTER_INACTIVE_TIMEOUT">Idle after inactive timeout</string>
+    <string name="SHORT_IDLE_PENDING_TIMEOUT">Idle pending timeout</string>
+    <string name="SHORT_MAX_IDLE_PENDING_TIMEOUT">Max idle pending timeout</string>
+    <string name="SHORT_IDLE_PENDING_FACTOR">Idle pending factor</string>
+    <string name="SHORT_IDLE_TIMEOUT">Idle timeout</string>
+    <string name="SHORT_MAX_IDLE_TIMEOUT">Max idle timeout</string>
+    <string name="SHORT_IDLE_FACTOR">Idle factor</string>
+    <string name="SHORT_MIN_TIME_TO_ALARM">Min time to alarm</string>
+    <string name="SHORT_MAX_TEMP_APP_WHITELIST_DURATION">Max temp app whitelist duration</string>
+    <string name="SHORT_MMS_TEMP_APP_WHITELIST_DURATION">Max MMS app whitelist duration</string>
+    <string name="SHORT_SMS_TEMP_APP_WHITELIST_DURATION">Max SMS app whitelist duration</string>
+    <string name="SHORT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT">Light idle after inactive timeout</string>
+    <string name="SHORT_LIGHT_PRE_IDLE_TIMEOUT">Light pre idle timeout</string>
+    <string name="SHORT_LIGHT_IDLE_TIMEOUT">Light idle timeout</string>
+    <string name="SHORT_LIGHT_IDLE_FACTOR">Light idle factor</string>
+    <string name="SHORT_LIGHT_MAX_IDLE_TIMEOUT">Max light idle timeout</string>
+    <string name="SHORT_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET">Maintenance mode light idle min timeout</string>
+    <string name="SHORT_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET">Maintenance mode light idle max timeout</string>
+    <string name="SHORT_MIN_LIGHT_MAINTENANCE_TIME">Maintenance mode light doze min timeout</string>
+    <string name="SHORT_MIN_DEEP_MAINTENANCE_TIME">Maintenance mode full doze min timeout</string>
+
 </resources>
diff --git a/res/xml/more_settings.xml b/res/xml/more_settings.xml
index d06f5da..0c08876 100644
--- a/res/xml/more_settings.xml
+++ b/res/xml/more_settings.xml
@@ -74,6 +74,12 @@
                 android:summary="@string/wakelocks_summary"
                 android:fragment="org.omnirom.omnigears.system.Wakelocks" />
 
+            <PreferenceScreen
+                android:key="doze_settings"
+                android:title="@string/doze_settings_title"
+                android:summary="@string/doze_settings_summary"
+                android:fragment="org.omnirom.omnigears.system.DozeSettings" />
+
             <org.omnirom.omnigears.preference.GlobalSettingSwitchPreference
                 android:key="show_cpu"
                 android:title="@string/show_cpu_title"
diff --git a/src/org/omnirom/omnigears/system/DozeSettings.java b/src/org/omnirom/omnigears/system/DozeSettings.java
new file mode 100644
index 0000000..608f24a
--- /dev/null
+++ b/src/org/omnirom/omnigears/system/DozeSettings.java
@@ -0,0 +1,428 @@
+/*
+ *  Copyright (C) 2017 The OmniROM Project
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+*/
+package org.omnirom.omnigears.system;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+public class DozeSettings extends SettingsPreferenceFragment {
+    private static final String TAG = "DozeSettings";
+
+    private static final String SHARED_PREFERENCES_NAME = "doze_settings";
+    private static final String DEVICE_IDLE_CONSTANTS = "device_idle_constants";
+    private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
+    private static final String KEY_LOCATION_ACCURACY = "location_accuracy";
+    private static final String KEY_IDLE_PENDING_FACTOR = "idle_pending_factor";
+    private static final String KEY_IDLE_FACTOR = "idle_factor";
+    private static final String KEY_SHOW_ADVANCED = "show_advanced";
+
+    final long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = 5 * 60 * 1000L;
+    final long LIGHT_PRE_IDLE_TIMEOUT = 10 * 60 * 1000L;
+    final long LIGHT_IDLE_TIMEOUT = 5 * 60 * 1000L;
+    final float LIGHT_IDLE_FACTOR = 2f;
+    final long LIGHT_MAX_IDLE_TIMEOUT = 15 * 60 * 1000L;
+    final long LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = 1 * 60 * 1000L;
+    final long LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = 5 * 60 * 1000L;
+    final long MIN_LIGHT_MAINTENANCE_TIME = 5 * 1000L;
+    final long MIN_DEEP_MAINTENANCE_TIME = 30 * 1000L;
+    final long INACTIVE_TIMEOUT = 30 * 60 * 1000L;
+    final long SENSING_TIMEOUT = 4 * 60 * 1000L;
+    final long LOCATING_TIMEOUT = 30 * 1000L;
+    final float LOCATION_ACCURACY = 20;
+    final long MOTION_INACTIVE_TIMEOUT = 10 * 60 * 1000L;
+    final long IDLE_AFTER_INACTIVE_TIMEOUT = 30 * 60 * 1000L;
+    final long IDLE_PENDING_TIMEOUT = 5 * 60 * 1000L;
+    final long MAX_IDLE_PENDING_TIMEOUT = 10 * 60 * 1000L;
+    final float IDLE_PENDING_FACTOR = 2;
+    final long IDLE_TIMEOUT = 60 * 60 * 1000L;
+    final long MAX_IDLE_TIMEOUT = 6 * 60 * 60 * 1000L;
+    final float IDLE_FACTOR = 2;
+    final long MIN_TIME_TO_ALARM = 60 * 60 * 1000L;
+    final long MAX_TEMP_APP_WHITELIST_DURATION = 5 * 60 * 1000L;
+    final long MMS_TEMP_APP_WHITELIST_DURATION = 60 * 1000L;
+    final long SMS_TEMP_APP_WHITELIST_DURATION = 20 * 1000L;
+
+    private int millisecondsInOneSecond = 1000;
+    private LinearLayout mContainer;
+    private List<String> mIdleConfigKeys = new ArrayList<String>();
+    private List<String> mIdleConfigDesc = new ArrayList<String>();
+    private List<String> mIdleConfigShort = new ArrayList<String>();
+    private List<Object> mIdleConfigValues = new ArrayList<Object>();
+    private List<String> mIdleConfigKeysBasic = new ArrayList<String>();
+    private List<EditText> mIdleConfigEdit = new ArrayList<EditText>();
+    private List<View> mIdleConfigViews = new ArrayList<View>();
+
+    private Context mContext;
+    private boolean mShowAdvanced;
+
+    private SharedPreferences getPrefs() {
+        return mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mContext = getActivity();
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    protected int getMetricsCategory() {
+        return MetricsEvent.OMNI_SETTINGS;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup root,
+            Bundle savedInstanceState) {
+        super.onCreateView(inflater, root, savedInstanceState);
+
+        mShowAdvanced = getPrefs().getBoolean(KEY_SHOW_ADVANCED, false);
+        View view = inflater.inflate(R.layout.doze_settings, root, false);
+
+        Profiles.initProfiles();
+        Profiles.loadUserProfiles(getPrefs());
+
+        mIdleConfigKeys.addAll(Arrays.asList(getResources().getStringArray(R.array.idle_config_keys)));
+        mIdleConfigDesc.addAll(Arrays.asList(getResources().getStringArray(R.array.idle_config_desc)));
+        mIdleConfigShort.addAll(Arrays.asList(getResources().getStringArray(R.array.idle_config_short)));
+        mIdleConfigKeysBasic.addAll(Arrays.asList(getResources().getStringArray(R.array.idle_config_keys_basic)));
+
+        mIdleConfigValues.add(LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
+        mIdleConfigValues.add(LIGHT_PRE_IDLE_TIMEOUT);
+        mIdleConfigValues.add(LIGHT_IDLE_TIMEOUT);
+        mIdleConfigValues.add(LIGHT_IDLE_FACTOR);
+        mIdleConfigValues.add(LIGHT_MAX_IDLE_TIMEOUT);
+        mIdleConfigValues.add(LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
+        mIdleConfigValues.add(LIGHT_IDLE_MAINTENANCE_MAX_BUDGET);
+        mIdleConfigValues.add(MIN_LIGHT_MAINTENANCE_TIME);
+        mIdleConfigValues.add(MIN_DEEP_MAINTENANCE_TIME);
+        mIdleConfigValues.add(INACTIVE_TIMEOUT);
+        mIdleConfigValues.add(SENSING_TIMEOUT);
+        mIdleConfigValues.add(LOCATING_TIMEOUT);
+        mIdleConfigValues.add(LOCATION_ACCURACY);
+        mIdleConfigValues.add(MOTION_INACTIVE_TIMEOUT);
+        mIdleConfigValues.add(IDLE_AFTER_INACTIVE_TIMEOUT);
+        mIdleConfigValues.add(IDLE_PENDING_TIMEOUT);
+        mIdleConfigValues.add(MAX_IDLE_PENDING_TIMEOUT);
+        mIdleConfigValues.add(IDLE_PENDING_FACTOR);
+        mIdleConfigValues.add(IDLE_TIMEOUT);
+        mIdleConfigValues.add(MAX_IDLE_TIMEOUT);
+        mIdleConfigValues.add(IDLE_FACTOR);
+        mIdleConfigValues.add(MIN_TIME_TO_ALARM);
+        mIdleConfigValues.add(MAX_TEMP_APP_WHITELIST_DURATION);
+        mIdleConfigValues.add(MMS_TEMP_APP_WHITELIST_DURATION);
+        mIdleConfigValues.add(SMS_TEMP_APP_WHITELIST_DURATION);
+
+        mContainer = (LinearLayout) view.findViewById(R.id.idle_config_container);
+        createOptionsList(inflater);
+
+        getSettings();
+        return view;
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        inflater.inflate(R.menu.doze_settings_menu, menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        int id = item.getItemId();
+
+        switch (id) {
+            case R.id.action_profile:
+                displayProfiles();
+                break;
+            case R.id.action_save:
+                save();
+                break;
+            case R.id.action_save_as_profile:
+                saveAsProfile();
+                break;
+            case R.id.action_restoredefault:
+                restoreDefaults();
+                break;
+            case R.id.action_filter:
+                mShowAdvanced = !mShowAdvanced;
+                getPrefs().edit().putBoolean(KEY_SHOW_ADVANCED, mShowAdvanced).commit();
+                int i = 0;
+                for (View idleConfig : mIdleConfigViews) {
+                    final String configKey = mIdleConfigKeys.get(i);
+                    if (mShowAdvanced) {
+                        idleConfig.setVisibility(View.VISIBLE);
+                    } else {
+                        idleConfig.setVisibility(!mIdleConfigKeysBasic.contains(configKey) ? View.GONE : View.VISIBLE);
+                    }
+                    i++;
+                }
+                break;
+            }
+
+        return super.onOptionsItemSelected(item);
+    }
+
+    private String getMessage(String desc, String value) {
+        return desc +
+                "\n\n" + getResources().getString(R.string.string_default) +
+                ": " +
+                value +
+                " " +
+                getResources().getString(R.string.string_seconds);
+    }
+
+
+    private void getSettings() {
+        String line = Settings.Global.getString(getContentResolver(), DEVICE_IDLE_CONSTANTS);
+        Log.d(TAG, "getSettings = " + line);
+
+        KeyValueListParser parser = new KeyValueListParser(',');
+        if ("null".equals(line)) {
+            parser.setString(line + "=0");
+        } else {
+            parser.setString(line);
+        }
+        int divideBy = getDisplayValueFix();
+        for (int i = 0; i < mIdleConfigKeys.size(); i++) {
+            EditText editText = mIdleConfigEdit.get(i);
+            String key = mIdleConfigKeys.get(i);
+            Object defaultValue = mIdleConfigValues.get(i);
+
+            if (!key.equals(KEY_IDLE_FACTOR) && !key.equals(KEY_IDLE_PENDING_FACTOR) && !key.equals(KEY_IDLE_PENDING_FACTOR) && !key.equals(KEY_LOCATION_ACCURACY) && !key.equals(KEY_LIGHT_IDLE_FACTOR)) {
+                Long value = parser.getLong(key, (Long) defaultValue);
+                value = value / divideBy;
+                editText.setText(String.valueOf(value));
+            } else {
+                Float value = parser.getFloat(key, (Float) defaultValue);
+                editText.setText(String.valueOf(value));
+            }
+        }
+    }
+
+
+    private int getDisplayValueFix() {
+        return millisecondsInOneSecond;
+    }
+
+    private void save() {
+        int multiplyBy = getDisplayValueFix();
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < mIdleConfigKeys.size(); i++) {
+            EditText editText = mIdleConfigEdit.get(i);
+            String key = mIdleConfigKeys.get(i);
+
+            if (!key.equals(KEY_IDLE_FACTOR) && !key.equals(KEY_IDLE_PENDING_FACTOR) && !key.equals(KEY_IDLE_PENDING_FACTOR) && !key.equals(KEY_LOCATION_ACCURACY) && !key.equals(KEY_LIGHT_IDLE_FACTOR)) {
+                Long value = Long.valueOf(editText.getText().toString()) * multiplyBy;
+                sb.append(key + "=" + value + ",");
+            } else {
+                Float value = Float.valueOf(editText.getText().toString());
+                sb.append(key + "=" + value + ",");
+            }
+        }
+        if (sb.length() != 0) {
+            sb.deleteCharAt(sb.length() - 1);
+        }
+        Log.d(TAG, "save = " + sb.toString());
+        Settings.Global.putString(getContentResolver(), DEVICE_IDLE_CONSTANTS, sb.toString());
+    }
+
+    private void restoreDefaults() {
+        Log.d(TAG, "restoreDefaults");
+        Settings.Global.putString(getContentResolver(), DEVICE_IDLE_CONSTANTS, null);
+        getSettings();
+    }
+
+    private void applyProfile(String settings) {
+        Log.d(TAG, "apply = " + settings);
+        Settings.Global.putString(getContentResolver(), DEVICE_IDLE_CONSTANTS, settings);
+        getSettings();
+    }
+
+    private void displayProfiles() {
+        final ArrayList<Profiles.Profile> combinedProfileList = new ArrayList<>();
+        combinedProfileList.addAll(Profiles.getSystemProfileList());
+        combinedProfileList.addAll(Profiles.getUserProfileList());
+        Collections.sort(combinedProfileList);
+        int profileCount = 0;
+        String[] names = new String[combinedProfileList.size()];
+        for (Profiles.Profile profile : combinedProfileList) {
+            if (Profiles.getSystemProfileList().contains(profile)) {
+                names[profileCount] = profile.getName() + " *";
+            } else {
+                names[profileCount] = profile.getName();
+            }
+            profileCount++;
+        }
+        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+        builder.setTitle(getResources().getString(R.string.action_profile));
+        builder.setItems(names, new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dialog, int item) {
+                applyProfile(combinedProfileList.get(item).getSettings());
+            }
+        });
+        final AlertDialog alert = builder.create();
+        alert.setOnShowListener(new DialogInterface.OnShowListener() {
+            @Override
+            public void onShow(DialogInterface dialog) {
+                ListView lv = alert.getListView();
+                lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
+                    @Override
+                    public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
+                        Profiles.Profile p = combinedProfileList.get(position);
+                        if (Profiles.getUserProfileList().contains(p)) {
+                            AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
+                            dialog.setTitle(getResources().getString(R.string.delete_profile));
+                            dialog.setMessage(p.getName());
+                            dialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                                @Override
+                                public void onClick(DialogInterface dialog, int which) {
+                                    Profiles.removeProfile(p);
+                                    combinedProfileList.remove(p);
+                                    Profiles.saveUserProfiles(getPrefs());
+                                    alert.hide();
+                                }
+                            });
+                            dialog.setNegativeButton(android.R.string.cancel, null);
+                            dialog.create().show();
+                        }
+                        return true;
+                    }
+                });
+            }
+        });
+        alert.show();
+    }
+
+    private void saveAsProfile() {
+        AlertDialog.Builder alert = new AlertDialog.Builder(mContext);
+        final EditText edittext = new EditText(mContext);
+        alert.setTitle(getResources().getString(R.string.profile_name));
+
+        alert.setView(edittext);
+
+        alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dialog, int whichButton) {
+                String name = edittext.getText().toString();
+                int multiplyBy = getDisplayValueFix();
+                StringBuilder sb = new StringBuilder();
+                for (int i = 0; i < mIdleConfigKeys.size(); i++) {
+                    EditText editText = mIdleConfigEdit.get(i);
+                    String key = mIdleConfigKeys.get(i);
+
+                    if (!key.equals(KEY_IDLE_FACTOR) && !key.equals(KEY_IDLE_PENDING_FACTOR) && !key.equals(KEY_IDLE_PENDING_FACTOR) && !key.equals(KEY_LOCATION_ACCURACY) && !key.equals(KEY_LIGHT_IDLE_FACTOR)) {
+                        Long value = Long.valueOf(editText.getText().toString()) * multiplyBy;
+                        sb.append(key + "=" + value + ",");
+                    } else {
+                        Float value = Float.valueOf(editText.getText().toString());
+                        sb.append(key + "=" + value + ",");
+                    }
+                }
+                if (sb.length() != 0) {
+                    sb.deleteCharAt(sb.length() - 1);
+                }
+                Profiles.Profile profile = new Profiles.Profile(name, sb.toString());
+                Profiles.addProfile(profile);
+                Profiles.saveUserProfiles(getPrefs());
+            }
+        });
+
+        alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dialog, int whichButton) {
+                // what ever you want to do with No option.
+            }
+        });
+
+        alert.show();
+    }
+
+    private void createOptionsList(LayoutInflater inflater) {
+        mContainer.removeAllViews();
+        for (int i = 0; i < mIdleConfigKeys.size(); i++) {
+            final String configKey = mIdleConfigKeys.get(i);
+            final int idx = i;
+            View idleConfig = inflater.inflate(R.layout.doze_item, null, false);
+            TextView idleConfigText = (TextView) idleConfig.findViewById(R.id.idle_config_text);
+            idleConfigText.setText(mIdleConfigShort.get(i));
+            EditText idleConfigValue = (EditText) idleConfig.findViewById(R.id.idle_config_edit);
+            idleConfigValue.setSaveEnabled(false);
+            mIdleConfigEdit.add(idleConfigValue);
+            ImageView idleConfigImage = (ImageView) idleConfig.findViewById(R.id.idle_config_image);
+            idleConfig.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    String key = mIdleConfigKeys.get(idx);
+                    int divideBy = getDisplayValueFix();
+                    AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+                    builder.setTitle(key);
+                    Object value = mIdleConfigValues.get(idx);
+                    if (!key.equals(KEY_IDLE_FACTOR) && !key.equals(KEY_IDLE_PENDING_FACTOR) && !key.equals(KEY_IDLE_PENDING_FACTOR) && !key.equals(KEY_LOCATION_ACCURACY) && !key.equals(KEY_LIGHT_IDLE_FACTOR)) {
+                        if (value instanceof Long) {
+                            value = ((Long) value) / divideBy;
+                        }
+                        builder.setMessage(getMessage(mIdleConfigDesc.get(idx), String.valueOf(value)));
+                    } else {
+                        builder.setMessage(mIdleConfigDesc.get(idx) +
+                                "\n\n" +
+                                getResources().getString(R.string.string_default) +
+                                ": " +
+                                String.valueOf(value));
+                    }
+                    builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int id) {
+                        }
+                    });
+                    AlertDialog dialog = builder.create();
+                    dialog.show();
+                }
+            });
+            mContainer.addView(idleConfig);
+            mIdleConfigViews.add(idleConfig);
+            if (mShowAdvanced) {
+                idleConfig.setVisibility(View.VISIBLE);
+            } else {
+                idleConfig.setVisibility(!mIdleConfigKeysBasic.contains(configKey) ? View.GONE : View.VISIBLE);
+            }
+        }
+    }
+}
diff --git a/src/org/omnirom/omnigears/system/KeyValueListParser.java b/src/org/omnirom/omnigears/system/KeyValueListParser.java
new file mode 100644
index 0000000..3669d78
--- /dev/null
+++ b/src/org/omnirom/omnigears/system/KeyValueListParser.java
@@ -0,0 +1,114 @@
+package org.omnirom.omnigears.system;
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.
+ */
+import android.text.TextUtils;
+import android.util.ArrayMap;
+
+/**
+ * Parses a list of key=value pairs, separated by some delimiter, and puts the results in
+ * an internal Map. Values can be then queried by key, or if not found, a default value
+ * can be used.
+ * @hide
+ */
+public class KeyValueListParser {
+    private final ArrayMap<String, String> mValues = new ArrayMap<>();
+    private final TextUtils.StringSplitter mSplitter;
+
+    /**
+     * Constructs a new KeyValueListParser. This can be reused for different strings
+     * by calling {@link #setString(String)}.
+     * @param delim The delimiter that separates key=value pairs.
+     */
+    public KeyValueListParser(char delim) {
+        mSplitter = new TextUtils.SimpleStringSplitter(delim);
+    }
+
+    /**
+     * Resets the parser with a new string to parse. The string is expected to be in the following
+     * format:
+     * <pre>key1=value,key2=value,key3=value</pre>
+     *
+     * where the delimiter is a comma.
+     *
+     * @param str the string to parse.
+     * @throws IllegalArgumentException if the string is malformed.
+     */
+    public void setString(String str) throws IllegalArgumentException {
+        mValues.clear();
+        if (str != null) {
+            mSplitter.setString(str);
+            for (String pair : mSplitter) {
+                int sep = pair.indexOf('=');
+                if (sep < 0) {
+                    mValues.clear();
+                    throw new IllegalArgumentException(
+                            "'" + pair + "' in '" + str + "' is not a valid key-value pair");
+                }
+                mValues.put(pair.substring(0, sep).trim(), pair.substring(sep + 1).trim());
+            }
+        }
+    }
+
+    /**
+     * Get the value for key as a long.
+     * @param key The key to lookup.
+     * @param def The value to return if the key was not found, or the value was not a long.
+     * @return the long value associated with the key.
+     */
+    public long getLong(String key, long def) {
+        String value = mValues.get(key);
+        if (value != null) {
+            try {
+                return Long.parseLong(value);
+            } catch (NumberFormatException e) {
+                // fallthrough
+            }
+        }
+        return def;
+    }
+
+    /**
+     * Get the value for key as a float.
+     * @param key The key to lookup.
+     * @param def The value to return if the key was not found, or the value was not a float.
+     * @return the float value associated with the key.
+     */
+    public float getFloat(String key, float def) {
+        String value = mValues.get(key);
+        if (value != null) {
+            try {
+                return Float.parseFloat(value);
+            } catch (NumberFormatException e) {
+                // fallthrough
+            }
+        }
+        return def;
+    }
+
+    /**
+     * Get the value for key as a string.
+     * @param key The key to lookup.
+     * @param def The value to return if the key was not found.
+     * @return the string value associated with the key.
+     */
+    public String getString(String key, String def) {
+        String value = mValues.get(key);
+        if (value != null) {
+            return value;
+        }
+        return def;
+    }
+}
diff --git a/src/org/omnirom/omnigears/system/Profiles.java b/src/org/omnirom/omnigears/system/Profiles.java
new file mode 100644
index 0000000..cabc784
--- /dev/null
+++ b/src/org/omnirom/omnigears/system/Profiles.java
@@ -0,0 +1,113 @@
+/*
+ *  Copyright (C) 2017 The OmniROM Project
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+*/
+package org.omnirom.omnigears.system;
+
+import android.content.SharedPreferences;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Profiles {
+
+    public static class Profile implements Comparable<Profile> {
+
+        private String mName;
+        private String mSettings;
+
+        public Profile(String name, String settings){
+            mName = name;
+            mSettings = settings;
+        }
+
+        public String getName() {
+            return mName;
+        }
+
+        public String getSettings() {
+            return mSettings;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == null || ! (o instanceof Profile)) {
+                return false;
+            }
+            return mName.equals(((Profile)o).getName());
+        }
+
+        @Override
+        public int compareTo(Profile profile) {
+            return mName.compareTo(profile.getName());
+        }
+    }
+
+    private static final String PROFILE_PREFS = "profiles";
+
+    private static List<Profile> mUserProfileList = new ArrayList<>();
+    private static List<Profile> mSysteProfileList = new ArrayList<>();
+
+    public static void initProfiles() {
+        mSysteProfileList.clear();
+        mSysteProfileList.add(new Profile("aggressive", "light_after_inactive_to=60000,light_pre_idle_to=60000,light_idle_to=120000,light_idle_factor=2.0,light_max_idle_to=900000,light_idle_maintenance_min_budget=60000,light_idle_maintenance_max_budget=300000,min_light_maintenance_time=5000,min_deep_maintenance_time=30000,inactive_to=120000,sensing_to=0,locating_to=30000,location_accuracy=20.0,motion_inactive_to=60000,idle_after_inactive_to=0,idle_pending_to=120000,max_idle_pending_to=120000,idle_pending_factor=2.0,idle_to=3600000,max_idle_to=21600000,idle_factor=2.0,min_time_to_alarm=3600000,max_temp_app_whitelist_duration=30000,mms_temp_app_whitelist_duration=30000,sms_temp_app_whitelist_duration=20000"));
+    }
+
+    public static List<Profile> getUserProfileList() {
+        return mUserProfileList;
+    }
+
+    public static List<Profile> getSystemProfileList() {
+        return mSysteProfileList;
+    }
+
+    public static void addProfile(Profile profile) {
+        if (mUserProfileList.contains(profile)) {
+            mUserProfileList.remove(profile);
+        }
+        mUserProfileList.add(profile);
+    }
+
+    public static void removeProfile(Profile profile) {
+        mUserProfileList.remove(profile);
+    }
+
+    public static void loadUserProfiles(SharedPreferences sharedPref) {
+        String userProfile = sharedPref.getString(PROFILE_PREFS , null);
+        mUserProfileList.clear();
+        if (!TextUtils.isEmpty(userProfile)) {
+            String[] profiles = userProfile.split(";");
+            for (String profile : profiles) {
+                String[] profileParts = profile.split(":");
+                Profile p = new Profile(profileParts[0], profileParts[1]);
+                mUserProfileList.add(p);
+            }
+        }
+    }
+
+    public static void saveUserProfiles(SharedPreferences sharedPref){
+        if (mUserProfileList.size() != 0) {
+            StringBuffer sb = new StringBuffer();
+            for (Profile p : mUserProfileList) {
+                sb.append(p.getName() + ":" + p.getSettings() + ";");
+            }
+            sharedPref.edit().putString(PROFILE_PREFS, sb.toString()).commit();
+        } else {
+            sharedPref.edit().remove(PROFILE_PREFS).commit();
+        }
+    }
+}