Skip to content

Instantly share code, notes, and snippets.

@JimmyPun610
Last active February 20, 2024 02:36
Show Gist options
  • Save JimmyPun610/521e9d166ea5f623178c2d417a1da6cc to your computer and use it in GitHub Desktop.
Save JimmyPun610/521e9d166ea5f623178c2d417a1da6cc to your computer and use it in GitHub Desktop.
Fixing Mopups Android Accessibility read by Talkback issue

In App.cs

   public App()
   {
        // .... All init methods....
#if ANDROID
        Mopups.Services.MopupService.Instance.Popped += Instance_Popped;
        Mopups.Services.MopupService.Instance.Pushed += Instance_Pushed;
#endif
   }

   private void Instance_Popped(object sender, Mopups.Events.PopupNavigationEventArgs e)
   {
       _accessibilityManager.ChangeAccessibilityForPopupPage(true, App.Current.MainPage);
       foreach (var modal in App.Current.MainPage.Navigation.ModalStack)
           _accessibilityManager.ChangeAccessibilityForPopupPage(true, modal);
       foreach (var ns in App.Current.MainPage.Navigation.NavigationStack)
           _accessibilityManager.ChangeAccessibilityForPopupPage(true, ns);
   }
   private void Instance_Pushed(object sender, Mopups.Events.PopupNavigationEventArgs e)
   {
       // When the page popup, we reset the list that storing previous controls
       _accessibilityManager.ChangeAccessibilityForPopupPage(false, App.Current.MainPage, true);
       foreach (var modal in App.Current.MainPage.Navigation.ModalStack)
           _accessibilityManager.ChangeAccessibilityForPopupPage(false, modal);
       foreach (var ns in App.Current.MainPage.Navigation.NavigationStack)
           _accessibilityManager.ChangeAccessibilityForPopupPage(false, ns);
   }

In Android implementation (AccessibilityManager.cs)

     public void ChangeAccessibilityForPopupPage(bool isAccessible, Page page, bool shouldReset = false)
     {
         if (shouldReset)
             importantForAccessibilities = new List<ViewOriginalImportance>();

         SetItemInAccessibilityTree(isAccessible, page);
     }

     class ViewOriginalImportance
     {
         public Android.Views.View View { get; set; }
         public Android.Views.ImportantForAccessibility OriginalImportance { get; set; }
     }
     List<ViewOriginalImportance> importantForAccessibilities = new List<ViewOriginalImportance>();


     private void SetItemInAccessibilityTree(bool isInAccessibilityTree, Page page)
     {
         if (page is FlyoutPage fp)
         {
             SetItemInAccessibilityTree(isInAccessibilityTree, fp.Detail);
             SetItemInAccessibilityTree(isInAccessibilityTree, fp.Flyout);
         }
         else if (page is NavigationPage np)
         {
             SetItemInAccessibilityTree(isInAccessibilityTree, np.CurrentPage);
             // Due with toolbar
             // https://stackoverflow.com/questions/75596420/how-do-i-add-a-listener-to-the-android-toolbar-in-maui
             var linearLayout = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.FindViewById<Android.Widget.LinearLayout>(UltracsApp3.Resource.Id.navigationlayout_appbar);
             if (linearLayout != null)
             {
                 var child1 = linearLayout.GetChildAt(0);

                 if (child1 is Google.Android.Material.AppBar.MaterialToolbar toolbarView)
                 {
                     RecursivelyChangeAccessibilityOfViewChildren(toolbarView, isInAccessibilityTree);
                     for (int i = 0; i < toolbarView.ChildCount; i++)
                     {
                         var v = toolbarView.GetChildAt(i);
                         RecursivelyChangeAccessibilityOfViewChildren(v, isInAccessibilityTree);
                     }
                 }

             }

         }

         var view = (page?.Handler?.PlatformView as Android.Views.View);
         if (view != null)
             RecursivelyChangeAccessibilityOfViewChildren(view, isInAccessibilityTree);
     }


     private void RecursivelyChangeAccessibilityOfViewChildren(Android.Views.View view, bool isInAccessibilityTree)
     {
         if (view is Android.Views.ViewGroup vGroup)
         {
             for (int i = 0; i < vGroup.ChildCount; i++)
             {
                 Android.Views.View vChild = vGroup.GetChildAt(i);
                 if (isInAccessibilityTree)
                 {
                     // In this case, we are reverting the value to it's default
                     var existingItem = importantForAccessibilities.FirstOrDefault(o => o.View == vChild);
                     if (existingItem != null)
                         vChild.ImportantForAccessibility = existingItem.OriginalImportance;
                     // Somehow we do not get any item matched...assign it to auto...This should not happen
                     else vChild.ImportantForAccessibility = Android.Views.ImportantForAccessibility.Auto;
                 }
                 else
                 {
                     // In this case, we are setting it to NoHideDescendants
                     importantForAccessibilities.Add(new ViewOriginalImportance
                     {
                         View = vChild,
                         OriginalImportance = vChild.ImportantForAccessibility
                     });
                     vChild.ImportantForAccessibility = Android.Views.ImportantForAccessibility.NoHideDescendants;
                 }
                 vChild.ClearFocus();
                 RecursivelyChangeAccessibilityOfViewChildren(vChild, isInAccessibilityTree);
             }
         }
     }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment