/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using Tizen.Internals.Errors; namespace Tizen.Applications { /// /// The Preference class provides APIs to store and retrieve application specific data/preference. A preference is saved in the form of a key-value pair. /// Keys are always text strings and value can be any one of four types: integer, double, string and boolean. /// public static class Preference { private const string LogTag = "Tizen.Applications"; private static Interop.Preference.ChangedCallback s_preferenceChangedCallback; private static IDictionary s_eventMap = new Dictionary(); static Preference() { s_preferenceChangedCallback = (string key, IntPtr userData) => { try { s_eventMap[key]?.FireEvent(); } catch (Exception e) { Log.Warn(LogTag, e.Message); } }; } /// /// Retrieves all keys of the application preferences /// /// /// The list of keys /// /// /// /// Preference.Set("Option_enabled", true); /// Preference.Set("active_user", "Joe"); /// Preference.Set("default_volume", 10); /// Preference.Set("brightness", "0.6"); /// foreach(string key in Preference.Keys) /// { /// Console.WriteLine("key {0}", key); /// } /// /// public static IEnumerable Keys { get { var collection = new List(); Interop.Preference.ItemCallback itemsCallback = (string key, IntPtr userData) => { collection.Add(key); return true; }; Interop.Preference.ForeachItem(itemsCallback, IntPtr.Zero); return collection; } } /// /// Gets the event context for the given key. /// /// /// The preference key /// The event context of respective key /// Thrown if the key is not found /// Thrown if the key is an invalid parameter. /// /// /// private static void Preference_PreferenceChanged(object sender, PreferenceChangedEventArgs e) /// { /// Console.WriteLine("key {0}", e.Key); /// } /// /// Preference.EventContext context = null; /// Preference.GetEventContext("active_user").TryGetTarget(out context); /// if(context != null) /// { /// context.Changed += Preference_PreferenceChanged; /// } /// /// Preference.Set("active_user", "Poe"); /// /// Preference.GetEventContext("active_user").TryGetTarget(out context); /// if (context != null) /// { /// context.Changed -= Preference_PreferenceChanged; /// } /// /// public static WeakReference GetEventContext(string key) { if (!s_eventMap.ContainsKey(key)) { if (Contains(key)) { s_eventMap[key] = new EventContext(key); } else { throw PreferenceErrorFactory.GetException((int)PreferenceErrorFactory.PreferenceError.KeyNotAvailable); } } return new WeakReference(s_eventMap[key]); } /// /// Checks whether the given key exists in the preference. /// /// The name of the key to check /// true if the key exists in the preference, otherwise false /// Thrown if the key is an invalid parameter. /// Thrown when method failed due to internal IO error. /// /// /// Preference.Set("active_user", "Joe"); /// bool exists = Preference.Contains("active_user"); /// if (exists) /// { /// string value = Preference.Get("active_user"); /// Console.WriteLine("user {0}", value); /// } /// /// public static bool Contains(string key) { bool contains; int ret = Interop.Preference.IsExisting(key, out contains); if (ret != (int)PreferenceErrorFactory.PreferenceError.None) { Log.Error(LogTag, "Failed to find key"); throw PreferenceErrorFactory.GetException(ret); } return contains; } /// /// Sets a key-value pair representing the preference. /// /// /// If the key already exists in the Preference, old value will be overwritten with new value. /// Data types supported for value are: integer, double, string and bool. /// /// The name of the key to create/modigy /// The value corresponding to the key. /// Thrown if the key is an invalid parameter. /// Thrown when method failed due to internal IO error. /// /// /// Preference.Set("Option_enabled", true); /// Preference.Set("active_user", "Joe"); /// Preference.Set("default_volume", 10); /// Preference.Set("brightness", "0.6"); /// /// public static void Set(string key, object value) { int ret = 0; if (value is int) { ret = Interop.Preference.SetInt(key, (int)value); if (ret != (int)PreferenceErrorFactory.PreferenceError.None) { Log.Error(LogTag, "Failed to find key"); throw PreferenceErrorFactory.GetException(ret); } } else if (value is double) { ret = Interop.Preference.SetDouble(key, (double)value); if (ret != (int)PreferenceErrorFactory.PreferenceError.None) { Log.Error(LogTag, "Failed to find key"); throw PreferenceErrorFactory.GetException(ret); } } else if (value is string) { ret = Interop.Preference.SetString(key, (string)value); if (ret != (int)PreferenceErrorFactory.PreferenceError.None) { Log.Error(LogTag, "Failed to find key"); throw PreferenceErrorFactory.GetException(ret); } } else if (value is bool) { ret = Interop.Preference.SetBoolean(key, (bool)value); if (ret != (int)PreferenceErrorFactory.PreferenceError.None) { Log.Error(LogTag, "Failed to find key"); throw PreferenceErrorFactory.GetException(ret); } } else { Log.Error(LogTag, "Failed to Set"); throw new ArgumentException("Invalid parameter"); } } /// /// Gets the value of a preference item with the specified key. /// Note that this is a generic method. /// /// The generic type to return. /// The key of the preference /// The value of the preference item if it is of the specified generic type. /// Thrown if the key is not found /// Thrown if the key is an invalid parameter. /// Thrown when method failed due to internal IO error. /// /// /// bool exists = Preference.Contains("active_user"); /// if (exists) /// { /// string value = Preference.Get("active_user"); /// Console.WriteLine("user {0}", value); /// } /// /// public static T Get(string key) { object result = null; int ret = (int)PreferenceErrorFactory.PreferenceError.None; if (typeof(T) == typeof(bool)) { bool val; ret = Interop.Preference.GetBoolean(key, out val); result = val; } else if (typeof(T) == typeof(int)) { int val; ret = Interop.Preference.GetInt(key, out val); result = val; } else if (typeof(T) == typeof(string)) { string val; ret = Interop.Preference.GetString(key, out val); result = val; } else if (typeof(T) == typeof(double)) { double val; ret = Interop.Preference.GetDouble(key, out val); result = val; } else { Log.Error(LogTag, "Failed to remove key"); throw new ArgumentException("Invalid parameter"); } if (ret != (int)PreferenceErrorFactory.PreferenceError.None) { Log.Error(LogTag, "Failed to remove key"); throw PreferenceErrorFactory.GetException(ret); } return (result != null) ? (T)result : default(T); } /// /// Removes any preference value with the given key. /// /// The key to remove /// Thrown if the key is not found /// Thrown when method failed due to internal IO error. /// /// /// bool exists = Preference.Contains("active_user"); /// if (exists) /// { /// string value = Preference.Remove("active_user"); /// } /// /// public static void Remove(string key) { int ret = Interop.Preference.Remove(key); if (ret != (int)PreferenceErrorFactory.PreferenceError.None) { Log.Error(LogTag, "Failed to remove key"); throw PreferenceErrorFactory.GetException(ret); } } /// /// Removes all key-value pairs from the preference. /// /// Thrown when method failed due to internal IO error. /// /// /// Preference.Set("Option_enabled", true); /// Preference.Set("active_user", "Joe"); /// Preference.Set("default_volume", 10); /// Preference.Set("brightness", "0.6"); /// Preference.RemoveAll(); /// /// public static void RemoveAll() { int ret = Interop.Preference.RemoveAll(); if (ret != (int)PreferenceErrorFactory.PreferenceError.None) { Log.Error(LogTag, "Failed to remove all keys"); throw PreferenceErrorFactory.GetException(ret); } } private static void AllowChangeNotifications(string key) { int ret = Interop.Preference.SetChangedCb(key, s_preferenceChangedCallback, IntPtr.Zero); if (ret != (int)PreferenceErrorFactory.PreferenceError.None) { Log.Error(LogTag, "Failed to set key notification"); throw PreferenceErrorFactory.GetException(ret); } } private static void DisallowChangeNotifications(string key) { int ret = Interop.Preference.UnsetChangedCb(key); if (ret != (int)PreferenceErrorFactory.PreferenceError.None) { Log.Error(LogTag, "Failed to remove key notification"); throw PreferenceErrorFactory.GetException(ret); } } /// /// The class manages event handlers of preference keys. The class enables having event handlers for individual preference keys. /// public class EventContext { private string _key; internal EventContext(string key) { _key = key; } /// /// Occurs whenever there is change in the value of preference key. /// /// Thrown when the key does not exist or when there is an invalid parameter. /// Thrown when the Bundle instance has been disposed. /// /// /// private static void Preference_PreferenceChanged(object sender, PreferenceChangedEventArgs e) /// { /// Console.WriteLine("key {0}", e.Key); /// } /// Preference.EventContext context = null; /// Preference.GetEventContext("active_user").TryGetTarget(out context); /// if(context != null) /// { /// context.Changed += Preference_PreferenceChanged; /// } /// /// Preference.Set("active_user", "Poe"); /// /// Preference.GetEventContext("active_user").TryGetTarget(out context); /// if (context != null) /// { /// context.Changed -= Preference_PreferenceChanged; /// } /// /// public event EventHandler Changed { add { if (_changed == null) { AllowChangeNotifications(_key); } _changed += value; } remove { _changed -= value; if (_changed == null) { DisallowChangeNotifications(_key); s_eventMap.Remove(_key); } } } private event EventHandler _changed; internal void FireEvent() { _changed?.Invoke(null, new PreferenceChangedEventArgs() { Key = _key }); } } } internal static class PreferenceErrorFactory { internal enum PreferenceError { None = ErrorCode.None, OutOfMemory = ErrorCode.OutOfMemory, InvalidParameter = ErrorCode.InvalidParameter, KeyNotAvailable = -0x01100000 | 0x30, IoError = ErrorCode.IoError } static internal Exception GetException(int error) { if ((PreferenceError)error == PreferenceError.OutOfMemory) { return new OutOfMemoryException("Out of memory"); } else if ((PreferenceError)error == PreferenceError.InvalidParameter) { return new ArgumentException("Invalid parameter"); } else if ((PreferenceError)error == PreferenceError.KeyNotAvailable) { return new KeyNotFoundException("Key does not exist in the bundle"); } else if ((PreferenceError)error == PreferenceError.IoError) { return new System.IO.IOException("I/O Error"); } else { return new ArgumentException("Unknown error"); } } } }