Support multiple camera preferences.

Change-Id: I7c8440424c472c9ff61ac22692ce60234d359efe
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index 5c12abe..c438522 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -49,7 +49,6 @@
 import android.os.Message;
 import android.os.MessageQueue;
 import android.os.SystemClock;
-import android.preference.PreferenceManager;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.util.AttributeSet;
@@ -136,7 +135,7 @@
 
     private OrientationEventListener mOrientationListener;
     private int mLastOrientation = 0;  // No rotation (landscape) by default.
-    private SharedPreferences mPreferences;
+    private ComboPreferences mPreferences;
 
     private static final int IDLE = 1;
     private static final int SNAPSHOT_IN_PROGRESS = 2;
@@ -894,11 +893,13 @@
         setContentView(R.layout.camera);
         mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview);
 
-        mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
-        CameraSettings.upgradePreferences(mPreferences);
+        mPreferences = new ComboPreferences(this);
+        CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
+        mCameraId = CameraSettings.readPreferredCameraId(mPreferences);
+        mPreferences.setLocalId(this, mCameraId);
+        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
 
         mNumberOfCameras = CameraHolder.instance().getNumberOfCameras();
-        mCameraId = CameraSettings.readPreferredCameraId(this);
 
         // comment out -- unused now.
         //mQuickCapture = getQuickCaptureSettings();
@@ -2097,7 +2098,7 @@
         mSwitching = true;
 
         mCameraId = (mCameraId + 1) % mNumberOfCameras;
-        CameraSettings.writePreferredCameraId(this, mCameraId);
+        CameraSettings.writePreferredCameraId(mPreferences, mCameraId);
 
         stopPreview();
         closeCamera();
@@ -2110,6 +2111,11 @@
         mJpegPictureCallbackTime = 0;
         mZoomValue = 0;
 
+        // Reload the preferences.
+        mPreferences.setLocalId(this, mCameraId);
+        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
+
+
         // Restart the preview.
         resetExposureCompensation();
         try {
@@ -2121,6 +2127,11 @@
 
         initializeZoom();
 
+        // Reload the UI.
+        if (mFirstTimeInitialized) {
+            initializeHeadUpDisplay();
+        }
+
         mSwitching = false;
         changeHeadUpDisplayState();
     }
