Files
custom_wda/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m

143 lines
4.1 KiB
Mathematica
Raw Normal View History

2026-02-03 16:52:44 +08:00
/**
* Copyright (c) 2018-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "FBTVNavigationTracker.h"
#import "FBTVNavigationTracker-Private.h"
#import "FBMathUtils.h"
#import "XCUIElement+FBCaching.h"
#import "XCUIElement+FBUtilities.h"
#import "XCUIElement+FBWebDriverAttributes.h"
#import "XCUIApplication+FBHelpers.h"
#if TARGET_OS_TV
@implementation FBTVNavigationItem
+ (instancetype)itemWithUid:(NSString *) uid
{
return [[FBTVNavigationItem alloc] initWithUid:uid];
}
- (instancetype)initWithUid:(NSString *) uid
{
self = [super init];
if(self) {
_uid = uid;
_directions = [NSMutableSet set];
}
return self;
}
@end
@interface FBTVNavigationTracker ()
@property (nonatomic, strong) XCUIElement *targetElement;
@property (nonatomic, assign) CGPoint targetCenter;
@property (nonatomic, strong) NSMutableDictionary<NSString *, FBTVNavigationItem* >* navigationItems;
@end
@implementation FBTVNavigationTracker
+ (instancetype)trackerWithTargetElement:(XCUIElement *)targetElement
{
FBTVNavigationTracker *tracker = [[FBTVNavigationTracker alloc] initWithTargetElement:targetElement];
tracker.targetElement = targetElement;
return tracker;
}
- (instancetype)initWithTargetElement:(XCUIElement *)targetElement
{
self = [super init];
if (self) {
_targetElement = targetElement;
CGRect frame = targetElement.wdFrame;
_targetCenter = FBRectGetCenter(frame);
_navigationItems = [NSMutableDictionary dictionary];
}
return self;
}
- (FBTVDirection)directionToFocusedElement
{
XCUIElement *focused = XCUIApplication.fb_activeApplication.fb_focusedElement;
CGPoint focusedCenter = FBRectGetCenter(focused.wdFrame);
FBTVNavigationItem *item = [self navigationItemWithElement:focused];
CGFloat yDelta = self.targetCenter.y - focusedCenter.y;
CGFloat xDelta = self.targetCenter.x - focusedCenter.x;
FBTVDirection direction;
if (fabs(yDelta) > fabs(xDelta)) {
direction = [self verticalDirectionWithItem:item andDelta:yDelta];
if (direction == FBTVDirectionNone) {
direction = [self horizontalDirectionWithItem:item andDelta:xDelta];
}
} else {
direction = [self horizontalDirectionWithItem:item andDelta:xDelta];
if (direction == FBTVDirectionNone) {
direction = [self verticalDirectionWithItem:item andDelta:yDelta];
}
}
return direction;
}
#pragma mark - Utilities
- (FBTVNavigationItem*)navigationItemWithElement:(id<FBElement>)element
{
NSString *uid = element.wdUID;
if (nil == uid) {
return nil;
}
FBTVNavigationItem* item = [self.navigationItems objectForKey:uid];
if (nil != item) {
return item;
}
item = [FBTVNavigationItem itemWithUid:uid];
[self.navigationItems setObject:item forKey:uid];
return item;
}
- (FBTVDirection)horizontalDirectionWithItem:(FBTVNavigationItem *)item andDelta:(CGFloat)delta
{
// GCFloat is double in 64bit. tvOS is only for arm64
if (delta > DBL_EPSILON &&
![item.directions containsObject: [NSNumber numberWithInteger: FBTVDirectionRight]]) {
[item.directions addObject: [NSNumber numberWithInteger: FBTVDirectionRight]];
return FBTVDirectionRight;
}
if (delta < -DBL_EPSILON &&
![item.directions containsObject: [NSNumber numberWithInteger: FBTVDirectionLeft]]) {
[item.directions addObject: [NSNumber numberWithInteger: FBTVDirectionLeft]];
return FBTVDirectionLeft;
}
return FBTVDirectionNone;
}
- (FBTVDirection)verticalDirectionWithItem:(FBTVNavigationItem *)item andDelta:(CGFloat)delta
{
// GCFloat is double in 64bit. tvOS is only for arm64
if (delta > DBL_EPSILON &&
![item.directions containsObject: [NSNumber numberWithInteger: FBTVDirectionDown]]) {
[item.directions addObject: [NSNumber numberWithInteger: FBTVDirectionDown]];
return FBTVDirectionDown;
}
if (delta < -DBL_EPSILON &&
![item.directions containsObject: [NSNumber numberWithInteger: FBTVDirectionUp]]) {
[item.directions addObject: [NSNumber numberWithInteger: FBTVDirectionUp]];
return FBTVDirectionUp;
}
return FBTVDirectionNone;
}
@end
#endif