Merge "Fix bug #17459965 Take photo for Profile twice leads to "A resource was acquired at attached stack trace but never released" into lmp-dev
diff --git a/res/layout/bluetooth_device_settings.xml b/res/layout/bluetooth_device_settings.xml
index b87551a..b65ca0f 100644
--- a/res/layout/bluetooth_device_settings.xml
+++ b/res/layout/bluetooth_device_settings.xml
@@ -20,35 +20,9 @@
         android:orientation="vertical"
         android:gravity="center">
 
-    <LinearLayout android:id="@+id/dialog_layout"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:paddingBottom="@dimen/bluetooth_dialog_padding"
-            style="@style/bt_item" >
-
-            <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/bluetooth_preference_paired_dialog_name_label"
-                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:textDirection="locale"
-                    style="@style/bt_item_label" />
-
-            <EditText android:id="@+id/name"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:inputType="textNoSuggestions"
-                    android:maxLength="@integer/bluetooth_name_length"
-                    android:singleLine="true"
-                    style="@style/bt_item_edit_content" />
-
             <fragment android:id="@+id/bluetooth_fragment_settings"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     class="com.android.settings.bluetooth.DeviceProfilesSettings" />
 
-    </LinearLayout>
-
 </LinearLayout>
diff --git a/res/layout/bluetooth_device_settings_header.xml b/res/layout/bluetooth_device_settings_header.xml
new file mode 100644
index 0000000..b1832c5
--- /dev/null
+++ b/res/layout/bluetooth_device_settings_header.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:gravity="center">
+
+    <LinearLayout android:id="@+id/dialog_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingBottom="@dimen/bluetooth_dialog_padding"
+            style="@style/bt_item" >
+
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/bluetooth_preference_paired_dialog_name_label"
+                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                    android:textColor="?android:attr/textColorSecondary"
+                    android:textDirection="locale"
+                    style="@style/bt_item_label" />
+
+            <EditText android:id="@+id/name"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:inputType="textNoSuggestions"
+                    android:maxLength="@integer/bluetooth_name_length"
+                    android:singleLine="true"
+                    style="@style/bt_item_edit_content" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/bluetooth_preference_category.xml b/res/layout/bluetooth_preference_category.xml
index 59a3e87..2b9a29a 100644
--- a/res/layout/bluetooth_preference_category.xml
+++ b/res/layout/bluetooth_preference_category.xml
@@ -22,4 +22,5 @@
     android:textAppearance="@android:style/TextAppearance.Material.Body1"
     android:textColor="?android:attr/textColorSecondary"
     android:paddingTop="16dip"
+    android:paddingStart="16dip"
     android:paddingBottom="16dip" />
diff --git a/res/layout/edit_user_info_dialog_content.xml b/res/layout/edit_user_info_dialog_content.xml
index d23f6f5..4d76e13 100644
--- a/res/layout/edit_user_info_dialog_content.xml
+++ b/res/layout/edit_user_info_dialog_content.xml
@@ -26,7 +26,7 @@
         android:layout_height="56dip"
         android:layout_gravity="bottom"
         android:layout_marginEnd="6dp"
-        android:contentDescription="@null"
+        android:contentDescription="@string/user_image_photo_selector"
         android:background="@*android:drawable/spinner_background_holo_dark"
         android:scaleType="fitCenter"/>
 
diff --git a/res/layout/preference_progress_category.xml b/res/layout/preference_progress_category.xml
index 5859fbf..1776fec 100644
--- a/res/layout/preference_progress_category.xml
+++ b/res/layout/preference_progress_category.xml
@@ -31,6 +31,7 @@
         android:background="@null"
         android:id="@+android:id/title"
         android:paddingStart="0dp"
+        android:paddingTop="6dp"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
@@ -40,6 +41,7 @@
     <ProgressBar
         android:id="@+id/scanning_progress"
         android:text="@string/progress_scanning"
+        android:paddingTop="6dp"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index afbd5c6..0b5f58a 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -91,7 +91,6 @@
     <dimen name="notification_app_icon_size">64dp</dimen>
     <dimen name="notification_app_icon_badge_size">20dp</dimen>
     <dimen name="notification_app_icon_badge_margin">4dp</dimen>
