Build out the SettingsManager model.

Change-Id: Ie831dbf624efc5c7e27924785a0ec193b3ce53bd
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index 37a8bd6..7884440 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -97,6 +97,9 @@
 import com.android.camera.filmstrip.FilmstripListener;
 import com.android.camera.module.ModuleController;
 import com.android.camera.module.ModulesInfo;
+import com.android.camera.settings.SettingsManager;
+import com.android.camera.settings.SettingsManager.SettingsCapabilities;
+import com.android.camera.settings.SettingsManager.StartupModuleSetting;
 import com.android.camera.tinyplanet.TinyPlanetFragment;
 import com.android.camera.ui.CameraControls;
 import com.android.camera.ui.DetailsDialog;
@@ -113,6 +116,7 @@
 import com.android.camera2.R;
 
 import java.io.File;
+import java.util.List;
 
 public class CameraActivity extends Activity
         implements AppController, CameraManager.CameraOpenCallback,
@@ -175,6 +179,7 @@
     private LocalDataAdapter mWrappedDataAdapter;
 
     private SettingsManager mSettingsManager;
+    private SettingsController mSettingsController;
     private PanoramaStitchingManager mPanoramaManager;
     private PlaceholderManager mPlaceholderManager;
     private ModeListView mModeListView;
@@ -247,6 +252,9 @@
                     "requesting");
         }
         if (mCurrentModule2 != null) {
+            SettingsCapabilities capabilities =
+                SettingsController.getSettingsCapabilities(camera);
+            mSettingsManager.changeCamera(camera.getCameraId(), capabilities);
             mCurrentModule2.onCameraAvailable(camera);
         }
     }
@@ -1162,35 +1170,7 @@
                 mCameraModuleRootView,
                 isSecureCamera(), isCaptureIntent());
 
-        int modeIndex = -1;
-        if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
-                || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
-            modeIndex = ModeListView.MODE_VIDEO;
-        } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
-                || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
-                        .getAction())) {
-            modeIndex = ModeListView.MODE_PHOTO;
-            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-            if (prefs.getInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, -1)
-                        == ModeListView.MODE_GCAM && GcamHelper.hasGcamCapture()) {
-                modeIndex = ModeListView.MODE_GCAM;
-            }
-        } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
-                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
-            modeIndex = ModeListView.MODE_PHOTO;
-        } else {
-            // If the activity has not been started using an explicit intent,
-            // read the module index from the last time the user changed modes
-            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-            modeIndex = prefs.getInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, -1);
-            if ((modeIndex == ModeListView.MODE_GCAM &&
-                    !GcamHelper.hasGcamCapture()) || modeIndex < 0) {
-                modeIndex = ModeListView.MODE_PHOTO;
-            }
-        }
-
-        mOrientationManager = new OrientationManagerImpl(this);
-        mOrientationManager.addOnOrientationChangeListener(mMainHandler, this);
+        mSettingsManager = new SettingsManager(this, null, mCameraController.getNumberOfCameras());
 
         mLocationManager = new LocationManager(this,
             new LocationManager.Listener() {
@@ -1203,7 +1183,35 @@
                 }
             });
 
-        mSettingsManager = new SettingsManager(this);
+        mSettingsController = new SettingsController(this, mSettingsManager, mLocationManager);
+
+        int modeIndex = -1;
+        if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
+                || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
+            modeIndex = ModeListView.MODE_VIDEO;
+        } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
+                || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
+                        .getAction())) {
+            modeIndex = ModeListView.MODE_PHOTO;
+            if (mSettingsManager.getInt(new StartupModuleSetting())
+                        == ModeListView.MODE_GCAM && GcamHelper.hasGcamCapture()) {
+                modeIndex = ModeListView.MODE_GCAM;
+            }
+        } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
+                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
+            modeIndex = ModeListView.MODE_PHOTO;
+        } else {
+            // If the activity has not been started using an explicit intent,
+            // read the module index from the last time the user changed modes
+            modeIndex = mSettingsManager.getInt(new StartupModuleSetting());
+            if ((modeIndex == ModeListView.MODE_GCAM &&
+                    !GcamHelper.hasGcamCapture()) || modeIndex < 0) {
+                modeIndex = ModeListView.MODE_PHOTO;
+            }
+        }
+
+        mOrientationManager = new OrientationManagerImpl(this);
+        mOrientationManager.addOnOrientationChangeListener(mMainHandler, this);
 
         setModuleFromModeIndex(modeIndex);
 
@@ -1551,8 +1559,7 @@
         LayoutInflater inflater = getLayoutInflater();
         SettingsView settingsView = (SettingsView) inflater.inflate(R.layout.settings_list_layout,
             null, false);
-        settingsView.setSettingsListener(new SettingsController(this, mSettingsManager));
-
+        settingsView.setSettingsListener(mSettingsController);
         PopupWindow popup = new PopupWindow(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
         popup.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
         popup.setOutsideTouchable(true);
@@ -1588,6 +1595,11 @@
         return (CameraServices) getApplication();
     }
 
+    @Override
+    public SettingsController getSettingsController() {
+        return mSettingsController;
+    }
+
     /**
      * Launches an ACTION_EDIT intent for the given local data item.
      */
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index 55867a1..4142ba2 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -28,6 +28,8 @@
 import android.media.CamcorderProfile;
 import android.util.Log;
 
+import com.android.camera.settings.SettingsManager;
+import com.android.camera.settings.SettingsManager.PictureSizeSetting;
 import com.android.camera.util.ApiHelper;
 import com.android.camera.util.CameraUtil;
 import com.android.camera.util.GcamHelper;
@@ -78,13 +80,15 @@
     private final Parameters mParameters;
     private final CameraInfo[] mCameraInfo;
     private final int mCameraId;
+    private final SettingsManager mSettingsManager;
 
