Separating Language changing logic and Region changing logic (#1556)
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.Common / Tizen.Applications / CoreApplication.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 using System;
18 using System.Globalization;
19 using System.Text;
20 using System.Timers;
21 using Tizen.Applications.CoreBackend;
22
23 namespace Tizen.Applications
24 {
25     /// <summary>
26     /// This class represents an application controlled lifecycles by the backend system.
27     /// </summary>
28     /// <since_tizen> 3 </since_tizen>
29     public class CoreApplication : Application
30     {
31         private readonly ICoreBackend _backend;
32         private bool _disposedValue = false;
33
34         private static Timer sTimer;
35
36         /// <summary>
37         /// Initializes the CoreApplication class.
38         /// </summary>
39         /// <param name="backend">The backend instance implementing ICoreBacked interface.</param>
40         /// <since_tizen> 3 </since_tizen>
41         public CoreApplication(ICoreBackend backend)
42         {
43             _backend = backend;
44         }
45
46         /// <summary>
47         /// Occurs when the application is launched.
48         /// </summary>
49         /// <since_tizen> 3 </since_tizen>
50         public event EventHandler Created;
51
52         /// <summary>
53         /// Occurs when the application is about to shutdown.
54         /// </summary>
55         /// <since_tizen> 3 </since_tizen>
56         public event EventHandler Terminated;
57
58         /// <summary>
59         /// Occurs whenever the application receives the appcontrol message.
60         /// </summary>
61         /// <since_tizen> 3 </since_tizen>
62         public event EventHandler<AppControlReceivedEventArgs> AppControlReceived;
63
64         /// <summary>
65         /// Occurs when the system memory is low.
66         /// </summary>
67         /// <since_tizen> 3 </since_tizen>
68         public event EventHandler<LowMemoryEventArgs> LowMemory;
69
70         /// <summary>
71         /// Occurs when the system battery is low.
72         /// </summary>
73         /// <since_tizen> 3 </since_tizen>
74         public event EventHandler<LowBatteryEventArgs> LowBattery;
75
76         /// <summary>
77         /// Occurs when the system language is chagned.
78         /// </summary>
79         /// <since_tizen> 3 </since_tizen>
80         public event EventHandler<LocaleChangedEventArgs> LocaleChanged;
81
82         /// <summary>
83         /// Occurs when the region format is changed.
84         /// </summary>
85         /// <since_tizen> 3 </since_tizen>
86         public event EventHandler<RegionFormatChangedEventArgs> RegionFormatChanged;
87
88         /// <summary>
89         /// Occurs when the device orientation is changed.
90         /// </summary>
91         /// <since_tizen> 3 </since_tizen>
92         public event EventHandler<DeviceOrientationEventArgs> DeviceOrientationChanged;
93
94         /// <summary>
95         /// The backend instance.
96         /// </summary>
97         /// <since_tizen> 3 </since_tizen>
98         protected ICoreBackend Backend { get { return _backend; } }
99
100         /// <summary>
101         /// Runs the application's main loop.
102         /// </summary>
103         /// <param name="args">Arguments from commandline.</param>
104         /// <since_tizen> 3 </since_tizen>
105         public override void Run(string[] args)
106         {
107             base.Run(args);
108
109             _backend.AddEventHandler(EventType.Created, OnCreate);
110             _backend.AddEventHandler(EventType.Terminated, OnTerminate);
111             _backend.AddEventHandler<AppControlReceivedEventArgs>(EventType.AppControlReceived, OnAppControlReceived);
112             _backend.AddEventHandler<LowMemoryEventArgs>(EventType.LowMemory, OnLowMemory);
113             _backend.AddEventHandler<LowBatteryEventArgs>(EventType.LowBattery, OnLowBattery);
114             _backend.AddEventHandler<LocaleChangedEventArgs>(EventType.LocaleChanged, OnLocaleChanged);
115             _backend.AddEventHandler<RegionFormatChangedEventArgs>(EventType.RegionFormatChanged, OnRegionFormatChanged);
116             _backend.AddEventHandler<DeviceOrientationEventArgs>(EventType.DeviceOrientationChanged, OnDeviceOrientationChanged);
117
118             string[] argsClone = new string[args.Length + 1];
119             if (args.Length > 1)
120             {
121                 args.CopyTo(argsClone, 1);
122             }
123             argsClone[0] = string.Empty;
124
125             _backend.Run(argsClone);
126         }
127
128         /// <summary>
129         /// Exits the main loop of the application.
130         /// </summary>
131         /// <since_tizen> 3 </since_tizen>
132         public override void Exit()
133         {
134             _backend.Exit();
135         }
136
137         /// <summary>
138         /// Overrides this method if want to handle behavior when the application is launched.
139         /// If base.OnCreated() is not called, the event 'Created' will not be emitted.
140         /// </summary>
141         /// <since_tizen> 3 </since_tizen>
142         protected virtual void OnCreate()
143         {
144             Created?.Invoke(this, EventArgs.Empty);
145         }
146
147         /// <summary>
148         /// Overrides this method if want to handle behavior when the application is terminated.
149         /// If base.OnTerminate() is not called, the event 'Terminated' will not be emitted.
150         /// </summary>
151         /// <since_tizen> 3 </since_tizen>
152         protected virtual void OnTerminate()
153         {
154             Terminated?.Invoke(this, EventArgs.Empty);
155         }
156
157         /// <summary>
158         /// Overrides this method if want to handle behavior when the application receives the appcontrol message.
159         /// If base.OnAppControlReceived() is not called, the event 'AppControlReceived' will not be emitted.
160         /// </summary>
161         /// <param name="e"></param>
162         /// <since_tizen> 3 </since_tizen>
163         protected virtual void OnAppControlReceived(AppControlReceivedEventArgs e)
164         {
165             AppControlReceived?.Invoke(this, e);
166         }
167
168         /// <summary>
169         /// Overrides this method if want to handle behavior when the system memory is low.
170         /// If base.OnLowMemory() is not called, the event 'LowMemory' will not be emitted.
171         /// </summary>
172         /// <param name="e">The low memory event argument</param>
173         /// <since_tizen> 3 </since_tizen>
174         protected virtual void OnLowMemory(LowMemoryEventArgs e)
175         {
176             LowMemory?.Invoke(this, e);
177             double interval = new Random().Next(10 * 1000);
178             if (interval <= 0)
179                 interval = 10 * 1000;
180
181             sTimer = new Timer(interval);
182             sTimer.Elapsed += OnTimedEvent;
183             sTimer.AutoReset = false;
184             sTimer.Enabled = true;
185         }
186
187         private static void OnTimedEvent(Object source, ElapsedEventArgs e)
188         {
189             System.GC.Collect();
190         }
191
192         /// <summary>
193         /// Overrides this method if want to handle behavior when the system battery is low.
194         /// If base.OnLowBattery() is not called, the event 'LowBattery' will not be emitted.
195         /// </summary>
196         /// <param name="e">The low battery event argument</param>
197         /// <since_tizen> 3 </since_tizen>
198         protected virtual void OnLowBattery(LowBatteryEventArgs e)
199         {
200             LowBattery?.Invoke(this, e);
201         }
202
203         /// <summary>
204         /// Overrides this method if want to handle behavior when the system language is changed.
205         /// If base.OnLocaleChanged() is not called, the event 'LocaleChanged' will not be emitted.
206         /// </summary>
207         /// <param name="e">The locale changed event argument</param>
208         /// <since_tizen> 3 </since_tizen>
209         protected virtual void OnLocaleChanged(LocaleChangedEventArgs e)
210         {
211             ChangeCurrentUICultureInfo(e.Locale);
212             LocaleChanged?.Invoke(this, e);
213         }
214
215         /// <summary>
216         /// Overrides this method if want to handle behavior when the region format is changed.
217         /// If base.OnRegionFormatChanged() is not called, the event 'RegionFormatChanged' will not be emitted.
218         /// </summary>
219         /// <param name="e">The region format changed event argument</param>
220         /// <since_tizen> 3 </since_tizen>
221         protected virtual void OnRegionFormatChanged(RegionFormatChangedEventArgs e)
222         {
223             ChangeCurrentCultureInfo(e.Region);
224             RegionFormatChanged?.Invoke(this, e);
225         }
226
227         /// <summary>
228         /// Overrides this method if want to handle behavior when the device orientation is changed.
229         /// If base.OnRegionFormatChanged() is not called, the event 'RegionFormatChanged' will not be emitted.
230         /// </summary>
231         /// <param name="e">The device orientation changed event argument</param>
232         /// <since_tizen> 3 </since_tizen>
233         protected virtual void OnDeviceOrientationChanged(DeviceOrientationEventArgs e)
234         {
235             DeviceOrientationChanged?.Invoke(this, e);
236         }
237
238         /// <summary>
239         /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
240         /// </summary>
241         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
242         /// <since_tizen> 3 </since_tizen>
243         protected override void Dispose(bool disposing)
244         {
245             if (!_disposedValue)
246             {
247                 if (disposing)
248                 {
249                     _backend.Dispose();
250                 }
251
252                 _disposedValue = true;
253             }
254             base.Dispose(disposing);
255         }
256
257         private CultureInfo ConvertCultureInfo(string locale)
258         {
259             ULocale pLocale = new ULocale(locale);
260             try
261             {
262                 return new CultureInfo(pLocale.Locale.Replace("_", "-"));
263             }
264             catch (CultureNotFoundException)
265             {
266                 return GetFallbackCultureInfo(pLocale);
267             }
268         }
269
270         private void ChangeCurrentCultureInfo(string locale)
271         {
272             CultureInfo.CurrentCulture = ConvertCultureInfo(locale);
273         }
274
275         private void ChangeCurrentUICultureInfo(string locale)
276         {
277             CultureInfo.CurrentUICulture = ConvertCultureInfo(locale);
278         }
279
280         private CultureInfo GetCultureInfo(string locale)
281         {
282             CultureInfo cultureInfo = null;
283
284             try
285             {
286                 cultureInfo = new CultureInfo(locale);
287             }
288             catch (CultureNotFoundException)
289             {
290                 return null;
291             }
292
293             return cultureInfo;
294         }
295
296         private CultureInfo GetFallbackCultureInfo(ULocale uLocale)
297         {
298             string locale = string.Empty;
299             CultureInfo fallbackCultureInfo = null;
300
301             if (uLocale.Script != null && uLocale.Country != null)
302             {
303                 locale = uLocale.Language + "-" + uLocale.Script + "-" + uLocale.Country;
304                 fallbackCultureInfo = GetCultureInfo(locale);
305             }
306
307             if (fallbackCultureInfo == null && uLocale.Script != null)
308             {
309                 locale = uLocale.Language + "-" + uLocale.Script;
310                 fallbackCultureInfo = GetCultureInfo(locale);
311             }
312
313             if (fallbackCultureInfo == null && uLocale.Country != null)
314             {
315                 locale = uLocale.Language + "-" + uLocale.Country;
316                 fallbackCultureInfo = GetCultureInfo(locale);
317             }
318
319             if (fallbackCultureInfo == null)
320             {
321                 try
322                 {
323                     fallbackCultureInfo = new CultureInfo(uLocale.Language);
324                 }
325                 catch (CultureNotFoundException)
326                 {
327                     fallbackCultureInfo = new CultureInfo("en");
328                 }
329             }
330
331             return fallbackCultureInfo;
332         }
333     }
334
335     internal class ULocale
336     {
337         private const int ULOC_FULLNAME_CAPACITY = 157;
338         private const int ULOC_LANG_CAPACITY = 12;
339         private const int ULOC_SCRIPT_CAPACITY = 6;
340         private const int ULOC_COUNTRY_CAPACITY = 4;
341         private const int ULOC_VARIANT_CAPACITY = ULOC_FULLNAME_CAPACITY;
342
343         internal ULocale(string locale)
344         {
345             Locale = Canonicalize(locale);
346             Language = GetLanguage(Locale);
347             Script = GetScript(Locale);
348             Country = GetCountry(Locale);
349             Variant = GetVariant(Locale);
350         }
351
352         internal string Locale { get; private set; }
353         internal string Language { get; private set; }
354         internal string Script { get; private set; }
355         internal string Country { get; private set; }
356         internal string Variant { get; private set; }
357
358         private string Canonicalize(string localeName)
359         {
360             // Get the locale name from ICU
361             StringBuilder sb = new StringBuilder(ULOC_FULLNAME_CAPACITY);
362             if (Interop.BaseUtilsi18n.Canonicalize(localeName, sb, sb.Capacity) <= 0)
363             {
364                 return null;
365             }
366
367             return sb.ToString();
368         }
369
370         private string GetLanguage(string locale)
371         {
372             // Get the language name from ICU
373             StringBuilder sb = new StringBuilder(ULOC_LANG_CAPACITY);
374             if (Interop.BaseUtilsi18n.GetLanguage(locale, sb, sb.Capacity, out int bufSizeLanguage) != 0)
375             {
376                 return null;
377             }
378
379             return sb.ToString();
380         }
381
382         private string GetScript(string locale)
383         {
384             // Get the script name from ICU
385             StringBuilder sb = new StringBuilder(ULOC_SCRIPT_CAPACITY);
386             if (Interop.BaseUtilsi18n.GetScript(locale, sb, sb.Capacity) <= 0)
387             {
388                 return null;
389             }
390
391             return sb.ToString();
392         }
393
394         private string GetCountry(string locale)
395         {
396             int err = 0;
397
398             // Get the country name from ICU
399             StringBuilder sb = new StringBuilder(ULOC_SCRIPT_CAPACITY);
400             if (Interop.BaseUtilsi18n.GetCountry(locale, sb, sb.Capacity, out err) <= 0)
401             {
402                 return null;
403             }
404
405             return sb.ToString();
406         }
407
408         private string GetVariant(string locale)
409         {
410             // Get the variant name from ICU
411             StringBuilder sb = new StringBuilder(ULOC_VARIANT_CAPACITY);
412             if (Interop.BaseUtilsi18n.GetVariant(locale, sb, sb.Capacity) <= 0)
413             {
414                 return null;
415             }
416
417             return sb.ToString();
418         }
419     }
420 }