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