[NUI] Fix ImageView.Image property bugs + Make AnimatedImageView use LazyUpdate.
authorEunki, Hong <eunkiki.hong@samsung.com>
Wed, 2 Mar 2022 14:05:43 +0000 (23:05 +0900)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Tue, 22 Mar 2022 08:34:14 +0000 (17:34 +0900)
Previous LazyUpdate feature have some bugs when we try to get ImageView.Image.
That API get from native engine side properies forcely.
But actually, we didn't send our NUI cached local properties before get from native engine.
So the result value was not matched what we expected want to get.

and also, LazyUpdate feature have some bugs when we call 'Play', 'Stop', etc.

This patch UpdateImage properties synchronously when we call these
AnimationAction API.

Furthermore, Make AnimatedImageView (which already use LazyUpdate feature internally)
also use LazyUpdate feature.

We cannot know URLs Property changeness. so keep a way to properties setup forcely.

Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
src/Tizen.NUI/src/public/BaseComponents/AnimatedImageView.cs
src/Tizen.NUI/src/public/BaseComponents/AnimatedImageViewBindableProperty.cs
src/Tizen.NUI/src/public/BaseComponents/ImageView.cs
src/Tizen.NUI/src/public/BaseComponents/ImageViewBindableProperty.cs
test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/res/dali-logo-anim.gif [new file with mode: 0644]
test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/testcase/TSAnimatedImageView.cs [new file with mode: 0644]
test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/testcase/TSImageView.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/AnimatedImageViewTest.cs

index 7afe68f..c5d3406 100755 (executable)
@@ -31,15 +31,15 @@ namespace Tizen.NUI.BaseComponents
         #endregion Internal
 
         #region Private
-        private string url = "";
+        // Collection of animated-image-sensitive properties.
+        private static readonly List<int> cachedAnimatedImagePropertyKeyList = new List<int> {
+            ImageVisualProperty.BatchSize,
+            ImageVisualProperty.CacheSize,
+            ImageVisualProperty.FrameDelay,
+            ImageVisualProperty.LoopCount,
+            ImageVisualProperty.StopBehavior,
+        };
         private List<string> resourceURLs = new List<string>();
-        private int batchSize = 1;
-        private int cacheSize = 1;
-        private int frameDelay = 0;
-        private int loopCount = -1;
-        private bool dirtyFlag = false;
-        private StopBehaviorType stopBehavior;
-        private PropertyMap propertyMap;
         #endregion Private
 
         #region Constructor, Destructor, Dispose
@@ -53,8 +53,6 @@ namespace Tizen.NUI.BaseComponents
             ActionPlay = Interop.AnimatedImageView.AnimatedImageVisualActionPlayGet();
             ActionPause = Interop.AnimatedImageView.AnimatedImageVisualActionPauseGet();
             ActionStop = Interop.AnimatedImageView.AnimatedImageVisualActionStopGet();
-    
-            dirtyFlag = true;
         }
 
         /// <summary>
@@ -79,37 +77,6 @@ namespace Tizen.NUI.BaseComponents
 
         #region Property
         /// <summary>
-        /// Image URL for Animated-GIF
-        /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public new string ResourceUrl
-        {
-            get
-            {
-                return GetValue(ResourceUrlProperty) as string;
-            }
-            set
-            {
-                SetValue(ResourceUrlProperty, value);
-                NotifyPropertyChanged();
-            }
-        }
-
-        private string InternalResourceUrl
-        {
-            get
-            {
-                return url;
-            }
-            set
-            {
-                dirtyFlag = true;
-                url = value;
-            }
-        }
-
-        /// <summary>
         ///  Image URL list for Image-Array
         /// </summary>
         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
@@ -145,12 +112,18 @@ namespace Tizen.NUI.BaseComponents
         {
             get
             {
-                return batchSize;
+                int ret = 1;
+
+                PropertyValue batchSize = GetCachedImageVisualProperty(ImageVisualProperty.BatchSize);
+                batchSize?.Get(out ret);
+                batchSize?.Dispose();
+
+                return ret;
             }
             set
             {
-                dirtyFlag = true;
-                batchSize = value;
+                using PropertyValue setValue = new PropertyValue(value);
+                UpdateImage(ImageVisualProperty.BatchSize, setValue);
             }
         }
 
@@ -181,12 +154,18 @@ namespace Tizen.NUI.BaseComponents
         {
             get
             {
-                return cacheSize;
+                int ret = 1;
+
+                PropertyValue cacheSize = GetCachedImageVisualProperty(ImageVisualProperty.CacheSize);
+                cacheSize?.Get(out ret);
+                cacheSize?.Dispose();
+
+                return ret;
             }
             set
             {
-                dirtyFlag = true;
-                cacheSize = value;
+                using PropertyValue setValue = new PropertyValue(value);
+                UpdateImage(ImageVisualProperty.CacheSize, setValue);
             }
         }
 
@@ -216,12 +195,18 @@ namespace Tizen.NUI.BaseComponents
         {
             get
             {
-                return frameDelay;
+                int ret = 0;
+
+                PropertyValue frameDelay = GetCachedImageVisualProperty(ImageVisualProperty.FrameDelay);
+                frameDelay?.Get(out ret);
+                frameDelay?.Dispose();
+
+                return ret;
             }
             set
             {
-                dirtyFlag = true;
-                frameDelay = value;
+                using PropertyValue setValue = new PropertyValue(value);
+                UpdateImage(ImageVisualProperty.FrameDelay, setValue);
             }
         }
 
@@ -247,12 +232,18 @@ namespace Tizen.NUI.BaseComponents
         {
             get
             {
-                return loopCount;
+                int ret = -1;
+
+                PropertyValue loopCount = GetCachedImageVisualProperty(ImageVisualProperty.LoopCount);
+                loopCount?.Get(out ret);
+                loopCount?.Dispose();
+
+                return ret;
             }
             set
             {
-                dirtyFlag = true;
-                loopCount = value;
+                using PropertyValue setValue = new PropertyValue(value);
+                UpdateImage(ImageVisualProperty.LoopCount, setValue);
             }
         }
 
@@ -275,14 +266,20 @@ namespace Tizen.NUI.BaseComponents
 
         private StopBehaviorType InternalStopBehavior
         {
-            set
+            get
             {
-                stopBehavior = (StopBehaviorType)value;
-                dirtyFlag = true;
+                int ret = 0;
+
+                PropertyValue stopBehavior = GetCachedImageVisualProperty(ImageVisualProperty.StopBehavior);
+                stopBehavior?.Get(out ret);
+                stopBehavior?.Dispose();
+
+                return (StopBehaviorType)ret;
             }
-            get
+            set
             {
-                return stopBehavior;
+                using PropertyValue setValue = new PropertyValue((int)value);
+                UpdateImage(ImageVisualProperty.StopBehavior, setValue);
             }
         }
 
