Merge: SharedPreferences: Nit API wrapping android SharedPreferences class
[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 native_app_glue
21 import serialization
22 import json_serialization
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 redef type SELF: NativeSharedPreferences
37
38 fun contains(key: JavaString): Bool in "Java" `{ return recv.contains(key); `}
39 fun get_all: HashMap[JavaString, JavaObject] import HashMap[JavaString, JavaObject],
40 HashMap[JavaString, JavaObject].[]= in "Java" `{
41 Map<String, ?> java_map = null;
42 int nit_hashmap = new_HashMap_of_JavaString_JavaObject();
43 try {
44 java_map = recv.getAll();
45 } catch (NullPointerException e) {
46 return nit_hashmap;
47 }
48
49 for (Map.Entry<String, ?> entry: java_map.entrySet())
50 HashMap_of_JavaString_JavaObject__index_assign(nit_hashmap,
51 entry.getKey(), entry.getValue());
52
53 return nit_hashmap;
54 `}
55 fun get_boolean(key: JavaString, def_value: Bool): Bool in "Java" `{
56 boolean return_value;
57 try {
58 return_value = recv.getBoolean(key, def_value);
59 } catch (ClassCastException e) {
60 return def_value;
61 }
62
63 return return_value;
64 `}
65 fun get_float(key: JavaString, def_value: Float): Float in "Java" `{
66 float return_value;
67 try {
68 return_value = recv.getFloat(key, (float) def_value);
69 } catch (ClassCastException e) {
70 return def_value;
71 }
72
73 return return_value;
74 `}
75 fun get_int(key: JavaString, def_value: Int): Int in "Java" `{
76 int return_value;
77 try {
78 return_value = recv.getInt(key, def_value);
79 } catch (ClassCastException e) {
80 return def_value;
81 }
82
83 return return_value;
84 `}
85 #FIXME: Get rid of the `int` cast when the ffi is fixed
86 fun get_long(key: JavaString, def_value: Int): Int in "Java" `{
87 long return_value;
88 try {
89 return_value = recv.getLong(key, def_value);
90 } catch (ClassCastException e) {
91 return def_value;
92 }
93
94 return (int) return_value;
95 `}
96 fun get_string(key: JavaString, def_value: JavaString): JavaString in "Java" `{
97 String return_value = null;
98 try {
99 return_value = recv.getString(key, def_value);
100 } catch (ClassCastException e) {
101 return def_value;
102 }
103
104 return return_value;
105 `}
106 end
107
108 extern class NativeSharedPreferencesEditor in "Java" `{ android.content.SharedPreferences$Editor `}
109 super JavaObject
110 redef type SELF: NativeSharedPreferencesEditor
111
112 fun clear: NativeSharedPreferencesEditor in "Java" `{ return recv.clear(); `}
113 fun commit: Bool in "Java" `{ return recv.commit(); `}
114 fun put_boolean(key: JavaString, value: Bool ): NativeSharedPreferencesEditor in "Java" `{
115 return recv.putBoolean (key, value);
116 `}
117 fun put_float(key: JavaString, value: Float): NativeSharedPreferencesEditor in "Java" `{
118 return recv.putFloat(key, (float) value);
119 `}
120 fun put_int(key: JavaString, value: Int): NativeSharedPreferencesEditor in "Java" `{
121 return recv.putInt(key, value);
122 `}
123 fun put_long(key: JavaString, value: Int): NativeSharedPreferencesEditor in "Java" `{
124 return recv.putLong(key, value);
125 `}
126 fun put_string(key: JavaString, value: JavaString): NativeSharedPreferencesEditor in "Java" `{
127 return recv.putString(key, value);
128 `}
129 fun remove(key: JavaString): NativeSharedPreferencesEditor in "Java" `{
130 return recv.remove(key);
131 `}
132 end
133
134 # Provides services to save and load data for the android platform
135 class SharedPreferences
136 protected var context: NativeActivity
137 protected var shared_preferences: NativeSharedPreferences
138 protected var editor: NativeSharedPreferencesEditor
139
140 # Automatically commits every saving/removing instructions (`true` by default)
141 var auto_commit = true
142
143 protected init(app: App, file_name: String, mode: Int)
144 do
145 self.context = app.native_activity
146 sys.jni_env.push_local_frame(1)
147 setup(file_name.to_java_string, mode)
148 sys.jni_env.pop_local_frame
149 end
150
151 # Restricts file access to the current application
152 init privately(app: App, file_name: String)
153 do
154 self.init(app, file_name, private_mode)
155 end
156
157 # File access mode
158 private fun private_mode: Int in "Java" `{ return Context.MODE_PRIVATE; `}
159
160 private fun set_vars(shared_pref: NativeSharedPreferences, editor: NativeSharedPreferencesEditor)
161 do
162 self.shared_preferences = shared_pref.new_global_ref
163 self.editor = editor.new_global_ref
164 end
165
166 private fun setup(file_name: JavaString, mode: Int) import context, set_vars in "Java" `{
167 Activity context = (Activity) SharedPreferences_context(recv);
168 SharedPreferences sp;
169
170 // Uses default SharedPreferences if file_name is an empty String
171 if (file_name.equals("")) {
172 sp = context.getPreferences( mode);
173 } else {
174 sp = context.getSharedPreferences(file_name, mode);
175 }
176
177 SharedPreferences.Editor editor = sp.edit();
178
179 SharedPreferences_set_vars(recv, sp, editor);
180 `}
181
182 private fun commit_if_auto do if auto_commit then self.commit
183
184 # Returns true if there's an entry corresponding the given key
185 fun has(key: String): Bool
186 do
187 sys.jni_env.push_local_frame(2)
188 var return_value = shared_preferences.contains(key.to_java_string)
189 sys.jni_env.pop_local_frame
190 return return_value
191 end
192
193 # Returns a `HashMap` containing all entries or `null` if there's no entries
194 #
195 # User has to manage local stack deallocation himself
196 #
197 # Example :
198 # ~~~
199 # var foo = new HashMap[JavaString, JavaObject]
200 # # ...
201 # for key, value in foo do
202 # key.delete_local_ref
203 # value.delete_local_ref
204 # end
205 # ~~~
206 # *You should use Nit getters instead and get each value one by one*
207 fun all: nullable HashMap[JavaString, JavaObject]
208 do
209 var hashmap = shared_preferences.get_all
210 if hashmap.is_empty then return null
211 return hashmap
212 end
213
214 # Returns the `Bool` value corresponding the given key or `def_value` if none
215 # or if the value isn't of correct type
216 fun bool(key: String, def_value: Bool): Bool
217 do
218 sys.jni_env.push_local_frame(2)
219 var return_value = shared_preferences.get_boolean(key.to_java_string, def_value)
220 sys.jni_env.pop_local_frame
221 return return_value
222 end
223
224 # Returns the `Float` value corresponding the given key or `def_value` if none
225 # or if the value isn't of correct type
226 fun float(key: String, def_value: Float): Float
227 do
228 sys.jni_env.push_local_frame(2)
229 var return_value = shared_preferences.get_float(key.to_java_string, def_value)
230 sys.jni_env.pop_local_frame
231 return return_value
232 end
233
234 # Returns the `Int` value corresponding the given key or `def_value` if none
235 # or if the value isn't of correct type
236 # Be aware of possible `def_value` integer overflow as the Nit `Int` corresponds
237 # to Java `long`
238 fun int(key: String, def_value: Int): Int
239 do
240 sys.jni_env.push_local_frame(2)
241 var return_value = shared_preferences.get_int(key.to_java_string, def_value)
242 sys.jni_env.pop_local_frame
243 return return_value
244 end
245
246 # Returns the `Int` value corresponding the given key or `def_value` if none
247 # or if the value isn't of correct type
248 # Calls `getLong(key, value)` java method
249 # Nit `Int` is equivalent to Java `long` so that no integer overflow will occur
250 fun long(key: String, def_value: Int): Int
251 do
252 sys.jni_env.push_local_frame(2)
253 var return_value = shared_preferences.get_long(key.to_java_string, def_value)
254 sys.jni_env.pop_local_frame
255 return return_value
256 end
257
258 # Returns the `String` value corresponding the given key or `def_value` if none
259 # or if the value isn't of correct type
260 fun string(key: String, def_value: String): String
261 do
262 sys.jni_env.push_local_frame(3)
263 var java_return_value = shared_preferences.get_string(key.to_java_string,
264 def_value.to_java_string)
265 var nit_return_value = java_return_value.to_s
266 sys.jni_env.pop_local_frame
267 return nit_return_value
268 end
269
270 # Clears all the dictionnary entries in the specified file or the default file
271 # if none specified at instanciation
272 # Returns `self` allowing fluent programming
273 fun clear: SharedPreferences
274 do
275 editor.clear
276 commit_if_auto
277 return self
278 end
279
280 # If auto_commit is `false`, has to be called to save the data to persistant memory
281 fun commit: Bool
282 do
283 sys.jni_env.push_local_frame(1)
284 var return_value = editor.commit
285 sys.jni_env.pop_local_frame
286 return return_value
287 end
288
289 # Set a key-value pair using a `Bool` value
290 # Returns `self` allowing fluent programming
291 fun add_bool(key: String, value: Bool ): SharedPreferences
292 do
293 sys.jni_env.push_local_frame(1)
294 editor.put_boolean(key.to_java_string, value)
295 sys.jni_env.pop_local_frame
296 commit_if_auto
297 return self
298 end
299
300 # Set a key-value pair using a `Float` value
301 # Returns `self` allowing fluent programming
302 #
303 # Be aware of possible loss of precision as Nit `Float` corresponds to Java `double`
304 # and the methods stores a Java `float`
305 fun add_float(key: String, value: Float): SharedPreferences
306 do
307 sys.jni_env.push_local_frame(1)
308 editor.put_float(key.to_java_string, value)
309 sys.jni_env.pop_local_frame
310 commit_if_auto
311 return self
312 end
313
314 # Set a key-value pair using a `Int` type value
315 # Returns `self` allowing fluent programming
316 #
317 # Be aware of possible integer overflow as the Nit `Int` corresponds to Java `long`
318 # and the methods stores a Java `int`
319 # *You might want to use add_long instead*
320 fun add_int(key: String, value: Int): SharedPreferences
321 do
322 sys.jni_env.push_local_frame(1)
323 editor.put_int(key.to_java_string, value)
324 sys.jni_env.pop_local_frame
325 commit_if_auto
326 return self
327 end
328
329 # Set a key-value pair using a `Int` type value
330 # Returns `self` allowing fluent programming
331 fun add_long(key: String, value: Int): SharedPreferences
332 do
333 sys.jni_env.push_local_frame(1)
334 editor.put_long(key.to_java_string, value)
335 sys.jni_env.pop_local_frame
336 commit_if_auto
337 return self
338 end
339
340 # Set a key-value pair using a `String` type value
341 # Returns `self` allowing fluent programming
342 fun add_string(key: String, value: String): SharedPreferences
343 do
344 sys.jni_env.push_local_frame(2)
345 editor.put_string(key.to_java_string, value.to_java_string)
346 sys.jni_env.pop_local_frame
347 commit_if_auto
348 return self
349 end
350
351 # Removes the corresponding entry in the file
352 # Returns `self` allowing fluent programming
353 fun remove(key: String): SharedPreferences
354 do
355 sys.jni_env.push_local_frame(1)
356 editor.remove(key.to_java_string)
357 sys.jni_env.pop_local_frame
358 commit_if_auto
359 return self
360 end
361
362 # Deallocate global references allocated by the SharedPreferences instance
363 fun destroy
364 do
365 self.shared_preferences.delete_global_ref
366 self.editor.delete_global_ref
367 end
368
369 # Save data to file dynamically calling the appropriate method according to value type
370 # Non-primitive Object (`String` excluded) will be stored as a serialized json `String`
371 # Nit `Int` are stored as Java `long`, therefore you'll have to retrieve it with `long` method
372 fun []=(key: String, value: Serializable)
373 do
374 value.add_to_preferences(self, key)
375 commit_if_auto
376 end
377
378 # Retrieve an `Object` serialized via `[]=` function
379 # Returns `null` if there's no serialized object corresponding to the given key
380 # Make sure that the serialized object is `auto_serializable` or that it redefines
381 # the appropriate methods. Refer to `Serializable` documentation for further details
382 fun deserialize(key: String): nullable Object
383 do
384 var serialized_string = self.string(key, "")
385
386 if serialized_string == "" then return null
387
388 var deserializer = new JsonDeserializer(serialized_string)
389 return deserializer.deserialize
390 end
391 end
392
393 redef class App
394 fun shared_preferences: SharedPreferences is cached do
395 return new SharedPreferences.privately(self, "")
396 end
397 end
398
399 redef class Serializable
400 # Called by []= operator to dynamically call the appropriate add method
401 # Non-primitive Object (`String` excluded) will be stored as a serialized json `String`
402 # Refine your class to customize this method behaviour
403 protected fun add_to_preferences(shared_preferences: SharedPreferences, key: String)
404 do
405 var serialized_string = new StringOStream
406 var serializer = new JsonSerializer(serialized_string)
407 serializer.serialize(self)
408
409 shared_preferences.add_string(key, serialized_string.to_s)
410 end
411 end
412
413 redef class Bool
414 redef fun add_to_preferences(shared_preferences, key)
415 do
416 shared_preferences.add_bool(key, self)
417 end
418 end
419
420 redef class Int
421 redef fun add_to_preferences(shared_preferences, key)
422 do
423 shared_preferences.add_long(key, self)
424 end
425 end
426
427 redef class Float
428 redef fun add_to_preferences(shared_preferences, key)
429 do
430 shared_preferences.add_float(key, self)
431 end
432 end
433
434 redef class String
435 redef fun add_to_preferences(shared_preferences, key)
436 do
437 shared_preferences.add_string(key, self)
438 end
439 end