| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- /**
- * 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 "FBPasteboard.h"
- #import <mach/mach_time.h>
- #import "FBAlert.h"
- #import "FBErrorBuilder.h"
- #import "FBMacros.h"
- #import "XCUIApplication+FBHelpers.h"
- #import "XCUIApplication+FBAlert.h"
- #define ALERT_TIMEOUT_SEC 30
- // Must not be less than FB_MONTORING_INTERVAL in FBAlertsMonitor
- #define ALERT_CHECK_INTERVAL_SEC 2
- #if !TARGET_OS_TV
- @implementation FBPasteboard
- + (BOOL)setData:(NSData *)data forType:(NSString *)type error:(NSError **)error
- {
- UIPasteboard *pb = UIPasteboard.generalPasteboard;
- if ([type.lowercaseString isEqualToString:@"plaintext"]) {
- pb.string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- } else if ([type.lowercaseString isEqualToString:@"image"]) {
- UIImage *image = [UIImage imageWithData:data];
- if (nil == image) {
- NSString *description = @"No image can be parsed from the given pasteboard data";
- if (error) {
- *error = [[FBErrorBuilder.builder withDescription:description] build];
- }
- return NO;
- }
- pb.image = image;
- } else if ([type.lowercaseString isEqualToString:@"url"]) {
- NSString *urlString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- NSURL *url = [[NSURL alloc] initWithString:urlString];
- if (nil == url) {
- NSString *description = @"No URL can be parsed from the given pasteboard data";
- if (error) {
- *error = [[FBErrorBuilder.builder withDescription:description] build];
- }
- return NO;
- }
- pb.URL = url;
- } else {
- NSString *description = [NSString stringWithFormat:@"Unsupported content type: %@", type];
- if (error) {
- *error = [[FBErrorBuilder.builder withDescription:description] build];
- }
- return NO;
- }
- return YES;
- }
- + (nullable id)pasteboardContentForItem:(NSString *)item
- instance:(UIPasteboard *)pbInstance
- timeout:(NSTimeInterval)timeout
- error:(NSError **)error
- {
- SEL selector = NSSelectorFromString(item);
- NSMethodSignature *methodSignature = [pbInstance methodSignatureForSelector:selector];
- if (nil == methodSignature) {
- NSString *description = [NSString stringWithFormat:@"Cannot retrieve '%@' from a UIPasteboard instance", item];
- if (error) {
- *error = [[FBErrorBuilder.builder withDescription:description] build];
- }
- return nil;
- }
- NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
- [invocation setSelector:selector];
- [invocation setTarget:pbInstance];
- if (SYSTEM_VERSION_LESS_THAN(@"16.0")) {
- [invocation invoke];
- id __unsafe_unretained result;
- [invocation getReturnValue:&result];
- return result;
- }
- // https://github.com/appium/appium/issues/17392
- __block id pasteboardContent;
- dispatch_queue_t backgroundQueue = dispatch_queue_create("GetPasteboard", NULL);
- __block BOOL didFinishGetPasteboard = NO;
- dispatch_async(backgroundQueue, ^{
- [invocation invoke];
- id __unsafe_unretained result;
- [invocation getReturnValue:&result];
- pasteboardContent = result;
- didFinishGetPasteboard = YES;
- });
- uint64_t timeStarted = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW);
- while (!didFinishGetPasteboard) {
- [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:ALERT_CHECK_INTERVAL_SEC]];
- if (didFinishGetPasteboard) {
- break;
- }
- XCUIElement *alertElement = XCUIApplication.fb_systemApplication.fb_alertElement;
- if (nil != alertElement) {
- FBAlert *alert = [FBAlert alertWithElement:alertElement];
- [alert acceptWithError:nil];
- }
- uint64_t timeElapsed = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW) - timeStarted;
- if (timeElapsed / NSEC_PER_SEC > timeout) {
- NSString *description = [NSString stringWithFormat:@"Cannot handle pasteboard alert within %@s timeout", @(timeout)];
- if (error) {
- *error = [[FBErrorBuilder.builder withDescription:description] build];
- }
- return nil;
- }
- }
- return pasteboardContent;
- }
- + (NSData *)dataForType:(NSString *)type error:(NSError **)error
- {
- UIPasteboard *pb = UIPasteboard.generalPasteboard;
- if ([type.lowercaseString isEqualToString:@"plaintext"]) {
- if (pb.hasStrings) {
- id result = [self.class pasteboardContentForItem:@"strings"
- instance:pb
- timeout:ALERT_TIMEOUT_SEC
- error:error
- ];
- return nil == result
- ? nil
- : [[(NSArray *)result componentsJoinedByString:@"\n"] dataUsingEncoding:NSUTF8StringEncoding];
- }
- } else if ([type.lowercaseString isEqualToString:@"image"]) {
- if (pb.hasImages) {
- id result = [self.class pasteboardContentForItem:@"image"
- instance:pb
- timeout:ALERT_TIMEOUT_SEC
- error:error
- ];
- return nil == result ? nil : UIImagePNGRepresentation((UIImage *)result);
- }
- } else if ([type.lowercaseString isEqualToString:@"url"]) {
- if (pb.hasURLs) {
- id result = [self.class pasteboardContentForItem:@"URLs"
- instance:pb
- timeout:ALERT_TIMEOUT_SEC
- error:error
- ];
- if (nil == result) {
- return nil;
- }
- NSMutableArray<NSString *> *urls = [NSMutableArray array];
- for (NSURL *url in (NSArray *)result) {
- if (nil != url.absoluteString) {
- [urls addObject:(id)url.absoluteString];
- }
- }
- return [[urls componentsJoinedByString:@"\n"] dataUsingEncoding:NSUTF8StringEncoding];
- }
- } else {
- NSString *description = [NSString stringWithFormat:@"Unsupported content type: %@", type];
- if (error) {
- *error = [[FBErrorBuilder.builder withDescription:description] build];
- }
- return nil;
- }
- return [@"" dataUsingEncoding:NSUTF8StringEncoding];
- }
- @end
- #endif
|