[NUI] fix testhub crash issue
authordongsug.song <dongsug.song@samsung.com>
Fri, 23 Dec 2022 01:59:26 +0000 (10:59 +0900)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Fri, 23 Dec 2022 05:56:46 +0000 (14:56 +0900)
src/Tizen.NUI.Components/Controls/ScrollableBase.cs
src/Tizen.NUI/src/public/Common/PropertyNotification.cs
src/Tizen.NUI/src/public/Events/PanGestureDetector.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DisposeWithoutEventUnsubscribedTest.cs

index 398cfad..04c3a65 100755 (executable)
@@ -1110,11 +1110,11 @@ namespace Tizen.NUI.Components
 
             bool isHorizontal = (ScrollingDirection == Direction.Horizontal);
 
-            float viewScreenPosition = (isHorizontal? ScreenPosition.X : ScreenPosition.Y);
-            float childScreenPosition = (isHorizontal? child.ScreenPosition.X : child.ScreenPosition.Y);
-            float scrollPosition = (isHorizontal? ScrollPosition.X : ScrollPosition.Y);
-            float viewSize = (isHorizontal? SizeWidth : SizeHeight);
-            float childSize = (isHorizontal? child.SizeWidth : child.SizeHeight);
+            float viewScreenPosition = (isHorizontal ? ScreenPosition.X : ScreenPosition.Y);
+            float childScreenPosition = (isHorizontal ? child.ScreenPosition.X : child.ScreenPosition.Y);
+            float scrollPosition = (isHorizontal ? ScrollPosition.X : ScrollPosition.Y);
+            float viewSize = (isHorizontal ? SizeWidth : SizeHeight);
+            float childSize = (isHorizontal ? child.SizeWidth : child.SizeHeight);
 
             if (viewScreenPosition > childScreenPosition ||
                 viewScreenPosition + viewSize < childScreenPosition + childSize)
@@ -1348,25 +1348,15 @@ namespace Tizen.NUI.Components
             StopOverShootingShadowAnimation();
             StopScroll();
 
-            if (mPanGestureDetector != null)
+            if (type == DisposeTypes.Explicit)
             {
-                mPanGestureDetector.Detected -= OnPanGestureDetected;
-                mPanGestureDetector.Dispose();
+                mPanGestureDetector?.Dispose();
                 mPanGestureDetector = null;
-            }
 
-            if (propertyNotification != null)
-            {
                 ContentContainer?.RemovePropertyNotification(propertyNotification);
-                propertyNotification.Notified -= OnPropertyChanged;
-                propertyNotification.Dispose();
+                propertyNotification?.Dispose();
                 propertyNotification = null;
             }
-
-            if (type == DisposeTypes.Explicit)
-            {
-
-            }
             base.Dispose(type);
         }
 
@@ -1698,7 +1688,7 @@ namespace Tizen.NUI.Components
                 var checkFinalTargetPosition = BoundScrollPosition(checkChildTargetPosition);
                 handled = !((int)checkFinalTargetPosition == 0 || -(int)checkFinalTargetPosition == (int)maxScrollDistance);
                 // If you propagate a gesture event, return;
-                if(!handled)
+                if (!handled)
                 {
                     return handled;
                 }
