Commit ef9515a6 authored by Robbie Gibson's avatar Robbie Gibson Committed by Commit Bot

[iOS] Use new clipboard recent content async apis in Today widget

The new async APIs don't get the actual clipboard content when checking
if the clipboard contains a url/image. This prevents them from
triggering the new iOS 14 pasteboard access notification at bad times.

Bug: 1110845
Change-Id: I8aa3989dae03999a319dc937f23432cff1f9ad81
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2325173Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Commit-Queue: Robbie Gibson <rkgibson@google.com>
Cr-Commit-Position: refs/heads/master@{#793547}
parent 3d90f272
......@@ -30,8 +30,7 @@ typedef NS_ENUM(NSInteger, CopiedContentType) {
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
- (void)setCopiedContentType:(CopiedContentType)type
copiedText:(NSString*)copiedText;
- (void)setCopiedContentType:(CopiedContentType)type;
@end
......
......@@ -24,8 +24,6 @@ const CGFloat kURLButtonMargin = 10;
// The type of the copied content
@property(nonatomic) CopiedContentType type;
// The copied text to be displayed if the type supports showing the string.
@property(nonatomic, copy) NSString* copiedText;
// The copied URL label containing the URL or a placeholder text.
@property(nonatomic, strong) UILabel* copiedContentLabel;
// The copied URL title label containing the title of the copied URL button.
......@@ -38,7 +36,7 @@ const CGFloat kURLButtonMargin = 10;
@property(nonatomic, strong) UIVisualEffectView* primaryEffectView;
@property(nonatomic, strong) UIVisualEffectView* secondaryEffectView;
// Updates the view to show the currently set |type| and |copiedText|.
// Updates the view to show the currently set |type|.
- (void)updateUI;
@end
......@@ -173,7 +171,7 @@ const CGFloat kURLButtonMargin = 10;
[_copiedContentLabel.trailingAnchor
constraintEqualToAnchor:_openCopiedContentTitleLabel.trailingAnchor],
]];
[self setCopiedContentType:CopiedContentTypeNone copiedText:nil];
[self setCopiedContentType:CopiedContentTypeNone];
self.highlightableViews = @[
_hairlineView, _copiedButtonView, _openCopiedContentTitleLabel,
_copiedContentLabel
......@@ -182,10 +180,8 @@ const CGFloat kURLButtonMargin = 10;
return self;
}
- (void)setCopiedContentType:(CopiedContentType)type
copiedText:(NSString*)copiedText {
- (void)setCopiedContentType:(CopiedContentType)type {
self.type = type;
self.copiedText = copiedText;
[self updateUI];
}
......@@ -224,12 +220,10 @@ const CGFloat kURLButtonMargin = 10;
}
case CopiedContentTypeURL: {
titleText = NSLocalizedString(@"IDS_IOS_OPEN_COPIED_LINK", nil);
contentText = self.copiedText;
break;
}
case CopiedContentTypeString: {
titleText = NSLocalizedString(@"IDS_IOS_OPEN_COPIED_TEXT", nil);
contentText = self.copiedText;
break;
}
case CopiedContentTypeImage: {
......
......@@ -44,10 +44,8 @@ typedef NS_ENUM(NSInteger, CopiedContentType);
// Gets the height of the widget.
- (CGFloat)widgetHeight;
// Sets the copied content type. |copiedText| should be provided if the content
// type requires textual data, otherwise it should be nil.
- (void)setCopiedContentType:(CopiedContentType)type
copiedText:(NSString*)copiedText;
// Sets the copied content type.
- (void)setCopiedContentType:(CopiedContentType)type;
@end
......
......@@ -210,9 +210,8 @@ const CGFloat kMaxContentSize = 421;
return [self actionContentHeight] + [self copiedURLSectionHeight];
}
- (void)setCopiedContentType:(CopiedContentType)type
copiedText:(NSString*)copiedText {
[self.copiedURLSection setCopiedContentType:type copiedText:copiedText];
- (void)setCopiedContentType:(CopiedContentType)type {
[self.copiedURLSection setCopiedContentType:type];
}
@end
......@@ -23,8 +23,6 @@
@interface SearchWidgetViewController ()<SearchWidgetViewActionTarget>
@property(nonatomic, weak) SearchWidgetView* widgetView;
@property(nonatomic, strong, nullable) NSString* copiedText;
@property(nonatomic, strong, nullable) UIImage* copiedImage;
@property(nonatomic) CopiedContentType copiedContentType;
@property(nonatomic, strong)
ClipboardRecentContentImplIOS* clipboardRecentContent;
......@@ -96,13 +94,26 @@
- (void)widgetPerformUpdateWithCompletionHandler:
(void (^)(NCUpdateResult))completionHandler {
completionHandler([self updateWidget] ? NCUpdateResultNewData
: NCUpdateResultNoData);
[self updateWidgetWithCompletionHandler:^(BOOL updates) {
completionHandler(updates ? NCUpdateResultNewData : NCUpdateResultNoData);
}];
}
// Updates the widget with latest data from the clipboard. Returns whether any
// visual updates occurred.
- (BOOL)updateWidget {
- (void)updateWidget {
[self updateWidgetWithCompletionHandler:^(BOOL updates) {
if (updates && self.extensionContext.widgetActiveDisplayMode ==
NCWidgetDisplayModeExpanded) {
CGSize maxSize = [self.extensionContext
widgetMaximumSizeForDisplayMode:NCWidgetDisplayModeExpanded];
self.preferredContentSize =
CGSizeMake(maxSize.width, [self.widgetView widgetHeight]);
}
}];
}
// Updates the widget with latest data from the clipboard. Calls completion
// handler with whether any updates occured..
- (void)updateWidgetWithCompletionHandler:(void (^)(BOOL))completionHandler {
NSUserDefaults* sharedDefaults = app_group::GetGroupUserDefaults();
NSString* fieldTrialKey =
base::SysUTF8ToNSString(app_group::kChromeExtensionFieldTrialPreference);
......@@ -113,35 +124,25 @@
self.supportsSearchByImage =
[sharedDefaults boolForKey:supportsSearchByImageKey];
NSString* copiedText;
UIImage* copiedImage;
CopiedContentType type = CopiedContentTypeNone;
if (UIImage* image = [self getCopiedImageFromClipboard]) {
copiedImage = image;
type = CopiedContentTypeImage;
} else if (NSURL* url =
[self.clipboardRecentContent recentURLFromClipboard]) {
copiedText = url.absoluteString;
type = CopiedContentTypeURL;
} else if (NSString* text =
[self.clipboardRecentContent recentTextFromClipboard]) {
copiedText = text;
type = CopiedContentTypeString;
}
return [self setCopiedContentType:type
copiedText:copiedText
copiedImage:copiedImage];
}
// Helper method to encapsulate checking whether the current search engine
// supports search-by-image and getting the copied image.
- (UIImage*)getCopiedImageFromClipboard {
if (!self.supportsSearchByImage) {
return nil;
}
return [self.clipboardRecentContent recentImageFromClipboard];
NSSet* wantedTypes = [NSSet
setWithArray:@[ ContentTypeURL, ContentTypeText, ContentTypeImage ]];
[self.clipboardRecentContent
hasContentMatchingTypes:wantedTypes
completionHandler:^(NSSet<ContentType>* matchedTypes) {
CopiedContentType newType = CopiedContentTypeNone;
if (self.supportsSearchByImage &&
[matchedTypes containsObject:ContentTypeImage]) {
newType = CopiedContentTypeImage;
} else if ([matchedTypes containsObject:ContentTypeURL]) {
newType = CopiedContentTypeURL;
} else if ([matchedTypes containsObject:ContentTypeText]) {
newType = CopiedContentTypeString;
}
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler([self updateCopiedContentType:newType]);
});
}];
}
- (void)viewWillTransitionToSize:(CGSize)size
......@@ -201,25 +202,47 @@
}
- (void)openCopiedContent:(id)sender {
DCHECK([self verifyCopiedContentType]);
switch (self.copiedContentType) {
case CopiedContentTypeURL:
[self.command prepareToOpenURL:[NSURL URLWithString:self.copiedText]];
case CopiedContentTypeURL: {
[self.clipboardRecentContent
recentURLFromClipboardAsync:^(NSURL* copiedURL) {
if (!copiedURL) {
return;
}
[self.command prepareToOpenURL:copiedURL];
[self.command executeInApp];
}];
break;
case CopiedContentTypeString:
[self.command prepareToSearchText:self.copiedText];
}
case CopiedContentTypeString: {
[self.clipboardRecentContent
recentTextFromClipboardAsync:^(NSString* copiedText) {
if (!copiedText) {
return;
}
[self.command prepareToSearchText:copiedText];
[self.command executeInApp];
}];
break;
}
case CopiedContentTypeImage: {
// Resize image before converting to NSData so we can store less data.
UIImage* resizedImage = ResizeImageForSearchByImage(self.copiedImage);
[self.command prepareToSearchImage:resizedImage];
[self.clipboardRecentContent
recentImageFromClipboardAsync:^(UIImage* copiedImage) {
if (!copiedImage) {
return;
}
// Resize image before converting to NSData so we can store less
// data.
UIImage* resizedImage = ResizeImageForSearchByImage(copiedImage);
[self.command prepareToSearchImage:resizedImage];
[self.command executeInApp];
}];
break;
}
case CopiedContentTypeNone:
NOTREACHED();
return;
}
[self.command executeInApp];
}
#pragma mark - internal
......@@ -241,38 +264,15 @@
forKey:app_group::kSearchExtensionDisplayCount];
}
// Sets the copied content type. |copiedText| should be provided if the content
// type requires textual data, otherwise it should be nil. Likewise,
// |copiedImage| should be provided if the content type requires image data.
// Also saves the data and returns YES if the screen needs updating and NO
// otherwise.
- (BOOL)setCopiedContentType:(CopiedContentType)type
copiedText:(NSString*)copiedText
copiedImage:(UIImage*)copiedImage {
if (self.copiedContentType == type &&
[self.copiedText isEqualToString:copiedText] &&
[self.copiedImage isEqual:copiedImage]) {
// Sets the copied content type returns YES if the screen needs updating and NO
// otherwise. This must only be called on the main thread.
- (BOOL)updateCopiedContentType:(CopiedContentType)type {
if (self.copiedContentType == type) {
return NO;
}
self.copiedContentType = type;
self.copiedText = copiedText;
self.copiedImage = copiedImage;
[self.widgetView setCopiedContentType:self.copiedContentType
copiedText:self.copiedText];
[self.widgetView setCopiedContentType:self.copiedContentType];
return YES;
}
// Verifies that the current copied content type has the required data with it.
- (BOOL)verifyCopiedContentType {
switch (self.copiedContentType) {
case CopiedContentTypeString:
case CopiedContentTypeURL:
return self.copiedText;
case CopiedContentTypeImage:
return self.copiedImage;
case CopiedContentTypeNone:
return true;
}
}
@end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment