2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 using System.Globalization;
19 using System.Runtime.InteropServices;
22 using Tizen.Applications.CoreBackend;
24 namespace Tizen.Applications
27 /// This class represents an application controlled lifecycles by the backend system.
29 /// <since_tizen> 3 </since_tizen>
30 public class CoreApplication : Application
32 private readonly ICoreBackend _backend;
33 private bool _disposedValue = false;
35 private static Timer sTimer;
38 /// Initializes the CoreApplication class.
40 /// <param name="backend">The backend instance implementing ICoreBacked interface.</param>
41 /// <since_tizen> 3 </since_tizen>
42 public CoreApplication(ICoreBackend backend)
48 /// Occurs when the application is launched.
50 /// <since_tizen> 3 </since_tizen>
51 public event EventHandler Created;
54 /// Occurs when the application is about to shutdown.
56 /// <since_tizen> 3 </since_tizen>
57 public event EventHandler Terminated;
60 /// Occurs whenever the application receives the appcontrol message.
62 /// <since_tizen> 3 </since_tizen>
63 public event EventHandler<AppControlReceivedEventArgs> AppControlReceived;
66 /// Occurs when the system memory is low.
68 /// <since_tizen> 3 </since_tizen>
69 public event EventHandler<LowMemoryEventArgs> LowMemory;
72 /// Occurs when the system battery is low.
74 /// <since_tizen> 3 </since_tizen>
75 public event EventHandler<LowBatteryEventArgs> LowBattery;
78 /// Occurs when the system language is chagned.
80 /// <since_tizen> 3 </since_tizen>
81 public event EventHandler<LocaleChangedEventArgs> LocaleChanged;
84 /// Occurs when the region format is changed.
86 /// <since_tizen> 3 </since_tizen>
87 public event EventHandler<RegionFormatChangedEventArgs> RegionFormatChanged;
90 /// Occurs when the device orientation is changed.
92 /// <since_tizen> 3 </since_tizen>
93 public event EventHandler<DeviceOrientationEventArgs> DeviceOrientationChanged;
96 /// The backend instance.
98 /// <since_tizen> 3 </since_tizen>
99 protected ICoreBackend Backend { get { return _backend; } }
102 /// Runs the application's main loop.
104 /// <param name="args">Arguments from commandline.</param>
105 /// <since_tizen> 3 </since_tizen>
106 public override void Run(string[] args)
110 _backend.AddEventHandler(EventType.Created, OnCreate);
111 _backend.AddEventHandler(EventType.Terminated, OnTerminate);
112 _backend.AddEventHandler<AppControlReceivedEventArgs>(EventType.AppControlReceived, OnAppControlReceived);
113 _backend.AddEventHandler<LowMemoryEventArgs>(EventType.LowMemory, OnLowMemory);
114 _backend.AddEventHandler<LowBatteryEventArgs>(EventType.LowBattery, OnLowBattery);
115 _backend.AddEventHandler<LocaleChangedEventArgs>(EventType.LocaleChanged, OnLocaleChanged);
116 _backend.AddEventHandler<RegionFormatChangedEventArgs>(EventType.RegionFormatChanged, OnRegionFormatChanged);
117 _backend.AddEventHandler<DeviceOrientationEventArgs>(EventType.DeviceOrientationChanged, OnDeviceOrientationChanged);
119 string[] argsClone = new string[args.Length + 1];
122 args.CopyTo(argsClone, 1);
124 argsClone[0] = string.Empty;
126 _backend.Run(argsClone);
130 /// Exits the main loop of the application.
132 /// <since_tizen> 3 </since_tizen>
133 public override void Exit()
139 /// Overrides this method if want to handle behavior when the application is launched.
140 /// If base.OnCreated() is not called, the event 'Created' will not be emitted.
142 /// <since_tizen> 3 </since_tizen>
143 protected virtual void OnCreate()
145 if (!GlobalizationMode.Invariant)
147 string locale = ULocale.GetDefaultLocale();
148 ChangeCurrentUICultureInfo(locale);
149 ChangeCurrentCultureInfo(locale);
153 Log.Warn(LogTag, "Run in invariant mode");
156 Created?.Invoke(this, EventArgs.Empty);
160 /// Overrides this method if want to handle behavior when the application is terminated.
161 /// If base.OnTerminate() is not called, the event 'Terminated' will not be emitted.
163 /// <since_tizen> 3 </since_tizen>
164 protected virtual void OnTerminate()
166 Terminated?.Invoke(this, EventArgs.Empty);
170 /// Overrides this method if want to handle behavior when the application receives the appcontrol message.
171 /// If base.OnAppControlReceived() is not called, the event 'AppControlReceived' will not be emitted.
173 /// <param name="e"></param>
174 /// <since_tizen> 3 </since_tizen>
175 protected virtual void OnAppControlReceived(AppControlReceivedEventArgs e)
177 AppControlReceived?.Invoke(this, e);
181 /// Overrides this method if want to handle behavior when the system memory is low.
182 /// If base.OnLowMemory() is not called, the event 'LowMemory' will not be emitted.
184 /// <param name="e">The low memory event argument</param>
185 /// <since_tizen> 3 </since_tizen>
186 protected virtual void OnLowMemory(LowMemoryEventArgs e)
188 LowMemory?.Invoke(this, e);
189 double interval = new Random().Next(10 * 1000);
191 interval = 10 * 1000;
193 sTimer = new Timer(interval);
194 sTimer.Elapsed += OnTimedEvent;
195 sTimer.AutoReset = false;
196 sTimer.Enabled = true;
199 private static void OnTimedEvent(Object source, ElapsedEventArgs e)
205 /// Overrides this method if want to handle behavior when the system battery is low.
206 /// If base.OnLowBattery() is not called, the event 'LowBattery' will not be emitted.
208 /// <param name="e">The low battery event argument</param>
209 /// <since_tizen> 3 </since_tizen>
210 protected virtual void OnLowBattery(LowBatteryEventArgs e)
212 LowBattery?.Invoke(this, e);
216 /// Overrides this method if want to handle behavior when the system language is changed.
217 /// If base.OnLocaleChanged() is not called, the event 'LocaleChanged' will not be emitted.
219 /// <param name="e">The locale changed event argument</param>
220 /// <since_tizen> 3 </since_tizen>
221 protected virtual void OnLocaleChanged(LocaleChangedEventArgs e)
223 if (!GlobalizationMode.Invariant)
225 ChangeCurrentUICultureInfo(e.Locale);
228 LocaleChanged?.Invoke(this, e);
232 /// Overrides this method if want to handle behavior when the region format is changed.
233 /// If base.OnRegionFormatChanged() is not called, the event 'RegionFormatChanged' will not be emitted.
235 /// <param name="e">The region format changed event argument</param>
236 /// <since_tizen> 3 </since_tizen>
237 protected virtual void OnRegionFormatChanged(RegionFormatChangedEventArgs e)
239 if (!GlobalizationMode.Invariant)
241 ChangeCurrentCultureInfo(e.Region);
244 RegionFormatChanged?.Invoke(this, e);
248 /// Overrides this method if want to handle behavior when the device orientation is changed.
249 /// If base.OnRegionFormatChanged() is not called, the event 'RegionFormatChanged' will not be emitted.
251 /// <param name="e">The device orientation changed event argument</param>
252 /// <since_tizen> 3 </since_tizen>
253 protected virtual void OnDeviceOrientationChanged(DeviceOrientationEventArgs e)
255 DeviceOrientationChanged?.Invoke(this, e);
259 /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
261 /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
262 /// <since_tizen> 3 </since_tizen>
263 protected override void Dispose(bool disposing)
272 _disposedValue = true;
274 base.Dispose(disposing);
277 private CultureInfo ConvertCultureInfo(string locale)
279 ULocale pLocale = new ULocale(locale);
280 string cultureName = CultureInfoHelper.GetCultureName(pLocale.Locale.Replace("_", "-"));
282 if (!string.IsNullOrEmpty(cultureName))
286 return new CultureInfo(cultureName);
288 catch (CultureNotFoundException)
290 Log.Error(LogTag, "CultureNotFoundException occurs. CultureName: " + cultureName);
296 return new CultureInfo(pLocale.LCID);
298 catch (ArgumentOutOfRangeException)
300 return GetFallbackCultureInfo(pLocale);
302 catch (CultureNotFoundException)
304 return GetFallbackCultureInfo(pLocale);
308 private void ChangeCurrentCultureInfo(string locale)
310 CultureInfo cultureInfo = ConvertCultureInfo(locale);
311 if (cultureInfo != null)
313 CultureInfo.CurrentCulture = cultureInfo;
317 Log.Error(LogTag, "CultureInfo is null. locale: " + locale);
321 private void ChangeCurrentUICultureInfo(string locale)
323 CultureInfo cultureInfo = ConvertCultureInfo(locale);
324 if (cultureInfo != null)
326 CultureInfo.CurrentUICulture = cultureInfo;
330 Log.Error(LogTag, "CultureInfo is null. locale: " + locale);
334 private bool ExistCultureInfo(string locale)
336 foreach (var cultureInfo in CultureInfo.GetCultures(CultureTypes.AllCultures))
338 if (cultureInfo.Name == locale)
347 private CultureInfo GetCultureInfo(string locale)
349 if (!ExistCultureInfo(locale))
356 return new CultureInfo(locale);
358 catch (CultureNotFoundException)
364 private CultureInfo GetFallbackCultureInfo(ULocale uLocale)
366 CultureInfo fallbackCultureInfo = null;
367 string locale = string.Empty;
369 if (uLocale.Locale != null)
371 locale = uLocale.Locale.Replace("_", "-");
372 fallbackCultureInfo = GetCultureInfo(locale);
375 if (fallbackCultureInfo == null && uLocale.Language != null && uLocale.Script != null && uLocale.Country != null)
377 locale = uLocale.Language + "-" + uLocale.Script + "-" + uLocale.Country;
378 fallbackCultureInfo = GetCultureInfo(locale);
381 if (fallbackCultureInfo == null && uLocale.Language != null && uLocale.Script != null)
383 locale = uLocale.Language + "-" + uLocale.Script;
384 fallbackCultureInfo = GetCultureInfo(locale);
387 if (fallbackCultureInfo == null && uLocale.Language != null && uLocale.Country != null)
389 locale = uLocale.Language + "-" + uLocale.Country;
390 fallbackCultureInfo = GetCultureInfo(locale);
393 if (fallbackCultureInfo == null && uLocale.Language != null)
395 locale = uLocale.Language;
396 fallbackCultureInfo = GetCultureInfo(locale);
399 if (fallbackCultureInfo == null)
403 fallbackCultureInfo = new CultureInfo("en");
405 catch (CultureNotFoundException e)
407 Log.Error(LogTag, "Failed to create CultureInfo. err = " + e.Message);
411 return fallbackCultureInfo;
415 internal static class GlobalizationMode
417 private static int _invariant = -1;
419 internal static bool Invariant
423 if (_invariant == -1)
425 string value = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT");
426 _invariant = value != null ? (value.Equals("1") ? 1 : 0) : 0;
429 return _invariant != 0;
434 internal class ULocale
436 private const int ULOC_FULLNAME_CAPACITY = 157;
437 private const int ULOC_LANG_CAPACITY = 12;
438 private const int ULOC_SCRIPT_CAPACITY = 6;
439 private const int ULOC_COUNTRY_CAPACITY = 4;
440 private const int ULOC_VARIANT_CAPACITY = ULOC_FULLNAME_CAPACITY;
442 internal ULocale(string locale)
444 Locale = Canonicalize(locale);
445 Language = GetLanguage(Locale);
446 Script = GetScript(Locale);
447 Country = GetCountry(Locale);
448 Variant = GetVariant(Locale);
449 LCID = GetLCID(Locale);
452 internal string Locale { get; private set; }
453 internal string Language { get; private set; }
454 internal string Script { get; private set; }
455 internal string Country { get; private set; }
456 internal string Variant { get; private set; }
457 internal int LCID { get; private set; }
459 private string Canonicalize(string localeName)
461 // Get the locale name from ICU
462 StringBuilder sb = new StringBuilder(ULOC_FULLNAME_CAPACITY);
463 if (Interop.BaseUtilsi18n.Canonicalize(localeName, sb, sb.Capacity) <= 0)
468 return sb.ToString();
471 private string GetLanguage(string locale)
473 // Get the language name from ICU
474 StringBuilder sb = new StringBuilder(ULOC_LANG_CAPACITY);
475 if (Interop.BaseUtilsi18n.GetLanguage(locale, sb, sb.Capacity, out int bufSizeLanguage) != 0)
480 return sb.ToString();
483 private string GetScript(string locale)
485 // Get the script name from ICU
486 StringBuilder sb = new StringBuilder(ULOC_SCRIPT_CAPACITY);
487 if (Interop.BaseUtilsi18n.GetScript(locale, sb, sb.Capacity) <= 0)
492 return sb.ToString();
495 private string GetCountry(string locale)
499 // Get the country name from ICU
500 StringBuilder sb = new StringBuilder(ULOC_COUNTRY_CAPACITY);
501 if (Interop.BaseUtilsi18n.GetCountry(locale, sb, sb.Capacity, out err) <= 0)
506 return sb.ToString();
509 private string GetVariant(string locale)
511 // Get the variant name from ICU
512 StringBuilder sb = new StringBuilder(ULOC_VARIANT_CAPACITY);
513 if (Interop.BaseUtilsi18n.GetVariant(locale, sb, sb.Capacity) <= 0)
518 return sb.ToString();
521 private int GetLCID(string locale)
523 // Get the LCID from ICU
524 uint lcid = Interop.BaseUtilsi18n.GetLCID(locale);
528 internal static string GetDefaultLocale()
530 IntPtr stringPtr = IntPtr.Zero;
531 if (Interop.BaseUtilsi18n.GetDefault(out stringPtr) != 0)
536 if (stringPtr == IntPtr.Zero)
541 return Marshal.PtrToStringAnsi(stringPtr);