• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base.test.util;
6 
7 import android.content.SharedPreferences;
8 
9 import java.util.Collections;
10 import java.util.HashMap;
11 import java.util.Map;
12 import java.util.Set;
13 
14 /**
15  * An implementation of SharedPreferences that can be used in tests.
16  * <p/>
17  * It keeps all state in memory, and there is no difference between apply() and commit().
18  */
19 public class InMemorySharedPreferences implements SharedPreferences {
20 
21     // Guarded on its own monitor.
22     private final Map<String, Object> mData;
23 
InMemorySharedPreferences()24     public InMemorySharedPreferences() {
25         mData = new HashMap<String, Object>();
26     }
27 
InMemorySharedPreferences(Map<String, Object> data)28     public InMemorySharedPreferences(Map<String, Object> data) {
29         mData = data;
30     }
31 
32     @Override
getAll()33     public Map<String, ?> getAll() {
34         synchronized (mData) {
35             return Collections.unmodifiableMap(mData);
36         }
37     }
38 
39     @Override
getString(String key, String defValue)40     public String getString(String key, String defValue) {
41         synchronized (mData) {
42             if (mData.containsKey(key)) {
43                 return (String) mData.get(key);
44             }
45         }
46         return defValue;
47     }
48 
49     @SuppressWarnings("unchecked")
50     @Override
getStringSet(String key, Set<String> defValues)51     public Set<String> getStringSet(String key, Set<String> defValues) {
52         synchronized (mData) {
53             if (mData.containsKey(key)) {
54                 return Collections.unmodifiableSet((Set<String>) mData.get(key));
55             }
56         }
57         return defValues;
58     }
59 
60     @Override
getInt(String key, int defValue)61     public int getInt(String key, int defValue) {
62         synchronized (mData) {
63             if (mData.containsKey(key)) {
64                 return (Integer) mData.get(key);
65             }
66         }
67         return defValue;
68     }
69 
70     @Override
getLong(String key, long defValue)71     public long getLong(String key, long defValue) {
72         synchronized (mData) {
73             if (mData.containsKey(key)) {
74                 return (Long) mData.get(key);
75             }
76         }
77         return defValue;
78     }
79 
80     @Override
getFloat(String key, float defValue)81     public float getFloat(String key, float defValue) {
82         synchronized (mData) {
83             if (mData.containsKey(key)) {
84                 return (Float) mData.get(key);
85             }
86         }
87         return defValue;
88     }
89 
90     @Override
getBoolean(String key, boolean defValue)91     public boolean getBoolean(String key, boolean defValue) {
92         synchronized (mData) {
93             if (mData.containsKey(key)) {
94                 return (Boolean) mData.get(key);
95             }
96         }
97         return defValue;
98     }
99 
100     @Override
contains(String key)101     public boolean contains(String key) {
102         synchronized (mData) {
103             return mData.containsKey(key);
104         }
105     }
106 
107     @Override
edit()108     public SharedPreferences.Editor edit() {
109         return new InMemoryEditor();
110     }
111 
112     @Override
registerOnSharedPreferenceChangeListener( SharedPreferences.OnSharedPreferenceChangeListener listener)113     public void registerOnSharedPreferenceChangeListener(
114             SharedPreferences.OnSharedPreferenceChangeListener
115                     listener) {
116         throw new UnsupportedOperationException();
117     }
118 
119     @Override
unregisterOnSharedPreferenceChangeListener( SharedPreferences.OnSharedPreferenceChangeListener listener)120     public void unregisterOnSharedPreferenceChangeListener(
121             SharedPreferences.OnSharedPreferenceChangeListener listener) {
122         throw new UnsupportedOperationException();
123     }
124 
125     private class InMemoryEditor implements SharedPreferences.Editor {
126 
127         // All guarded by |mChanges|
128         private boolean mClearCalled;
129         private volatile boolean mApplyCalled;
130         private final Map<String, Object> mChanges = new HashMap<String, Object>();
131 
132         @Override
putString(String key, String value)133         public SharedPreferences.Editor putString(String key, String value) {
134             synchronized (mChanges) {
135                 if (mApplyCalled) throw new IllegalStateException();
136                 mChanges.put(key, value);
137                 return this;
138             }
139         }
140 
141         @Override
putStringSet(String key, Set<String> values)142         public SharedPreferences.Editor putStringSet(String key, Set<String> values) {
143             synchronized (mChanges) {
144                 if (mApplyCalled) throw new IllegalStateException();
145                 mChanges.put(key, values);
146                 return this;
147             }
148         }
149 
150         @Override
putInt(String key, int value)151         public SharedPreferences.Editor putInt(String key, int value) {
152             synchronized (mChanges) {
153                 if (mApplyCalled) throw new IllegalStateException();
154                 mChanges.put(key, value);
155                 return this;
156             }
157         }
158 
159         @Override
putLong(String key, long value)160         public SharedPreferences.Editor putLong(String key, long value) {
161             synchronized (mChanges) {
162                 if (mApplyCalled) throw new IllegalStateException();
163                 mChanges.put(key, value);
164                 return this;
165             }
166         }
167 
168         @Override
putFloat(String key, float value)169         public SharedPreferences.Editor putFloat(String key, float value) {
170             synchronized (mChanges) {
171                 if (mApplyCalled) throw new IllegalStateException();
172                 mChanges.put(key, value);
173                 return this;
174             }
175         }
176 
177         @Override
putBoolean(String key, boolean value)178         public SharedPreferences.Editor putBoolean(String key, boolean value) {
179             synchronized (mChanges) {
180                 if (mApplyCalled) throw new IllegalStateException();
181                 mChanges.put(key, value);
182                 return this;
183             }
184         }
185 
186         @Override
remove(String key)187         public SharedPreferences.Editor remove(String key) {
188             synchronized (mChanges) {
189                 if (mApplyCalled) throw new IllegalStateException();
190                 // Magic value for removes
191                 mChanges.put(key, this);
192                 return this;
193             }
194         }
195 
196         @Override
clear()197         public SharedPreferences.Editor clear() {
198             synchronized (mChanges) {
199                 if (mApplyCalled) throw new IllegalStateException();
200                 mClearCalled = true;
201                 return this;
202             }
203         }
204 
205         @Override
commit()206         public boolean commit() {
207             apply();
208             return true;
209         }
210 
211         @Override
apply()212         public void apply() {
213             synchronized (mData) {
214                 synchronized (mChanges) {
215                     if (mApplyCalled) throw new IllegalStateException();
216                     if (mClearCalled) {
217                         mData.clear();
218                     }
219                     for (Map.Entry<String, Object> entry : mChanges.entrySet()) {
220                         String key = entry.getKey();
221                         Object value = entry.getValue();
222                         if (value == this) {
223                             // Special value for removal
224                             mData.remove(key);
225                         } else {
226                             mData.put(key, value);
227                         }
228                     }
229                     // The real shared prefs clears out the temporaries allowing the caller to
230                     // reuse the Editor instance, however this is undocumented behavior and subtle
231                     // to read, so instead we just ban any future use of this instance.
232                     mApplyCalled = true;
233                 }
234             }
235         }
236     }
237 
238 }
239