Commit e4a2ed98 authored by Sebastien Lalancette's avatar Sebastien Lalancette Committed by Commit Bot

[iOS] Add Sharing API For Shared Highlight

Adds an "additionalText" optional parameter to the ActivityServices
scenarios, allowing to share a piece of text along with a page's URL
and title. This additional text will be added as an extra activity
item, and will be stored in the pasteboard when users select the Copy
activity.

Bug: 1136043
Change-Id: Ia8d86c4ecfb57bdbc2bac3f209ab37973d79fc59
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2451309
Commit-Queue: Sebastien Lalancette <seblalancette@chromium.org>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#814811}
parent 4caf63cb
......@@ -57,6 +57,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"bookmark_activity_unittest.mm",
"copy_activity_unittest.mm",
"find_in_page_activity_unittest.mm",
"generate_qr_code_activity_unittest.mm",
"print_activity_unittest.mm",
......@@ -75,6 +76,7 @@ source_set("unit_tests") {
"//ios/chrome/browser/ui/activity_services/data",
"//ios/chrome/browser/ui/bookmarks:test_support",
"//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/util",
"//ios/web/public/test",
"//testing/gtest",
"//third_party/ocmock",
......
......@@ -7,13 +7,14 @@
#import <UIKit/UIKit.h>
class GURL;
@class ShareToData;
// Activity that copies the URL to the pasteboard.
@interface CopyActivity : UIActivity
// Initializes the copy activity with the given |URL| to be copied.
- (instancetype)initWithURL:(const GURL&)URL;
// Initializes the copy activity with the |data| object holding the URL and,
// potentially, additional text to be copied.
- (instancetype)initWithData:(ShareToData*)data;
@end
......
......@@ -4,10 +4,11 @@
#import "ios/chrome/browser/ui/activity_services/activities/copy_activity.h"
#import "ios/chrome/browser/ui/activity_services/data/share_to_data.h"
#import "ios/chrome/browser/ui/util/pasteboard_util.h"
#include "ios/chrome/grit/ios_strings.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "url/gurl.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util_mac.h"
#import "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
......@@ -19,16 +20,21 @@ NSString* const kCopyActivityType = @"com.google.chrome.copyActivity";
} // namespace
@implementation CopyActivity {
GURL _URL;
}
@interface CopyActivity ()
@property(nonatomic, strong) ShareToData* data;
@end
@implementation CopyActivity
#pragma mark - Public
- (instancetype)initWithURL:(const GURL&)URL {
- (instancetype)initWithData:(ShareToData*)data {
DCHECK(data);
self = [super init];
if (self) {
_URL = URL;
_data = data;
}
return self;
}
......@@ -48,7 +54,7 @@ NSString* const kCopyActivityType = @"com.google.chrome.copyActivity";
}
- (BOOL)canPerformWithActivityItems:(NSArray*)activityItems {
return YES;
return !!self.data;
}
- (void)prepareWithActivityItems:(NSArray*)activityItems {
......@@ -59,7 +65,11 @@ NSString* const kCopyActivityType = @"com.google.chrome.copyActivity";
}
- (void)performActivity {
StoreURLInPasteboard(_URL);
if (self.data.additionalText) {
StoreInPasteboard(self.data.additionalText, self.data.shareURL);
} else {
StoreURLInPasteboard(self.data.shareURL);
}
[self activityDidFinish:YES];
}
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/activity_services/activities/copy_activity.h"
#import "base/strings/sys_string_conversions.h"
#import "ios/chrome/browser/ui/activity_services/data/share_to_data.h"
#import "ios/chrome/browser/ui/util/pasteboard_util.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#import "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
const char kTestShareURL[] = "https://www.google.com/";
const char kTestVisibleURL[] = "https://google.com/";
NSString* const kTestAdditionaText = @"Foo Bar";
} // namespace
// Test fixture for covering the CopyActivity class.
class CopyActivityTest : public PlatformTest {
protected:
CopyActivityTest() {}
void SetUp() override {
PlatformTest::SetUp();
// Start with a clean pasteboard.
ClearPasteboard();
}
void TearDown() override {
PlatformTest::TearDown();
// End with a clean pasteboard.
ClearPasteboard();
}
// Creates a ShareToData instance with the given |additional_text|.
ShareToData* CreateData(NSString* additional_text) {
return [[ShareToData alloc] initWithShareURL:GURL(kTestShareURL)
visibleURL:GURL(kTestVisibleURL)
title:@"Some Title"
additionalText:additional_text
isOriginalTitle:YES
isPagePrintable:YES
isPageSearchable:YES
canSendTabToSelf:YES
userAgent:web::UserAgentType::MOBILE
thumbnailGenerator:nil];
}
NSURL* GetExpectedURL() {
return [NSURL URLWithString:base::SysUTF8ToNSString(kTestShareURL)];
}
};
// Tests that the activity can be performed.
TEST_F(CopyActivityTest, ActivityEnabled) {
ShareToData* data = CreateData(nil);
CopyActivity* activity = [[CopyActivity alloc] initWithData:data];
EXPECT_TRUE([activity canPerformWithActivityItems:@[]]);
}
// Tests that executing the activity with just a URL copies it.
TEST_F(CopyActivityTest, ExecuteActivityJustURL) {
ShareToData* data = CreateData(nil);
CopyActivity* activity = [[CopyActivity alloc] initWithData:data];
id activity_partial_mock = OCMPartialMock(activity);
[[activity_partial_mock expect] activityDidFinish:YES];
[activity performActivity];
[activity_partial_mock verify];
NSURL* expected_url = GetExpectedURL();
EXPECT_TRUE([expected_url isEqual:UIPasteboard.generalPasteboard.URL]);
}
// Tests that executing the activity with a URL and additional text copies them.
TEST_F(CopyActivityTest, ExecuteActivityURLAndAdditionalText) {
ShareToData* data = CreateData(kTestAdditionaText);
CopyActivity* activity = [[CopyActivity alloc] initWithData:data];
id activity_partial_mock = OCMPartialMock(activity);
[[activity_partial_mock expect] activityDidFinish:YES];
[activity performActivity];
[activity_partial_mock verify];
// Additional text is stored as the first pasteboard item.
EXPECT_TRUE([kTestAdditionaText
isEqualToString:UIPasteboard.generalPasteboard.string]);
// URL is stored as the second pasteboard item, but can be accessed as the
// first (and only) URL item.
ASSERT_TRUE([UIPasteboard generalPasteboard].hasURLs);
NSURL* expected_url = GetExpectedURL();
EXPECT_TRUE([expected_url isEqual:UIPasteboard.generalPasteboard.URLs[0]]);
}
......@@ -31,6 +31,7 @@ class FindInPageActivityTest : public PlatformTest {
return [[ShareToData alloc] initWithShareURL:GURL("https://www.google.com/")
visibleURL:GURL("https://google.com/")
title:@"Some Title"
additionalText:nil
isOriginalTitle:YES
isPagePrintable:YES
isPageSearchable:is_page_searchable
......
......@@ -31,6 +31,7 @@ class PrintActivityTest : public PlatformTest {
return [[ShareToData alloc] initWithShareURL:GURL("https://www.google.com/")
visibleURL:GURL("https://google.com/")
title:@"Some Title"
additionalText:nil
isOriginalTitle:YES
isPagePrintable:is_page_printable
isPageSearchable:YES
......
......@@ -31,6 +31,7 @@ class SendTabToSelfActivityTest : public PlatformTest {
return [[ShareToData alloc] initWithShareURL:GURL("https://www.google.com/")
visibleURL:GURL("https://google.com/")
title:@"Some Title"
additionalText:nil
isOriginalTitle:YES
isPagePrintable:YES
isPageSearchable:YES
......
......@@ -31,6 +31,13 @@ class GURL;
title:(NSString*)title
scenario:(ActivityScenario)scenario;
// Initializes an instance configured to share an |URL|, along
// with its |title| and |additionalText|, for the metrics |scenario|.
- (instancetype)initWithURL:(const GURL&)URL
title:(NSString*)title
additionalText:(NSString*)additionalText
scenario:(ActivityScenario)scenario;
- (instancetype)init NS_UNAVAILABLE;
// Image to be shared.
......@@ -43,6 +50,9 @@ class GURL;
// set.
@property(nonatomic, readonly, copy) NSString* title;
// Any additional text to be shared along with the page's details. May be nil.
@property(nonatomic, readonly, copy) NSString* additionalText;
// Current sharing scenario.
@property(nonatomic, readonly, assign) ActivityScenario scenario;
......
......@@ -43,4 +43,15 @@
return self;
}
- (instancetype)initWithURL:(const GURL&)URL
title:(NSString*)title
additionalText:(NSString*)additionalText
scenario:(ActivityScenario)scenario {
DCHECK(additionalText);
if (self = [self initWithURL:URL title:title scenario:scenario]) {
_additionalText = [additionalText copy];
}
return self;
}
@end
......@@ -15,6 +15,7 @@
#import "ios/chrome/browser/ui/activity_services/canonical_url_retriever.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_image_source.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_item_source.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_text_source.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_url_source.h"
#import "ios/chrome/browser/ui/activity_services/data/share_image_data.h"
#import "ios/chrome/browser/ui/activity_services/data/share_to_data.h"
......@@ -202,12 +203,13 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency";
#pragma mark - Private Methods: Share URL
// Configures activities and items for a URL and its title, and shows
// an activity view.
// an activity view. Also adds another activity item for additional text, if
// there is any.
- (void)shareURL {
ShareToData* data =
activity_services::ShareToDataForURL(self.params.URL, self.params.title);
ShareToData* data = activity_services::ShareToDataForURL(
self.params.URL, self.params.title, self.params.additionalText);
NSArray<ChromeActivityURLSource*>* items =
NSArray<id<ChromeActivityItemSource>>* items =
[self.mediator activityItemsForData:data];
NSArray* activities = [self.mediator applicationActivitiesForData:data];
......
......@@ -43,7 +43,8 @@ class PrefService;
// Generates an array of activity items to be shared via an activity view for
// the given |data|.
- (NSArray<ChromeActivityURLSource*>*)activityItemsForData:(ShareToData*)data;
- (NSArray<id<ChromeActivityItemSource>>*)activityItemsForData:
(ShareToData*)data;
// Generates an array of activities to be added to the activity view for the
// given |data|.
......
......@@ -27,6 +27,7 @@
#import "ios/chrome/browser/ui/activity_services/activity_type_util.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_image_source.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_item_source.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_text_source.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_url_source.h"
#import "ios/chrome/browser/ui/activity_services/data/share_image_data.h"
#import "ios/chrome/browser/ui/activity_services/data/share_to_data.h"
......@@ -72,21 +73,28 @@
return self;
}
- (NSArray<ChromeActivityURLSource*>*)activityItemsForData:(ShareToData*)data {
// The provider object ChromeActivityURLSource supports the public.url UTType
// for Share Extensions (e.g. Facebook, Twitter).
- (NSArray<id<ChromeActivityItemSource>>*)activityItemsForData:
(ShareToData*)data {
NSMutableArray* items = [[NSMutableArray alloc] init];
if (data.additionalText) {
[items addObject:[[ChromeActivityTextSource alloc]
initWithText:data.additionalText]];
}
ChromeActivityURLSource* activityURLSource =
[[ChromeActivityURLSource alloc] initWithShareURL:data.shareNSURL
subject:data.title];
activityURLSource.thumbnailGenerator = data.thumbnailGenerator;
return @[ activityURLSource ];
[items addObject:activityURLSource];
return items;
}
- (NSArray*)applicationActivitiesForData:(ShareToData*)data {
NSMutableArray* applicationActivities = [NSMutableArray array];
[applicationActivities
addObject:[[CopyActivity alloc] initWithURL:data.shareURL]];
[applicationActivities addObject:[[CopyActivity alloc] initWithData:data]];
if (data.shareURL.SchemeIsHTTPOrHTTPS()) {
SendTabToSelfActivity* sendTabToSelfActivity =
......
......@@ -4,12 +4,12 @@
#import "ios/chrome/browser/ui/activity_services/activity_service_mediator.h"
#include "base/test/metrics/histogram_tester.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/testing_pref_service.h"
#include "ios/chrome/browser/pref_names.h"
#import "base/test/metrics/histogram_tester.h"
#import "components/bookmarks/browser/bookmark_model.h"
#import "components/prefs/pref_registry_simple.h"
#import "components/prefs/pref_service.h"
#import "components/prefs/testing_pref_service.h"
#import "ios/chrome/browser/pref_names.h"
#import "ios/chrome/browser/ui/activity_services/activities/bookmark_activity.h"
#import "ios/chrome/browser/ui/activity_services/activities/copy_activity.h"
#import "ios/chrome/browser/ui/activity_services/activities/find_in_page_activity.h"
......@@ -21,7 +21,9 @@
#import "ios/chrome/browser/ui/activity_services/activity_scenario.h"
#import "ios/chrome/browser/ui/activity_services/activity_type_util.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_image_source.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_item_source.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_item_thumbnail_generator.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_text_source.h"
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_url_source.h"
#import "ios/chrome/browser/ui/activity_services/data/share_image_data.h"
#import "ios/chrome/browser/ui/activity_services/data/share_to_data.h"
......@@ -29,9 +31,9 @@
#import "ios/chrome/browser/ui/commands/browser_commands.h"
#import "ios/chrome/browser/ui/commands/find_in_page_commands.h"
#import "ios/chrome/browser/ui/commands/qr_generation_commands.h"
#include "ios/web/common/user_agent.h"
#include "testing/gtest_mac.h"
#include "testing/platform_test.h"
#import "ios/web/common/user_agent.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
......@@ -85,12 +87,14 @@ class ActivityServiceMediatorTest : public PlatformTest {
};
// Tests that only one ChromeActivityURLSource is initialized from a ShareToData
// instance.
TEST_F(ActivityServiceMediatorTest, ActivityItemsForData_Success) {
// instance without additional text.
TEST_F(ActivityServiceMediatorTest,
ActivityItemsForData_NoAdditionalText_Success) {
ShareToData* data =
[[ShareToData alloc] initWithShareURL:GURL("https://www.google.com/")
visibleURL:GURL("https://google.com/")
title:@"Some Title"
additionalText:nil
isOriginalTitle:YES
isPagePrintable:YES
isPageSearchable:YES
......@@ -98,10 +102,36 @@ TEST_F(ActivityServiceMediatorTest, ActivityItemsForData_Success) {
userAgent:web::UserAgentType::MOBILE
thumbnailGenerator:mocked_thumbnail_generator_];
NSArray<ChromeActivityURLSource*>* activityItems =
NSArray<id<ChromeActivityItemSource>>* activityItems =
[mediator_ activityItemsForData:data];
EXPECT_EQ(1U, [activityItems count]);
EXPECT_TRUE([activityItems[0] isKindOfClass:[ChromeActivityURLSource class]]);
}
// Tests that two activity items are created from a ShareToData instance with
// additional text.
TEST_F(ActivityServiceMediatorTest,
ActivityItemsForData_WithAdditionalText_Success) {
ShareToData* data =
[[ShareToData alloc] initWithShareURL:GURL("https://www.google.com/")
visibleURL:GURL("https://google.com/")
title:@"Some Title"
additionalText:@"Foo, bar!"
isOriginalTitle:YES
isPagePrintable:YES
isPageSearchable:YES
canSendTabToSelf:YES
userAgent:web::UserAgentType::MOBILE
thumbnailGenerator:mocked_thumbnail_generator_];
NSArray<id<ChromeActivityItemSource>>* activityItems =
[mediator_ activityItemsForData:data];
EXPECT_EQ(2U, [activityItems count]);
EXPECT_TRUE(
[activityItems[0] isKindOfClass:[ChromeActivityTextSource class]]);
EXPECT_TRUE([activityItems[1] isKindOfClass:[ChromeActivityURLSource class]]);
}
// Tests that only the CopyActivity and PrintActivity get added for a page that
......@@ -111,6 +141,7 @@ TEST_F(ActivityServiceMediatorTest, ActivitiesForData_NotHTTPOrHTTPS) {
[[ShareToData alloc] initWithShareURL:GURL("chrome://chromium.org/")
visibleURL:GURL("chrome://chromium.org/")
title:@"baz"
additionalText:nil
isOriginalTitle:YES
isPagePrintable:YES
isPageSearchable:YES
......@@ -130,6 +161,7 @@ TEST_F(ActivityServiceMediatorTest, ActivitiesForData_HTTP) {
[[ShareToData alloc] initWithShareURL:GURL("http://example.com")
visibleURL:GURL("http://example.com")
title:@"baz"
additionalText:nil
isOriginalTitle:YES
isPagePrintable:YES
isPageSearchable:YES
......@@ -154,6 +186,7 @@ TEST_F(ActivityServiceMediatorTest, ActivitiesForData_HTTPS) {
[[ShareToData alloc] initWithShareURL:GURL("https://example.com")
visibleURL:GURL("https://example.com")
title:@"baz"
additionalText:nil
isOriginalTitle:YES
isPagePrintable:YES
isPageSearchable:YES
......@@ -283,6 +316,7 @@ TEST_F(ActivityServiceMediatorTest, PrintPrefDisabled) {
[[ShareToData alloc] initWithShareURL:GURL("http://example.com")
visibleURL:GURL("http://example.com")
title:@"baz"
additionalText:nil
isOriginalTitle:YES
isPagePrintable:YES
isPageSearchable:YES
......
......@@ -10,6 +10,8 @@ source_set("data") {
"chrome_activity_item_source.h",
"chrome_activity_item_thumbnail_generator.h",
"chrome_activity_item_thumbnail_generator.mm",
"chrome_activity_text_source.h",
"chrome_activity_text_source.mm",
"chrome_activity_url_source.h",
"chrome_activity_url_source.mm",
"share_image_data.h",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_CHROME_ACTIVITY_TEXT_SOURCE_H_
#define IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_CHROME_ACTIVITY_TEXT_SOURCE_H_
#import <UIKit/UIKit.h>
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_item_source.h"
// This UIActivityItemSource-conforming object conforms to UTType public.text.
@interface ChromeActivityTextSource : NSObject <ChromeActivityItemSource>
// Default initializer. |text| must not be nil.
- (instancetype)initWithText:(NSString*)text;
@end
#endif // IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_CHROME_ACTIVITY_TEXT_SOURCE_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/activity_services/data/chrome_activity_text_source.h"
#import <MobileCoreServices/MobileCoreServices.h>
#include "base/check.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface ChromeActivityTextSource ()
// Text to be shared with share extensions.
@property(nonatomic, strong) NSString* text;
@end
@implementation ChromeActivityTextSource
- (instancetype)initWithText:(NSString*)text {
DCHECK(text);
if (self = [super init]) {
_text = [text copy];
}
return self;
}
#pragma mark - ChromeActivityItemSource
- (NSSet*)excludedActivityTypes {
return [NSSet setWithArray:@[
UIActivityTypeAddToReadingList, UIActivityTypeCopyToPasteboard,
UIActivityTypePrint, UIActivityTypeSaveToCameraRoll
]];
}
#pragma mark - UIActivityItemSource
- (id)activityViewControllerPlaceholderItem:
(UIActivityViewController*)activityViewController {
return self.text;
}
- (id)activityViewController:(UIActivityViewController*)activityViewController
itemForActivityType:(NSString*)activityType {
return self.text;
}
- (NSString*)activityViewController:
(UIActivityViewController*)activityViewController
dataTypeIdentifierForActivityType:(NSString*)activityType {
return (NSString*)kUTTypeText;
}
@end
......@@ -17,6 +17,7 @@
- (id)initWithShareURL:(const GURL&)shareURL
visibleURL:(const GURL&)visibleURL
title:(NSString*)title
additionalText:(NSString*)additionalText
isOriginalTitle:(BOOL)isOriginalTitle
isPagePrintable:(BOOL)isPagePrintable
isPageSearchable:(BOOL)isPageSearchable
......@@ -37,6 +38,10 @@
// Title to be shared (not nil).
@property(nonatomic, readonly, copy) NSString* title;
// Additional text to be shared, such as highlighted text. May be nil.
@property(nonatomic, readonly, copy) NSString* additionalText;
// Whether the title was provided by the page (i.e., was not generated from
// the url).
@property(nonatomic, readonly, assign) BOOL isOriginalTitle;
......
......@@ -26,6 +26,7 @@
- (id)initWithShareURL:(const GURL&)shareURL
visibleURL:(const GURL&)visibleURL
title:(NSString*)title
additionalText:(NSString*)additionalText
isOriginalTitle:(BOOL)isOriginalTitle
isPagePrintable:(BOOL)isPagePrintable
isPageSearchable:(BOOL)isPageSearchable
......@@ -41,6 +42,7 @@
_shareURL = shareURL;
_visibleURL = visibleURL;
_title = [title copy];
_additionalText = [additionalText copy];
_isOriginalTitle = isOriginalTitle;
_isPagePrintable = isPagePrintable;
_isPageSearchable = isPageSearchable;
......
......@@ -25,8 +25,11 @@ ShareToData* ShareToDataForWebState(web::WebState* web_state,
const GURL& share_url);
// Returns a ShareToData object for a single |URL|, and its page's |title|,
// which is not associated to a WebState.
ShareToData* ShareToDataForURL(const GURL& URL, NSString* title);
// which is not associated to a WebState. Will also add |additionalText|, if
// present.
ShareToData* ShareToDataForURL(const GURL& URL,
NSString* title,
NSString* additionalText);
} // namespace activity_services
......
......@@ -75,6 +75,7 @@ ShareToData* ShareToDataForWebState(web::WebState* web_state,
return [[ShareToData alloc] initWithShareURL:finalURLToShare
visibleURL:web_state->GetVisibleURL()
title:tab_title
additionalText:nil
isOriginalTitle:is_original_title
isPagePrintable:is_page_printable
isPageSearchable:is_page_searchable
......@@ -83,10 +84,13 @@ ShareToData* ShareToDataForWebState(web::WebState* web_state,
thumbnailGenerator:thumbnail_generator];
}
ShareToData* ShareToDataForURL(const GURL& URL, NSString* title) {
ShareToData* ShareToDataForURL(const GURL& URL,
NSString* title,
NSString* additionalText) {
return [[ShareToData alloc] initWithShareURL:URL
visibleURL:URL
title:title
additionalText:additionalText
isOriginalTitle:YES
isPagePrintable:NO
isPageSearchable:NO
......
......@@ -132,12 +132,15 @@ TEST_F(ShareToDataBuilderTest, TestReturnsNilWhenClosing) {
TEST_F(ShareToDataBuilderTest, ShareToDataForURL) {
GURL testURL = GURL("http://www.testurl.com/");
NSString* testTitle = @"Some Title";
NSString* additionalText = @"Foo, Bar!";
ShareToData* data = activity_services::ShareToDataForURL(testURL, testTitle);
ShareToData* data =
activity_services::ShareToDataForURL(testURL, testTitle, additionalText);
EXPECT_EQ(testURL, data.shareURL);
EXPECT_EQ(testURL, data.visibleURL);
EXPECT_EQ(testTitle, data.title);
EXPECT_EQ(additionalText, data.additionalText);
EXPECT_TRUE(data.isOriginalTitle);
EXPECT_FALSE(data.isPagePrintable);
EXPECT_FALSE(data.isPageSearchable);
......
......@@ -139,6 +139,7 @@ source_set("unit_tests") {
"manual_text_framer_unittest.mm",
"named_guide_unittest.mm",
"optional_property_animator_unittest.mm",
"pasteboard_util_unittest.mm",
"terms_util_unittest.mm",
"text_region_mapper_unittest.mm",
"ui_util_unittest.mm",
......
......@@ -5,8 +5,17 @@
#ifndef IOS_CHROME_BROWSER_UI_UTIL_PASTEBOARD_UTIL_H_
#define IOS_CHROME_BROWSER_UI_UTIL_PASTEBOARD_UTIL_H_
#import <UIKit/UIKit.h>
class GURL;
// Stores |url| into the pasteboard.
void StoreURLInPasteboard(const GURL& url);
// Stores |text| and |url| into the pasteboard.
void StoreInPasteboard(NSString* text, const GURL& url);
// Effectively clears any items in the pasteboard.
void ClearPasteboard();
#endif // IOS_CHROME_BROWSER_UI_UTIL_PASTEBOARD_UTIL_H_
......@@ -7,9 +7,9 @@
#import <MobileCoreServices/MobileCoreServices.h>
#import <UIKit/UIKit.h>
#include "base/strings/sys_string_conversions.h"
#import "base/strings/sys_string_conversions.h"
#import "net/base/mac/url_conversions.h"
#include "url/gurl.h"
#import "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
......@@ -29,3 +29,26 @@ void StoreURLInPasteboard(const GURL& URL) {
};
[[UIPasteboard generalPasteboard] setItems:@[ copiedItem ]];
}
void StoreInPasteboard(NSString* text, const GURL& URL) {
DCHECK(text);
DCHECK(URL.is_valid());
if (!text || !URL.is_valid()) {
return;
}
NSData* plainText = [text dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* copiedText = @{
(NSString*)kUTTypeText : text,
(NSString*)kUTTypeUTF8PlainText : plainText,
};
NSDictionary* copiedURL = @{
(NSString*)kUTTypeURL : net::NSURLWithGURL(URL),
};
[[UIPasteboard generalPasteboard] setItems:@[ copiedText, copiedURL ]];
}
void ClearPasteboard() {
[UIPasteboard generalPasteboard].items = @[];
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/util/pasteboard_util.h"
#import "base/strings/sys_string_conversions.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
const char kTestText[] = "Some test text";
const char kTestURL[] = "https://www.chromium.org/";
class PasteboardUtilTest : public PlatformTest {
public:
PasteboardUtilTest() {}
void SetUp() override { ClearPasteboard(); }
void TearDown() override { ClearPasteboard(); }
};
// Tests that the StoreInPasteboard function properly adds two items to the
// general pasteboard.
TEST_F(PasteboardUtilTest, StoreInPasteboardWorks) {
NSString* test_text = base::SysUTF8ToNSString(kTestText);
GURL test_url(kTestURL);
NSURL* test_ns_url = [NSURL URLWithString:base::SysUTF8ToNSString(kTestURL)];
StoreInPasteboard(test_text, test_url);
// Additional text is stored as the first pasteboard item.
ASSERT_TRUE([UIPasteboard generalPasteboard].hasStrings);
EXPECT_TRUE(
[test_text isEqualToString:UIPasteboard.generalPasteboard.string]);
// URL is stored as the second pasteboard item, but can be accessed as the
// first (and only) URL item.
ASSERT_TRUE([UIPasteboard generalPasteboard].hasURLs);
EXPECT_TRUE([test_ns_url isEqual:UIPasteboard.generalPasteboard.URLs[0]]);
}
// Tests that the minimum line height attribute is reflected in GetLineHeight().
TEST_F(PasteboardUtilTest, ClearPasteboardWorks) {
// Get something stored in the pasteboard.
NSString* test_text = base::SysUTF8ToNSString(kTestText);
GURL test_url(kTestURL);
StoreInPasteboard(test_text, test_url);
// Clear and assert.
ClearPasteboard();
EXPECT_FALSE([UIPasteboard generalPasteboard].hasURLs);
EXPECT_FALSE([UIPasteboard generalPasteboard].hasStrings);
}
} // namespace
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