[Tizen.Applications.Common] Add a timer for handling GC collection (#716)
[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 = null;
119
120             if (args == null)
121             {
122                 argsClone = new string[1];
123             }
124             else
125             {
126                 argsClone = new string[args.Length + 1];
127                 args.CopyTo(argsClone, 1);
128             }
129             argsClone[0] = string.Empty;
130             _backend.Run(argsClone);
131         }
132
133         /// <summary>
134         /// Exits the main loop of the application.
135         /// </summary>
136         /// <since_tizen> 3 </since_tizen>
137         public override void Exit()
138         {
139             _backend.Exit();
140         }
141
142         /// <summary>
143         /// Overrides this method if want to handle behavior when the application is launched.
144         /// If base.OnCreated() is not called, the event 'Created' will not be emitted.
145         /// </summary>
146         /// <since_tizen> 3 </since_tizen>
147         protected virtual void OnCreate()
148         {
149             Created?.Invoke(this, EventArgs.Empty);
150         }
151
152         /// <summary>
153         /// Overrides this method if want to handle behavior when the application is terminated.
154         /// If base.OnTerminate() is not called, the event 'Terminated' will not be emitted.
155         /// </summary>
156         /// <since_tizen> 3 </since_tizen>
157         protected virtual void OnTerminate()
158         {
159             Terminated?.Invoke(this, EventArgs.Empty);
160         }
161
162         /// <summary>
163         /// Overrides this method if want to handle behavior when the application receives the appcontrol message.
164         /// If base.OnAppControlReceived() is not called, the event 'AppControlReceived' will not be emitted.
165         /// </summary>
166         /// <param name="e"></param>
167         /// <since_tizen> 3 </since_tizen>
168         protected virtual void OnAppControlReceived(AppControlReceivedEventArgs e)
169         {
170             AppControlReceived?.Invoke(this, e);
171         }
172
173         /// <summary>
174         /// Overrides this method if want to handle behavior when the system memory is low.
175         /// If base.OnLowMemory() is not called, the event 'LowMemory' will not be emitted.
176         /// </summary>
177         /// <since_tizen> 3 </since_tizen>
178         protected virtual void OnLowMemory(LowMemoryEventArgs e)
179         {
180             LowMemory?.Invoke(this, e);
181             sTimer = new Timer(new Random().Next(10 * 1000));
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         /// <since_tizen> 3 </since_tizen>
197         protected virtual void OnLowBattery(LowBatteryEventArgs e)
198         {
199             LowBattery?.Invoke(this, e);
200         }
201
202         /// <summary>
203         /// Overrides this method if want to handle behavior when the system language is changed.
204         /// If base.OnLocaleChanged() is not called, the event 'LocaleChanged' will not be emitted.
205         /// </summary>
206         /// <since_tizen> 3 </since_tizen>
207         protected virtual void OnLocaleChanged(LocaleChangedEventArgs e)
208         {
209             ChangeCurrentCultureInfo(e.Locale);
210             LocaleChanged?.Invoke(this, e);
211         }
212
213         /// <summary>
214         /// Overrides this method if want to handle behavior when the region format is changed.
215         /// If base.OnRegionFormatChanged() is not called, the event 'RegionFormatChanged' will not be emitted.
216         /// </summary>
217         /// <since_tizen> 3 </since_tizen>
218         protected virtual void OnRegionFormatChanged(RegionFormatChangedEventArgs e)
219         {
220             RegionFormatChanged?.Invoke(this, e);
221         }
222
223         /// <summary>
224         /// Overrides this method if want to handle behavior when the device orientation is changed.
225         /// If base.OnRegionFormatChanged() is not called, the event 'RegionFormatChanged' will not be emitted.
226         /// </summary>
227         /// <since_tizen> 3 </since_tizen>
228         protected virtual void OnDeviceOrientationChanged(DeviceOrientationEventArgs e)
229         {
230             DeviceOrientationChanged?.Invoke(this, e);
231         }
232
233         /// <summary>
234         /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
235         /// </summary>
236         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
237         /// <since_tizen> 3 </since_tizen>
238         protected override void Dispose(bool disposing)
239         {
240             if (!_disposedValue)
241             {
242                 if (disposing)
243                 {
244                     _backend.Dispose();
245                 }
246
247                 _disposedValue = true;
248             }
249             base.Dispose(disposing);
250         }
251
252         private void ChangeCurrentCultureInfo(string locale)
253         {
254             ULocale pLocale = new ULocale(locale);
255             CultureInfo currentCultureInfo = null;
256
257             try
258             {
259                 currentCultureInfo = new CultureInfo(pLocale.Locale.Replace("_", "-"));
260             }
261             catch (CultureNotFoundException)
262             {
263                 currentCultureInfo = GetFallbackCultureInfo(pLocale);
264             }
265
266             CultureInfo.CurrentCulture = currentCultureInfo;
267         }
268
269         private CultureInfo GetCultureInfo(string locale)
270         {
271             CultureInfo cultureInfo = null;
272
273             try
274             {
275                 cultureInfo = new CultureInfo(locale);
276             }
277             catch (CultureNotFoundException)
278             {
279                 return null;
280             }
281
282             return cultureInfo;
283         }
284
285         private CultureInfo GetFallbackCultureInfo(ULocale uLocale)
286         {
287             string locale = string.Empty;
288             CultureInfo fallbackCultureInfo = null;
289
290             if (uLocale.Script != null && uLocale.Country != null)
291             {
292                 locale = uLocale.Language + "-" + uLocale.Script + "-" + uLocale.Country;
293                 fallbackCultureInfo = GetCultureInfo(locale);
294             }
295
296             if (fallbackCultureInfo == null && uLocale.Script != null)
297             {
298                 locale = uLocale.Language + "-" + uLocale.Script;
299                 fallbackCultureInfo = GetCultureInfo(locale);
300             }
301
302             if (fallbackCultureInfo == null && uLocale.Country != null)
303             {
304                 locale = uLocale.Language + "-" + uLocale.Country;
305                 fallbackCultureInfo = GetCultureInfo(locale);
306             }
307
308             if (fallbackCultureInfo == null)
309             {
310                 try
311                 {
312                     fallbackCultureInfo = new CultureInfo(uLocale.Language);
313                 }
314                 catch (CultureNotFoundException)
315                 {
316                     fallbackCultureInfo = new CultureInfo("en");
317                 }
318             }
319
320             return fallbackCultureInfo;
321         }
322     }
323
324     internal class ULocale
325     {
326         private const int ICU_ULOC_FULLNAME_CAPACITY = 157;
327         private const int ICU_ULOC_LANG_CAPACITY = 12;
328         private const int ICU_ULOC_SCRIPT_CAPACITY = 6;
329         private const int ICU_ULOC_COUNTRY_CAPACITY = 4;
330         private const int ICU_ULOC_VARIANT_CAPACITY = ICU_ULOC_FULLNAME_CAPACITY;
331         private const int ICU_U_ZERO_ERROR = 0;
332
333         internal ULocale(string locale)
334         {
335             Locale = Canonicalize(locale);
336             Language = GetLanguage(Locale);
337             Script = GetScript(Locale);
338             Country = GetCountry(Locale);
339             Variant = GetVariant(Locale);
340         }
341
342         internal string Locale { get; private set; }
343         internal string Language { get; private set; }
344         internal string Script { get; private set; }
345         internal string Country { get; private set; }
346         internal string Variant { get; private set; }
347
348         private string Canonicalize(string localeName)
349         {
350             int err = ICU_U_ZERO_ERROR;
351
352             // Get the locale name from ICU
353             StringBuilder sb = new StringBuilder(ICU_ULOC_FULLNAME_CAPACITY);
354             if (Interop.Icu.Canonicalize(localeName, sb, sb.Capacity, out err) <= 0)
355             {
356                 return null;
357             }
358
359             return sb.ToString();
360         }
361
362         private string GetLanguage(string locale)
363         {
364             int err = ICU_U_ZERO_ERROR;
365
366             // Get the language name from ICU
367             StringBuilder sb = new StringBuilder(ICU_ULOC_LANG_CAPACITY);
368             if (Interop.Icu.GetLanguage(locale, sb, sb.Capacity, out err) <= 0)
369             {
370                 return null;
371             }
372
373             return sb.ToString();
374         }
375
376         private string GetScript(string locale)
377         {
378             int err = ICU_U_ZERO_ERROR;
379
380             // Get the script name from ICU
381             StringBuilder sb = new StringBuilder(ICU_ULOC_SCRIPT_CAPACITY);
382             if (Interop.Icu.GetScript(locale, sb, sb.Capacity, out err) <= 0)
383             {
384                 return null;
385             }
386
387             return sb.ToString();
388         }
389
390         private string GetCountry(string locale)
391         {
392             int err = ICU_U_ZERO_ERROR;
393
394             // Get the country name from ICU
395             StringBuilder sb = new StringBuilder(ICU_ULOC_SCRIPT_CAPACITY);
396             if (Interop.Icu.GetCountry(locale, sb, sb.Capacity, out err) <= 0)
397             {
398                 return null;
399             }
400
401             return sb.ToString();
402         }
403
404         private string GetVariant(string locale)
405         {
406             int err = ICU_U_ZERO_ERROR;
407
408             // Get the variant name from ICU
409             StringBuilder sb = new StringBuilder(ICU_ULOC_VARIANT_CAPACITY);
410             if (Interop.Icu.GetVariant(locale, sb, sb.Capacity, out err) <= 0)
411             {
412                 return null;
413             }
414
415             return sb.ToString();
416         }
417     }
418 }