@@ -335,6 +332,9 @@ namespace Tizen.NUI.BaseComponents
         {
             set
             {
+                // Sync as current properties
+                UpdateImage();
+
                 DoAction(ImageView.Property.IMAGE, ActionJumpTo, new PropertyValue(value));
             }
             get
@@ -372,101 +372,76 @@ namespace Tizen.NUI.BaseComponents
         [EditorBrowsable(EditorBrowsableState.Never)]
         public void SetValues()
         {
-            if (dirtyFlag == false)
-            {
-                return;
-            }
-            dirtyFlag = false;
+            // This API assume that Animated relative properties setuped forcely.
+            imagePropertyUpdatedFlag = true;
 
-            PropertyMap tMap = new PropertyMap();
-            PropertyValue animatiedImage = new PropertyValue((int)Visual.Type.AnimatedImage);
-            tMap.Insert(Visual.Property.Type, animatiedImage);
-            if (resourceURLs?.Count != 0)
-            {
-                PropertyArray indexPropertyArray = new PropertyArray();
-                PropertyArray returnedArr = new PropertyArray();
-                PropertyValue index = new PropertyValue();
-                foreach (var iter in resourceURLs)
-                {
-                    index = new PropertyValue(iter);
-                    returnedArr = indexPropertyArray.Add(index);
-                }
-                index.Dispose();
-                returnedArr.Dispose();
-                PropertyValue arrayProperty = new PropertyValue(indexPropertyArray);
-                tMap.Insert(ImageVisualProperty.URL, arrayProperty);
-                PropertyValue frameDelayProperty = new PropertyValue(frameDelay);
-                tMap.Insert(ImageVisualProperty.FrameDelay, frameDelayProperty);
-
-                arrayProperty.Dispose();
-                indexPropertyArray.Dispose();
-                frameDelayProperty.Dispose();
-            }
-            else
-            {
-                PropertyValue urlProperty = new PropertyValue(url);
-                tMap.Insert(ImageVisualProperty.URL, urlProperty);
-                urlProperty.Dispose();
-            }
-
-            PropertyValue batchSizeProperty = new PropertyValue(batchSize);
-            tMap.Insert(ImageVisualProperty.BatchSize, batchSizeProperty);
-            PropertyValue cacheSizeProperty = new PropertyValue(cacheSize);
-            tMap.Insert(ImageVisualProperty.CacheSize, cacheSizeProperty);
-            PropertyValue loopCountProperty = new PropertyValue(loopCount);
-            tMap.Insert(ImageVisualProperty.LoopCount, loopCountProperty);
-            PropertyValue stopBehaviorProperty = new PropertyValue((int)stopBehavior);
-            tMap.Insert(ImageVisualProperty.StopBehavior, stopBehaviorProperty);
-
-            loopCountProperty.Dispose();
-            cacheSizeProperty.Dispose();
-            batchSizeProperty.Dispose();
-            stopBehaviorProperty.Dispose();
-
-            propertyMap = tMap;
-            PropertyValue mapProperty = new PropertyValue(propertyMap);
-            SetProperty(ImageView.Property.IMAGE, mapProperty);
-            mapProperty.Dispose();
-
-            tMap.Dispose();
-            animatiedImage.Dispose();
+            // Sync as current properties
+            UpdateImage();
         }
 
         /// <summary>
-        /// Play animation
+        /// Update animated-image-relative properties synchronously.
+        /// After call this API, All image properties updated.
         /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public new void Play()
+        protected override void UpdateImage()
         {
-            SetValues();
-            base.Play();
-        }
+            if(!imagePropertyUpdatedFlag) return;
 
-        /// <summary>
-        /// Pause animation. Currently pause and stop are same
-        /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public new void Pause()
-        {
-            SetValues();
-            base.Pause();
+            if (resourceURLs?.Count != 0)
+            {
+                using(PropertyArray indexPropertyArray = new PropertyArray())
+                {
+                    PropertyArray returnedArr = new PropertyArray();
+                    foreach (var iter in resourceURLs)
+                    {
+                        using(PropertyValue index = new PropertyValue(iter))
+                        {
+                            returnedArr = indexPropertyArray.Add(index);
+                        }
+                    }
+                    returnedArr.Dispose();
+                    using PropertyValue arrayProperty = new PropertyValue(indexPropertyArray);
+
+                    // Trigger the ImageView so that we have something update
+                    UpdateImage(ImageVisualProperty.URL, arrayProperty);
+                }
+            }
+
+            using PropertyValue animatiedImage = new PropertyValue((int)Visual.Type.AnimatedImage);
+            UpdateImage(Visual.Property.Type, animatiedImage);
+
+            base.UpdateImage();
         }
 
         /// <summary>
-        /// Stop animation. Currently pause and stop are same
+        /// Update NUI cached animated image visual property map by inputed property map.
+        /// And call base.MergeCachedImageVisualProperty()
         /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+        /// <remarks>
+        /// For performance issue, we will collect only "cachedAnimatedImagePropertyKeyList" hold in this class.
+        /// </remarks>
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public new void Stop()
+        protected override void MergeCachedImageVisualProperty(PropertyMap map)
         {
-            SetValues();
-            base.Stop();
+            if(map == null) return;
+            if(cachedImagePropertyMap == null)
+            {
+                cachedImagePropertyMap = new PropertyMap();
+            }
+            foreach(var key in cachedAnimatedImagePropertyKeyList)
+            {
+                PropertyValue value = map.Find(key);
+                if(value != null)
+                {
+                    // Update-or-Insert new value
+                    cachedImagePropertyMap[key] = value;
+                }
+            }
+            base.MergeCachedImageVisualProperty(map);
         }
         #endregion Method
 
-
         #region Event, Enum, Struct, ETC
 
         /// <summary>
index fcb0380..804e5d4 100755 (executable)
@@ -23,24 +23,6 @@ namespace Tizen.NUI.BaseComponents
     public partial class AnimatedImageView
     {
         /// <summary>
-        /// ResourceUrlProperty
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public static new readonly BindableProperty ResourceUrlProperty = BindableProperty.Create(nameof(ResourceUrl), typeof(string), typeof(AnimatedImageView), string.Empty, propertyChanged: (bindable, oldValue, newValue) =>
-        {
-            var instance = (Tizen.NUI.BaseComponents.AnimatedImageView)bindable;
-            if (newValue != null)
-            {
-                instance.InternalResourceUrl = (string)newValue;
-            }
-        },
-        defaultValueCreator: (bindable) =>
-        {
-            var instance = (Tizen.NUI.BaseComponents.AnimatedImageView)bindable;
-            return instance.InternalResourceUrl;
-        });
-
-        /// <summary>
         /// BatchSizeProperty
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
index 44ea173..83916fb 100755 (executable)
@@ -15,6 +15,7 @@
 *
 */
 using System;
+using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.ComponentModel;
 using Tizen.NUI.Binding;
@@ -37,9 +38,26 @@ namespace Tizen.NUI.BaseComponents
         private _resourceLoadedCallbackType _resourceLoadedCallback;
 
         // Collection of image-sensitive properties.
-        private bool _imagePropertyUpdatedFlag = false;
-        private bool _imagePropertyUpdateProcessAttachedFlag = false;
-        private PropertyMap _imagePropertyMap;
+        private static readonly List<int> cachedImagePropertyKeyList = new List<int> {
+            Visual.Property.Type,
+            ImageVisualProperty.URL,
+            ImageVisualProperty.AlphaMaskURL,
+            ImageVisualProperty.CropToMask,
+            Visual.Property.VisualFittingMode,
+            ImageVisualProperty.DesiredWidth,
+            ImageVisualProperty.DesiredHeight,
+            ImageVisualProperty.ReleasePolicy,
+            ImageVisualProperty.WrapModeU,
+            ImageVisualProperty.WrapModeV,
+            ImageVisualProperty.SynchronousLoading,
+            ImageVisualProperty.OrientationCorrection,
+            NpatchImageVisualProperty.Border,
+            NpatchImageVisualProperty.BorderOnly,
+        };
+        internal PropertyMap cachedImagePropertyMap;
+        internal bool imagePropertyUpdatedFlag = false;
+
+        private bool imagePropertyUpdateProcessAttachedFlag = false;
         private Rectangle _border;
         private string _resourceUrl = "";
         private int _desired_width = -1;
@@ -260,12 +278,20 @@ namespace Tizen.NUI.BaseComponents
             {
                 if (_border == null)
                 {
+                    // Sync as current properties
+                    UpdateImage();
+
                     // Get current properties force.
-                    // TODO: Need to make some flag that we only need cached property map.
                     PropertyMap returnValue = new PropertyMap();
                     PropertyValue image = GetProperty(ImageView.Property.IMAGE);
                     image?.Get(returnValue);
                     image?.Dispose();
+
+                    // Update cached property map
+                    if(returnValue != null)
+                    {
+                        MergeCachedImageVisualProperty(returnValue);
+                    }
                     return returnValue;
                 }
                 else
@@ -279,14 +305,13 @@ namespace Tizen.NUI.BaseComponents
                 {
                     PropertyValue setValue = new Tizen.NUI.PropertyValue(value);
                     SetProperty(ImageView.Property.IMAGE, setValue);
+
                     // Image properties are changed hardly. We should ignore lazy UpdateImage
-                    _imagePropertyUpdatedFlag = false;
-                    _imagePropertyMap?.Dispose();
-                    _imagePropertyMap = null;
-                    if(value != null)
-                    {
-                        _imagePropertyMap = new PropertyMap(value);
-                    }
+                    imagePropertyUpdatedFlag = false;
+                    cachedImagePropertyMap?.Dispose();
+                    cachedImagePropertyMap = null;
+                    MergeCachedImageVisualProperty(value);
+
                     NotifyPropertyChanged();
                     setValue?.Dispose();
                 }
@@ -564,6 +589,9 @@ namespace Tizen.NUI.BaseComponents
         /// <since_tizen> 5 </since_tizen>
         public void Reload()
         {
+            // Sync as current properties
+            UpdateImage();
+
             PropertyValue attributes = new PropertyValue(0);
             this.DoAction(ImageView.Property.IMAGE, ActionReload, attributes);
             attributes?.Dispose();
@@ -575,6 +603,9 @@ namespace Tizen.NUI.BaseComponents
         /// <since_tizen> 5 </since_tizen>
         public void Play()
         {
+            // Sync as current properties
+            UpdateImage();
+
             PropertyValue attributes = new PropertyValue(0);
             this.DoAction(ImageView.Property.IMAGE, ActionPlay, attributes);
             attributes?.Dispose();
@@ -586,6 +617,9 @@ namespace Tizen.NUI.BaseComponents
         /// <since_tizen> 5 </since_tizen>
         public void Pause()
         {
+            // Sync as current properties
+            UpdateImage();
+
             PropertyValue attributes = new PropertyValue(0);
             this.DoAction(ImageView.Property.IMAGE, ActionPause, attributes);
             attributes?.Dispose();
@@ -597,6 +631,9 @@ namespace Tizen.NUI.BaseComponents
         /// <since_tizen> 5 </since_tizen>
         public void Stop()
         {
+            // Sync as current properties
+            UpdateImage();
+
             PropertyValue attributes = new PropertyValue(0);
             this.DoAction(ImageView.Property.IMAGE, ActionStop, attributes);
             attributes?.Dispose();
@@ -627,7 +664,7 @@ namespace Tizen.NUI.BaseComponents
             {
                 string ret = "";
 
-                PropertyValue maskUrl = _imagePropertyMap?.Find(ImageVisualProperty.AlphaMaskURL);
+                PropertyValue maskUrl = GetCachedImageVisualProperty(ImageVisualProperty.AlphaMaskURL);
                 maskUrl?.Get(out ret);
                 maskUrl?.Dispose();
 
@@ -638,7 +675,7 @@ namespace Tizen.NUI.BaseComponents
                 PropertyValue setValue = new PropertyValue(value ?? "");
                 UpdateImage(ImageVisualProperty.AlphaMaskURL, setValue);
                 // When we never set CropToMask property before, we should set default value as true.
-                using(PropertyValue cropToMask = _imagePropertyMap?.Find(ImageVisualProperty.CropToMask))
+                using(PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask))
                 {
                     if(cropToMask == null)
                     {
@@ -673,7 +710,7 @@ namespace Tizen.NUI.BaseComponents
             {
                 bool ret = false;
 
-                PropertyValue cropToMask = _imagePropertyMap?.Find(ImageVisualProperty.CropToMask);
+                PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask);
                 cropToMask?.Get(out ret);
                 cropToMask?.Dispose();
 
@@ -787,7 +824,7 @@ namespace Tizen.NUI.BaseComponents
             {
                 int ret = (int)VisualFittingModeType.Fill;
 
-                PropertyValue fittingMode = _imagePropertyMap?.Find(Visual.Property.VisualFittingMode);
+                PropertyValue fittingMode = GetCachedImageVisualProperty(Visual.Property.VisualFittingMode);
                 fittingMode?.Get(out ret);
                 fittingMode?.Dispose();
 
@@ -833,7 +870,7 @@ namespace Tizen.NUI.BaseComponents
                 {
                     UpdateImage();
                 }
-                PropertyValue desirewidth = _imagePropertyMap?.Find(ImageVisualProperty.DesiredWidth);
+                PropertyValue desirewidth = GetCachedImageVisualProperty(ImageVisualProperty.DesiredWidth);
                 desirewidth?.Get(out _desired_width);
                 desirewidth?.Dispose();
 
@@ -880,7 +917,7 @@ namespace Tizen.NUI.BaseComponents
                 {
                     UpdateImage();
                 }
-                PropertyValue desireheight = _imagePropertyMap?.Find(ImageVisualProperty.DesiredHeight);
+                PropertyValue desireheight = GetCachedImageVisualProperty(ImageVisualProperty.DesiredHeight);
                 desireheight?.Get(out _desired_height);
                 desireheight?.Dispose();
 
@@ -922,7 +959,7 @@ namespace Tizen.NUI.BaseComponents
             {
                 int ret = (int)ReleasePolicyType.Detached;
 
-                PropertyValue releasePoli = _imagePropertyMap?.Find(ImageVisualProperty.ReleasePolicy);
+                PropertyValue releasePoli = GetCachedImageVisualProperty(ImageVisualProperty.ReleasePolicy);
                 releasePoli?.Get(out ret);
                 releasePoli?.Dispose();
 
@@ -964,7 +1001,7 @@ namespace Tizen.NUI.BaseComponents
             {
                 int ret = (int)WrapModeType.Default;
 
-                PropertyValue wrapModeU = _imagePropertyMap?.Find(ImageVisualProperty.WrapModeU);
+                PropertyValue wrapModeU = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeU);
                 wrapModeU?.Get(out ret);
                 wrapModeU?.Dispose();
 
@@ -1007,7 +1044,7 @@ namespace Tizen.NUI.BaseComponents
             {
                 int ret = (int)WrapModeType.Default;
 
-                PropertyValue wrapModeV = _imagePropertyMap?.Find(ImageVisualProperty.WrapModeV);
+                PropertyValue wrapModeV = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeV);
                 wrapModeV?.Get(out ret);
                 wrapModeV?.Dispose();
 
@@ -1169,14 +1206,14 @@ namespace Tizen.NUI.BaseComponents
                 _border = null;
                 borderSelector?.Reset(this);
                 resourceUrlSelector?.Reset(this);
-                _imagePropertyUpdatedFlag = false;
-                if (_imagePropertyUpdateProcessAttachedFlag)
+                imagePropertyUpdatedFlag = false;
+                if (imagePropertyUpdateProcessAttachedFlag)
                 {
                     ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
-                    _imagePropertyUpdateProcessAttachedFlag = false;
+                    imagePropertyUpdateProcessAttachedFlag = false;
                 }
-                _imagePropertyMap?.Dispose();
-                _imagePropertyMap = null;
+                cachedImagePropertyMap?.Dispose();
+                cachedImagePropertyMap = null;
             }
 
             base.Dispose(type);
@@ -1215,7 +1252,18 @@ namespace Tizen.NUI.BaseComponents
             if(_resourceUrl != value)
             {
                 _resourceUrl = value;
-                UpdateImage(ImageVisualProperty.URL, new PropertyValue(value));
+                if(string.IsNullOrEmpty(_resourceUrl))
+                {
+                    // Special case. If we set ResourceUrl as empty, Unregist visual.
+                    RemoveImage();
+                }
+                else
+                {
+                    using(PropertyValue setValue = new PropertyValue(value))
+                    {
+                        UpdateImage(ImageVisualProperty.URL, setValue);
+                    }
+                }
             }
         }
 
@@ -1233,55 +1281,57 @@ namespace Tizen.NUI.BaseComponents
         }
 
         /// <summary>
-        /// Lazy call to UpdateImage.
-        /// Collect Properties need to be update, and set properties that starts the Processing.
+        /// Unregist image visual directly. After this operation, we cannot get any properties from Image property.
         /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        protected void UpdateImage(int key, PropertyValue value)
+        private void RemoveImage()
         {
-            // If we set ResourceUrl as empty, Unregist visual.
-            if (key == ImageVisualProperty.URL && string.IsNullOrEmpty(_resourceUrl))
+            // If previous resourceUrl was already empty, we don't need to do anything. just ignore.
+            // Unregist and detach process only if previous resourceUrl was not empty
+            string currentResourceUrl = "";
+            PropertyValue currentResourceUrlValue = GetCachedImageVisualProperty(ImageVisualProperty.URL);
+            if((currentResourceUrlValue?.Get(out currentResourceUrl) ?? false) && !string.IsNullOrEmpty(currentResourceUrl))
             {
-                // If previous resourceUrl was already empty, we don't need to do anything. just ignore.
-                // Unregist and dettach Process only if previous resourceUrl was not empty
-                string currentResourceUrl = "";
-                PropertyValue currentResourceUrlValue = _imagePropertyMap?.Find(ImageVisualProperty.URL);
-                if((currentResourceUrlValue?.Get(out currentResourceUrl) ?? false) && !string.IsNullOrEmpty(currentResourceUrl))
-                {
-                    PropertyValue emptyValue = new PropertyValue();
-
-                    // Remove current registed Image.
-                    SetProperty(ImageView.Property.IMAGE, emptyValue);
+                PropertyValue emptyValue = new PropertyValue();
 
-                    // Image visual is not exist anymore. We should ignore lazy UpdateImage
-                    _imagePropertyUpdatedFlag = false;
-                    if(_imagePropertyUpdateProcessAttachedFlag)
-                    {
-                        ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
-                        _imagePropertyUpdateProcessAttachedFlag = false;
-                    }
-                    // Update resourceUrl as null
-                    _imagePropertyMap[ImageVisualProperty.URL] = emptyValue;
+                // Remove current registed Image.
+                SetProperty(ImageView.Property.IMAGE, emptyValue);
 
-                    emptyValue?.Dispose();
+                // Image visual is not exist anymore. We should ignore lazy UpdateImage
+                imagePropertyUpdatedFlag = false;
+                if(imagePropertyUpdateProcessAttachedFlag)
+                {
+                    ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
+                    imagePropertyUpdateProcessAttachedFlag = false;
                 }
-                return;
+                // Update resourceUrl as empty value
+                cachedImagePropertyMap[ImageVisualProperty.URL] = emptyValue;
+
+                emptyValue?.Dispose();
             }
+            currentResourceUrlValue?.Dispose();
+        }
 
+        /// <summary>
+        /// Lazy call to UpdateImage.
+        /// Collect Properties need to be update, and set properties that starts the Processing.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void UpdateImage(int key, PropertyValue value)
+        {
             // Update image property map value as inputed value.
             if (key != 0)
             {
-                if (_imagePropertyMap == null)
+                if (cachedImagePropertyMap == null)
                 {
-                    _imagePropertyMap = new PropertyMap();
+                    cachedImagePropertyMap = new PropertyMap();
                 }
-                _imagePropertyUpdatedFlag = true;
-                _imagePropertyMap[key] = value;
+                imagePropertyUpdatedFlag = true;
+                cachedImagePropertyMap[key] = value;
 
                 // Lazy update only if _resourceUrl is not empty and ProcessAttachedFlag is false.
-                if (!string.IsNullOrEmpty(_resourceUrl) && !_imagePropertyUpdateProcessAttachedFlag)
+                if (!string.IsNullOrEmpty(_resourceUrl) && !imagePropertyUpdateProcessAttachedFlag)
                 {
-                    _imagePropertyUpdateProcessAttachedFlag = true;
+                    imagePropertyUpdateProcessAttachedFlag = true;
                     ProcessorController.Instance.ProcessorOnceEvent += UpdateImage;
                     // Call process hardly.
                     ProcessorController.Instance.Awake();
@@ -1295,7 +1345,7 @@ namespace Tizen.NUI.BaseComponents
         private void UpdateImage(object source, EventArgs e)
         {
             UpdateImage();
-            _imagePropertyUpdateProcessAttachedFlag = false;
+            imagePropertyUpdateProcessAttachedFlag = false;
         }
 
         /// <summary>
@@ -1308,31 +1358,42 @@ namespace Tizen.NUI.BaseComponents
         /// Please call this ImageView.UpdateImage() API.
         /// </remarks>
         [EditorBrowsable(EditorBrowsableState.Never)]
-        protected void UpdateImage()
+        protected virtual void UpdateImage()
         {
-            if(!_imagePropertyUpdatedFlag) return;
+            if(!imagePropertyUpdatedFlag) return;
 
-            _imagePropertyUpdatedFlag = false;
+            imagePropertyUpdatedFlag = false;
 
-            if(_imagePropertyMap == null)
+            if(cachedImagePropertyMap == null)
             {
-                _imagePropertyMap = new PropertyMap();
+                cachedImagePropertyMap = new PropertyMap();
             }
 
-            if (_border == null)
-            {
-                PropertyValue image = new PropertyValue((int)Visual.Type.Image);
-                _imagePropertyMap[Visual.Property.Type] = image;
-                image?.Dispose();
-            }
-            else
+            // Checkup the cached visual type is AnimatedImage.
+            // It is trick to know that this code is running on AnimatedImageView.UpdateImage() or not.
+            int visualType = -1;
+            if(!((GetCachedImageVisualProperty(Visual.Property.Type)?.Get(out visualType) ?? false) && visualType == (int)Visual.Type.AnimatedImage))
             {
-                PropertyValue nPatch = new PropertyValue((int)Visual.Type.NPatch);
-                _imagePropertyMap[Visual.Property.Type] = nPatch;
-                nPatch?.Dispose();
-                PropertyValue border = new PropertyValue(_border);
-                _imagePropertyMap[NpatchImageVisualProperty.Border] = border;
-                border?.Dispose();
+                // If ResourceUrl is not setuped, don't set property. fast return.
+                if(string.IsNullOrEmpty(_resourceUrl))
+                {
+                    return;
+                }
+                if (_border == null)
+                {
+                    PropertyValue image = new PropertyValue((int)Visual.Type.Image);
+                    cachedImagePropertyMap[Visual.Property.Type] = image;
+                    image?.Dispose();
+                }
+                else
+                {
+                    PropertyValue nPatch = new PropertyValue((int)Visual.Type.NPatch);
+                    cachedImagePropertyMap[Visual.Property.Type] = nPatch;
+                    nPatch?.Dispose();
+                    PropertyValue border = new PropertyValue(_border);
+                    cachedImagePropertyMap[NpatchImageVisualProperty.Border] = border;
+                    border?.Dispose();
+                }
             }
 
             if (backgroundExtraData != null && backgroundExtraData.CornerRadius != null)
@@ -1340,8 +1401,8 @@ namespace Tizen.NUI.BaseComponents
                 using (var cornerRadius = new PropertyValue(backgroundExtraData.CornerRadius))
                 using (var cornerRadiusPolicy = new PropertyValue((int)backgroundExtraData.CornerRadiusPolicy))
                 {
-                    _imagePropertyMap[Visual.Property.CornerRadius] = cornerRadius;
-                    _imagePropertyMap[Visual.Property.CornerRadiusPolicy] = new PropertyValue((int)(backgroundExtraData.CornerRadiusPolicy));
+                    cachedImagePropertyMap[Visual.Property.CornerRadius] = cornerRadius;
+                    cachedImagePropertyMap[Visual.Property.CornerRadiusPolicy] = new PropertyValue((int)(backgroundExtraData.CornerRadiusPolicy));
                 }
             }
 
@@ -1351,9 +1412,9 @@ namespace Tizen.NUI.BaseComponents
                 using (var borderlineColor = new PropertyValue(backgroundExtraData.BorderlineColor))
                 using (var borderlineOffset = new PropertyValue(backgroundExtraData.BorderlineOffset))
                 {
-                    _imagePropertyMap[Visual.Property.BorderlineWidth] = borderlineWidth;
-                    _imagePropertyMap[Visual.Property.BorderlineColor] = borderlineColor;
-                    _imagePropertyMap[Visual.Property.BorderlineOffset] = borderlineOffset;
+                    cachedImagePropertyMap[Visual.Property.BorderlineWidth] = borderlineWidth;
+                    cachedImagePropertyMap[Visual.Property.BorderlineColor] = borderlineColor;
+                    cachedImagePropertyMap[Visual.Property.BorderlineOffset] = borderlineOffset;
                 }
             }
 
@@ -1380,13 +1441,13 @@ namespace Tizen.NUI.BaseComponents
                         }
 
                         PropertyValue returnWidth = new PropertyValue(adjustedDesiredWidth);
-                        _imagePropertyMap[ImageVisualProperty.DesiredWidth] = returnWidth;
+                        cachedImagePropertyMap[ImageVisualProperty.DesiredWidth] = returnWidth;
                         returnWidth?.Dispose();
                         PropertyValue returnHeight = new PropertyValue(adjustedDesiredHeight);
-                        _imagePropertyMap[ImageVisualProperty.DesiredHeight] = returnHeight;
+                        cachedImagePropertyMap[ImageVisualProperty.DesiredHeight] = returnHeight;
                         returnHeight?.Dispose();
                         PropertyValue scaleToFit = new PropertyValue((int)FittingModeType.ScaleToFill);
-                        _imagePropertyMap[ImageVisualProperty.FittingMode] = scaleToFit;
+                        cachedImagePropertyMap[ImageVisualProperty.FittingMode] = scaleToFit;
                         scaleToFit?.Dispose();
                     }
                     else
@@ -1399,24 +1460,84 @@ namespace Tizen.NUI.BaseComponents
 
             UpdateImageMap();
         }
+
+        /// <summary>
+        /// Merge our collected properties, and set IMAGE property internally.
+        /// </summary>
         private void UpdateImageMap()
         {
-            PropertyMap imageMap = new PropertyMap();
+            // Note : We can't use ImageView.Image property here. Because That property call UpdateImage internally.
+            using(PropertyMap imageMap = new PropertyMap())
+            {
+                using(PropertyValue returnValue = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE))
+                {
+                    returnValue?.Get(imageMap);
+                }
+                if(cachedImagePropertyMap != null)
+                {
+                    imageMap?.Merge(cachedImagePropertyMap);
+                }
+                using(PropertyValue setValue = new PropertyValue(imageMap))
+                {
+                    SetProperty(ImageView.Property.IMAGE, setValue);
+                }
+
+                // Update cached image property.
+                MergeCachedImageVisualProperty(imageMap);
+            }
+        }
 
-            PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
-            image?.Get(imageMap);
-            imageMap.Merge(_imagePropertyMap);
-            PropertyValue setValue = new PropertyValue(imageMap);
-            SetProperty(ImageView.Property.IMAGE, setValue);
+        /// <summary>
+        /// Get image visual property by key.
+        /// If we found value in local Cached result, return that.
+        /// Else, get synced native map and return that.
+        /// If there is no matched value, return null.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual PropertyValue GetImageVisualProperty(int key)
+        {
+            PropertyValue ret = GetCachedImageVisualProperty(key);
+            if(ret == null)
+            {
+                // If we cannot find result form cached map, Get value from native engine.
+                ret = Image?.Find(key);
+            }
+            return ret;
+        }
 
-            // Sync local PropertyMap
-            // TODO: Do we need to use GetProperty(SwigCPtr, ImageView.Property.IMAGE); here?
-            _imagePropertyMap.Dispose();
-            _imagePropertyMap = new PropertyMap(imageMap);
+        /// <summary>
+        /// Get image visual property from NUI cached image map by key.
+        /// If there is no matched value, return null.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual PropertyValue GetCachedImageVisualProperty(int key)
+        {
+            return cachedImagePropertyMap?.Find(key);
+        }
 
-            imageMap?.Dispose();
-            image?.Dispose();
-            setValue?.Dispose();
+        /// <summary>
+        /// Update NUI cached image visual property map by inputed property map.
+        /// </summary>
+        /// <remarks>
+        /// For performance issue, we will collect only "cachedImagePropertyKeyList" hold.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void MergeCachedImageVisualProperty(PropertyMap map)
+        {
+            if(map == null) return;
+            if(cachedImagePropertyMap == null)
+            {
+                cachedImagePropertyMap = new PropertyMap();
+            }
+            foreach(var key in cachedImagePropertyKeyList)
+            {
+                PropertyValue value = map.Find(key);
+                if(value != null)
+                {
+                    // Update-or-Insert new value
+                    cachedImagePropertyMap[key] = value;
+                }
+            }
         }
 
         /// <summary>
index 11ffa69..e7a3226 100755 (executable)
@@ -44,7 +44,7 @@ namespace Tizen.NUI.BaseComponents
             var imageView = (ImageView)bindable;
             string ret = "";
 
-            imageView._imagePropertyMap?.Find(ImageVisualProperty.URL)?.Get(out ret);
+            imageView.GetCachedImageVisualProperty(ImageVisualProperty.URL)?.Get(out ret);
 
             return ret;
         }));
@@ -94,13 +94,11 @@ namespace Tizen.NUI.BaseComponents
                 if (imageView._border == null)
                 {
                     // Image properties are changed hardly. We should ignore lazy UpdateImage
-                    imageView._imagePropertyUpdatedFlag = false;
-                    imageView._imagePropertyMap?.Dispose();
-                    imageView._imagePropertyMap = null;
-                    if(map != null)
-                    {
-                        imageView._imagePropertyMap = new PropertyMap(map);
-                    }
+                    imageView.imagePropertyUpdatedFlag = false;
+                    imageView.cachedImagePropertyMap?.Dispose();
+                    imageView.cachedImagePropertyMap = null;
+                    imageView.MergeCachedImageVisualProperty(map);
+
                     Tizen.NUI.Object.SetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE, new Tizen.NUI.PropertyValue(map));
                 }
             }
@@ -110,11 +108,19 @@ namespace Tizen.NUI.BaseComponents
             var imageView = (ImageView)bindable;
             if (imageView._border == null)
             {
+                // Sync as current properties
+                imageView.UpdateImage();
+
                 // Get current properties force.
-                // TODO: Need to make some flag that we only need cached property map.
-                PropertyMap temp = new PropertyMap();
-                Tizen.NUI.Object.GetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE).Get(temp);
-                return temp;
+                PropertyMap returnValue = new PropertyMap();
+                Tizen.NUI.Object.GetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE).Get(returnValue);
+
+                // Update cached property map
+                if(returnValue != null)
+                {
+                    imageView.MergeCachedImageVisualProperty(returnValue);
+                }
+                return returnValue;
             }
             else
             {
@@ -206,7 +212,7 @@ namespace Tizen.NUI.BaseComponents
             var imageView = (ImageView)bindable;
             bool ret = false;
 
-            imageView._imagePropertyMap?.Find(NpatchImageVisualProperty.BorderOnly)?.Get(out ret);
+            imageView.GetCachedImageVisualProperty(NpatchImageVisualProperty.BorderOnly)?.Get(out ret);
 
             return ret;
         }));
