mirror of
https://github.com/wu736139669/Monkey-Test.git
synced 2026-08-05 05:55:46 +00:00
158 lines
4.7 KiB
Objective-C
Executable File
158 lines
4.7 KiB
Objective-C
Executable File
/**
|
|
* Copyright (c) 2015-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. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
#import "FBApplication.h"
|
|
|
|
#import "FBApplicationProcessProxy.h"
|
|
#import "FBRunLoopSpinner.h"
|
|
#import "FBMacros.h"
|
|
#import "FBXCodeCompatibility.h"
|
|
#import "XCAccessibilityElement.h"
|
|
#import "XCAXClient_iOS.h"
|
|
#import "XCUIApplication.h"
|
|
#import "XCUIApplicationImpl.h"
|
|
#import "XCUIApplicationProcess.h"
|
|
#import "XCUIElement.h"
|
|
#import "XCUIElementQuery.h"
|
|
|
|
@interface FBApplication ()
|
|
@property (nonatomic, assign) BOOL fb_isObservingAppImplCurrentProcess;
|
|
@end
|
|
|
|
@implementation FBApplication
|
|
|
|
+ (instancetype)fb_activeApplication
|
|
{
|
|
[[[FBRunLoopSpinner new]
|
|
timeout:5]
|
|
spinUntilTrue:^BOOL{
|
|
return [[XCAXClient_iOS sharedClient] activeApplications].count == 1;
|
|
}];
|
|
|
|
XCAccessibilityElement *activeApplicationElement = [[[XCAXClient_iOS sharedClient] activeApplications] firstObject];
|
|
if (!activeApplicationElement) {
|
|
return nil;
|
|
}
|
|
FBApplication *application = [FBApplication fb_applicationWithPID:activeApplicationElement.processIdentifier];
|
|
NSAssert(nil != application, @"Active application instance is not expected to be equal to nil", nil);
|
|
return application;
|
|
}
|
|
|
|
+ (instancetype)appWithPID:(pid_t)processID
|
|
{
|
|
if ([NSProcessInfo processInfo].processIdentifier == processID) {
|
|
return nil;
|
|
}
|
|
FBApplication *application = [self fb_registeredApplicationWithProcessID:processID];
|
|
if (application) {
|
|
return application;
|
|
}
|
|
application = [super appWithPID:processID];
|
|
[FBApplication fb_registerApplication:application withProcessID:processID];
|
|
return application;
|
|
}
|
|
|
|
+ (instancetype)applicationWithPID:(pid_t)processID
|
|
{
|
|
if ([NSProcessInfo processInfo].processIdentifier == processID) {
|
|
return nil;
|
|
}
|
|
FBApplication *application = [self fb_registeredApplicationWithProcessID:processID];
|
|
if (application) {
|
|
return application;
|
|
}
|
|
application = [super applicationWithPID:processID];
|
|
[FBApplication fb_registerApplication:application withProcessID:processID];
|
|
return application;
|
|
}
|
|
|
|
- (void)launch
|
|
{
|
|
if (!self.fb_shouldWaitForQuiescence) {
|
|
[self.fb_appImpl addObserver:self forKeyPath:FBStringify(XCUIApplicationImpl, currentProcess) options:(NSKeyValueObservingOptions)(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:nil];
|
|
self.fb_isObservingAppImplCurrentProcess = YES;
|
|
}
|
|
[super launch];
|
|
[FBApplication fb_registerApplication:self withProcessID:self.processID];
|
|
}
|
|
|
|
- (void)terminate
|
|
{
|
|
if (self.fb_isObservingAppImplCurrentProcess) {
|
|
[self.fb_appImpl removeObserver:self forKeyPath:FBStringify(XCUIApplicationImpl, currentProcess)];
|
|
}
|
|
[super terminate];
|
|
}
|
|
|
|
|
|
#pragma mark - Quiescence
|
|
|
|
- (void)_waitForQuiescence
|
|
{
|
|
if (!self.fb_shouldWaitForQuiescence) {
|
|
return;
|
|
}
|
|
[super _waitForQuiescence];
|
|
}
|
|
|
|
- (XCUIApplicationImpl *)fb_appImpl
|
|
{
|
|
if (![self respondsToSelector:@selector(applicationImpl)]) {
|
|
return nil;
|
|
}
|
|
XCUIApplicationImpl *appImpl = [self applicationImpl];
|
|
if (![appImpl respondsToSelector:@selector(currentProcess)]) {
|
|
return nil;
|
|
}
|
|
return appImpl;
|
|
}
|
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context
|
|
{
|
|
if (object != self.fb_appImpl) {
|
|
return;
|
|
}
|
|
if (![keyPath isEqualToString:FBStringify(XCUIApplicationImpl, currentProcess)]) {
|
|
return;
|
|
}
|
|
if ([change[NSKeyValueChangeKindKey] unsignedIntegerValue] != NSKeyValueChangeSetting) {
|
|
return;
|
|
}
|
|
XCUIApplicationProcess *applicationProcess = change[NSKeyValueChangeNewKey];
|
|
if (!applicationProcess || [applicationProcess isProxy] || ![applicationProcess isMemberOfClass:XCUIApplicationProcess.class]) {
|
|
return;
|
|
}
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
// Dispatching this call out of KVO call stack will trigger additional KVO call,
|
|
// which is required in case there are already registered observers.
|
|
self.fb_appImpl.currentProcess = (XCUIApplicationProcess *)[FBApplicationProcessProxy proxyWithApplicationProcess:applicationProcess];
|
|
});
|
|
}
|
|
|
|
|
|
#pragma mark - Process registration
|
|
|
|
static NSMutableDictionary *FBPidToApplicationMapping;
|
|
|
|
+ (instancetype)fb_registeredApplicationWithProcessID:(pid_t)processID
|
|
{
|
|
return FBPidToApplicationMapping[@(processID)];
|
|
}
|
|
|
|
+ (void)fb_registerApplication:(FBApplication *)application withProcessID:(pid_t)processID
|
|
{
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
FBPidToApplicationMapping = [NSMutableDictionary dictionary];
|
|
});
|
|
FBPidToApplicationMapping[@(application.processID)] = application;
|
|
}
|
|
|
|
@end
|