blob: 142f6984c3a988e423ddfac4463fb0a53fc2e7d7 [file] [log] [blame]
Michael Kolb8872c232013-01-29 10:33:22 -08001/*
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
17package com.android.camera;
18
19import android.app.backup.BackupManager;
20import android.content.Context;
21import android.content.SharedPreferences;
22import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
23import android.preference.PreferenceManager;
24
25import java.util.Map;
26import java.util.Set;
27import java.util.WeakHashMap;
28import java.util.concurrent.CopyOnWriteArrayList;
29
Sascha Haeberling8e963a52013-08-06 11:43:02 -070030import com.android.camera.util.UsageStatistics;
31
Michael Kolb8872c232013-01-29 10:33:22 -080032public class ComboPreferences implements
33 SharedPreferences,
34 OnSharedPreferenceChangeListener {
35 private SharedPreferences mPrefGlobal; // global preferences
36 private SharedPreferences mPrefLocal; // per-camera preferences
Doris Liu4e72c902013-02-07 12:32:42 -080037 private String mPackageName;
Michael Kolb8872c232013-01-29 10:33:22 -080038 private CopyOnWriteArrayList<OnSharedPreferenceChangeListener> mListeners;
Doris Liu4e72c902013-02-07 12:32:42 -080039 // TODO: Remove this WeakHashMap in the camera code refactoring
Michael Kolb8872c232013-01-29 10:33:22 -080040 private static WeakHashMap<Context, ComboPreferences> sMap =
41 new WeakHashMap<Context, ComboPreferences>();
42
43 public ComboPreferences(Context context) {
Doris Liu4e72c902013-02-07 12:32:42 -080044 mPackageName = context.getPackageName();
Michael Kolb8872c232013-01-29 10:33:22 -080045 mPrefGlobal = context.getSharedPreferences(
46 getGlobalSharedPreferencesName(context), Context.MODE_PRIVATE);
47 mPrefGlobal.registerOnSharedPreferenceChangeListener(this);
48
49 synchronized (sMap) {
50 sMap.put(context, this);
51 }
Michael Kolb8872c232013-01-29 10:33:22 -080052 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)
Angus Kong1580df62013-03-15 17:32:59 -0700153 || key.equals(CameraSettings.KEY_TIMER_SOUND_EFFECTS)
154 || key.equals(CameraSettings.KEY_PHOTOSPHERE_PICTURESIZE);
Michael Kolb8872c232013-01-29 10:33:22 -0800155 }
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) {
Bobby Georgescu806e78b2013-04-01 14:31:40 -0700210 return mPrefLocal.contains(key) || mPrefGlobal.contains(key);
Michael Kolb8872c232013-01-29 10:33:22 -0800211 }
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 }
Doris Liu4e72c902013-02-07 12:32:42 -0800332 BackupManager.dataChanged(mPackageName);
Bobby Georgescu806e78b2013-04-01 14:31:40 -0700333 UsageStatistics.onEvent("CameraSettingsChange", null, key);
Michael Kolb8872c232013-01-29 10:33:22 -0800334 }
335}