• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import com.android.camera.util.UsageStatistics;
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 
ComboPreferences(Context context)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 
get(Context context)65     public static ComboPreferences get(Context context) {
66         synchronized (sMap) {
67             return sMap.get(context);
68         }
69     }
70 
getLocalSharedPreferencesName( Context context, int cameraId)71     private static String getLocalSharedPreferencesName(
72             Context context, int cameraId) {
73         return context.getPackageName() + "_preferences_" + cameraId;
74     }
75 
getGlobalSharedPreferencesName(Context context)76     private static String getGlobalSharedPreferencesName(Context context) {
77         return context.getPackageName() + "_preferences_camera";
78     }
79 
movePrefFrom( Map<String, ?> m, String key, SharedPreferences src)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 
moveGlobalPrefsFrom(SharedPreferences src)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 
getSharedPreferencesNames(Context context)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.
setLocalId(Context context, int cameraId)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 
getGlobal()132     public SharedPreferences getGlobal() {
133         return mPrefGlobal;
134     }
135 
getLocal()136     public SharedPreferences getLocal() {
137         return mPrefLocal;
138     }
139 
140     @Override
getAll()141     public Map<String, ?> getAll() {
142         throw new UnsupportedOperationException(); // Can be implemented if needed.
143     }
144 
isGlobal(String key)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
getString(String key, String defValue)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
getInt(String key, int defValue)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
getLong(String key, long defValue)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
getFloat(String key, float defValue)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
getBoolean(String key, boolean defValue)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
getStringSet(String key, Set<String> defValues)204     public Set<String> getStringSet(String key, Set<String> defValues) {
205         throw new UnsupportedOperationException();
206     }
207 
208     @Override
contains(String key)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 
MyEditor()217         MyEditor() {
218             mEditorGlobal = mPrefGlobal.edit();
219             mEditorLocal = mPrefLocal.edit();
220         }
221 
222         @Override
commit()223         public boolean commit() {
224             boolean result1 = mEditorGlobal.commit();
225             boolean result2 = mEditorLocal.commit();
226             return result1 && result2;
227         }
228 
229         @Override
apply()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
clear()237         public Editor clear() {
238             mEditorGlobal.clear();
239             mEditorLocal.clear();
240             return this;
241         }
242 
243         @Override
remove(String key)244         public Editor remove(String key) {
245             mEditorGlobal.remove(key);
246             mEditorLocal.remove(key);
247             return this;
248         }
249 
250         @Override
putString(String key, String value)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
putInt(String key, int value)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
putLong(String key, long value)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
putFloat(String key, float value)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
putBoolean(String key, boolean value)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
putStringSet(String key, Set<String> values)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
edit()310     public Editor edit() {
311         return new MyEditor();
312     }
313 
314     @Override
registerOnSharedPreferenceChangeListener( OnSharedPreferenceChangeListener listener)315     public void registerOnSharedPreferenceChangeListener(
316             OnSharedPreferenceChangeListener listener) {
317         mListeners.add(listener);
318     }
319 
320     @Override
unregisterOnSharedPreferenceChangeListener( OnSharedPreferenceChangeListener listener)321     public void unregisterOnSharedPreferenceChangeListener(
322             OnSharedPreferenceChangeListener listener) {
323         mListeners.remove(listener);
324     }
325 
326     @Override
onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)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     }
334 }
335