-    <dimen name="zen_mode_dropdown_width">160dp</dimen>
     <dimen name="zen_downtime_checkbox_padding">7dp</dimen>
     <dimen name="zen_downtime_margin">17dp</dimen>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 14d81df..e054423 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5479,6 +5479,8 @@
     <string name="user_image_take_photo" msgid="7496128293167402354">Take photo</string>
     <!-- An option in a photo selection dialog, if there is no photo yet [CHAR LIMIT=50] -->
     <string name="user_image_choose_photo" msgid="3746334626214970837">Choose photo from Gallery</string>
+    <!-- Accessibility message for the photo selector which is a button/popup with the current photo [CHAR LIMIT=50] -->
+    <string name="user_image_photo_selector">Select photo</string>
 
     <!-- Text to display in regulatory info screen (from device overlay). -->
     <string name="regulatory_info_text"></string>
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
index 54acf73..a89d718 100644
--- a/src/com/android/settings/ConfirmLockPassword.java
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -72,6 +72,8 @@
 
     public static class ConfirmLockPasswordFragment extends Fragment implements OnClickListener,
             OnEditorActionListener, TextWatcher {
+        private static final String KEY_NUM_WRONG_CONFIRM_ATTEMPTS
+                = "confirm_lock_password_fragment.key_num_wrong_confirm_attempts";
         private static final long ERROR_MESSAGE_TIMEOUT = 3000;
         private TextView mPasswordEntry;
         private LockPatternUtils mLockPatternUtils;
@@ -93,6 +95,10 @@
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             mLockPatternUtils = new LockPatternUtils(getActivity());
+            if (savedInstanceState != null) {
+                mNumWrongConfirmAttempts = savedInstanceState.getInt(
+                        KEY_NUM_WRONG_CONFIRM_ATTEMPTS, 0);
+            }
         }
 
         @Override
@@ -166,6 +172,12 @@
             }
         }
 
+        @Override
+        public void onSaveInstanceState(Bundle outState) {
+            super.onSaveInstanceState(outState);
+            outState.putInt(KEY_NUM_WRONG_CONFIRM_ATTEMPTS, mNumWrongConfirmAttempts);
+        }
+
         private void handleNext() {
             final String pin = mPasswordEntry.getText().toString();
             if (mLockPatternUtils.checkPassword(pin)) {
diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java
index a084137..1282409 100755
--- a/src/com/android/settings/bluetooth/BluetoothSettings.java
+++ b/src/com/android/settings/bluetooth/BluetoothSettings.java
@@ -44,6 +44,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 import android.widget.TextView;
 
@@ -322,7 +323,6 @@
                 mMyDevicePreference.setSummary(getResources().getString(
                             R.string.bluetooth_is_visible_message, mLocalAdapter.getName()));
                 mMyDevicePreference.setSelectable(false);
-                mMyDevicePreference.setEnabled(false);
                 preferenceScreen.addPreference(mMyDevicePreference);
 
                 getActivity().invalidateOptionsMenu();
@@ -401,11 +401,17 @@
                     parent.removeView(mSettingsDialogView);
                 }
             }
+
             if (profileFrag == null) {
                 LayoutInflater inflater = getActivity().getLayoutInflater();
                 mSettingsDialogView = inflater.inflate(R.layout.bluetooth_device_settings, null);
                 profileFrag = (DeviceProfilesSettings)activity.getFragmentManager()
                     .findFragmentById(R.id.bluetooth_fragment_settings);
+
+                // To enable scrolling we store the name field in a seperate header and add to
+                // the ListView of the profileFrag.
+                View header = inflater.inflate(R.layout.bluetooth_device_settings_header, null);
+                profileFrag.getListView().addHeaderView(header);
             }
 
             final View dialogLayout = mSettingsDialogView;
@@ -439,6 +445,10 @@
             AlertDialog dialog = settingsDialog.create();
             dialog.create();
             dialog.show();
+
+            // We must ensure that clicking on the EditText will bring up the keyboard.
+            dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
         }
     };
 
diff --git a/src/com/android/settings/bluetooth/HidProfile.java b/src/com/android/settings/bluetooth/HidProfile.java
index 8df2845..91e715d 100755
--- a/src/com/android/settings/bluetooth/HidProfile.java
+++ b/src/com/android/settings/bluetooth/HidProfile.java
@@ -169,7 +169,7 @@
 
     public int getDrawableResource(BluetoothClass btClass) {
         if (btClass == null) {
-            return R.drawable.ic_bt_keyboard_hid;
+            return R.drawable.ic_lockscreen_ime;
         }
         return getHidClassDrawable(btClass);
     }
