Revert "Add Test cases for app shortcut, managedapps"
[profile/tv/apps/dotnet/home.git] / TVApps / TVApps / ViewModels / AppsHolder.cs
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 LibTVRefCommonPortable.DataModels;
18 using LibTVRefCommonPortable.Utils;
19 using System.Collections.Generic;
20 using System.Linq;
21 using System.Threading;
22 using System.Threading.Tasks;
23 using Xamarin.Forms;
24
25 namespace TVApps.ViewModels
26 {
27     /// <summary>
28     /// A class contains installed, pinned application list.
29     /// The MainPageViewModel changes state of application item by AppsHolder's API
30     /// </summary>
31     internal class AppsHolder
32     {
33         /// <summary>
34         /// The interface for interaction with view model
35         /// </summary>
36         IAppsViewModel ViewModel;
37
38         /// <summary>
39         /// A flag indicates how to sort InstalledApps
40         /// </summary>
41         /// <see cref="SortingOptions"/>
42         public SortingOptions SortingOption;
43
44         /// <summary>
45         /// A list contains AppShortcutInfo about installed applications
46         /// </summary>
47         /// <see cref="AppShortcutInfo"/>
48         public List<AppShortcutInfo> InstalledApps;
49
50         /// <summary>
51         /// A dictionary contains ID of pinned applications
52         /// </summary>
53         public Dictionary<string, string> PinnedApps;
54
55         /// <summary>
56         /// A name of pinned application
57         /// </summary>
58         public string PinnedAppName;
59
60         /// <summary>
61         /// A name of unpinned application
62         /// </summary>
63         public string UnpinnedAppName;
64
65         public bool IsSelectedExceeds;
66
67         /// <summary>
68         /// A constructor
69         /// Initializes installed and pinned app list
70         /// </summary>
71         /// <param name="ViewModel">The instance of MainPageViewModel</param>
72         public AppsHolder(IAppsViewModel ViewModel)
73         {
74             this.ViewModel = ViewModel;
75
76             InstalledApps = new List<AppShortcutInfo>();
77             PinnedApps = new Dictionary<string, string>();
78
79             App.SetAppInstalledListener((s, e) =>
80             {
81                 SetApps();
82             });
83
84             App.SetAppUninstalledListener((s, e) =>
85             {
86                 SetApps();
87             });
88             SynchronizationContext.Current.Post((o) =>
89             {
90                 SetApps();
91             }, "");
92
93         }
94
95         /// <summary>
96         /// A method gets installed, pinned application information from AppShortcutController.
97         /// And adds state descriptions about pin, delete, long press state
98         /// </summary>
99         private async void SetApps()
100         {
101             var pinnedAppsGettingTask = TVHomeImpl.GetInstance.AppShortcutControllerInstance.GetPinnedAppsAppIDs();
102             var installedAppsGettingTask = TVHomeImpl.GetInstance.AppShortcutControllerInstance.GetInstalledApps();
103
104             await Task.WhenAll(pinnedAppsGettingTask, installedAppsGettingTask);
105
106             PinnedApps = pinnedAppsGettingTask.Result;
107             ViewModel.OnPropertyChanged("SumOfCheckedApp");
108
109             var installedApps = installedAppsGettingTask.Result;
110
111             foreach (AppShortcutInfo item in installedApps)
112             {
113                 if (item.CurrentStateDescription == null)
114                 {
115                     DebuggingUtils.Err("Invalid AppshortcutInfo, " + item.AppID);
116                     continue;
117                 }
118
119                 item.IsPinned = PinnedApps.ContainsKey(item.AppID);
120
121                 CommandAction pinAction = new CommandAction()
122                 {
123                     NextStateDescription = AppsStatus.Pin.ToString().ToLower(),
124                     CommandParameter = item.AppID
125                 };
126                 pinAction.Command += new System.EventHandler<string>((s, arg) =>
127                 {
128                     PinToggle(arg);
129                 });
130
131                 var pinStateDescription = new StateDescription()
132                 {
133                     Label = item.CurrentStateDescription.Label,
134                     IconPath = item.CurrentStateDescription.IconPath,
135                     Action = pinAction,
136                 };
137
138                 item.StateDescriptions.Add(AppsStatus.Pin.ToString().ToLower(), pinStateDescription);
139
140                 CommandAction checkDeleteAction = new CommandAction()
141                 {
142                     NextStateDescription = AppsStatus.Delete.ToString().ToLower(),
143                     CommandParameter = item.AppID
144                 };
145                 checkDeleteAction.Command += new System.EventHandler<string>((s, arg) =>
146                 {
147                     CheckDeleteApp(arg);
148                 });
149
150                 var deleteStateDescription = new StateDescription()
151                 {
152                     Label = item.CurrentStateDescription.Label,
153                     IconPath = item.CurrentStateDescription.IconPath,
154                     Action = checkDeleteAction,
155                 };
156
157                 item.StateDescriptions.Add(AppsStatus.Delete.ToString().ToLower(), deleteStateDescription);
158
159                 CommandAction longPressAction = new CommandAction()
160                 {
161                     NextStateDescription = AppsStatus.LongPress.ToString().ToLower(),
162                     CommandParameter = item.AppID
163                 };
164                 pinAction.Command += new System.EventHandler<string>((s, arg) =>
165                 {
166                     LongPressApp(arg);
167                 });
168
169                 var longPressStateDescription = new StateDescription()
170                 {
171                     Label = item.CurrentStateDescription.Label,
172                     IconPath = item.CurrentStateDescription.IconPath,
173                     Action = longPressAction,
174                 };
175                 item.StateDescriptions.Add(AppsStatus.LongPress.ToString().ToLower(), longPressStateDescription);
176             }
177
178             InstalledApps = installedApps.ToList();
179             SortApps(SortingOption);
180             UpdateStateDescription(ViewModel.CurrentStatus);
181         }
182
183         /// <summary>
184         /// A method changes pin state of AppShortcutInfo
185         /// And adds or removes application ID in PinnedApps
186         /// </summary>
187         /// <param name="appID">The ID of application for changing pin state</param>
188         private void PinToggle(string appID)
189         {
190             AppShortcutInfo selectedApp = InstalledApps.FirstOrDefault(a => a.AppID == appID);
191             if (selectedApp == null)
192             {
193                 DebuggingUtils.Err("Failed to Pin!!!, Nothing selected, AppID = " + appID);
194                 return;
195             }
196
197             if (PinnedApps.ContainsKey(appID))
198             {
199                 DebuggingUtils.Dbg("UnPin! : " + selectedApp);
200                 selectedApp.IsChecked = false;
201                 selectedApp.IsPinned = false;
202                 PinnedApps.Remove(appID);
203                 UnpinnedAppName = selectedApp.CurrentStateDescription.Label;
204                 ViewModel.OnPropertyChanged("UnpinnedAppName");
205             }
206             else
207             {
208                 if (PinnedApps.Count >= 10)
209                 {
210                     IsSelectedExceeds = true;
211                     ViewModel.OnPropertyChanged("IsSelectedExceeds");
212                     return;
213                 }
214
215                 DebuggingUtils.Dbg("Pin! : " + selectedApp);
216                 selectedApp.IsChecked = true;
217                 selectedApp.IsPinned = true;
218                 PinnedApps.Add(appID, appID);
219                 PinnedAppName = selectedApp.CurrentStateDescription.Label;
220                 ViewModel.OnPropertyChanged("PinnedAppName");
221             }
222
223             UpdatePinnedApps();
224             ViewModel.OnPropertyChanged("SumOfCheckedApp");
225         }
226
227         /// <summary>
228         /// A method changes pin state of AppShortcutInfo by the Option Menu Pin/Unpin button
229         /// And adds or removes application ID in PinnedApps
230         /// </summary>
231         /// <param name="appID">The ID of application for changing pin state</param>
232         public void OptionMenuPinToggle(string appID)
233         {
234             AppShortcutInfo SelectedApp = InstalledApps.FirstOrDefault(a => a.AppID.Equals(appID));
235             if (SelectedApp == null)
236             {
237                 DebuggingUtils.Err("Failed to get selected app : " + appID);
238                 return;
239             }
240
241             if (PinnedApps.ContainsKey(appID))
242             {
243                 DebuggingUtils.Dbg("Unpin : " + appID);
244                 SelectedApp.IsPinned = false;
245                 PinnedApps.Remove(appID);
246             }
247             else
248             {
249                 DebuggingUtils.Dbg("Pin : " + appID);
250                 SelectedApp.IsPinned = true;
251                 PinnedApps.Add(appID, appID);
252             }
253
254             ViewModel.OnPropertyChanged("SumOfCheckedApp");
255
256             this.UpdatePinnedApps();
257             ViewModel.ChangeCurrentStatus(AppsStatus.Default);
258         }
259
260         /// <summary>
261         /// A method for changing status of applications to Default
262         /// </summary>
263         public void ChangeToDefaultStatus()
264         {
265             ViewModel.ChangeCurrentStatus(AppsStatus.Default);
266         }
267
268         /// <summary>
269         /// Removes the pinned app by app ID
270         /// </summary>
271         /// <param name="removableAppsList">The apps list to remove at the pinned app list</param>
272         public void RemovePinnedApp(List<string> removableAppsList)
273         {
274             foreach (string app in removableAppsList)
275             {
276                 if (PinnedApps.ContainsKey(app))
277                 {
278                     DebuggingUtils.Dbg("UnPin! : " + app);
279
280                     PinnedApps.Remove(app);
281                 }
282             }
283
284             UpdatePinnedApps();
285         }
286
287         /// <summary>
288         /// A method for checking the application is removable
289         /// If the application is removable, show Delete Popup
290         /// </summary>
291         /// <param name="appID">The ID of application for checking</param>
292         public void CheckDeleteApp(string appID)
293         {
294             DebuggingUtils.Dbg("check that the app( " + appID + ") can be deleted");
295
296             if (!ApplicationManagerUtils.Instance.GetAppInfoRemovable(appID))
297             {
298                 DebuggingUtils.Dbg("This app is not removable : " + appID);
299                 return;
300             }
301
302             string appLabel = null;
303             if (ApplicationManagerUtils.Instance.GetInstalledApplication(appID).TryGetValue("Label", out appLabel))
304             {
305                 ViewModel.ShowDeletePopup(appLabel);
306             }
307         }
308
309         /// <summary>
310         /// A method sends application delete request
311         /// If application is pinned, removes in PinnedApps
312         /// </summary>
313         /// <param name="appID">The ID of application for deleting</param>
314         public void DeleteApp(string appID)
315         {
316             // if the app to be deleted is pinned, remove the app in the pinned apps list
317             string pkgID = PackageManagerUtils.GetPackageIDByAppID(appID);
318             if (pkgID == null)
319             {
320                 DebuggingUtils.Err("Failed to get the package ID by app ID(" + appID + ")");
321
322                 return;
323             }
324
325             List<string> appsList = PackageManagerUtils.GetApplicationsByPkgID(pkgID);
326             if (appsList == null || appsList.Count == 0)
327             {
328                 DebuggingUtils.Err("Failed to get the apps list by package ID(" + pkgID + ")");
329
330                 return;
331             }
332
333             ViewModel.ChangeCurrentStatus(AppsStatus.Default);
334
335             if (PackageManagerUtils.UninstallPackageByAppID(appID) == false)
336             {
337                 DebuggingUtils.Err("App uninstall is failed!!!, " + appID);
338             }
339             else
340             {
341                 var removed = from app in InstalledApps
342                               where app.AppID == appID
343                               select app;
344                 InstalledApps.Remove(removed.First());
345                 foreach (var item in InstalledApps)
346                 {
347                     DebuggingUtils.Dbg("- " + item.AppID);
348                 }
349
350                 RemovePinnedApp(appsList);
351                 RefreshApps();
352             }
353         }
354
355         /// <summary>
356         /// A method changes long press state of AppShortcutInfo
357         /// </summary>
358         /// <param name="AppID">The ID of application for showing option menu</param>
359         private void LongPressApp(string AppID)
360         {
361             DebuggingUtils.Dbg(" +++++ long press app : " + AppID);
362         }
363
364         /// <summary>
365         /// A method updates state description of applications
366         /// </summary>
367         /// <param name="status">The state name for updating state description</param>
368         public void UpdateStateDescription(AppsStatus status)
369         {
370             string tag = status.ToString().ToLower();
371
372             if (status == AppsStatus.LongPress)
373             {
374                 AppShortcutInfo focuesedApp = InstalledApps.Find(a => a.IsFocused);
375                 if (focuesedApp == null)
376                 {
377                     DebuggingUtils.Dbg("FocusedApp is not exist. Change app status to default");
378                     ViewModel.ChangeCurrentStatus(AppsStatus.Default);
379                     return;
380                 }
381             }
382
383             DebuggingUtils.Dbg("AppsListStateUpdate, status = " + status.ToString() + ", tag = " + tag);
384             foreach (AppShortcutInfo item in InstalledApps)
385             {
386                 item.CurrentStateDescription = item.StateDescriptions[tag];
387                 switch (status)
388                 {
389                     case AppsStatus.Default:
390                         item.IsChecked = false;
391                         item.IsDim = false;
392                         item.IsShowOptions = false;
393                         break;
394                     case AppsStatus.Pin:
395                         item.IsChecked = item.IsPinned;
396                         break;
397                     case AppsStatus.LongPress:
398                         if (item.IsFocused)
399                         {
400                             item.IsShowOptions = true;
401                         }
402                         else
403                         {
404                             item.IsDim = true;
405                         }
406
407                         break;
408                     case AppsStatus.Delete:
409                         if (!item.IsRemovable)
410                         {
411                             item.IsDim = true;
412                         }
413
414                         item.IsChecked = false;
415                         break;
416                 }
417
418                 item.IsPinned = PinnedApps.ContainsKey(item.AppID);
419             }
420
421             ViewModel.OnPropertyChanged("InstalledAppList");
422         }
423
424         /// <summary>
425         /// A method refresh InstalledApps
426         /// </summary>
427         private void RefreshApps()
428         {
429             // Only updating elements of InstalledApps is not update the GUI.
430             InstalledApps = new List<AppShortcutInfo>(InstalledApps);
431             ViewModel.OnPropertyChanged("InstalledAppList");
432         }
433
434         /// <summary>
435         /// A method sorts InstalledApps according to parameter
436         /// </summary>
437         /// <param name="sortOption">The option for sorting InstalledApps</param>
438         /// <see cref="SortingOptions"></see>
439         public void SortApps(SortingOptions sortOption)
440         {
441             AppsListSorter.GetSortedAppsList(sortOption, ref InstalledApps);
442             RefreshApps();
443         }
444
445         /// <summary>
446         /// A method reloads PinnedApps from AppShortcutController
447         /// </summary>
448         public async void ResetPinnedApps()
449         {
450             PinnedApps = await TVHomeImpl.GetInstance.AppShortcutControllerInstance.GetPinnedAppsAppIDs();
451         }
452
453         /// <summary>
454         /// A method updates list about pinned application to AppShortcutController
455         /// </summary>
456         public void UpdatePinnedApps()
457         {
458             List<AppShortcutInfo> pinnedAppList = new List<AppShortcutInfo>();
459             foreach (var item in PinnedApps)
460             {
461                 pinnedAppList.Add(new AppShortcutInfo()
462                 {
463                     AppID = item.Key,
464                 });
465             }
466
467             TVHomeImpl.GetInstance.AppShortcutControllerInstance.UpdatePinnedApps(pinnedAppList);
468         }
469
470         /// <summary>
471         /// A method changes visible state of option menu to true
472         /// </summary>
473         /// <param name="appId">The ID of application for showing option menu</param>
474         public void ShowLongPressOption(string appId)
475         {
476             AppShortcutInfo longPressedApp = InstalledApps.Find(app => app.AppID.Equals(appId));
477             if (longPressedApp != null)
478             {
479                 longPressedApp.IsDim = false;
480                 longPressedApp.IsShowOptions = true;
481             }
482         }
483
484         /// <summary>
485         /// A method changes visible state of option menu to false
486         /// </summary>
487         /// <param name="appId">The ID of application for hiding option menu</param>
488         public void HideLongPressOption(string appId)
489         {
490             AppShortcutInfo longPressedApp = InstalledApps.Find(app => app.AppID.Equals(appId));
491             if (longPressedApp != null)
492             {
493                 longPressedApp.IsShowOptions = false;
494             }
495         }
496     }
497 }