Refactor Lifecycles
[platform/core/csapi/tizenfx.git] / Tizen.Applications / Tizen.Applications / Application.cs
1 /// Copyright 2016 by Samsung Electronics, Inc.,
2 ///
3 /// This software is the confidential and proprietary information
4 /// of Samsung Electronics, Inc. ("Confidential Information"). You
5 /// shall not disclose such Confidential Information and shall use
6 /// it only in accordance with the terms of the license agreement
7 /// you entered into with Samsung.
8
9
10 using System;
11 using System.Collections.Generic;
12 using System.Linq;
13
14 using Tizen.UI;
15
16 namespace Tizen.Applications
17 {
18     /// <summary>
19     /// Provides static methods and properties to manage an application, such as methods to register Actors and Services, 
20     /// to start an application.
21     /// </summary>
22     public static class Application
23     {
24         private static readonly Dictionary<AppControlFilter, Type> s_filterMap = new Dictionary<AppControlFilter, Type>();
25         private static readonly List<ServiceController> s_serviceControllerList = new List<ServiceController>();
26         private static readonly UIControllerStack s_uiControllerStack = new UIControllerStack();
27         private static Window s_defaultWindow = null;
28
29         /// <summary>
30         /// Occurs when the application starts.
31         /// </summary>
32         public static event EventHandler Created = delegate { };
33
34         /// <summary>
35         /// Occurs when the application's main loop exits.
36         /// </summary>
37         public static event EventHandler Exited = delegate { };
38
39         private static UIController Foreground
40         {
41             get
42             {
43                 return s_uiControllerStack.Peek();
44             }
45         }
46
47         /// <summary>
48         /// Runs the application's main loop.
49         /// </summary>
50         /// <param name="args">The command-line arguments</param>
51         public static void Run(string[] args)
52         {
53             Interop.Application.UIAppLifecycleCallbacks ops;
54             ops.OnCreate = (userData) =>
55             {
56                 Created(null, EventArgs.Empty);
57                 return true;
58             };
59             ops.OnPause = (userData) =>
60             {
61                 if (Foreground != null)
62                 {
63                     Foreground.SendPause();
64                 }
65             };
66             ops.OnResume = (userData) =>
67             {
68                 if (Foreground != null)
69                 {
70                     Foreground.SendResume();
71                 }
72             };
73             ops.OnAppControl = (appControlHandle, userData) =>
74             {
75                 AppControl control = new AppControl(appControlHandle);
76                 StartController(null, null, control, Controller.ControlFlags.NewInstance);
77             };
78             ops.OnTerminate = (userData) =>
79             {
80                 Exit();
81             };
82
83             TizenSynchronizationContext.Initialize();
84
85             // TODO: check ret of UIAppMain and throw exceptions when errors are returned.
86             Interop.Application.UIAppMain(args.Length, args, ref ops, IntPtr.Zero);
87         }
88
89         /// <summary>
90         /// Exits the main loop of application.
91         /// </summary>
92         public static void Exit()
93         {
94             Exited(null, null);
95             // TODO: clear context and group
96             Interop.Application.UIAppExit();
97         }
98
99         /// <summary>
100         /// 
101         /// </summary>
102         /// <param name="controllerType"></param>
103         public static void RegisterController(Type controllerType)
104         {
105             RegisterController(controllerType, new AppControlFilter[0] { });
106         }
107
108         /// <summary>
109         /// 
110         /// </summary>
111         /// <param name="controllerType"></param>
112         /// <param name="filter"></param>
113         public static void RegisterController(Type controllerType, AppControlFilter filter)
114         {
115             RegisterController(controllerType, new AppControlFilter[] { filter });
116         }
117
118         /// <summary>
119         /// 
120         /// </summary>
121         /// <param name="controllerType"></param>
122         /// <param name="filters"></param>
123         public static void RegisterController(Type controllerType, AppControlFilter[] filters)
124         {
125             if (controllerType == null)
126             {
127                 throw new ArgumentNullException("controllerType");
128             }
129
130             if (!controllerType.IsSubclassOf(typeof(UIController)) || !controllerType.IsSubclassOf(typeof(ServiceController)))
131             {                
132                 throw new ArgumentException(controllerType.FullName + " is not a sub class of UIController or ServiceController.", "controllerType");
133             }
134
135             foreach (var prop in controllerType.GetProperties())
136             {
137                 foreach (var attr in prop.GetCustomAttributes(false))
138                 {
139                     var filter = attr as AppControlFilter;
140                     if (filter != null)
141                     {
142                         s_filterMap.Add(filter, controllerType);
143                     }
144                 }
145             }
146             if (filters != null)
147             {
148                 foreach (var filter in filters)
149                 {
150                     s_filterMap.Add(filter, controllerType);
151                 }
152             }
153         }
154         
155         internal static void StartController(Controller caller, Type controllerType, AppControl control, Controller.ControlFlags flags)
156         {
157             if (control == null)
158             {
159                 throw new ArgumentNullException("control");
160             }
161
162             if (controllerType == null)
163             {
164                 controllerType = FindControllerInFilterMap(control);
165                 if (controllerType == null)
166                 {
167                     throw new ArgumentException("Could not find any matched controller.", "controllerType");
168                 }
169             }
170
171             if (controllerType.IsSubclassOf(typeof(UIController)))
172             {
173                 UIController target = null;
174                 UIController uiCaller = caller as UIController;
175                 if (uiCaller != null && uiCaller != Foreground)
176                 {
177                     throw new InvalidOperationException("Starting UIController should be called from the foreground.");
178                 }
179                 if (uiCaller != null && !IsFlagSet(flags, Controller.ControlFlags.NewInstance))
180                 {
181                     target = s_uiControllerStack.FindInForegroundTask(controllerType);
182                 }
183
184
185                 if (s_defaultWindow == null)
186                 {
187                     s_defaultWindow = new Window();
188                 }
189
190                 if (!s_defaultWindow.Visible)
191                 {
192                     s_defaultWindow.Active();
193                     s_defaultWindow.Show();
194                 }
195
196                 if (target == null)
197                 {
198                     target = (UIController)Activator.CreateInstance(controllerType);
199                     target.TaskId = uiCaller == null ? Guid.NewGuid() : uiCaller.TaskId;
200                     target.Window = s_defaultWindow;
201                     target.SendCreate();
202                     s_uiControllerStack.Push(target);
203                 }
204                 else
205                 {
206                     if (IsFlagSet(flags, Controller.ControlFlags.ClearTop))
207                     {
208                         while (target != Foreground)
209                         {
210                             UIController popped = s_uiControllerStack.Pop();
211                             popped.SendPause();
212                             popped.SendDestroy();
213                         }
214                     }
215                     else if (IsFlagSet(flags, Controller.ControlFlags.MoveToTop))
216                     {
217                         if (Foreground != target)
218                         {
219                             Foreground.SendPause();
220                             s_uiControllerStack.MoveToTop(target);
221                         }
222                     }
223                 }
224                 Foreground.SendStart(control);
225                 Foreground.SendResume();
226             }
227             else if (controllerType.IsSubclassOf(typeof(ServiceController)))
228             {
229                 ServiceController svc = s_serviceControllerList.Find(s => s.GetType() == controllerType);
230                 if (svc == null)
231                 {
232                     svc = (ServiceController)Activator.CreateInstance(controllerType);
233                     s_serviceControllerList.Add(svc);
234                     svc.SendCreate();
235                 }
236                 svc.SendStart(control);
237             }
238             else
239             {
240                 throw new ArgumentException("Invalid controller type.", "controllerType");
241             }
242         }
243
244         internal static void StopController(UIController target)
245         {
246             if (Foreground == null)
247             {
248                 throw new InvalidOperationException("The UIController stack is empty.");
249             }
250
251             Guid prevForegroundTaskId = Foreground.TaskId;
252
253             s_uiControllerStack.Remove(target);
254             target.SendPause();
255             target.SendDestroy();
256             if (target.TaskId == prevForegroundTaskId)
257             {
258                 if (Foreground.TaskId == target.TaskId)
259                 {
260                     Foreground.SendResume();
261                 }
262                 else
263                 {
264                     if (s_uiControllerStack.Count == 0 && s_serviceControllerList.Count == 0)
265                     {
266                         Exit();
267                     }
268                     else
269                     {
270                         s_defaultWindow.Hide();
271                     }
272                 }
273             }
274         }
275
276         internal static void StopController(Type controllerType)
277         {
278             if (controllerType.IsSubclassOf(typeof(UIController)))
279             {                
280                 UIController target = s_uiControllerStack.Find(controllerType);
281                 if (target == null)
282                 {
283                     throw new InvalidOperationException("Could not find the UIController to stop.");
284                 }
285                 StopController(target);
286             }
287             else if (controllerType.IsSubclassOf(typeof(ServiceController)))
288             {
289                 ServiceController svc = s_serviceControllerList.Find(s => s.GetType() == controllerType);
290                 if (svc != null)
291                 {
292                     svc.SendDestroy();
293                     s_serviceControllerList.Remove(svc);
294                     if (s_uiControllerStack.Count == 0 && s_serviceControllerList.Count == 0)
295                     {
296                         Exit();
297                     }
298                 }
299             }
300         }
301         
302         private static Type FindControllerInFilterMap(AppControl control)
303         {            
304             foreach (var item in s_filterMap)
305             {
306                 if (item.Key.IsMatch(control))
307                 {
308                     return item.Value;
309                 }
310             }
311             return null;
312         }
313         
314         private static bool IsFlagSet(Controller.ControlFlags flags, Controller.ControlFlags values)
315         {
316             return (values & flags) == values;
317         }
318
319
320         private class UIControllerStack
321         {
322             private readonly List<UIController> _uiControllerList;
323
324             public int Count
325             {
326                 get
327                 {
328                     return _uiControllerList.Count;
329                 }
330             }
331
332             public UIControllerStack()
333             {
334                 _uiControllerList = new List<UIController>();
335             }
336
337             public UIController Peek()
338             {
339                 return _uiControllerList.LastOrDefault(null);
340             }
341
342             public void Push(UIController item)
343             {
344                 _uiControllerList.Add(item);
345             }
346
347             public UIController Pop()
348             {
349                 UIController last = Peek();
350                 _uiControllerList.Remove(last);
351                 return last;
352             }
353
354             public void Remove(UIController actor)
355             {
356                 _uiControllerList.Remove(actor);
357             }
358
359             public UIController Find(Type controllerType)
360             {
361                 return _uiControllerList.Find(s => s.GetType() == controllerType);
362             }
363
364             public UIController FindInForegroundTask(Type controllerType)
365             {
366                 return _uiControllerList.Find(s => s.GetType() == controllerType && s.TaskId == Peek().TaskId);
367             }
368
369             public void MoveToTop(UIController actor)
370             {
371                 _uiControllerList.Remove(actor);
372                 _uiControllerList.Add(actor);
373             }
374         }
375     }
376 }