Skip to content

Commit 614eec7

Browse files
author
Bianca Marina Stana
committed
Simplified the accessibility hierarchy
1 parent 66cb678 commit 614eec7

File tree

4 files changed

+47
-161
lines changed

4 files changed

+47
-161
lines changed

Assets/Scripts/Screen Reader/AccessibilityManager.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -362,11 +362,7 @@ static void RemoveSubHierarchyForService(AccessibilityService service)
362362

363363
static void CreateSubHierarchyForService(AccessibilityService service)
364364
{
365-
var rootNode = hierarchy.AddNode(service.serviceName);
366-
rootNode.role = AccessibilityRole.Container;
367-
rootNode.isActive = Application.platform == RuntimePlatform.OSXPlayer; // false;
368-
369-
service.hierarchy = new AccessibilitySubHierarchy(hierarchy, rootNode);
365+
service.hierarchy = new AccessibilitySubHierarchy(hierarchy);
370366
}
371367

372368
static void GenerateSubHierarchyForService(Scene scene, AccessibilityService service)

Assets/Scripts/Screen Reader/AccessibilitySubHierarchy.cs

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Generic;
12
using UnityEngine;
23
using UnityEngine.Accessibility;
34

@@ -17,7 +18,7 @@ public struct AccessibilitySubHierarchy
1718
/// <summary>
1819
/// Returns the node used as root for this sub-hierarchy.
1920
/// </summary>
20-
public AccessibilityNode rootNode { get; private set; }
21+
public List<AccessibilityNode> rootNodes { get; private set; }
2122

2223
/// <summary>
2324
/// Returns true if this sub-hierarchy is valid.
@@ -27,39 +28,31 @@ public struct AccessibilitySubHierarchy
2728
/// <summary>
2829
/// Constructs a sub-hierarchy from the specified hierarchy and root node.
2930
/// </summary>
30-
/// <param name="mainHierarchy"></param>
31-
/// <param name="rootNode"></param>
32-
public AccessibilitySubHierarchy(AccessibilityHierarchy mainHierarchy, AccessibilityNode rootNode)
31+
/// <param name="hierarchy"></param>
32+
public AccessibilitySubHierarchy(AccessibilityHierarchy hierarchy)
3333
{
34-
// Assert that the main hierarchy exists.
35-
if (mainHierarchy == null)
36-
{
37-
throw new System.ArgumentNullException(nameof(mainHierarchy), "The main hierarchy cannot be null.");
38-
}
39-
40-
// Assert that the root node belongs to the main hierarchy.
41-
if (rootNode != null && !mainHierarchy.ContainsNode(rootNode))
42-
{
43-
throw new System.ArgumentException("The root node must belong to the main hierarchy.", nameof(rootNode));
44-
}
45-
46-
// Note: if the root element is null then the sub-hierarchy represents the whole hierarchy.
47-
this.mainHierarchy = mainHierarchy;
48-
this.rootNode = rootNode;
34+
mainHierarchy = hierarchy ?? throw new System.ArgumentNullException(nameof(hierarchy), "The main hierarchy cannot be null.");
35+
rootNodes = new List<AccessibilityNode>();
4936
}
5037

5138
/// <summary>
5239
/// Disposes the sub-hierarchy removing the root node from the main hierarchy.
5340
/// </summary>
5441
public void Dispose()
5542
{
56-
if (mainHierarchy != null && rootNode != null && mainHierarchy.ContainsNode(rootNode))
43+
if (mainHierarchy != null)
5744
{
58-
mainHierarchy.RemoveNode(rootNode);
45+
foreach (var rootNode in rootNodes)
46+
{
47+
if (mainHierarchy.ContainsNode(rootNode))
48+
{
49+
mainHierarchy.RemoveNode(rootNode);
50+
}
51+
}
5952
}
6053

6154
mainHierarchy = null;
62-
rootNode = null;
55+
rootNodes?.Clear();
6356
}
6457

6558
/// <summary>
@@ -80,16 +73,16 @@ public bool ContainsNode(AccessibilityNode node)
8073
}
8174

