2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.camera.settings;
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
22 import android.preference.PreferenceManager;
23 import android.util.Log;
24 import android.util.SparseArray;
26 import com.android.camera.ListPreference;
27 import com.android.camera.app.AppController;
28 import com.android.camera.app.LocationManager;
29 import com.android.camera.util.CameraUtil;
30 import com.android.camera.util.SettingsHelper;
31 import com.android.camera2.R;
33 import java.util.ArrayList;
34 import java.util.List;
37 * SettingsManager class provides an api for getting and setting both global and
38 * local SharedPreferences.
40 public class SettingsManager {
41 private static final String TAG = "SettingsManager";
43 private final Context mContext;
44 private final SharedPreferences mDefaultSettings;
45 private final SettingsCache mSettingsCache;
46 private SharedPreferences mGlobalSettings;
47 private SharedPreferences mCameraSettings;
48 private final SparseArray<SharedPreferences> mModuleSettings = new SparseArray<SharedPreferences>();
49 private SettingsCapabilities mCapabilities;
51 private int mCameraId = -1;
52 private final AppController mAppController;
55 * General settings upgrade model:
57 * On app upgrade, there are three main ways Settings can be stale/incorrect:
58 * (1) if the type of a setting has changed.
59 * (2) if a set value is no longer a member of the set of possible values.
60 * (3) if the SharedPreferences backing file has changed for a setting.
62 * Recovery strategies:
63 * (1) catch the ClassCastException or NumberFormatException and try to do a
64 * type conversion, or reset the setting to whatever default is valid.
65 * (2) sanitize sets, and reset to default if set value is no longer valid.
66 * (3) use the default value by virtue of the setting not yet being in the
71 * There are some settings which shouldn't be reset to default on upgrade if
72 * possible. We provide a callback which is executed only on strict upgrade.
73 * This callback does special case upgrades to a subset of the settings. This
74 * contrasts with the general upgrade strategies, which happen lazily, once a
77 * Removing obsolete key/value pairs:
79 * This can be done in the strict upgrade callback. The strict upgrade callback
80 * should be idempotent, so it is important to leave removal code in the upgrade
81 * callback so the key/value pairs are removed even if a user skips a version.
83 public interface StrictUpgradeCallback {
85 * Will be executed in the SettingsManager constructor if the strict
86 * upgrade version counter has changed.
88 public void upgrade(SettingsManager settingsManager, int version);
92 * Increment this value whenever a new StrictUpgradeCallback needs to
93 * be executed. This defines upgrade behavior that should be executed
94 * strictly on app upgrades, when the upgrade behavior differs from the general,
95 * lazy upgrade strategies.
97 private static final int STRICT_UPGRADE_VERSION = 1;
100 * A List of OnSettingChangedListener's, maintained to compare to new
101 * listeners and prevent duplicate registering.
103 private final List<OnSettingChangedListener> mListeners = new ArrayList<OnSettingChangedListener>();
106 * A List of OnSharedPreferenceChangeListener's, maintained to hold pointers
107 * to actually registered listeners, so they can be unregistered.
109 private final List<OnSharedPreferenceChangeListener> mSharedPreferenceListeners = new ArrayList<OnSharedPreferenceChangeListener>();
111 public SettingsManager(Context context, AppController app, int nCameras,
112 StrictUpgradeCallback upgradeCallback) {
114 mAppController = app;
116 SettingsCache.ExtraSettings extraSettings = new SettingsHelper();
117 mSettingsCache = new SettingsCache(mContext, extraSettings);
119 mDefaultSettings = PreferenceManager.getDefaultSharedPreferences(context);
122 if (upgradeCallback != null) {
123 // Check for a strict version upgrade.
124 int version = getInt(SETTING_STRICT_UPGRADE_VERSION);
125 if (STRICT_UPGRADE_VERSION != version) {
126 upgradeCallback.upgrade(this, STRICT_UPGRADE_VERSION);
128 setInt(SETTING_STRICT_UPGRADE_VERSION, STRICT_UPGRADE_VERSION);
133 * Initialize global SharedPreferences.
135 private void initGlobal() {
136 String globalKey = mContext.getPackageName() + "_preferences_camera";
137 mGlobalSettings = mContext.getSharedPreferences(globalKey, Context.MODE_PRIVATE);
141 * Load and cache a module specific SharedPreferences.
143 public SharedPreferences getModulePreferences(int modeIndex) {
144 SharedPreferences sharedPreferences = mModuleSettings.get(modeIndex);
145 if (sharedPreferences == null) {
146 String moduleKey = mContext.getPackageName() + "_preferences_module_" + modeIndex;
147 sharedPreferences = mContext.getSharedPreferences(moduleKey, Context.MODE_PRIVATE);
148 mModuleSettings.put(modeIndex, sharedPreferences);
150 return sharedPreferences;
154 * Initialize SharedPreferences for other cameras.
156 public void changeCamera(int cameraId, SettingsCapabilities capabilities) {
157 mCapabilities = capabilities;
158 mSettingsCache.setCapabilities(mCapabilities);
160 if (cameraId == mCameraId) {
164 // We've changed camera ids, that means we need to flush the
165 // settings cache of settings dependent on SettingsCapabilities.
166 mSettingsCache.flush();
168 // Cache the camera id so we don't need to reload preferences
169 // if we're using the same camera.
170 mCameraId = cameraId;
172 String cameraKey = mContext.getPackageName() + "_preferences_" + cameraId;
173 mCameraSettings = mContext.getSharedPreferences(
174 cameraKey, Context.MODE_PRIVATE);
176 for (OnSharedPreferenceChangeListener listener : mSharedPreferenceListeners) {
177 mCameraSettings.registerOnSharedPreferenceChangeListener(listener);
182 * Interface with Camera Parameters and Modules.
184 public interface OnSettingChangedListener {
186 * Called every time a SharedPreference has been changed.
188 public void onSettingChanged(SettingsManager settingsManager, int setting);
191 private OnSharedPreferenceChangeListener getSharedPreferenceListener(
192 final OnSettingChangedListener listener) {
193 return new OnSharedPreferenceChangeListener() {
195 public void onSharedPreferenceChanged(
196 SharedPreferences sharedPreferences, String key) {
197 Integer settingId = mSettingsCache.getId(key);
198 if (settingId != null) {
199 listener.onSettingChanged(SettingsManager.this, settingId);
201 Log.w(TAG, "Setting id from key=" + key + " is null");
208 * Add an OnSettingChangedListener to the SettingsManager, which will
209 * execute onSettingsChanged when any SharedPreference has been updated.
211 public void addListener(final OnSettingChangedListener listener) {
212 if (listener == null) {
213 throw new IllegalArgumentException("OnSettingChangedListener cannot be null.");
216 if (mListeners.contains(listener)) {
220 mListeners.add(listener);
221 OnSharedPreferenceChangeListener sharedPreferenceListener =
222 getSharedPreferenceListener(listener);
223 mSharedPreferenceListeners.add(sharedPreferenceListener);
225 if (mGlobalSettings != null) {
226 mGlobalSettings.registerOnSharedPreferenceChangeListener(sharedPreferenceListener);
229 if (mCameraSettings != null) {
230 mCameraSettings.registerOnSharedPreferenceChangeListener(sharedPreferenceListener);
233 if (mDefaultSettings != null) {
234 mDefaultSettings.registerOnSharedPreferenceChangeListener(sharedPreferenceListener);
239 * Remove a specific SettingsListener. This should be done in onPause if a
240 * listener has been set.
242 public void removeListener(OnSettingChangedListener listener) {
243 if (listener == null) {
244 throw new IllegalArgumentException();
247 if (!mListeners.contains(listener)) {
251 int index = mListeners.indexOf(listener);
252 mListeners.remove(listener);
254 // Get the reference to the actual OnSharedPreferenceChangeListener
255 // that was registered.
256 OnSharedPreferenceChangeListener sharedPreferenceListener =
257 mSharedPreferenceListeners.get(index);
258 mSharedPreferenceListeners.remove(index);
260 if (mGlobalSettings != null) {
261 mGlobalSettings.unregisterOnSharedPreferenceChangeListener(
262 sharedPreferenceListener);
265 if (mCameraSettings != null) {
266 mCameraSettings.unregisterOnSharedPreferenceChangeListener(
267 sharedPreferenceListener);
270 if (mDefaultSettings != null) {
271 mDefaultSettings.unregisterOnSharedPreferenceChangeListener(
272 sharedPreferenceListener);
277 * Remove all OnSharedPreferenceChangedListener's. This should be done in
280 public void removeAllListeners() {
281 for (OnSharedPreferenceChangeListener listener : mSharedPreferenceListeners) {
282 if (mGlobalSettings != null) {
283 mGlobalSettings.unregisterOnSharedPreferenceChangeListener(listener);
286 if (mCameraSettings != null) {
287 mCameraSettings.unregisterOnSharedPreferenceChangeListener(listener);
290 if (mDefaultSettings != null) {
291 mDefaultSettings.unregisterOnSharedPreferenceChangeListener(listener);
294 mSharedPreferenceListeners.clear();
299 * SettingsCapabilities defines constraints around settings that need to be
300 * queried from external sources, like the camera parameters. This interface
301 * is camera api agnostic.
303 public interface SettingsCapabilities {
305 * Returns a dynamically calculated list of exposure values, based on
306 * the min and max exposure compensation supported by the camera device.
308 public String[] getSupportedExposureValues();
311 * Returns a list of camera ids based on the number of cameras available
314 public String[] getSupportedCameraIds();
318 * Get the camera id for which the SettingsManager has loaded camera
319 * specific preferences.
321 public int getRegisteredCameraId() {
325 // Manage individual settings.
326 public static final String VALUE_NONE = "none";
327 public static final String VALUE_ON = "on";
328 public static final String VALUE_OFF = "off";
330 public static final String TYPE_STRING = "string";
331 public static final String TYPE_BOOLEAN = "boolean";
332 public static final String TYPE_INTEGER = "integer";
334 public static final String SOURCE_DEFAULT = "default";
335 public static final String SOURCE_GLOBAL = "global";
336 public static final String SOURCE_CAMERA = "camera";
337 public static final String SOURCE_MODULE = "module";
339 public static final boolean FLUSH_ON = true;
340 public static final boolean FLUSH_OFF = false;
342 // For quick lookup from id to Setting.
343 public static final int SETTING_RECORD_LOCATION = 0;
344 public static final int SETTING_VIDEO_QUALITY = 1;
345 public static final int SETTING_VIDEO_TIME_LAPSE_FRAME_INTERVAL = 2;
346 public static final int SETTING_PICTURE_SIZE = 3;
347 public static final int SETTING_JPEG_QUALITY = 4;
348 public static final int SETTING_FOCUS_MODE = 5;
349 public static final int SETTING_FLASH_MODE = 6;
350 public static final int SETTING_VIDEOCAMERA_FLASH_MODE = 7;
351 public static final int SETTING_WHITE_BALANCE = 8;
352 public static final int SETTING_SCENE_MODE = 9;
353 public static final int SETTING_EXPOSURE = 10;
354 public static final int SETTING_TIMER = 11;
355 public static final int SETTING_TIMER_SOUND_EFFECTS = 12;
356 public static final int SETTING_VIDEO_EFFECT = 13;
357 public static final int SETTING_CAMERA_ID = 14;
358 public static final int SETTING_CAMERA_HDR = 15;
359 public static final int SETTING_CAMERA_HDR_PLUS = 16;
360 public static final int SETTING_CAMERA_FIRST_USE_HINT_SHOWN = 17;
361 public static final int SETTING_VIDEO_FIRST_USE_HINT_SHOWN = 18;
362 public static final int SETTING_STARTUP_MODULE_INDEX = 19;
363 public static final int SETTING_SHIMMY_REMAINING_PLAY_TIMES_INDEX = 20;
364 public static final int SETTING_KEY_CAMERA_MODULE_LAST_USED_INDEX = 21;
365 public static final int SETTING_CAMERA_PANO_ORIENTATION = 22;
366 public static final int SETTING_CAMERA_GRID_LINES = 23;
367 public static final int SETTING_RELEASE_DIALOG_LAST_SHOWN_VERSION = 24;
368 public static final int SETTING_FLASH_SUPPORTED_BACK_CAMERA = 25;
369 public static final int SETTING_STRICT_UPGRADE_VERSION = 26;
370 public static final int SETTING_FILMSTRIP_PEEK_ANIM_REMAINING_PLAY_TIMES_INDEX = 27;
371 // A boolean for requesting to return to HDR plus
372 // as soon as possible, if a user requests a setting/mode option
373 // that forces them to leave HDR plus.
374 public static final int SETTING_REQUEST_RETURN_HDR_PLUS = 28;
376 // Shared preference keys.
377 public static final String KEY_RECORD_LOCATION = "pref_camera_recordlocation_key";
378 public static final String KEY_VIDEO_QUALITY = "pref_video_quality_key";
379 public static final String KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL =
380 "pref_video_time_lapse_frame_interval_key";
381 public static final String KEY_PICTURE_SIZE = "pref_camera_picturesize_key";
382 public static final String KEY_JPEG_QUALITY = "pref_camera_jpegquality_key";
383 public static final String KEY_FOCUS_MODE = "pref_camera_focusmode_key";
384 public static final String KEY_FLASH_MODE = "pref_camera_flashmode_key";
385 public static final String KEY_VIDEOCAMERA_FLASH_MODE = "pref_camera_video_flashmode_key";
386 public static final String KEY_WHITE_BALANCE = "pref_camera_whitebalance_key";
387 public static final String KEY_SCENE_MODE = "pref_camera_scenemode_key";
388 public static final String KEY_EXPOSURE = "pref_camera_exposure_key";
389 public static final String KEY_TIMER = "pref_camera_timer_key";
390 public static final String KEY_TIMER_SOUND_EFFECTS = "pref_camera_timer_sound_key";
391 public static final String KEY_VIDEO_EFFECT = "pref_video_effect_key";
392 public static final String KEY_CAMERA_ID = "pref_camera_id_key";
393 public static final String KEY_CAMERA_HDR = "pref_camera_hdr_key";
394 public static final String KEY_CAMERA_HDR_PLUS = "pref_camera_hdr_plus_key";
395 public static final String KEY_CAMERA_FIRST_USE_HINT_SHOWN =
396 "pref_camera_first_use_hint_shown_key";
397 public static final String KEY_VIDEO_FIRST_USE_HINT_SHOWN =
398 "pref_video_first_use_hint_shown_key";
399 public static final String KEY_STARTUP_MODULE_INDEX = "camera.startup_module";
400 public static final String KEY_SHIMMY_REMAINING_PLAY_TIMES =
401 "pref_shimmy_remaining_play_times";
402 public static final String KEY_CAMERA_MODULE_LAST_USED =
403 "pref_camera_module_last_used_index";
404 public static final String KEY_CAMERA_PANO_ORIENTATION = "pref_camera_pano_orientation";
405 public static final String KEY_CAMERA_GRID_LINES = "pref_camera_grid_lines";
406 public static final String KEY_RELEASE_DIALOG_LAST_SHOWN_VERSION =
407 "pref_release_dialog_last_shown_version";
408 public static final String KEY_FLASH_SUPPORTED_BACK_CAMERA =
409 "pref_flash_supported_back_camera";
410 public static final String KEY_STRICT_UPGRADE_VERSION = "pref_strict_upgrade_version";
411 public static final String KEY_FILMSTRIP_PEEK_ANIM_REMAINING_PLAY_TIMES =
412 "pref_filmstrip_peek_anim_remaining_play_times";
413 public static final String KEY_REQUEST_RETURN_HDR_PLUS = "pref_request_return_hdr_plus";
415 public static final int WHITE_BALANCE_DEFAULT_INDEX = 2;
418 * Defines a simple class for holding a the spec of a setting. This spec is
419 * used by the generic api methods to query and update a setting.
421 public static class Setting {
422 private final String mSource;
423 private final String mType;
424 private final String mDefault;
425 private final String mKey;
426 private final String[] mValues;
427 private final boolean mFlushOnCameraChange;
430 * A constructor used to store a setting's profile.
432 Setting(String source, String type, String defaultValue, String key,
433 String[] values, boolean flushOnCameraChange) {
436 mDefault = defaultValue;
439 mFlushOnCameraChange = flushOnCameraChange;
443 * Returns the id of a SharedPreferences instance from which this
444 * Setting may be found. Possible values are {@link #SOURCE_DEFAULT},
445 * {@link #SOURCE_GLOBAL}, {@link #SOURCE_CAMERA}.
447 public String getSource() {
452 * Returns the type of the setting stored in SharedPreferences. Possible
453 * values are {@link #TYPE_STRING}, {@link #TYPE_INTEGER},
454 * {@link #TYPE_BOOLEAN}.
456 public String getType() {
461 * Returns the default value of this setting.
463 public String getDefault() {
468 * Returns the SharedPreferences key for this setting.
470 public String getKey() {
475 * Returns an array of possible String values for this setting. If this
476 * setting is not of type {@link #TYPE_STRING}, or it's not possible to
477 * generate the string values, this should return null;
479 public String[] getStringValues() {
484 * Returns whether the setting should be flushed from the cache when the
485 * camera device has changed.
487 public boolean isFlushedOnCameraChanged() {
488 return mFlushOnCameraChange;
493 * Get the SharedPreferences needed to query/update the setting.
495 public SharedPreferences getSettingSource(Setting setting) {
496 String source = setting.getSource();
497 if (source.equals(SOURCE_DEFAULT)) {
498 return mDefaultSettings;
500 if (source.equals(SOURCE_GLOBAL)) {
501 return mGlobalSettings;
503 if (source.equals(SOURCE_CAMERA)) {
504 return mCameraSettings;
506 if (source.equals(SOURCE_MODULE)) {
507 int modeIndex = CameraUtil.getCameraModeParentModeId(
508 mAppController.getCurrentModuleIndex(), mAppController.getAndroidContext());
509 return getModulePreferences(modeIndex);
515 * Based on Setting id, finds the index of a Setting's String value in an
516 * array of possible String values. If the Setting is not of type String,
519 * TODO: make this a supported api call for all types.
522 public int getStringValueIndex(int id) {
523 Setting setting = mSettingsCache.get(id);
524 if (setting == null || !TYPE_STRING.equals(setting.getType())) {
527 return getStringValueIndex(setting.getStringValues(), get(id));
530 private int getStringValueIndex(String[] possibleValues, String value) {
532 if (possibleValues != null) {
533 for (int i = 0; i < possibleValues.length; i++) {
534 if (value.equals(possibleValues[i])) {
544 * Based on Setting id, sets a Setting's String value using the index into
545 * an array of possible String values. Fails to set a value if the index is
546 * out of bounds or the Setting is not of type String.
548 * @return Whether the value was set.
550 public boolean setStringValueIndex(int id, int index) {
551 Setting setting = mSettingsCache.get(id);
552 if (setting == null || setting.getType() != TYPE_STRING) {
556 String[] possibleValues = setting.getStringValues();
557 if (possibleValues != null) {
558 if (index >= 0 && index < possibleValues.length) {
559 set(id, possibleValues[index]);
567 * Returns whether this Setting was last set as a String.
569 private boolean isString(int id) {
570 Setting setting = mSettingsCache.get(id);
571 SharedPreferences preferences = getSettingSource(setting);
573 preferences.getString(setting.getKey(), null);
575 } catch (ClassCastException e) {
581 * Returns whether this Setting was last set as a boolean.
583 private boolean isBoolean(int id) {
584 Setting setting = mSettingsCache.get(id);
585 SharedPreferences preferences = getSettingSource(setting);
587 preferences.getBoolean(setting.getKey(), false);
589 } catch (ClassCastException e) {
595 * Returns whether this Setting was last set as an Integer.
597 private boolean isInteger(int id) {
598 Setting setting = mSettingsCache.get(id);
599 SharedPreferences preferences = getSettingSource(setting);
601 preferences.getInt(setting.getKey(), 0);
603 } catch (NumberFormatException e) {
609 * Recover a Setting by converting it to a String if the type
610 * is known and the type conversion is successful, otherwise
611 * reset to the default.
613 private String recoverToString(int id) {
617 value = (getBoolean(id) ? VALUE_ON : VALUE_OFF);
618 } else if (isInteger(id)) {
619 value = Integer.toString(getInt(id));
621 throw new Exception();
623 } catch (Exception e) {
624 value = mSettingsCache.get(id).getDefault();
631 * Recover a Setting by converting it to a boolean if the type
632 * is known and the type conversion is successful, otherwise
633 * reset to the default.
635 private boolean recoverToBoolean(int id) {
639 value = VALUE_ON.equals(get(id));
640 } else if (isInteger(id)) {
641 value = getInt(id) != 0;
643 throw new Exception();
645 } catch (Exception e) {
646 value = VALUE_ON.equals(mSettingsCache.get(id).getDefault());
648 setBoolean(id, value);
653 * Recover a Setting by converting it to an Integer if the type
654 * is known and the type conversion is successful, otherwise
655 * reset to the default.
657 private int recoverToInteger(int id) {
661 value = Integer.parseInt(get(id));
662 } else if (isBoolean(id)) {
663 value = getBoolean(id) ? 1 : 0;
665 throw new Exception();
667 } catch (Exception e) {
668 value = Integer.parseInt(mSettingsCache.get(id).getDefault());
675 * Check if a String value is in the set of possible values for a Setting.
676 * We only keep track of possible values for String types for now.
678 private String sanitize(Setting setting, String value) {
679 if (setting.getStringValues() != null &&
680 getStringValueIndex(setting.getStringValues(), value) < 0) {
681 // If the set of possible values is not empty, and the value
682 // is not in the set of possible values, use the default, because
683 // the set of possible values probably changed.
684 return setting.getDefault();
690 * Get a Setting's String value based on Setting id.
692 // TODO: rename to something more descriptive.
693 public String get(int id) {
694 Setting setting = mSettingsCache.get(id);
695 if (!TYPE_STRING.equals(setting.getType())) {
696 // Incorrect use of the api, the defaults will
697 // probably be defined as the wrong type, no recovery.
698 throw new IllegalArgumentException(
699 "Trying to get String when Setting id=" + id
700 + " is defined as a " + setting.getType());
703 SharedPreferences preferences = getSettingSource(setting);
704 if (preferences != null) {
706 String value = preferences.getString(setting.getKey(), setting.getDefault());
707 return sanitize(setting, value);
708 } catch (ClassCastException e) {
709 // If the api defines this Setting as a String, but the
710 // last set saved it as a different type, try to recover
711 // the value, but if impossible reset to default.
712 return recoverToString(id);
715 throw new IllegalStateException(
716 "Setting source=" + setting.getSource() + " is unitialized.");
721 * Get a Setting's boolean value based on Setting id.
723 public boolean getBoolean(int id) {
724 Setting setting = mSettingsCache.get(id);
725 if (!TYPE_BOOLEAN.equals(setting.getType())) {
726 // Incorrect use of the api, the defaults will
727 // probably be defined as the wrong type, no recovery.
728 throw new IllegalArgumentException(
729 "Trying to get boolean when Setting id=" + id
730 + " is defined as a " + setting.getType());
733 SharedPreferences preferences = getSettingSource(setting);
734 boolean defaultValue = VALUE_ON.equals(setting.getDefault());
735 if (preferences != null) {
737 return preferences.getBoolean(setting.getKey(), defaultValue);
738 } catch (ClassCastException e) {
739 // If the api defines this Setting as a boolean, but the
740 // last set saved it as a different type, try to recover
741 // the value, but if impossible reset to default.
742 return recoverToBoolean(id);
745 throw new IllegalStateException(
746 "Setting source=" + setting.getSource() + " is unitialized.");
751 * Get a Setting's int value based on Setting id.
753 public int getInt(int id) {
754 Setting setting = mSettingsCache.get(id);
755 if (!TYPE_INTEGER.equals(setting.getType())) {
756 // Incorrect use of the api, the defaults will
757 // probably be defined as the wrong type, no recovery.
758 throw new IllegalArgumentException(
759 "Trying to get Integer when Setting id=" + id
760 + " is defined as a " + setting.getType());
763 SharedPreferences preferences = getSettingSource(setting);
764 int defaultValue = Integer.parseInt(setting.getDefault());
765 if (preferences != null) {
767 return preferences.getInt(setting.getKey(), defaultValue);
768 } catch (NumberFormatException e) {
769 // If the api defines this Setting as an Integer, but the
770 // last set saved it as a different type, try to recover
771 // the value, but if impossible reset to default.
772 return recoverToInteger(id);
775 throw new IllegalStateException(
776 "Setting source=" + setting.getSource() + " is unitialized.");
781 * Set a Setting with a String value based on Setting id.
783 // TODO: rename to something more descriptive.
784 public void set(int id, String value) {
785 Setting setting = mSettingsCache.get(id);
786 value = sanitize(setting, value);
787 SharedPreferences preferences = getSettingSource(setting);
788 if (preferences != null) {
789 preferences.edit().putString(setting.getKey(), value).apply();
791 throw new IllegalStateException(
792 "Setting source=" + setting.getSource() + " is unitialized.");
797 * Set a Setting with a boolean value based on Setting id.
799 public void setBoolean(int id, boolean value) {
800 Setting setting = mSettingsCache.get(id);
801 SharedPreferences preferences = getSettingSource(setting);
802 if (preferences != null) {
803 preferences.edit().putBoolean(setting.getKey(), value).apply();
805 throw new IllegalStateException(
806 "Setting source=" + setting.getSource() + " is unitialized.");
811 * Set a Setting with an int value based on Setting id.
813 public void setInt(int id, int value) {
814 Setting setting = mSettingsCache.get(id);
815 SharedPreferences preferences = getSettingSource(setting);
816 if (preferences != null) {
817 preferences.edit().putInt(setting.getKey(), value).apply();
819 throw new IllegalStateException(
820 "Setting source=" + setting.getSource() + " is unitialized.");
825 * Check if a Setting has ever been set based on Setting id.
827 public boolean isSet(int id) {
828 Setting setting = mSettingsCache.get(id);
829 SharedPreferences preferences = getSettingSource(setting);
830 if (preferences != null) {
831 return preferences.contains(setting.getKey());
833 throw new IllegalStateException(
834 "Setting source=" + setting.getSource() + " is unitialized.");
839 * Set a Setting to its default value based on Setting id.
841 public void setDefault(int id) {
842 Setting setting = mSettingsCache.get(id);
843 SharedPreferences preferences = getSettingSource(setting);
844 if (preferences != null) {
845 preferences.edit().putString(setting.getKey(), setting.getDefault());
847 throw new IllegalStateException(
848 "Setting source=" + setting.getSource() + " is unitialized.");
853 * Check if a Setting is set to its default value.
855 public boolean isDefault(int id) {
856 Setting setting = mSettingsCache.get(id);
857 SharedPreferences preferences = getSettingSource(setting);
858 if (preferences != null) {
859 String type = setting.getType();
860 if (TYPE_STRING.equals(type)) {
861 String value = get(id);
862 return (value.equals(setting.getDefault()));
863 } else if (TYPE_BOOLEAN.equals(type)) {
864 boolean value = getBoolean(id);
865 boolean defaultValue = VALUE_ON.equals(setting.getDefault());
866 return (value == defaultValue);
867 } else if (TYPE_INTEGER.equals(type)) {
868 int value = getInt(id);
869 int defaultValue = Integer.parseInt(setting.getDefault());
870 return (value == defaultValue);
872 throw new IllegalArgumentException("Type " + type + " is not known.");
875 throw new IllegalStateException(
876 "Setting source=" + setting.getSource() + " is unitialized.");
881 * Remove a Setting from SharedPreferences.
883 public void remove(int id) {
884 Setting setting = mSettingsCache.get(id);
885 SharedPreferences preferences = getSettingSource(setting);
886 if (preferences != null) {
887 preferences.edit().remove(setting.getKey()).apply();
889 throw new IllegalStateException(
890 "Setting source=" + setting.getSource() + " is unitialized.");
894 public static Setting getLocationSetting(Context context) {
895 String defaultValue = context.getString(R.string.setting_none_value);
896 String[] values = null;
897 return new Setting(SOURCE_DEFAULT, TYPE_BOOLEAN, defaultValue, KEY_RECORD_LOCATION,
901 public static Setting getPictureSizeSetting(Context context) {
902 String defaultValue = null;
903 String[] values = context.getResources().getStringArray(
904 R.array.pref_camera_picturesize_entryvalues);
905 return new Setting(SOURCE_DEFAULT, TYPE_STRING, defaultValue, KEY_PICTURE_SIZE,
909 public static Setting getDefaultCameraIdSetting(Context context,
910 SettingsCapabilities capabilities) {
911 String defaultValue = context.getString(R.string.pref_camera_id_default);
912 String[] values = null;
913 if (capabilities != null) {
914 values = capabilities.getSupportedCameraIds();
916 return new Setting(SOURCE_MODULE, TYPE_STRING, defaultValue, KEY_CAMERA_ID,
920 public static Setting getWhiteBalanceSetting(Context context) {
921 String defaultValue = context.getString(R.string.pref_camera_whitebalance_default);
922 String[] values = context.getResources().getStringArray(
923 R.array.pref_camera_whitebalance_entryvalues);
924 return new Setting(SOURCE_CAMERA, TYPE_STRING, defaultValue, KEY_WHITE_BALANCE,
928 public static Setting getHdrSetting(Context context) {
929 String defaultValue = context.getString(R.string.pref_camera_hdr_default);
930 String[] values = context.getResources().getStringArray(
931 R.array.pref_camera_hdr_entryvalues);
932 return new Setting(SOURCE_GLOBAL, TYPE_STRING, defaultValue, KEY_CAMERA_HDR,
936 public static Setting getHdrPlusSetting(Context context) {
937 String defaultValue = context.getString(R.string.pref_camera_hdr_plus_default);
938 String[] values = context.getResources().getStringArray(
939 R.array.pref_camera_hdr_plus_entryvalues);
940 return new Setting(SOURCE_GLOBAL, TYPE_STRING, defaultValue, KEY_CAMERA_HDR_PLUS,
944 public static Setting getSceneModeSetting(Context context) {
945 String defaultValue = context.getString(R.string.pref_camera_scenemode_default);
946 String[] values = context.getResources().getStringArray(
947 R.array.pref_camera_scenemode_entryvalues);
948 return new Setting(SOURCE_CAMERA, TYPE_STRING, defaultValue, KEY_SCENE_MODE,
952 public static Setting getFlashSetting(Context context) {
953 String defaultValue = context.getString(R.string.pref_camera_flashmode_default);
954 String[] values = context.getResources().getStringArray(
955 R.array.pref_camera_flashmode_entryvalues);
956 return new Setting(SOURCE_CAMERA, TYPE_STRING, defaultValue, KEY_FLASH_MODE,
960 public static Setting getExposureSetting(Context context,
961 SettingsCapabilities capabilities) {
962 String defaultValue = context.getString(R.string.pref_exposure_default);
963 String[] values = null;
964 if (capabilities != null) {
965 values = capabilities.getSupportedExposureValues();
967 return new Setting(SOURCE_CAMERA, TYPE_STRING, defaultValue, KEY_EXPOSURE,
971 public static Setting getHintSetting(Context context) {
972 String defaultValue = context.getString(R.string.setting_on_value);
973 String[] values = null;
974 return new Setting(SOURCE_GLOBAL, TYPE_BOOLEAN, defaultValue,
975 KEY_CAMERA_FIRST_USE_HINT_SHOWN, values, FLUSH_OFF);
978 public static Setting getFocusModeSetting(Context context) {
979 String defaultValue = null;
980 String[] values = context.getResources().getStringArray(
981 R.array.pref_camera_focusmode_entryvalues);
982 return new Setting(SOURCE_CAMERA, TYPE_STRING, defaultValue, KEY_FOCUS_MODE,
986 public static Setting getTimerSetting(Context context) {
987 String defaultValue = context.getString(R.string.pref_camera_timer_default);
988 String[] values = null; // TODO: get the values dynamically.
989 return new Setting(SOURCE_GLOBAL, TYPE_STRING, defaultValue, KEY_TIMER,
993 public static Setting getTimerSoundSetting(Context context) {
994 String defaultValue = context.getString(R.string.pref_camera_timer_sound_default);
995 String[] values = context.getResources().getStringArray(
996 R.array.pref_camera_timer_sound_entryvalues);
997 return new Setting(SOURCE_GLOBAL, TYPE_STRING, defaultValue, KEY_TIMER_SOUND_EFFECTS,
1001 public static Setting getVideoQualitySetting(Context context) {
1002 String defaultValue = context.getString(R.string.pref_video_quality_default);
1003 String[] values = context.getResources().getStringArray(
1004 R.array.pref_video_quality_entryvalues);
1005 return new Setting(SOURCE_DEFAULT, TYPE_STRING, defaultValue, KEY_VIDEO_QUALITY,
1009 public static Setting getTimeLapseFrameIntervalSetting(Context context) {
1010 String defaultValue = context.getString(
1011 R.string.pref_video_time_lapse_frame_interval_default);
1012 String[] values = context.getResources().getStringArray(
1013 R.array.pref_video_time_lapse_frame_interval_entryvalues);
1014 return new Setting(SOURCE_GLOBAL, TYPE_STRING, defaultValue,
1015 KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL, values, FLUSH_OFF);
1018 public static Setting getJpegQualitySetting(Context context) {
1019 String defaultValue = context.getString(
1020 R.string.pref_camera_jpeg_quality_normal);
1021 String[] values = context.getResources().getStringArray(
1022 R.array.pref_camera_jpeg_quality_entryvalues);
1023 return new Setting(SOURCE_CAMERA, TYPE_STRING, defaultValue, KEY_JPEG_QUALITY,
1027 public static Setting getVideoFlashSetting(Context context) {
1028 String defaultValue = context.getString(R.string.pref_camera_video_flashmode_default);
1029 String[] values = context.getResources().getStringArray(
1030 R.array.pref_camera_video_flashmode_entryvalues);
1031 return new Setting(SOURCE_CAMERA, TYPE_STRING, defaultValue,
1032 KEY_VIDEOCAMERA_FLASH_MODE, values, FLUSH_OFF);
1035 public static Setting getVideoEffectSetting(Context context) {
1036 String defaultValue = context.getString(R.string.pref_video_effect_default);
1037 String[] values = context.getResources().getStringArray(
1038 R.array.pref_video_effect_entryvalues);
1039 return new Setting(SOURCE_GLOBAL, TYPE_STRING, defaultValue, KEY_VIDEO_EFFECT,
1043 public static Setting getHintVideoSetting(Context context) {
1044 String defaultValue = context.getString(R.string.setting_on_value);
1045 String[] values = null;
1046 return new Setting(SOURCE_GLOBAL, TYPE_STRING, defaultValue,
1047 KEY_VIDEO_FIRST_USE_HINT_SHOWN, values, FLUSH_OFF);
1050 public static Setting getStartupModuleSetting(Context context) {
1051 String defaultValue = context.getString(R.string.pref_camera_startup_index_default);
1052 String[] values = null;
1053 return new Setting(SOURCE_DEFAULT, TYPE_INTEGER, defaultValue,
1054 KEY_STARTUP_MODULE_INDEX, values, FLUSH_OFF);
1057 public static Setting getShimmyRemainingTimesSetting(Context context) {
1058 String defaultValue = context.getString(R.string.pref_shimmy_play_times);
1059 return new Setting(SOURCE_DEFAULT, TYPE_INTEGER, defaultValue,
1060 KEY_SHIMMY_REMAINING_PLAY_TIMES, null, FLUSH_OFF);
1063 public static Setting getLastUsedCameraModule(Context context) {
1064 String defaultValue = Integer.toString(context.getResources()
1065 .getInteger(R.integer.camera_mode_photo));
1066 return new Setting(SOURCE_DEFAULT, TYPE_INTEGER, defaultValue,
1067 KEY_CAMERA_MODULE_LAST_USED, null, FLUSH_OFF);
1070 public static Setting getPanoOrientationSetting(Context context) {
1071 String defaultValue = context.getString(R.string.pano_orientation_horizontal);
1072 String[] values = context.getResources().getStringArray(
1073 R.array.pref_camera_pano_orientation_entryvalues);
1074 return new Setting(SOURCE_GLOBAL, TYPE_STRING, defaultValue,
1075 KEY_CAMERA_PANO_ORIENTATION, values, FLUSH_OFF);
1078 public static Setting getGridLinesSetting(Context context) {
1079 String defaultValue = context.getString(R.string.setting_off_value);
1080 String[] values = context.getResources().getStringArray(
1081 R.array.pref_camera_gridlines_entryvalues);
1082 return new Setting(SOURCE_GLOBAL, TYPE_STRING, defaultValue,
1083 KEY_CAMERA_GRID_LINES, values, FLUSH_OFF);
1086 public static Setting getReleaseDialogLastShownVersionSetting(Context context) {
1087 return new Setting(SOURCE_DEFAULT, TYPE_STRING, null,
1088 KEY_RELEASE_DIALOG_LAST_SHOWN_VERSION, null, FLUSH_OFF);
1091 public static Setting getFlashSupportedBackCameraSetting(Context context) {
1092 String defaultValue = context.getString(R.string.setting_none_value);
1093 return new Setting(SOURCE_GLOBAL, TYPE_BOOLEAN, defaultValue,
1094 KEY_FLASH_SUPPORTED_BACK_CAMERA, null, FLUSH_OFF);
1097 public static Setting getStrictUpgradeVersionSetting(Context context) {
1098 String defaultValue = "0";
1099 return new Setting(SOURCE_DEFAULT, TYPE_INTEGER, defaultValue,
1100 KEY_STRICT_UPGRADE_VERSION, null, FLUSH_OFF);
1103 public static Setting getPeekAnimRemainingTimesSetting(Context context) {
1104 String defaultValue = context.getString(R.string.pref_filmstrip_peek_anim_play_times);
1105 return new Setting(SOURCE_DEFAULT, TYPE_INTEGER, defaultValue,
1106 KEY_FILMSTRIP_PEEK_ANIM_REMAINING_PLAY_TIMES, null, FLUSH_OFF);
1109 public static Setting getRequestReturnHdrPlusSetting(Context context) {
1110 String defaultValue = context.getString(R.string.setting_none_value);
1111 return new Setting(SOURCE_MODULE, TYPE_BOOLEAN, VALUE_OFF,
1112 KEY_REQUEST_RETURN_HDR_PLUS, null, FLUSH_OFF);
1118 * Returns whether the camera has been set to back facing in settings.
1120 public boolean isCameraBackFacing() {
1121 String cameraFacing = get(SETTING_CAMERA_ID);
1122 String backFacing = mContext.getString(R.string.pref_camera_id_default);
1123 return (Integer.parseInt(cameraFacing) == Integer.parseInt(backFacing));
1127 * Returns whether hdr plus mode is set on.
1129 public boolean isHdrPlusOn() {
1130 String hdrOn = get(SettingsManager.SETTING_CAMERA_HDR);
1131 return hdrOn.equals(SettingsManager.VALUE_ON);
1135 * Returns whether the app should return to hdr plus mode if possible.
1137 public boolean requestsReturnToHdrPlus() {
1138 return getBoolean(SettingsManager.SETTING_REQUEST_RETURN_HDR_PLUS);
1142 * Returns whether grid lines are set on.
1144 public boolean areGridLinesOn() {
1145 String gridLinesOn = get(SettingsManager.SETTING_CAMERA_GRID_LINES);
1146 return gridLinesOn.equals(SettingsManager.VALUE_ON);
1150 * Returns whether pano orientation is horizontal.
1152 public boolean isPanoOrientationHorizontal() {
1153 String orientation = get(SettingsManager.SETTING_CAMERA_PANO_ORIENTATION);
1154 String horizontal = mContext.getString(R.string.pano_orientation_horizontal);
1155 return orientation.equals(horizontal);
1158 // TODO: refactor this into a separate utils module.
1161 * Get a String value from first the ListPreference, and if not found from
1162 * the SettingsManager. This is a wrapper that adds backwards compatibility
1163 * to views that rely on PreferenceGroups.
1165 public String getValueFromPreference(ListPreference pref) {
1166 String value = pref.getValue();
1167 if (value == null) {
1168 Integer id = mSettingsCache.getId(pref.getKey());
1178 * Set a String value first from the ListPreference, and if unable from the
1179 * SettingsManager. This is a wrapper that adds backwards compatibility to
1180 * views that rely on PreferenceGroups.
1182 public void setValueFromPreference(ListPreference pref, String value) {
1183 boolean set = pref.setValue(value);
1185 Integer id = mSettingsCache.getId(pref.getKey());
1193 * Set a String value first from the ListPreference based on a
1194 * ListPreference index, and if unable use the ListPreference key to set the
1195 * value using the SettingsManager. This is a wrapper that adds backwards
1196 * compatibility to views that rely on PreferenceGroups.
1198 public void setValueIndexFromPreference(ListPreference pref, int index) {
1199 boolean set = pref.setValueIndex(index);
1201 Integer id = mSettingsCache.getId(pref.getKey());
1203 String value = pref.getValueAtIndex(index);
1210 * Sets the settings for whether location recording should be enabled or
1211 * not. Also makes sure to pass on the change to the location manager.
1213 public void setLocation(boolean on, LocationManager locationManager) {
1214 setBoolean(SettingsManager.SETTING_RECORD_LOCATION, on);
1215 locationManager.recordLocation(on);
1219 * Reads the current location recording settings and passes it on to the
1220 * given location manager.
1222 public void syncLocationManager(LocationManager locationManager) {
1223 boolean value = getBoolean(SettingsManager.SETTING_RECORD_LOCATION);
1224 locationManager.recordLocation(value);