[NUI] Add DoActionExtension to set dynamic property (#4467)
authordongsug-song <35130733+dongsug-song@users.noreply.github.com>
Thu, 18 Aug 2022 01:10:20 +0000 (10:10 +0900)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Mon, 22 Aug 2022 09:37:36 +0000 (18:37 +0900)
* [WIP][NUI] Add DoActionExtension to set dynamic property

* [NUI] Remove weak ref of Lottie and remove saved callback when disposed

* [NUI] Fix ABI break warning

* [NUI] Fix ABI break warning msg

* [NUI] Fix VS warnings

* [NUI] Fix VS warnings and add more test code in the Sample

* [NUI] Remove debugging logs

* [NUI] Fix typos by the review

src/Tizen.NUI/src/internal/Interop/Interop.View.cs
src/Tizen.NUI/src/public/BaseComponents/LottieAnimationView.cs
src/Tizen.NUI/src/public/Common/PropertyValue.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples.sln
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/LottieAnimationViewDynamicPropertyTest.cs [new file with mode: 0644]
test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/done.json [new file with mode: 0644]

index 2c32be7..5101007 100755 (executable)
@@ -80,9 +80,11 @@ namespace Tizen.NUI
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_ResourceReadySignal")]
             public static extern global::System.IntPtr ResourceReadySignal(global::System.Runtime.InteropServices.HandleRef jarg1);
 
-
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_View_GetVisualResourceStatus")]
             public static extern int View_GetVisualResourceStatus(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_View_DoActionExtension")]
+            public static extern void DoActionExtension(global::System.Runtime.InteropServices.HandleRef control, int visualIndex, int actionId, int id, string keyPath, int property, global::System.IntPtr callback);
         }
     }
 }
index cef676c..7f84339 100755 (executable)
@@ -80,6 +80,8 @@ namespace Tizen.NUI.BaseComponents
                 return;
             }
 
+            CleanCallbackDictionaries();
+
             //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.
@@ -87,13 +89,22 @@ namespace Tizen.NUI.BaseComponents
             //disconnect event signal
             if (finishedEventHandler != null && visualEventSignalCallback != null)
             {
-                VisualEventSignal().Disconnect(visualEventSignalCallback);
+                using VisualEventSignal visualEvent = VisualEventSignal();
+                visualEvent.Disconnect(visualEventSignalCallback);
                 finishedEventHandler = null;
                 NUILog.Debug($"disconnect event signal");
             }
 
             base.Dispose(type);
         }
+
+        // This is used for internal purpose. hidden API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void Dispose(bool disposing)
+        {
+            CleanCallbackDictionaries();
+            base.Dispose(disposing);
+        }
         #endregion Constructor, Destructor, Dispose
 
 
@@ -125,12 +136,18 @@ namespace Tizen.NUI.BaseComponents
 
                 NUILog.Debug($"<[{GetId()}]SET url={currentStates.url}");
 
-                PropertyMap map = new PropertyMap();
-                map.Add(Visual.Property.Type, new PropertyValue((int)DevelVisual.Type.AnimatedVectorImage))
-                    .Add(ImageVisualProperty.URL, new PropertyValue(currentStates.url))
-                    .Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount))
-                    .Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction))
-                    .Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
+                using PropertyMap map = new PropertyMap();
+                using PropertyValue type = new PropertyValue((int)DevelVisual.Type.AnimatedVectorImage);
+                using PropertyValue url = new PropertyValue(currentStates.url);
+                using PropertyValue loopCnt = new PropertyValue(currentStates.loopCount);
+                using PropertyValue stopAction = new PropertyValue((int)currentStates.stopEndAction);
+                using PropertyValue loopMode = new PropertyValue((int)currentStates.loopMode);
+
+                map.Add(Visual.Property.Type, type)
+                    .Add(ImageVisualProperty.URL, url)
+                    .Add(ImageVisualProperty.LoopCount, loopCnt)
+                    .Add(ImageVisualProperty.StopBehavior, stopAction)
+                    .Add(ImageVisualProperty.LoopingMode, loopMode);
                 Image = map;
 
                 currentStates.contentInfo = null;
@@ -146,10 +163,10 @@ namespace Tizen.NUI.BaseComponents
                 string ret = currentStates.url;
                 NUILog.Debug($"<[{GetId()}] GET");
 