@@ -235,7 +241,7 @@ namespace Tizen.NUI.BaseComponents
             var imageView = (ImageView)bindable;
             bool ret = false;
 
-            imageView._imagePropertyMap?.Find(ImageVisualProperty.SynchronousLoading)?.Get(out ret);
+            imageView.GetCachedImageVisualProperty(ImageVisualProperty.SynchronousLoading)?.Get(out ret);
 
             return ret;
         });
@@ -264,7 +270,7 @@ namespace Tizen.NUI.BaseComponents
             var imageView = (ImageView)bindable;
             bool ret = false;
 
-            imageView._imagePropertyMap?.Find(ImageVisualProperty.SynchronousLoading)?.Get(out ret);
+            imageView.GetCachedImageVisualProperty(ImageVisualProperty.SynchronousLoading)?.Get(out ret);
 
             return ret;
         });
@@ -294,7 +300,7 @@ namespace Tizen.NUI.BaseComponents
 
             bool ret = false;
 
-            imageView._imagePropertyMap?.Find(ImageVisualProperty.OrientationCorrection)?.Get(out ret);
+            imageView.GetCachedImageVisualProperty(ImageVisualProperty.OrientationCorrection)?.Get(out ret);
 
             return ret;
         }));
diff --git a/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/res/dali-logo-anim.gif b/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/res/dali-logo-anim.gif
new file mode 100644 (file)
index 0000000..9a085ba
Binary files /dev/null and b/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/res/dali-logo-anim.gif differ
diff --git a/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/testcase/TSAnimatedImageView.cs b/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/testcase/TSAnimatedImageView.cs
new file mode 100644 (file)
index 0000000..a77db5f
--- /dev/null
@@ -0,0 +1,288 @@
+using global::System;
+using NUnit.Framework;
+using NUnit.Framework.TUnit;
+using Tizen.NUI.Components;
+using Tizen.NUI.BaseComponents;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Devel.Tests
+{
+    using tlog = Tizen.Log;
+
+    [TestFixture]
+    [Description("public/BaseComponents/ImageView")]
+    public class InternalAnimatedImageViewTest
+    {
+        private const string tag = "NUITEST";
+        private string image_path = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "Image.png";
+        private string animated_image_path = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "dali-logo-anim.gif";
+
+        [SetUp]
+        public void Init()
+        {
+            tlog.Info(tag, "Init() is called!");
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            tlog.Info(tag, "Destroy() is called!");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, AnimatedImageView.ResourceUrl")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.AnimatedImageView.ResourceUrl")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void ResourceUrl_SET_GET_VALUE()
+        {
+            /* TEST CODE */
+            AnimatedImageView testView = new AnimatedImageView();
+            // Note : Current version of ANIMATED_IMAGE Visual works well only ResourceUrl's suffix is *.gif or *.webp
+            string testUrl1 = "test1.gif";
+            testView.ResourceUrl = testUrl1;
+
+            Assert.AreEqual(testView.ResourceUrl, testUrl1, "ResourceUrl is not equal");
+
+            testView.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, AnimatedImageView.NaturalSize2D")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.AnimatedImageView.NaturalSize2D")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void NaturalSize2D_GET_VALUE()
+        {
+            /* TEST CODE */
+            AnimatedImageView testView = new AnimatedImageView();
+            testView.ResourceUrl = animated_image_path;
+            Size2D result = new Size2D(326, 171); // The size of animated_image_path image.
+            Size2D size = testView.NaturalSize2D;
+
+            Assert.AreEqual(result.Width, size.Width, "NaturalSize Width is not equal");
+            Assert.AreEqual(result.Height, size.Height, "NaturalSize Height is not equal");
+
+            testView.Dispose();
+        }
+
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, AnimatedImageView.NaturalSize")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.AnimatedImageView.NaturalSize")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void NaturalSize_GET_VALUE()
+        {
+            /* TEST CODE */
+            AnimatedImageView testView = new AnimatedImageView();
+            testView.ResourceUrl = animated_image_path;
+            Vector3 result = new Vector3(326, 171, 0); // The size of animated_image_path image.
+            Vector3 size = testView.NaturalSize;
+
+            Assert.AreEqual(result.X, size.X, "NaturalSize Width is not equal");
+            Assert.AreEqual(result.Y, size.Y, "NaturalSize Height is not equal");
+
+            testView.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, AnimatedImageView.NaturalSize")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.AnimatedImageView.NaturalSize")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void NaturalSize_GET_VALUE_as_View_class()
+        {
+            /* TEST CODE */
+            AnimatedImageView testView = new AnimatedImageView();
+            testView.ResourceUrl = animated_image_path;
+            Vector3 result = new Vector3(326, 171, 0); // The size of animated_image_path image.
+            View testView2 = testView; // Convert class as View.
+            Vector3 size = testView2.NaturalSize; // Check whether virtual ImageView.GetNaturalSize() called well.
+
+            Assert.AreEqual(result.X, size.X, "NaturalSize Width is not equal");
+            Assert.AreEqual(result.Y, size.Y, "NaturalSize Height is not equal");
+
+            testView.Dispose();
+            testView2.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, AnimatedImageView.Image with ResourceUrl")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.AnimatedImageView.Image")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void Image_GET_VALUE_After_Set_ResourceUrl()
+        {
+            /* TEST CODE */
+            AnimatedImageView testView = new AnimatedImageView();
+            string resultUrl1 = "";
+
+            PropertyMap map1 = testView.Image;
+
+            bool ret1 = (map1.Find(ImageVisualProperty.URL)?.Get(out resultUrl1) ?? false) && string.IsNullOrEmpty(resultUrl1);
+
+            Assert.AreEqual(false, ret1, "map don't have ResourceUrl");
+
+            // Note : Current version of ANIMATED_IMAGE Visual works well only ResourceUrl's suffix is *.gif or *.webp
+            string testUrl1 = "test1.gif";
+            testView.ResourceUrl = testUrl1;
+
+            PropertyMap map2 = testView.Image;
+
+            bool ret2 = (map2.Find(ImageVisualProperty.URL)?.Get(out resultUrl1) ?? false) && !string.IsNullOrEmpty(resultUrl1);
+
+            Assert.AreEqual(true, ret2, "map must have ResourceUrl");
+            Assert.AreEqual(testUrl1, resultUrl1, "...and That value must be equal what we added");
+
+            testView.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, AnimatedImageView.TotalFrame")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.AnimatedImageView.TotalFrame")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void TotalFrame_GET_VALUE()
+        {
+            /* TEST CODE */
+            AnimatedImageView testView = new AnimatedImageView();
+            int expectedTotalFrame = 15; // The total frame of animated_image_path image
+
+            Assert.AreEqual(-1, testView.TotalFrame, "Total frame should be -1 when ResourceUrl is not setup");
+
+            testView.ResourceUrl = animated_image_path;
+
+            Assert.AreEqual(expectedTotalFrame, testView.TotalFrame, "Total frame doesn't matched!");
+
+            testView.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, AnimatedImageView.CurrentFrame")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.AnimatedImageView.CurrentFrame")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void CurrentFrame_SET_GET_VALUE()
+        {
+            /* TEST CODE */
+            AnimatedImageView testView = new AnimatedImageView();
+
+            Assert.AreEqual(-1, testView.CurrentFrame, "Current frame should be -1 when ResourceUrl is not setup");
+
+            testView.ResourceUrl = animated_image_path;
+
+            Assert.AreEqual(0, testView.CurrentFrame, "Current frame doesn't matched!");
+
+            // Set CurrentFrame will works well only if view is scene on.
+            NUIApplication.GetDefaultWindow().Add(testView);
+
+            int expectFrame = 3;
+            testView.CurrentFrame = expectFrame;
+
+            Assert.AreEqual(expectFrame, testView.CurrentFrame, "Current frame doesn't matched!");
+
+            testView.Unparent();
+            testView.Dispose();
+        }
+
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, AnimatedImageView.LoopCount")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.AnimatedImageView.LoopCount")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void LoopCount_SET_GET_VALUE()
+        {
+            /* TEST CODE */
+            AnimatedImageView testView = new AnimatedImageView();
+
+            Assert.AreEqual(-1, testView.LoopCount, "LoopCount should be -1 when ResourceUrl is not setup");
+
+            testView.ResourceUrl = animated_image_path;
+
+            Assert.AreEqual(-1, testView.LoopCount, "LoopCount should be -1 (mean infinite loop) even ResourceUrl is setup");
+
+            int expectLoopCount = 3;
+            testView.LoopCount = expectLoopCount;
+            Assert.AreEqual(expectLoopCount, testView.LoopCount, "LoopCount doesn't matched!");
+
+            testView.LoopCount++;
+            Assert.AreEqual(expectLoopCount + 1, testView.LoopCount, "LoopCount doesn't matched!");
+
+            testView.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, AnimatedImageView.StopBehavior")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.AnimatedImageView.StopBehavior")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void StopBehavior_SET_GET_VALUE()
+        {
+            /* TEST CODE */
+            AnimatedImageView testView = new AnimatedImageView();
+
+            testView.ResourceUrl = animated_image_path;
+
+            testView.StopBehavior = AnimatedImageView.StopBehaviorType.CurrentFrame;
+            Assert.AreEqual(AnimatedImageView.StopBehaviorType.CurrentFrame, testView.StopBehavior, "StopBehavior is not equal");
+            testView.StopBehavior = AnimatedImageView.StopBehaviorType.MinimumFrame;
+            Assert.AreEqual(AnimatedImageView.StopBehaviorType.MinimumFrame, testView.StopBehavior, "StopBehavior is not equal");
+            testView.StopBehavior = AnimatedImageView.StopBehaviorType.MaximumFrame;
+            Assert.AreEqual(AnimatedImageView.StopBehaviorType.MaximumFrame, testView.StopBehavior, "StopBehavior is not equal");
+
+            testView.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, AnimatedImageView.URLs")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.AnimatedImageView.URLs")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void URLs_SET_GET_VALUE()
+        {
+            /* TEST CODE */
+            AnimatedImageView testView = new AnimatedImageView();
+            List<string> urls = testView.URLs;
+
+            urls.Add(image_path);
+            urls.Add(image_path);
+            urls.Add(image_path);
+
+            // URLs don't have any change notifier. So we have to update property forcely by SetValues API.
+            testView.SetValues();
+
+            int expectedTotalFrame = urls.Count;
+            int defaultFrameDelay = 100; ///< It can be changed in dali engine side
+            int expectFrameDelay = 300;
+
+            Assert.AreEqual(expectedTotalFrame, testView.TotalFrame, "Total frame doesn't matched!");
+            Assert.AreEqual(defaultFrameDelay, testView.FrameDelay, "Default frame delay doesn't matched!");
+            testView.FrameDelay = expectFrameDelay;
+            Assert.AreEqual(expectFrameDelay, testView.FrameDelay, "frame delay doesn't matched!");
+
+            testView.Dispose();
+        }
+    }
+}
index bde78a9..588549f 100644 (file)
@@ -181,5 +181,212 @@ namespace Tizen.NUI.Devel.Tests
             testView.Dispose();
             testView2.Dispose();
         }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, ImageView.Image with ResourceUrl")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.ImageView.Image")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void Image_GET_VALUE_After_Set_ResourceUrl()
