Home | History | Annotate | Download | only in camera
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera;
     18 
     19 import android.app.backup.BackupManager;
     20 import android.content.Context;
     21 import android.content.SharedPreferences;
     22 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
     23 import android.preference.PreferenceManager;
     24 
     25 import com.android.gallery3d.util.UsageStatistics;
     26 
     27 import java.util.Map;
     28 import java.util.Set;
     29 import java.util.WeakHashMap;
     30 import java.util.concurrent.CopyOnWriteArrayList;
     31 
     32 public class ComboPreferences implements
     33         SharedPreferences,
     34         OnSharedPreferenceChangeListener {
     35     private SharedPreferences mPrefGlobal;  // global preferences
     36     private SharedPreferences mPrefLocal;  // per-camera preferences
     37     private String mPackageName;
     38     private CopyOnWriteArrayList<OnSharedPreferenceChangeListener> mListeners;
     39     // TODO: Remove this WeakHashMap in the camera code refactoring
     40     private static WeakHashMap<Context, ComboPreferences> sMap =
     41             new WeakHashMap<Context, ComboPreferences>();
     42 
     43     public ComboPreferences(Context context) {
     44         mPackageName = context.getPackageName();
     45         mPrefGlobal = context.getSharedPreferences(
     46                 getGlobalSharedPreferencesName(context), Context.MODE_PRIVATE);
     47         mPrefGlobal.registerOnSharedPreferenceChangeListener(this);
     48 
     49         synchronized (sMap) {
     50             sMap.put(context, this);
     51         }
     52         mListeners = new CopyOnWriteArrayList<OnSharedPreferenceChangeListener>();
     53 
     54         // The global preferences was previously stored in the default
     55         // shared preferences file. They should be stored in the camera-specific
     56         // shared preferences file so we can backup them solely.
     57         SharedPreferences oldprefs =
     58                 PreferenceManager.getDefaultSharedPreferences(context);
     59         if (!mPrefGlobal.contains(CameraSettings.KEY_VERSION)
     60                 && oldprefs.contains(CameraSettings.KEY_VERSION)) {
     61             moveGlobalPrefsFrom(oldprefs);
     62         }
     63     }
     64 
     65     public static ComboPreferences get(Context context) {
     66         synchronized (sMap) {
     67             return sMap.get(context);
     68         }
     69     }
     70 
     71     private static String getLocalSharedPreferencesName(
     72             Context context, int cameraId) {
     73         return context.getPackageName() + "_preferences_" + cameraId;
     74     }
     75 
     76     private static String getGlobalSharedPreferencesName(Context context) {
     77         return context.getPackageName() + "_preferences_camera";
     78     }
     79 
     80     private void movePrefFrom(
     81             Map<String, ?> m, String key, SharedPreferences src) {
     82         if (m.containsKey(key)) {
     83             Object v = m.get(key);
     84             if (v instanceof String) {
     85                 mPrefGlobal.edit().putString(key, (String) v).apply();
     86             } else if (v instanceof Integer) {
     87                 mPrefGlobal.edit().putInt(key, (Integer) v).apply();
     88             } else if (v instanceof Long) {
     89                 mPrefGlobal.edit().putLong(key, (Long) v).apply();
     90             } else if (v instanceof Float) {
     91                 mPrefGlobal.edit().putFloat(key, (Float) v).apply();
     92             } else if (v instanceof Boolean) {
     93                 mPrefGlobal.edit().putBoolean(key, (Boolean) v).apply();
     94             }
     95             src.edit().remove(key).apply();
     96         }
     97     }
     98 
     99     private void moveGlobalPrefsFrom(SharedPreferences src) {
    100         Map<String, ?> prefMap = src.getAll();
    101         movePrefFrom(prefMap, CameraSettings.KEY_VERSION, src);
    102         movePrefFrom(prefMap, CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL, src);
    103         movePrefFrom(prefMap, CameraSettings.KEY_CAMERA_ID, src);
    104         movePrefFrom(prefMap, CameraSettings.KEY_RECORD_LOCATION, src);
    105         movePrefFrom(prefMap, CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, src);
    106         movePrefFrom(prefMap, CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN, src);
    107         movePrefFrom(prefMap, CameraSettings.KEY_VIDEO_EFFECT, src);
    108     }
    109 
    110     public static String[] getSharedPreferencesNames(Context context) {
    111         int numOfCameras = CameraHolder.instance().getNumberOfCameras();
    112         String prefNames[] = new String[numOfCameras + 1];
    113         prefNames[0] = getGlobalSharedPreferencesName(context);
    114         for (int i = 0; i < numOfCameras; i++) {
    115             prefNames[i + 1] = getLocalSharedPreferencesName(context, i);
    116         }
    117         return prefNames;
    118     }
    119 
    120     // Sets the camera id and reads its preferences. Each camera has its own
    121     // preferences.
    122     public void setLocalId(Context context, int cameraId) {
    123         String prefName = getLocalSharedPreferencesName(context, cameraId);
    124         if (mPrefLocal != null) {
    125             mPrefLocal.unregisterOnSharedPreferenceChangeListener(this);
    126         }
    127         mPrefLocal = context.getSharedPreferences(
    128                 prefName, Context.MODE_PRIVATE);
    129         mPrefLocal.registerOnSharedPreferenceChangeListener(this);
    130     }
    131 
    132     public SharedPreferences getGlobal() {
    133         return mPrefGlobal;
    134     }
    135 
    136     public SharedPreferences getLocal() {
    137         return mPrefLocal;
    138     }
    139 
    140     @Override
    141     public Map<String, ?> getAll() {
    142         throw new UnsupportedOperationException(); // Can be implemented if needed.
    143     }
    144 
    145     private static boolean isGlobal(String key) {
    146         return key.equals(CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL)
    147                 || key.equals(CameraSettings.KEY_CAMERA_ID)
    148                 || key.equals(CameraSettings.KEY_RECORD_LOCATION)
    149                 || key.equals(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN)
    150                 || key.equals(CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN)
    151                 || key.equals(CameraSettings.KEY_VIDEO_EFFECT)
    152                 || key.equals(CameraSettings.KEY_TIMER)
    153                 || key.equals(CameraSettings.KEY_TIMER_SOUND_EFFECTS)
    154                 || key.equals(CameraSettings.KEY_PHOTOSPHERE_PICTURESIZE);
    155     }
    156 
    157     @Override
    158     public String getString(String key, String defValue) {
    159         if (isGlobal(key) || !mPrefLocal.contains(key)) {
    160             return mPrefGlobal.getString(key, defValue);
    161         } else {
    162             return mPrefLocal.getString(key, defValue);
    163         }
    164     }
    165 
    166     @Override
    167     public int getInt(String key, int defValue) {
    168         if (isGlobal(key) || !mPrefLocal.contains(key)) {
    169             return mPrefGlobal.getInt(key, defValue);
    170         } else {
    171             return mPrefLocal.getInt(key, defValue);
    172         }
    173     }
    174 
    175     @Override
    176     public long getLong(String key, long defValue) {
    177         if (isGlobal(key) || !mPrefLocal.contains(key)) {
    178             return mPrefGlobal.getLong(key, defValue);
    179         } else {
    180             return mPrefLocal.getLong(key, defValue);
    181         }
    182     }
    183 
    184     @Override
    185     public float getFloat(String key, float defValue) {
    186         if (isGlobal(key) || !mPrefLocal.contains(key)) {
    187             return mPrefGlobal.getFloat(key, defValue);
    188         } else {
    189             return mPrefLocal.getFloat(key, defValue);
    190         }
    191     }
    192 
    193     @Override
    194     public boolean getBoolean(String key, boolean defValue) {
    195         if (isGlobal(key) || !mPrefLocal.contains(key)) {
    196             return mPrefGlobal.getBoolean(key, defValue);
    197         } else {
    198             return mPrefLocal.getBoolean(key, defValue);
    199         }
    200     }
    201 
    202     // This method is not used.
    203     @Override
    204     public Set<String> getStringSet(String key, Set<String> defValues) {
    205         throw new UnsupportedOperationException();
    206     }
    207 
    208     @Override
    209     public boolean contains(String key) {
    210         return mPrefLocal.contains(key) || mPrefGlobal.contains(key);
    211     }
    212 
    213     private class MyEditor implements Editor {
    214         private Editor mEditorGlobal;
    215         private Editor mEditorLocal;
    216 
    217         MyEditor() {
    218             mEditorGlobal = mPrefGlobal.edit();
    219             mEditorLocal = mPrefLocal.edit();
    220         }
    221 
    222         @Override
    223         public boolean commit() {
    224             boolean result1 = mEditorGlobal.commit();
    225             boolean result2 = mEditorLocal.commit();
    226             return result1 && result2;
    227         }
    228 
    229         @Override
    230         public void apply() {
    231             mEditorGlobal.apply();
    232             mEditorLocal.apply();
    233         }
    234 
    235         // Note: clear() and remove() affects both local and global preferences.
    236         @Override
    237         public Editor clear() {
    238             mEditorGlobal.clear();
    239             mEditorLocal.clear();
    240             return this;
    241         }
    242 
    243         @Override
    244         public Editor remove(String key) {
    245             mEditorGlobal.remove(key);
    246             mEditorLocal.remove(key);
    247             return this;
    248         }
    249 
    250         @Override
    251         public Editor putString(String key, String value) {
    252             if (isGlobal(key)) {
    253                 mEditorGlobal.putString(key, value);
    254             } else {
    255                 mEditorLocal.putString(key, value);
    256             }
    257             return this;
    258         }
    259 
    260         @Override
    261         public Editor putInt(String key, int value) {
    262             if (isGlobal(key)) {
    263                 mEditorGlobal.putInt(key, value);
    264             } else {
    265                 mEditorLocal.putInt(key, value);
    266             }
    267             return this;
    268         }
    269 
    270         @Override
    271         public Editor putLong(String key, long value) {
    272             if (isGlobal(key)) {
    273                 mEditorGlobal.putLong(key, value);
    274             } else {
    275                 mEditorLocal.putLong(key, value);
    276             }
    277             return this;
    278         }
    279 
    280         @Override
    281         public Editor putFloat(String key, float value) {
    282             if (isGlobal(key)) {
    283                 mEditorGlobal.putFloat(key, value);
    284             } else {
    285                 mEditorLocal.putFloat(key, value);
    286             }
    287             return this;
    288         }
    289 
    290         @Override
    291         public Editor putBoolean(String key, boolean value) {
    292             if (isGlobal(key)) {
    293                 mEditorGlobal.putBoolean(key, value);
    294             } else {
    295                 mEditorLocal.putBoolean(key, value);
    296             }
    297             return this;
    298         }
    299 
    300         // This method is not used.
    301         @Override
    302         public Editor putStringSet(String key, Set<String> values) {
    303             throw new UnsupportedOperationException();
    304         }
    305     }
    306 
    307     // Note the remove() and clear() of the returned Editor may not work as
    308     // expected because it doesn't touch the global preferences at all.
    309     @Override
    310     public Editor edit() {
    311         return new MyEditor();
    312     }
    313 
    314     @Override
    315     public void registerOnSharedPreferenceChangeListener(
    316             OnSharedPreferenceChangeListener listener) {
    317         mListeners.add(listener);
    318     }
    319 
    320     @Override
    321     public void unregisterOnSharedPreferenceChangeListener(
    322             OnSharedPreferenceChangeListener listener) {
    323         mListeners.remove(listener);
    324     }
    325 
    326     @Override
    327     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
    328             String key) {
    329         for (OnSharedPreferenceChangeListener listener : mListeners) {
    330             listener.onSharedPreferenceChanged(this, key);
    331         }
    332         BackupManager.dataChanged(mPackageName);
    333         UsageStatistics.onEvent("CameraSettingsChange", null, key);
    334     }
    335 }
    336