18872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb/*
28872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Copyright (C) 2010 The Android Open Source Project
38872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb *
48872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Licensed under the Apache License, Version 2.0 (the "License");
58872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * you may not use this file except in compliance with the License.
68872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * You may obtain a copy of the License at
78872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb *
88872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb *      http://www.apache.org/licenses/LICENSE-2.0
98872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb *
108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Unless required by applicable law or agreed to in writing, software
118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * distributed under the License is distributed on an "AS IS" BASIS,
128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * See the License for the specific language governing permissions and
148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * limitations under the License.
158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */
168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
178872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbpackage com.android.camera;
188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
198872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.app.backup.BackupManager;
208872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.content.Context;
218872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.content.SharedPreferences;
228872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.content.SharedPreferences.OnSharedPreferenceChangeListener;
238872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.preference.PreferenceManager;
248872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport java.util.Map;
268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport java.util.Set;
278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport java.util.WeakHashMap;
288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport java.util.concurrent.CopyOnWriteArrayList;
298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
308e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberlingimport com.android.camera.util.UsageStatistics;
318e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberling
328872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbpublic class ComboPreferences implements
338872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        SharedPreferences,
348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        OnSharedPreferenceChangeListener {
358872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    private SharedPreferences mPrefGlobal;  // global preferences
368872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    private SharedPreferences mPrefLocal;  // per-camera preferences
374e72c9098e96866fe9d7612c197a5b26f8f99d57Doris Liu    private String mPackageName;
388872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    private CopyOnWriteArrayList<OnSharedPreferenceChangeListener> mListeners;
394e72c9098e96866fe9d7612c197a5b26f8f99d57Doris Liu    // TODO: Remove this WeakHashMap in the camera code refactoring
408872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    private static WeakHashMap<Context, ComboPreferences> sMap =
418872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            new WeakHashMap<Context, ComboPreferences>();
428872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
438872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public ComboPreferences(Context context) {
444e72c9098e96866fe9d7612c197a5b26f8f99d57Doris Liu        mPackageName = context.getPackageName();
458872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        mPrefGlobal = context.getSharedPreferences(
468872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                getGlobalSharedPreferencesName(context), Context.MODE_PRIVATE);
478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        mPrefGlobal.registerOnSharedPreferenceChangeListener(this);
488872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        synchronized (sMap) {
508872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            sMap.put(context, this);
518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
528872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        mListeners = new CopyOnWriteArrayList<OnSharedPreferenceChangeListener>();
538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
548872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        // The global preferences was previously stored in the default
558872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        // shared preferences file. They should be stored in the camera-specific
568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        // shared preferences file so we can backup them solely.
578872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        SharedPreferences oldprefs =
588872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                PreferenceManager.getDefaultSharedPreferences(context);
598872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        if (!mPrefGlobal.contains(CameraSettings.KEY_VERSION)
608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                && oldprefs.contains(CameraSettings.KEY_VERSION)) {
618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            moveGlobalPrefsFrom(oldprefs);
628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
648872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
658872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public static ComboPreferences get(Context context) {
668872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        synchronized (sMap) {
678872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return sMap.get(context);
688872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
698872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
708872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
718872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    private static String getLocalSharedPreferencesName(
728872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            Context context, int cameraId) {
738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        return context.getPackageName() + "_preferences_" + cameraId;
748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    private static String getGlobalSharedPreferencesName(Context context) {
778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        return context.getPackageName() + "_preferences_camera";
788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
798872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
808872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    private void movePrefFrom(
818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            Map<String, ?> m, String key, SharedPreferences src) {
828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        if (m.containsKey(key)) {
838872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            Object v = m.get(key);
848872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            if (v instanceof String) {
858872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mPrefGlobal.edit().putString(key, (String) v).apply();
868872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            } else if (v instanceof Integer) {
878872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mPrefGlobal.edit().putInt(key, (Integer) v).apply();
888872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            } else if (v instanceof Long) {
898872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mPrefGlobal.edit().putLong(key, (Long) v).apply();
908872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            } else if (v instanceof Float) {
918872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mPrefGlobal.edit().putFloat(key, (Float) v).apply();
928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            } else if (v instanceof Boolean) {
938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mPrefGlobal.edit().putBoolean(key, (Boolean) v).apply();
948872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            }
958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            src.edit().remove(key).apply();
968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    private void moveGlobalPrefsFrom(SharedPreferences src) {
1008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        Map<String, ?> prefMap = src.getAll();
1018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        movePrefFrom(prefMap, CameraSettings.KEY_VERSION, src);
1028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        movePrefFrom(prefMap, CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL, src);
1038872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        movePrefFrom(prefMap, CameraSettings.KEY_CAMERA_ID, src);
1048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        movePrefFrom(prefMap, CameraSettings.KEY_RECORD_LOCATION, src);
1058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        movePrefFrom(prefMap, CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, src);
1068872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        movePrefFrom(prefMap, CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN, src);
1078872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        movePrefFrom(prefMap, CameraSettings.KEY_VIDEO_EFFECT, src);
1088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public static String[] getSharedPreferencesNames(Context context) {
1118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        int numOfCameras = CameraHolder.instance().getNumberOfCameras();
1128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        String prefNames[] = new String[numOfCameras + 1];
1138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        prefNames[0] = getGlobalSharedPreferencesName(context);
1148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        for (int i = 0; i < numOfCameras; i++) {
1158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            prefNames[i + 1] = getLocalSharedPreferencesName(context, i);
1168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
1178872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        return prefNames;
1188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1198872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1208872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    // Sets the camera id and reads its preferences. Each camera has its own
1218872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    // preferences.
1228872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public void setLocalId(Context context, int cameraId) {
1238872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        String prefName = getLocalSharedPreferencesName(context, cameraId);
1248872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        if (mPrefLocal != null) {
1258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            mPrefLocal.unregisterOnSharedPreferenceChangeListener(this);
1268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
1278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        mPrefLocal = context.getSharedPreferences(
1288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                prefName, Context.MODE_PRIVATE);
1298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        mPrefLocal.registerOnSharedPreferenceChangeListener(this);
1308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1318872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1328872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public SharedPreferences getGlobal() {
1338872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        return mPrefGlobal;
1348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1358872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1368872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public SharedPreferences getLocal() {
1378872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        return mPrefLocal;
1388872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1398872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1408872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
1418872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public Map<String, ?> getAll() {
1428872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        throw new UnsupportedOperationException(); // Can be implemented if needed.
1438872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1448872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1458872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    private static boolean isGlobal(String key) {
1468872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        return key.equals(CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL)
1478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                || key.equals(CameraSettings.KEY_CAMERA_ID)
1488872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                || key.equals(CameraSettings.KEY_RECORD_LOCATION)
1498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                || key.equals(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN)
1508872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                || key.equals(CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN)
1518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                || key.equals(CameraSettings.KEY_VIDEO_EFFECT)
1528872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                || key.equals(CameraSettings.KEY_TIMER)
1531580df6aed1e5569ede61af0949279819ec03119Angus Kong                || key.equals(CameraSettings.KEY_TIMER_SOUND_EFFECTS)
1541580df6aed1e5569ede61af0949279819ec03119Angus Kong                || key.equals(CameraSettings.KEY_PHOTOSPHERE_PICTURESIZE);
1558872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1578872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
1588872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public String getString(String key, String defValue) {
1598872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        if (isGlobal(key) || !mPrefLocal.contains(key)) {
1608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return mPrefGlobal.getString(key, defValue);
1618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        } else {
1628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return mPrefLocal.getString(key, defValue);
1638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
1648872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1658872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1668872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
1678872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public int getInt(String key, int defValue) {
1688872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        if (isGlobal(key) || !mPrefLocal.contains(key)) {
1698872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return mPrefGlobal.getInt(key, defValue);
1708872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        } else {
1718872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return mPrefLocal.getInt(key, defValue);
1728872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
1738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
1768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public long getLong(String key, long defValue) {
1778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        if (isGlobal(key) || !mPrefLocal.contains(key)) {
1788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return mPrefGlobal.getLong(key, defValue);
1798872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        } else {
1808872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return mPrefLocal.getLong(key, defValue);
1818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
1828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1838872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1848872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
1858872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public float getFloat(String key, float defValue) {
1868872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        if (isGlobal(key) || !mPrefLocal.contains(key)) {
1878872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return mPrefGlobal.getFloat(key, defValue);
1888872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        } else {
1898872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return mPrefLocal.getFloat(key, defValue);
1908872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
1918872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
1928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
1938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
1948872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public boolean getBoolean(String key, boolean defValue) {
1958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        if (isGlobal(key) || !mPrefLocal.contains(key)) {
1968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return mPrefGlobal.getBoolean(key, defValue);
1978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        } else {
1988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return mPrefLocal.getBoolean(key, defValue);
1998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
2018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    // This method is not used.
2038872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
2048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public Set<String> getStringSet(String key, Set<String> defValues) {
2058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        throw new UnsupportedOperationException();
2068872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
2078872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
2098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public boolean contains(String key) {
210806e78b99ae440423547aca436fe5361882bcc33Bobby Georgescu        return mPrefLocal.contains(key) || mPrefGlobal.contains(key);
2118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
2128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    private class MyEditor implements Editor {
2148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        private Editor mEditorGlobal;
2158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        private Editor mEditorLocal;
2168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2178872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        MyEditor() {
2188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            mEditorGlobal = mPrefGlobal.edit();
2198872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            mEditorLocal = mPrefLocal.edit();
2208872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2218872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2228872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        @Override
2238872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        public boolean commit() {
2248872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            boolean result1 = mEditorGlobal.commit();
2258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            boolean result2 = mEditorLocal.commit();
2268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return result1 && result2;
2278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        @Override
2308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        public void apply() {
2318872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            mEditorGlobal.apply();
2328872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            mEditorLocal.apply();
2338872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2358872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        // Note: clear() and remove() affects both local and global preferences.
2368872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        @Override
2378872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        public Editor clear() {
2388872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            mEditorGlobal.clear();
2398872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            mEditorLocal.clear();
2408872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return this;
2418872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2428872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2438872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        @Override
2448872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        public Editor remove(String key) {
2458872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            mEditorGlobal.remove(key);
2468872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            mEditorLocal.remove(key);
2478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return this;
2488872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2508872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        @Override
2518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        public Editor putString(String key, String value) {
2528872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            if (isGlobal(key)) {
2538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mEditorGlobal.putString(key, value);
2548872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            } else {
2558872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mEditorLocal.putString(key, value);
2568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            }
2578872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return this;
2588872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2598872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        @Override
2618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        public Editor putInt(String key, int value) {
2628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            if (isGlobal(key)) {
2638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mEditorGlobal.putInt(key, value);
2648872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            } else {
2658872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mEditorLocal.putInt(key, value);
2668872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            }
2678872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return this;
2688872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2698872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2708872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        @Override
2718872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        public Editor putLong(String key, long value) {
2728872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            if (isGlobal(key)) {
2738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mEditorGlobal.putLong(key, value);
2748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            } else {
2758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mEditorLocal.putLong(key, value);
2768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            }
2778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return this;
2788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2798872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2808872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        @Override
2818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        public Editor putFloat(String key, float value) {
2828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            if (isGlobal(key)) {
2838872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mEditorGlobal.putFloat(key, value);
2848872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            } else {
2858872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mEditorLocal.putFloat(key, value);
2868872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            }
2878872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return this;
2888872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2898872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
2908872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        @Override
2918872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        public Editor putBoolean(String key, boolean value) {
2928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            if (isGlobal(key)) {
2938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mEditorGlobal.putBoolean(key, value);
2948872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            } else {
2958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb                mEditorLocal.putBoolean(key, value);
2968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            }
2978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            return this;
2988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
2998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
3008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        // This method is not used.
3018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        @Override
3028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        public Editor putStringSet(String key, Set<String> values) {
3038872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            throw new UnsupportedOperationException();
3048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
3058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
3068872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
3078872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    // Note the remove() and clear() of the returned Editor may not work as
3088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    // expected because it doesn't touch the global preferences at all.
3098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
3108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public Editor edit() {
3118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        return new MyEditor();
3128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
3138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
3148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
3158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public void registerOnSharedPreferenceChangeListener(
3168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            OnSharedPreferenceChangeListener listener) {
3178872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        mListeners.add(listener);
3188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
3198872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
3208872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
3218872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public void unregisterOnSharedPreferenceChangeListener(
3228872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            OnSharedPreferenceChangeListener listener) {
3238872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        mListeners.remove(listener);
3248872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
3258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb
3268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    @Override
3278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
3288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            String key) {
3298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        for (OnSharedPreferenceChangeListener listener : mListeners) {
3308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb            listener.onSharedPreferenceChanged(this, key);
3318872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb        }
3324e72c9098e96866fe9d7612c197a5b26f8f99d57Doris Liu        BackupManager.dataChanged(mPackageName);
3338872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb    }
3348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb}
335