-    public CameraSettings(Activity activity, Parameters parameters,
+    public CameraSettings(CameraActivity activity, Parameters parameters,
                           int cameraId, CameraInfo[] cameraInfo) {
-        mContext = activity;
+        mContext = (Context) activity;
         mParameters = parameters;
         mCameraId = cameraId;
         mCameraInfo = cameraInfo;
+        mSettingsManager = activity.getSettingsManager();
     }
 
     public PreferenceGroup getPreferenceGroup(int preferenceRes) {
@@ -107,8 +111,9 @@
         return supported.get(0);
     }
 
+    // TODO: move this logic into the settings manager utilities.
     public static void initialCameraPictureSize(
-            Context context, Parameters parameters) {
+            Context context, Parameters parameters, SettingsManager settingsManager) {
         // When launching the camera app first time, we will set the picture
         // size to the first one in the list defined in "arrays.xml" and is also
         // supported by the driver.
@@ -117,10 +122,7 @@
         for (String candidate : context.getResources().getStringArray(
                 R.array.pref_camera_picturesize_entryvalues)) {
             if (setCameraPictureSize(candidate, supported, parameters)) {
-                SharedPreferences.Editor editor = ComboPreferences
-                        .get(context).edit();
-                editor.putString(KEY_PICTURE_SIZE, candidate);
-                editor.apply();
+                settingsManager.set(new PictureSizeSetting(), candidate);
                 return;
             }
         }
@@ -301,6 +303,9 @@
 
     private void filterUnsupportedOptions(PreferenceGroup group,
             ListPreference pref, List<String> supported) {
+        if (pref == null) {
+            return;
+        }
 
         // Remove the preference if the parameter is not supported or there is
         // only one options for the settings.
@@ -330,9 +335,9 @@
 
     private void resetIfInvalid(ListPreference pref) {
         // Set the value to the first entry if it is invalid.
-        String value = pref.getValue();
+        String value = mSettingsManager.getValueFromPreference(pref);
         if (pref.findIndexOfValue(value) == NOT_FOUND) {
-            pref.setValueIndex(0);
+            mSettingsManager.setValueIndexFromPreference(pref, 0);
         }
     }
 
@@ -451,40 +456,6 @@
         return 0;
     }
 
-    public static void restorePreferences(Context context,
-            ComboPreferences preferences, Parameters parameters) {
-        int currentCameraId = readPreferredCameraId(preferences);
-
-        // Clear the preferences of both cameras.
-        int backCameraId = CameraHolder.instance().getBackCameraId();
-        if (backCameraId != -1) {
-            preferences.setLocalId(context, backCameraId);
-            Editor editor = preferences.edit();
-            editor.clear();
-            editor.apply();
-        }
-        int frontCameraId = CameraHolder.instance().getFrontCameraId();
-        if (frontCameraId != -1) {
-            preferences.setLocalId(context, frontCameraId);
-            Editor editor = preferences.edit();
-            editor.clear();
-            editor.apply();
-        }
-
-        // Switch back to the preferences of the current camera. Otherwise,
-        // we may write the preference to wrong camera later.
-        preferences.setLocalId(context, currentCameraId);
-
-        upgradeGlobalPreferences(preferences.getGlobal());
-        upgradeLocalPreferences(preferences.getLocal());
-
-        // Write back the current camera id because parameters are related to
-        // the camera. Otherwise, we may switch to the front camera but the
-        // initial picture size is that of the back camera.
-        initialCameraPictureSize(context, parameters);
-        writePreferredCameraId(preferences, currentCameraId);
-    }
-
     private static ArrayList<String> getSupportedVideoQuality(int cameraId) {
         ArrayList<String> supported = new ArrayList<String>();
         // Check for supported quality
diff --git a/src/com/android/camera/FocusOverlayManager.java b/src/com/android/camera/FocusOverlayManager.java
index f382a2a..5214085 100644
--- a/src/com/android/camera/FocusOverlayManager.java
+++ b/src/com/android/camera/FocusOverlayManager.java
@@ -28,6 +28,8 @@
 import android.os.Message;
 import android.util.Log;
 
+import com.android.camera.settings.SettingsManager;
+import com.android.camera.settings.SettingsManager.FocusModeSetting;
 import com.android.camera.util.CameraUtil;
 import com.android.camera.util.UsageStatistics;
 
@@ -85,7 +87,7 @@
     private String[] mDefaultFocusModes;
     private String mOverrideFocusMode;
     private Parameters mParameters;
-    private ComboPreferences mPreferences;
+    private SettingsManager mSettingsManager;
     private Handler mHandler;
     Listener mListener;
     private boolean mPreviousMoving;
@@ -131,12 +133,13 @@
         }
     }
 
-    public FocusOverlayManager(ComboPreferences preferences, String[] defaultFocusModes,
+    public FocusOverlayManager(SettingsManager settingsManager,
+            String[] defaultFocusModes,
             Parameters parameters, Listener listener,
             boolean mirror, Looper looper, FocusUI ui) {
+        mSettingsManager = settingsManager;
         mHandler = new MainHandler(looper);
         mMatrix = new Matrix();
-        mPreferences = preferences;
         mDefaultFocusModes = defaultFocusModes;
         setParameters(parameters);
         mListener = listener;
@@ -452,8 +455,7 @@
             mFocusMode = Parameters.FOCUS_MODE_AUTO;
         } else {
             // The default is continuous autofocus.
-            mFocusMode = mPreferences.getString(
-                    CameraSettings.KEY_FOCUS_MODE, null);
+            mFocusMode = mSettingsManager.get(new FocusModeSetting());
 
             // Try to find a supported focus mode from the default list.
             if (mFocusMode == null) {
diff --git a/src/com/android/camera/ListPreference.java b/src/com/android/camera/ListPreference.java
index 909b32c..6b12b9e 100644
--- a/src/com/android/camera/ListPreference.java
+++ b/src/com/android/camera/ListPreference.java
@@ -26,6 +26,7 @@
 import android.util.Log;
 import android.util.TypedValue;
 
+import com.android.camera.settings.SettingsManager;
 import com.android.camera.util.CameraUtil;
 import com.android.camera.util.UsageStatistics;
 import com.android.camera2.R;
@@ -80,6 +81,10 @@
         return mKey;
     }
 
+    public String getDefault() {
+        return findSupportedDefaultValue();
+    }
+
     public CharSequence[] getEntries() {
         return mEntries;
     }
@@ -106,8 +111,17 @@
 
     public String getValue() {
         if (!mLoaded) {
-            mValue = getSharedPreferences().getString(mKey,
+            SharedPreferences preferences = getSharedPreferences();
+            if (preferences == null) {
+                // TEMP
+                // This module doesn't use ComboPreferences.
+                // Check this value and use the global settings
+                // manager instead.
+                return mValue;
+            } else {
+                mValue = preferences.getString(mKey,
                     findSupportedDefaultValue());
+            }
             mLoaded = true;
         }
         return mValue;
@@ -127,14 +141,18 @@
         return null;
     }
 
-    public void setValue(String value) {
+    public boolean setValue(String value) {
         if (findIndexOfValue(value) < 0) throw new IllegalArgumentException();
         mValue = value;
-        persistStringValue(value);
+        return persistStringValue(value);
     }
 
-    public void setValueIndex(int index) {
-        setValue(mEntryValues[index].toString());
+    public boolean setValueIndex(int index) {
+        return setValue(mEntryValues[index].toString());
+    }
+
+    public String getValueAtIndex(int index) {
+        return mEntryValues[index].toString();
     }
 
     public int findIndexOfValue(String value) {
@@ -156,11 +174,16 @@
         return mLabels[findIndexOfValue(getValue())].toString();
     }
 
-    protected void persistStringValue(String value) {
-        SharedPreferences.Editor editor = getSharedPreferences().edit();
+    protected boolean persistStringValue(String value) {
+        SharedPreferences preferences = getSharedPreferences();
+        if (preferences == null) {
+            return false;
+        }
+        SharedPreferences.Editor editor = preferences.edit();
         editor.putString(mKey, value);
         editor.apply();
         UsageStatistics.onEvent("CameraSettingsChange", value, mKey);
+        return true;
     }
 
     @Override
diff --git a/src/com/android/camera/PhotoController.java b/src/com/android/camera/PhotoController.java
index 833c825..aa43140 100644
--- a/src/com/android/camera/PhotoController.java
+++ b/src/com/android/camera/PhotoController.java
@@ -59,8 +59,6 @@
 
     public void updateCameraOrientation();
 
-    public void enableRecordingLocation(boolean enable);
-
     /**
      * This is the callback when the UI or buffer holder for camera preview,
      * such as {@link android.graphics.SurfaceTexture}, is ready to be used.
diff --git a/src/com/android/camera/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java
index 08ce337..a867721 100644
--- a/src/com/android/camera/PhotoMenu.java
+++ b/src/com/android/camera/PhotoMenu.java
@@ -21,6 +21,7 @@
 import android.content.res.Resources;
 import android.hardware.Camera.Parameters;
 
+import com.android.camera.settings.SettingsManager;
 import com.android.camera.ui.AbstractSettingPopup;
 import com.android.camera.ui.CountdownTimerPopup;
 import com.android.camera.ui.ListPrefSettingPopup;
@@ -94,10 +95,13 @@
                     ListPreference pref = mPreferenceGroup
                             .findPreference(CameraSettings.KEY_CAMERA_ID);
                     if (pref != null) {
-                        int index = pref.findIndexOfValue(pref.getValue());
+                        SettingsManager settingsManager = mActivity.getSettingsManager();
+                        String value = settingsManager.getValueFromPreference(pref);
+                        int index = pref.findIndexOfValue(value);
+
                         CharSequence[] values = pref.getEntryValues();
                         index = (index + 1) % values.length;
-                        pref.setValueIndex(index);
+                        settingsManager.setValueIndexFromPreference(pref, index);
                         mListener.onCameraPickerClicked(index);
                     }
                     updateItem(fitem, CameraSettings.KEY_CAMERA_ID);
@@ -105,15 +109,6 @@
             });
             mRenderer.addItem(item);
         }
-        // Location.
-        if (group.findPreference(CameraSettings.KEY_RECORD_LOCATION) != null) {
-            item = makeSwitchItem(CameraSettings.KEY_RECORD_LOCATION, true);
-            more.addItem(item);
-            if (mActivity.isSecureCamera()) {
-                // Prevent location preference from getting changed in secure camera mode
-                item.setEnabled(false);
-            }
-        }
         // Countdown timer.
         final ListPreference ctpref = group.findPreference(CameraSettings.KEY_TIMER);
         final ListPreference beeppref = group.findPreference(CameraSettings.KEY_TIMER_SOUND_EFFECTS);
@@ -132,23 +127,6 @@
             }
         });
         more.addItem(item);
-        // Image size.
-        item = makeItem(R.drawable.ic_imagesize);
-        final ListPreference sizePref = group.findPreference(CameraSettings.KEY_PICTURE_SIZE);
-        item.setLabel(res.getString(R.string.pref_camera_picturesize_title).toUpperCase(locale));
-        item.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(PieItem item) {
-                ListPrefSettingPopup popup = (ListPrefSettingPopup) mActivity.getLayoutInflater().inflate(
-                        R.layout.list_pref_setting_popup, null, false);
-                popup.initialize(sizePref);
-                popup.setSettingChangedListener(PhotoMenu.this);
-                mUI.dismissPopup();
-                mPopup = popup;
-                mUI.showPopup(mPopup);
-            }
-        });
-        more.addItem(item);
         // White balance.
         if (group.findPreference(CameraSettings.KEY_WHITE_BALANCE) != null) {
             item = makeItem(CameraSettings.KEY_WHITE_BALANCE);
@@ -181,14 +159,18 @@
     }
 
     // Return true if the preference has the specified key but not the value.
-    private static boolean notSame(ListPreference pref, String key, String value) {
-        return (key.equals(pref.getKey()) && !value.equals(pref.getValue()));
+    private boolean notSame(ListPreference pref, String key, String value) {
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+        String prefValue = settingsManager.getValueFromPreference(pref);
+        return (key.equals(pref.getKey()) && !value.equals(prefValue));
     }
 
     private void setPreference(String key, String value) {
         ListPreference pref = mPreferenceGroup.findPreference(key);
-        if (pref != null && !value.equals(pref.getValue())) {
-            pref.setValue(value);
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+        String prefValue = settingsManager.getValueFromPreference(pref);
+        if (pref != null && !value.equals(prefValue)) {
+            settingsManager.setValueFromPreference(pref, value);
             reloadPreferences();
         }
     }
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 69706cc..03711ea 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -22,7 +22,9 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
@@ -64,6 +66,21 @@
 import com.android.camera.exif.ExifTag;
 import com.android.camera.exif.Rational;
 import com.android.camera.module.ModuleController;
+import com.android.camera.settings.SettingsManager;
+import com.android.camera.settings.SettingsManager.DefaultCameraIdSetting;
+import com.android.camera.settings.SettingsManager.ExposureSetting;
+import com.android.camera.settings.SettingsManager.FlashSetting;
+import com.android.camera.settings.SettingsManager.FocusModeSetting;
+import com.android.camera.settings.SettingsManager.HintSetting;
+import com.android.camera.settings.SettingsManager.HdrSetting;
+import com.android.camera.settings.SettingsManager.HdrPlusSetting;
+import com.android.camera.settings.SettingsManager.LocationSetting;
+import com.android.camera.settings.SettingsManager.PictureSizeSetting;
+import com.android.camera.settings.SettingsManager.SettingsListener;
+import com.android.camera.settings.SettingsManager.TimerSetting;
+import com.android.camera.settings.SettingsManager.TimerSoundSetting;
+import com.android.camera.settings.SettingsManager.SceneModeSetting;
+import com.android.camera.settings.SettingsManager.WhiteBalanceSetting;
 import com.android.camera.ui.CountDownView.OnCountDownFinishedListener;
 import com.android.camera.ui.ModeListView;
 import com.android.camera.ui.RotateTextToast;
@@ -153,7 +170,6 @@
 
     // The degrees of the device rotated clockwise from its natural orientation.
     private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
-    private ComboPreferences mPreferences;
 
     private static final String sTempCropFilename = "crop-temp";
 
@@ -206,7 +222,6 @@
     private ContentResolver mContentResolver;
 
     private LocationManager mLocationManager;
-    private SettingsManager mSettingsManager;
 
     private final PostViewPictureCallback mPostViewPictureCallback =
             new PostViewPictureCallback();
@@ -371,25 +386,19 @@
     public void init(CameraActivity activity, View parent) {
         mActivity = activity;
         mUI = new PhotoUI(activity, this, parent);
-        mPreferences = new ComboPreferences(mActivity);
-        CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
-        mCameraId = getPreferredCameraId(mPreferences);
+
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+        mCameraId = Integer.parseInt(settingsManager.get(
+            new DefaultCameraIdSetting()));
 
         mContentResolver = mActivity.getContentResolver();
-        mSettingsManager = mActivity.getSettingsManager();
 
         // Surface texture is from camera screen nail and startPreview needs it.
         // This must be done before startPreview.
         mIsImageCaptureIntent = isImageCaptureIntent();
 
-        mPreferences.setLocalId(mActivity, mCameraId);
-        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
-
         mActivity.getCameraProvider().requestCamera(mCameraId);
 
-        // we need to reset exposure for the preview
-        resetExposureCompensation();
-
         initializeControlByIntent();
         mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
         mLocationManager = mActivity.getLocationManager();
@@ -412,7 +421,8 @@
     // Prompt the user to pick to record location for the very first run of
     // camera only
     private void locationFirstRun() {
-        if (RecordLocationPreference.isSet(mPreferences)) {
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+        if (settingsManager.isSet(new LocationSetting())) {
             return;
         }
         if (mActivity.isSecureCamera()) return;
@@ -426,12 +436,6 @@
     }
 
     @Override
-    public void enableRecordingLocation(boolean enable) {
-        setLocationPreference(enable ? RecordLocationPreference.VALUE_ON
-                : RecordLocationPreference.VALUE_OFF);
-    }
-
-    @Override
     public void onPreviewUIReady() {
         startPreview();
     }
@@ -445,15 +449,6 @@
         stopPreview();
     }
 
-    private void setLocationPreference(String value) {
-        mPreferences.edit()
-                .putString(CameraSettings.KEY_RECORD_LOCATION, value)
-                .apply();
-        // TODO: Fix this to use the actual onSharedPreferencesChanged listener
-        // instead of invoking manually
-        onSharedPreferenceChanged();
-    }
-
     private void onCameraOpened() {
         View root = mUI.getRootView();
         // These depend on camera parameters.
@@ -466,20 +461,20 @@
 
     private void switchCamera() {
         if (mPaused) return;
+        SettingsManager settingsManager = mActivity.getSettingsManager();
 
         Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
         mCameraId = mPendingSwitchCameraId;
         mPendingSwitchCameraId = -1;
-        setCameraId(mCameraId);
+        settingsManager.set(new DefaultCameraIdSetting(),
+            "" + mCameraId);
         mActivity.getCameraProvider().requestCamera(mCameraId);
 
         mUI.collapseCameraControls();
         mUI.clearFaces();
         if (mFocusManager != null) mFocusManager.removeMessages();
 
-        // Restart the camera and initialize the UI. From onCreate.
-        mPreferences.setLocalId(mActivity, mCameraId);
-        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
+        // TODO: this needs to be brought into onCameraAvailable();
         CameraInfo info = mActivity.getCameraProvider().getCameraInfo()[mCameraId];
         mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
         mFocusManager.setMirror(mMirror);
@@ -488,16 +483,12 @@
         mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
     }
 
-    protected void setCameraId(int cameraId) {
-        ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
-        pref.setValue("" + cameraId);
-    }
-
     // either open a new camera or switch cameras
     private void openCameraCommon() {
-        loadCameraPreferences();
+        mPreferenceGroup = loadPreferenceGroup();
 
-        mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this);
+        // TODO: remove dependency on PreferenceGroup
+        mUI.onCameraOpened(mPreferenceGroup, mParameters, this);
         if (mIsImageCaptureIntent) {
             mUI.overrideSettings(CameraSettings.KEY_CAMERA_HDR_PLUS,
                     mActivity.getString(R.string.setting_off_value));
@@ -512,13 +503,12 @@
     }
 
     private void resetExposureCompensation() {
-        String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE,
-                CameraSettings.EXPOSURE_DEFAULT_VALUE);
-        if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) {
-            Editor editor = mPreferences.edit();
-            editor.putString(CameraSettings.KEY_EXPOSURE, "0");
-            editor.apply();
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+        if (settingsManager == null) {
+            Log.e(TAG, "Settings manager is null!");
+            return;
         }
+        settingsManager.setDefault(new ExposureSetting());
     }
 
     private void keepMediaProviderInstance() {
@@ -540,9 +530,8 @@
         }
 
         // Initialize location service.
-        boolean recordLocation = RecordLocationPreference.get(
-                mPreferences, mContentResolver);
-        mLocationManager.recordLocation(recordLocation);
+        SettingsController settingsController = mActivity.getSettingsController();
+        settingsController.syncLocationManager();
 
         keepMediaProviderInstance();
 
@@ -566,9 +555,9 @@
     // onResume.
     private void initializeSecondTime() {
         // Start location update if needed.
-        boolean recordLocation = RecordLocationPreference.get(
-                mPreferences, mContentResolver);
-        mLocationManager.recordLocation(recordLocation);
+        SettingsController settingsController = mActivity.getSettingsController();
+        settingsController.syncLocationManager();
+
         MediaSaver s = getServices().getMediaSaver();
         if (s != null) {
             s.setQueueListener(this);
@@ -580,8 +569,10 @@
 
     private void showTapToFocusToastIfNeeded() {
         // Show the tap to focus toast if this is the first start.
-        if (mFocusAreaSupported &&
-                mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) {
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+        boolean showHint = settingsManager.getBoolean(new HintSetting());
+        // CONVERT THIS SETTING TO A STRING
+        if (mFocusAreaSupported && showHint) {
             // Delay the toast for one second to wait for orientation.
             mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000);
         }
@@ -922,17 +913,6 @@
         setCameraParameters(UPDATE_PARAM_PREFERENCE);
     }
 
-    private int getPreferredCameraId(ComboPreferences preferences) {
-        int intentCameraId = CameraUtil.getCameraFacingIntentExtras(mActivity);
-        if (intentCameraId != -1) {
-            // Testing purpose. Launch a specific camera through the intent
-            // extras.
-            return intentCameraId;
-        } else {
-            return CameraSettings.readPreferredCameraId(preferences);
-        }
-    }
-
     private void updateSceneMode() {
         // If scene mode is set, we cannot set flash mode, white balance, and
         // focus mode, instead, we read it from driver
@@ -952,10 +932,10 @@
                 CameraSettings.KEY_FOCUS_MODE, focusMode);
     }
 
-    private void loadCameraPreferences() {
+    private PreferenceGroup loadPreferenceGroup() {
         CameraSettings settings = new CameraSettings(mActivity, mInitialParams,
-                mCameraId, CameraHolder.instance().getCameraInfo());
-        mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences);
+            mCameraId, CameraHolder.instance().getCameraInfo());
+        return settings.getPreferenceGroup(R.xml.camera_preferences);
     }
 
     @Override
@@ -980,6 +960,7 @@
         }
         mCameraDevice = cameraProxy;
 
+        resetExposureCompensation();
         initializeCapabilities();
 
         // Reset zoom value index.
@@ -1150,13 +1131,9 @@
             return;
         }
 
-        String timer = mPreferences.getString(
-                CameraSettings.KEY_TIMER,
-                mActivity.getString(R.string.pref_camera_timer_default));
-        boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS,
-                mActivity.getString(R.string.pref_camera_timer_sound_default))
-                .equals(mActivity.getString(R.string.setting_on_value));
-
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+        String timer = settingsManager.get(new TimerSetting());
+        String playSound = settingsManager.get(new TimerSoundSetting());
         int seconds = Integer.parseInt(timer);
         // When shutter button is pressed, check whether the previous countdown is
         // finished. If not, cancel the previous countdown and start a new one.
@@ -1164,7 +1141,7 @@
             mUI.cancelCountDown();
         }
         if (seconds > 0) {
-            mUI.startCountDown(seconds, playSound);
+            mUI.startCountDown(seconds, playSound.equals(SettingsManager.VALUE_ON));
         } else {
             mSnapshotOnIdle = false;
             mFocusManager.doSnap();
@@ -1189,7 +1166,6 @@
 
         mJpegPictureCallbackTime = 0;
         mZoomValue = 0;
-        resetExposureCompensation();
 
         mOnResumeTime = SystemClock.uptimeMillis();
         checkDisplayRotation();
@@ -1233,7 +1209,8 @@
             mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
             String[] defaultFocusModes = mActivity.getResources().getStringArray(
                     R.array.pref_camera_focusmode_default_array);
-            mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes,
+            mFocusManager = new FocusOverlayManager(mActivity.getSettingsManager(),
+                    defaultFocusModes,
                     mInitialParams, this, mMirror,
                     mActivity.getMainLooper(), mUI);
         }
@@ -1533,7 +1510,8 @@
         if (!mSnapshotOnIdle) {
             // If the focus mode is continuous autofocus, call cancelAutoFocus to
             // resume it because it may have been paused by autoFocus call.
-            if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
+            String focusMode = mFocusManager.getFocusMode();
+            if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
                 mCameraDevice.cancelAutoFocus();
             }
             mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
@@ -1619,16 +1597,20 @@
     }
 
     private boolean updateCameraParametersPreference() {
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+
         setAutoExposureLockIfSupported();
         setAutoWhiteBalanceLockIfSupported();
         setFocusAreasIfSupported();
         setMeteringAreasIfSupported();
 
         // Set picture size.
-        String pictureSize = mPreferences.getString(
-                CameraSettings.KEY_PICTURE_SIZE, null);
+        String pictureSize = settingsManager.get(
+            new PictureSizeSetting());
         if (pictureSize == null) {
-            CameraSettings.initialCameraPictureSize(mActivity, mParameters);
+            //TODO: deprecate CameraSettings.
+            CameraSettings.initialCameraPictureSize(
+                    mActivity, mParameters, settingsManager);
         } else {
             List<Size> supported = mParameters.getSupportedPictureSizes();
             CameraSettings.setCameraPictureSize(
@@ -1666,10 +1648,8 @@
         // first. HDR is a scene mode. To promote it in UI, it is stored in a
         // separate preference.
         String onValue = mActivity.getString(R.string.setting_on_value);
-        String hdr = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR,
-                mActivity.getString(R.string.pref_camera_hdr_default));
-        String hdrPlus = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR_PLUS,
-                mActivity.getString(R.string.pref_camera_hdr_plus_default));
+        String hdr = settingsManager.get(new HdrSetting());
+        String hdrPlus = settingsManager.get(new HdrPlusSetting());
         boolean hdrOn = onValue.equals(hdr);
         boolean hdrPlusOn = onValue.equals(hdrPlus);
 
@@ -1681,9 +1661,7 @@
             if (hdrOn) {
                 mSceneMode = CameraUtil.SCENE_MODE_HDR;
             } else {
-                mSceneMode = mPreferences.getString(
-                        CameraSettings.KEY_SCENE_MODE,
-                        mActivity.getString(R.string.pref_camera_scenemode_default));
+                mSceneMode = settingsManager.get(new SceneModeSetting());
             }
         }
         if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
@@ -1712,7 +1690,8 @@
         // still supported by latest driver, if not, ignore the settings.
 
         // Set exposure compensation
-        int value = CameraSettings.readExposure(mPreferences);
+        int value = Integer.parseInt(
+            settingsManager.get(new ExposureSetting()));
         int max = mParameters.getMaxExposureCompensation();
         int min = mParameters.getMinExposureCompensation();
         if (value >= min && value <= max) {
@@ -1723,9 +1702,7 @@
 
         if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
             // Set flash mode.
-            String flashMode = mPreferences.getString(
-                    CameraSettings.KEY_FLASH_MODE,
-                    mActivity.getString(R.string.pref_camera_flashmode_default));
+            String flashMode = settingsManager.get(new FlashSetting());
             List<String> supportedFlash = mParameters.getSupportedFlashModes();
             if (CameraUtil.isSupported(flashMode, supportedFlash)) {
                 mParameters.setFlashMode(flashMode);
@@ -1738,9 +1715,8 @@
             }
 
             // Set white balance parameter.
-            String whiteBalance = mPreferences.getString(
-                    CameraSettings.KEY_WHITE_BALANCE,
-                    mActivity.getString(R.string.pref_camera_whitebalance_default));
+            String whiteBalance = settingsManager.get(
+                new WhiteBalanceSetting());
             if (CameraUtil.isSupported(whiteBalance,
                     mParameters.getSupportedWhiteBalance())) {
                 mParameters.setWhiteBalance(whiteBalance);
@@ -1850,12 +1826,11 @@
         // ignore the events after "onPause()"
         if (mPaused) return;
 
-        boolean recordLocation = RecordLocationPreference.get(
-                mPreferences, mContentResolver);
-        mLocationManager.recordLocation(recordLocation);
+        SettingsController settingsController = mActivity.getSettingsController();
+        settingsController.syncLocationManager();
 
         setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
-        mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences);
+        mUI.updateOnScreenIndicators(mParameters);
     }
 
     @Override
@@ -1908,9 +1883,8 @@
         // TODO: Use a toast?
         new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
         // Clear the preference.
-        Editor editor = mPreferences.edit();
-        editor.putBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, false);
-        editor.apply();
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+        settingsManager.setBoolean(new HintSetting(), false);
     }
 
     private void initializeCapabilities() {
diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java
index c75e97b..ddb9ade 100644
--- a/src/com/android/camera/PhotoUI.java
+++ b/src/com/android/camera/PhotoUI.java
@@ -44,6 +44,10 @@
 import com.android.camera.CameraPreference.OnPreferenceChangedListener;
 import com.android.camera.FocusOverlayManager.FocusUI;
 import com.android.camera.app.CameraManager;
+import com.android.camera.settings.SettingsManager;
+import com.android.camera.settings.SettingsManager.ExposureSetting;
+import com.android.camera.settings.SettingsManager.LocationSetting;
+import com.android.camera.settings.SettingsManager.WhiteBalanceSetting;
 import com.android.camera.ui.AbstractSettingPopup;
 import com.android.camera.ui.CameraControls;
 import com.android.camera.ui.CameraRootView;
@@ -329,7 +333,7 @@
                 mRootView.findViewById(R.id.on_screen_indicators));
     }
 
-    public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs,
+    public void onCameraOpened(PreferenceGroup prefGroup,
             Camera.Parameters params, OnPreferenceChangedListener listener) {
         if (mPieRenderer == null) {
             mPieRenderer = new PieRenderer(mActivity);
@@ -341,6 +345,7 @@
             mMenu = new PhotoMenu(mActivity, this, mPieRenderer);
             mMenu.setListener(listener);
         }
+        // TODO: Refactor the prefGroup out of this.
         mMenu.initialize(prefGroup);
 
         if (mZoomRenderer == null) {
@@ -350,7 +355,7 @@
         mRenderOverlay.setGestures(null);
 
         initializeZoom(params);
-        updateOnScreenIndicators(params, prefGroup, prefs);
+        updateOnScreenIndicators(params);
     }
 
     public void animateCapture(final byte[] jpegData, int orientation, boolean mirror) {
@@ -443,12 +448,13 @@
         if (mController.isImageCaptureIntent()) {
             hidePostCaptureAlert();
         }
-        if (mMenu != null) {
-            mMenu.reloadPreferences();
-        }
+        // Removes pie menu.
     }
 
     public void showLocationDialog() {
+        final SettingsController settingsController =
+            mActivity.getSettingsController();
+
         mLocationDialog = new AlertDialog.Builder(mActivity)
                 .setTitle(R.string.remember_location_title)
                 .setMessage(R.string.remember_location_prompt)
@@ -456,7 +462,7 @@
                         new DialogInterface.OnClickListener() {
                             @Override
                             public void onClick(DialogInterface dialog, int arg1) {
-                                mController.enableRecordingLocation(true);
+                                settingsController.setLocation(true);
                                 mLocationDialog = null;
                             }
                         })
@@ -470,7 +476,7 @@
                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
                     @Override
                     public void onCancel(DialogInterface dialog) {
-                        mController.enableRecordingLocation(false);
+                        settingsController.setLocation(false);
                         mLocationDialog = null;
                     }
                 })
@@ -496,22 +502,25 @@
         mMenu.overrideSettings(keyvalues);
     }
 
-    public void updateOnScreenIndicators(Camera.Parameters params,
-            PreferenceGroup group, ComboPreferences prefs) {
+    public void updateOnScreenIndicators(Camera.Parameters params) {
         if (params == null) return;
+
+        SettingsManager settingsManager = mActivity.getSettingsManager();
         mOnScreenIndicators.updateSceneOnScreenIndicator(params.getSceneMode());
+
+        String exposure = settingsManager.get(new ExposureSetting());
         mOnScreenIndicators.updateExposureOnScreenIndicator(params,
-                CameraSettings.readExposure(prefs));
+            Integer.parseInt(exposure));
         mOnScreenIndicators.updateFlashOnScreenIndicator(params.getFlashMode());
+
         int wbIndex = 2;
-        ListPreference pref = group.findPreference(CameraSettings.KEY_WHITE_BALANCE);
-        if (pref != null) {
-            wbIndex = pref.getCurrentIndex();
-        }
-        mOnScreenIndicators.updateWBIndicator(wbIndex);
-        boolean location = RecordLocationPreference.get(
-                prefs, mActivity.getContentResolver());
-        mOnScreenIndicators.updateLocationIndicator(location);
+        String whiteBalance = settingsManager.get(new WhiteBalanceSetting());
+        mOnScreenIndicators.updateWBIndicator(
+            SettingsManager.getWhiteBalanceIndex(mActivity, whiteBalance));
+
+        String location = settingsManager.get(new LocationSetting());
+        mOnScreenIndicators.updateLocationIndicator(
+            location.equals(SettingsManager.VALUE_ON));
     }
 
     public void setCameraState(int state) {
@@ -578,7 +587,9 @@
                 @Override
                 public void onDismiss() {
                     mPopup = null;
-                    mMenu.popupDismissed();
+                    if (mMenu != null) {
+                        mMenu.popupDismissed();
+                    }
                     showUI();
 
                     // Switch back into fullscreen/lights-out mode after popup
@@ -805,22 +816,33 @@
 
     @Override
     public void setFocusPosition(int x, int y) {
-        mPieRenderer.setFocus(x, y);
+        if (mPieRenderer != null) {
+            mPieRenderer.setFocus(x, y);
+        }
     }
 
     @Override
     public void onFocusStarted() {
-        getFocusIndicator().showStart();
+        FocusIndicator indicator = getFocusIndicator();
+        if (indicator != null) {
+            indicator.showStart();
+        }
     }
 
     @Override
     public void onFocusSucceeded(boolean timeout) {
-        getFocusIndicator().showSuccess(timeout);
+        FocusIndicator indicator = getFocusIndicator();
+        if (indicator != null) {
+            indicator.showSuccess(timeout);
+        }
     }
 
     @Override
     public void onFocusFailed(boolean timeout) {
-        getFocusIndicator().showFail(timeout);
+        FocusIndicator indicator = getFocusIndicator();
+        if (indicator != null) {
+            indicator.showFail(timeout);
+        }
     }
 
     @Override
diff --git a/src/com/android/camera/PieController.java b/src/com/android/camera/PieController.java
index 6224401..0a7fcc6 100644
--- a/src/com/android/camera/PieController.java
+++ b/src/com/android/camera/PieController.java
@@ -16,12 +16,13 @@
 
 package com.android.camera;
 
-import android.app.Activity;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
 
+import com.android.camera.CameraActivity;
 import com.android.camera.CameraPreference.OnPreferenceChangedListener;
 import com.android.camera.drawable.TextDrawable;
+import com.android.camera.settings.SettingsManager;
 import com.android.camera.ui.PieItem;
 import com.android.camera.ui.PieItem.OnClickListener;
 import com.android.camera.ui.PieRenderer;
@@ -41,7 +42,7 @@
     protected static float CENTER = (float) Math.PI / 2;
     protected static final float SWEEP = 0.06f;
 
-    protected Activity mActivity;
+    protected CameraActivity mActivity;
     protected PreferenceGroup mPreferenceGroup;
     protected OnPreferenceChangedListener mListener;
     protected PieRenderer mRenderer;
@@ -53,7 +54,7 @@
         mListener = listener;
     }
 
-    public PieController(Activity activity, PieRenderer pie) {
+    public PieController(CameraActivity activity, PieRenderer pie) {
         mActivity = activity;
         mRenderer = pie;
         mPreferences = new ArrayList<IconListPreference>();
@@ -75,7 +76,8 @@
 
     protected void setCameraId(int cameraId) {
         ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
-        pref.setValue("" + cameraId);
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+        settingsManager.setValueFromPreference(pref, "" + cameraId);
     }
 
     protected PieItem makeItem(int resId) {
@@ -90,6 +92,8 @@
     }
 
     public PieItem makeItem(String prefKey) {
+        final SettingsManager settingsManager = mActivity.getSettingsManager();
+
         final IconListPreference pref =
                 (IconListPreference) mPreferenceGroup.findPreference(prefKey);
         if (pref == null) return null;
@@ -97,7 +101,8 @@
         int resid = -1;
         if (!pref.getUseSingleIcon() && iconIds != null) {
             // Each entry has a corresponding icon.
-            int index = pref.findIndexOfValue(pref.getValue());
+            String value = settingsManager.getValueFromPreference(pref);
+            int index = pref.findIndexOfValue(value);
             resid = iconIds[index];
         } else {
             // The preference only has a single icon to represent it.
@@ -122,7 +127,7 @@
                 inner.setOnClickListener(new OnClickListener() {
                     @Override
                     public void onClick(PieItem item) {
-                        pref.setValueIndex(index);
+                        settingsManager.setValueIndexFromPreference(pref, index);
                         reloadPreference(pref);
                         onSettingChanged(pref);
                     }
@@ -138,7 +143,10 @@
         if (pref == null) return null;
         int[] iconIds = pref.getLargeIconIds();
         int resid = -1;
-        int index = pref.findIndexOfValue(pref.getValue());
+        SettingsManager settingsManager = mActivity.getSettingsManager();
+        String value = settingsManager.getValueFromPreference(pref);
+        int index = pref.findIndexOfValue(value);
+
         if (!pref.getUseSingleIcon() && iconIds != null) {
             // Each entry has a corresponding icon.
             resid = iconIds[index];
@@ -161,10 +169,14 @@
                     }
                     IconListPreference pref = (IconListPreference) mPreferenceGroup
                             .findPreference(prefKey);
-                    int index = pref.findIndexOfValue(pref.getValue());
+
+                    SettingsManager settingsManager = mActivity.getSettingsManager();
+                    String value = settingsManager.getValueFromPreference(pref);
+                    int index = pref.findIndexOfValue(value);
+
                     CharSequence[] values = pref.getEntryValues();
                     index = (index + 1) % values.length;
-                    pref.setValueIndex(index);
+                    settingsManager.setValueIndexFromPreference(pref, index);
                     fitem.setLabel(pref.getLabels()[index]);
                     fitem.setImageResource(mActivity,
                             ((IconListPreference) pref).getLargeIconIds()[index]);
@@ -191,7 +203,10 @@
         IconListPreference pref = (IconListPreference) mPreferenceGroup
                 .findPreference(prefKey);
         if (pref != null) {
-            int index = pref.findIndexOfValue(pref.getValue());
+            SettingsManager settingsManager = mActivity.getSettingsManager();
+            String value = settingsManager.getValueFromPreference(pref);
+            int index = pref.findIndexOfValue(value);
+
             item.setLabel(pref.getLabels()[index]);
             item.setImageResource(mActivity,
                     ((IconListPreference) pref).getLargeIconIds()[index]);
@@ -218,7 +233,9 @@
             // Each entry has a corresponding icon.
             int index;
             if (overrideValue == null) {
-                index = pref.findIndexOfValue(pref.getValue());
+                SettingsManager settingsManager = mActivity.getSettingsManager();
+                String value = settingsManager.getValueFromPreference(pref);
+                index = pref.findIndexOfValue(value);
             } else {
                 index = pref.findIndexOfValue(overrideValue);
                 if (index == -1) {
diff --git a/src/com/android/camera/RecordLocationPreference.java b/src/com/android/camera/RecordLocationPreference.java
index 9992afa..849a691 100644
--- a/src/com/android/camera/RecordLocationPreference.java
+++ b/src/com/android/camera/RecordLocationPreference.java
@@ -40,7 +40,11 @@
 
     @Override
     public String getValue() {
-        return get(getSharedPreferences(), mResolver) ? VALUE_ON : VALUE_OFF;
+        SharedPreferences preferences = getSharedPreferences();
+        if (preferences == null) {
+            return null;
+        }
+        return get(preferences, mResolver) ? VALUE_ON : VALUE_OFF;
     }
 
     public static boolean get(
diff --git a/src/com/android/camera/SettingsController.java b/src/com/android/camera/SettingsController.java
index ecf6bd5..ed6e2e5 100644
--- a/src/com/android/camera/SettingsController.java
+++ b/src/com/android/camera/SettingsController.java
@@ -16,25 +16,48 @@
 
 package com.android.camera;
 
-import com.android.camera.ui.SettingsView;
-import com.android.camera.SettingsManager.LocationSetting;
+import android.hardware.Camera.Parameters;
+import android.hardware.Camera.Size;
+import android.media.CamcorderProfile;
+import android.util.Log;
 
-public class SettingsController implements SettingsView.SettingsListener {
+import com.android.camera.app.CameraManager;
+import com.android.camera.ui.SettingsView;
+import com.android.camera.settings.SettingsManager;
+import com.android.camera.settings.SettingsManager.LocationSetting;
+import com.android.camera.settings.SettingsManager.PictureSizeSetting;
+import com.android.camera.settings.SettingsManager.SettingsCapabilities;
+import com.android.camera.settings.SettingsManager.StartupModuleSetting;
+import com.android.camera.settings.SettingsManager.VideoQualitySetting;
+import com.android.camera2.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SettingsController implements SettingsView.SettingsViewListener {
     private static final String TAG = "CAM_SettingsController";
 
     private CameraActivity mActivity;
     private SettingsManager mSettingsManager;
+    private LocationManager mLocationManager;
 
-    SettingsController(CameraActivity activity, SettingsManager manager) {
+    public SettingsController(CameraActivity activity, SettingsManager settingsManager,
+            LocationManager locationManager) {
         mActivity = activity;
-        mSettingsManager = manager;
+        mSettingsManager = settingsManager;
+        mLocationManager = locationManager;
+    }
+
+    public void syncLocationManager() {
+        String value = mSettingsManager.get(new LocationSetting());
+        mLocationManager.recordLocation(value.equals(SettingsManager.VALUE_ON));
     }
 
     @Override
     public void setLocation(boolean on) {
         if (!mActivity.isPaused()) {
-            LocationSetting locationPreference = mSettingsManager.getLocationSetting();
-            locationPreference.set(on ? SettingsManager.VALUE_ON : SettingsManager.VALUE_OFF);
+            mSettingsManager.set(new LocationSetting(),
+                (on ? SettingsManager.VALUE_ON : SettingsManager.VALUE_OFF));
 
             LocationManager locationManager = mActivity.getLocationManager();
             locationManager.recordLocation(on);
@@ -42,14 +65,83 @@
     }
 
     @Override
-    public void setPictureSize(int size) {
+    public String[] getSupportedPictureSizeEntries() {
+        ArrayList<String> supported = new ArrayList<String>();
+        List<Size> sizes = mSettingsManager.getSupportedPictureSizes();
+        String[] entries = mActivity.getResources().getStringArray(
+            R.array.pref_camera_picturesize_entries);
+        String[] values = mActivity.getResources().getStringArray(
+            R.array.pref_camera_picturesize_entryvalues);
+
+        if (entries.length != values.length) {
+            return supported.toArray(new String[0]);
+        }
+
+        int i = 0;
+        for (String value : values) {
+            int index = value.indexOf('x');
+            if (index >= 0) {
+                int width = Integer.parseInt(value.substring(0, index));
+                int height = Integer.parseInt(value.substring(index + 1));
+                for (Size size : sizes) {
+                    if (size.width == width && size.height == height) {
+                        supported.add(entries[i]);
+                    }
+                }
+            }
+            i++;
+        }
+        return supported.toArray(new String[supported.size()]);
     }
 
     @Override
-    public void setVideoResolution(int resolution) {
+    public void setPictureSize(String size) {
+        if (!mActivity.isPaused()) {
+            mSettingsManager.set(new PictureSizeSetting(), size);
+        }
+    }
+
+    @Override
+    public String[] getSupportedVideoQualityEntries() {
+        ArrayList<String> supported = new ArrayList();
+        int cameraId = mSettingsManager.getRegisteredCameraId();
+
+        if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_1080P)) {
+            String entry = mActivity.getString(R.string.pref_video_quality_entry_1080p);
+            supported.add(entry);
+        }
+        if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P)) {
+            String entry = mActivity.getString(R.string.pref_video_quality_entry_720p);
+            supported.add(entry);
+        }
+        if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P)) {
+            String entry = mActivity.getString(R.string.pref_video_quality_entry_480p);
+            supported.add(entry);
+        }
+        return supported.toArray(new String[supported.size()]);
+    }
+
+    @Override
+    public void setVideoQuality(String quality) {
+        if (!mActivity.isPaused()) {
+            mSettingsManager.set(new VideoQualitySetting(), quality);
+        }
     }
 
     @Override
     public void setDefaultCamera(int id) {
+        mSettingsManager.setInt(new StartupModuleSetting(), id);
+    }
+
+    public static SettingsCapabilities
+            getSettingsCapabilities(CameraManager.CameraProxy camera) {
+        Parameters parameters = camera.getParameters();
+        final List<Size> sizes = parameters.getSupportedPictureSizes();
+        return (new SettingsCapabilities() {
+                @Override
+                public List<Size> getSupportedPictureSizes() {
+                    return sizes;
+                }
+            });
     }
 }
\ No newline at end of file
diff --git a/src/com/android/camera/SettingsManager.java b/src/com/android/camera/SettingsManager.java
deleted file mode 100644
index e76ce8f..0000000
--- a/src/com/android/camera/SettingsManager.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-package com.android.camera;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.location.Location;
-import android.util.Log;
-
-public class SettingsManager {
-    private static final String TAG = "CAM_SettingsManager";
-
-    private Context mContext;
-    // TODO(edahlgren): plumb this into this class.
-    private ComboPreferences mPreferences;
-
-    // List settings here.
-    private LocationSetting mLocationSetting;
-
-    public SettingsManager(Context context) {
-        mContext = context;
-
-        mPreferences = new ComboPreferences(context);
-        // Local preferences must be non-null to edit preferences.
-        int cameraId = CameraSettings.readPreferredCameraId(mPreferences);
-        mPreferences.setLocalId(context, cameraId);
-        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
-
-        init();
-    }
-
-    private void init() {
-        mLocationSetting = new LocationSetting();
-        // initialize other settings here.
-    }
-
-    // There's global and camera dependent preferences.
-    // We need to distinguish between the two.
-    public static final String VALUE_GLOBAL = "global";
-    public static final String VALUE_CAMERA = "camera";
-
-    public static final String VALUE_NONE = "none";
-    public static final String VALUE_ON = "on";
-    public static final String VALUE_OFF = "off";
-
-    public class LocationSetting {
-        public String isGlobal() {
-            return VALUE_GLOBAL;
-        }
-
-        public String get() {
-            return mPreferences.getString(CameraSettings.KEY_RECORD_LOCATION,
-                VALUE_NONE);
-        }
-
-        public void set(String value) {
-            mPreferences.edit()
-                .putString(CameraSettings.KEY_RECORD_LOCATION, value)
-                .apply();
-        }
-    }
-
-    public LocationSetting getLocationSetting() {
-        return mLocationSetting;
-    }
-}
diff --git a/src/com/android/camera/app/AppController.java b/src/com/android/camera/app/AppController.java
index 84398eb..7029492 100644
--- a/src/com/android/camera/app/AppController.java
+++ b/src/com/android/camera/app/AppController.java
@@ -23,8 +23,9 @@
 import android.widget.FrameLayout;
 
 import com.android.camera.LocationManager;
-import com.android.camera.SettingsManager;
 import com.android.camera.ui.ModeListView;
+import com.android.camera.SettingsController;
+import com.android.camera.settings.SettingsManager;
 
 /**
  * The controller at app level.
@@ -189,4 +190,12 @@
      * @return Common services and functionality to be shared.
      */
     public CameraServices getServices();
+
+    /**
+     * Returns the {@link com.android.camera.SettingsController}.
+     * TODO: remove this once all settings dialogs are consolidated.
+     *
+     * @return {@code null} if not available yet.
+     */
+    public SettingsController getSettingsController();
 }
diff --git a/src/com/android/camera/settings/SettingsManager.java b/src/com/android/camera/settings/SettingsManager.java
new file mode 100644
index 0000000..790c6f6
--- /dev/null
+++ b/src/com/android/camera/settings/SettingsManager.java
@@ -0,0 +1,806 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.camera.settings;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.hardware.Camera.Size;
+import android.location.Location;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.android.camera.CameraActivity;
+import com.android.camera.ListPreference;
+import com.android.camera2.R;
+
+import java.util.List;
+
+public class SettingsManager {
+    private static final String TAG = "CAM_SettingsManager";
+
+    private Context mContext;
+    private SharedPreferences mDefaultSettings;
+    private SharedPreferences mGlobalSettings;
+    private SharedPreferences mCameraSettings;
+    private OnSharedPreferenceChangeListener mListener;
+    private SettingsCapabilities mCapabilities;
+
+    private int mCameraId = -1;
+
+    public SettingsManager(Context context,
+            OnSharedPreferenceChangeListener globalListener,
+            int nCameras) {
+        mContext = context;
+        mDefaultSettings = PreferenceManager.getDefaultSharedPreferences(context);
+        initGlobal(globalListener);
+
+        DefaultCameraIdSetting cameraIdSetting = new DefaultCameraIdSetting();
+        int cameraId = Integer.parseInt(get(cameraIdSetting));
+        if (cameraId < 0 || cameraId >= nCameras) {
+            setDefault(cameraIdSetting);
+        }
+    }
+
+    /**
+     * Initialize global SharedPreferences.
+     */
+    private void initGlobal(OnSharedPreferenceChangeListener listener) {
+        String globalKey = mContext.getPackageName() + "_preferences_camera";
+        mGlobalSettings = mContext.getSharedPreferences(
+            globalKey, Context.MODE_PRIVATE);
+        mGlobalSettings.registerOnSharedPreferenceChangeListener(listener);
+    }
+
+    /**
+     * Initialize SharedPreferences for other cameras.
+     */
+    public void changeCamera(int cameraId, SettingsCapabilities capabilities) {
+        mCapabilities = capabilities;
+
+        if (cameraId == mCameraId) {
+            if (mCameraSettings != null) {
+                mCameraSettings.registerOnSharedPreferenceChangeListener(mListener);
+            }
+            return;
+        }
+        // Cache the camera id so we don't need to reload preferences
+        // if we're using the same camera.
+        mCameraId = cameraId;
+
+        String cameraKey = mContext.getPackageName() + "_preferences_" + cameraId;
+        mCameraSettings = mContext.getSharedPreferences(
+            cameraKey, Context.MODE_PRIVATE);
+        mCameraSettings.registerOnSharedPreferenceChangeListener(mListener);
+    }
+
+    /**
+     * Interface with Camera Parameters and Modules.
+     */
+    public interface SettingsListener {
+        public void onSettingsChanged();
+    }
+
+    public void addListener(final SettingsListener listener) {
+        mListener =
+            new OnSharedPreferenceChangeListener() {
+                @Override
+                public void onSharedPreferenceChanged(
+                        SharedPreferences sharedPreferences, String key) {
+                    listener.onSettingsChanged();
+                }
+            };
+    }
+
+    public void removeListener() {
+        if (mCameraSettings != null && mListener != null) {
+            mCameraSettings.unregisterOnSharedPreferenceChangeListener(mListener);
+            mListener = null;
+        }
+    }
+
+    public interface SettingsCapabilities {
+        public List<Size> getSupportedPictureSizes();
+    }
+
+    public List<Size> getSupportedPictureSizes() {
+        if (mCapabilities != null) {
+            return mCapabilities.getSupportedPictureSizes();
+        } else {
+            return null;
+        }
+    }
+
+    public int getRegisteredCameraId() {
+        return mCameraId;
+    }
+
+    /**
+     * Manage individual settings.
+     */
+    public static final String VALUE_NONE = "none";
+    public static final String VALUE_ON = "on";
+    public static final String VALUE_OFF = "off";
+
+    public static final String VALUE_STRING = "string";
+    public static final String VALUE_BOOLEAN = "boolean";
+    public static final String VALUE_INTEGER = "integer";
+
+    public static final String VALUE_DEFAULT = "default";
+    public static final String VALUE_GLOBAL = "global";
+    public static final String VALUE_CAMERA = "camera";
+
+    // TODO: Order theses by global/camera.
+    public static final String KEY_VERSION = "pref_version_key";
+    public static final String KEY_LOCAL_VERSION = "pref_local_version_key";
+    public static final String KEY_RECORD_LOCATION = "pref_camera_recordlocation_key";
+    public static final String KEY_VIDEO_QUALITY = "pref_video_quality_key";
+    public static final String KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL = 
+        "pref_video_time_lapse_frame_interval_key";
+    public static final String KEY_PICTURE_SIZE = "pref_camera_picturesize_key";
+    public static final String KEY_JPEG_QUALITY = "pref_camera_jpegquality_key";
+    public static final String KEY_FOCUS_MODE = "pref_camera_focusmode_key";
+    public static final String KEY_FLASH_MODE = "pref_camera_flashmode_key";
+    public static final String KEY_VIDEOCAMERA_FLASH_MODE = "pref_camera_video_flashmode_key";
+    public static final String KEY_WHITE_BALANCE = "pref_camera_whitebalance_key";
+    public static final String KEY_SCENE_MODE = "pref_camera_scenemode_key";
+    public static final String KEY_EXPOSURE = "pref_camera_exposure_key";
+    public static final String KEY_TIMER = "pref_camera_timer_key";
+    public static final String KEY_TIMER_SOUND_EFFECTS = "pref_camera_timer_sound_key";
+    public static final String KEY_VIDEO_EFFECT = "pref_video_effect_key";
+    public static final String KEY_CAMERA_ID = "pref_camera_id_key";
+    public static final String KEY_CAMERA_HDR = "pref_camera_hdr_key";
+    public static final String KEY_CAMERA_HDR_PLUS = "pref_camera_hdr_plus_key";
+    public static final String KEY_CAMERA_FIRST_USE_HINT_SHOWN = "pref_camera_first_use_hint_shown_key";
+    public static final String KEY_VIDEO_FIRST_USE_HINT_SHOWN = "pref_video_first_use_hint_shown_key";
+    public static final String KEY_PHOTOSPHERE_PICTURESIZE = "pref_photosphere_picturesize_key";
+    public static final String KEY_STARTUP_MODULE_INDEX = "camera.startup_module";
+
+    public static final int WHITE_BALANCE_DEFAULT_INDEX = 2;
+
+    public interface Setting {
+        public String getSource();
+        public String getType();
+        public String getDefault(Context context);
+        public String getKey();
+    }
+
+    public SharedPreferences getSettingSource(Setting setting) {
+        String source = setting.getSource();
+        if (source.equals(VALUE_DEFAULT)) {
+            return mDefaultSettings;
+        }
+        if (source.equals(VALUE_GLOBAL)) {
+            return mGlobalSettings;
+        }
+        if (source.equals(VALUE_CAMERA)) {
+            return mCameraSettings;
+        }
+        return null;
+    }
+
+    public String get(Setting setting) {
+        SharedPreferences preferences = getSettingSource(setting);
+        if (preferences != null) {
+            return preferences.getString(setting.getKey(), setting.getDefault(mContext));
+        } else {
+            return null;
+        }
+    }
+
+    public boolean getBoolean(Setting setting) {
+        SharedPreferences preferences = getSettingSource(setting);
+        boolean defaultValue = setting.getDefault(mContext).equals(VALUE_ON);
+        if (preferences != null) {
+            return preferences.getBoolean(setting.getKey(), defaultValue);
+        } else {
+            return defaultValue;
+        }
+    }
+
+    public int getInt(Setting setting) {
+        SharedPreferences preferences = getSettingSource(setting);
+        int defaultValue = Integer.parseInt(setting.getDefault(mContext));
+        if (preferences != null) {
+            return preferences.getInt(setting.getKey(), defaultValue);
+        } else {
+            return defaultValue;
+        }
+    }
+
+    public String get(String key) {
+        Setting setting = settingFromKey(key);
+        if (setting == null) {
+            return null;
+        }
+        return get(setting);
+    }
+
+    public void set(String key, String value) {
+        Setting setting = settingFromKey(key);
+        if (setting != null) {
+            set(setting, value);
+        }
+    }
+
+    public void set(Setting setting, String value) {
+        SharedPreferences preferences = getSettingSource(setting);
+        if (preferences != null) {
+            preferences.edit().putString(setting.getKey(), value).apply();
+        }
+    }
+
+    public void setBoolean(Setting setting, boolean value) {
+        SharedPreferences preferences = getSettingSource(setting);
+        if (preferences != null) {
+            preferences.edit().putBoolean(setting.getKey(), value).apply();
+        }
+    }
+
+    public void setInt(Setting setting, int value) {
+        SharedPreferences preferences = getSettingSource(setting);
+        if (preferences != null) {
+            preferences.edit().putInt(setting.getKey(), value).apply();
+        }
+    }
+
+    public boolean isSet(Setting setting) {
+        SharedPreferences preferences = getSettingSource(setting);
+        if (preferences != null) {
+            return (preferences.getString(setting.getKey(), null) != null);
+        } else {
+            return false;
+        }
+    }
+
+    public void setDefault(Setting setting) {
+        SharedPreferences preferences = getSettingSource(setting);
+        if (preferences != null) {
+            preferences.edit().putString(setting.getKey(),
+                setting.getDefault(mContext));
+        }
+    }
+
+    public Setting settingFromKey(String key) {
+        if (key.equals(KEY_VERSION)) {
+            return new VersionSetting();
+        }
+        if (key.equals(KEY_LOCAL_VERSION)) {
+            return new LocalVersionSetting();
+        }
+        if (key.equals(KEY_RECORD_LOCATION)) {
+            return new LocationSetting();
+        }
+        if (key.equals(KEY_VIDEO_QUALITY)) {
+            return new VideoQualitySetting();
+        }
+        if (key.equals(KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL)) {
+            return new TimeLapseFrameIntervalSetting();
+        }
+        if (key.equals(KEY_PICTURE_SIZE)) {
+            return new PictureSizeSetting();
+        }
+        if (key.equals(KEY_JPEG_QUALITY)) {
+            return new JpegQualitySetting();
+        }
+        if (key.equals(KEY_FOCUS_MODE)) {
+            return new FocusModeSetting();
+        }
+        if (key.equals(KEY_FLASH_MODE)) {
+            return new FlashSetting();
+        }
+        if (key.equals(KEY_VIDEOCAMERA_FLASH_MODE)) {
+            return new VideoFlashSetting();
+        }
+        if (key.equals(KEY_WHITE_BALANCE)) {
+            return new WhiteBalanceSetting();
+        }
+        if (key.equals(KEY_SCENE_MODE)) {
+            return new SceneModeSetting();
+        }
+        if (key.equals(KEY_EXPOSURE)) {
+            return new ExposureSetting();
+        }
+        if (key.equals(KEY_TIMER)) {
+            return new TimerSetting();
+        }
+        if (key.equals(KEY_TIMER_SOUND_EFFECTS)) {
+            return new TimerSoundSetting();
+        }
+        if (key.equals(KEY_VIDEO_EFFECT)) {
+            return new VideoEffectSetting();
+        }
+        if (key.equals(KEY_CAMERA_ID)) {
+            return new DefaultCameraIdSetting();
+        }
+        if (key.equals(KEY_CAMERA_HDR)) {
+            return new HdrSetting();
+        }
+        if (key.equals(KEY_CAMERA_HDR_PLUS)) {
+            return new HdrPlusSetting();
+        }
+        if (key.equals(KEY_CAMERA_FIRST_USE_HINT_SHOWN)) {
+            return new HintSetting();
+        }
+        if (key.equals(KEY_VIDEO_FIRST_USE_HINT_SHOWN)) {
+            return new HintVideoSetting();
+        }
+        if (key.equals(KEY_PHOTOSPHERE_PICTURESIZE)) {
+            return new PhotoSpherePictureSizeSetting();
+        }
+        if (key.equals(KEY_STARTUP_MODULE_INDEX)) {
+            return new StartupModuleSetting();
+        }
+        return null;
+    }
+
+    public static class VersionSetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return "0";
+        }
+
+        public String getKey() {
+            return KEY_VERSION;
+        }
+    }
+
+    public static class LocalVersionSetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return "0";
+        }
+
+        public String getKey() {
+            return KEY_LOCAL_VERSION;
+        }
+    }
+
+    public static class LocationSetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return VALUE_NONE;
+        }
+
+        public String getKey() {
+            return KEY_RECORD_LOCATION;
+        }
+    }
+
+    public static class PictureSizeSetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return null;
+        }
+
+        public String getKey() {
+            return KEY_PICTURE_SIZE;
+        }
+    }
+
+    public static class DefaultCameraIdSetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return "0";
+        }
+
+        public String getKey() {
+            return KEY_CAMERA_ID;
+        }
+    }
+
+    public static class WhiteBalanceSetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return context.getString(R.string.pref_camera_whitebalance_default);
+        }
+
+        public String getKey() {
+            return KEY_WHITE_BALANCE;
+        }
+    }
+
+    public static class HdrSetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return context.getString(R.string.pref_camera_hdr_default);
+        }
+
+        public String getKey() {
+            return KEY_CAMERA_HDR;
+        }
+    }
+
+    public static class HdrPlusSetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return context.getString(R.string.pref_camera_hdr_plus_default);
+        }
+
+        public String getKey() {
+            return KEY_CAMERA_HDR_PLUS;
+        }
+    }
+
+    public static class SceneModeSetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return context.getString(R.string.pref_camera_scenemode_default);
+        }
+
+        public String getKey() {
+            return KEY_SCENE_MODE;
+        }
+    }
+
+    public static class FlashSetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return context.getString(R.string.pref_camera_flashmode_default);
+        }
+
+        public String getKey() {
+            return KEY_FLASH_MODE;
+        }
+    }
+
+    public static class ExposureSetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return "0";
+        }
+
+        public String getKey() {
+            return KEY_EXPOSURE;
+        }
+    }
+
+    public static class HintSetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_BOOLEAN;
+        }
+
+        public String getDefault(Context context) {
+            return VALUE_ON;
+        }
+
+        public String getKey() {
+            return KEY_CAMERA_FIRST_USE_HINT_SHOWN;
+        }
+    }
+
+    public static class FocusModeSetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return null;
+        }
+
+        public String getKey() {
+            return KEY_FOCUS_MODE;
+        }
+    }
+
+    public static class TimerSetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return context.getString(R.string.pref_camera_timer_default);
+        }
+
+        public String getKey() {
+            return KEY_TIMER;
+        }
+    }
+
+    public static class TimerSoundSetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return context.getString(R.string.pref_camera_timer_sound_default);
+        }
+
+        public String getKey() {
+            return KEY_TIMER_SOUND_EFFECTS;
+        }
+    }
+
+    public static class VideoQualitySetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return null;
+        }
+
+        public String getKey() {
+            return KEY_VIDEO_QUALITY;
+        }
+    }
+
+    public static class TimeLapseFrameIntervalSetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return context.getString(R.string.pref_video_time_lapse_frame_interval_default);
+        }
+
+        public String getKey() {
+            return KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL;
+        }
+    }
+
+    public static class JpegQualitySetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return "85";
+        }
+
+        public String getKey() {
+            return KEY_JPEG_QUALITY;
+        }
+    }
+
+    public static class VideoFlashSetting implements Setting {
+        public String getSource() {
+            return VALUE_CAMERA;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return context.getString(R.string.pref_camera_video_flashmode_default);
+        }
+
+        public String getKey() {
+            return KEY_VIDEOCAMERA_FLASH_MODE;
+        }
+    }
+
+    public static class VideoEffectSetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return context.getString(R.string.pref_video_effect_default);
+        }
+
+        public String getKey() {
+            return KEY_VIDEO_EFFECT;
+        }
+    }
+
+    public static class HintVideoSetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_BOOLEAN;
+        }
+
+        public String getDefault(Context context) {
+            return VALUE_ON;
+        }
+
+        public String getKey() {
+            return KEY_VIDEO_FIRST_USE_HINT_SHOWN;
+        }
+    }
+
+    public static class PhotoSpherePictureSizeSetting implements Setting {
+        public String getSource() {
+            return VALUE_GLOBAL;
+        }
+
+        public String getType() {
+            return VALUE_STRING;
+        }
+
+        public String getDefault(Context context) {
+            return null;
+        }
+
+        public String getKey() {
+            return KEY_PHOTOSPHERE_PICTURESIZE;
+        }
+    }
+
+    public static class StartupModuleSetting implements Setting {
+        public String getSource() {
+            return VALUE_DEFAULT;
+        }
+
+        public String getType() {
+            return VALUE_INTEGER;
+        }
+
+        public String getDefault(Context context) {
+            return "0";
+        }
+
+        public String getKey() {
+            return KEY_STARTUP_MODULE_INDEX;
+        }
+    }
+
+    /**
+     * Utilities.
+     * TODO: refactor this into a separate utils module.
+     */
+
+    public String getValueFromPreference(ListPreference pref) {
+        String value = pref.getValue();
+        if (value == null) {
+            value = get(pref.getKey());
+        }
+        return value;
+    }
+
+    public void setValueFromPreference(ListPreference pref, String value) {
+        boolean set = pref.setValue(value);
+        if (!set) {
+            set(pref.getKey(), value);
+        }
+    }
+
+    public void setValueIndexFromPreference(ListPreference pref, int index) {
+        boolean set = pref.setValueIndex(index);
+        if (!set) {
+            String value = pref.getValueAtIndex(index);
+            set(pref.getKey(), value);
+        }
+    }
+
+    public static int getWhiteBalanceIndex(Context context, String whiteBalance) {
+        String[] values = context.getResources().getStringArray(
+            R.array.pref_camera_whitebalance_entryvalues);
+
+        for (int i = 0; i < values.length; i++) {
+            if (values[i].equals(whiteBalance)) {
+                return i;
+            }
+        }
+        return WHITE_BALANCE_DEFAULT_INDEX;
+    }
+}
diff --git a/src/com/android/camera/ui/SettingsView.java b/src/com/android/camera/ui/SettingsView.java
index 1788127..b563902 100644
--- a/src/com/android/camera/ui/SettingsView.java
+++ b/src/com/android/camera/ui/SettingsView.java
@@ -22,6 +22,7 @@
 import android.content.DialogInterface;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.hardware.Camera.Size;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -34,6 +35,8 @@
 import com.android.camera.CameraActivity;
 import com.android.camera2.R;
 