@@ -178,7 +178,7 @@
         switch (btClass.getDeviceClass()) {
             case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
             case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
-                return R.drawable.ic_bt_keyboard_hid;
+                return R.drawable.ic_lockscreen_ime;
             case BluetoothClass.Device.PERIPHERAL_POINTING:
                 return R.drawable.ic_bt_pointing_hid;
             default:
diff --git a/src/com/android/settings/notification/SettingPref.java b/src/com/android/settings/notification/SettingPref.java
index de01def..a06c35a 100644
--- a/src/com/android/settings/notification/SettingPref.java
+++ b/src/com/android/settings/notification/SettingPref.java
@@ -33,15 +33,15 @@
     public static final int TYPE_GLOBAL = 1;
     public static final int TYPE_SYSTEM = 2;
 
-    private final int mType;
+    protected final int mType;
     private final String mKey;
-    private final String mSetting;
-    private final int mDefault;
+    protected final String mSetting;
+    protected final int mDefault;
     private final int[] mValues;
     private final Uri mUri;
 
-    private TwoStatePreference mTwoState;
-    private DropDownPreference mDropDown;
+    protected TwoStatePreference mTwoState;
+    protected DropDownPreference mDropDown;
 
     public SettingPref(int type, String key, String setting, int def, int... values) {
         mType = type;
@@ -129,7 +129,7 @@
         throw new IllegalArgumentException();
     }
 
-    private static boolean putInt(int type, ContentResolver cr, String setting, int value) {
+    protected static boolean putInt(int type, ContentResolver cr, String setting, int value) {
         switch(type) {
             case TYPE_GLOBAL:
                 return Global.putInt(cr, setting, value);
@@ -139,7 +139,7 @@
         throw new IllegalArgumentException();
     }
 
-    private static int getInt(int type, ContentResolver cr, String setting, int def) {
+    protected static int getInt(int type, ContentResolver cr, String setting, int def) {
         switch(type) {
             case TYPE_GLOBAL:
                 return Global.getInt(cr, setting, def);
diff --git a/src/com/android/settings/notification/ZenModeConditionSelection.java b/src/com/android/settings/notification/ZenModeConditionSelection.java
index 610baba..856a7f6 100644
--- a/src/com/android/settings/notification/ZenModeConditionSelection.java
+++ b/src/com/android/settings/notification/ZenModeConditionSelection.java
@@ -19,13 +19,13 @@
 import android.animation.LayoutTransition;
 import android.app.INotificationManager;
 import android.content.Context;
-import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.service.notification.Condition;
 import android.service.notification.IConditionListener;
+import android.service.notification.ZenModeConfig;
 import android.util.Log;
 import android.widget.CompoundButton;
 import android.widget.RadioButton;
@@ -33,6 +33,9 @@
 
 import com.android.settings.R;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class ZenModeConditionSelection extends RadioGroup {
     private static final String TAG = "ZenModeConditionSelection";
     private static final boolean DEBUG = true;
@@ -40,18 +43,24 @@
     private final INotificationManager mNoMan;
     private final H mHandler = new H();
     private final Context mContext;
+    private final List<Condition> mConditions;
+    private Condition mCondition;
 
     public ZenModeConditionSelection(Context context) {
         super(context);
         mContext = context;
+        mConditions = new ArrayList<Condition>();
         setLayoutTransition(new LayoutTransition());
         final int p = mContext.getResources().getDimensionPixelSize(R.dimen.content_margin_left);
         setPadding(p, p, p, 0);
         mNoMan = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
         final RadioButton b = newRadioButton(null);
-        b.setText(R.string.zen_mode_default_option);
+        b.setText(mContext.getString(com.android.internal.R.string.zen_mode_forever));
         b.setChecked(true);
+        for (int i = ZenModeConfig.MINUTE_BUCKETS.length - 1; i >= 0; --i) {
+            handleCondition(ZenModeConfig.toTimeCondition(ZenModeConfig.MINUTE_BUCKETS[i]));
+        }
     }
 
     private RadioButton newRadioButton(Condition condition) {
@@ -61,7 +70,7 @@
             @Override
             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                 if (isChecked) {
-                    handleSubscribe((Condition) button.getTag());
+                    setCondition((Condition) button.getTag());
                 }
             }
         });
@@ -91,24 +100,35 @@
     }
 
     protected void handleConditions(Condition[] conditions) {
-        for (final Condition c : conditions) {
-            RadioButton v = (RadioButton) findViewWithTag(c.id);
-            if (c.state == Condition.STATE_TRUE || c.state == Condition.STATE_UNKNOWN) {
-                if (v == null) {
-                    v = newRadioButton(c);
-                }
-            }
-            if (v != null) {
-                v.setText(c.summary);
-                v.setEnabled(c.state == Condition.STATE_TRUE);
-            }
+        for (Condition c : conditions) {
+            handleCondition(c);
         }
     }
 
-    protected void handleSubscribe(Condition c) {
-        if (DEBUG) Log.d(TAG, "handleSubscribe " + c);
+    protected void handleCondition(Condition c) {
+        if (mConditions.contains(c)) return;
+        RadioButton v = (RadioButton) findViewWithTag(c.id);
+        if (c.state == Condition.STATE_TRUE || c.state == Condition.STATE_UNKNOWN) {
+            if (v == null) {
+                v = newRadioButton(c);
+            }
+        }
+        if (v != null) {
+            v.setText(c.summary);
+            v.setEnabled(c.state == Condition.STATE_TRUE);
+        }
+        mConditions.add(c);
+    }
+
+    protected void setCondition(Condition c) {
+        if (DEBUG) Log.d(TAG, "setCondition " + c);
+        mCondition = c;
+    }
+
+    public void confirmCondition() {
+        if (DEBUG) Log.d(TAG, "confirmCondition " + mCondition);
         try {
-            mNoMan.setZenModeCondition(c);
+            mNoMan.setZenModeCondition(mCondition);
         } catch (RemoteException e) {
             // noop
         }
@@ -127,7 +147,7 @@
 
         @Override
         public void handleMessage(Message msg) {
-            if (msg.what == CONDITIONS) handleConditions((Condition[])msg.obj);
+            if (msg.what == CONDITIONS) handleConditions((Condition[]) msg.obj);
         }
     }
 }
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index 9ea3c93..091e121 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -46,11 +46,13 @@
 import android.text.format.DateFormat;
 import android.util.Log;
 import android.util.SparseArray;
+import android.widget.ScrollView;
 import android.widget.TimePicker;
 
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.Utils;
+import com.android.settings.notification.DropDownPreference.Callback;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
 import com.android.settings.search.SearchIndexableRaw;
@@ -81,9 +83,10 @@
     private static final String KEY_ENTRY = "entry";
     private static final String KEY_CONDITION_PROVIDERS = "manage_condition_providers";
 
-    private static final SettingPref PREF_ZEN_MODE = new SettingPref(SettingPref.TYPE_GLOBAL,
-            KEY_ZEN_MODE, Global.ZEN_MODE, Global.ZEN_MODE_OFF, Global.ZEN_MODE_OFF,
-            Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, Global.ZEN_MODE_NO_INTERRUPTIONS) {
+    private static final SettingPrefWithCallback PREF_ZEN_MODE = new SettingPrefWithCallback(
+            SettingPref.TYPE_GLOBAL, KEY_ZEN_MODE, Global.ZEN_MODE, Global.ZEN_MODE_OFF,
+            Global.ZEN_MODE_OFF, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+            Global.ZEN_MODE_NO_INTERRUPTIONS) {
         protected String getCaption(Resources res, int value) {
             switch (value) {
                 case Global.ZEN_MODE_NO_INTERRUPTIONS:
@@ -135,6 +138,7 @@
     private PreferenceCategory mAutomationCategory;
     private Preference mEntry;
     private Preference mConditionProviders;
+    private AlertDialog mDialog;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -149,6 +153,14 @@
         if (DEBUG) Log.d(TAG, "Loaded mConfig=" + mConfig);
 
         final Preference zenMode = PREF_ZEN_MODE.init(this);
+        PREF_ZEN_MODE.setCallback(new SettingPrefWithCallback.Callback() {
+            @Override
+            public void onSettingSelected(int value) {
+                if (value != Global.ZEN_MODE_OFF) {
+                    showConditionSelection(value);
+                }
+            }
+        });
         if (!Utils.isVoiceCapable(mContext)) {
             zenMode.setTitle(R.string.zen_mode_option_title_novoice);
         }
@@ -190,7 +202,6 @@
         });
 
         mStarred = (DropDownPreference) important.findPreference(KEY_STARRED);
-        mStarred.setDropDownWidth(R.dimen.zen_mode_dropdown_width);
         mStarred.addItem(R.string.zen_mode_from_anyone, ZenModeConfig.SOURCE_ANYONE);
         mStarred.addItem(R.string.zen_mode_from_starred, ZenModeConfig.SOURCE_STAR);
         mStarred.addItem(R.string.zen_mode_from_contacts, ZenModeConfig.SOURCE_CONTACT);
@@ -467,8 +478,44 @@
         Global.putInt(getContentResolver(), Global.ZEN_MODE, value);
     }
 
-    protected ZenModeConditionSelection newConditionSelection() {
-        return new ZenModeConditionSelection(mContext);
+    protected void showConditionSelection(final int newSettingsValue) {
+        if (mDialog != null) return;
+
+        final ZenModeConditionSelection zenModeConditionSelection =
+                new ZenModeConditionSelection(mContext);
+        DialogInterface.OnClickListener positiveListener = new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                zenModeConditionSelection.confirmCondition();
+                mDialog = null;
+            }
+        };
+        final int oldSettingsValue = PREF_ZEN_MODE.getValue(mContext);
+        ScrollView scrollView = new ScrollView(mContext);
+        scrollView.addView(zenModeConditionSelection);
+        mDialog = new AlertDialog.Builder(getActivity())
+                .setTitle(PREF_ZEN_MODE.getCaption(getResources(), newSettingsValue))
+                .setView(scrollView)
+                .setPositiveButton(R.string.okay, positiveListener)
+                .setNegativeButton(R.string.cancel_all_caps, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        cancelDialog(oldSettingsValue);
+                    }
+                })
+                .setOnCancelListener(new DialogInterface.OnCancelListener() {
+                    @Override
+                    public void onCancel(DialogInterface dialog) {
+                        cancelDialog(oldSettingsValue);
+                    }
+                }).create();
+        mDialog.show();
+    }
+
+    protected void cancelDialog(int oldSettingsValue) {
+        // If not making a decision, reset drop down to current setting.
+        PREF_ZEN_MODE.setValueWithoutCallback(mContext, oldSettingsValue);
+        mDialog = null;
     }
 
     // Enable indexing of searchable data
@@ -499,6 +546,60 @@
             }
         };
 
+    private static class SettingPrefWithCallback extends SettingPref {
+
+        private Callback mCallback;
+        private int mValue;
+
+        public SettingPrefWithCallback(int type, String key, String setting, int def,
+                int... values) {
+            super(type, key, setting, def, values);
+        }
+
+        public void setCallback(Callback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void update(Context context) {
+            // Avoid callbacks from non-user changes.
+            mValue = getValue(context);
+            super.update(context);
+        }
+
+        @Override
+        protected boolean setSetting(Context context, int value) {
+            if (value == mValue) return true;
+            mValue = value;
+            if (mCallback != null) {
+                mCallback.onSettingSelected(value);
+            }
+            return super.setSetting(context, value);
+        }
+
+        @Override
+        public Preference init(SettingsPreferenceFragment settings) {
+            Preference ret = super.init(settings);
+            mValue = getValue(settings.getActivity());
+
+            return ret;
+        }
+
+        public boolean setValueWithoutCallback(Context context, int value) {
+            // Set the current value ahead of time, this way we won't trigger a callback.
+            mValue = value;
+            return putInt(mType, context.getContentResolver(), mSetting, value);
+        }
+
+        public int getValue(Context context) {
+            return getInt(mType, context.getContentResolver(), mSetting, mDefault);
+        }
+
+        public interface Callback {
+            void onSettingSelected(int value);
+        }
+    }
+
     private final class SettingsObserver extends ContentObserver {
         private final Uri ZEN_MODE_URI = Global.getUriFor(Global.ZEN_MODE);
         private final Uri ZEN_MODE_CONFIG_ETAG_URI = Global.getUriFor(Global.ZEN_MODE_CONFIG_ETAG);