[NUI] Fix Navigator to support Page with Transitions
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Navigation / Navigator.cs
index 1be9928..9d5dd83 100755 (executable)
@@ -19,6 +19,7 @@ using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
 
 namespace Tizen.NUI.Components
 {
@@ -73,7 +74,43 @@ namespace Tizen.NUI.Components
     /// <since_tizen> 9 </since_tizen>
     public class Navigator : Control
     {
-        private const int DefaultTransitionDuration = 500;
+        /// <summary>
+        /// TransitionProperty
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty TransitionProperty = BindableProperty.Create(nameof(Transition), typeof(Transition), typeof(Navigator), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = (Navigator)bindable;
+            if (newValue != null)
+            {
+                instance.InternalTransition = newValue as Transition;
+            }
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            var instance = (Navigator)bindable;
+            return instance.InternalTransition;
+        });
+
+        /// <summary>
+        /// EnableBackNavigationProperty
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty EnableBackNavigationProperty = BindableProperty.Create(nameof(EnableBackNavigation), typeof(bool), typeof(Navigator), default(bool), propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = (Navigator)bindable;
+            if (newValue != null)
+            {
+                instance.InternalEnableBackNavigation = (bool)newValue;
+            }
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            var instance = (Navigator)bindable;
+            return instance.InternalEnableBackNavigation;
+        });
+
+        private const int DefaultTransitionDuration = 300;
 
         //This will be replaced with view transition class instance.
         private Animation curAnimation = null;
@@ -98,13 +135,76 @@ namespace Tizen.NUI.Components
 
         private List<Page> navigationPages = new List<Page>();
 
+        private bool enableBackNavigation = true;
+
+        private Window parentWindow;
+
+        private void OnWindowKeyEvent(object sender, Window.KeyEventArgs e)
+        {
+            if (!EnableBackNavigation)
+            {
+                return;
+            }
+
+            if ((e.Key.State == Key.StateType.Up) && ((e.Key.KeyPressedName == "Escape") || (e.Key.KeyPressedName == "BackSpace") || (e.Key.KeyPressedName == "XF86Back")))
+            {
+                OnBackNavigation(new BackNavigationEventArgs());
+            }
+        }
+
+        private void OnAddedToWindow(object sender, EventArgs e)
+        {
+            parentWindow = Window.Get(this);
+            if (null != parentWindow)
+            {
+                parentWindow.KeyEvent += OnWindowKeyEvent;
+            }
+        }
+
+        private void OnRemovedFromWindow(object sender, EventArgs e)
+        {
+            if (null != parentWindow)
+            {
+                parentWindow.KeyEvent -= OnWindowKeyEvent;
+                parentWindow = null;
+            }
+        }
+
+        private void Initialize()
+        {
+            Layout = new AbsoluteLayout();
+
+            AddedToWindow += OnAddedToWindow;
+            RemovedFromWindow += OnRemovedFromWindow;
+        }
+
         /// <summary>
         /// Creates a new instance of a Navigator.
         /// </summary>
         /// <since_tizen> 9 </since_tizen>
         public Navigator() : base()
         {
-            Layout = new AbsoluteLayout();
+            Initialize();
+        }
+
+        /// <summary>
+        /// Creates a new instance of Navigator with style.
+        /// </summary>
+        /// <param name="style">Creates Navigator by special style defined in UX.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Navigator(string style) : base(style)
+        {
+            Initialize();
+        }
+
+        /// <summary>
+        /// Creates a new instance of a Navigator with style.
+        /// </summary>
+        /// <param name="style">A style applied to the newly created Navigator.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Navigator(ControlStyle style) : base(style)
+        {
+            Initialize();
         }
 
         /// <inheritdoc/>
@@ -113,7 +213,7 @@ namespace Tizen.NUI.Components
         {
             base.OnInitialize();
 
-            SetAccessibilityConstructor(Role.PageTabList);
+            AccessibilityRole = Role.PageTabList;
         }
 
         /// <summary>