diff --git a/src/com/android/camera/CameraButtonIntentReceiver.java b/src/com/android/camera/CameraButtonIntentReceiver.java
index 148542d..a2e86ca 100644
--- a/src/com/android/camera/CameraButtonIntentReceiver.java
+++ b/src/com/android/camera/CameraButtonIntentReceiver.java
@@ -36,7 +36,8 @@
     public void onReceive(Context context, Intent intent) {
         // Try to get the camera hardware
         CameraHolder holder = CameraHolder.instance();
-        int cameraId = CameraSettings.readPreferredCameraId(context);
+        ComboPreferences pref = new ComboPreferences(context);
+        int cameraId = CameraSettings.readPreferredCameraId(pref);
         if (holder.tryOpen(cameraId) == null) return;
 
         // We are going to launch the camera, so hold the camera for later use
diff --git a/src/com/android/camera/CameraPreference.java b/src/com/android/camera/CameraPreference.java
index 62bf91f..1a02070 100644
--- a/src/com/android/camera/CameraPreference.java
+++ b/src/com/android/camera/CameraPreference.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.TypedArray;
-import android.preference.PreferenceManager;
 import android.util.AttributeSet;
 
 import com.android.camera.R;
@@ -48,8 +47,7 @@
 
     public SharedPreferences getSharedPreferences() {
         if (mSharedPreferences == null) {
-            mSharedPreferences =
-                    PreferenceManager.getDefaultSharedPreferences(mContext);
+            mSharedPreferences = ComboPreferences.get(mContext);
         }
         return mSharedPreferences;
     }
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index 6ac2e71..f6b95f6 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -19,10 +19,10 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
 import android.hardware.Camera.Parameters;
 import android.hardware.Camera.Size;
 import android.media.CamcorderProfile;
-import android.preference.PreferenceManager;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -35,6 +35,7 @@
     private static final int NOT_FOUND = -1;
 
     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 = RecordLocationPreference.KEY;
     public static final String KEY_VIDEO_QUALITY = "pref_video_quality_key";
     public static final String KEY_PICTURE_SIZE = "pref_camera_picturesize_key";
@@ -60,6 +61,7 @@
     public static final String EXPOSURE_DEFAULT_VALUE = "0";
 
     public static final int CURRENT_VERSION = 4;
+    public static final int CURRENT_LOCAL_VERSION = 1;
 
     // max video duration in seconds for mms and youtube.
     private static final int MMS_VIDEO_DURATION = CamcorderProfile.get(CamcorderProfile.QUALITY_LOW).duration;
@@ -100,8 +102,8 @@
         for (String candidate : context.getResources().getStringArray(
                 R.array.pref_camera_picturesize_entryvalues)) {
             if (setCameraPictureSize(candidate, supported, parameters)) {
-                SharedPreferences.Editor editor = PreferenceManager
-                        .getDefaultSharedPreferences(context).edit();
+                SharedPreferences.Editor editor = ComboPreferences
+                        .get(context).edit();
                 editor.putString(KEY_PICTURE_SIZE, candidate);
                 editor.commit();
                 return;
@@ -271,7 +273,20 @@
         return list;
     }
 
-    public static void upgradePreferences(SharedPreferences pref) {
+    public static void upgradeLocalPreferences(SharedPreferences pref) {
+        int version;
+        try {
+            version = pref.getInt(KEY_LOCAL_VERSION, 0);
+        } catch (Exception ex) {
+            version = 0;
+        }
+        if (version == CURRENT_LOCAL_VERSION) return;
+        SharedPreferences.Editor editor = pref.edit();
+        editor.putInt(KEY_LOCAL_VERSION, CURRENT_LOCAL_VERSION);
+        editor.commit();
+    }
+
+    public static void upgradeGlobalPreferences(SharedPreferences pref) {
         int version;
         try {
             version = pref.getInt(KEY_VERSION, 0);
@@ -316,6 +331,11 @@
         editor.commit();
     }
 
+    public static void upgradeAllPreferences(ComboPreferences pref) {
+        upgradeGlobalPreferences(pref.getGlobal());
+        upgradeLocalPreferences(pref.getLocal());
+    }
+
     public static boolean getVideoQuality(String quality) {
         return VIDEO_QUALITY_YOUTUBE.equals(
                 quality) || VIDEO_QUALITY_HIGH.equals(quality);
@@ -330,15 +350,13 @@
         return DEFAULT_VIDEO_DURATION * 1000;
     }
 
-    public static int readPreferredCameraId(Context context) {
-        SharedPreferences pref =
-                PreferenceManager.getDefaultSharedPreferences(context);
+    public static int readPreferredCameraId(SharedPreferences pref) {
         return pref.getInt(KEY_CAMERA_ID, 0);
     }
 
-    public static void writePreferredCameraId(Context context, int cameraId) {
-        SharedPreferences.Editor editor = PreferenceManager
-                .getDefaultSharedPreferences(context).edit();
+    public static void writePreferredCameraId(SharedPreferences pref,
+            int cameraId) {
+        Editor editor = pref.edit();
         editor.putInt(KEY_CAMERA_ID, cameraId);
         editor.commit();
     }
diff --git a/src/com/android/camera/ComboPreferences.java b/src/com/android/camera/ComboPreferences.java
new file mode 100644
index 0000000..6af2862
--- /dev/null
+++ b/src/com/android/camera/ComboPreferences.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2010 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.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.preference.PreferenceManager;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class ComboPreferences implements SharedPreferences, OnSharedPreferenceChangeListener {
+    private SharedPreferences mPrefGlobal;  // global preferences
+    private SharedPreferences mPrefLocal;  // per-camera preferences
+    private CopyOnWriteArrayList<OnSharedPreferenceChangeListener> mListeners;
+    private static WeakHashMap<Context, ComboPreferences> sMap =
+            new WeakHashMap<Context, ComboPreferences>();
+
+    public ComboPreferences(Context context) {
+        mPrefGlobal = PreferenceManager.getDefaultSharedPreferences(context);
+        mPrefGlobal.registerOnSharedPreferenceChangeListener(this);
+        synchronized (sMap) {
+            sMap.put(context, this);
+        }
+        mListeners = new CopyOnWriteArrayList<OnSharedPreferenceChangeListener>();
+    }
+
+    public static ComboPreferences get(Context context) {
+        synchronized (sMap) {
+            return sMap.get(context);
+        }
+    }
+
+    public void setLocalId(Context context, int id) {
+        String prefName = context.getPackageName() + "_preferences_" + id;
+        if (mPrefLocal != null) {
+            mPrefLocal.unregisterOnSharedPreferenceChangeListener(this);
+        }
+        mPrefLocal = context.getSharedPreferences(
+                prefName, Context.MODE_PRIVATE);
+        mPrefLocal.registerOnSharedPreferenceChangeListener(this);
+    }
+
+    public SharedPreferences getGlobal() {
+        return mPrefGlobal;
+    }
+
+    public SharedPreferences getLocal() {
+        return mPrefLocal;
+    }
+
+    public Map<String, ?> getAll() {
+        throw new UnsupportedOperationException(); // Can be implemented if needed.
+    }
+
+    private static boolean isGlobal(String key) {
+        return key.equals(CameraSettings.KEY_CAMERA_ID)
+                || key.equals(CameraSettings.KEY_RECORD_LOCATION);
+    }
+
+    public String getString(String key, String defValue) {
+        if (isGlobal(key) || !mPrefLocal.contains(key)) {
+            return mPrefGlobal.getString(key, defValue);
+        } else {
+            return mPrefLocal.getString(key, defValue);
+        }
+    }
+
+    public int getInt(String key, int defValue) {
+        if (isGlobal(key) || !mPrefLocal.contains(key)) {
+            return mPrefGlobal.getInt(key, defValue);
+        } else {
+            return mPrefLocal.getInt(key, defValue);
+        }
+    }
+
+    public long getLong(String key, long defValue) {
+        if (isGlobal(key) || !mPrefLocal.contains(key)) {
+            return mPrefGlobal.getLong(key, defValue);
+        } else {
+            return mPrefLocal.getLong(key, defValue);
+        }
+    }
+
+    public float getFloat(String key, float defValue) {
+        if (isGlobal(key) || !mPrefLocal.contains(key)) {
+            return mPrefGlobal.getFloat(key, defValue);
+        } else {
+            return mPrefLocal.getFloat(key, defValue);
+        }
+    }
+
+    public boolean getBoolean(String key, boolean defValue) {
+        if (isGlobal(key) || !mPrefLocal.contains(key)) {
+            return mPrefGlobal.getBoolean(key, defValue);
+        } else {
+            return mPrefLocal.getBoolean(key, defValue);
+        }
+    }
+
+    public boolean contains(String key) {
+        if (mPrefLocal.contains(key)) return true;
+        if (mPrefGlobal.contains(key)) return true;
+        return false;
+    }
+
+    private class MyEditor implements Editor {
+        private Editor mEditorGlobal;
+        private Editor mEditorLocal;
+
+        MyEditor() {
+            mEditorGlobal = mPrefGlobal.edit();
+            mEditorLocal = mPrefLocal.edit();
+        }
+
+        public boolean commit() {
+            boolean result1 = mEditorGlobal.commit();
+            boolean result2 = mEditorLocal.commit();
+            return result1 && result2;
+        }
+
+        // Note: clear() and remove() affects both local and global preferences.
+        public Editor clear() {
+            mEditorGlobal.clear();
+            mEditorLocal.clear();
+            return this;
+        }
+
+        public Editor remove(String key) {
+            mEditorGlobal.remove(key);
+            mEditorLocal.remove(key);
+            return this;
+        }
+
+        public Editor putString(String key, String value) {
+            if (isGlobal(key)) {
+                mEditorGlobal.putString(key, value);
+            } else {
+                mEditorLocal.putString(key, value);
+            }
+            return this;
+        }
+
+        public Editor putInt(String key, int value) {
+            if (isGlobal(key)) {
+                mEditorGlobal.putInt(key, value);
+            } else {
+                mEditorLocal.putInt(key, value);
+            }
+            return this;
+        }
+
+        public Editor putLong(String key, long value) {
+            if (isGlobal(key)) {
+                mEditorGlobal.putLong(key, value);
+            } else {
+                mEditorLocal.putLong(key, value);
+            }
+            return this;
+        }
+
+        public Editor putFloat(String key, float value) {
+            if (isGlobal(key)) {
+                mEditorGlobal.putFloat(key, value);
+            } else {
+                mEditorLocal.putFloat(key, value);
+            }
+            return this;
+        }
+
+        public Editor putBoolean(String key, boolean value) {
+            if (isGlobal(key)) {
+                mEditorGlobal.putBoolean(key, value);
+            } else {
+                mEditorLocal.putBoolean(key, value);
+            }
+            return this;
+        }
+    }
+
+    // Note the remove() and clear() of the returned Editor may not work as
+    // expected because it doesn't touch the global preferences at all.
+    public Editor edit() {
+        return new MyEditor();
+    }
+
+    public void registerOnSharedPreferenceChangeListener(
+            OnSharedPreferenceChangeListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void unregisterOnSharedPreferenceChangeListener(
+            OnSharedPreferenceChangeListener listener) {
+        mListeners.remove(listener);
+    }
+
+    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+            String key) {
+        for (OnSharedPreferenceChangeListener listener : mListeners) {
+            listener.onSharedPreferenceChanged(this, key);
+        }
+    }
+}
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java
index 0fc4c43..b5cafe3 100644
--- a/src/com/android/camera/VideoCamera.java
+++ b/src/com/android/camera/VideoCamera.java
@@ -48,7 +48,6 @@
 import android.os.Message;
 import android.os.StatFs;
 import android.os.SystemClock;
-import android.preference.PreferenceManager;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.provider.MediaStore.Video;
@@ -123,7 +122,7 @@
     private final static String EXTRA_QUICK_CAPTURE =
             "android.intent.extra.quickCapture";
 
-    private SharedPreferences mPreferences;
+    private ComboPreferences mPreferences;
 
     private PreviewFrameLayout mPreviewFrameLayout;
     private SurfaceView mVideoPreview;
@@ -271,11 +270,13 @@
             win.setAttributes(winParams);
         }
 
-        mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
-        CameraSettings.upgradePreferences(mPreferences);
+        mPreferences = new ComboPreferences(this);
+        CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
+        mCameraId = CameraSettings.readPreferredCameraId(mPreferences);
+        mPreferences.setLocalId(this, mCameraId);
+        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
 
         mNumberOfCameras = CameraHolder.instance().getNumberOfCameras();
-        mCameraId = CameraSettings.readPreferredCameraId(this);
 
         readVideoPreferences();
 
@@ -1079,8 +1080,8 @@
     private void switchCameraId() {
         mSwitching = true;
 
-        int nextId = (mCameraId + 1) % mNumberOfCameras;
-        CameraSettings.writePreferredCameraId(this, nextId);
+        mCameraId = (mCameraId + 1) % mNumberOfCameras;
+        CameraSettings.writePreferredCameraId(mPreferences, mCameraId);
 
         changeHeadUpDisplayState();
 
@@ -1099,6 +1100,10 @@
         closeCamera();
         mHandler.removeMessages(INIT_RECORDER);
 
+        // Reload the preferences.
+        mPreferences.setLocalId(this, mCameraId);
+        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
+
         // Restart preview
         try {
             startPreview();
@@ -1107,6 +1112,9 @@
             return;
         }
 
+        // Reload the UI.
+        initializeHeadUpDisplay();
+
         if (mSurfaceHolder != null) {
             mHandler.sendEmptyMessage(INIT_RECORDER);
         }
diff --git a/src/com/android/camera/ui/HeadUpDisplay.java b/src/com/android/camera/ui/HeadUpDisplay.java
index 03926f2..0db869b 100644
--- a/src/com/android/camera/ui/HeadUpDisplay.java
+++ b/src/com/android/camera/ui/HeadUpDisplay.java
@@ -28,7 +28,6 @@
 import android.hardware.Camera.Parameters;
 import android.os.Handler;
 import android.os.Message;
-import android.preference.PreferenceManager;
 import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 import android.view.View.MeasureSpec;
@@ -36,6 +35,7 @@
 import android.view.animation.Animation;
 
 import com.android.camera.CameraSettings;
+import com.android.camera.ComboPreferences;
 import com.android.camera.IconListPreference;
 import com.android.camera.ListPreference;
 import com.android.camera.PreferenceGroup;
@@ -67,7 +67,7 @@
 
     protected IndicatorBar mIndicatorBar;
 
-    private SharedPreferences mSharedPrefs;
+    private ComboPreferences mSharedPrefs;
     private PreferenceGroup mPreferenceGroup;
 
     private PopupWindow mPopupWindow;
@@ -180,7 +180,7 @@
 
     public void initialize(Context context, PreferenceGroup preferenceGroup) {
         mPreferenceGroup = preferenceGroup;
-        mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
+        mSharedPrefs = ComboPreferences.get(context);
         mSharedPrefs.registerOnSharedPreferenceChangeListener(
                 mSharedPreferenceChangeListener);
         initializeIndicatorBar(context, preferenceGroup);
@@ -406,7 +406,7 @@
         Editor editor = mSharedPrefs.edit();
         editor.clear();
         editor.commit();
-        CameraSettings.upgradePreferences(mSharedPrefs);
+        CameraSettings.upgradeAllPreferences(mSharedPrefs);
         CameraSettings.initialCameraPictureSize(context, param);
         reloadPreferences();
         if (mListener != null) {