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.Collections.Concurrent;
19 using System.ComponentModel;
20 using System.Globalization;
21 using System.Runtime.InteropServices;
23 using System.Threading;
25 using Tizen.Applications.CoreBackend;
27 namespace Tizen.Applications
30 /// This class represents an application controlled lifecycles by the backend system.
32 /// <since_tizen> 3 </since_tizen>
33 public class CoreApplication : Application
35 private readonly ICoreBackend _backend;
36 private readonly ICoreTask _task;
37 private bool _disposedValue = false;
39 private static System.Timers.Timer sTimer;
42 /// Initializes the CoreApplication class.
44 /// <param name="backend">The backend instance implementing ICoreBacked interface.</param>
45 /// <since_tizen> 3 </since_tizen>
46 public CoreApplication(ICoreBackend backend)
53 /// Initializes the CoreApplication class.
55 /// <param name="backend">The backend instance implementing ICoreBackend interface.</param>
56 /// <param name="task">The backend instance implmenting ICoreTask interface.</param>
57 /// <since_tizen> 10 </since_tizen>
58 [EditorBrowsable(EditorBrowsableState.Never)]
59 public CoreApplication(ICoreBackend backend, ICoreTask task)
66 /// Occurs when the application is launched.
68 /// <since_tizen> 3 </since_tizen>
69 public event EventHandler Created;
72 /// Occurs when the application is about to shutdown.
74 /// <since_tizen> 3 </since_tizen>
75 public event EventHandler Terminated;
78 /// Occurs whenever the application receives the appcontrol message.
80 /// <since_tizen> 3 </since_tizen>
81 public event EventHandler<AppControlReceivedEventArgs> AppControlReceived;
84 /// Occurs when the system memory is low.
86 /// <since_tizen> 3 </since_tizen>
87 public event EventHandler<LowMemoryEventArgs> LowMemory;
90 /// Occurs when the system battery is low.
92 /// <since_tizen> 3 </since_tizen>
93 public event EventHandler<LowBatteryEventArgs> LowBattery;
96 /// Occurs when the system language is chagned.
98 /// <since_tizen> 3 </since_tizen>
99 public event EventHandler<LocaleChangedEventArgs> LocaleChanged;
102 /// Occurs when the region format is changed.
104 /// <since_tizen> 3 </since_tizen>
105 public event EventHandler<RegionFormatChangedEventArgs> RegionFormatChanged;
108 /// Occurs when the device orientation is changed.
110 /// <since_tizen> 3 </since_tizen>
111 public event EventHandler<DeviceOrientationEventArgs> DeviceOrientationChanged;
114 /// The backend instance.
116 /// <since_tizen> 3 </since_tizen>
117 protected ICoreBackend Backend { get { return _backend; } }
120 /// Runs the application's main loop.
122 /// <param name="args">Arguments from commandline.</param>
123 /// <since_tizen> 3 </since_tizen>
124 public override void Run(string[] args)
128 _backend.AddEventHandler(EventType.Created, OnCreate);
129 _backend.AddEventHandler(EventType.Terminated, OnTerminate);
130 _backend.AddEventHandler<AppControlReceivedEventArgs>(EventType.AppControlReceived, OnAppControlReceived);
131 _backend.AddEventHandler<LowMemoryEventArgs>(EventType.LowMemory, OnLowMemory);
132 _backend.AddEventHandler<LowBatteryEventArgs>(EventType.LowBattery, OnLowBattery);
133 _backend.AddEventHandler<LocaleChangedEventArgs>(EventType.LocaleChanged, OnLocaleChanged);
134 _backend.AddEventHandler<RegionFormatChangedEventArgs>(EventType.RegionFormatChanged, OnRegionFormatChanged);
135 _backend.AddEventHandler<DeviceOrientationEventArgs>(EventType.DeviceOrientationChanged, OnDeviceOrientationChanged);
137 string[] argsClone = new string[args == null ? 1 : args.Length + 1];
138 if (args != null && args.Length > 1)
140 args.CopyTo(argsClone, 1);
142 argsClone[0] = string.Empty;
146 ICoreTaskBackend backend = (ICoreTaskBackend)_backend;
147 backend.SetCoreTask(_task);
148 backend.Run(argsClone);
152 _backend.Run(argsClone);
157 /// Exits the main loop of the application.
159 /// <since_tizen> 3 </since_tizen>
160 public override void Exit()
166 /// Overrides this method if want to handle behavior when the application is launched.
167 /// If base.OnCreated() is not called, the event 'Created' will not be emitted.
169 /// <since_tizen> 3 </since_tizen>
170 protected virtual void OnCreate()
174 TizenUISynchronizationContext.Initialize();
177 if (!GlobalizationMode.Invariant)
179 string locale = ULocale.GetDefaultLocale();
180 ChangeCurrentUICultureInfo(locale);
181 ChangeCurrentCultureInfo(locale);
185 Log.Warn(LogTag, "Run in invariant mode");
188 Created?.Invoke(this, EventArgs.Empty);
192 /// Overrides this method if want to handle behavior when the application is terminated.
193 /// If base.OnTerminate() is not called, the event 'Terminated' will not be emitted.
195 /// <since_tizen> 3 </since_tizen>
196 protected virtual void OnTerminate()
198 Terminated?.Invoke(this, EventArgs.Empty);
202 /// Overrides this method if want to handle behavior when the application receives the appcontrol message.
203 /// If base.OnAppControlReceived() is not called, the event 'AppControlReceived' will not be emitted.
205 /// <param name="e"></param>
206 /// <since_tizen> 3 </since_tizen>
207 protected virtual void OnAppControlReceived(AppControlReceivedEventArgs e)
209 AppControlReceived?.Invoke(this, e);
213 /// Overrides this method if want to handle behavior when the system memory is low.
214 /// If base.OnLowMemory() is not called, the event 'LowMemory' will not be emitted.
216 /// <param name="e">The low memory event argument</param>
217 /// <since_tizen> 3 </since_tizen>
218 protected virtual void OnLowMemory(LowMemoryEventArgs e)
220 LowMemory?.Invoke(this, e);
221 double interval = new Random().Next(10 * 1000);
223 interval = 10 * 1000;
225 sTimer = new System.Timers.Timer(interval);
226 sTimer.Elapsed += OnTimedEvent;
227 sTimer.AutoReset = false;
228 sTimer.Enabled = true;
231 private static void OnTimedEvent(Object source, ElapsedEventArgs e)
237 /// Overrides this method if want to handle behavior when the system battery is low.
238 /// If base.OnLowBattery() is not called, the event 'LowBattery' will not be emitted.
240 /// <param name="e">The low battery event argument</param>
241 /// <since_tizen> 3 </since_tizen>
242 protected virtual void OnLowBattery(LowBatteryEventArgs e)
244 LowBattery?.Invoke(this, e);
248 /// Overrides this method if want to handle behavior when the system language is changed.
249 /// If base.OnLocaleChanged() is not called, the event 'LocaleChanged' will not be emitted.
251 /// <param name="e">The locale changed event argument</param>
252 /// <since_tizen> 3 </since_tizen>
253 protected virtual void OnLocaleChanged(LocaleChangedEventArgs e)
255 if (!GlobalizationMode.Invariant)
257 ChangeCurrentUICultureInfo(e.Locale);
260 LocaleChanged?.Invoke(this, e);
264 /// Overrides this method if want to handle behavior when the region format is changed.
265 /// If base.OnRegionFormatChanged() is not called, the event 'RegionFormatChanged' will not be emitted.
267 /// <param name="e">The region format changed event argument</param>
268 /// <since_tizen> 3 </since_tizen>
269 protected virtual void OnRegionFormatChanged(RegionFormatChangedEventArgs e)
271 if (!GlobalizationMode.Invariant)
273 ChangeCurrentCultureInfo(e.Region);
276 RegionFormatChanged?.Invoke(this, e);
280 /// Overrides this method if want to handle behavior when the device orientation is changed.
281 /// If base.OnRegionFormatChanged() is not called, the event 'RegionFormatChanged' will not be emitted.
283 /// <param name="e">The device orientation changed event argument</param>
284 /// <since_tizen> 3 </since_tizen>
285 protected virtual void OnDeviceOrientationChanged(DeviceOrientationEventArgs e)
287 DeviceOrientationChanged?.Invoke(this, e);
291 /// Dispatches an asynchronous message to the main loop of the CoreTask.
293 /// <param name="runner">The runner callaback.</param>
294 /// <exception cref="ArgumentNullException">Thrown when the runner is null.</exception>
295 /// <since_tizen> 10 </since_tizen>
296 [EditorBrowsable(EditorBrowsableState.Never)]
297 public void Post(Action runner)
301 throw new ArgumentNullException(nameof(runner));
304 GSourceManager.Post(runner);
308 /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
310 /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
311 /// <since_tizen> 3 </since_tizen>
312 protected override void Dispose(bool disposing)
321 _disposedValue = true;
323 base.Dispose(disposing);
326 private CultureInfo ConvertCultureInfo(string locale)
328 ULocale pLocale = new ULocale(locale);
329 string cultureName = CultureInfoHelper.GetCultureName(pLocale.Locale.Replace("_", "-"));
331 if (!string.IsNullOrEmpty(cultureName))
335 return new CultureInfo(cultureName);
337 catch (CultureNotFoundException)
339 Log.Error(LogTag, "CultureNotFoundException occurs. CultureName: " + cultureName);
345 return new CultureInfo(pLocale.LCID);
347 catch (ArgumentOutOfRangeException)
349 return GetFallbackCultureInfo(pLocale);
351 catch (CultureNotFoundException)
353 return GetFallbackCultureInfo(pLocale);
357 private void ChangeCurrentCultureInfo(string locale)
359 CultureInfo cultureInfo = ConvertCultureInfo(locale);
360 if (cultureInfo != null)
362 CultureInfo.CurrentCulture = cultureInfo;
366 Log.Error(LogTag, "CultureInfo is null. locale: " + locale);
370 private void ChangeCurrentUICultureInfo(string locale)
372 CultureInfo cultureInfo = ConvertCultureInfo(locale);
373 if (cultureInfo != null)
375 CultureInfo.CurrentUICulture = cultureInfo;
379 Log.Error(LogTag, "CultureInfo is null. locale: " + locale);
383 private bool ExistCultureInfo(string locale)
385 foreach (var cultureInfo in CultureInfo.GetCultures(CultureTypes.AllCultures))
387 if (cultureInfo.Name == locale)
396 private CultureInfo GetCultureInfo(string locale)
398 if (!ExistCultureInfo(locale))
405 return new CultureInfo(locale);
407 catch (CultureNotFoundException)
413 private CultureInfo GetFallbackCultureInfo(ULocale uLocale)
415 CultureInfo fallbackCultureInfo = null;
416 string locale = string.Empty;
418 if (uLocale.Locale != null)
420 locale = uLocale.Locale.Replace("_", "-");
421 fallbackCultureInfo = GetCultureInfo(locale);
424 if (fallbackCultureInfo == null && uLocale.Language != null && uLocale.Script != null && uLocale.Country != null)
426 locale = uLocale.Language + "-" + uLocale.Script + "-" + uLocale.Country;
427 fallbackCultureInfo = GetCultureInfo(locale);
430 if (fallbackCultureInfo == null && uLocale.Language != null && uLocale.Script != null)
432 locale = uLocale.Language + "-" + uLocale.Script;
433 fallbackCultureInfo = GetCultureInfo(locale);
436 if (fallbackCultureInfo == null && uLocale.Language != null && uLocale.Country != null)
438 locale = uLocale.Language + "-" + uLocale.Country;
439 fallbackCultureInfo = GetCultureInfo(locale);
442 if (fallbackCultureInfo == null && uLocale.Language != null)
444 locale = uLocale.Language;
445 fallbackCultureInfo = GetCultureInfo(locale);
448 if (fallbackCultureInfo == null)
452 fallbackCultureInfo = new CultureInfo("en");
454 catch (CultureNotFoundException e)
456 Log.Error(LogTag, "Failed to create CultureInfo. err = " + e.Message);
460 return fallbackCultureInfo;
464 internal static class GlobalizationMode
466 private static int _invariant = -1;
468 internal static bool Invariant
472 if (_invariant == -1)
474 string value = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT");
475 _invariant = value != null ? (value.Equals("1") ? 1 : 0) : 0;
478 return _invariant != 0;
483 internal class ULocale
485 private const int ULOC_FULLNAME_CAPACITY = 157;
486 private const int ULOC_LANG_CAPACITY = 12;
487 private const int ULOC_SCRIPT_CAPACITY = 6;
488 private const int ULOC_COUNTRY_CAPACITY = 4;
489 private const int ULOC_VARIANT_CAPACITY = ULOC_FULLNAME_CAPACITY;
491 internal ULocale(string locale)
493 Locale = Canonicalize(locale);
494 Language = GetLanguage(Locale);
495 Script = GetScript(Locale);
496 Country = GetCountry(Locale);
497 Variant = GetVariant(Locale);
498 LCID = GetLCID(Locale);
501 internal string Locale { get; private set; }
502 internal string Language { get; private set; }
503 internal string Script { get; private set; }
504 internal string Country { get; private set; }
505 internal string Variant { get; private set; }
506 internal int LCID { get; private set; }
508 private string Canonicalize(string localeName)
510 // Get the locale name from ICU
511 StringBuilder sb = new StringBuilder(ULOC_FULLNAME_CAPACITY);
512 if (Interop.BaseUtilsi18n.Canonicalize(localeName, sb, sb.Capacity) <= 0)
517 return sb.ToString();
520 private string GetLanguage(string locale)
522 // Get the language name from ICU
523 StringBuilder sb = new StringBuilder(ULOC_LANG_CAPACITY);
524 if (Interop.BaseUtilsi18n.GetLanguage(locale, sb, sb.Capacity, out int bufSizeLanguage) != 0)
529 return sb.ToString();
532 private string GetScript(string locale)
534 // Get the script name from ICU
535 StringBuilder sb = new StringBuilder(ULOC_SCRIPT_CAPACITY);
536 if (Interop.BaseUtilsi18n.GetScript(locale, sb, sb.Capacity) <= 0)
541 return sb.ToString();
544 private string GetCountry(string locale)
548 // Get the country name from ICU
549 StringBuilder sb = new StringBuilder(ULOC_COUNTRY_CAPACITY);
550 if (Interop.BaseUtilsi18n.GetCountry(locale, sb, sb.Capacity, out err) <= 0)
555 return sb.ToString();
558 private string GetVariant(string locale)
560 // Get the variant name from ICU
561 StringBuilder sb = new StringBuilder(ULOC_VARIANT_CAPACITY);
562 if (Interop.BaseUtilsi18n.GetVariant(locale, sb, sb.Capacity) <= 0)
567 return sb.ToString();
570 private int GetLCID(string locale)
572 // Get the LCID from ICU
573 uint lcid = Interop.BaseUtilsi18n.GetLCID(locale);
577 internal static string GetDefaultLocale()
579 IntPtr stringPtr = IntPtr.Zero;
580 if (Interop.BaseUtilsi18n.GetDefault(out stringPtr) != 0)
585 if (stringPtr == IntPtr.Zero)
590 return Marshal.PtrToStringAnsi(stringPtr);