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