+        {
+            /* TEST CODE */
+            ImageView testView = new ImageView();
+            string resultUrl1 = "";
+
+            PropertyMap map1 = testView.Image;
+
+            bool ret1 = (map1.Find(ImageVisualProperty.URL)?.Get(out resultUrl1) ?? false) && string.IsNullOrEmpty(resultUrl1);
+
+            Assert.AreEqual(false, ret1, "map don't have ResourceUrl");
+
+            string testUrl1 = "test1";
+            testView.ResourceUrl = testUrl1;
+
+            PropertyMap map2 = testView.Image;
+
+            bool ret2 = (map2.Find(ImageVisualProperty.URL)?.Get(out resultUrl1) ?? false) && !string.IsNullOrEmpty(resultUrl1);
+
+            Assert.AreEqual(true, ret2, "map must have ResourceUrl");
+            Assert.AreEqual(testUrl1, resultUrl1, "...and That value must be equal what we added");
+
+            testView.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, ImageView.Image with something")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.ImageView.Image")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void Image_GET_VALUE_After_Set_something()
+        {
+            /* TEST CODE */
+            ImageView testView = new ImageView();
+            string resultString = "";
+            bool resultBool = false;
+
+            using(PropertyMap map = testView.Image)
+            {
+                bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(false, ret, "map don't have ResourceUrl");
+                ret = map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false;
+                Assert.AreEqual(false, ret, "map don't have AlphaMaskURL");
+                ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(false, ret, "map don't have CropToMask");
+                ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(false, ret, "map don't have SynchronousLoading");
+            }
+
+            string testUrl1 = "test1";
+            testView.AlphaMaskURL = testUrl1;
+            testView.CropToMask = true;
+            testView.SynchronousLoading = true;
+
+            using(PropertyMap map = testView.Image)
+            {
+                bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(false, ret, "map don't have ResourceUrl");
+                ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(false, ret, "map don't have AlphaMaskURL cause ResoureUrl is empty");
+                ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(false, ret, "map don't have CropToMask cause ResoureUrl is empty");
+                ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(false, ret, "map don't have SynchronousLoading cause ResoureUrl is empty");
+            }
+
+            testView.ResourceUrl = image_path;
+
+            using(PropertyMap map = testView.Image)
+            {
+                bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(true, ret, "map must have ResourceUrl");
+                Assert.AreEqual(image_path, resultString, "...and That value must be equal what we added");
+                ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(true, ret, "map must have AlphaMaskURL");
+                Assert.AreEqual(testUrl1, resultString, "...and That value must be equal what we added");
+                ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(true, ret, "map must have CropToMask");
+                Assert.AreEqual(true, resultBool, "...and That value must be equal what we added");
+                ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(true, ret, "map must have SynchronousLoading");
+                Assert.AreEqual(true, resultBool, "...and That value must be equal what we added");
+            }
+
+            // Insert empty resource Url
+            testView.ResourceUrl = "";
+
+            using(PropertyMap map = testView.Image)
+            {
+                bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(false, ret, "map don't have ResourceUrl");
+                ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(false, ret, "map don't have AlphaMaskURL cause ResoureUrl is empty");
+                ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(false, ret, "map don't have CropToMask cause ResoureUrl is empty");
+                ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(false, ret, "map don't have SynchronousLoading cause ResoureUrl is empty");
+            }
+
+            // Insert valid resource Url
+            testView.ResourceUrl = mask_path;
+
+            using(PropertyMap map = testView.Image)
+            {
+                bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(true, ret, "map must have ResourceUrl");
+                Assert.AreEqual(mask_path, resultString, "...and That value must be equal what we added");
+                ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(true, ret, "map must have AlphaMaskURL");
+                Assert.AreEqual(testUrl1, resultString, "...and That value must be equal what we added");
+                ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(true, ret, "map must have CropToMask");
+                Assert.AreEqual(true, resultBool, "...and That value must be equal what we added");
+                ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(true, ret, "map must have SynchronousLoading");
+                Assert.AreEqual(true, resultBool, "...and That value must be equal what we added");
+            }
+
+            testView.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("internal API test in Ubuntu, set ImageView.Image and check cached properties changed")]
+        [Property("SPEC", "Tizen.NUI.BaseComponents.ImageView.Image")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "eunkiki.hong@samsung.com")]
+        public void Image_SET_VALUE_After_Set_something()
+        {
+            /* TEST CODE */
+            ImageView testView = new ImageView();
+            string resultString = "";
+            bool resultBool = false;
+
+            using(PropertyMap map = testView.Image)
+            {
+                bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(false, ret, "map don't have ResourceUrl");
+                ret = map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false;
+                Assert.AreEqual(false, ret, "map don't have AlphaMaskURL");
+                ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(false, ret, "map don't have CropToMask");
+                ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(false, ret, "map don't have SynchronousLoading");
+            }
+
+            string testUrl1 = "test1";
+            string testUrl2 = "test2";
+            testView.ResourceUrl = testUrl1;
+            testView.AlphaMaskURL = testUrl2;
+            testView.CropToMask = true;
+            testView.SynchronousLoading = true;
+
+            using(PropertyMap map = testView.Image)
+            {
+                bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(true, ret, "map must have ResourceUrl");
+                Assert.AreEqual(testUrl1, resultString, "...and That value must be equal what we added");
+                ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(true, ret, "map must have AlphaMaskURL");
+                Assert.AreEqual(testUrl2, resultString, "...and That value must be equal what we added");
+                ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(true, ret, "map must have CropToMask");
+                Assert.AreEqual(true, resultBool, "...and That value must be equal what we added");
+                ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(true, ret, "map must have SynchronousLoading");
+                Assert.AreEqual(true, resultBool, "...and That value must be equal what we added");
+            }
+
+            // Update Image map by PropertyMap.
+            // Cached property map will be overwrited.
+            using(PropertyMap setImageMap = new PropertyMap())
+            {
+                setImageMap[ImageVisualProperty.URL] = new PropertyValue(image_path);
+                setImageMap[ImageVisualProperty.AlphaMaskURL] = new PropertyValue(mask_path);
+                setImageMap[ImageVisualProperty.CropToMask] = new PropertyValue(false);
+                setImageMap[ImageVisualProperty.SynchronousLoading] = new PropertyValue(false);
+                testView.Image = setImageMap;
+            }
+
+            using(PropertyMap map = testView.Image)
+            {
+                bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(true, ret, "map must have ResourceUrl");
+                Assert.AreEqual(image_path, resultString, "...and That value must be equal what we added");
+                ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString);
+                Assert.AreEqual(true, ret, "map must have AlphaMaskURL");
+                Assert.AreEqual(mask_path, resultString, "...and That value must be equal what we added");
+                ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(true, ret, "map must have CropToMask");
+                Assert.AreEqual(false, resultBool, "...and That value must be equal what we added");
+                ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false;
+                Assert.AreEqual(true, ret, "map must have SynchronousLoading");
+                Assert.AreEqual(false, resultBool, "...and That value must be equal what we added");
+            }
+        }
     }
 }
index 5921935..0313329 100755 (executable)
@@ -167,6 +167,7 @@ namespace Tizen.NUI.Samples
             {
                 box2.image.URLs.Add(resPath + "images/AGIF/dog-anim-00" + i + ".png");
             }
+            box2.image.SetValues();
             box2.image.Play();
 
             box2.but1.Clicked += But1_Clicked1;