Enable voice over mode on device while running in accessibility exploration mode

Summary:
All the FoA have different logic depending on whether device is running in  VoiceOver mode or not. This results in incorrect accessibility being reported through the Flipper plugin.

For example on Instagram we fetch the image descriptions, in Facebook app we group individual elements into the accessibility groups to simplify traversing the screen

This tells device that it is in a voice over mode while inspecting accessibility mode is on meaning that it will be the closest approximation to the

Reviewed By: nscoding

Differential Revision: D49579241

fbshipit-source-id: f3be9057007ee6eefbe3b448f0f97c1fcd2c8f46
This commit is contained in:
Sash Zats
2023-09-24 12:24:19 -07:00
committed by Facebook GitHub Bot
parent 7d77be1c9d
commit f2e402e6e9
3 changed files with 37 additions and 0 deletions

View File

@@ -33,6 +33,15 @@
[self processNode:node withSnapshot:false withContext:context]; [self processNode:node withSnapshot:false withContext:context];
} }
- (void)setTraversalMode:(UIDTraversalMode)traversalMode {
if (_traversalMode == traversalMode) {
return;
}
_traversalMode = traversalMode;
[UIDAllyTraversal setVoiceOverServiceEnabled:traversalMode ==
UIDTraversalModeAccessibilityHierarchy];
}
- (void)processNode:(id)node - (void)processNode:(id)node
withSnapshot:(BOOL)snapshot withSnapshot:(BOOL)snapshot
withContext:(UIDContext*)context { withContext:(UIDContext*)context {

View File

@@ -17,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface UIDAllyTraversal : NSObject @interface UIDAllyTraversal : NSObject
+ (void)setVoiceOverServiceEnabled:(BOOL)enabled;
@property(nonatomic, class, readonly, getter=isSupported) BOOL supported; @property(nonatomic, class, readonly, getter=isSupported) BOOL supported;
- (instancetype)initWithDescriptorRegister: - (instancetype)initWithDescriptorRegister:

View File

@@ -8,6 +8,7 @@
#if FB_SONARKIT_ENABLED #if FB_SONARKIT_ENABLED
#import "UIDAllyTraversal.h" #import "UIDAllyTraversal.h"
#import <dlfcn.h>
#import "UIDDescriptorRegister.h" #import "UIDDescriptorRegister.h"
#import "UIDMetadataRegister.h" #import "UIDMetadataRegister.h"
#import "UIDNode.h" #import "UIDNode.h"
@@ -34,6 +35,12 @@
(_accessibilityLeafDescendantsWithOptions:)]; (_accessibilityLeafDescendantsWithOptions:)];
} }
+ (void)setVoiceOverServiceEnabled:(BOOL)enabled {
if (self.isSupported) {
_setVoiceOver(enabled);
}
}
- (instancetype)initWithDescriptorRegister: - (instancetype)initWithDescriptorRegister:
(UIDDescriptorRegister*)descriptorRegister { (UIDDescriptorRegister*)descriptorRegister {
self = [super init]; self = [super init];
@@ -114,6 +121,25 @@ static BOOL _loadAccessibilityFramework(void) {
return isAccessibilityFrameworkLoaded; return isAccessibilityFrameworkLoaded;
} }
static void _setVoiceOver(BOOL enabled) {
NSString* const accessibilityUtilitiesPath =
[[NSBundle bundleForClass:UIApplication.class]
.bundleURL.URLByDeletingLastPathComponent
.URLByDeletingLastPathComponent
URLByAppendingPathComponent:
@"PrivateFrameworks/AccessibilityUtilities.framework/AccessibilityUtilities"]
.relativePath;
void* handler = dlopen(
[accessibilityUtilitiesPath cStringUsingEncoding:NSUTF8StringEncoding],
RTLD_NOW);
if (!handler) {
return;
}
void (*_AXSVoiceOverTouchSetEnabled)(BOOL) =
dlsym(handler, "_AXSVoiceOverTouchSetEnabled");
_AXSVoiceOverTouchSetEnabled(enabled);
}
static NSString* _nameForNode(NSObject* node) { static NSString* _nameForNode(NSObject* node) {
NSMutableArray* const parts = [NSMutableArray new]; NSMutableArray* const parts = [NSMutableArray new];
if (node.accessibilityLabel.length > 0) { if (node.accessibilityLabel.length > 0) {