-                PropertyMap map = base.Image;
+                using PropertyMap map = base.Image;
                 if (map != null)
                 {
-                    PropertyValue val = map.Find(ImageVisualProperty.URL);
+                    using PropertyValue val = map.Find(ImageVisualProperty.URL);
                     if (val != null)
                     {
                         if (val.Get(out ret))
@@ -173,11 +190,11 @@ namespace Tizen.NUI.BaseComponents
             get
             {
                 NUILog.Debug($"< Get!");
-                PropertyMap map = base.Image;
+                using PropertyMap map = base.Image;
                 var ret = 0;
                 if (map != null)
                 {
-                    PropertyValue val = map.Find(ImageVisualProperty.PlayState);
+                    using PropertyValue val = map.Find(ImageVisualProperty.PlayState);
                     if (val != null)
                     {
                         if (val.Get(out ret))
@@ -204,15 +221,15 @@ namespace Tizen.NUI.BaseComponents
             get
             {
                 int ret = -1;
-                PropertyMap map = base.Image;
+                using PropertyMap map = base.Image;
                 if (map != null)
                 {
-                    PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
+                    using PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
                     if (val != null)
                     {
                         if (val.Get(out ret))
                         {
-                            //NUILog.Debug( $"TotalFrameNumber get! ret={ret}");
+                            NUILog.Debug($"TotalFrameNumber get! ret={ret}");
                             currentStates.totalFrame = ret;
                             return ret;
                         }
@@ -261,20 +278,21 @@ namespace Tizen.NUI.BaseComponents
             {
                 currentStates.frame = value;
                 NUILog.Debug($"<[{GetId()}]SET frame={currentStates.frame}>");
-                DoAction(ImageView.Property.IMAGE, ActionJumpTo, new PropertyValue(currentStates.frame));
+                using PropertyValue attribute = new PropertyValue(currentStates.frame);
+                DoAction(ImageView.Property.IMAGE, ActionJumpTo, attribute);
             }
             get
             {
                 int ret = 0;
-                PropertyMap map = base.Image;
+                using PropertyMap map = base.Image;
                 if (map != null)
                 {
-                    PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
+                    using PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
                     if (val != null)
                     {
                         if (val.Get(out ret))
                         {
-                            //NUILog.Debug( $"CurrentFrameNumber get! val={ret}");
+                            NUILog.Debug($"CurrentFrameNumber get! val={ret}");
                             return ret;
                         }
                     }
@@ -309,23 +327,25 @@ namespace Tizen.NUI.BaseComponents
                 currentStates.changed = true;
 
                 NUILog.Debug($"<[{GetId()}] SET loopMode={currentStates.loopMode}>");
-                PropertyMap map = new PropertyMap();
-                map.Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
-                DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, new PropertyValue(map));
+                using PropertyMap map = new PropertyMap();
+                using PropertyValue loopMode = new PropertyValue((int)currentStates.loopMode);
+                map.Add(ImageVisualProperty.LoopingMode, loopMode);
+                using PropertyValue attribute = new PropertyValue(map);
+                DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, attribute);
             }
             get
             {
-                //NUILog.Debug( $"LoopMode get!");
-                PropertyMap map = base.Image;
+                NUILog.Debug($"LoopMode get!");
+                using PropertyMap map = base.Image;
                 var ret = 0;
                 if (map != null)
                 {
-                    PropertyValue val = map.Find(ImageVisualProperty.LoopingMode);
+                    using PropertyValue val = map.Find(ImageVisualProperty.LoopingMode);
                     if (val != null)
                     {
                         if (val.Get(out ret))
                         {
-                            //NUILog.Debug( $"gotten LoopMode={ret}");
+                            NUILog.Debug($"gotten LoopMode={ret}");
                             if (ret != (int)currentStates.loopMode && ret > 0)
                             {
                                 NUILog.Debug($" [ERROR][{GetId()}](LottieAnimationView) different LoopMode! gotten={ret}, loopMode={currentStates.loopMode}");
@@ -379,23 +399,25 @@ namespace Tizen.NUI.BaseComponents
                 currentStates.changed = true;
                 currentStates.loopCount = value;
                 NUILog.Debug($"<[{GetId()}]SET currentStates.loopCount={currentStates.loopCount}>");
-                PropertyMap map = new PropertyMap();
-                map.Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount));
-                DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, new PropertyValue(map));
+                using PropertyMap map = new PropertyMap();
+                using PropertyValue loopCnt = new PropertyValue(currentStates.loopCount);
+                map.Add(ImageVisualProperty.LoopCount, loopCnt);
+                using PropertyValue attribute = new PropertyValue(map);
+                DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, attribute);
             }
             get
             {
-                //NUILog.Debug( $"LoopCount get!");
-                PropertyMap map = base.Image;
+                NUILog.Debug($"LoopCount get!");
+                using PropertyMap map = base.Image;
                 var ret = 0;
                 if (map != null)
                 {
-                    PropertyValue val = map.Find(ImageVisualProperty.LoopCount);
+                    using PropertyValue val = map.Find(ImageVisualProperty.LoopCount);
                     if (val != null)
                     {
                         if (val.Get(out ret))
                         {
-                            //NUILog.Debug( $"gotten loop count={ret}");
+                            NUILog.Debug($"gotten loop count={ret}");
                             if (ret != currentStates.loopCount && ret > 0)
                             {
                                 NUILog.Debug($"<[ERROR][{GetId()}](LottieAnimationView) different loop count! gotten={ret}, loopCount={currentStates.loopCount}>");
@@ -435,23 +457,25 @@ namespace Tizen.NUI.BaseComponents
                 currentStates.changed = true;
 
                 NUILog.Debug($"<[{GetId()}]SET val={currentStates.stopEndAction}>");
-                PropertyMap map = new PropertyMap();
-                map.Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction));
-                DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, new PropertyValue(map));
+                using PropertyMap map = new PropertyMap();
+                using PropertyValue stopAction = new PropertyValue((int)currentStates.stopEndAction);
+                map.Add(ImageVisualProperty.StopBehavior, stopAction);
+                using PropertyValue attribute = new PropertyValue(map);
+                DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, attribute);
             }
             get
             {
-                //NUILog.Debug( $"StopBehavior get!");
-                PropertyMap map = base.Image;
+                NUILog.Debug($"StopBehavior get!");
+                using PropertyMap map = base.Image;
                 var ret = 0;
                 if (map != null)
                 {
-                    PropertyValue val = map.Find(ImageVisualProperty.StopBehavior);
+                    using PropertyValue val = map.Find(ImageVisualProperty.StopBehavior);
                     if (val != null)
                     {
                         if (val.Get(out ret))
                         {
-                            //NUILog.Debug( $"gotten StopBehavior={ret}");
+                            NUILog.Debug($"gotten StopBehavior={ret}");
                             if (ret != (int)currentStates.stopEndAction)
                             {
                                 NUILog.Debug($"<[ERROR][{GetId()}](LottieAnimationView) different StopBehavior! gotten={ret}, StopBehavior={currentStates.stopEndAction}>");
@@ -494,9 +518,11 @@ namespace Tizen.NUI.BaseComponents
                 currentStates.changed = true;
                 currentStates.redrawInScalingDown = value;
                 NUILog.Debug($"<[{GetId()}]SET currentStates.redrawInScalingDown={currentStates.redrawInScalingDown}>");
-                PropertyMap map = new PropertyMap();
-                map.Add(ImageVisualProperty.RedrawInScalingDown, new PropertyValue(currentStates.redrawInScalingDown));
-                DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, new PropertyValue(map));
+                using PropertyMap map = new PropertyMap();
+                using PropertyValue redraw = new PropertyValue(currentStates.redrawInScalingDown);
+                map.Add(ImageVisualProperty.RedrawInScalingDown, redraw);
+                using PropertyValue action = new PropertyValue(map);
+                DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, action);
             }
             get
             {
@@ -504,7 +530,7 @@ namespace Tizen.NUI.BaseComponents
                 var ret = true;
                 if (map != null)
                 {
-                    PropertyValue val = map.Find(ImageVisualProperty.RedrawInScalingDown);
+                    using PropertyValue val = map.Find(ImageVisualProperty.RedrawInScalingDown);
                     if (val != null)
                     {
                         if (val.Get(out ret))
@@ -530,6 +556,10 @@ namespace Tizen.NUI.BaseComponents
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         protected int ActionJumpTo { get; set; } = Interop.LottieAnimationView.AnimatedVectorImageVisualActionJumpToGet();
+
+        // This is used for internal purpose. hidden API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected int SetDynamicProperty => ActionJumpTo + 1;
         #endregion Property
 
 
@@ -548,13 +578,17 @@ namespace Tizen.NUI.BaseComponents
             currentStates.framePlayRangeMin = minFrame;
             currentStates.framePlayRangeMax = maxFrame;
 
-            PropertyArray array = new PropertyArray();
-            array.PushBack(new PropertyValue(currentStates.framePlayRangeMin));
-            array.PushBack(new PropertyValue(currentStates.framePlayRangeMax));
-
-            PropertyMap map = new PropertyMap();
-            map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
-            DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, new PropertyValue(map));
+            using PropertyArray array = new PropertyArray();
+            using PropertyValue min = new PropertyValue(currentStates.framePlayRangeMin);
+            using PropertyValue max = new PropertyValue(currentStates.framePlayRangeMax);
+            array.PushBack(min);
+            array.PushBack(max);
+
+            using PropertyMap map = new PropertyMap();
+            using PropertyValue range = new PropertyValue(array);
+            map.Add(ImageVisualProperty.PlayRange, range);
+            using PropertyValue action = new PropertyValue(map);
+            DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, action);
             NUILog.Debug($"  [{GetId()}] currentStates.min:({currentStates.framePlayRangeMin}, max:{currentStates.framePlayRangeMax})>");
         }
 
@@ -602,43 +636,50 @@ namespace Tizen.NUI.BaseComponents
         public List<Tuple<string, int, int>> GetContentInfo()
         {
             NUILog.Debug($"<");
+
             if (currentStates.contentInfo != null)
             {
                 return currentStates.contentInfo;
             }
 
             PropertyMap imageMap = base.Image;
-            PropertyMap contentMap = new PropertyMap();
             if (imageMap != null)
             {
                 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
-                if (val != null)
+                PropertyMap contentMap = new PropertyMap();
+                if (val?.Get(ref contentMap) == true)
                 {
-                    if (val.Get(contentMap))
+                    currentStates.contentInfo = new List<Tuple<string, int, int>>();
+                    for (uint i = 0; i < contentMap.Count(); i++)
                     {
-                        currentStates.contentInfo = new List<Tuple<string, int, int>>();
-                        for (uint i = 0; i < contentMap.Count(); i++)
+                        using PropertyKey propertyKey = contentMap.GetKeyAt(i);
+                        string key = propertyKey.StringKey;
+
+                        using PropertyValue arrVal = contentMap.GetValue(i);
+                        using PropertyArray arr = new PropertyArray();
+                        if (arrVal.Get(arr))
                         {
-                            string key = contentMap.GetKeyAt(i).StringKey;
-                            PropertyArray arr = new PropertyArray();
-                            contentMap.GetValue(i).Get(arr);
-                            if (arr != null)
-                            {
-                                int startFrame, endFrame;
-                                arr.GetElementAt(0).Get(out startFrame);
-                                arr.GetElementAt(1).Get(out endFrame);
+                            int startFrame = -1;
+                            using PropertyValue start = arr.GetElementAt(0);
+                            start?.Get(out startFrame);
 
-                                NUILog.Debug($"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
+                            int endFrame = -1;
+                            using PropertyValue end = arr.GetElementAt(1);
+                            end?.Get(out endFrame);
 
-                                Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
+                            NUILog.Debug($"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
 
-                                currentStates.contentInfo?.Add(item);
-                            }
+                            Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
+
+                            currentStates.contentInfo?.Add(item);
                         }
                     }
                 }
+                contentMap.Dispose();
+                val.Dispose();
             }
             NUILog.Debug($">");
+
             return currentStates.contentInfo;
         }
 
@@ -659,16 +700,20 @@ namespace Tizen.NUI.BaseComponents
             currentStates.mark1 = marker1;
             currentStates.mark2 = marker2;
 
-            PropertyArray array = new PropertyArray();
-            array.PushBack(new PropertyValue(currentStates.mark1));
+            using PropertyArray array = new PropertyArray();
+            using PropertyValue mark1 = new PropertyValue(currentStates.mark1);
+            array.PushBack(mark1);
+            using PropertyValue mark2 = new PropertyValue(currentStates.mark2);
             if (marker2 != null)
             {
-                array.PushBack(new PropertyValue(currentStates.mark2));
+                array.PushBack(mark2);
             }
 
-            PropertyMap map = new PropertyMap();
-            map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
-            DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, new PropertyValue(map));
+            using PropertyMap map = new PropertyMap();
+            using PropertyValue range = new PropertyValue(array);
+            map.Add(ImageVisualProperty.PlayRange, range);
+            using PropertyValue actionProperty = new PropertyValue(map);
+            DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, actionProperty);
             NUILog.Debug($"  [{GetId()}] currentStates.mark1:{currentStates.mark1}, mark2:{currentStates.mark2} >");
         }
 
@@ -682,20 +727,20 @@ namespace Tizen.NUI.BaseComponents
         {
             NUILog.Debug($"< [{GetId()}] GetMinMaxFrame()! total frame={currentStates.totalFrame}");
 
-            PropertyMap map = Image;
+            using PropertyMap map = Image;
             if (map != null)
             {
-                PropertyValue val = map.Find(ImageVisualProperty.PlayRange);
+                using PropertyValue val = map.Find(ImageVisualProperty.PlayRange);
                 if (val != null)
                 {
-                    PropertyArray array = new PropertyArray();
+                    using PropertyArray array = new PropertyArray();
                     if (val.Get(array))
                     {
                         uint cnt = array.Count();
                         int item1 = -1, item2 = -1;
                         for (uint i = 0; i < cnt; i++)
                         {
-                            PropertyValue v = array.GetElementAt(i);
+                            using PropertyValue v = array.GetElementAt(i);
                             int intRet;
                             if (v.Get(out intRet))
                             {
@@ -722,6 +767,36 @@ namespace Tizen.NUI.BaseComponents
             Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#2");
             return new Tuple<int, int>(-1, -1);
         }
+
+        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void DoActionExtension(LottieAnimationViewDynamicProperty info)
+        {
+            dynamicPropertyCallbackId++;
+
+            weakReferencesOfLottie?.Add(dynamicPropertyCallbackId, new WeakReference<LottieAnimationView>(this));
+            InternalSavedDynamicPropertyCallbacks?.Add(dynamicPropertyCallbackId, info.Callback);
+
+            Interop.View.DoActionExtension(SwigCPtr, ImageView.Property.IMAGE, SetDynamicProperty, dynamicPropertyCallbackId, info.KeyPath, (int)info.Property, Marshal.GetFunctionPointerForDelegate<System.Delegate>(rootCallback));
+
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        private void CleanCallbackDictionaries()
+        {
+            if (weakReferencesOfLottie?.Count > 0 && InternalSavedDynamicPropertyCallbacks != null)
+            {
+                foreach (var key in InternalSavedDynamicPropertyCallbacks?.Keys)
+                {
+                    if (weakReferencesOfLottie.ContainsKey(key))
+                    {
+                        weakReferencesOfLottie.Remove(key);
+                    }
+                }
+            }
+            InternalSavedDynamicPropertyCallbacks?.Clear();
+            InternalSavedDynamicPropertyCallbacks = null;
+        }
         #endregion Method
 
 
@@ -738,7 +813,8 @@ namespace Tizen.NUI.BaseComponents
                 {
                     NUILog.Debug($"<[{GetId()}] Finished eventhandler added>");
                     visualEventSignalCallback = onVisualEventSignal;
-                    VisualEventSignal().Connect(visualEventSignalCallback);
+                    using VisualEventSignal visualEvent = VisualEventSignal();
+                    visualEvent.Connect(visualEventSignalCallback);
                 }
                 finishedEventHandler += value;
             }
@@ -748,7 +824,12 @@ namespace Tizen.NUI.BaseComponents
                 finishedEventHandler -= value;
                 if (finishedEventHandler == null && visualEventSignalCallback != null)
                 {
-                    VisualEventSignal().Disconnect(visualEventSignalCallback);
+                    using VisualEventSignal visualEvent = VisualEventSignal();
+                    visualEvent.Disconnect(visualEventSignalCallback);
+                    if (visualEvent?.Empty() == true)
+                    {
+                        visualEventSignalCallback = null;
+                    }
                 }
             }
         }
@@ -821,6 +902,79 @@ namespace Tizen.NUI.BaseComponents
             /// <since_tizen> 7 </since_tizen>
             AutoReverse
         }
+
+        /// <summary>
+        /// Vector Property
+        /// </summary>
+        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public enum VectorProperty
+        {
+            /// <summary>
+            /// Fill color of the object, Type of <see cref="Vector3"/>
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            FillColor,
+
+            /// <summary>
+            /// Fill opacity of the object, Type of float
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            FillOpacity,
+
+            /// <summary>
+            /// Stroke color of the object, Type of <see cref="Vector3"/>
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            StrokeColor,
+
+            /// <summary>
+            /// Stroke opacity of the object, Type of float
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            StrokeOpacity,
+
+            /// <summary>
+            /// Stroke width of the object, Type of float
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            StrokeWidth,
+
+            /// <summary>
+            /// Transform anchor of the Layer and Group object, Type of <see cref="Vector2"/>
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            TransformAnchor,
+
+            /// <summary>
+            /// Transform position of the Layer and Group object, Type of <see cref="Vector2"/>
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            TransformPosition,
+
+            /// <summary>
+            /// Transform scale of the Layer and Group object, Type of <see cref="Vector2"/>, Value range of [0..100]
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            TransformScale,
+
+            /// <summary>
+            /// Transform rotation of the Layer and Group object, Type of float, Value range of [0..360] in degrees
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            TransformRotation,
+
+            /// <summary>
+            /// Transform opacity of the Layer and Group object, Type of float
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            TransformOpacity
+        };
+
+        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        public delegate PropertyValue DynamicPropertyCallbackType(int returnType, uint frameNumber);
         #endregion Event, Enum, Struct, ETC
 
 
@@ -846,23 +1000,30 @@ namespace Tizen.NUI.BaseComponents
                 if (visualEventSignalHandler == null)
                 {
                     visualEventSignalCallback = onVisualEventSignal;
-                    VisualEventSignal().Connect(visualEventSignalCallback);
+                    using VisualEventSignal visualEvent = VisualEventSignal();
+                    visualEvent?.Connect(visualEventSignalCallback);
                 }
                 visualEventSignalHandler += value;
             }
             remove
             {
                 visualEventSignalHandler -= value;
-                if (visualEventSignalHandler == null && VisualEventSignal().Empty() == false)
+                if (visualEventSignalHandler == null && visualEventSignalCallback != null)
                 {
-                    VisualEventSignal().Disconnect(visualEventSignalCallback);
+                    using VisualEventSignal visualEvent = VisualEventSignal();
+                    visualEvent?.Disconnect(visualEventSignalCallback);
+                    if (visualEvent?.Empty() == true)
+                    {
+                        visualEventSignalCallback = null;
+                    }
                 }
             }
         }
 
         internal void EmitVisualEventSignal(int visualIndex, int signalId)
         {
-            VisualEventSignal().Emit(this, visualIndex, signalId);
+            using VisualEventSignal visualEvent = VisualEventSignal();
+            visualEvent?.Emit(this, visualIndex, signalId);
         }
 
         internal VisualEventSignal VisualEventSignal()
@@ -871,6 +1032,91 @@ namespace Tizen.NUI.BaseComponents
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
             return ret;
         }
+
+        internal Dictionary<int, DynamicPropertyCallbackType> InternalSavedDynamicPropertyCallbacks = new Dictionary<int, DynamicPropertyCallbackType>();
+
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void RootCallbackType(int id, int returnType, uint frameNumber, ref float val1, ref float val2, ref float val3);
+
+        internal RootCallbackType rootCallback = RootCallback;
+
+        static internal void RootCallback(int id, int returnType, uint frameNumber, ref float val1, ref float val2, ref float val3)
+        {
+            WeakReference<LottieAnimationView> current = null;
+            LottieAnimationView currentView = null;
+            DynamicPropertyCallbackType currentCallback = null;
+            PropertyValue ret = null;
+
+            if (weakReferencesOfLottie.TryGetValue(id, out current))
+            {
+                if (current.TryGetTarget(out currentView))
+                {
+                    if (currentView.InternalSavedDynamicPropertyCallbacks.TryGetValue(id, out currentCallback) && currentView != null
+                        && currentView.InternalSavedDynamicPropertyCallbacks != null)
+                    {
+                        ret = currentCallback?.Invoke(returnType, frameNumber);
+                    }
+                    else
+                    {
+                        Tizen.Log.Error("NUI", "can't find the callback in LottieAnimationView, just return here!");
+                        return;
+                    }
+                }
+                else
+                {
+                    Tizen.Log.Error("NUI", "can't find the callback in LottieAnimationView, just return here!");
+                    return;
+                }
+            }
+            else
+            {
+                Tizen.Log.Error("NUI", "can't find LottieAnimationView by id, just return here!");
+                return;
+            }
+
+            switch (returnType)
+            {
+                case (int)(VectorProperty.FillColor):
+                case (int)(VectorProperty.StrokeColor):
+                    Vector3 tmpVector3 = new Vector3(-1, -1, -1);
+                    if (ret.Get(tmpVector3))
+                    {
+                        val1 = tmpVector3.X;
+                        val2 = tmpVector3.Y;
+                        val3 = tmpVector3.Z;
+                    }
+                    tmpVector3.Dispose();
+                    break;
+
+                case (int)(VectorProperty.TransformAnchor):
+                case (int)(VectorProperty.TransformPosition):
+                case (int)(VectorProperty.TransformScale):
+                    Vector2 tmpVector2 = new Vector2(-1, -1);
+                    if (ret.Get(tmpVector2))
+                    {
+                        val1 = tmpVector2.X;
+                        val2 = tmpVector2.Y;
+                    }
+                    tmpVector2.Dispose();
+                    break;
+
+                case (int)(VectorProperty.FillOpacity):
+                case (int)(VectorProperty.StrokeOpacity):
+                case (int)(VectorProperty.StrokeWidth):
+                case (int)(VectorProperty.TransformRotation):
+                case (int)(VectorProperty.TransformOpacity):
+                    float tmpFloat = -1;
+                    if (ret.Get(out tmpFloat))
+                    {
+                        val1 = tmpFloat;
+                    }
+                    break;
+                default:
+                    //do nothing
+                    break;
+            }
+            ret.Dispose();
+        }
         #endregion Internal
 
 
@@ -942,6 +1188,10 @@ namespace Tizen.NUI.BaseComponents
         private VisualEventSignalCallbackType visualEventSignalCallback;
         private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
 
+        static private int dynamicPropertyCallbackId = 0;
+        //static private Dictionary<int, DynamicPropertyCallbackType> dynamicPropertyCallbacks = new Dictionary<int, DynamicPropertyCallbackType>();
+        static private Dictionary<int, WeakReference<LottieAnimationView>> weakReferencesOfLottie = new Dictionary<int, WeakReference<LottieAnimationView>>();
+
         private void debugPrint()
         {
             NUILog.Debug($"===================================");
@@ -950,6 +1200,7 @@ namespace Tizen.NUI.BaseComponents
             NUILog.Debug($"  RedrawInScalingDown={RedrawInScalingDown} >");
             NUILog.Debug($"===================================");
         }
+
         #endregion Private
     }
 
@@ -1068,6 +1319,7 @@ namespace Tizen.NUI.BaseComponents
         /// <param name="lottieView">The target LottieAnimationView to play.</param>
         /// <param name="noPlay">Whether go direct to the EndFrame. It is false by default.</param>
         [EditorBrowsable(EditorBrowsableState.Never)]
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062: Validate arguments of public methods", Justification = "The null checking is done by BeReadyToShow()")]
         public void Show(LottieAnimationView lottieView, bool noPlay = false)
         {
             if (!BeReadyToShow(lottieView))
@@ -1109,4 +1361,58 @@ namespace Tizen.NUI.BaseComponents
             return true;
         }
     }
+
+    // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public struct LottieAnimationViewDynamicProperty : IEquatable<LottieAnimationViewDynamicProperty>
+    {
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string KeyPath { get; set; }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public LottieAnimationView.VectorProperty Property { get; set; }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public LottieAnimationView.DynamicPropertyCallbackType Callback { get; set; }
+
+        public override bool Equals(object obj)
+        {
+            if (obj is LottieAnimationViewDynamicProperty target)
+            {
+                if (KeyPath == target.KeyPath && Property == target.Property && Callback == target.Callback)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        public static bool operator ==(LottieAnimationViewDynamicProperty left, LottieAnimationViewDynamicProperty right)
+        {
+            return left.Equals(right);
+        }
+
+        public static bool operator !=(LottieAnimationViewDynamicProperty left, LottieAnimationViewDynamicProperty right)
+        {
+            return !(left == right);
+        }
+
+        public bool Equals(LottieAnimationViewDynamicProperty other)
+        {
+            if (other != null)
+            {
+                if (KeyPath == other.KeyPath && Property == other.Property && Callback == other.Callback)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
 }
index e6e2c07..2e176cd 100755 (executable)
@@ -680,6 +680,23 @@ namespace Tizen.NUI
         }
 
         /// <summary>
+        /// Retrieves a map property value.
+        /// </summary>
+        /// <param name="mapValue">On return, the map as vector of string and property value pairs.</param>
+        /// <returns>Returns true if the value is successfully retrieved, false if the type is not convertible.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool Get(ref PropertyMap mapValue)
+        {
+            if (mapValue == null)
+            {
+                return false;
+            }
+            bool ret = Interop.PropertyValue.GetMap(SwigCPtr, mapValue.SwigCPtr);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+        /// <summary>
         /// Retrieves a Extents value.
         /// </summary>
         /// <param name="extentsValue">On return, a extents.</param>
index 09ee2be..70a3157 100755 (executable)
@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29613.14
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.32414.318
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI.Samples", "Tizen.NUI.Samples\Tizen.NUI.Samples.csproj", "{B2EC3963-C77F-4D1A-9387-8BA0DB298266}"
 EndProject
@@ -37,6 +37,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.ThemeMan
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI.Extension", "..\..\src\Tizen.NUI.Extension\Tizen.NUI.Extension.csproj", "{47829CA1-0E21-4687-9ABB-0C27E1A67E85}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Tracer", "..\..\src\Tizen.Tracer\Tizen.Tracer.csproj", "{A0AA9346-2025-4803-A168-3B39A367BB92}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI.Scene3D", "..\..\src\Tizen.NUI.Scene3D\Tizen.NUI.Scene3D.csproj", "{C5BFC65A-91D1-424E-BEC4-4A40329DA185}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -111,6 +115,14 @@ Global
                {47829CA1-0E21-4687-9ABB-0C27E1A67E85}.Debug|Any CPU.Build.0 = Debug|Any CPU
                {47829CA1-0E21-4687-9ABB-0C27E1A67E85}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {47829CA1-0E21-4687-9ABB-0C27E1A67E85}.Release|Any CPU.Build.0 = Release|Any CPU
+               {A0AA9346-2025-4803-A168-3B39A367BB92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {A0AA9346-2025-4803-A168-3B39A367BB92}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {A0AA9346-2025-4803-A168-3B39A367BB92}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {A0AA9346-2025-4803-A168-3B39A367BB92}.Release|Any CPU.Build.0 = Release|Any CPU
+               {C5BFC65A-91D1-424E-BEC4-4A40329DA185}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {C5BFC65A-91D1-424E-BEC4-4A40329DA185}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {C5BFC65A-91D1-424E-BEC4-4A40329DA185}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {C5BFC65A-91D1-424E-BEC4-4A40329DA185}.Release|Any CPU.Build.0 = Release|Any CPU
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/LottieAnimationViewDynamicPropertyTest.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/LottieAnimationViewDynamicPropertyTest.cs
new file mode 100644 (file)
index 0000000..d3da7c2
--- /dev/null
@@ -0,0 +1,271 @@
+
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Samples
+{
+    using tlog = Tizen.Log;
+    public class LottieAnimationViewDynamicPropertyTest : IExample
+    {
+
+        const int NUM_OF_VIEW = 5;
+        const int TIMER_INTERVAL = 3000;
+        const string tag = "NUITEST";
+        Window win;
+        View root;
+        Timer timer;
+        public void Activate()
+        {
+            win = NUIApplication.GetDefaultWindow();
+
+            root = new View()
+            {
+                Size = new Size(win.Size.Width, win.Size.Height, 0),
+                BackgroundColor = Color.Yellow,
+                Layout = new LinearLayout()
+                {
+                    LinearOrientation = LinearLayout.Orientation.Horizontal,
+                },
+            };
+            win.Add(root);
+
+            timer = new Timer(TIMER_INTERVAL);
+            timer.Tick += OnTick;
+            timer.Start();
+        }
+
+        int cnt;
+        bool OnTick(object sender, Timer.TickEventArgs e)
+        {
+            bool ret = false;
+            //ret = Test1();
+            //ret = Test2();
+            ret = Test3();
+            return ret;
+        }
+
+        //create objects => explicit dispose => create objects => implicit dispose
+        bool Test1()
+        {
+            switch (cnt % 4)
+            {
+                case 0:
+                    MakeAll();
+                    break;
+                case 1:
+                    DisposeAll();
+                    break;
+                case 2:
+                    MakeAll();
+                    break;
+                case 3:
+                    ImplicitDispose();
+                    break;
+                default:
+                    DisposeAll();
+                    break;
+            }
+            cnt++;
+            return true;
+        }
+
+        //create objects => implicit dispose => force full GC
+        bool Test2()
+        {
+            switch (cnt % 3)
+            {
+                case 0:
+                    MakeAll();
+                    break;
+                case 1:
+                    ImplicitDispose();
+                    break;
+                case 2:
+                    ForceFullGC();
+                    break;
+                default:
+                    DisposeAll();
+                    break;
+            }
+            cnt++;
+            return true;
+        }
+
+        global::System.Random rand = new global::System.Random();
+        bool Test3()
+        {
+            var lav = new LottieAnimationView();
+            lav.Size2D = new Size2D(300, 300);
+            lav.Position2D = new Position2D(rand.Next(10, 1000), rand.Next(10, 1000));
+            if (cnt++ % 2 == 0)
+            {
+                lav.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "a.json";
+            }
+            else
+            {
+                lav.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "done.json";
+            }
+            lav.LoopCount = -1;
+            lav.BackgroundColor = Color.White;
+            win.Add(lav);
+            lav.Play();
+
+            var ret = lav.GetContentInfo();
+            tlog.Fatal(tag, $"ret.Count {ret.Count}");
+            foreach (var item in ret)
+            {
+                tlog.Fatal(tag, $"item:({item.Item1}, {item.Item2}, {item.Item3})");
+            }
+            return true;
+        }
+
+        void ForceFullGC()
+        {
+            tlog.Debug(tag, "ForceFullGC start");
+            global::System.GC.Collect();
+            global::System.GC.WaitForPendingFinalizers();
+            global::System.GC.Collect();
+            tlog.Debug(tag, "ForceFullGC end");
+        }
+
+        void MakeAll()
+        {
+            tlog.Debug(tag, $"MakeAll() start");
+            int width = (int)(root.Size.Width / NUM_OF_VIEW);
+            for (int i = 0; i < NUM_OF_VIEW; i++)
+            {
+                var lav = new LottieAnimationView();
+                lav.Size2D = new Size2D(width, width);
+                lav.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "done.json";
+                lav.LoopCount = -1;
+                lav.BackgroundColor = Color.White;
+                root.Add(lav);
+
+                LottieAnimationViewDynamicProperty pro = new LottieAnimationViewDynamicProperty
+                {
+                    KeyPath = "Shape Layer 1.Ellipse 1.Fill 1",
+                    Property = LottieAnimationView.VectorProperty.FillColor,
+                    Callback = new Tizen.NUI.BaseComponents.LottieAnimationView.DynamicPropertyCallbackType(OnFillColor),
+                };
+
+                if (i % 1 == 0)
+                {
+                    lav.DoActionExtension(pro);
+                }
+
+                if (i % 2 == 0)
+                {
+                    pro.KeyPath = "**";
+                    pro.Property = LottieAnimationView.VectorProperty.StrokeColor;
+                    pro.Callback = new Tizen.NUI.BaseComponents.LottieAnimationView.DynamicPropertyCallbackType(OnStrokColor);
+                    lav.DoActionExtension(pro);
+                }
+
+                if (i % 3 == 0)
+                {
+                    pro.KeyPath = "**";
+                    pro.Property = LottieAnimationView.VectorProperty.StrokeWidth;
+                    pro.Callback = new Tizen.NUI.BaseComponents.LottieAnimationView.DynamicPropertyCallbackType(OnStrokWidth);
+                    lav.DoActionExtension(pro);
+                }
+
+                if (i % 4 == 0)
+                {
+                    pro.KeyPath = "Shape Layer 2.Shape 1";
+                    pro.Property = LottieAnimationView.VectorProperty.TransformRotation;
+                    pro.Callback = new Tizen.NUI.BaseComponents.LottieAnimationView.DynamicPropertyCallbackType(OnTransformRotation);
+                    lav.DoActionExtension(pro);
+                }
+                lav.Play();
+            }
+            tlog.Debug(tag, $"MakeAll() end");
+        }
+
+        void DisposeAll()
+        {
+            tlog.Debug(tag, $"DisposeAll() start");
+            int childNum = (int)root.ChildCount;
+            for (int i = childNum - 1; i >= 0; i--)
+            {
+                var child = root.GetChildAt((uint)i);
+                if (child != null)
+                {
+                    child.Unparent();
+                    child.Dispose();
+                }
+            }
+            tlog.Debug(tag, $"DisposeAll() end");
+        }
+
+        void ImplicitDispose()
+        {
+            tlog.Debug(tag, $"ImplicitDispose() start");
+            int childNum = (int)root.ChildCount;
+            for (int i = childNum - 1; i >= 0; i--)
+            {
+                var child = root.GetChildAt((uint)i);
+                if (child != null)
+                {
+                    child.Unparent();
+                }
+            }
+            tlog.Debug(tag, $"ImplicitDispose() end");
+        }
+
+        private PropertyValue OnFillColor(int returnType, uint frameNumber)
+        {
+            tlog.Debug(tag, $"OnFillColor() returnType={returnType} frameNumber={frameNumber}");
+            if (frameNumber < 60)
+            {
+                return new PropertyValue(new Vector3(0, 0, 1));
+            }
+            else
+            {
+                return new PropertyValue(new Vector3(1, 0, 0));
+            }
+        }
+
+        private PropertyValue OnStrokColor(int returnType, uint frameNumber)
+        {
+            tlog.Debug(tag, $"OnStrokColor() returnType={returnType} frameNumber={frameNumber}");
+            if (frameNumber < 60)
+            {
+                return new PropertyValue(new Vector3(1, 0, 1));
+            }
+            else
+            {
+                return new PropertyValue(new Vector3(1, 1, 0));
+            }
+        }
+
+        private PropertyValue OnStrokWidth(int returnType, uint frameNumber)
+        {
+            tlog.Debug(tag, $"OnStrokWidth() returnType={returnType} frameNumber={frameNumber}");
+
+            if (frameNumber < 60)
+            {
+                return new PropertyValue(2.0f);
+            }
+            else
+            {
+                return new PropertyValue(5.0f);
+            }
+        }
+
+        private PropertyValue OnTransformRotation(int returnType, uint frameNumber)
+        {
+            tlog.Debug(tag, $"OnTransformRotation() returnType={returnType} frameNumber={frameNumber}");
+
+            return new PropertyValue(frameNumber * 20.0f);
+        }
+
+        public void Deactivate()
+        {
+            root.Unparent();
+            timer.Stop();
+            DisposeAll();
+            root.Dispose();
+        }
+    }
+}
diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/done.json b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/done.json
new file mode 100644 (file)
index 0000000..a4b1196
--- /dev/null
@@ -0,0 +1 @@
+{"v":"4.11.1","fr":29.9700012207031,"ip":0,"op":76.0000030955435,"w":70,"h":70,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[35,35,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":33,"s":[0,0,100],"e":[120,120,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":46,"s":[120,120,100],"e":[100,100,100]},{"t":52.0000021180034}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-7,1.438],[-2.656,5.781],[7.422,-4.297]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":33,"s":[0],"e":[100]},{"t":52.0000021180034}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":450.000018328876,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[35,35,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":18,"s":[0,0,100],"e":[120,120,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":33,"s":[120,120,100],"e":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":41,"s":[80,80,100],"e":[110,110,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":49,"s":[110,110,100],"e":[100,100,100]},{"t":52.0000021180034}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[13.015,0],[0,-13.015],[-13.015,0],[0,13.015]],"o":[[-13.015,0],[0,13.015],[13.015,0],[0,-13.015]],"v":[[0,-23.566],[-23.566,0],[0,23.566],[23.566,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.898039215686,0.898039215686,0.898039215686,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.760784313725,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[105.535,105.535],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":450.000018328876,"st":0,"bm":0}]}
\ No newline at end of file