@@ -143,6 +243,18 @@ namespace Tizen.NUI.Components
         /// <since_tizen> 9 </since_tizen>
         public Transition Transition
         {
+            get
+            {
+                return GetValue(TransitionProperty) as Transition;
+            }
+            set
+            {
+                SetValue(TransitionProperty, value);
+                NotifyPropertyChanged();
+            }
+        }
+        private Transition InternalTransition
+        {
             set
             {
                 transition = value;
@@ -191,18 +303,25 @@ namespace Tizen.NUI.Components
             //Invoke Page events
             page.InvokeAppearing();
             topPage.InvokeDisappearing();
+            topPage.SaveKeyFocus();
 
             transitionSet = CreateTransitions(topPage, page, true);
             transitionSet.Finished += (object sender, EventArgs e) =>
             {
                 if (page is DialogPage == false)
                 {
-                   topPage.SetVisible(false);     
+                    topPage.SetVisible(false);
                 }
 
+                // Need to update Content of the new page
+                ShowContentOfPage(page);
+
                 //Invoke Page events
                 page.InvokeAppeared();
+                page.RestoreKeyFocus();
+                
                 topPage.InvokeDisappeared();
+                NotifyAccessibilityStatesChangeOfPages(topPage, page);
             };
             transitionFinished = false;
         }
@@ -242,6 +361,7 @@ namespace Tizen.NUI.Components
             //Invoke Page events
             newTopPage.InvokeAppearing();
             topPage.InvokeDisappearing();
+            topPage.SaveKeyFocus();
 
             transitionSet = CreateTransitions(topPage, newTopPage, false);
             transitionSet.Finished += (object sender, EventArgs e) =>
@@ -249,8 +369,13 @@ namespace Tizen.NUI.Components
                 Remove(topPage);
                 topPage.SetVisible(true);
 
+                // Need to update Content of the new page
+                ShowContentOfPage(newTopPage);
+
                 //Invoke Page events
                 newTopPage.InvokeAppeared();
+                newTopPage.RestoreKeyFocus();
+
                 topPage.InvokeDisappeared();
 
                 //Invoke Popped event
@@ -284,6 +409,9 @@ namespace Tizen.NUI.Components
             //Duplicate page is not pushed.
             if (navigationPages.Contains(page)) return;
 
+            //TODO: The following transition codes will be replaced with view transition.
+            InitializeAnimation();
+
             var curTop = Peek();
 
             if (!curTop)
@@ -300,13 +428,12 @@ namespace Tizen.NUI.Components
             page.InvokeAppearing();
             curTop.InvokeDisappearing();
 
-            //TODO: The following transition codes will be replaced with view transition.
-            InitializeAnimation();
+            curTop.SaveKeyFocus();
 
             if (page is DialogPage == false)
             {
-                curAnimation = new Animation(1000);
-                curAnimation.AnimateTo(curTop, "Opacity", 1.0f, 0, 1000);
+                curAnimation = new Animation(DefaultTransitionDuration);
+                curAnimation.AnimateTo(curTop, "PositionX", 0.0f, 0, DefaultTransitionDuration);
                 curAnimation.EndAction = Animation.EndActions.StopFinal;
                 curAnimation.Finished += (object sender, EventArgs args) =>
                 {
@@ -317,18 +444,32 @@ namespace Tizen.NUI.Components
                 };
                 curAnimation.Play();
 
-                page.Opacity = 0.0f;
+                page.PositionX = SizeWidth;
                 page.SetVisible(true);
-                newAnimation = new Animation(1000);
-                newAnimation.AnimateTo(page, "Opacity", 1.0f, 0, 1000);
+                // Set Content visible because it was hidden by HideContentOfPage.
+                (page as ContentPage)?.Content?.SetVisible(true);
+
+                newAnimation = new Animation(DefaultTransitionDuration);
+                newAnimation.AnimateTo(page, "PositionX", 0.0f, 0, DefaultTransitionDuration);
                 newAnimation.EndAction = Animation.EndActions.StopFinal;
                 newAnimation.Finished += (object sender, EventArgs e) =>
                 {
+                    // Need to update Content of the new page
+                    ShowContentOfPage(page);
+
                     //Invoke Page events
                     page.InvokeAppeared();
+                    NotifyAccessibilityStatesChangeOfPages(curTop, page);
+
+                    page.RestoreKeyFocus();
                 };
                 newAnimation.Play();
             }
+            else
+            {
+                ShowContentOfPage(page);
+                page.RestoreKeyFocus();
+            }
         }
 
         /// <summary>
@@ -350,6 +491,9 @@ namespace Tizen.NUI.Components
                 throw new InvalidOperationException("There is no page in Navigator.");
             }
 
