[Applications.Common] Add missing application APIs (#547)
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.Common / Tizen.Applications / ApplicationManager.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.Collections.Generic;
19 using System.ComponentModel;
20 using System.Runtime.InteropServices;
21 using System.Threading.Tasks;
22 using static Interop.ApplicationManager;
23
24 namespace Tizen.Applications
25 {
26     /// <summary>
27     /// This class has the methods and events of the ApplicationManager.
28     /// </summary>
29     /// <since_tizen> 3 </since_tizen>
30     public static class ApplicationManager
31     {
32         private const string LogTag = "Tizen.Applications";
33         private static EventHandler<ApplicationLaunchedEventArgs> s_launchedHandler;
34         private static EventHandler<ApplicationTerminatedEventArgs> s_terminatedHandler;
35         private static Interop.ApplicationManager.AppManagerAppContextEventCallback s_applicationChangedEventCallback;
36         private static EventHandler<ApplicationEnabledEventArgs> s_enabledHandler;
37         private static EventHandler<ApplicationDisabledEventArgs> s_disabledHandler;
38         private static Interop.ApplicationManager.AppManagerEventCallback s_eventCallback;
39         private static IntPtr _eventHandle = IntPtr.Zero;
40         private static readonly object s_eventLock = new object();
41         private static readonly object s_applicationChangedEventLock = new object();
42
43         /// <summary>
44         /// Occurs whenever the installed application is enabled.
45         /// </summary>
46         /// <since_tizen> 3 </since_tizen>
47         public static event EventHandler<ApplicationEnabledEventArgs> ApplicationEnabled
48         {
49             add
50             {
51                 lock (s_eventLock)
52                 {
53                     if (s_eventCallback == null)
54                     {
55                         RegisterApplicationEvent();
56                     }
57                     s_enabledHandler += value;
58                 }
59             }
60             remove
61             {
62                 lock (s_eventLock)
63                 {
64                     s_enabledHandler -= value;
65                     if (s_enabledHandler == null && s_disabledHandler == null && s_eventCallback != null)
66                     {
67                         UnRegisterApplicationEvent();
68                         s_eventCallback = null;
69                     }
70                 }
71             }
72         }
73
74         /// <summary>
75         /// Occurs whenever the installed application is disabled.
76         /// </summary>
77         /// <since_tizen> 3 </since_tizen>
78         public static event EventHandler<ApplicationDisabledEventArgs> ApplicationDisabled
79         {
80             add
81             {
82                 lock (s_eventLock)
83                 {
84                     if (s_eventCallback == null)
85                     {
86                         RegisterApplicationEvent();
87                     }
88                     s_disabledHandler += value;
89                 }
90             }
91             remove
92             {
93                 lock (s_eventLock)
94                 {
95                     s_disabledHandler -= value;
96                     if (s_enabledHandler == null && s_disabledHandler == null && s_eventCallback != null)
97                     {
98                         UnRegisterApplicationEvent();
99                         s_eventCallback = null;
100                     }
101                 }
102             }
103         }
104
105         /// <summary>
106         /// Occurs whenever the installed applications get launched.
107         /// </summary>
108         /// <since_tizen> 3 </since_tizen>
109         public static event EventHandler<ApplicationLaunchedEventArgs> ApplicationLaunched
110         {
111             add
112             {
113                 lock (s_applicationChangedEventLock)
114                 {
115                     if (s_applicationChangedEventCallback == null)
116                     {
117                         RegisterApplicationChangedEvent();
118                     }
119                     s_launchedHandler += value;
120                 }
121             }
122             remove
123             {
124                 lock (s_applicationChangedEventLock)
125                 {
126                     s_launchedHandler -= value;
127                     if (s_launchedHandler == null && s_terminatedHandler == null && s_applicationChangedEventCallback != null)
128                     {
129                         UnRegisterApplicationChangedEvent();
130                         s_applicationChangedEventCallback = null;
131                     }
132                 }
133             }
134         }
135
136         /// <summary>
137         /// Occurs whenever the installed applications get terminated.
138         /// </summary>
139         /// <since_tizen> 3 </since_tizen>
140         public static event EventHandler<ApplicationTerminatedEventArgs> ApplicationTerminated
141         {
142             add
143             {
144                 lock (s_applicationChangedEventLock)
145                 {
146                     if (s_applicationChangedEventCallback == null)
147                     {
148                         RegisterApplicationChangedEvent();
149                     }
150                     s_terminatedHandler += value;
151                 }
152             }
153             remove
154             {
155                 lock (s_applicationChangedEventLock)
156                 {
157                     s_terminatedHandler -= value;
158                     if (s_launchedHandler == null && s_terminatedHandler == null && s_applicationChangedEventCallback != null)
159                     {
160                         UnRegisterApplicationChangedEvent();
161                         s_applicationChangedEventCallback = null;
162                     }
163                 }
164             }
165         }
166
167         /// <summary>
168         /// Gets the information of the installed applications asynchronously.
169         /// </summary>
170         /// <returns>The installed application info list.</returns>
171         /// <since_tizen> 3 </since_tizen>
172         public static async Task<IEnumerable<ApplicationInfo>> GetInstalledApplicationsAsync()
173         {
174             return await Task.Run(() =>
175             {
176                 Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.ErrorCode.None;
177                 List<ApplicationInfo> result = new List<ApplicationInfo>();
178
179                 Interop.ApplicationManager.AppManagerAppInfoCallback cb = (IntPtr infoHandle, IntPtr userData) =>
180                 {
181                     if (infoHandle != IntPtr.Zero)
182                     {
183                         IntPtr clonedHandle = IntPtr.Zero;
184                         err = Interop.ApplicationManager.AppInfoClone(out clonedHandle, infoHandle);
185                         if (err != Interop.ApplicationManager.ErrorCode.None)
186                         {
187                             Log.Warn(LogTag, "Failed to clone the appinfo. err = " + err);
188                             return false;
189                         }
190                         ApplicationInfo app = new ApplicationInfo(clonedHandle);
191                         result.Add(app);
192                         return true;
193                     }
194                     return false;
195                 };
196                 err = Interop.ApplicationManager.AppManagerForeachAppInfo(cb, IntPtr.Zero);
197                 if (err != Interop.ApplicationManager.ErrorCode.None)
198                 {
199                     throw ApplicationManagerErrorFactory.GetException(err, "Failed to foreach the appinfo.");
200                 }
201                 return result;
202             });
203         }
204
205         /// <summary>
206         /// Terminates the application if it is running on background.
207         /// </summary>
208         /// <param name="app">ApplicationRunningContext object</param>
209         /// <exception cref="ArgumentException">Thrown when failed of invalid argument.</exception>
210         /// <exception cref="UnauthorizedAccessException">Thrown when failed because of permission denied.</exception>
211         /// <exception cref="InvalidOperationException">Thrown when failed because of system error.</exception>
212         /// <privilege>http://tizen.org/privilege/appmanager.kill.bgapp</privilege>
213         /// <remarks>
214         /// This function returns after it just sends a request for terminating a background application.
215         /// Platform will decide if the target application could be terminated or not according to the state of the target application.
216         /// </remarks>
217         /// <since_tizen> 6 </since_tizen>
218         public static void TerminateBackgroundApplication(ApplicationRunningContext app)
219         {
220             ErrorCode err = Interop.ApplicationManager.AppManagerRequestTerminateBgApp(app._contextHandle);
221             if (err != Interop.ApplicationManager.ErrorCode.None)
222             {
223                 switch (err)
224                 {
225                     case Interop.ApplicationManager.ErrorCode.InvalidParameter:
226                         throw new ArgumentException("Invalid argument.");
227                     case Interop.ApplicationManager.ErrorCode.PermissionDenied:
228                         throw new UnauthorizedAccessException("Permission denied.");
229                     default:
230                         throw new InvalidOperationException("Invalid Operation.");
231                 }
232             }
233         }
234
235         /// <summary>
236         /// Gets the information of the installed applications with the ApplicationInfoFilter asynchronously.
237         /// </summary>
238         /// <param name="filter">Key-value pairs for filtering.</param>
239         /// <returns>The installed application info list.</returns>
240         /// <since_tizen> 3 </since_tizen>
241         public static async Task<IEnumerable<ApplicationInfo>> GetInstalledApplicationsAsync(ApplicationInfoFilter filter)
242         {
243             return await Task.Run(() =>
244             {
245                 List<ApplicationInfo> result = new List<ApplicationInfo>();
246
247                 Interop.ApplicationManager.AppInfoFilterCallback cb = (IntPtr infoHandle, IntPtr userData) =>
248                 {
249                     if (infoHandle != IntPtr.Zero)
250                     {
251                         IntPtr clonedHandle = IntPtr.Zero;
252                         Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.AppInfoClone(out clonedHandle, infoHandle);
253                         if (err != Interop.ApplicationManager.ErrorCode.None)
254                         {
255                             Log.Warn(LogTag, "Failed to clone the appinfo. err = " + err);
256                             return false;
257                         }
258                         ApplicationInfo app = new ApplicationInfo(clonedHandle);
259                         result.Add(app);
260                         return true;
261                     }
262                     return false;
263                 };
264                 filter.Fetch(cb);
265                 return result;
266             });
267         }
268
269         /// <summary>
270         /// Gets the information of the installed applications with the ApplicationInfoMetadataFilter asynchronously.
271         /// </summary>
272         /// <param name="filter">Key-value pairs for filtering.</param>
273         /// <returns>The installed application info list.</returns>
274         /// <since_tizen> 3 </since_tizen>
275         public static async Task<IEnumerable<ApplicationInfo>> GetInstalledApplicationsAsync(ApplicationInfoMetadataFilter filter)
276         {
277             return await Task.Run(() =>
278             {
279                 List<ApplicationInfo> result = new List<ApplicationInfo>();
280
281                 Interop.ApplicationManager.AppInfoFilterCallback cb = (IntPtr infoHandle, IntPtr userData) =>
282                 {
283                     if (infoHandle != IntPtr.Zero)
284                     {
285                         IntPtr clonedHandle = IntPtr.Zero;
286                         Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.AppInfoClone(out clonedHandle, infoHandle);
287                         if (err != Interop.ApplicationManager.ErrorCode.None)
288                         {
289                             Log.Warn(LogTag, "Failed to clone the appinfo. err = " + err);
290                             return false;
291                         }
292                         ApplicationInfo app = new ApplicationInfo(clonedHandle);
293                         result.Add(app);
294                         return true;
295                     }
296                     return false;
297                 };
298                 filter.Fetch(cb);
299                 return result;
300             });
301         }
302
303         /// <summary>
304         /// Gets the information of the running applications asynchronously.
305         /// </summary>
306         /// <returns>The application running context list.</returns>
307         /// <since_tizen> 3 </since_tizen>
308         public static async Task<IEnumerable<ApplicationRunningContext>> GetRunningApplicationsAsync()
309         {
310             return await Task.Run(() =>
311             {
312                 Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.ErrorCode.None;
313                 List<ApplicationRunningContext> result = new List<ApplicationRunningContext>();
314
315                 Interop.ApplicationManager.AppManagerAppContextCallback cb = (IntPtr contextHandle, IntPtr userData) =>
316                 {
317                     if (contextHandle != IntPtr.Zero)
318                     {
319                         IntPtr clonedHandle = IntPtr.Zero;
320                         err = Interop.ApplicationManager.AppContextClone(out clonedHandle, contextHandle);
321                         if (err != Interop.ApplicationManager.ErrorCode.None)
322                         {
323                             Log.Warn(LogTag, "Failed to clone the app context. err = " + err);
324                             return false;
325                         }
326                         ApplicationRunningContext context = new ApplicationRunningContext(clonedHandle);
327                         result.Add(context);
328                         return true;
329                     }
330                     return false;
331                 };
332
333                 err = Interop.ApplicationManager.AppManagerForeachAppContext(cb, IntPtr.Zero);
334                 if (err != Interop.ApplicationManager.ErrorCode.None)
335                 {
336                     throw ApplicationManagerErrorFactory.GetException(err, "Failed to foreach appcontext.");
337                 }
338                 return result;
339             });
340         }
341
342         /// <summary>
343         /// Gets the information of the running applications including subapp asynchronously.
344         /// </summary>
345         /// <returns>The application running context list.</returns>
346         /// <since_tizen> 3 </since_tizen>
347         public static async Task<IEnumerable<ApplicationRunningContext>> GetAllRunningApplicationsAsync()
348         {
349             return await Task.Run(() =>
350             {
351                 Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.ErrorCode.None;
352                 List<ApplicationRunningContext> result = new List<ApplicationRunningContext>();
353
354                 Interop.ApplicationManager.AppManagerAppContextCallback cb = (IntPtr contextHandle, IntPtr userData) =>
355                 {
356                     if (contextHandle != IntPtr.Zero)
357                     {
358                         IntPtr clonedHandle = IntPtr.Zero;
359                         err = Interop.ApplicationManager.AppContextClone(out clonedHandle, contextHandle);
360                         if (err != Interop.ApplicationManager.ErrorCode.None)
361                         {
362                             Log.Warn(LogTag, "Failed to clone the app context. err = " + err);
363                             return false;
364                         }
365                         ApplicationRunningContext context = new ApplicationRunningContext(clonedHandle);
366                         result.Add(context);
367                         return true;
368                     }
369                     return false;
370                 };
371
372                 err = Interop.ApplicationManager.AppManagerForeachRunningAppContext(cb, IntPtr.Zero);
373                 if (err != Interop.ApplicationManager.ErrorCode.None)
374                 {
375                     throw ApplicationManagerErrorFactory.GetException(err, "Failed to foreach appcontext.");
376                 }
377                 return result;
378             });
379         }
380
381         /// <summary>
382         /// Gets the information of the specified application with the application ID.
383         /// </summary>
384         /// <param name="applicationId">Application ID.</param>
385         /// <returns>The application info.</returns>
386         /// <since_tizen> 3 </since_tizen>
387         public static ApplicationInfo GetInstalledApplication(string applicationId)
388         {
389             IntPtr infoHandle = IntPtr.Zero;
390             Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.AppManagerGetAppInfo(applicationId, out infoHandle);
391             if (err != Interop.ApplicationManager.ErrorCode.None)
392             {
393                 throw ApplicationManagerErrorFactory.GetException(err, "Failed to get the installed application information of " + applicationId + ".");
394             }
395             ApplicationInfo app = new ApplicationInfo(infoHandle);
396             return app;
397         }
398
399         /// <summary>
400         /// Returns if the specified application is running or not.
401         /// </summary>
402         /// <param name="applicationId">The application ID.</param>
403         /// <returns>Returns true if the given application is running, otherwise false.</returns>
404         /// <exception cref="ArgumentException">Thrown when the given parameter is invalid.</exception>
405         /// <since_tizen> 3 </since_tizen>
406         public static bool IsRunning(string applicationId)
407         {
408             bool isRunning = false;
409             Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.AppManagerIsRunning(applicationId, out isRunning);
410             if (err != Interop.ApplicationManager.ErrorCode.None)
411             {
412                 throw ApplicationManagerErrorFactory.GetException(Interop.ApplicationManager.ErrorCode.InvalidParameter, "Invalid parameter");
413             }
414             return isRunning;
415         }
416
417         /// <summary>
418         /// Returns the application id.
419         /// </summary>
420         /// <param name="processId">The application pid.</param>
421         /// <returns>Returns the application id.</returns>
422         /// <exception cref="ArgumentException">Thrown when the given parameter is invalid.</exception>
423         /// <since_tizen> 6 </since_tizen>
424         public static string GetAppId(int processId)
425         {
426             string appid;
427             Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.AppManagerGetAppId(processId, out appid);
428             if (err != Interop.ApplicationManager.ErrorCode.None)
429             {
430                 throw ApplicationManagerErrorFactory.GetException(err, "fail to get appid(" + processId + ")");
431             }
432             return appid;
433         }
434
435         private static void RegisterApplicationChangedEvent()
436         {
437             Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.ErrorCode.None;
438             s_applicationChangedEventCallback = (IntPtr contextHandle, Interop.ApplicationManager.AppContextEvent state, IntPtr userData) =>
439             {
440                 if (contextHandle == IntPtr.Zero) return;
441
442                 IntPtr clonedHandle = IntPtr.Zero;
443                 err = Interop.ApplicationManager.AppContextClone(out clonedHandle, contextHandle);
444                 if (err != Interop.ApplicationManager.ErrorCode.None)
445                 {
446                     throw ApplicationManagerErrorFactory.GetException(err, "Failed to register the application context event.");
447                 }
448                 using (ApplicationRunningContext context = new ApplicationRunningContext(clonedHandle))
449                 {
450                     if (state == Interop.ApplicationManager.AppContextEvent.Launched)
451                     {
452                         s_launchedHandler?.Invoke(null, new ApplicationLaunchedEventArgs { ApplicationRunningContext = context });
453                     }
454                     else if (state == Interop.ApplicationManager.AppContextEvent.Terminated)
455                     {
456                         s_terminatedHandler?.Invoke(null, new ApplicationTerminatedEventArgs { ApplicationRunningContext = context });
457                     }
458                 }
459             };
460             err = Interop.ApplicationManager.AppManagerSetAppContextEvent(s_applicationChangedEventCallback, IntPtr.Zero);
461             if (err != Interop.ApplicationManager.ErrorCode.None)
462             {
463                 throw ApplicationManagerErrorFactory.GetException(err, "Failed to register the application context event.");
464             }
465         }
466
467         private static void UnRegisterApplicationChangedEvent()
468         {
469             Interop.ApplicationManager.AppManagerUnSetAppContextEvent();
470         }
471
472         private static void RegisterApplicationEvent()
473         {
474             Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.ErrorCode.None;
475             err = Interop.ApplicationManager.AppManagerEventCreate(out _eventHandle);
476             if (err != Interop.ApplicationManager.ErrorCode.None)
477             {
478                 throw ApplicationManagerErrorFactory.GetException(err, "Failed to create the application event handle");
479             }
480
481             err = Interop.ApplicationManager.AppManagerEventSetStatus(_eventHandle, Interop.ApplicationManager.AppManagerEventStatusType.All);
482             if (err != Interop.ApplicationManager.ErrorCode.None)
483             {
484                 Interop.ApplicationManager.AppManagerEventDestroy(_eventHandle);
485                 _eventHandle = IntPtr.Zero;
486                 throw ApplicationManagerErrorFactory.GetException(err, "Failed to set the application event");
487             }
488
489             s_eventCallback = (string appType, string appId, Interop.ApplicationManager.AppManagerEventType eventType, Interop.ApplicationManager.AppManagerEventState eventState, IntPtr eventHandle, IntPtr UserData) =>
490             {
491                 if (eventType == Interop.ApplicationManager.AppManagerEventType.Enable)
492                 {
493                     s_enabledHandler?.Invoke(null, new ApplicationEnabledEventArgs(appId, (ApplicationEventState)eventState));
494                 }
495                 else if (eventType == Interop.ApplicationManager.AppManagerEventType.Disable)
496                 {
497                     s_disabledHandler?.Invoke(null, new ApplicationDisabledEventArgs(appId, (ApplicationEventState)eventState));
498                 }
499             };
500             err = Interop.ApplicationManager.AppManagerSetEventCallback(_eventHandle, s_eventCallback, IntPtr.Zero);
501             if (err != Interop.ApplicationManager.ErrorCode.None)
502             {
503                 Interop.ApplicationManager.AppManagerEventDestroy(_eventHandle);
504                 _eventHandle = IntPtr.Zero;
505                 throw ApplicationManagerErrorFactory.GetException(err, "Failed to set the application event callback");
506             }
507         }
508
509         private static void UnRegisterApplicationEvent()
510         {
511             if (_eventHandle != IntPtr.Zero)
512             {
513                 Interop.ApplicationManager.AppManagerUnSetEventCallback(_eventHandle);
514                 Interop.ApplicationManager.AppManagerEventDestroy(_eventHandle);
515                 _eventHandle = IntPtr.Zero;
516             }
517         }
518
519         /// <summary>
520         /// Gets the information of the recent applications.
521         /// </summary>
522         /// <returns>Returns a dictionary containing all the recent application info.</returns>
523         /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
524         /// <since_tizen> 3 </since_tizen>
525         [EditorBrowsable(EditorBrowsableState.Never)]
526         public static IEnumerable<RecentApplicationInfo> GetRecentApplications()
527         {
528             Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.ErrorCode.None;
529
530             List<RecentApplicationInfo> result = new List<RecentApplicationInfo>();
531             IntPtr table;
532             int nrows, ncols;
533
534             err = Interop.ApplicationManager.RuaHistoryLoadDb(out table, out nrows, out ncols);
535             if (err != Interop.ApplicationManager.ErrorCode.None)
536             {
537                 throw ApplicationManagerErrorFactory.GetException(err, "Failed to load a table for the recent application list.");
538             }
539
540             for (int row = 0; row < nrows; ++row)
541             {
542                 Interop.ApplicationManager.RuaRec record;
543
544                 err = Interop.ApplicationManager.RuaHistoryGetRecord(out record, table, nrows, ncols, row);
545                 if (err != Interop.ApplicationManager.ErrorCode.None)
546                 {
547                     throw ApplicationManagerErrorFactory.GetException(err, "Failed to get record.");
548                 }
549
550                 RecentApplicationInfo info = new RecentApplicationInfo(record);
551                 result.Add(info);
552             }
553
554             err = Interop.ApplicationManager.RuaHistoryUnLoadDb(ref table);
555             if (err != Interop.ApplicationManager.ErrorCode.None)
556             {
557                 throw ApplicationManagerErrorFactory.GetException(err, "Failed to unload a table for the recent application list.");
558             }
559
560             return result;
561         }
562     }
563
564     internal static class FilterExtension
565     {
566         private const string LogTag = "Tizen.Applications";
567         internal static void Fetch(this ApplicationInfoFilter filter, Interop.ApplicationManager.AppInfoFilterCallback callback)
568         {
569             if (filter is ApplicationInfoMetadataFilter)
570             {
571                 ApplicationInfoMetadataFilter metaFilter = (ApplicationInfoMetadataFilter)filter;
572                 metaFilter.Fetch(callback);
573                 return;
574             }
575
576             IntPtr nativeHandle = MakeNativeAppInfoFilter(filter.Filter);
577             if (nativeHandle == IntPtr.Zero)
578             {
579                 throw ApplicationManagerErrorFactory.NativeFilterHandleIsInvalid();
580             }
581             try
582             {
583                 Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.AppInfoFilterForeachAppinfo(nativeHandle, callback, IntPtr.Zero);
584                 if (err != Interop.ApplicationManager.ErrorCode.None)
585                 {
586                     throw ApplicationManagerErrorFactory.GetException(err, "Failed to get application information list with filter.");
587                 }
588             }
589             finally
590             {
591                 Interop.ApplicationManager.AppInfoFilterDestroy(nativeHandle);
592             }
593         }
594
595         internal static void Fetch(this ApplicationInfoMetadataFilter filter, Interop.ApplicationManager.AppInfoFilterCallback callback)
596         {
597             IntPtr nativeHandle = MakeNativeAppMetadataFilter(filter.Filter);
598             if (nativeHandle == IntPtr.Zero)
599             {
600                 throw ApplicationManagerErrorFactory.NativeFilterHandleIsInvalid();
601             }
602             try
603             {
604                 Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.AppInfoMetadataFilterForeach(nativeHandle, callback, IntPtr.Zero);
605                 if (err != Interop.ApplicationManager.ErrorCode.None)
606                 {
607                     throw ApplicationManagerErrorFactory.GetException(err, "Failed to get metadata list with filter.");
608                 }
609             }
610             finally
611             {
612                 Interop.ApplicationManager.AppInfoMetadataFilterDestroy(nativeHandle);
613             }
614         }
615
616         private static IntPtr MakeNativeAppInfoFilter(IDictionary<string, string> filter)
617         {
618             if (filter == null || filter.Count == 0)
619             {
620                 throw ApplicationManagerErrorFactory.FilterIsInvalid();
621             }
622
623             IntPtr infoHandle = IntPtr.Zero;
624             Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.AppInfoFilterCreate(out infoHandle);
625             if (err != Interop.ApplicationManager.ErrorCode.None)
626             {
627                 throw ApplicationManagerErrorFactory.GetException(err, "Failed to create the filter handle.");
628             }
629
630             foreach (var item in filter)
631             {
632                 if ((item.Key == ApplicationInfoFilter.Keys.Id) ||
633                     (item.Key == ApplicationInfoFilter.Keys.Type) ||
634                     (item.Key == ApplicationInfoFilter.Keys.Category) ||
635                     (item.Key == ApplicationInfoFilter.Keys.InstalledStorage))
636                 {
637                     err = Interop.ApplicationManager.AppInfoFilterAddString(infoHandle, item.Key, item.Value);
638                 }
639                 else if ((item.Key == ApplicationInfoFilter.Keys.NoDisplay) ||
640                          (item.Key == ApplicationInfoFilter.Keys.TaskManage))
641                 {
642                     err = Interop.ApplicationManager.AppInfoFilterAddBool(infoHandle, item.Key, Convert.ToBoolean(item.Value));
643                 }
644                 else
645                 {
646                     Log.Warn(LogTag, string.Format("'{0}' is not supported key for the filter.", item.Key));
647                 }
648                 if (err != Interop.ApplicationManager.ErrorCode.None)
649                 {
650                     Interop.ApplicationManager.AppInfoFilterDestroy(infoHandle);
651                     throw ApplicationManagerErrorFactory.GetException(err, "Failed to add item to the filter.");
652                 }
653             }
654             return infoHandle;
655         }
656
657         private static IntPtr MakeNativeAppMetadataFilter(IDictionary<string, string> filter)
658         {
659             if (filter == null || filter.Count == 0)
660             {
661                 throw ApplicationManagerErrorFactory.FilterIsInvalid();
662             }
663
664             IntPtr infoHandle = IntPtr.Zero;
665             Interop.ApplicationManager.ErrorCode err = Interop.ApplicationManager.AppInfoMetadataFilterCreate(out infoHandle);
666             if (err != Interop.ApplicationManager.ErrorCode.None)
667             {
668                 throw ApplicationManagerErrorFactory.GetException(err, "Failed to create the filter for searching with metadata.");
669             }
670             foreach (var item in filter)
671             {
672                 err = Interop.ApplicationManager.AppInfoMetadataFilterAdd(infoHandle, item.Key, item.Value);
673                 if (err != Interop.ApplicationManager.ErrorCode.None)
674                 {
675                     Interop.ApplicationManager.AppInfoMetadataFilterDestroy(infoHandle);
676                     throw ApplicationManagerErrorFactory.GetException(err, "Failed to add the item to the filter.");
677                 }
678             }
679             return infoHandle;
680         }
681     }
682
683     internal static class ApplicationManagerErrorFactory
684     {
685         internal static Exception NativeFilterHandleIsInvalid()
686         {
687             return new InvalidOperationException("The native handle for filtering is invalid.");
688         }
689
690         internal static Exception FilterIsInvalid()
691         {
692             return new ArgumentException("The filter is invalid.");
693         }
694
695         internal static Exception GetException(Interop.ApplicationManager.ErrorCode err, string message)
696         {
697             string errMessage = String.Format("{0} err = {1}", message, err);
698             switch (err)
699             {
700                 case Interop.ApplicationManager.ErrorCode.InvalidParameter:
701                     return new ArgumentException(errMessage);
702                 default:
703                     return new InvalidOperationException(errMessage);
704             }
705         }
706     }
707 }