@@ -2005,7 +1995,7 @@ namespace Tizen.NUI.Components
         {
             bool isHorizontal = (ScrollingDirection == Direction.Horizontal);
             float targetPosition = -(ScrollingDirection == Direction.Horizontal ? ContentContainer.CurrentPosition.X : ContentContainer.CurrentPosition.Y);
-            float stepDistance = (stepScrollDistance != 0? stepScrollDistance : (isHorizontal ? Size.Width * 0.25f :  Size.Height * 0.25f));
+            float stepDistance = (stepScrollDistance != 0 ? stepScrollDistance : (isHorizontal ? Size.Width * 0.25f : Size.Height * 0.25f));
 
             bool forward = ((isHorizontal && direction == View.FocusDirection.Right) ||
                             (!isHorizontal && direction == View.FocusDirection.Down) ||
index 201ed2c..c879662 100755 (executable)
@@ -30,7 +30,7 @@ namespace Tizen.NUI
     {
 
         private DaliEventHandler<object, NotifyEventArgs> propertyNotificationNotifyEventHandler;
-        private NotifyEventCallbackDelegate propertyNotificationNotifyEventCallbackDelegate;
+        private NotifyEventCallbackDelegate propertyNotificationNotifyEventCallback;
 
         /// <summary>
         /// Create a instance of PropertyNotification.
@@ -66,24 +66,29 @@ namespace Tizen.NUI
         {
             add
             {
-                // Restricted to only one listener
                 if (propertyNotificationNotifyEventHandler == null)
                 {
-                    propertyNotificationNotifyEventHandler += value;
-
-                    propertyNotificationNotifyEventCallbackDelegate = new NotifyEventCallbackDelegate(OnPropertyNotificationNotify);
-                    this.NotifySignal().Connect(propertyNotificationNotifyEventCallbackDelegate);
+                    propertyNotificationNotifyEventCallback = OnPropertyNotificationNotify;
+                    using PropertyNotifySignal signal = new PropertyNotifySignal(Interop.PropertyNotification.NotifySignal(SwigCPtr), false);
+                    signal?.Connect(propertyNotificationNotifyEventCallback);
                 }
+                propertyNotificationNotifyEventHandler += value;
             }
-
             remove
             {
-                if (propertyNotificationNotifyEventHandler != null)
+                propertyNotificationNotifyEventHandler -= value;
+                if (propertyNotificationNotifyEventHandler == null)
                 {
-                    this.NotifySignal().Disconnect(propertyNotificationNotifyEventCallbackDelegate);
+                    using PropertyNotifySignal signal = new PropertyNotifySignal(Interop.PropertyNotification.NotifySignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(propertyNotificationNotifyEventCallback);
+                        if (signal?.Empty() == true)
+                        {
+                            propertyNotificationNotifyEventCallback = null;
+                        }
+                    }
                 }
-
-                propertyNotificationNotifyEventHandler -= value;
             }
         }
 
@@ -230,14 +235,38 @@ namespace Tizen.NUI
         }
 
         /// <summary>
-        /// Connects to this signal to be notified when the notification has occurred.
+        /// override it to clean-up your own resources.
         /// </summary>
-        /// <returns>A signal object to Connect() with</returns>
-        internal PropertyNotifySignal NotifySignal()
+        /// <param name="type"></param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void Dispose(DisposeTypes type)
         {
-            PropertyNotifySignal ret = new PropertyNotifySignal(Interop.PropertyNotification.NotifySignal(SwigCPtr), false);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-            return ret;
+            if (disposed)
+            {
+                return;
+            }
+
+            if (type == DisposeTypes.Explicit)
+            {
+                //Called by User
+                //Release your own managed resources here.
+                //You should release all of your own disposable objects here.
+            }
+
+            //Release your own unmanaged resources here.
+            //You should not access any managed member here except static instance.
+            //because the execution order of Finalizes is non-deterministic.
+
+            if (HasBody())
+            {
+                if (propertyNotificationNotifyEventCallback != null)
+                {
+                    using PropertyNotifySignal signal = new PropertyNotifySignal(Interop.PropertyNotification.NotifySignal(SwigCPtr), false);
+                    signal?.Disconnect(propertyNotificationNotifyEventCallback);
+                    propertyNotificationNotifyEventCallback = null;
+                }
+            }
+            base.Dispose(type);
         }
 
         /// This will not be public opened.
@@ -250,11 +279,42 @@ namespace Tizen.NUI
         // Callback for PropertyNotification NotifySignal
         private void OnPropertyNotificationNotify(IntPtr propertyNotification)
         {
-            NotifyEventArgs e = new NotifyEventArgs();
-            e.PropertyNotification = GetPropertyNotificationFromPtr(propertyNotification);
+            if (IsNativeHandleInvalid())
+            {
+                if (this.Disposed)
+                {
+                    if (propertyNotificationNotifyEventHandler != null)
+                    {
+                        var process = global::System.Diagnostics.Process.GetCurrentProcess().Id;
+                        var thread = global::System.Threading.Thread.CurrentThread.ManagedThreadId;
+                        var me = this.GetType().FullName;
+
+                        Tizen.Log.Error("NUI", $"Error! NUI's native dali object is already disposed. " +
+                            $"OR the native dali object handle of NUI becomes null! \n" +
+                            $" process:{process} thread:{thread}, isDisposed:{this.Disposed}, isDisposeQueued:{this.IsDisposeQueued}, me:{me}\n");
+                    }
+                }
+                else
+                {
+                    if (this.IsDisposeQueued)
+                    {
+                        var process = global::System.Diagnostics.Process.GetCurrentProcess().Id;
+                        var thread = global::System.Threading.Thread.CurrentThread.ManagedThreadId;
+                        var me = this.GetType().FullName;
+
+                        //in this case, this object is ready to be disposed waiting on DisposeQueue, so event callback should not be invoked!
+                        Tizen.Log.Error("NUI", "in this case, the View object is ready to be disposed waiting on DisposeQueue, so event callback should not be invoked! just return here! \n" +
+                            $"process:{process} thread:{thread}, isDisposed:{this.Disposed}, isDisposeQueued:{this.IsDisposeQueued}, me:{me}\n");
+                        return;
+                    }
+                }
+            }
 
             if (propertyNotificationNotifyEventHandler != null)
             {
+                NotifyEventArgs e = new NotifyEventArgs();
+                e.PropertyNotification = GetPropertyNotificationFromPtr(propertyNotification);
+
                 //here we send all data to user event handlers
                 propertyNotificationNotifyEventHandler(this, e);
             }
index 27b9b95..f705010 100755 (executable)
@@ -71,19 +71,25 @@ namespace Tizen.NUI
                 if (detectedEventHandler == null)
                 {
                     detectedCallback = OnPanGestureDetected;
-                    DetectedSignal().Connect(detectedCallback);
+                    using PanGestureDetectedSignal signal = new PanGestureDetectedSignal(Interop.PanGestureDetector.DetectedSignal(SwigCPtr), false);
+                    signal?.Connect(detectedCallback);
                 }
-
                 detectedEventHandler += value;
             }
-
             remove
             {
                 detectedEventHandler -= value;
-
-                if (detectedEventHandler == null && DetectedSignal().Empty() == false)
+                if (detectedEventHandler == null)
                 {
-                    DetectedSignal().Disconnect(detectedCallback);
+                    using PanGestureDetectedSignal signal = new PanGestureDetectedSignal(Interop.PanGestureDetector.DetectedSignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(detectedCallback);
+                        if (signal?.Empty() == true)
+                        {
+                            detectedCallback = null;
+                        }
+                    }
                 }
             }
         }
@@ -537,27 +543,81 @@ namespace Tizen.NUI
             return ret;
         }
 