+            //TODO: The following transition codes will be replaced with view transition.
+            InitializeAnimation();
+
             var curTop = Peek();
 
             if (navigationPages.Count == 1)
@@ -367,20 +511,19 @@ namespace Tizen.NUI.Components
             //Invoke Page events
             newTop.InvokeAppearing();
             curTop.InvokeDisappearing();
-
-            //TODO: The following transition codes will be replaced with view transition.
-            InitializeAnimation();
+            curTop.SaveKeyFocus();
 
             if (curTop is DialogPage == false)
             {
-                curAnimation = new Animation(1000);
-                curAnimation.AnimateTo(curTop, "Opacity", 0.0f, 0, 1000);
+                curAnimation = new Animation(DefaultTransitionDuration);
+                curAnimation.AnimateTo(curTop, "PositionX", SizeWidth, 0, DefaultTransitionDuration);
                 curAnimation.EndAction = Animation.EndActions.StopFinal;
                 curAnimation.Finished += (object sender, EventArgs e) =>
                 {
                     //Removes the current top page after transition is finished.
                     Remove(curTop);
-                    curTop.Opacity = 1.0f;
+
+                    curTop.PositionX = 0.0f;
 
                     //Invoke Page events
                     curTop.InvokeDisappeared();
@@ -390,21 +533,29 @@ namespace Tizen.NUI.Components
                 };
                 curAnimation.Play();
 
-                newTop.Opacity = 1.0f;
                 newTop.SetVisible(true);
-                newAnimation = new Animation(1000);
-                newAnimation.AnimateTo(newTop, "Opacity", 1.0f, 0, 1000);
+                // Set Content visible because it was hidden by HideContentOfPage.
+                (newTop as ContentPage)?.Content?.SetVisible(true);
+
+                newAnimation = new Animation(DefaultTransitionDuration);
+                newAnimation.AnimateTo(newTop, "PositionX", 0.0f, 0, DefaultTransitionDuration);
                 newAnimation.EndAction = Animation.EndActions.StopFinal;
                 newAnimation.Finished += (object sender, EventArgs e) =>
                 {
+                    // Need to update Content of the new page
+                    ShowContentOfPage(newTop);
+
                     //Invoke Page events
                     newTop.InvokeAppeared();
+
+                    newTop.RestoreKeyFocus();
                 };
                 newAnimation.Play();
             }
             else
             {
                 Remove(curTop);
+                newTop.RestoreKeyFocus();
             }
 
             return curTop;
@@ -485,20 +636,32 @@ namespace Tizen.NUI.Components
             //TODO: The following transition codes will be replaced with view transition.
             InitializeAnimation();
 
+            ShowContentOfPage(page);
+
             if (index == PageCount)
             {
-                page.Opacity = 1.0f;
                 page.SetVisible(true);
             }
             else
             {
                 page.SetVisible(false);
-                page.Opacity = 0.0f;
             }
 
             navigationPages.Insert(index, page);
             Add(page);
+            page.SiblingOrder = index;
             page.Navigator = this;
+            if (index == PageCount - 1)
+            {
+                if (PageCount > 1)
+                {
+                    NotifyAccessibilityStatesChangeOfPages(navigationPages[PageCount - 2], page);
+                }
+                else
+                {
+                    NotifyAccessibilityStatesChangeOfPages(null, page);
+                }
+            }
         }
 
         /// <summary>
@@ -551,12 +714,20 @@ namespace Tizen.NUI.Components
             //TODO: The following transition codes will be replaced with view transition.
             InitializeAnimation();
 
-            if ((page == Peek()) && (PageCount >= 2))
+            HideContentOfPage(page);
+
+            if (page == Peek())
             {
-                navigationPages[PageCount - 2].Opacity = 1.0f;
-                navigationPages[PageCount - 2].SetVisible(true);
+                if (PageCount >= 2)
+                {
+                    navigationPages[PageCount - 2].SetVisible(true);
+                    NotifyAccessibilityStatesChangeOfPages(page, navigationPages[PageCount - 2]);
+                }
+                else if (PageCount == 1)
+                {
+                    NotifyAccessibilityStatesChangeOfPages(page, null);
+                }
             }
-
             page.Navigator = null;
             navigationPages.Remove(page);
             base.Remove(page);
@@ -594,6 +765,37 @@ namespace Tizen.NUI.Components
         }
 
         /// <summary>
