Add missing API and fix wrong behavior
authorjongmyeongko <jongmyeong.ko@samsung.com>
Wed, 15 Feb 2017 12:55:03 +0000 (21:55 +0900)
committerjongmyeong ko <jongmyeong.ko@samsung.com>
Fri, 17 Mar 2017 00:55:48 +0000 (17:55 -0700)
1. Add request-callback feature
Usage)
PackageManager.Install(packagePath, MyCallback1);
PackageManager.Install(packagePath, tepPath, MyCallback1);
PackageManager.Install(packagePath, tepPath, pkgType, MyCallback1);
...
PackageManager.Move(packageID, PackageType.TPK, StorageType.External, MyCallbackMove1);
PackageManager.Move(packageID, PackageType.TPK, StorageType.Internal, MyCallbackMove2);
PackageManager.Uninstall(packageID, PackageType.TPK, MyCallback2);
...

2. Add Move, ClearData event
usage)
private static EventHandler<PackageManagerEventArgs> PackageEventCallback;
PackageEventCallback = (s, e) => { Log.Debug(TAG, "callback called"); };
// set cb
PackageManger.MoveProgressChanged += PackageEventCallback;
PackageManger.ClearDataProgressChanged += PackageEventCallback;
// unset cb
PackageManger.MoveProgressChanged -= PackageEventCallback;
PackageManger.ClearDataProgressChanged -= PackageEventCallback;

3. Fix wrong behavior of package-event handling.

Requires:
https://review.tizen.org/gerrit/#/c/116315/
https://review.tizen.org/gerrit/#/c/117332/

Change-Id: I31fa3eb35e7e56599e794221cd0e0120b297fb21
Signed-off-by: jongmyeongko <jongmyeong.ko@samsung.com>
Tizen.Applications/Tizen.Applications.csproj
src/Tizen.Applications.PackageManager/Interop/Interop.PackageManager.cs
src/Tizen.Applications.PackageManager/Tizen.Applications.PackageManager.csproj
src/Tizen.Applications.PackageManager/Tizen.Applications/PackageEventType.cs [new file with mode: 0755]
src/Tizen.Applications.PackageManager/Tizen.Applications/PackageManager.cs
src/Tizen.Applications.PackageManager/Tizen.Applications/PackageType.cs
src/Tizen.Applications.PackageManager/Tizen.Applications/SafePackageManagerRequestHandle.cs [new file with mode: 0755]
src/Tizen.Applications.UI/Tizen.Applications.UI.csproj

index 62b1fba..48adeff 100755 (executable)
     <Compile Include="../Tizen.Applications.PackageManager/Tizen.Applications/Package.cs" />
     <Compile Include="../Tizen.Applications.PackageManager/Tizen.Applications/PackageCertificate.cs" />
     <Compile Include="../Tizen.Applications.PackageManager/Tizen.Applications/PackageEventState.cs" />
+    <Compile Include="../Tizen.Applications.PackageManager/Tizen.Applications/PackageEventType.cs" />
     <Compile Include="../Tizen.Applications.PackageManager/Tizen.Applications/PackageFilter.cs" />
     <Compile Include="../Tizen.Applications.PackageManager/Tizen.Applications/PackageManager.cs" />
     <Compile Include="../Tizen.Applications.PackageManager/Tizen.Applications/PackageManagerEventArgs.cs" />
     <Compile Include="../Tizen.Applications.Common/Tizen.Applications/SafeAppControlHandle.cs" />
     <Compile Include="../Tizen.Applications.Common/Tizen.Applications/SafeBundleHandle.cs" />
     <Compile Include="../Tizen.Applications.PackageManager/Tizen.Applications/SafePackageManagerHandle.cs" />
+    <Compile Include="../Tizen.Applications.PackageManager/Tizen.Applications/SafePackageManagerRequestHandle.cs" />
     <Compile Include="../Tizen.Applications.Service/Tizen.Applications/ServiceApplication.cs" />
     <Compile Include="../Tizen.Applications.Service/Tizen.Applications.CoreBackend/ServiceCoreBackend.cs" />
     <Compile Include="../Tizen.Applications.PackageManager/Tizen.Applications/StorageType.cs" />
