1 /* 2 * Copyright (C) 2017 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 package com.android.networkrecommendation.config; 17 18 import android.annotation.SuppressLint; 19 import android.content.Context; 20 import android.content.SharedPreferences; 21 import android.content.SharedPreferences.Editor; 22 import android.os.Build; 23 24 import java.util.Collection; 25 import java.util.Locale; 26 import java.util.Map; 27 import java.util.Set; 28 29 /** 30 * Utility class for retrieving and storing key/value pairs in a SharedPreferences file. 31 * 32 * Typical usage: 33 * 34 * In your application's onCreate(); 35 * PreferenceFile.init(this); 36 * 37 * In common preferences declaration area: 38 * private static final PreferenceFile sFile = new PreferenceFile("my_prefs"); 39 * public static final SharedPreference<String> pageUrl = sFile.value("page_url", "http://blah"); 40 * 41 * At usage time: 42 * String pageUrl = Preferences.pageUrl.get(); 43 * Preferences.pageUrl.put("http://www.newurl.com/"); 44 */ 45 public class PreferenceFile { 46 private static final String TAG = "PreferenceFile"; 47 48 private static Context sContext; 49 init(Context context)50 public static void init(Context context) { 51 sContext = context; 52 } 53 54 private final String mName; 55 private final int mMode; 56 57 @SuppressWarnings("deprecation") PreferenceFile(String name)58 public PreferenceFile(String name) { 59 this(name, Context.MODE_PRIVATE); 60 } 61 62 /** 63 * @deprecated any mode other than MODE_PRIVATE is a bad idea. If you need multi-process 64 * support, see if {@link MultiProcessPreferenceFile} is suitable. 65 */ 66 @Deprecated PreferenceFile(String name, int mode)67 public PreferenceFile(String name, int mode) { 68 mName = name; 69 mMode = mode; 70 } 71 72 /** 73 * Returns a text dump of all preferences in this file; for debugging. 74 */ dump()75 public String dump() { 76 SharedPreferences sp = open(); 77 Map<String, ?> allPrefs = sp.getAll(); 78 String format = "%" + longestString(allPrefs.keySet()) + "s = %s\n"; 79 StringBuilder s = new StringBuilder(); 80 for (String key : allPrefs.keySet()) { 81 s.append(String.format(Locale.US, format, key, allPrefs.get(key))); 82 } 83 return s.toString(); 84 } 85 86 /** Return a SharedPreferences for this file. */ open()87 public SharedPreferences open() { 88 return sContext.getSharedPreferences(mName, mMode); 89 } 90 remove(SharedPreference<?>.... preferences)91 public void remove(SharedPreference<?>... preferences) { 92 SharedPreferences.Editor editor = open().edit(); 93 for (SharedPreference<?> preference : preferences) { 94 editor.remove(preference.getKey()); 95 } 96 commit(editor); 97 } 98 99 /** Synchronously clear all SharedPreferences in this file. */ clear()100 public void clear() { 101 open().edit().clear().commit(); 102 } 103 104 105 /** 106 * If on API >= 9, use the asynchronous 107 * {@link Editor#apply()} method. Otherwise, use the 108 * synchronous {@link Editor#commit()} method. <br /> 109 * <br /> 110 * If commit() is used, the result will be returned. If apply() is used, it 111 * will always return true. 112 * 113 * @param editor The editor to save 114 * @return the result of commit() on API < 9 and true on API >= 9. 115 */ 116 @SuppressLint("NewApi") commit(Editor editor)117 public static boolean commit(Editor editor) { 118 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) { 119 return editor.commit(); 120 } 121 editor.apply(); 122 return true; 123 } 124 125 /** Define a new Long value shared pref key. */ longValue(final String key, final Long defaultValue)126 public SharedPreference<Long> longValue(final String key, final Long defaultValue) { 127 return new SharedPreference<Long>(this, key) { 128 @Override 129 protected Long read(SharedPreferences sp) { 130 if (sp.contains(key)) { 131 return sp.getLong(key, 0L); 132 } 133 return defaultValue; 134 } 135 136 @Override 137 protected void write(Editor editor, Long value) { 138 if (value == null) { 139 throw new IllegalArgumentException("null cannot be written for Long"); 140 } 141 editor.putLong(key, value); 142 } 143 }; 144 } 145 146 /** Define a new String value shared pref key. */ 147 public SharedPreference<String> stringValue(final String key, final String defaultValue) { 148 return new SharedPreference<String>(this, key) { 149 @Override 150 protected String read(SharedPreferences sp) { 151 if (sp.contains(key)) { 152 return sp.getString(key, null); 153 } 154 return defaultValue; 155 } 156 157 @Override 158 protected void write(Editor editor, String value) { 159 if (value == null) { 160 throw new IllegalArgumentException("null cannot be written for String"); 161 } 162 editor.putString(key, value); 163 } 164 }; 165 } 166 167 /** Define a new Boolean value shared pref key. */ 168 public SharedPreference<Boolean> booleanValue(final String key, final Boolean defaultValue) { 169 return new SharedPreference<Boolean>(this, key) { 170 @Override 171 protected Boolean read(SharedPreferences sp) { 172 if (sp.contains(key)) { 173 return sp.getBoolean(key, false); 174 } 175 return defaultValue; 176 } 177 178 @Override 179 protected void write(Editor editor, Boolean value) { 180 if (value == null) { 181 throw new IllegalArgumentException("null cannot be written for Boolean"); 182 } 183 editor.putBoolean(key, value); 184 } 185 }; 186 } 187 188 /** Define a new Integer value shared pref key. */ 189 public SharedPreference<Integer> intValue(final String key, final Integer defaultValue) { 190 return new SharedPreference<Integer>(this, key) { 191 @Override 192 protected Integer read(SharedPreferences sp) { 193 if (sp.contains(key)) { 194 return sp.getInt(key, 0); 195 } 196 return defaultValue; 197 } 198 199 @Override 200 protected void write(Editor editor, Integer value) { 201 if (value == null) { 202 throw new IllegalArgumentException("null cannot be written for Integer"); 203 } 204 editor.putInt(key, value); 205 } 206 }; 207 } 208 209 /** Define a new Set<String> value shared pref key. */ 210 public SharedPreference<Set<String>> stringSetValue(final String key, 211 final Set<String> defaultValue) { 212 return new SharedPreference<Set<String>>(this, key) { 213 @Override 214 protected Set<String> read(SharedPreferences sp) { 215 if (sp.contains(key)) { 216 return sp.getStringSet(key, null); 217 } 218 return defaultValue; 219 } 220 221 @Override 222 protected void write(Editor editor, Set<String> value) { 223 if (value == null) { 224 throw new IllegalArgumentException("null cannot be written for Set<String>"); 225 } 226 editor.putStringSet(key, value); 227 } 228 }; 229 } 230 231 /** 232 * A class representing a key/value pair in a given {@link PreferenceFile}. 233 */ 234 public static abstract class SharedPreference<T> { 235 PreferenceFile mFile; 236 final String mKey; 237 238 protected SharedPreference(PreferenceFile file, String key) { 239 mFile = file; 240 mKey = key; 241 } 242 243 /** Read the value stored for this pref, or the default value if none is stored. */ 244 public final T get() { 245 return read(mFile.open()); 246 } 247 248 /** Get the representation in string of the value for this pref. */ 249 public String getValueString() { 250 T value = get(); 251 if (value == null) { 252 return null; 253 } 254 return value.toString(); 255 } 256 257 /** Return this pref's key. */ 258 public final String getKey() { 259 return mKey; 260 } 261 262 /** Return true if this key is defined in its file. */ 263 public final boolean exists() { 264 return mFile.open().contains(mKey); 265 } 266 267 /** Write a new value for this pref to its file. */ 268 public final void put(T value) { 269 SharedPreferences sp = mFile.open(); 270 Editor editor = sp.edit(); 271 write(editor, value); 272 commit(editor); 273 } 274 275 /** Removes this pref from its file. */ 276 public final void remove() { 277 commit(mFile.open().edit().remove(mKey)); 278 } 279 280 /** Override the PreferenceFile used by this preference (for testing). */ 281 public final void override(PreferenceFile file) { 282 mFile = file; 283 } 284 285 protected abstract T read(SharedPreferences sp); 286 protected abstract void write(Editor editor, T value); 287 } 288 289 /** 290 * Returns the length of the longest string in the provided Collection. 291 */ 292 private static int longestString(Collection<String> strings) { 293 int longest = 0; 294 for (String s : strings) { 295 longest = Math.max(longest, s.length()); 296 } 297 return longest; 298 } 299 } 300