8275
// We know the node is in the main hierarchy, now we need to check if it's part of this sub-hierarchy.
83-
var parentNode = node.parent;
76+
var currentNode = node;
8477

85-
while (parentNode != null)
78+
while (currentNode != null)
8679
{
87-
if (parentNode == rootNode)
80+
if (rootNodes.Contains(currentNode))
8881
{
8982
return true;
9083
}
9184

92-
parentNode = parentNode.parent;
85+
currentNode = currentNode.parent;
9386
}
9487

9588
return false;
@@ -159,9 +152,14 @@ public AccessibilityNode InsertNode(int childIndex, string label = null, Accessi
159152
return null;
160153
}
161154

162-
var actualParent = parent ?? rootNode;
155+
var node = mainHierarchy.InsertNode(childIndex, label, parent);
156+
157+
if (parent == null)
158+
{
159+
rootNodes.Add(node);
160+
}
163161

164-
return mainHierarchy.AddNode(label, actualParent);
162+
return node;
165163
}
166164

167165
/// <summary>
@@ -178,9 +176,7 @@ public bool MoveNode(AccessibilityNode node, AccessibilityNode newParent, int ne
178176
return false;
179177
}
180178

181-
var actualParent = newParent ?? rootNode;
182-
183-
return mainHierarchy.MoveNode(node, actualParent, newChildIndex);
179+
return mainHierarchy.MoveNode(node, newParent, newChildIndex);
184180
}
185181

186182
/// <summary>
@@ -203,12 +199,12 @@ public void RemoveNode(AccessibilityNode node, bool removeChildren = true)
203199
/// </summary>
204200
public void Clear()
205201
{
206-
if (rootNode != null)
202+
if (rootNodes is { Count: > 0 })
207203
{
208204
// Removes from the last to the first to avoid messing up the indices.
209-
for (var i = rootNode.children.Count - 1; i >= 0; i--)
205+
for (var i = rootNodes.Count - 1; i >= 0; i--)
210206
{
211-
mainHierarchy.RemoveNode(rootNode.children[i]);
207+
mainHierarchy.RemoveNode(rootNodes[i]);
212208
}
213209
}
214210
else

Assets/Scripts/Screen Reader/UITk/UITkAccessibilityService.cs

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -27,51 +27,8 @@ public UITkAccessibilityService() : base("UITk", 100)
2727
AssistiveSupport.nodeFocusChanged += OnNodeFocusChanged;
2828
}
2929

