Skip to content

Commit 9c5338a

Browse files
rm-gh-8Paul Hohensee
authored andcommitted
8286258: [Accessibility,macOS,VoiceOver] VoiceOver reads the spinner value wrong and sometime partially
Backport-of: 8c82b58
1 parent 596db3c commit 9c5338a

4 files changed

Lines changed: 139 additions & 4 deletions

File tree

src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -29,5 +29,6 @@
2929
@interface NavigableTextAccessibility : CommonComponentAccessibility <NSAccessibilityNavigableStaticText>
3030

3131
@property(readonly) BOOL accessibleIsPasswordText;
32+
@property BOOL announceEditUpdates;
3233

3334
@end

src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -60,6 +60,22 @@ - (BOOL)accessibleIsPasswordText {
6060
return [fJavaRole isEqualToString:@"passwordtext"];
6161
}
6262

63+
- (id)init {
64+
self = [super init];
65+
if (self) {
66+
_announceEditUpdates = YES;
67+
}
68+
return self;
69+
}
70+
71+
- (void)suppressEditUpdates {
72+
_announceEditUpdates = NO;
73+
}
74+
75+
- (void)resumeEditUpdates {
76+
_announceEditUpdates = YES;
77+
}
78+
6379
// NSAccessibilityElement protocol methods
6480

6581
- (NSRect)accessibilityFrameForRange:(NSRange)range
@@ -117,6 +133,9 @@ - (NSRange)accessibilityRangeForLine:(NSInteger)line
117133

118134
- (NSString *)accessibilityStringForRange:(NSRange)range
119135
{
136+
if (!_announceEditUpdates) {
137+
return @"";
138+
}
120139
JNIEnv *env = [ThreadUtilities getJNIEnv];
121140
GET_CACCESSIBLETEXT_CLASS_RETURN(nil);
122141
DECLARE_STATIC_METHOD_RETURN(jm_getStringForRange, sjc_CAccessibleText, "getStringForRange",
@@ -306,6 +325,12 @@ - (id)accessibilityParent
306325
return [super accessibilityParent];
307326
}
308327

328+
- (void)postSelectedTextChanged
329+
{
330+
[super postSelectedTextChanged];
331+
[self resumeEditUpdates];
332+
}
333+
309334
/*
310335
* Other text methods
311336
- (NSRange)accessibilitySharedCharacterRange;

src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/SpinboxAccessibility.m

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
2424
*/
2525

2626
#import "SpinboxAccessibility.h"
27+
#import "ThreadUtilities.h"
2728

2829
#define INCREMENT 0
2930
#define DECREMENT 1
@@ -44,7 +45,15 @@ - (NSString * _Nullable)accessibilityLabel
4445

4546
- (id _Nullable)accessibilityValue
4647
{
47-
return [super accessibilityValue];
48+
id val = [super accessibilityValue];
49+
NSArray *clist = [super accessibilityChildren];
50+
for (NSUInteger i = 0; i < [clist count]; i++) {
51+
id child = [clist objectAtIndex:i];
52+
if ([child conformsToProtocol:@protocol(NSAccessibilityNavigableStaticText)]) {
53+
val = [child accessibilityValue];
54+
}
55+
}
56+
return val;
4857
}
4958

5059
- (BOOL)accessibilityPerformIncrement
@@ -68,4 +77,18 @@ - (id)accessibilityParent
6877
return [super accessibilityParent];
6978
}
7079

80+
- (void)postValueChanged
81+
{
82+
AWT_ASSERT_APPKIT_THREAD;
83+
NSAccessibilityPostNotification(self, NSAccessibilityValueChangedNotification);
84+
NSArray *clist = [super accessibilityChildren];
85+
for (NSUInteger i = 0; i < [clist count]; i++) {
86+
id child = [clist objectAtIndex:i];
87+
if ([child conformsToProtocol:@protocol(NSAccessibilityNavigableStaticText)]) {
88+
NSAccessibilityPostNotification(child, NSAccessibilityLayoutChangedNotification);
89+
[child suppressEditUpdates];
90+
}
91+
}
92+
}
93+
7194
@end
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.awt.GridLayout;
25+
import java.lang.reflect.InvocationTargetException;
26+
import javax.swing.JLabel;
27+
import javax.swing.JPanel;
28+
import javax.swing.JSpinner;
29+
import javax.swing.SpinnerListModel;
30+
31+
/*
32+
* @test
33+
* @bug 8286258
34+
* @library /java/awt/regtesthelpers
35+
* @build PassFailJFrame
36+
* @requires (os.family == "mac")
37+
* @summary Checks that JSpinner with custom model announces
38+
* the value every time it is changed
39+
* @run main/manual CustomSpinnerAccessibilityTest
40+
*/
41+
42+
public class CustomSpinnerAccessibilityTest extends JPanel {
43+
private static final String INSTRUCTIONS = """
44+
1. Turn on VoiceOver
45+
2. In the window named "Test UI" click on the text editor inside the
46+
spinner component
47+
3. Using up and down arrows change current month
48+
4. Wait for the VoiceOver to finish speaking
49+
5. Repeat steps 3 and 4 couple more times
50+
51+
If every time value of the spinner is changed VoiceOver
52+
announces the new value click "Pass".
53+
If instead the value is narrated only partially
54+
and the new value is never fully narrated press "Fail".
55+
""";
56+
57+
public CustomSpinnerAccessibilityTest() {
58+
super(new GridLayout(0, 2));
59+
String[] monthStrings = new java.text.DateFormatSymbols().getMonths();
60+
int lastIndex = monthStrings.length - 1;
61+
if (monthStrings[lastIndex] == null
62+
|| monthStrings[lastIndex].length() <= 0) {
63+
String[] tmp = new String[lastIndex];
64+
System.arraycopy(monthStrings, 0,
65+
tmp, 0, lastIndex);
66+
monthStrings = tmp;
67+
}
68+
69+
SpinnerListModel model = new SpinnerListModel(monthStrings);
70+
JLabel label = new JLabel("Month: ");
71+
add(label);
72+
JSpinner spinner = new JSpinner(model);
73+
label.setLabelFor(spinner);
74+
add(spinner);
75+
}
76+
77+
public static void main(String[] args) throws InterruptedException,
78+
InvocationTargetException {
79+
PassFailJFrame.builder()
80+
.title("Custom Spinner Accessibility Test")
81+
.instructions(INSTRUCTIONS)
82+
.testUI(CustomSpinnerAccessibilityTest::new)
83+
.build()
84+
.awaitAndCheck();
85+
}
86+
}

0 commit comments

Comments
 (0)