0464b6714cc57af68921361007e7340caafd0bdc
[nit.git] / lib / android / shared_preferences / shared_preferences_api10.nit
1 # This file is part of NIT (http://www.nitlanguage.org).
2 #
3 # Copyright 2014 Frédéric Vachon <fredvac@gmail.com>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Services to save/load data using `android.content.SharedPreferences` for the android platform
18 module shared_preferences_api10
19
20 import dalvik
21 import serialization
22 private import json
23
24 in "Java" `{
25 import android.content.SharedPreferences;
26 import android.content.Context;
27 import android.app.Activity;
28 import java.util.Map;
29 import java.util.Iterator;
30 import java.lang.ClassCastException;
31 import java.lang.NullPointerException;
32 `}
33
34 extern class NativeSharedPreferences in "Java" `{ android.content.SharedPreferences `}
35 super JavaObject
36
37 fun contains(key: JavaString): Bool in "Java" `{ return self.contains(key); `}
38 fun get_all: HashMap[JavaString, JavaObject] import HashMap[JavaString, JavaObject],
39 HashMap[JavaString, JavaObject].[]= in "Java" `{
40 Map<String, ?> java_map = null;
41 int nit_hashmap = new_HashMap_of_JavaString_JavaObject();
42 try {
43 java_map = self.getAll();
44 } catch (NullPointerException e) {
45 return nit_hashmap;
46 }
47
48 for (Map.Entry<String, ?> entry: java_map.entrySet())
49 HashMap_of_JavaString_JavaObject__index_assign(nit_hashmap,
50 entry.getKey(), entry.getValue());
51
52 return nit_hashmap;
53 `}
54 fun get_boolean(key: JavaString, def_value: Bool): Bool in "Java" `{
55 boolean return_value;
56 try {
57 return_value = self.getBoolean(key, def_value);
58 } catch (ClassCastException e) {
59 return def_value;
60 }
61
62 return return_value;
63 `}
64 fun get_float(key: JavaString, def_value: Float): Float in "Java" `{
65 float return_value;
66 try {
67 return_value = self.getFloat(key, (float) def_value);
68 } catch (ClassCastException e) {
69 return def_value;
70 }
71
72 return return_value;
73 `}
74 fun get_int(key: JavaString, def_value: Int): Int in "Java" `{
75 int return_value;
76 try {
77 return_value = self.getInt(key, (int)def_value);
78 } catch (ClassCastException e) {
79 return def_value;
80 }
81
82 return return_value;
83 `}
84 fun get_long(key: JavaString, def_value: Int): Int in "Java" `{
85 long return_value;
86 try {
87 return_value = self.getLong(key, def_value);
88 } catch (ClassCastException e) {
89 return def_value;
90 }
91
92 return (int) return_value;
93 `}
94 fun get_string(key: JavaString, def_value: JavaString): JavaString in "Java" `{
95 String return_value = null;
96 try {
97 return_value = self.getString(key, def_value);
98 } catch (ClassCastException e) {
99 return def_value;
100 }
101
102 return return_value;
103 `}
104
105 # HACK for bug #845
106 redef fun new_global_ref import sys, Sys.jni_env `{
107 Sys sys = NativeSharedPreferences_sys(self);
108 JNIEnv *env = Sys_jni_env(sys);
109 return (*env)->NewGlobalRef(env, self);
110 `}
111 end
112
113 extern class NativeSharedPreferencesEditor in "Java" `{ android.content.SharedPreferences$Editor `}
114 super JavaObject
115
116 fun clear: NativeSharedPreferencesEditor in "Java" `{ return self.clear(); `}
117 fun commit: Bool in "Java" `{ return self.commit(); `}
118 fun put_boolean(key: JavaString, value: Bool): NativeSharedPreferencesEditor in "Java" `{
119 return self.putBoolean (key, value);
120 `}
121 fun put_float(key: JavaString, value: Float): NativeSharedPreferencesEditor in "Java" `{
122 return self.putFloat(key, (float) value);
123 `}
124 fun put_int(key: JavaString, value: Int): NativeSharedPreferencesEditor in "Java" `{
125 return self.putInt(key, (int)value);
126 `}
127 fun put_long(key: JavaString, value: Int): NativeSharedPreferencesEditor in "Java" `{
128 return self.putLong(key, value);
129 `}
130 fun put_string(key: JavaString, value: JavaString): NativeSharedPreferencesEditor in "Java" `{
131 return self.putString(key, value);
132 `}
133 fun remove(key: JavaString): NativeSharedPreferencesEditor in "Java" `{
134 return self.remove(key);
135 `}
136
137 # HACK for bug #845
138 redef fun new_global_ref import sys, Sys.jni_env `{
139 Sys sys = NativeSharedPreferencesEditor_sys(self);
140 JNIEnv *env = Sys_jni_env(sys);
141 return (*env)->NewGlobalRef(env, self);
142 `}
143 end
144
145 # Provides services to save and load data for the android platform
146 class SharedPreferences
147 protected var shared_preferences: NativeSharedPreferences
148 protected var editor: NativeSharedPreferencesEditor
149
150 # Automatically commits every saving/removing instructions (`true` by default)
151 var auto_commit = true
152
153 protected init(app: App, file_name: String, mode: Int)
154 do
155 sys.jni_env.push_local_frame(1)
156 setup(file_name.to_java_string, mode, app.native_context)
157 sys.jni_env.pop_local_frame
158 end
159
160 # Restricts file access to the current application
161 init privately(app: App, file_name: String)
162 do
163 self.init(app, file_name, private_mode)
164 end
165
166 # File access mode
167 private fun private_mode: Int in "Java" `{ return Context.MODE_PRIVATE; `}
168
169 private fun set_vars(shared_pref: NativeSharedPreferences, editor: NativeSharedPreferencesEditor)
170 do
171 self.shared_preferences = shared_pref.new_global_ref
172 self.editor = editor.new_global_ref
173 end
174
175 private fun setup(file_name: JavaString, mode: Int, context: NativeContext) import set_vars in "Java" `{
176 SharedPreferences sp;
177
178 // Uses default SharedPreferences if file_name is an empty String
179 if (file_name.equals("")) {
180 Activity activity = (Activity)context;
181 sp = activity.getPreferences((int)mode);
182 } else {
183 sp = context.getSharedPreferences(file_name, (int)mode);
184 }
185
186 SharedPreferences.Editor editor = sp.edit();
187
188 SharedPreferences_set_vars(self, sp, editor);
189 `}
190
191 private fun commit_if_auto do if auto_commit then self.commit
192
193 # Returns true if there's an entry corresponding the given key
194 fun has(key: String): Bool
195 do
196 sys.jni_env.push_local_frame(2)
197 var return_value = shared_preferences.contains(key.to_java_string)
198 sys.jni_env.pop_local_frame
199 return return_value
200 end
201
202 # Returns a `HashMap` containing all entries or `null` if there's no entries
203 #
204 # User has to manage local stack deallocation himself
205 #
206 # ~~~nitish
207 # var foo = new HashMap[JavaString, JavaObject]
208 # # ...
209 # for key, value in foo do
210 # key.delete_local_ref
211 # value.delete_local_ref
212 # end
213 # ~~~
214 # *You should use Nit getters instead and get each value one by one*
215 fun all: nullable HashMap[JavaString, JavaObject]
216 do
217 var hashmap = shared_preferences.get_all
218 if hashmap.is_empty then return null
219 return hashmap
220 end
221
222 # Returns the `Bool` value corresponding the given key or `def_value` if none
223 # or if the value isn't of correct type
224 fun bool(key: String, def_value: Bool): Bool
225 do
226 sys.jni_env.push_local_frame(2)
227 var return_value = shared_preferences.get_boolean(key.to_java_string, def_value)
228 sys.jni_env.pop_local_frame
229 return return_value
230 end
231
232 # Returns the `Float` value corresponding the given key or `def_value` if none
233 # or if the value isn't of correct type
234 fun float(key: String, def_value: Float): Float
235 do
236 sys.jni_env.push_local_frame(2)
237 var return_value = shared_preferences.get_float(key.to_java_string, def_value)
238 sys.jni_env.pop_local_frame
239 return return_value
240 end
241
242 # Returns the `Int` value corresponding the given key or `def_value` if none
243 # or if the value isn't of correct type
244 # Be aware of possible `def_value` integer overflow as the Nit `Int` corresponds
245 # to Java `long`
246 fun int(key: String, def_value: Int): Int
247 do
248 sys.jni_env.push_local_frame(2)
249 var return_value = shared_preferences.get_int(key.to_java_string, def_value)
250 sys.jni_env.pop_local_frame
251 return return_value
252 end
253
254 # Returns the `Int` value corresponding the given key or `def_value` if none
255 # or if the value isn't of correct type
256 # Calls `getLong(key, value)` java method
257 # Nit `Int` is equivalent to Java `long` so that no integer overflow will occur
258 fun long(key: String, def_value: Int): Int
259 do
260 sys.jni_env.push_local_frame(2)
261 var return_value = shared_preferences.get_long(key.to_java_string, def_value)
262 sys.jni_env.pop_local_frame
263 return return_value
264 end
265
266 # Returns the `String` value corresponding the given key or `def_value` if none
267 # or if the value isn't of correct type
268 fun string(key: String, def_value: String): String
269 do
270 sys.jni_env.push_local_frame(3)
271 var java_return_value = shared_preferences.get_string(key.to_java_string,
272 def_value.to_java_string)
273 var nit_return_value = java_return_value.to_s
274 sys.jni_env.pop_local_frame
275 return nit_return_value
276 end
277
278 # Clears all the dictionnary entries in the specified file or the default file
279 # if none specified at instanciation
280 # Returns `self` allowing fluent programming
281 fun clear: SharedPreferences
282 do
283 editor.clear
284 commit_if_auto
285 return self
286 end
287
288 # If auto_commit is `false`, has to be called to save the data to persistant memory
289 fun commit: Bool
290 do
291 sys.jni_env.push_local_frame(1)
292 var return_value = editor.commit
293 sys.jni_env.pop_local_frame
294 return return_value
295 end
296
297 # Set a key-value pair using a `Bool` value
298 # Returns `self` allowing fluent programming
299 fun add_bool(key: String, value: Bool): SharedPreferences
300 do
301 sys.jni_env.push_local_frame(1)
302 editor.put_boolean(key.to_java_string, value)
303 sys.jni_env.pop_local_frame
304 commit_if_auto
305 return self
306 end
307
308 # Set a key-value pair using a `Float` value
309 # Returns `self` allowing fluent programming
310 #
311 # Be aware of possible loss of precision as Nit `Float` corresponds to Java `double`
312 # and the methods stores a Java `float`
313 fun add_float(key: String, value: Float): SharedPreferences
314 do
315 sys.jni_env.push_local_frame(1)
316 editor.put_float(key.to_java_string, value)
317 sys.jni_env.pop_local_frame
318 commit_if_auto
319 return self
320 end
321
322 # Set a key-value pair using a `Int` type value
323 # Returns `self` allowing fluent programming
324 #
325 # Be aware of possible integer overflow as the Nit `Int` corresponds to Java `long`
326 # and the methods stores a Java `int`
327 # *You might want to use add_long instead*
328 fun add_int(key: String, value: Int): SharedPreferences
329 do
330 sys.jni_env.push_local_frame(1)
331 editor.put_int(key.to_java_string, value)
332 sys.jni_env.pop_local_frame
333 commit_if_auto
334 return self
335 end
336
337 # Set a key-value pair using a `Int` type value
338 # Returns `self` allowing fluent programming
339 fun add_long(key: String, value: Int): SharedPreferences
340 do
341 sys.jni_env.push_local_frame(1)
342 editor.put_long(key.to_java_string, value)
343 sys.jni_env.pop_local_frame
344 commit_if_auto
345 return self
346 end
347
348 # Set a key-value pair using a `String` type value
349 # Returns `self` allowing fluent programming
350 fun add_string(key: String, value: String): SharedPreferences
351 do
352 sys.jni_env.push_local_frame(2)
353 editor.put_string(key.to_java_string, value.to_java_string)
354 sys.jni_env.pop_local_frame
355 commit_if_auto
356 return self
357 end
358
359 # Removes the corresponding entry in the file
360 # Returns `self` allowing fluent programming
361 fun remove(key: String): SharedPreferences
362 do
363 sys.jni_env.push_local_frame(1)
364 editor.remove(key.to_java_string)
365 sys.jni_env.pop_local_frame
366 commit_if_auto
367 return self
368 end
369
370 # Deallocate global references allocated by the SharedPreferences instance
371 fun destroy
372 do
373 self.shared_preferences.delete_global_ref
374 self.editor.delete_global_ref
375 end
376
377 # Store `value` as a serialized Json string
378 fun []=(key: String, value: nullable Serializable)
379 do
380 var serialized_string = new StringWriter
381 var serializer = new JsonSerializer(serialized_string)
382 serializer.serialize(value)
383
384 add_string(key, serialized_string.to_s)
385 commit_if_auto
386 end
387
388 # Retrieve an `Object` stored via `[]=` function
389 #
390 # Returns `null` if there's no serialized object corresponding to the given key
391 # Make sure that the serialized object is `serialize` or that it redefines
392 # the appropriate methods. Refer to `Serializable` documentation for further details
393 fun [](key: String): nullable Object
394 do
395 var serialized_string = self.string(key, "")
396
397 if serialized_string == "" then return null
398
399 var deserializer = new JsonDeserializer(serialized_string)
400 var deserialized = deserializer.deserialize
401
402 var errors = deserializer.errors
403 if errors.not_empty then
404 # An update may have broken the versioning compatibility
405 print_error "{class_name} error at deserialization: {errors.join(", ")}"
406 return null # Let's be safe
407 end
408
409 return deserialized
410 end
411 end
412
413 redef class App
414 var shared_preferences: SharedPreferences is lazy do
415 return new SharedPreferences.privately(self, "app.nit")
416 end
417 end