+import java.util.List;
+
 /**
  * SettingsView class displays all global settings in the form
  * of a list.  Each setting launches a dialog or a toggle.
@@ -58,7 +61,7 @@
         R.string.setting_video_resolution, R.string.setting_default_camera,};
 
     private Context mContext;
-    private SettingsListener mListener;
+    private SettingsViewListener mListener;
     private AlertDialog.Builder mDialogBuilder;
 
     private ArrayAdapter mAdapter;
@@ -80,14 +83,19 @@
             });
     }
 
-    public interface SettingsListener {
+    public interface SettingsViewListener {
         public void setLocation(boolean on);
-        public void setPictureSize(int size);
-        public void setVideoResolution(int resolution);
-        public void setDefaultCamera(int id);
+
+        public String[] getSupportedPictureSizeEntries();
+        public void setPictureSize(String size);
+
+        public String[] getSupportedVideoQualityEntries();
+        public void setVideoQuality(String resolution);
+
+        public void setDefaultCamera(int index);
     }
 
-    public void setSettingsListener(SettingsListener listener) {
+    public void setSettingsListener(SettingsViewListener listener) {
         mListener = listener;
     }
 
@@ -134,7 +142,6 @@
         LocationAlertBuilder() {
             super(mContext);
             setTitle(R.string.remember_location_title);
-            setMessage(R.string.remember_location_prompt);
             setPositiveButton(R.string.remember_location_yes,
                 new DialogInterface.OnClickListener() {
                     @Override
@@ -149,37 +156,92 @@
                         dialog.cancel();
                     }
                 });
-            setOnCancelListener(new DialogInterface.OnCancelListener() {
-                    @Override
-                    public void onCancel(DialogInterface dialog) {
-                        mListener.setLocation(false);
-                    }
-                });
         }
     }
 
     private class PictureSizeAlertBuilder extends AlertDialog.Builder {
         PictureSizeAlertBuilder() {
             super(mContext);
+
+            final String[] supported = mListener.getSupportedPictureSizeEntries();
+            final String[] values = mContext.getResources().getStringArray(
+                R.array.pref_camera_picturesize_entryvalues);
+
             setTitle(R.string.setting_picture_size);
+            setItems(supported, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        int index = getIndex(supported[which]);
+                        if (index > 0) {
+                            mListener.setPictureSize(values[index]);
+                        }
+                    }
+                });
         }
-        //mListener.setPictureSize();
+
+        private int getIndex(String val) {
+            String[] entries = mContext.getResources().getStringArray(
+                R.array.pref_camera_picturesize_entries);
+            for (int i = 0; i < entries.length; i++) {
+                if (entries[i].equals(val)) {
+                    return i;
+                }
+            }
+            return -1;
+        }
     }
 
     private class VideoResAlertBuilder extends AlertDialog.Builder {
         VideoResAlertBuilder() {
             super(mContext);
+
+            final String[] supported = mListener.getSupportedVideoQualityEntries();
+            final String[] values = mContext.getResources().getStringArray(
+                R.array.pref_video_quality_entryvalues);
+
             setTitle(R.string.setting_video_resolution);
+            setItems(supported, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        int index = getIndex(supported[which]);
+                        if (index > 0) {
+                            mListener.setVideoQuality(values[index]);
+                        }
+                    }
+                });
         }
-        //mListener.setVideoResolution();
+
+        private int getIndex(String val) {
+            String[] entries = mContext.getResources().getStringArray(
+                R.array.pref_video_quality_entries);
+            for (int i = 0; i < entries.length; i++) {
+                if (entries[i].equals(val)) {
+                    return i;
+                }
+            }
+            return -1;
+        }
     }
 
     private class DefaultCameraAlertBuilder extends AlertDialog.Builder {
         DefaultCameraAlertBuilder() {
             super(mContext);
             setTitle(R.string.setting_default_camera);
+
+            String[] modes = {mContext.getString(R.string.mode_camera),
+                              mContext.getString(R.string.mode_video),
+                              mContext.getString(R.string.mode_photosphere),
+                              mContext.getString(R.string.mode_craft),
+                              mContext.getString(R.string.mode_timelapse),
+                              mContext.getString(R.string.mode_wideangle)};
+
+            setItems(modes, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        mListener.setDefaultCamera(which);
+                    }
+                });
         }
-        //mListener.setDefaultCamera();
     }