-        internal PanGestureDetectedSignal DetectedSignal()
+        /// <summary>
+        /// override it to clean-up your own resources.
+        /// </summary>
+        /// <param name="type"></param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void Dispose(DisposeTypes type)
         {
-            PanGestureDetectedSignal ret = new PanGestureDetectedSignal(Interop.PanGestureDetector.DetectedSignal(SwigCPtr), false);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-            return ret;
+            if (disposed)
+            {
+                return;
+            }
+
+            if (type == DisposeTypes.Explicit)
+            {
+                //Called by User
+                //Release your own managed resources here.
+                //You should release all of your own disposable objects here.
+            }
+
+            //Release your own unmanaged resources here.
+            //You should not access any managed member here except static instance.
+            //because the execution order of Finalizes is non-deterministic.
+
+            if (HasBody())
+            {
+                if (detectedCallback != null)
+                {
+                    using PanGestureDetectedSignal signal = new PanGestureDetectedSignal(Interop.PanGestureDetector.DetectedSignal(GetBaseHandleCPtrHandleRef), false);
+                    signal?.Disconnect(detectedCallback);
+                    detectedCallback = null;
+                }
+            }
+            base.Dispose(type);
         }
 
         /// This will not be public opened.
         [EditorBrowsable(EditorBrowsableState.Never)]
         protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
         {
-            if (detectedCallback != null)
-            {
-                DetectedSignal().Disconnect(detectedCallback);
-            }
-
             Interop.PanGestureDetector.DeletePanGestureDetector(swigCPtr);
         }
 
         private void OnPanGestureDetected(IntPtr actor, IntPtr panGesture)
         {
+            if (IsNativeHandleInvalid())
+            {
+                if (this.Disposed)
+                {
+                    if (detectedEventHandler != null)
+                    {
+                        var process = global::System.Diagnostics.Process.GetCurrentProcess().Id;
+                        var thread = global::System.Threading.Thread.CurrentThread.ManagedThreadId;
+                        var me = this.GetType().FullName;
+
+                        Tizen.Log.Error("NUI", $"Error! NUI's native dali object is already disposed. " +
+                            $"OR the native dali object handle of NUI becomes null! \n" +
+                            $" process:{process} thread:{thread}, isDisposed:{this.Disposed}, isDisposeQueued:{this.IsDisposeQueued}, me:{me}\n");
+                    }
+                }
+                else
+                {
+                    if (this.IsDisposeQueued)
+                    {
+                        var process = global::System.Diagnostics.Process.GetCurrentProcess().Id;
+                        var thread = global::System.Threading.Thread.CurrentThread.ManagedThreadId;
+                        var me = this.GetType().FullName;
+
+                        //in this case, this object is ready to be disposed waiting on DisposeQueue, so event callback should not be invoked!
+                        Tizen.Log.Error("NUI", "in this case, the View object is ready to be disposed waiting on DisposeQueue, so event callback should not be invoked! just return here! \n" +
+                            $"process:{process} thread:{thread}, isDisposed:{this.Disposed}, isDisposeQueued:{this.IsDisposeQueued}, me:{me}\n");
+                        return;
+                    }
+                }
+            }
+
             if (detectedEventHandler != null)
             {
                 DetectedEventArgs e = new DetectedEventArgs();
index 70668b7..47de741 100644 (file)
@@ -2,6 +2,7 @@
 using global::System;
 using Tizen.NUI.BaseComponents;
 using System.Collections.Generic;
+using Tizen.NUI.Components;
 
 namespace Tizen.NUI.Samples
 {
@@ -26,8 +27,11 @@ namespace Tizen.NUI.Samples
 
         public void Activate()
         {
+            //test case 1: checking dispose without "-=" of event.
             DisposeWithoutUnsubscribedEventTest();
-            AnimationDisposeTest();
+
+            //test case 2: checking Animation class dispose.
+            //AnimationDisposeTest();
         }
         public void Deactivate()
         {
@@ -126,6 +130,35 @@ namespace Tizen.NUI.Samples
             }
         }
 
+        private void AddManyScrollableBases()
+        {
+            tlog.Fatal(tag, $"AddManyScrollableBases()");
+
+            for (int i = 0; i < NUMBER_OF_VIEW; i++)
+            {
+                var child = new ScrollableBase()
+                {
+                    Size = new Size(60, 60),
+                    Position = new Position(rand.Next(MIN_POSITION, MAX_POSITION), rand.Next(MIN_POSITION, MAX_POSITION)),
+                    BackgroundColor = new Color((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), 1),
+                };
+
+                rootView.Add(child);
+                child.Relayout += Child_Relayout;
+                child.RemovedFromWindow += Child_RemovedFromWindow;
+                child.AddedToWindow += Child_AddedToWindow;
+                child.WheelEvent += Child_WheelEvent;
+                child.HoverEvent += Child_HoverEvent;
+                child.InterceptTouchEvent += Child_InterceptTouchEvent;
+                child.TouchEvent += Child_TouchEvent;
+                child.ResourcesLoaded += Child_ResourcesLoaded;
+                child.KeyEvent += Child_KeyEvent;
+                child.FocusLost += Child_FocusLost;
+                child.FocusGained += Child_FocusGained;
+            }
+        }
+
+
         private void Child_FocusGained(object sender, EventArgs e)
         {
             if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
@@ -260,7 +293,11 @@ namespace Tizen.NUI.Samples
             toggle = !toggle;
             if (toggle)
             {
-                AddManyObject();
+                //test case 1: checking ImageView object dispose.
+                //AddManyObject();
+                
+                //test case 2: checking ScrollableBase object dispose.
+                AddManyScrollableBases();
             }
             else
             {