+        /// Gets or sets if Navigator proceeds back navigation when back button or back key is pressed and released.
+        /// Back navigation pops the peek page if Navigator has more than one page.
+        /// If Navigator has only one page, then the current program is exited.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool EnableBackNavigation
+        {
+            get
+            {
+                return (bool)GetValue(EnableBackNavigationProperty);
+            }
+            set
+            {
+                SetValue(EnableBackNavigationProperty, value);
+                NotifyPropertyChanged();
+            }
+        }
+
+        private bool InternalEnableBackNavigation
+        {
+            set
+            {
+                enableBackNavigation = value;
+            }
+            get
+            {
+                return enableBackNavigation;
+            }
+        }
+
+        /// <summary>
         /// Disposes Navigator and all children on it.
         /// </summary>
         /// <param name="type">Dispose type.</param>
@@ -620,6 +822,9 @@ namespace Tizen.NUI.Components
                     navigatorWindow.Remove(this);
                     windowNavigator.Remove(window);
                 }
+
+                AddedToWindow -= OnAddedToWindow;
+                RemovedFromWindow -= OnRemovedFromWindow;
             }
 
             base.Dispose(type);
@@ -654,6 +859,73 @@ namespace Tizen.NUI.Components
         }
 
         /// <summary>
+        /// Sets the default navigator of the given window.
+        /// SetDefaultNavigator does not remove the previous default navigator from the window.
+        /// Therefore, if a user does not want to show the previous default navigator, then it should be removed from the window manually.
+        /// </summary>
+        /// <exception cref="ArgumentNullException">Thrown when the argument window is null.</exception>
+        /// <exception cref="ArgumentNullException">Thrown when the argument newNavigator is null.</exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static void SetDefaultNavigator(Window window, Navigator newNavigator)
+        {
+            if (window == null)
+            {
+                throw new ArgumentNullException(nameof(window), "window should not be null.");
+            }
+
+            if (newNavigator == null)
+            {
+                throw new ArgumentNullException(nameof(newNavigator), "newNavigator should not be null.");
+            }
+
+            if (windowNavigator.ContainsKey(window) == true)
+            {
+                var oldNavigator = windowNavigator[window];
+                if (oldNavigator == newNavigator)
+                {
+                    return;
+                }
+
+                navigatorWindow.Remove(oldNavigator);
+                windowNavigator.Remove(window);
+            }
+
+            window.Add(newNavigator);
+            windowNavigator.Add(window, newNavigator);
+            navigatorWindow.Add(newNavigator, window);
+        }
+
+        /// <summary>
+        /// Called when the back navigation is started.
+        /// Back navigation pops the peek page if Navigator has more than one page.
+        /// If Navigator has only one page, then the current program is exited.
+        /// </summary>
+        /// <param name="eventArgs">The back navigation information.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void OnBackNavigation(BackNavigationEventArgs eventArgs)
+        {
+            if (PageCount >= 1)
+            {
+                if (Peek().EnableBackNavigation)
+                {
+                    Peek().NavigateBack();
+                }
+            }
+            else
+            {
+                NUIApplication.Current?.Exit();
+            }
+        }
+
+        /// <summary>
+        /// Called when the back navigation is required outside Navigator.
+        /// </summary>
+        internal void NavigateBack()
+        {
+            OnBackNavigation(new BackNavigationEventArgs());
+        }
+
+        /// <summary>
         /// Create Transitions between currentTopPage and newTopPage
         /// </summary>
         /// <param name="currentTopPage">The top page of Navigator.</param>
