From: dongsug.song Date: Fri, 23 Dec 2022 01:59:26 +0000 (+0900) Subject: [NUI] fix testhub crash issue X-Git-Tag: accepted/tizen/unified/20231205.024657~525 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fcad2de3b6f39c9e2d4b12910e12e1b427e0fb47;p=platform%2Fcore%2Fcsapi%2Ftizenfx.git [NUI] fix testhub crash issue --- diff --git a/src/Tizen.NUI.Components/Controls/ScrollableBase.cs b/src/Tizen.NUI.Components/Controls/ScrollableBase.cs index 7a90695..b08af63 100755 --- a/src/Tizen.NUI.Components/Controls/ScrollableBase.cs +++ b/src/Tizen.NUI.Components/Controls/ScrollableBase.cs @@ -1131,11 +1131,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) @@ -1369,18 +1369,13 @@ 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; } @@ -1721,7 +1716,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; } @@ -2028,7 +2023,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) || diff --git a/src/Tizen.NUI/src/public/Common/PropertyNotification.cs b/src/Tizen.NUI/src/public/Common/PropertyNotification.cs index 201ed2c..c879662 100755 --- a/src/Tizen.NUI/src/public/Common/PropertyNotification.cs +++ b/src/Tizen.NUI/src/public/Common/PropertyNotification.cs @@ -30,7 +30,7 @@ namespace Tizen.NUI { private DaliEventHandler propertyNotificationNotifyEventHandler; - private NotifyEventCallbackDelegate propertyNotificationNotifyEventCallbackDelegate; + private NotifyEventCallbackDelegate propertyNotificationNotifyEventCallback; /// /// 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 } /// - /// Connects to this signal to be notified when the notification has occurred. + /// override it to clean-up your own resources. /// - /// A signal object to Connect() with - internal PropertyNotifySignal NotifySignal() + /// + [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); } diff --git a/src/Tizen.NUI/src/public/Events/PanGestureDetector.cs b/src/Tizen.NUI/src/public/Events/PanGestureDetector.cs index 27b9b95..f705010 100755 --- a/src/Tizen.NUI/src/public/Events/PanGestureDetector.cs +++ b/src/Tizen.NUI/src/public/Events/PanGestureDetector.cs @@ -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() + /// + /// override it to clean-up your own resources. + /// + /// + [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(); diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DisposeWithoutEventUnsubscribedTest.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DisposeWithoutEventUnsubscribedTest.cs index 70668b7..47de741 100644 --- a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DisposeWithoutEventUnsubscribedTest.cs +++ b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DisposeWithoutEventUnsubscribedTest.cs @@ -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 {