[Packagemanager] Fix managing delegate lifetime
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.PackageManager / Tizen.Applications / PackageManager.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.Threading.Tasks;
20 using System.IO;
21
22 namespace Tizen.Applications
23 {
24     /// <summary>
25     /// PackageManager class. This class has the methods and events of the PackageManager.
26     /// </summary>
27     /// <remarks>
28     /// The package manager is one of the core modules of the Tizen application framework and responsible for getting their information.
29     /// You can also retrieve information related to the packages that are installed on the device.
30     /// </remarks>
31     /// <since_tizen> 3 </since_tizen>
32     public static class PackageManager
33     {
34         private const string LogTag = "Tizen.Applications.PackageManager";
35
36         private static SafePackageManagerHandle s_handle = new SafePackageManagerHandle();
37         private static Interop.PackageManager.EventStatus s_eventStatus = Interop.PackageManager.EventStatus.All;
38         private static event EventHandler<PackageManagerEventArgs> s_installEventHandler;
39         private static event EventHandler<PackageManagerEventArgs> s_uninstallEventHandler;
40         private static event EventHandler<PackageManagerEventArgs> s_updateEventHandler;
41         private static event EventHandler<PackageManagerEventArgs> s_moveEventHandler;
42         private static event EventHandler<PackageManagerEventArgs> s_clearDataEventHandler;
43
44         private static Interop.PackageManager.PackageManagerEventCallback s_packageManagerEventCallback;
45
46         /// <summary>
47         /// Event callback method for the request.
48         /// </summary>
49         /// <param name="type">Type of the package which was requested.</param>
50         /// <param name="packageId">ID of the package which was requested.</param>
51         /// <param name="eventType">Event type of the request.</param>
52         /// <param name="eventState">Current event state of the request.</param>
53         /// <param name="progress">Progress for the request being processed by the package manager (in percent).</param>
54         /// <since_tizen> 3 </since_tizen>
55         public delegate void RequestEventCallback(string type, string packageId, PackageEventType eventType, PackageEventState eventState, int progress);
56
57         private static Dictionary<int, RequestEventCallback> RequestCallbacks = new Dictionary<int, RequestEventCallback>();
58         private static Dictionary<int, SafePackageManagerRequestHandle> RequestHandles = new Dictionary<int, SafePackageManagerRequestHandle>();
59
60         private delegate Interop.PackageManager.ErrorCode InstallMethodWithCallback(SafePackageManagerRequestHandle requestHandle, string pkgPath, Interop.PackageManager.PackageManagerRequestEventCallback requestCallback, IntPtr userData, out int requestID);
61         private delegate Interop.PackageManager.ErrorCode InstallMethod(SafePackageManagerRequestHandle requestHandle, string pkgPath, out int requestID);
62
63         /// <summary>
64         /// InstallProgressChanged event. This event occurs when a package is getting installed and the progress of the request to the package manager is changed.
65         /// </summary>
66         /// <since_tizen> 3 </since_tizen>
67         public static event EventHandler<PackageManagerEventArgs> InstallProgressChanged
68         {
69             add
70             {
71                 SetPackageManagerEventStatus(Interop.PackageManager.EventStatus.Install);
72                 RegisterPackageManagerEventIfNeeded();
73                 s_installEventHandler += value;
74             }
75             remove
76             {
77                 s_installEventHandler -= value;
78                 UnregisterPackageManagerEventIfNeeded();
79                 UnsetPackageManagerEventStatus();
80             }
81         }
82
83         /// <summary>
84         /// UninstallProgressChanged event. This event occurs when a package is getting uninstalled and the progress of the request to the package manager is changed.
85         /// </summary>
86         /// <since_tizen> 3 </since_tizen>
87         public static event EventHandler<PackageManagerEventArgs> UninstallProgressChanged
88         {
89             add
90             {
91                 SetPackageManagerEventStatus(Interop.PackageManager.EventStatus.Uninstall);
92                 RegisterPackageManagerEventIfNeeded();
93                 s_uninstallEventHandler += value;
94             }
95             remove
96             {
97                 s_uninstallEventHandler -= value;
98                 UnregisterPackageManagerEventIfNeeded();
99                 UnsetPackageManagerEventStatus();
100             }
101         }
102
103         /// <summary>
104         /// UpdateProgressChanged event. This event occurs when a package is getting updated and the progress of the request to the package manager is changed.
105         /// </summary>
106         /// <since_tizen> 3 </since_tizen>
107         public static event EventHandler<PackageManagerEventArgs> UpdateProgressChanged
108         {
109             add
110             {
111                 SetPackageManagerEventStatus(Interop.PackageManager.EventStatus.Upgrade);
112                 RegisterPackageManagerEventIfNeeded();
113                 s_updateEventHandler += value;
114             }
115             remove
116             {
117                 s_updateEventHandler -= value;
118                 UnregisterPackageManagerEventIfNeeded();
119                 UnsetPackageManagerEventStatus();
120             }
121         }
122
123         /// <summary>
124         /// MoveProgressChanged event. This event occurs when a package is getting moved and the progress of the request to the package manager is changed.
125         /// </summary>
126         /// <since_tizen> 3 </since_tizen>
127         public static event EventHandler<PackageManagerEventArgs> MoveProgressChanged
128         {
129             add
130             {
131                 SetPackageManagerEventStatus(Interop.PackageManager.EventStatus.Move);
132                 RegisterPackageManagerEventIfNeeded();
133                 s_moveEventHandler += value;
134             }
135             remove
136             {
137                 s_moveEventHandler -= value;
138                 UnregisterPackageManagerEventIfNeeded();
139                 UnsetPackageManagerEventStatus();
140             }
141         }
142
143         /// <summary>
144         /// ClearDataProgressChanged event. This event occurs when data directories are cleared in the given package.
145         /// </summary>
146         /// <since_tizen> 3 </since_tizen>
147         public static event EventHandler<PackageManagerEventArgs> ClearDataProgressChanged
148         {
149             add
150             {
151                 SetPackageManagerEventStatus(Interop.PackageManager.EventStatus.ClearData);
152                 RegisterPackageManagerEventIfNeeded();
153                 s_clearDataEventHandler += value;
154             }
155             remove
156             {
157                 s_clearDataEventHandler -= value;
158                 UnregisterPackageManagerEventIfNeeded();
159                 UnsetPackageManagerEventStatus();
160             }
161         }
162
163         private static SafePackageManagerHandle Handle
164         {
165             get
166             {
167                 if (s_handle.IsInvalid)
168                 {
169                     var err = Interop.PackageManager.PackageManagerCreate(out s_handle);
170                     if (err != Interop.PackageManager.ErrorCode.None)
171                     {
172                         Log.Warn(LogTag, string.Format("Failed to create package manager handle. err = {0}", err));
173                     }
174                 }
175                 return s_handle;
176             }
177         }
178
179         private static Interop.PackageManager.PackageManagerRequestEventCallback internalRequestEventCallback = (id, packageType, packageId, eventType, eventState, progress, error, userData) =>
180         {
181             if (RequestCallbacks.ContainsKey(id))
182             {
183                 try
184                 {
185                     RequestCallbacks[id](packageType, packageId, (PackageEventType)eventType, (PackageEventState)eventState, progress);
186                     if (eventState == Interop.PackageManager.PackageEventState.Completed || eventState == Interop.PackageManager.PackageEventState.Failed)
187                     {
188                         Log.Debug(LogTag, string.Format("release request handle for id : {0}", id));
189                         RequestHandles[id].Dispose();
190                         RequestHandles.Remove(id);
191                         RequestCallbacks.Remove(id);
192                     }
193                 }
194                 catch (Exception e)
195                 {
196                     Log.Warn(LogTag, e.Message);
197                     RequestHandles[id].Dispose();
198                     RequestHandles.Remove(id);
199                     RequestCallbacks.Remove(id);
200                 }
201             }
202         };
203
204         /// <summary>
205         /// Gets the package ID for the given application ID.
206         /// </summary>
207         /// <param name="applicationId">The ID of the application.</param>
208         /// <returns>Returns the ID of the package. Empty string if the application ID does not exist.</returns>
209         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory to continue the execution of the method.</exception>
210         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception>
211         /// <privilege>http://tizen.org/privilege/packagemanager.info</privilege>
212         /// <since_tizen> 3 </since_tizen>
213         public static string GetPackageIdByApplicationId(string applicationId)
214         {
215             string packageId;
216             var err = Interop.PackageManager.PackageManageGetPackageIdByAppId(applicationId, out packageId);
217             if (err != Interop.PackageManager.ErrorCode.None)
218             {
219                 Log.Warn(LogTag, string.Format("Failed to get package Id of {0}. err = {1}", applicationId, err));
220                 if (err != Interop.PackageManager.ErrorCode.InvalidParameter)
221                 {
222                     throw PackageManagerErrorFactory.GetException(err, "Failed to get package Id");
223                 }
224             }
225             return packageId;
226         }
227
228         /// <summary>
229         /// Gets the package information for the given package.
230         /// </summary>
231         /// <param name="packageId">The ID of the package.</param>
232         /// <returns>Returns the package information for the given package ID.</returns>
233         /// <exception cref="ArgumentException">Thrown when the failed input package ID is invalid.</exception>
234         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory to continue the execution of the method.</exception>
235         /// <exception cref="System.IO.IOException">Thrown when the method fails due to an internal I/O error.</exception>
236         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception>
237         /// <privilege>http://tizen.org/privilege/packagemanager.info</privilege>
238         /// <since_tizen> 3 </since_tizen>
239         public static Package GetPackage(string packageId)
240         {
241             return Package.GetPackage(packageId);
242         }
243
244         /// <summary>
245         /// Clears the application's internal and external cache directories.
246         /// </summary>
247         /// <param name="packageId">ID of the package.</param>
248         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory to continue the execution of the method.</exception>
249         /// <exception cref="System.IO.IOException">Thrown when the method fails due to an internal I/O error.</exception>
250         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception>
251         /// <exception cref="SystemException">Thrown when the method failed due to an internal system error.</exception>
252         /// <privilege>http://tizen.org/privilege/packagemanager.clearcache</privilege>
253         /// <since_tizen> 3 </since_tizen>
254         public static void ClearCacheDirectory(string packageId)
255         {
256             Interop.PackageManager.ErrorCode err = Interop.PackageManager.PackageManagerClearCacheDir(packageId);
257             if (err != Interop.PackageManager.ErrorCode.None)
258             {
259                 Log.Warn(LogTag, string.Format("Failed to clear cache directory for {0}. err = {1}", packageId, err));
260                 throw PackageManagerErrorFactory.GetException(err, "Failed to clear cache directory");
261             }
262         }
263
264         /// <summary>
265         /// Clears all the application's internal and external cache directories.
266         /// </summary>
267         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory to continue the execution of the method.</exception>
268         /// <exception cref="System.IO.IOException">Thrown when the method fails due to an internal IO error.</exception>
269         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception>
270         /// <exception cref="SystemException">Thrown when the method failed due to an internal system error.</exception>
271         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
272         /// <privlevel>platform</privlevel>
273         /// <since_tizen> 3 </since_tizen>
274         public static void ClearAllCacheDirectory()
275         {
276             var err = Interop.PackageManager.PackageManagerClearAllCacheDir();
277             if (err != Interop.PackageManager.ErrorCode.None)
278             {
279                 Log.Warn(LogTag, string.Format("Failed to clear all cache directories. err = {0}", err));
280                 throw PackageManagerErrorFactory.GetException(err, "Failed to clear all cache directories");
281             }
282         }
283
284         /// <summary>
285         /// Clears the application's internal and external data directories.
286         /// </summary>
287         /// <remarks>
288         /// All files under data, shared/data, and shared/trusted in the internal storage are removed.
289         /// And, if the external storage exists, then all files under data and shared/trusted in the external storage are removed.
290         /// </remarks>
291         /// <param name="packageId">ID of the package.</param>
292         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory to continue the execution of the method.</exception>
293         /// <exception cref="System.IO.IOException">Thrown when the method failed due to an internal IO error.</exception>
294         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception>
295         /// <exception cref="SystemException">Thrown when the method failed due to an internal system error.</exception>
296         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
297         /// <privlevel>platform</privlevel>
298         /// <since_tizen> 3 </since_tizen>
299         public static void ClearDataDirectory(string packageId)
300         {
301             Interop.PackageManager.ErrorCode err = Interop.PackageManager.PackageManagerClearDataDir(packageId);
302             if (err != Interop.PackageManager.ErrorCode.None)
303             {
304                 Log.Warn(LogTag, string.Format("Failed to clear data directory for {0}. err = {1}", packageId, err));
305                 throw PackageManagerErrorFactory.GetException(err, "Failed to clear data directory");
306             }
307         }
308
309         /// <summary>
310         /// Retrieves the package information of all installed packages.
311         /// </summary>
312         /// <returns>Returns the list of packages.</returns>
313         /// <privilege>http://tizen.org/privilege/packagemanager.info</privilege>
314         /// <since_tizen> 3 </since_tizen>
315         public static IEnumerable<Package> GetPackages()
316         {
317             return GetPackages(null);
318         }
319
320         /// <summary>
321         /// Retrieves the package information of all the installed packages satisfying the filter conditions.
322         /// </summary>
323         /// <param name="filter">Optional - package filters.</param>
324         /// <returns>Returns the list of packages.</returns>
325         /// <privilege>http://tizen.org/privilege/packagemanager.info</privilege>
326         /// <since_tizen> 3 </since_tizen>
327         public static IEnumerable<Package> GetPackages(PackageFilter filter)
328         {
329             List<Package> packageList = new List<Package>();
330
331             IntPtr filterHandle;
332             var err = Interop.PackageManager.PackageManagerFilterCreate(out filterHandle);
333             if (err != Interop.PackageManager.ErrorCode.None)
334             {
335                 Log.Warn(LogTag, string.Format("Failed to create package filter handle. err = {0}", err));
336                 return packageList;
337             }
338
339             if (filter != null && filter.Filters != null)
340             {
341                 foreach (KeyValuePair<string, bool> entry in filter?.Filters)
342                 {
343                     err = Interop.PackageManager.PackageManagerFilterAdd(filterHandle, entry.Key, entry.Value);
344                     if (err != Interop.PackageManager.ErrorCode.None)
345                     {
346                         Log.Warn(LogTag, string.Format("Failed to configure package filter. err = {0}", err));
347                         break;
348                     }
349                 }
350             }
351
352             if (err == Interop.PackageManager.ErrorCode.None)
353             {
354                 Interop.PackageManager.PackageManagerPackageInfoCallback cb = (handle, userData) =>
355                 {
356                     packageList.Add(Package.GetPackage(handle));
357                     return true;
358                 };
359
360                 err = Interop.PackageManager.PackageManagerFilterForeachPackageInfo(filterHandle, cb, IntPtr.Zero);
361                 if (err != Interop.PackageManager.ErrorCode.None)
362                 {
363                     Log.Warn(LogTag, string.Format("Failed to get package Informations. err = {0}", err));
364                 }
365             }
366
367             err = Interop.PackageManager.PackageManagerFilterDestroy(filterHandle);
368             if (err != Interop.PackageManager.ErrorCode.None)
369             {
370                 Log.Warn(LogTag, string.Format("Failed to destroy package filter handle. err = {0}", err));
371             }
372             return packageList;
373         }
374
375         /// <summary>
376         /// Gets the total package size information.
377         /// </summary>
378         /// <returns>Returns the total package size information asynchronously.</returns>
379         /// <privilege>http://tizen.org/privilege/packagemanager.info</privilege>
380         /// <since_tizen> 3 </since_tizen>
381         public static async Task<PackageSizeInformation> GetTotalSizeInformationAsync()
382         {
383             TaskCompletionSource<PackageSizeInformation> tcs = new TaskCompletionSource<PackageSizeInformation>();
384             Interop.PackageManager.PackageManagerTotalSizeInfoCallback cb = (handle, userData) =>
385             {
386                 if (handle != IntPtr.Zero)
387                 {
388                     tcs.TrySetResult(PackageSizeInformation.GetPackageSizeInformation(handle));
389                 }
390             };
391
392             var err = Interop.PackageManager.PackageManagerGetTotalSizeInfo(cb, IntPtr.Zero);
393             if (err != Interop.PackageManager.ErrorCode.None)
394             {
395                 tcs.TrySetException(PackageManagerErrorFactory.GetException(err, "Failed to get total package size info"));
396             }
397             return await tcs.Task.ConfigureAwait(false);
398         }
399
400         /// <summary>
401         /// Installs the package located at the given path.
402         /// </summary>
403         /// <param name="packagePath">Absolute path for the package to be installed.</param>
404         /// <param name="installMode">Optional parameter to indicate special installation mode.</param>
405         /// <returns>Returns true if the installation request is successful, otherwise false.</returns>
406         /// <remarks>
407         /// The 'true' means that the request for installation is successful.
408         /// To check the result of the installation, the caller should check the progress using the InstallProgressChanged event.
409         /// </remarks>
410         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
411         /// <privlevel>platform</privlevel>
412         /// <since_tizen> 3 </since_tizen>
413         public static bool Install(string packagePath, InstallationMode installMode = InstallationMode.Normal)
414         {
415             return Install(packagePath, null, PackageType.UNKNOWN, null, installMode);
416         }
417
418         /// <summary>
419         /// Installs the package located at the given path.
420         /// </summary>
421         /// <param name="packagePath">Absolute path for the package to be installed.</param>
422         /// <param name="eventCallback">The event callback will be invoked only for the current request.</param>
423         /// <param name="installMode">Optional parameter to indicate special installation mode.</param>
424         /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
425         /// <remarks>
426         /// The 'true' means that the request for installation is successful.
427         /// To check the result of installation, the caller should check the progress using the InstallProgressChanged event or eventCallback.
428         /// </remarks>
429         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
430         /// <privlevel>platform</privlevel>
431         /// <since_tizen> 3 </since_tizen>
432         public static bool Install(string packagePath, RequestEventCallback eventCallback, InstallationMode installMode = InstallationMode.Normal)
433         {
434             return Install(packagePath, null, PackageType.UNKNOWN, eventCallback, installMode);
435         }
436
437         /// <summary>
438         /// Installs the package located at the given path.
439         /// </summary>
440         /// <param name="packagePath">Absolute path for the package to be installed.</param>
441         /// <param name="type">Package type for the package to be installed.</param>
442         /// <param name="installMode">Optional parameter to indicate special installation mode.</param>
443         /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
444         /// <remarks>
445         /// The 'true' means that the request for installation is successful.
446         /// To check the result of installation, the caller should check the progress using the InstallProgressChanged event.
447         /// </remarks>
448         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
449         /// <privlevel>platform</privlevel>
450         /// <since_tizen> 3 </since_tizen>
451         public static bool Install(string packagePath, PackageType type, InstallationMode installMode = InstallationMode.Normal)
452         {
453             return Install(packagePath, null, type, null, installMode);
454         }
455
456         /// <summary>
457         /// Installs the package located at the given path.
458         /// </summary>
459         /// <param name="packagePath">Absolute path for the package to be installed.</param>
460         /// <param name="expansionPackagePath">Absolute path for the expansion package to be installed.</param>
461         /// <param name="installMode">Optional parameter to indicate special installation mode.</param>
462         /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
463         /// <remarks>
464         /// The 'true' means that the request for installation is successful.
465         /// To check the result of installation, the caller should check the progress using the InstallProgressChanged event.
466         /// </remarks>
467         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
468         /// <privlevel>platform</privlevel>
469         /// <since_tizen> 3 </since_tizen>
470         public static bool Install(string packagePath, string expansionPackagePath, InstallationMode installMode = InstallationMode.Normal)
471         {
472             return Install(packagePath, expansionPackagePath, PackageType.UNKNOWN, null, installMode);
473         }
474
475         /// <summary>
476         /// Installs the package located at the given path.
477         /// </summary>
478         /// <param name="packagePath">Absolute path for the package to be installed.</param>
479         /// <param name="type">Package type for the package to be installed.</param>
480         /// <param name="eventCallback">The event callback will be invoked only for the current request.</param>
481         /// <param name="installMode">Optional parameter to indicate special installation mode.</param>
482         /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
483         /// <remarks>
484         /// The 'true' means that the request for installation is successful.
485         /// To check the result of installation, the caller should check the progress using the InstallProgressChanged event or eventCallback.
486         /// </remarks>
487         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
488         /// <privlevel>platform</privlevel>
489         /// <since_tizen> 3 </since_tizen>
490         public static bool Install(string packagePath, PackageType type, RequestEventCallback eventCallback, InstallationMode installMode = InstallationMode.Normal)
491         {
492             return Install(packagePath, null, type, eventCallback, installMode);
493         }
494
495         /// <summary>
496         /// Installs the package located at the given path.
497         /// </summary>
498         /// <param name="packagePath">Absolute path for the package to be installed.</param>
499         /// <param name="expansionPackagePath">Absolute path for the expansion package to be installed.</param>
500         /// <param name="eventCallback">The event callback will be invoked only for the current request.</param>
501         /// <param name="installMode">Optional parameter to indicate special installation mode.</param>
502         /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
503         /// <remarks>
504         /// The 'true' means that the request for installation is successful.
505         /// To check the result of installation, the caller should check the progress using the InstallProgressChanged event or eventCallback.
506         /// </remarks>
507         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
508         /// <privlevel>platform</privlevel>
509         /// <since_tizen> 3 </since_tizen>
510         public static bool Install(string packagePath, string expansionPackagePath, RequestEventCallback eventCallback, InstallationMode installMode = InstallationMode.Normal)
511         {
512             return Install(packagePath, expansionPackagePath, PackageType.UNKNOWN, eventCallback, installMode);
513         }
514
515         /// <summary>
516         /// Installs the package located at the given path.
517         /// </summary>
518         /// <param name="packagePath">Absolute path for the package to be installed.</param>
519         /// <param name="expansionPackagePath">Absolute path for the expansion package to be installed.</param>
520         /// <param name="type">Package type for the package to be installed.</param>
521         /// <param name="installMode">Optional parameter to indicate special installation mode.</param>
522         /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
523         /// <remarks>
524         /// The 'true' means that the request for installation is successful.
525         /// To check the result of installation, the caller should check the progress using the InstallProgressChanged event.
526         /// </remarks>
527         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
528         /// <privlevel>platform</privlevel>
529         /// <since_tizen> 3 </since_tizen>
530         public static bool Install(string packagePath, string expansionPackagePath, PackageType type, InstallationMode installMode = InstallationMode.Normal)
531         {
532             return Install(packagePath, expansionPackagePath, type, null, installMode);
533         }
534
535         /// <summary>
536         /// Installs the package located at the given path.
537         /// </summary>
538         /// <param name="packagePath">Absolute path for the package to be installed.</param>
539         /// <param name="expansionPackagePath">Absolute path for the expansion package to be installed.</param>
540         /// <param name="type">Package type for the package to be installed.</param>
541         /// <param name="eventCallback">The event callback will be invoked only for the current request.</param>
542         /// <param name="installMode">Optional parameter to indicate special installation mode.</param>
543         /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
544         /// <remarks>
545         /// The 'true' means that the request for installation is successful.
546         /// To check the result of installation, the caller should check the progress using the InstallProgressChanged event or eventCallback.
547         /// </remarks>
548         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
549         /// <privlevel>platform</privlevel>
550         /// <since_tizen> 3 </since_tizen>
551         public static bool Install(string packagePath, string expansionPackagePath, PackageType type, RequestEventCallback eventCallback, InstallationMode installMode = InstallationMode.Normal)
552         {
553             SafePackageManagerRequestHandle RequestHandle;
554             var err = Interop.PackageManager.PackageManagerRequestCreate(out RequestHandle);
555             if (err != Interop.PackageManager.ErrorCode.None)
556             {
557                 Log.Warn(LogTag, string.Format("Failed to install package {0}. Error in creating package manager request handle. err = {1}", packagePath, err));
558                 return false;
559             }
560
561             try
562             {
563                 if (type != PackageType.UNKNOWN)
564                 {
565                     err = Interop.PackageManager.PackageManagerRequestSetType(RequestHandle, type.ToString().ToLower());
566                     if (err != Interop.PackageManager.ErrorCode.None)
567                     {
568                         Log.Warn(LogTag, string.Format("Failed to install package {0}. Error in setting request package type. err = {1}", packagePath, err));
569                         RequestHandle.Dispose();
570                         return false;
571                     }
572                 }
573
574                 if (!string.IsNullOrEmpty(expansionPackagePath))
575                 {
576                     err = Interop.PackageManager.PackageManagerRequestSetTepPath(RequestHandle, expansionPackagePath);
577                     if (err != Interop.PackageManager.ErrorCode.None)
578                     {
579                         Log.Warn(LogTag, string.Format("Failed to install package {0}. Error in setting request package mode. err = {1}", packagePath, err));
580                         RequestHandle.Dispose();
581                         return false;
582                     }
583                 }
584
585                 int requestId;
586                 if (eventCallback != null)
587                 {
588                     InstallMethodWithCallback install;
589                     if (installMode == InstallationMode.Mount)
590                     {
591                         install = Interop.PackageManager.PackageManagerRequestMountInstallWithCB;
592                     }
593                     else
594                     {
595                         install = Interop.PackageManager.PackageManagerRequestInstallWithCB;
596                     }
597                     err = install(RequestHandle, packagePath, internalRequestEventCallback, IntPtr.Zero, out requestId);
598                     if (err == Interop.PackageManager.ErrorCode.None)
599                     {
600                         RequestCallbacks.Add(requestId, eventCallback);
601                         RequestHandles.Add(requestId, RequestHandle);
602                     }
603                     else
604                     {
605                         Log.Warn(LogTag, string.Format("Failed to install package {0}. err = {1}", packagePath, err));
606                         RequestHandle.Dispose();
607                         return false;
608                     }
609                 }
610                 else
611                 {
612                     InstallMethod install;
613                     if (installMode == InstallationMode.Mount)
614                     {
615                         install = Interop.PackageManager.PackageManagerRequestMountInstall;
616                     }
617                     else
618                     {
619                         install = Interop.PackageManager.PackageManagerRequestInstall;
620                     }
621                     err = install(RequestHandle, packagePath, out requestId);
622                     if (err != Interop.PackageManager.ErrorCode.None)
623                     {
624                         Log.Warn(LogTag, string.Format("Failed to install package {0}. err = {1}", packagePath, err));
625                         RequestHandle.Dispose();
626                         return false;
627                     }
628                     // RequestHandle isn't necessary when this method is called without 'eventCallback' parameter.
629                     RequestHandle.Dispose();
630                 }
631                 return true;
632             }
633             catch (Exception e)
634             {
635                 Log.Warn(LogTag, e.Message);
636                 RequestHandle.Dispose();
637                 return false;
638             }
639         }
640
641         /// <summary>
642         /// Uninstalls the package with the given name.
643         /// </summary>
644         /// <param name="packageId">ID of the package to be uninstalled.</param>
645         /// <returns>Returns true if the uninstallation request is successful, false otherwise.</returns>
646         /// <remarks>
647         /// The 'true' means that the request for uninstallation is successful.
648         /// To check the result of uninstallation, the caller should check the progress using the UninstallProgressChanged event.
649         /// </remarks>
650         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
651         /// <privlevel>platform</privlevel>
652         /// <since_tizen> 3 </since_tizen>
653         public static bool Uninstall(string packageId)
654         {
655             return Uninstall(packageId, PackageType.UNKNOWN, null);
656         }
657
658         /// <summary>
659         /// Uninstalls package with the given names.
660         /// </summary>
661         /// <param name="packageId">ID of the package to be uninstalled.</param>
662         /// <param name="type">Optional - Package type for the package to be uninstalled.</param>
663         /// <returns>Returns true if the uninstalltion request is successful, false otherwise.</returns>
664         /// <remarks>
665         /// The 'true' means that the request for uninstallation is successful.
666         /// To check the result of uninstallation, the caller should check the progress using the UninstallProgressChanged event.
667         /// </remarks>
668         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
669         /// <privlevel>platform</privlevel>
670         /// <since_tizen> 3 </since_tizen>
671         public static bool Uninstall(string packageId, PackageType type)
672         {
673             return Uninstall(packageId, type, null);
674         }
675
676         /// <summary>
677         /// Uninstalls the package with the given name.
678         /// </summary>
679         /// <param name="packageId">ID of the package to be uninstalled.</param>
680         /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request.</param>
681         /// <returns>Returns true if the uninstallation request is successful, false otherwise.</returns>
682         /// <remarks>
683         /// The 'true' means that the request for uninstallation is successful.
684         /// To check the result of uninstallation, the caller should check the progress using the UninstallProgressChanged event or eventCallback.
685         /// </remarks>
686         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
687         /// <privlevel>platform</privlevel>
688         /// <since_tizen> 3 </since_tizen>
689         public static bool Uninstall(string packageId, RequestEventCallback eventCallback)
690         {
691             return Uninstall(packageId, PackageType.UNKNOWN, eventCallback);
692         }
693
694         /// <summary>
695         /// Uninstalls the package with the given name.
696         /// </summary>
697         /// <param name="packageId">ID of the package to be uninstalled</param>
698         /// <param name="type">Optional - Package type for the package to be uninstalled.</param>
699         /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request.</param>
700         /// <returns>Returns true if the uninstallation request is successful, false otherwise.</returns>
701         /// <remarks>
702         /// The 'true' means that the request for uninstallation is successful.
703         /// To check the result of uninstallation, the caller should check the progress using the UninstallProgressChanged event or eventCallback.
704         /// </remarks>
705         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
706         /// <privlevel>platform</privlevel>
707         /// <since_tizen> 3 </since_tizen>
708         public static bool Uninstall(string packageId, PackageType type, RequestEventCallback eventCallback)
709         {
710             SafePackageManagerRequestHandle RequestHandle;
711             var err = Interop.PackageManager.PackageManagerRequestCreate(out RequestHandle);
712             if (err != Interop.PackageManager.ErrorCode.None)
713             {
714                 Log.Warn(LogTag, string.Format("Failed to uninstall package {0}. Error in creating package manager request handle. err = {1}", packageId, err));
715                 return false;
716             }
717
718             try
719             {
720                 err = Interop.PackageManager.PackageManagerRequestSetType(RequestHandle, type.ToString().ToLower());
721                 if (err != Interop.PackageManager.ErrorCode.None)
722                 {
723                     Log.Warn(LogTag, string.Format("Failed to uninstall package {0}. Error in setting request package type. err = {1}", packageId, err));
724                     RequestHandle.Dispose();
725                     return false;
726                 }
727
728                 int requestId;
729                 if (eventCallback != null)
730                 {
731                     err = Interop.PackageManager.PackageManagerRequestUninstallWithCB(RequestHandle, packageId, internalRequestEventCallback, IntPtr.Zero, out requestId);
732                     if (err == Interop.PackageManager.ErrorCode.None)
733                     {
734                         RequestCallbacks.Add(requestId, eventCallback);
735                         RequestHandles.Add(requestId, RequestHandle);
736                     }
737                     else
738                     {
739                         Log.Warn(LogTag, string.Format("Failed to uninstall package {0}. err = {1}", packageId, err));
740                         RequestHandle.Dispose();
741                         return false;
742                     }
743                 }
744                 else
745                 {
746                     err = Interop.PackageManager.PackageManagerRequestUninstall(RequestHandle, packageId, out requestId);
747                     if (err != Interop.PackageManager.ErrorCode.None)
748                     {
749                         Log.Warn(LogTag, string.Format("Failed to uninstall package. err = {0}", err));
750                         RequestHandle.Dispose();
751                         return false;
752                     }
753                     // RequestHandle isn't necessary when this method is called without 'eventCallback' parameter.
754                     RequestHandle.Dispose();
755                 }
756                 return true;
757             }
758             catch (Exception e)
759             {
760                 Log.Warn(LogTag, e.Message);
761                 RequestHandle.Dispose();
762                 return false;
763             }
764         }
765
766         /// <summary>
767         /// Moves the package to the given storage.
768         /// </summary>
769         /// <param name="packageId">ID of the package to be moved.</param>
770         /// <param name="newStorage">Storage package should be moved to.</param>
771         /// <returns>Returns true if the move request is successful, false otherwise.</returns>
772         /// <remarks>
773         /// The 'true' means that the request for move is successful.
774         /// To check the result of move, the caller should check the progress using the MoveProgressChanged event.
775         /// </remarks>
776         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
777         /// <privlevel>platform</privlevel>
778         /// <since_tizen> 3 </since_tizen>
779         public static bool Move(string packageId, StorageType newStorage)
780         {
781             return Move(packageId, PackageType.UNKNOWN, newStorage, null);
782         }
783
784         /// <summary>
785         /// Moves the package to the given storage.
786         /// </summary>
787         /// <param name="packageId">ID of the package to be moved.</param>
788         /// <param name="type">Optional - Package type for the package to be moved.</param>
789         /// <param name="newStorage">Storage package should be moved to.</param>
790         /// <returns>Returns true if the move request is successful, false otherwise.</returns>
791         /// <remarks>
792         /// The 'true' means that the request for move is successful.
793         /// To check the result of move, the caller should check the progress using the MoveProgressChanged event.
794         /// </remarks>
795         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
796         /// <privlevel>platform</privlevel>
797         /// <since_tizen> 3 </since_tizen>
798         public static bool Move(string packageId, PackageType type, StorageType newStorage)
799         {
800             return Move(packageId, type, newStorage, null);
801         }
802
803         /// <summary>
804         /// Moves the package to the given storage.
805         /// </summary>
806         /// <param name="packageId">ID of the package to be moved.</param>
807         /// <param name="newStorage">Storage package should be moved to.</param>
808         /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request.</param>
809         /// <returns>Returns true if move request is successful, false otherwise.</returns>
810         /// <remarks>
811         /// The 'true' means that the request for move is successful.
812         /// To check the result of move, the caller should check the progress using the MoveProgressChanged event.
813         /// </remarks>
814         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
815         /// <privlevel>platform</privlevel>
816         /// <since_tizen> 3 </since_tizen>
817         public static bool Move(string packageId, StorageType newStorage, RequestEventCallback eventCallback)
818         {
819             return Move(packageId, PackageType.UNKNOWN, newStorage, eventCallback);
820         }
821
822         /// <summary>
823         /// Moves the package to the given storage.
824         /// </summary>
825         /// <param name="packageId">ID of the package to be moved.</param>
826         /// <param name="type">Optional - Package type for the package to be moved.</param>
827         /// <param name="newStorage">Storage, package should be moved to.</param>
828         /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request.</param>
829         /// <returns>Returns true if move request is successful, false otherwise.</returns>
830         /// <remarks>
831         /// The 'true' means that the request for move is successful.
832         /// To check the result of move, the caller should check the progress using the MoveProgressChanged event.
833         /// </remarks>
834         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
835         /// <privlevel>platform</privlevel>
836         /// <since_tizen> 3 </since_tizen>
837         public static bool Move(string packageId, PackageType type, StorageType newStorage, RequestEventCallback eventCallback)
838         {
839             SafePackageManagerRequestHandle RequestHandle;
840             var err = Interop.PackageManager.PackageManagerRequestCreate(out RequestHandle);
841             if (err != Interop.PackageManager.ErrorCode.None)
842             {
843                 Log.Warn(LogTag, string.Format("Failed to create package manager request handle. err = {0}", err));
844                 return false;
845             }
846
847             try
848             {
849                 bool result = true;
850                 err = Interop.PackageManager.PackageManagerRequestSetType(RequestHandle, type.ToString().ToLower());
851                 if (err != Interop.PackageManager.ErrorCode.None)
852                 {
853                     Log.Warn(LogTag, string.Format("Failed to move package. Error in setting request package type. err = {0}", err));
854                     RequestHandle.Dispose();
855                     return false;
856                 }
857
858                 if (eventCallback != null)
859                 {
860                     int requestId;
861                     err = Interop.PackageManager.PackageManagerRequestMoveWithCB(RequestHandle, packageId, (Interop.PackageManager.StorageType)newStorage, internalRequestEventCallback, IntPtr.Zero, out requestId);
862                     if (err == Interop.PackageManager.ErrorCode.None)
863                     {
864                         RequestCallbacks.Add(requestId, eventCallback);
865                         RequestHandles.Add(requestId, RequestHandle);
866                     }
867                     else
868                     {
869                         Log.Warn(LogTag, string.Format("Failed to move package to requested location. err = {0}", err));
870                         RequestHandle.Dispose();
871                         result = false;
872                     }
873                 }
874                 else
875                 {
876                     err = Interop.PackageManager.PackageManagerRequestMove(RequestHandle, packageId, (Interop.PackageManager.StorageType)newStorage);
877                     if (err != Interop.PackageManager.ErrorCode.None)
878                     {
879                         Log.Warn(LogTag, string.Format("Failed to move package to requested location. err = {0}", err));
880                         RequestHandle.Dispose();
881                         result = false;
882                     }
883                     // RequestHandle isn't necessary when this method is called without 'eventCallback' parameter.
884                     RequestHandle.Dispose();
885                 }
886                 return result;
887             }
888             catch (Exception e)
889             {
890                 Log.Warn(LogTag, e.Message);
891                 RequestHandle.Dispose();
892                 return false;
893             }
894         }
895
896         /// <summary>
897         /// Gets the permission type of the package which has a given application ID.
898         /// </summary>
899         /// <param name="applicationId">ID of the application.</param>
900         /// <returns>Returns the permission type.</returns>
901         /// <privilege>http://tizen.org/privilege/packagemanager.info</privilege>
902         /// <exception cref="ArgumentException">Thrown when the failed input package ID is invalid.</exception>
903         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception>
904         /// <since_tizen> 3 </since_tizen>
905         public static PermissionType GetPermissionTypeByApplicationId(string applicationId)
906         {
907             Interop.PackageManager.PackageManagerPermissionType permissionType;
908             Interop.PackageManager.ErrorCode err = Interop.PackageManager.PackageManagerGetPermissionType(applicationId, out permissionType);
909             if (err != Interop.PackageManager.ErrorCode.None)
910             {
911                 throw PackageManagerErrorFactory.GetException(err, "Failed to get permission type.");
912             }
913
914             return (PermissionType)permissionType;
915         }
916
917         /// <summary>
918         /// Gets the package's preload attribute which contains a given application ID.
919         /// </summary>
920         /// <param name="applicationId">ID of the application.</param>
921         /// <returns>Returns true if the package is preloaded, otherwise false.</returns>
922         /// <privilege>http://tizen.org/privilege/packagemanager.info</privilege>
923         /// <exception cref="ArgumentException">Thrown when the failed input package ID is invalid.</exception>
924         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception>
925         /// <since_tizen> 3 </since_tizen>
926         public static bool IsPreloadPackageByApplicationId(string applicationId)
927         {
928             bool isPreloadPackage;
929             Interop.PackageManager.ErrorCode err = Interop.PackageManager.PackageManagerIsPreloadPackageByApplicationId(applicationId, out isPreloadPackage);
930             if (err != Interop.PackageManager.ErrorCode.None)
931             {
932                 throw PackageManagerErrorFactory.GetException(err, "Failed to get preload info");
933             }
934
935             return isPreloadPackage;
936         }
937
938         /// <summary>
939         /// Compares the certificate of the two packages.
940         /// </summary>
941         /// <param name="lhsPackageId">Package ID to compare.</param>
942         /// <param name="rhsPackageId">Package ID to be compared.</param>
943         /// <returns>Returns certificate comparison result.</returns>
944         /// <exception cref="ArgumentException">Thrown when the failed input package ID is invalid.</exception>
945         /// <exception cref="System.IO.IOException">Thrown when the method failed due to an internal I/O error.</exception>
946         /// <since_tizen> 3 </since_tizen>
947         public static CertCompareResultType CompareCertInfo(string lhsPackageId, string rhsPackageId)
948         {
949             Interop.PackageManager.CertCompareResultType compareResult;
950             Interop.PackageManager.ErrorCode err = Interop.PackageManager.PackageManagerCompareCertInfo(lhsPackageId, rhsPackageId, out compareResult);
951             if (err != Interop.PackageManager.ErrorCode.None)
952             {
953                 throw PackageManagerErrorFactory.GetException(err, "Failed to compare cert info");
954             }
955
956             return (CertCompareResultType)compareResult;
957         }
958
959         /// <summary>
960         /// Compares the certificate of the two packages which contain each given application ID.
961         /// </summary>
962         /// <param name="lhsApplicationId">Application ID to compare.</param>
963         /// <param name="rhsApplicationId">Application ID to be compared.</param>
964         /// <returns>Returns certificate comparison result.</returns>
965         /// <exception cref="ArgumentException">Thrown when the failed input package ID is invalid.</exception>
966         /// <exception cref="System.IO.IOException">Thrown when the method failed due to an internal I/O error.</exception>
967         /// <since_tizen> 3 </since_tizen>
968         public static CertCompareResultType CompareCertInfoByApplicationId(string lhsApplicationId, string rhsApplicationId)
969         {
970             Interop.PackageManager.CertCompareResultType compareResult;
971             Interop.PackageManager.ErrorCode err = Interop.PackageManager.PackageManagerCompareCertInfoByApplicationId(lhsApplicationId, rhsApplicationId, out compareResult);
972             if (err != Interop.PackageManager.ErrorCode.None)
973             {
974                 throw PackageManagerErrorFactory.GetException(err, "Failed to compare cert info by application id");
975             }
976
977             return (CertCompareResultType)compareResult;
978         }
979
980         /// <summary>
981         /// Drm nested class. This class has the PackageManager's drm related methods.
982         /// </summary>
983         /// <since_tizen> 3 </since_tizen>
984         public static class Drm
985         {
986             /// <summary>
987             /// Generates a request for getting the license.
988             /// </summary>
989             /// <param name="responseData">Response data string of the purchase request.</param>
990             /// <returns>Returns the package DRM information of a given response data which contains the required data and license URL.</returns>
991             /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
992             /// <privlevel>platform</privlevel>
993             /// <exception cref="ArgumentException">Thrown when failed when input package ID is invalid.</exception>
994             /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory to continue the execution of the method.</exception>
995             /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception>
996             /// <exception cref="SystemException">Thrown when the method failed due to an internal system error.</exception>
997             /// <since_tizen> 3 </since_tizen>
998             public static PackageDrm GenerateLicenseRequest(string responseData)
999             {
1000                 return PackageDrm.GenerateLicenseRequest(responseData);
1001
1002             }
1003
1004             /// <summary>
1005             /// Registers the encrypted license.
1006             /// </summary>
1007             /// <param name="responseData">The response data string of the rights request.</param>
1008             /// <returns>Returns true if succeeds, otherwise false.</returns>
1009             /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
1010             /// <privlevel>platform</privlevel>
1011             /// <exception cref="ArgumentException">Thrown when failed when input package ID is invalid.</exception>
1012             /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory to continue the execution of the method.</exception>
1013             /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception>
1014             /// <exception cref="SystemException">Thrown when the method failed due to internal system error.</exception>
1015             /// <since_tizen> 3 </since_tizen>
1016             public static bool RegisterLicense(string responseData)
1017             {
1018                 Interop.PackageManager.ErrorCode err = Interop.PackageManager.PackageManagerDrmRegisterLicense(responseData);
1019                 if (err != Interop.PackageManager.ErrorCode.None)
1020                 {
1021                     throw PackageManagerErrorFactory.GetException(err, "Failed to register drm license");
1022                 }
1023
1024                 return true;
1025             }
1026
1027             /// <summary>
1028             /// Decrypts the contents which are encrypted.
1029             /// </summary>
1030             /// <param name="drmFilePath">Drm file path.</param>
1031             /// <param name="decryptedFilePath">Decrypted file path.</param>
1032             /// <returns>Returns true if succeeds, otherwise false.</returns>
1033             /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
1034             /// <privlevel>platform</privlevel>
1035             /// <exception cref="ArgumentException">Thrown when failed when input package ID is invalid.</exception>
1036             /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory to continue the execution of the method.</exception>
1037             /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception>
1038             /// <exception cref="SystemException">Thrown when the method failed due to an internal system error.</exception>
1039             /// <since_tizen> 3 </since_tizen>
1040             public static bool DecryptPackage(string drmFilePath, string decryptedFilePath)
1041             {
1042                 Interop.PackageManager.ErrorCode err = Interop.PackageManager.PackageManagerDrmDecryptPackage(drmFilePath, decryptedFilePath);
1043                 if (err != Interop.PackageManager.ErrorCode.None)
1044                 {
1045                     throw PackageManagerErrorFactory.GetException(err, "Failed to decrypt drm package");
1046                 }
1047
1048                 return true;
1049             }
1050         }
1051
1052         private static void SetPackageManagerEventStatus(Interop.PackageManager.EventStatus status)
1053         {
1054             if (Handle.IsInvalid) return;
1055
1056             Interop.PackageManager.EventStatus eventStatus = s_eventStatus;
1057             eventStatus |= status;
1058             if (eventStatus != Interop.PackageManager.EventStatus.All)
1059                 eventStatus |= Interop.PackageManager.EventStatus.Progress;
1060
1061             var err = Interop.PackageManager.ErrorCode.None;
1062             if (s_eventStatus != eventStatus)
1063             {
1064                 err = Interop.PackageManager.PackageManagerSetEvenStatus(Handle, eventStatus);
1065                 if (err == Interop.PackageManager.ErrorCode.None)
1066                 {
1067                     s_eventStatus = eventStatus;
1068                     Log.Debug(LogTag, string.Format("New Event Status flag: {0}", s_eventStatus));
1069                     return;
1070                 }
1071                 Log.Debug(LogTag, string.Format("Failed to set flag for {0} event. err = {1}", eventStatus, err));
1072             }
1073         }
1074
1075         private static void UnsetPackageManagerEventStatus()
1076         {
1077             if (Handle.IsInvalid) return;
1078
1079             Interop.PackageManager.EventStatus eventStatus = Interop.PackageManager.EventStatus.All;
1080             if (s_installEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.Install;
1081             if (s_uninstallEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.Uninstall;
1082             if (s_updateEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.Upgrade;
1083             if (s_moveEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.Move;
1084             if (s_clearDataEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.ClearData;
1085             if (eventStatus != Interop.PackageManager.EventStatus.All)
1086                 eventStatus |= Interop.PackageManager.EventStatus.Progress;
1087
1088             var err = Interop.PackageManager.ErrorCode.None;
1089             if (s_eventStatus != eventStatus)
1090             {
1091                 err = Interop.PackageManager.PackageManagerSetEvenStatus(Handle, eventStatus);
1092                 if (err == Interop.PackageManager.ErrorCode.None)
1093                 {
1094                     s_eventStatus = eventStatus;
1095                     Log.Debug(LogTag, string.Format("New Event Status flag: {0}", s_eventStatus));
1096                     return;
1097                 }
1098                 Log.Debug(LogTag, string.Format("Failed to set flag for {0} event. err = {1}", eventStatus, err));
1099             }
1100         }
1101
1102         private static void RegisterPackageManagerEventIfNeeded()
1103         {
1104             if (s_packageManagerEventCallback != null)
1105                 return;
1106
1107             var err = Interop.PackageManager.ErrorCode.None;
1108             s_packageManagerEventCallback = new Interop.PackageManager.PackageManagerEventCallback(InternalEventCallback);
1109
1110             if (!Handle.IsInvalid)
1111             {
1112                 Log.Debug(LogTag, "Reset Package Event");
1113                 err = Interop.PackageManager.PackageManagerUnsetEvent(Handle);
1114                 if (err != Interop.PackageManager.ErrorCode.None)
1115                 {
1116                     throw PackageManagerErrorFactory.GetException(err, "Failed to unregister package manager event event.");
1117                 }
1118
1119                 err = Interop.PackageManager.PackageManagerSetEvent(Handle, s_packageManagerEventCallback, IntPtr.Zero);
1120             }
1121             if (err != Interop.PackageManager.ErrorCode.None)
1122             {
1123                 Log.Warn(LogTag, string.Format("Failed to register callback for package manager event. err = {0}", err));
1124             }
1125         }
1126
1127         private static void InternalEventCallback(string packageType, string packageId, Interop.PackageManager.EventType eventType, Interop.PackageManager.PackageEventState eventState, int progress, Interop.PackageManager.ErrorCode error, IntPtr user_data)
1128         {
1129             try
1130             {
1131                 if (eventType == Interop.PackageManager.EventType.Install)
1132                 {
1133                     s_installEventHandler?.Invoke(null, new PackageManagerEventArgs(packageType, packageId, (PackageEventState)eventState, progress));
1134                 }
1135                 else if (eventType == Interop.PackageManager.EventType.Uninstall)
1136                 {
1137                     s_uninstallEventHandler?.Invoke(null, new PackageManagerEventArgs(packageType, packageId, (PackageEventState)eventState, progress));
1138                 }
1139                 else if (eventType == Interop.PackageManager.EventType.Update)
1140                 {
1141                     s_updateEventHandler?.Invoke(null, new PackageManagerEventArgs(packageType, packageId, (PackageEventState)eventState, progress));
1142                 }
1143                 else if (eventType == Interop.PackageManager.EventType.Move)
1144                 {
1145                     s_moveEventHandler?.Invoke(null, new PackageManagerEventArgs(packageType, packageId, (PackageEventState)eventState, progress));
1146                 }
1147                 else if (eventType == Interop.PackageManager.EventType.ClearData)
1148                 {
1149                     s_clearDataEventHandler?.Invoke(null, new PackageManagerEventArgs(packageType, packageId, (PackageEventState)eventState, progress));
1150                 }
1151             }
1152             catch (Exception e)
1153             {
1154                 Log.Warn(LogTag, e.Message);
1155             }
1156         }
1157
1158         private static void UnregisterPackageManagerEventIfNeeded()
1159         {
1160             if (Handle.IsInvalid || s_packageManagerEventCallback == null || s_installEventHandler != null || s_uninstallEventHandler != null || s_updateEventHandler != null || s_moveEventHandler != null || s_clearDataEventHandler != null)
1161             {
1162                 return;
1163             }
1164
1165             s_packageManagerEventCallback = null;
1166
1167             var err = Interop.PackageManager.PackageManagerUnsetEvent(Handle);
1168             if (err != Interop.PackageManager.ErrorCode.None)
1169             {
1170                 throw PackageManagerErrorFactory.GetException(err, "Failed to unregister package manager event event.");
1171             }
1172         }
1173     }
1174
1175     internal static class PackageManagerErrorFactory
1176     {
1177         internal static Exception GetException(Interop.PackageManager.ErrorCode err, string message)
1178         {
1179             string errMessage = string.Format("{0} err = {1}", message, err);
1180             switch (err)
1181             {
1182                 case Interop.PackageManager.ErrorCode.InvalidParameter:
1183                 case Interop.PackageManager.ErrorCode.NoSuchPackage:
1184                     return new ArgumentException(errMessage);
1185                 case Interop.PackageManager.ErrorCode.PermissionDenied:
1186                     return new UnauthorizedAccessException(errMessage);
1187                 case Interop.PackageManager.ErrorCode.IoError:
1188                     return new global::System.IO.IOException(errMessage);
1189                 default:
1190                     return new InvalidOperationException(errMessage);
1191             }
1192         }
1193     }
1194 }