@@ -662,7 +934,12 @@ namespace Tizen.NUI.Components
         private TransitionSet CreateTransitions(Page currentTopPage, Page newTopPage, bool pushTransition)
         {
             currentTopPage.SetVisible(true);
+            // Set Content visible because it was hidden by HideContentOfPage.
+            (currentTopPage as ContentPage)?.Content?.SetVisible(true);
+
             newTopPage.SetVisible(true);
+            // Set Content visible because it was hidden by HideContentOfPage.
+            (newTopPage as ContentPage)?.Content?.SetVisible(true);
 
             List<View> taggedViewsInNewTopPage = new List<View>();
             RetrieveTaggedViews(taggedViewsInNewTopPage, newTopPage, true);
@@ -670,12 +947,12 @@ namespace Tizen.NUI.Components
             RetrieveTaggedViews(taggedViewsInCurrentTopPage, currentTopPage, true);
 
             List<KeyValuePair<View, View>> sameTaggedViewPair = new List<KeyValuePair<View, View>>();
-            foreach(View currentTopPageView in taggedViewsInCurrentTopPage)
+            foreach (View currentTopPageView in taggedViewsInCurrentTopPage)
             {
                 bool findPair = false;
-                foreach(View newTopPageView in taggedViewsInNewTopPage)
+                foreach (View newTopPageView in taggedViewsInNewTopPage)
                 {
-                    if((currentTopPageView.TransitionOptions != null) && (newTopPageView.TransitionOptions != null) &&
+                    if ((currentTopPageView.TransitionOptions != null) && (newTopPageView.TransitionOptions != null) &&
                         currentTopPageView.TransitionOptions?.TransitionTag == newTopPageView.TransitionOptions?.TransitionTag)
                     {
                         sameTaggedViewPair.Add(new KeyValuePair<View, View>(currentTopPageView, newTopPageView));
@@ -683,21 +960,21 @@ namespace Tizen.NUI.Components
                         break;
                     }
                 }
-                if(findPair)
+                if (findPair)
                 {
                     taggedViewsInNewTopPage.Remove(sameTaggedViewPair[sameTaggedViewPair.Count - 1].Value);
                 }
             }
-            foreach(KeyValuePair<View, View> pair in sameTaggedViewPair)
+            foreach (KeyValuePair<View, View> pair in sameTaggedViewPair)
             {
                 taggedViewsInCurrentTopPage.Remove(pair.Key);
             }
 
             TransitionSet newTransitionSet = new TransitionSet();
-            foreach(KeyValuePair<View, View> pair in sameTaggedViewPair)
+            foreach (KeyValuePair<View, View> pair in sameTaggedViewPair)
             {
                 TransitionItem pairTransition = transition.CreateTransition(pair.Key, pair.Value, pushTransition);
-                if(pair.Value.TransitionOptions?.TransitionWithChild ?? false)
+                if (pair.Value.TransitionOptions?.TransitionWithChild ?? false)
                 {
                     pairTransition.TransitionWithChild = true;
                 }
@@ -706,23 +983,31 @@ namespace Tizen.NUI.Components
 
             newTransitionSet.Finished += (object sender, EventArgs e) =>
             {
-                if(newTopPage.Layout != null)
+                if (newTopPage.Layout != null)
                 {
                     newTopPage.Layout.RequestLayout();
                 }
-                if(currentTopPage.Layout != null)
+                if (currentTopPage.Layout != null)
                 {
                     currentTopPage.Layout.RequestLayout();
                 }
                 transitionFinished = true;
                 InvokeTransitionFinished();
                 transitionSet.Dispose();
-                currentTopPage.Opacity = 1.0f;
             };
 
             if (!pushTransition || newTopPage is DialogPage == false)
             {
-                View transitionView = (currentTopPage is ContentPage) ? (currentTopPage as ContentPage).Content : (currentTopPage as DialogPage).Content;
+                View transitionView = currentTopPage;
+                if (currentTopPage is ContentPage)
+                {
+                    transitionView = (currentTopPage as ContentPage).Content;
+                }
+                else if (currentTopPage is DialogPage)
+                {
+                    transitionView = (currentTopPage as DialogPage).Content;
+                }
+
                 if (currentTopPage.DisappearingTransition != null && transitionView != null)
                 {
                     TransitionItemBase disappearingTransition = currentTopPage.DisappearingTransition.CreateTransition(transitionView, false);
@@ -736,7 +1021,16 @@ namespace Tizen.NUI.Components
             }
             if (pushTransition || currentTopPage is DialogPage == false)
             {
-                View transitionView = (newTopPage is ContentPage) ? (newTopPage as ContentPage).Content : (newTopPage as DialogPage).Content;
+                View transitionView = newTopPage;
+                if (newTopPage is ContentPage)
+                {
+                    transitionView = (newTopPage as ContentPage).Content;
+                }
+                else if (newTopPage is DialogPage)
+                {
+                    transitionView = (newTopPage as DialogPage).Content;
+                }
+
                 if (newTopPage.AppearingTransition != null && transitionView != null)
                 {
                     TransitionItemBase appearingTransition = newTopPage.AppearingTransition.CreateTransition(transitionView, true);
@@ -777,6 +1071,32 @@ namespace Tizen.NUI.Components
             }
         }
 
+        /// <summary>
+        /// Notify accessibility states change of pages.
+        /// </summary>
+        /// <param name="disappearedPage">Disappeared page</param>
+        /// <param name="appearedPage">Appeared page</param>
+        private void NotifyAccessibilityStatesChangeOfPages(Page disappearedPage, Page appearedPage)
+        {
+            if (disappearedPage != null)
+            {
+                disappearedPage.UnregisterDefaultLabel();
+                //We can call disappearedPage.NotifyAccessibilityStatesChange
+                //To reduce accessibility events, we are using currently highlighted view instead
+                View curHighlightedView = Accessibility.Accessibility.GetCurrentlyHighlightedView();
+                if (curHighlightedView != null)
+                {
+                    curHighlightedView.NotifyAccessibilityStatesChange(new AccessibilityStates(AccessibilityState.Visible, AccessibilityState.Showing), AccessibilityStatesNotifyMode.Single);
+                }
+            }
+
+            if (appearedPage != null)
+            {
+                appearedPage.RegisterDefaultLabel();
+                appearedPage.NotifyAccessibilityStatesChange(new AccessibilityStates(AccessibilityState.Visible, AccessibilityState.Showing), AccessibilityStatesNotifyMode.Single);
+            }
+        }
+
         internal void InvokeTransitionFinished()
         {
             TransitionFinished?.Invoke(this, new EventArgs());
@@ -785,19 +1105,80 @@ namespace Tizen.NUI.Components
         //TODO: The following transition codes will be replaced with view transition.
         private void InitializeAnimation()
         {
+            bool isCurAnimPlaying = false;
+            bool isNewAnimPlaying = false;
+
             if (curAnimation != null)
             {
-                curAnimation.Stop();
+                if (curAnimation.State == Animation.States.Playing)
+                {
+                    isCurAnimPlaying = true;
+                    curAnimation.Stop();
+                }
+            }
+
+            if (newAnimation != null)
+            {
+                if (newAnimation.State == Animation.States.Playing)
+                {
+                    isNewAnimPlaying = true;
+                    newAnimation.Stop();
+                }
+            }
+
+            if (isCurAnimPlaying)
+            {
+                // To enable multiple Pop(), animation's Finished callback is required.
+                // To call animation's Finished callback, FinishedSignal is emitted.
+                curAnimation.FinishedSignal().Emit(curAnimation);
                 curAnimation.Clear();
+
+                // InitializeAnimation() can be called by FinishedSignal().Emit().
+                // Not to cause null pointer dereference by calling InitializeAnimation() in InitializeAnimation(),
+                // animation handle is assigned to be null only if the animation is playing.
                 curAnimation = null;
             }
 
-            if (newAnimation != null)
+            if (isNewAnimPlaying)
             {
-                newAnimation.Stop();
+                // To enable multiple Pop(), animation's Finished callback is required.
+                // To call animation's Finished callback, FinishedSignal is emitted.
+                newAnimation.FinishedSignal().Emit(newAnimation);
                 newAnimation.Clear();
+
+                // InitializeAnimation() can be called by FinishedSignal().Emit().
+                // Not to cause null pointer dereference by calling InitializeAnimation() in InitializeAnimation(),
+                // animation handle is assigned to be null only if the animation is playing.
                 newAnimation = null;
             }
         }
+
+        // Show and Register Content of Page to Accessibility bridge
+        private void ShowContentOfPage(Page page)
+        {
+            View content = (page is DialogPage) ? (page as DialogPage)?.Content : (page as ContentPage)?.Content;
+            if (content != null)
+            {
+                content.Show(); // Calls RegisterDefaultLabel()
+            }
+        }
+
+        // Hide and Remove Content of Page from Accessibility bridge
+        private void HideContentOfPage(Page page)
+        {
+            View content = (page is DialogPage) ? (page as DialogPage)?.Content : (page as ContentPage)?.Content;
+            if (content != null)
+            {
+                content.Hide(); // Calls UnregisterDefaultLabel()
+            }
+        }
+    }
+
+    /// <summary>
+    /// BackNavigationEventArgs is a class to record back navigation event arguments which will sent to user.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class BackNavigationEventArgs : EventArgs
+    {
     }
 }