30-
bool m_NeedsToRecomputeRootFrames;
31-
32-
public void DirtyRootFrames()
33-
{
34-
m_NeedsToRecomputeRootFrames = true;
35-
}
36-
37-
public void UpdateRootAndPanelFrames()
38-
{
39-
m_NeedsToRecomputeRootFrames = true;
40-
41-
foreach (var accessibilityUpdater in m_AccessibilityUpdaters)
42-
{
43-
accessibilityUpdater.UpdateRootFrame();
44-
}
45-
46-
var serviceRootFrame = Rect.zero;
47-
48-
foreach (var panelNode in hierarchy.rootNode.children)
49-
{
50-
// Calculate the union of all root nodes frames.
51-
if (panelNode.frame.size != Vector2.zero)
52-
{
53-
Encompass(ref serviceRootFrame, panelNode.frame);
54-
}
55-
}
56-
57-
hierarchy.rootNode.frame = serviceRootFrame;
58-
void Encompass(ref Rect a, Rect b)
59-
{
60-
a.xMin = Math.Min(a.xMin, b.xMin);
61-
a.yMin = Math.Min(a.yMin, b.yMin);
62-
a.xMax = Math.Max(a.xMax, b.xMax);
63-
a.yMax = Math.Max(a.yMax, b.yMax);
64-
}
65-
}
66-
6730
public override void Update()
6831
{
69-
if (m_NeedsToRecomputeRootFrames)
70-
{
71-
UpdateRootAndPanelFrames();
72-
m_NeedsToRecomputeRootFrames = false;
73-
}
74-
7532
foreach (var accessibilityUpdater in m_AccessibilityUpdaters)
7633
{
7734
accessibilityUpdater.Update();
@@ -172,11 +129,6 @@ public override void SetUp(Scene scene)
172129
}
173130

174131
var panel = uiDocument.runtimePanel;
175-
var rootAcc = uiDocument.rootVisualElement.GetOrCreateAccessibleProperties();
176-
177-
rootAcc.label = uiDocument.rootVisualElement.name;
178-
rootAcc.active = Application.platform == RuntimePlatform.OSXPlayer; // false;
179-
rootAcc.role = AccessibilityRole.Container;
180132

181133
if (!panels.Contains(panel))
182134
{

Assets/Scripts/Screen Reader/UITk/VisualTreeAccessibilityUpdater.cs

Lines changed: 16 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,11 @@ enum NotificationType
3434
VisualElement m_VisualTree;
3535
IVisualElementScheduledItem m_UpdateJob;
3636
UITkAccessibilityService m_AccessibilityService;
37-
AccessibilitySubHierarchy m_SubHierarchy;
3837

3938
/// <summary>
4039
/// The sub-hierarchy this updater is managing.
4140
/// </summary>
42-
public AccessibilitySubHierarchy hierarchy
43-
{
44-
get => m_SubHierarchy;
45-
set
46-
{
47-
m_SubHierarchy = value;
48-
49-
if (m_SubHierarchy.isValid && visualTree != null)
50-
{
51-
DirtyRootFrame();
52-
}
53-
}
54-
}
41+
public AccessibilitySubHierarchy hierarchy { get; set; }
5542

5643
/// <summary>
5744
/// The panel of the visual tree being managed.
@@ -111,14 +98,10 @@ public VisualTreeAccessibilityUpdater(IPanel panel, VisualElement visualTree, UI
11198
m_AccessibilityService = service;
11299
visualTree.RegisterCallback<AttachToPanelEvent>(OnAttachmentToPanel);
113100
visualTree.RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);
114-
115-
DirtyRootFrame();
116101
}
117102

118103
void OnGeometryChanged(GeometryChangedEvent evt)
119104
{
120-
DirtyRootFrame();
121-
122105
// OnScreenDebug.Log("OnGeometryChanged " + evt.target);
123106

124107
OnVersionChanged(evt.target as VisualElement, VersionChangeType.Size | VersionChangeType.Transform);
@@ -187,11 +170,10 @@ VisualElementAccessibilityHandler CreateHandler(VisualElement element)
187170

188171
void InsertNode(VisualElementAccessibilityHandler parentHandler, VisualElementAccessibilityHandler accHandler)
189172
{
190-
var p = parentHandler;
191-
var parentNode = p?.node;
173+
var parentNode = parentHandler?.node;
192174

193175
// Keep track of insertion index for each parent node.
194-
var index = p?.nextInsertionIndex ?? m_RootNextInsertionIndex;
176+
var index = parentHandler?.nextInsertionIndex ?? m_RootNextInsertionIndex;
195177
var node = hierarchy.InsertNode(index, accHandler.ownerElement.name, parentNode);
196178

197179
accHandler.node = node;
@@ -202,9 +184,9 @@ void InsertNode(VisualElementAccessibilityHandler parentHandler, VisualElementAc
202184

203185
m_HandlersForNodes[node] = accHandler;
204186

205-
if (p != null)
187+
if (parentHandler != null)
206188
{
207-
p.nextInsertionIndex++;
189+
parentHandler.nextInsertionIndex++;
208190
}
209191
else
210192
{
@@ -216,14 +198,13 @@ void InsertNode(VisualElementAccessibilityHandler parentHandler, VisualElementAc
216198

217199
bool MoveNode(VisualElementAccessibilityHandler parentElement, VisualElementAccessibilityHandler accHandler)
218200
{
219-
var p = parentElement;
220-
var parentNode = p?.node;
221-
var index = p?.nextInsertionIndex ?? m_RootNextInsertionIndex;
201+
var parentNode = parentElement?.node;
202+
var index = parentElement?.nextInsertionIndex ?? m_RootNextInsertionIndex;
222203
var moved = hierarchy.MoveNode(accHandler.node, parentNode, index);
223204

224-
if (p != null)
205+
if (parentElement != null)
225206
{
226-
p.nextInsertionIndex++;
207+
parentElement.nextInsertionIndex++;
227208
}
228209
else
229210
{
@@ -431,19 +412,6 @@ void GetMinMaxY(Vector3[] vector, out float min, out float max)
431412
}
432413
}
433414

434-
void DirtyRootFrame()
435-
{
436-
m_AccessibilityService.DirtyRootFrames();
437-
}
438-
439-
public void UpdateRootFrame()
440-
{
441-
if (hierarchy.isValid)
442-
{
443-
hierarchy.rootNode.frame = GetScreenPosition(visualTree);
444-
}
445-
}
446-
447415
void UpdateNode(VisualElementAccessibilityHandler accElement)
448416
{
449417
if (!IsNodeValid(accElement.node))
@@ -528,30 +496,9 @@ public void Update()
528496
Update(visualTree);
529497
}
530498

531-
string GetPanelName(VisualElement ve)
532-
{
533-
// Try to get the name of the panel using reflection.
534-
var panel = ve.panel;
535-
536-
if (panel == null)
537-
{
538-
return null;
539-
}
540-
541-
var panelType = panel.GetType();
542-
var nameProperty = panelType.GetProperty("name");
543-
544-
if (nameProperty != null)
545-
{
546-
return nameProperty.GetValue(panel, null) as string;
547-
}
548-
549-
return null;
550-
}
551-
552499
NotificationType m_Notification = NotificationType.None;
553500

554-
void Update(VisualElement visualTree)
501+
void Update(VisualElement ve)
555502
{
556503
var shouldSendNotification = false;
557504

@@ -563,13 +510,8 @@ void Update(VisualElement visualTree)
563510
{
564511
if (!hierarchy.isValid)
565512
{
566-
var panelName = GetPanelName(visualTree);
567-
var rootNode = m_AccessibilityService.hierarchy.AddNode(string.IsNullOrEmpty(panelName) ?
568-
visualTree.name : panelName);
569-
rootNode.role = AccessibilityRole.Container;
570-
rootNode.isActive = Application.platform == RuntimePlatform.OSXPlayer;
571-
hierarchy = new AccessibilitySubHierarchy(m_AccessibilityService.hierarchy.mainHierarchy, rootNode);
572-
DirtyRootFrame();
513+
hierarchy = new AccessibilitySubHierarchy(m_AccessibilityService.hierarchy.mainHierarchy);
514+
573515
shouldSendNotification = true;
574516
}
575517

@@ -580,24 +522,24 @@ void Update(VisualElement visualTree)
580522

581523
var modalElement = currentModalElement;
582524

583-
UpdateAccessibilityHierarchyRecursively(visualTree, null, false, true);
525+
UpdateAccessibilityHierarchyRecursively(ve, null, false, true);
584526

585527
// If there is a current modal element or if the current model element has changed then update the
586528
// active state of all nodes.
587529
if (currentModalElement != null || currentModalElement != modalElement)
588530
{
589531
OnScreenDebug.Log("Updating active state from modality " + currentModalElement?.name);
590-
UpdateActiveStateFromModalityRecursively(visualTree);
532+
UpdateActiveStateFromModalityRecursively(ve);
591533
}
592534
}
593535

594536
if (shouldSendNotification || m_Notification.HasFlag(NotificationType.ScreenChanged))
595537
{
596-
visualTree.schedule.Execute(() => AssistiveSupport.notificationDispatcher.SendScreenChanged());
538+
ve.schedule.Execute(() => AssistiveSupport.notificationDispatcher.SendScreenChanged());
597539
}
598540
else if (m_Notification.HasFlag(NotificationType.LayoutChanged))
599541
{
600-
visualTree.schedule.Execute(() => AssistiveSupport.notificationDispatcher.SendLayoutChanged());
542+
ve.schedule.Execute(() => AssistiveSupport.notificationDispatcher.SendLayoutChanged());
601543
}
602544
}
603545

0 commit comments

Comments
 (0)