Skip to main content
Glama
XCUIApplicationProcess+FBQuiescence.m4.67 kB
#import "XCUIApplicationProcess+FBQuiescence.h" #import <objc/runtime.h> #import "FBConfiguration.h" #import "FBLogger.h" static void (*original_waitForQuiescenceIncludingAnimationsIdle)(id, SEL, BOOL); static void (*original_waitForQuiescenceIncludingAnimationsIdlePreEvent)(id, SEL, BOOL, BOOL); static void swizzledWaitForQuiescenceIncludingAnimationsIdle(id self, SEL _cmd, BOOL includingAnimations) { NSString *bundleId = [self bundleID]; if (![[self fb_shouldWaitForQuiescence] boolValue] || FBConfiguration.waitForIdleTimeout < DBL_EPSILON) { [FBLogger logFmt:@"Quiescence checks are disabled for %@ application. Making it to believe it is idling", bundleId]; return; } NSTimeInterval desiredTimeout = FBConfiguration.waitForIdleTimeout; NSTimeInterval previousTimeout = _XCTApplicationStateTimeout(); _XCTSetApplicationStateTimeout(desiredTimeout); [FBLogger logFmt:@"Waiting up to %@s until %@ is in idle state (%@ animations)", @(desiredTimeout), bundleId, includingAnimations ? @"including" : @"excluding"]; @try { original_waitForQuiescenceIncludingAnimationsIdle(self, _cmd, includingAnimations); } @finally { _XCTSetApplicationStateTimeout(previousTimeout); } } static void swizzledWaitForQuiescenceIncludingAnimationsIdlePreEvent(id self, SEL _cmd, BOOL includingAnimations, BOOL isPreEvent) { NSString *bundleId = [self bundleID]; if (![[self fb_shouldWaitForQuiescence] boolValue] || FBConfiguration.waitForIdleTimeout < DBL_EPSILON) { [FBLogger logFmt:@"Quiescence checks are disabled for %@ application. Making it to believe it is idling", bundleId]; return; } NSTimeInterval desiredTimeout = FBConfiguration.waitForIdleTimeout; NSTimeInterval previousTimeout = _XCTApplicationStateTimeout(); _XCTSetApplicationStateTimeout(desiredTimeout); [FBLogger logFmt:@"Waiting up to %@s until %@ is in idle state (%@ animations)", @(desiredTimeout), bundleId, includingAnimations ? @"including" : @"excluding"]; @try { original_waitForQuiescenceIncludingAnimationsIdlePreEvent(self, _cmd, includingAnimations, isPreEvent); } @finally { _XCTSetApplicationStateTimeout(previousTimeout); } } @implementation XCUIApplicationProcess (FBQuiescence) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-load-method" #pragma clang diagnostic ignored "-Wcast-function-type-strict" + (void)load { Method waitForQuiescenceIncludingAnimationsIdleMethod = class_getInstanceMethod(self.class, @selector(waitForQuiescenceIncludingAnimationsIdle:)); Method waitForQuiescenceIncludingAnimationsIdlePreEventMethod = class_getInstanceMethod(self.class, @selector(waitForQuiescenceIncludingAnimationsIdle:isPreEvent:)); if (nil != waitForQuiescenceIncludingAnimationsIdleMethod) { IMP swizzledImp = (IMP)swizzledWaitForQuiescenceIncludingAnimationsIdle; original_waitForQuiescenceIncludingAnimationsIdle = (void (*)(id, SEL, BOOL)) method_setImplementation(waitForQuiescenceIncludingAnimationsIdleMethod, swizzledImp); } else if (nil != waitForQuiescenceIncludingAnimationsIdlePreEventMethod) { IMP swizzledImp = (IMP)swizzledWaitForQuiescenceIncludingAnimationsIdlePreEvent; original_waitForQuiescenceIncludingAnimationsIdlePreEvent = (void (*)(id, SEL, BOOL, BOOL)) method_setImplementation(waitForQuiescenceIncludingAnimationsIdlePreEventMethod, swizzledImp); } else { [FBLogger log:@"Could not find method -[XCUIApplicationProcess waitForQuiescenceIncludingAnimationsIdle:]"]; } } #pragma clang diagnostic pop static char XCUIAPPLICATIONPROCESS_SHOULD_WAIT_FOR_QUIESCENCE; @dynamic fb_shouldWaitForQuiescence; - (NSNumber *)fb_shouldWaitForQuiescence { id result = objc_getAssociatedObject(self, &XCUIAPPLICATIONPROCESS_SHOULD_WAIT_FOR_QUIESCENCE); if (nil == result) { return @(YES); } return (NSNumber *)result; } - (void)setFb_shouldWaitForQuiescence:(NSNumber *)value { objc_setAssociatedObject(self, &XCUIAPPLICATIONPROCESS_SHOULD_WAIT_FOR_QUIESCENCE, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)fb_waitForQuiescenceIncludingAnimationsIdle:(bool)waitForAnimations { if ([self respondsToSelector:@selector(waitForQuiescenceIncludingAnimationsIdle:)]) { [self waitForQuiescenceIncludingAnimationsIdle:waitForAnimations]; } else if ([self respondsToSelector:@selector(waitForQuiescenceIncludingAnimationsIdle:isPreEvent:)]) { [self waitForQuiescenceIncludingAnimationsIdle:waitForAnimations isPreEvent:NO]; } else { @throw [NSException exceptionWithName: @"NoApiFound" reason:@"The current driver build is not compatible to your device OS version" userInfo:@{}]; } } @end

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mobile-dev-inc/Maestro'

If you have feedback or need assistance with the MCP directory API, please join our Discord server