index 5d726c8..e8fac2d 100644 (file)
@@ -34,6 +34,9 @@ internal static partial class Interop
         [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
         internal delegate void PackageManagerTotalSizeInfoCallback(IntPtr sizeInfoHandle, IntPtr userData);
 
+        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
+        internal delegate void PackageManagerRequestEventCallback(int requestId, string type, string packageId, EventType eventType, PackageEventState eventState, int progress, ErrorCode error, IntPtr userData);
+
         // Any change here might require changes in Tizen.Applications.PackageManagerEventError enum
         internal enum ErrorCode
         {
@@ -60,15 +63,20 @@ internal static partial class Interop
         {
             All = 0x00,
             Install = 0x01,
-            Unstall = 0x02,
-            Upgrade = 0x24,
+            Uninstall = 0x02,
+            Upgrade = 0x04,
+            Move = 0x08,
+            ClearData = 0x10,
+            Progress = 0x20,
         }
 
         internal enum EventType
         {
             Install = 0,
             Uninstall = 1,
-            Update = 2
+            Update = 2,
+            Move = 3,
+            ClearData = 4
         }
 
         internal enum CertCompareResultType
@@ -164,25 +172,25 @@ internal static partial class Interop
         internal static extern ErrorCode PackageSizeInfoGetExtAppSize(IntPtr handle, out long extAppSize);
 
         [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_request_create")]
-        internal static extern ErrorCode PackageManagerRequestCreate(out IntPtr request);
+        internal static extern ErrorCode PackageManagerRequestCreate(out SafePackageManagerRequestHandle requestHandle);
 
         [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_request_destroy")]
-        internal static extern ErrorCode PackageManagerRequestDestroy(IntPtr request);
+        internal static extern ErrorCode PackageManagerRequestDestroy(IntPtr requestHandle);
 
         [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_request_set_type")]
-        internal static extern ErrorCode PackageManagerRequestSetType(IntPtr request, string type);
+        internal static extern ErrorCode PackageManagerRequestSetType(SafePackageManagerRequestHandle requestHandle, string type);
 
         [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_request_set_tep")]
-        internal static extern ErrorCode PackageManagerRequestSetTepPath(IntPtr request, string tepPath);
+        internal static extern ErrorCode PackageManagerRequestSetTepPath(SafePackageManagerRequestHandle requestHandle, string tepPath);
 
         [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_request_install")]
-        internal static extern ErrorCode PackageManagerRequestInstall(IntPtr request, string path, out int id);
+        internal static extern ErrorCode PackageManagerRequestInstall(SafePackageManagerRequestHandle requestHandle, string path, out int id);
 
         [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_request_uninstall")]
-        internal static extern ErrorCode PackageManagerRequestUninstall(IntPtr request, string name, out int id);
+        internal static extern ErrorCode PackageManagerRequestUninstall(SafePackageManagerRequestHandle requestHandle, string name, out int id);
 
         [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_request_move")]
-        internal static extern ErrorCode PackageManagerRequestMove(IntPtr request, string name, StorageType moveToStorageType);
+        internal static extern ErrorCode PackageManagerRequestMove(SafePackageManagerRequestHandle requestHandle, string name, StorageType moveToStorageType);
 
         [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_compare_package_cert_info")]
         internal static extern ErrorCode PackageManagerCompareCertInfo(string lhsPackageId, string rhsPackageId, out CertCompareResultType CompareResult);
@@ -204,5 +212,14 @@ internal static partial class Interop
 
         [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_drm_decrypt_package")]
         internal static extern ErrorCode PackageManagerDrmDecryptPackage(string drmFilePath, string decryptedFilePath);
+
+        [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_request_install_with_cb")]
+        internal static extern ErrorCode PackageManagerRequestInstallWithCB(SafePackageManagerRequestHandle requestHandle, string path, PackageManagerRequestEventCallback callback, IntPtr userData, out int id);
+
+        [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_request_uninstall_with_cb")]
+        internal static extern ErrorCode PackageManagerRequestUninstallWithCB(SafePackageManagerRequestHandle requestHandle, string name, PackageManagerRequestEventCallback callback, IntPtr userData, out int id);
+
+        [DllImport(Libraries.PackageManager, EntryPoint = "package_manager_request_move_with_cb")]
+        internal static extern ErrorCode PackageManagerRequestMoveWithCB(SafePackageManagerRequestHandle requestHandle, string name, StorageType moveToStorageType, PackageManagerRequestEventCallback callback, IntPtr userData, out int id);
     }
 }
index 4fa2cb5..826da96 100644 (file)
@@ -55,6 +55,7 @@
     <Compile Include="Tizen.Applications\PackageEventState.cs" />
     <Compile Include="Tizen.Applications\Package.cs" />
     <Compile Include="Tizen.Applications\PackageCertificate.cs" />
+    <Compile Include="Tizen.Applications\PackageEventType.cs" />
     <Compile Include="Tizen.Applications\PackageFilter.cs" />
     <Compile Include="Tizen.Applications\PackageManager.cs" />
     <Compile Include="Tizen.Applications\PackageManagerEventArgs.cs" />
@@ -62,6 +63,7 @@
     <Compile Include="Tizen.Applications\PackageType.cs" />
     <Compile Include="Tizen.Applications\PermissionType.cs" />
     <Compile Include="Tizen.Applications\SafePackageManagerHandle.cs" />
+    <Compile Include="Tizen.Applications\SafePackageManagerRequestHandle.cs" />
     <Compile Include="Tizen.Applications\StorageType.cs" />
   </ItemGroup>
   <ItemGroup>
diff --git a/src/Tizen.Applications.PackageManager/Tizen.Applications/PackageEventType.cs b/src/Tizen.Applications.PackageManager/Tizen.Applications/PackageEventType.cs
new file mode 100755 (executable)
index 0000000..25b9d61
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Tizen.Applications
+{
+    /// <summary>
+    /// Enumeration for package manager event type.
+    /// </summary>
+    public enum PackageEventType
+    {
+        /// <summary>
+        /// Install event.
+        /// </summary>
+        Install = Interop.PackageManager.EventType.Install,
+        /// <summary>
+        /// Uninstall event.
+        /// </summary>
+        Uninstall = Interop.PackageManager.EventType.Uninstall,
+        /// <summary>
+        /// Update event.
+        /// </summary>
+        Update = Interop.PackageManager.EventType.Update
+    }
+}
index 6329204..738e3c3 100644 (file)
@@ -30,16 +30,22 @@ namespace Tizen.Applications
     /// </remarks>
     public static class PackageManager
     {
-        private const string LogTag = "Tizen.Applications";
-        private static SafePackageManagerHandle s_handle = new SafePackageManagerHandle();
+        private const string LogTag = "Tizen.Applications.PackageManager";
 
-        private static Interop.PackageManager.EventStatus s_eventStatus;
+        private static SafePackageManagerHandle s_handle = new SafePackageManagerHandle();
+        private static Interop.PackageManager.EventStatus s_eventStatus = Interop.PackageManager.EventStatus.All;
         private static event EventHandler<PackageManagerEventArgs> s_installEventHandler;
         private static event EventHandler<PackageManagerEventArgs> s_uninstallEventHandler;
         private static event EventHandler<PackageManagerEventArgs> s_updateEventHandler;
+        private static event EventHandler<PackageManagerEventArgs> s_moveEventHandler;
+        private static event EventHandler<PackageManagerEventArgs> s_clearDataEventHandler;
 
         private static Interop.PackageManager.PackageManagerEventCallback s_packageManagerEventCallback;
 
+        public delegate void RequestEventCallback(string type, string packageId, PackageEventType eventType, PackageEventState eventState, int progress);
+        private static Dictionary<int, RequestEventCallback> RequestCallbacks = new Dictionary<int, RequestEventCallback>();
+        private static Dictionary<int, SafePackageManagerRequestHandle> RequestHandles = new Dictionary<int, SafePackageManagerRequestHandle>();
+
         /// <summary>
         /// InstallProgressChanged event. This event is occurred when a package is getting installed and the progress of the request to the package manager changes.
         /// </summary>
@@ -47,7 +53,7 @@ namespace Tizen.Applications
         {
             add
             {
-                SetPackageManagerEventStatus();
+                SetPackageManagerEventStatus(Interop.PackageManager.EventStatus.Install);
                 RegisterPackageManagerEventIfNeeded();
                 s_installEventHandler += value;
             }
@@ -55,7 +61,7 @@ namespace Tizen.Applications
             {
                 s_installEventHandler -= value;
                 UnregisterPackageManagerEventIfNeeded();
-                SetPackageManagerEventStatus();
+                UnsetPackageManagerEventStatus();
             }
         }
 
@@ -66,7 +72,7 @@ namespace Tizen.Applications
         {
             add
             {
-                SetPackageManagerEventStatus();
+                SetPackageManagerEventStatus(Interop.PackageManager.EventStatus.Uninstall);
                 RegisterPackageManagerEventIfNeeded();
                 s_uninstallEventHandler += value;
             }
@@ -74,7 +80,7 @@ namespace Tizen.Applications
             {
                 s_uninstallEventHandler -= value;
                 UnregisterPackageManagerEventIfNeeded();
-                SetPackageManagerEventStatus();
+                UnsetPackageManagerEventStatus();
             }
         }
 
@@ -85,7 +91,7 @@ namespace Tizen.Applications
         {
             add
             {
-                SetPackageManagerEventStatus();
+                SetPackageManagerEventStatus(Interop.PackageManager.EventStatus.Upgrade);
                 RegisterPackageManagerEventIfNeeded();
                 s_updateEventHandler += value;
             }
@@ -93,7 +99,45 @@ namespace Tizen.Applications
             {
                 s_updateEventHandler -= value;
                 UnregisterPackageManagerEventIfNeeded();
-                SetPackageManagerEventStatus();
+                UnsetPackageManagerEventStatus();
+            }
+        }
+
+        /// <summary>
+        /// MoveProgressChanged event. This event is occurred when a package is getting moved and the progress of the request to the package manager changes.
+        /// </summary>
+        public static event EventHandler<PackageManagerEventArgs> MoveProgressChanged
+        {
+            add
+            {
+                SetPackageManagerEventStatus(Interop.PackageManager.EventStatus.Move);
+                RegisterPackageManagerEventIfNeeded();
+                s_moveEventHandler += value;
+            }
+            remove
+            {
+                s_moveEventHandler -= value;
+                UnregisterPackageManagerEventIfNeeded();
+                UnsetPackageManagerEventStatus();
+            }
+        }
+
+        /// <summary>
+        /// ClearDataProgressChanged event. This event is occurred when data directories are cleared in the given package.
+        /// </summary>
+        public static event EventHandler<PackageManagerEventArgs> ClearDataProgressChanged
+        {
+            add
+            {
+                SetPackageManagerEventStatus(Interop.PackageManager.EventStatus.ClearData);
+                RegisterPackageManagerEventIfNeeded();
+                s_clearDataEventHandler += value;
+            }
+            remove
+            {
+                s_clearDataEventHandler -= value;
+                UnregisterPackageManagerEventIfNeeded();
+                UnsetPackageManagerEventStatus();
             }
         }
 
@@ -113,6 +157,19 @@ namespace Tizen.Applications
             }
         }
 
+        private static Interop.PackageManager.PackageManagerRequestEventCallback internalRequestEventCallback = (id, packageType, packageId, eventType, eventState, progress, error, userData) =>
+        {
+            if (RequestCallbacks.ContainsKey(id))
+            {
+                RequestCallbacks[id](packageType, packageId, (PackageEventType)eventType, (PackageEventState)eventState, progress);
+                if (eventState == Interop.PackageManager.PackageEventState.Completed || eventState == Interop.PackageManager.PackageEventState.Failed)
+                {
+                    Log.Debug(LogTag, string.Format("release request handle for id : {0}", id));
+                    RequestHandles[id].Dispose();
+                }
+            }
+        };
+
         /// <summary>
         /// Gets the package ID for the given app ID.
         /// </summary>
@@ -303,11 +360,47 @@ namespace Tizen.Applications
         /// Installs package located at the given path
         /// </summary>
         /// <param name="packagePath">Absolute path for the package to be installed</param>
-        /// <returns>Returns true if installtion is successful, false otherwise.</returns>
+        /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of installation is seccessful.
+        /// To check the result of installation, the caller should check the progress using InstallProgressChanged event.
+        /// </remarks>
         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
         public static bool Install(string packagePath)
         {
-            return Install(packagePath, null);
+            return Install(packagePath, null, PackageType.UNKNOWN, null);
+        }
+
+        /// <summary>
+        /// Installs package located at the given path
+        /// </summary>
+        /// <param name="packagePath">Absolute path for the package to be installed</param>
+        /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request</param>
+        /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of installation is seccessful.
+        /// To check the result of installation, the caller should check the progress using InstallProgressChanged event OR eventCallback.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Install(string packagePath, RequestEventCallback eventCallback)
+        {
+            return Install(packagePath, null, PackageType.UNKNOWN, eventCallback);
+        }
+
+        /// <summary>
+        /// Installs package located at the given path
+        /// </summary>
+        /// <param name="packagePath">Absolute path for the package to be installed</param>
+        /// <param name="type">Optional - Package type for the package to be installed</param>
+        /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of installation is seccessful.
+        /// To check the result of installation, the caller should check the progress using InstallProgressChanged event.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Install(string packagePath, PackageType type)
+        {
+            return Install(packagePath, null, type, null);
         }
 
         /// <summary>
@@ -315,23 +408,49 @@ namespace Tizen.Applications
         /// </summary>
         /// <param name="packagePath">Absolute path for the package to be installed</param>
         /// <param name="expansionPackagePath">Optional - Absolute path for the expansion package to be installed</param>
-        /// <returns>Returns true if installtion is successful, false otherwise.</returns>
+        /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of installation is seccessful.
+        /// To check the result of installation, the caller should check the progress using InstallProgressChanged event.
+        /// </remarks>
         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
         public static bool Install(string packagePath, string expansionPackagePath)
         {
-            PackageType type;
-            string extension = Path.GetExtension(packagePath);
+            return Install(packagePath, expansionPackagePath, PackageType.UNKNOWN, null);
+        }
 
-            if (extension.Contains("tpk"))
-            {
-                type = PackageType.TPK;
-            }
-            else
-            {
-                type = PackageType.WGT;
-            }
+        /// <summary>
+        /// Installs package located at the given path
+        /// </summary>
+        /// <param name="packagePath">Absolute path for the package to be installed</param>
+        /// <param name="type">Optional - Package type for the package to be installed</param>
+        /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request</param>
+        /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of installation is seccessful.
+        /// To check the result of installation, the caller should check the progress using InstallProgressChanged event OR eventCallback.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Install(string packagePath, PackageType type, RequestEventCallback eventCallback)
+        {
+            return Install(packagePath, null, type, eventCallback);
+        }
 
-            return Install(packagePath, expansionPackagePath, type);
+        /// <summary>
+        /// Installs package located at the given path
+        /// </summary>
+        /// <param name="packagePath">Absolute path for the package to be installed</param>
+        /// <param name="expansionPackagePath">Optional - Absolute path for the expansion package to be installed</param>
+        /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request</param>
+        /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of installation is seccessful.
+        /// To check the result of installation, the caller should check the progress using InstallProgressChanged event OR eventCallback.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Install(string packagePath, string expansionPackagePath, RequestEventCallback eventCallback)
+        {
+            return Install(packagePath, expansionPackagePath, PackageType.UNKNOWN, eventCallback);
         }
 
         /// <summary>
@@ -339,53 +458,90 @@ namespace Tizen.Applications
         /// </summary>
         /// <param name="packagePath">Absolute path for the package to be installed</param>
         /// <param name="expansionPackagePath">Optional - Absolute path for the expansion package to be installed</param>
-        /// <param name="type">Package type for the package to be installed</param>
-        /// <returns>Returns true if installtion is successful, false otherwise.</returns>
+        /// <param name="type">Optional - Package type for the package to be installed</param>
+        /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of installation is seccessful.
+        /// To check the result of installation, the caller should check the progress using InstallProgressChanged event.
+        /// </remarks>
         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
         public static bool Install(string packagePath, string expansionPackagePath, PackageType type)
         {
-            IntPtr requestHandle;
-            var err = Interop.PackageManager.PackageManagerRequestCreate(out requestHandle);
+            return Install(packagePath, expansionPackagePath, type, null);
+        }
+
+        /// <summary>
+        /// Installs package located at the given path
+        /// </summary>
+        /// <param name="packagePath">Absolute path for the package to be installed</param>
+        /// <param name="expansionPackagePath">Optional - Absolute path for the expansion package to be installed</param>
+        /// <param name="type">Optional - Package type for the package to be installed</param>
+        /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request</param>
+        /// <returns>Returns true if installtion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of installation is seccessful.
+        /// To check the result of installation, the caller should check the progress using InstallProgressChanged event OR eventCallback.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Install(string packagePath, string expansionPackagePath, PackageType type, RequestEventCallback eventCallback)
+        {
+            SafePackageManagerRequestHandle RequestHandle = new SafePackageManagerRequestHandle();
+            var err = Interop.PackageManager.PackageManagerRequestCreate(out RequestHandle);
             if (err != Interop.PackageManager.ErrorCode.None)
             {
-                Log.Warn(LogTag, string.Format("Failed to install package. Error in creating request handle. err = {0}", err));
+                Log.Warn(LogTag, string.Format("Failed to create package manager request handle. err = {0}", err));
                 return false;
             }
 
-            err = Interop.PackageManager.PackageManagerRequestSetType(requestHandle, type.ToString().ToLower());
-            if (err != Interop.PackageManager.ErrorCode.None)
+            if (type != PackageType.UNKNOWN)
             {
-                Log.Warn(LogTag, string.Format("Failed to install package. Error in setting request package type. err = {0}", err));
-                Interop.PackageManager.PackageManagerRequestDestroy(requestHandle);
-                return false;
+                err = Interop.PackageManager.PackageManagerRequestSetType(RequestHandle, type.ToString().ToLower());
+                if (err != Interop.PackageManager.ErrorCode.None)
+                {
+                    Log.Warn(LogTag, string.Format("Failed to install package. Error in setting request package type. err = {0}", err));
+                    RequestHandle.Dispose();
+                    return false;
+                }
             }
 
             if (!string.IsNullOrEmpty(expansionPackagePath))
             {
-                err = Interop.PackageManager.PackageManagerRequestSetTepPath(requestHandle, expansionPackagePath);
+                err = Interop.PackageManager.PackageManagerRequestSetTepPath(RequestHandle, expansionPackagePath);
                 if (err != Interop.PackageManager.ErrorCode.None)
                 {
                     Log.Warn(LogTag, string.Format("Failed to install package. Error in setting request package mode. err = {0}", err));
-                    Interop.PackageManager.PackageManagerRequestDestroy(requestHandle);
+                    RequestHandle.Dispose();
                     return false;
                 }
             }
 
             int requestId;
-            err = Interop.PackageManager.PackageManagerRequestInstall(requestHandle, packagePath, out requestId);
-            if (err != Interop.PackageManager.ErrorCode.None)
+            if (eventCallback != null)
             {
-                Log.Warn(LogTag, string.Format("Failed to install package. err = {0}", err));
-                Interop.PackageManager.PackageManagerRequestDestroy(requestHandle);
-                return false;
+                err = Interop.PackageManager.PackageManagerRequestInstallWithCB(RequestHandle, packagePath, internalRequestEventCallback, IntPtr.Zero, out requestId);
+                if (err == Interop.PackageManager.ErrorCode.None)
+                {
+                    RequestCallbacks.Add(requestId, eventCallback);
+                    RequestHandles.Add(requestId, RequestHandle);
+                }
+                else
+                {
+                    Log.Warn(LogTag, string.Format("Failed to install package. err = {0}", err));
+                    RequestHandle.Dispose();
+                    return false;
+                }
             }
-
-            err = Interop.PackageManager.PackageManagerRequestDestroy(requestHandle);
-            if (err != Interop.PackageManager.ErrorCode.None)
+            else
             {
-                Log.Warn(LogTag, string.Format("Failed to destroy package manager request handle. err = {0}", err));
-                // This method returns true if all other operations are completed and error occured in destroying request handle.
+                err = Interop.PackageManager.PackageManagerRequestInstall(RequestHandle, packagePath, out requestId);
+                if (err != Interop.PackageManager.ErrorCode.None)
+                {
+                    Log.Warn(LogTag, string.Format("Failed to install package. err = {0}", err));
+                    return false;
+                }
+                RequestHandle.Dispose();
             }
+
             return true;
         }
 
@@ -393,42 +549,106 @@ namespace Tizen.Applications
         /// Uninstalls package with the given name.
         /// </summary>
         /// <param name="packageId">Id of the package to be uninstalled</param>
-        /// <param name="type">Package type for the package to be uninstalled</param>
-        /// <returns>Returns true if installtion is successful, false otherwise.</returns>
+        /// <returns>Returns true if uninstallation request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of uninstallation is seccessful.
+        /// To check the result of uninstallation, the caller should check the progress using UninstallProgressChanged event.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Uninstall(string packageId)
+        {
+            return Uninstall(packageId, PackageType.UNKNOWN, null);
+        }
+
+        /// <summary>
+        /// Uninstalls package with the given name.
+        /// </summary>
+        /// <param name="packageId">Id of the package to be uninstalled</param>
+        /// <param name="type">Optional - Package type for the package to be uninstalled</param>
+        /// <returns>Returns true if uninstalltion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of uninstallation is seccessful.
+        /// To check the result of uninstallation, the caller should check the progress using UninstallProgressChanged event.
+        /// </remarks>
         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
         public static bool Uninstall(string packageId, PackageType type)
         {
-            IntPtr requestHandle;
-            var err = Interop.PackageManager.PackageManagerRequestCreate(out requestHandle);
+            return Uninstall(packageId, type, null);
+        }
+
+        /// <summary>
+        /// Uninstalls package with the given name.
+        /// </summary>
+        /// <param name="packageId">Id of the package to be uninstalled</param>
+        /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request</param>
+        /// <returns>Returns true if uninstalltion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of uninstallation is seccessful.
+        /// To check the result of uninstallation, the caller should check the progress using UninstallProgressChanged event OR eventCallback.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Uninstall(string packageId, RequestEventCallback eventCallback)
+        {
+            return Uninstall(packageId, PackageType.UNKNOWN, eventCallback);
+        }
+
+        /// <summary>
+        /// Uninstalls package with the given name.
+        /// </summary>
+        /// <param name="packageId">Id of the package to be uninstalled</param>
+        /// <param name="type">Optional - Package type for the package to be uninstalled</param>
+        /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request</param>
+        /// <returns>Returns true if uninstalltion request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of uninstallation is seccessful.
+        /// To check the result of uninstallation, the caller should check the progress using UninstallProgressChanged event OR eventCallback.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Uninstall(string packageId, PackageType type, RequestEventCallback eventCallback)
+        {
+            SafePackageManagerRequestHandle RequestHandle = new SafePackageManagerRequestHandle();
+            var err = Interop.PackageManager.PackageManagerRequestCreate(out RequestHandle);
             if (err != Interop.PackageManager.ErrorCode.None)
             {
-                Log.Warn(LogTag, string.Format("Failed to uninstall package. Error in creating request handle. err = {0}", err));
+                Log.Warn(LogTag, string.Format("Failed to create package manager request handle. err = {0}", err));
                 return false;
             }
 
-            err = Interop.PackageManager.PackageManagerRequestSetType(requestHandle, type.ToString().ToLower());
+            err = Interop.PackageManager.PackageManagerRequestSetType(RequestHandle, type.ToString().ToLower());
             if (err != Interop.PackageManager.ErrorCode.None)
             {
                 Log.Warn(LogTag, string.Format("Failed to uninstall package. Error in setting request package type. err = {0}", err));
-                Interop.PackageManager.PackageManagerRequestDestroy(requestHandle);
+                RequestHandle.Dispose();
                 return false;
             }
 
             int requestId;
-            err = Interop.PackageManager.PackageManagerRequestUninstall(requestHandle, packageId, out requestId);
-            if (err != Interop.PackageManager.ErrorCode.None)
+            if (eventCallback != null)
             {
-                Log.Warn(LogTag, string.Format("Failed to uninstall package. err = {0}", err));
-                Interop.PackageManager.PackageManagerRequestDestroy(requestHandle);
-                return false;
+                err = Interop.PackageManager.PackageManagerRequestUninstallWithCB(RequestHandle, packageId, internalRequestEventCallback, IntPtr.Zero, out requestId);
+                if (err == Interop.PackageManager.ErrorCode.None)
+                {
+                    RequestCallbacks.Add(requestId, eventCallback);
+                    RequestHandles.Add(requestId, RequestHandle);
+                }
+                else
+                {
+                    Log.Warn(LogTag, string.Format("Failed to uninstall package. err = {0}", err));
+                    RequestHandle.Dispose();
+                    return false;
+                }
             }
-
-            err = Interop.PackageManager.PackageManagerRequestDestroy(requestHandle);
-            if (err != Interop.PackageManager.ErrorCode.None)
+            else
             {
-                Log.Warn(LogTag, string.Format("Failed to destroy package manager request handle. err = {0}", err));
-                // This method returns true if all other operations are completed and error occured in destroying request handle.
+                err = Interop.PackageManager.PackageManagerRequestUninstall(RequestHandle, packageId, out requestId);
+                if (err != Interop.PackageManager.ErrorCode.None)
+                {
+                    Log.Warn(LogTag, string.Format("Failed to uninstall package. err = {0}", err));
+                    return false;
+                }
+                RequestHandle.Dispose();
             }
+
             return true;
         }
 
@@ -436,41 +656,109 @@ namespace Tizen.Applications
         /// Move package to given storage.
         /// </summary>
         /// <param name="packageId">Id of the package to be moved</param>
-        /// <param name="type">Package type for the package to be moved</param>
         /// <param name="newStorage">Storage, package should be moved to</param>
-        /// <returns>Returns true if installtion is successful, false otherwise.</returns>
+        /// <returns>Returns true if move request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of move is seccessful.
+        /// To check the result of move, the caller should check the progress using MoveProgressChanged event.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Move(string packageId, StorageType newStorage)
+        {
+            return Move(packageId, PackageType.UNKNOWN, newStorage, null);
+        }
+
+        /// <summary>
+        /// Move package to given storage.
+        /// </summary>
+        /// <param name="packageId">Id of the package to be moved</param>
+        /// <param name="type">Optional - Package type for the package to be moved</param>
+        /// <param name="newStorage">Storage, package should be moved to</param>
+        /// <returns>Returns true if move request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of move is seccessful.
+        /// To check the result of move, the caller should check the progress using MoveProgressChanged event.
+        /// </remarks>
         /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
         public static bool Move(string packageId, PackageType type, StorageType newStorage)
         {
-            IntPtr request;
-            Interop.PackageManager.ErrorCode err = Interop.PackageManager.PackageManagerRequestCreate(out request);
+            return Move(packageId, type, newStorage, null);
+        }
+
+        /// <summary>
+        /// Move package to given storage.
+        /// </summary>
+        /// <param name="packageId">Id of the package to be moved</param>
+        /// <param name="newStorage">Storage, package should be moved to</param>
+        /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request</param>
+        /// <returns>Returns true if move request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of move is seccessful.
+        /// To check the result of move, the caller should check the progress using MoveProgressChanged event.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Move(string packageId, StorageType newStorage, RequestEventCallback eventCallback)
+        {
+            return Move(packageId, PackageType.UNKNOWN, newStorage, eventCallback);
+        }
+
+        /// <summary>
+        /// Move package to given storage.
+        /// </summary>
+        /// <param name="packageId">Id of the package to be moved</param>
+        /// <param name="type">Optional - Package type for the package to be moved</param>
+        /// <param name="newStorage">Storage, package should be moved to</param>
+        /// <param name="eventCallback">Optional - The event callback will be invoked only for the current request</param>
+        /// <returns>Returns true if move request is successful, false otherwise.</returns>
+        /// <remarks>
+        /// The 'true' means that just the request of move is seccessful.
+        /// To check the result of move, the caller should check the progress using MoveProgressChanged event.
+        /// </remarks>
+        /// <privilege>http://tizen.org/privilege/packagemanager.admin</privilege>
+        public static bool Move(string packageId, PackageType type, StorageType newStorage, RequestEventCallback eventCallback)
+        {
+            SafePackageManagerRequestHandle RequestHandle = new SafePackageManagerRequestHandle();
+            var err = Interop.PackageManager.PackageManagerRequestCreate(out RequestHandle);
             if (err != Interop.PackageManager.ErrorCode.None)
             {
-                Log.Warn(LogTag, string.Format("Failed to create request handle. err = {0}", err));
+                Log.Warn(LogTag, string.Format("Failed to create package manager request handle. err = {0}", err));
                 return false;
             }
 
-            err = Interop.PackageManager.PackageManagerRequestSetType(request, type.ToString().ToLower());
+            err = Interop.PackageManager.PackageManagerRequestSetType(RequestHandle, type.ToString().ToLower());
             if (err != Interop.PackageManager.ErrorCode.None)
             {
                 Log.Warn(LogTag, string.Format("Failed to move package. Error in setting request package type. err = {0}", err));
-                Interop.PackageManager.PackageManagerRequestDestroy(request);
+                RequestHandle.Dispose();
                 return false;
             }
 
             bool result = true;
-            err = Interop.PackageManager.PackageManagerRequestMove(request, packageId, (Interop.PackageManager.StorageType)newStorage);
-            if (err != Interop.PackageManager.ErrorCode.None)
+            if (eventCallback != null)
             {
-                Log.Warn(LogTag, string.Format("Failed to move package to requested location. err = {0}", err));
-                result = false;
+                int requestId;
+                err = Interop.PackageManager.PackageManagerRequestMoveWithCB(RequestHandle, packageId, (Interop.PackageManager.StorageType)newStorage, internalRequestEventCallback, IntPtr.Zero, out requestId);
+                if (err == Interop.PackageManager.ErrorCode.None)
+                {
+                    RequestCallbacks.Add(requestId, eventCallback);
+                    RequestHandles.Add(requestId, RequestHandle);
+                }
+                else
+                {
+                    Log.Warn(LogTag, string.Format("Failed to move package to requested location. err = {0}", err));
+                    RequestHandle.Dispose();
+                    result = false;
+                }
             }
-
-            err = Interop.PackageManager.PackageManagerRequestDestroy(request);
-            if (err != Interop.PackageManager.ErrorCode.None)
+            else
             {
-                Log.Warn(LogTag, string.Format("Failed to destroy package manager request handle. err = {0}", err));
-                // This method returns true if all other operations are completed and error occured in destroying request handle.
+                err = Interop.PackageManager.PackageManagerRequestMove(RequestHandle, packageId, (Interop.PackageManager.StorageType)newStorage);
+                if (err != Interop.PackageManager.ErrorCode.None)
+                {
+                    Log.Warn(LogTag, string.Format("Failed to move package to requested location. err = {0}", err));
+                    result = false;
+                }
+                RequestHandle.Dispose();
             }
 
             return result;
@@ -621,14 +909,41 @@ namespace Tizen.Applications
             }
         }
 
-        private static void SetPackageManagerEventStatus()
+        private static void SetPackageManagerEventStatus(Interop.PackageManager.EventStatus status)
+        {
+            if (Handle.IsInvalid) return;
+
+            Interop.PackageManager.EventStatus eventStatus = s_eventStatus;
+            eventStatus |= status;
+            if (eventStatus != Interop.PackageManager.EventStatus.All)
+                eventStatus |= Interop.PackageManager.EventStatus.Progress;
+
+            var err = Interop.PackageManager.ErrorCode.None;
+            if (s_eventStatus != eventStatus)
+            {
+                err = Interop.PackageManager.PackageManagerSetEvenStatus(Handle, eventStatus);
+                if (err == Interop.PackageManager.ErrorCode.None)
+                {
+                    s_eventStatus = eventStatus;
+                    Log.Debug(LogTag, string.Format("New Event Status flag: {0}", s_eventStatus));
+                    return;
+                }
+                Log.Debug(LogTag, string.Format("Failed to set flag for {0} event. err = {1}", eventStatus, err));
+            }
+        }
+
+        private static void UnsetPackageManagerEventStatus()
         {
             if (Handle.IsInvalid) return;
 
             Interop.PackageManager.EventStatus eventStatus = Interop.PackageManager.EventStatus.All;
             if (s_installEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.Install;
-            if (s_uninstallEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.Unstall;
+            if (s_uninstallEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.Uninstall;
             if (s_updateEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.Upgrade;
+            if (s_moveEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.Move;
+            if (s_clearDataEventHandler != null) eventStatus |= Interop.PackageManager.EventStatus.ClearData;
+            if (eventStatus != Interop.PackageManager.EventStatus.All)
+                eventStatus |= Interop.PackageManager.EventStatus.Progress;
 
             var err = Interop.PackageManager.ErrorCode.None;
             if (s_eventStatus != eventStatus)
@@ -646,7 +961,7 @@ namespace Tizen.Applications
 
         private static void RegisterPackageManagerEventIfNeeded()
         {
-            if (s_installEventHandler != null || s_uninstallEventHandler != null || s_updateEventHandler != null)
+            if (s_installEventHandler != null && s_uninstallEventHandler != null && s_updateEventHandler != null && s_moveEventHandler != null && s_clearDataEventHandler != null)
             {
                 return;
             }
@@ -668,6 +983,14 @@ namespace Tizen.Applications
                     {
                         s_updateEventHandler?.Invoke(null, new PackageManagerEventArgs(packageType, packageId, (PackageEventState)eventState, progress));
                     }
+                    else if (eventType == Interop.PackageManager.EventType.Move)
+                    {
+                        s_moveEventHandler?.Invoke(null, new PackageManagerEventArgs(packageType, packageId, (PackageEventState)eventState, progress));
+                    }
+                    else if (eventType == Interop.PackageManager.EventType.ClearData)
+                    {
+                        s_clearDataEventHandler?.Invoke(null, new PackageManagerEventArgs(packageType, packageId, (PackageEventState)eventState, progress));
+                    }
                 }
                 catch (Exception e)
                 {
@@ -677,6 +1000,13 @@ namespace Tizen.Applications
 
             if (!Handle.IsInvalid)
             {
+                Log.Debug(LogTag, "Reset Package Event");
+                err = Interop.PackageManager.PackageManagerUnsetEvent(Handle);
+                if (err != Interop.PackageManager.ErrorCode.None)
+                {
+                    throw PackageManagerErrorFactory.GetException(err, "Failed to unregister package manager event event.");
+                }
+
                 err = Interop.PackageManager.PackageManagerSetEvent(Handle, s_packageManagerEventCallback, IntPtr.Zero);
             }
             if (err != Interop.PackageManager.ErrorCode.None)
@@ -687,7 +1017,7 @@ namespace Tizen.Applications
 
         private static void UnregisterPackageManagerEventIfNeeded()
         {
-            if (Handle.IsInvalid || s_installEventHandler != null || s_uninstallEventHandler != null || s_updateEventHandler != null)
+            if (Handle.IsInvalid || s_installEventHandler != null || s_uninstallEventHandler != null || s_updateEventHandler != null || s_moveEventHandler != null || s_clearDataEventHandler != null)
             {
                 return;
             }
index b62a049..97089b9 100755 (executable)
@@ -23,6 +23,7 @@ namespace Tizen.Applications
     /// </summary>
     public enum PackageType
     {
+        UNKNOWN,
         /// <summary>
         /// Tizen native application package
         /// </summary>
diff --git a/src/Tizen.Applications.PackageManager/Tizen.Applications/SafePackageManagerRequestHandle.cs b/src/Tizen.Applications.PackageManager/Tizen.Applications/SafePackageManagerRequestHandle.cs
new file mode 100755 (executable)
index 0000000..add74f5
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Tizen.Applications
+{
+    internal class SafePackageManagerRequestHandle : SafeHandle
+    {
+        /// <summary>
+        /// Initializes a new instance of the SafePackageManagerRequestHandle class.
+        /// </summary>
+        public SafePackageManagerRequestHandle() : base(IntPtr.Zero, true)
+        {
+        }
+
+        /// <summary>
+        /// Gets a value that indicates whether the handle is invalid.
+        /// </summary>
+        public override bool IsInvalid
+        {
+            get { return handle == IntPtr.Zero; }
+        }
+
+        /// <summary>
+        /// Executes the code required to free the SafePackageManagerRequestHandle.
+        /// </summary>
+        /// <returns>true if the handle is released successfully</returns>
+        protected override bool ReleaseHandle()
+        {
+            Interop.PackageManager.PackageManagerRequestDestroy(handle);
+            this.SetHandle(IntPtr.Zero);
+            return true;
+        }
+    }
+}
\ No newline at end of file
index 1773b61..2ae4d16 100755 (executable)
@@ -81,4 +81,4 @@
     <_FullFrameworkReferenceAssemblyPaths>$(MSBuildThisFileDirectory)</_FullFrameworkReferenceAssemblyPaths>
     <AutoUnifyAssemblyReferences>true</AutoUnifyAssemblyReferences>
   </PropertyGroup>
-</Project>
\ No newline at end of file
+</Project>