Commit 787948e5 authored by Sebastien Lalancette's avatar Sebastien Lalancette Committed by Commit Bot

[iOS] Add Share URL Sharing Flow

Adding a new SharingCoordinator initializer and updating
ActivityServiceCoordinator's initializers to enable triggering a URL
sharing flow for URLs that aren't necessarily associated with a WebState.

Some activities that depended on a WebState have been disabled for that
flow (e.g. Print, Find in Page). Also, this CL makes ThumbnailGenerator
optional for ChromeActivityURLSource, as no thumbnail can be generated
without a WebState.

This CL also modifies the initialization of ActivityServiceCoordinator
to use a new ActivityParams object which will contain the properties
used to configure the various sharing flows.

Bug: 1102892
Change-Id: I0b28d5fcc7bae78e669dbfac33ba252165ce86bf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2319793
Commit-Queue: Sebastien Lalancette <seblalancette@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#796486}
parent 4ffaffd7
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
source_set("activity_services") { source_set("activity_services") {
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
sources = [ sources = [
"activity_params.h",
"activity_params.mm",
"activity_scenario.h", "activity_scenario.h",
"activity_service_coordinator.h", "activity_service_coordinator.h",
"activity_service_coordinator.mm", "activity_service_coordinator.mm",
......
// 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_ACTIVITY_PARAMS_H_
#define IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_ACTIVITY_PARAMS_H_
#import <UIKit/UIKit.h>
#import "ios/chrome/browser/ui/activity_services/activity_scenario.h"
class GURL;
// Parameter object used to configure the activity service scenario.
@interface ActivityParams : NSObject
// Initializes an instance configured to share the current tab's URL for the
// metrics |scenario|.
- (instancetype)initWithScenario:(ActivityScenario)scenario
NS_DESIGNATED_INITIALIZER;
// Initializes an instance configured to share an |image|, along
// with its |title|, for the metrics |scenario|.
- (instancetype)initWithImage:(UIImage*)image
title:(NSString*)title
scenario:(ActivityScenario)scenario;
// Initializes an instance configured to share an |URL|, along
// with its |title|, for the metrics |scenario|.
- (instancetype)initWithURL:(const GURL&)URL
title:(NSString*)title
scenario:(ActivityScenario)scenario;
- (instancetype)init NS_UNAVAILABLE;
// Image to be shared.
@property(nonatomic, readonly, strong) UIImage* image;
// URL of a page to be shared.
@property(nonatomic, readonly, assign) GURL URL;
// Title of the content that will be shared. Must be set if |image| or |URL| are
// set.
@property(nonatomic, readonly, copy) NSString* title;
// Current sharing scenario.
@property(nonatomic, readonly, assign) ActivityScenario scenario;
@end
#endif // IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_ACTIVITY_PARAMS_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/activity_params.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@implementation ActivityParams
- (instancetype)initWithScenario:(ActivityScenario)scenario {
if (self = [super init]) {
_scenario = scenario;
}
return self;
}
- (instancetype)initWithImage:(UIImage*)image
title:(NSString*)title
scenario:(ActivityScenario)scenario {
DCHECK(image);
DCHECK(title);
if (self = [self initWithScenario:scenario]) {
_image = image;
_title = title;
}
return self;
}
- (instancetype)initWithURL:(const GURL&)URL
title:(NSString*)title
scenario:(ActivityScenario)scenario {
DCHECK(URL.is_valid());
DCHECK(title);
if (self = [self initWithScenario:scenario]) {
_URL = URL;
_title = title;
}
return self;
}
@end
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#import "ios/chrome/browser/ui/activity_services/activity_scenario.h" #import "ios/chrome/browser/ui/activity_services/activity_scenario.h"
#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
@class ActivityParams;
@protocol ActivityServicePositioner; @protocol ActivityServicePositioner;
@protocol ActivityServicePresentation; @protocol ActivityServicePresentation;
class Browser; class Browser;
...@@ -17,9 +18,12 @@ class Browser; ...@@ -17,9 +18,12 @@ class Browser;
// menu feature. // menu feature.
@interface ActivityServiceCoordinator : ChromeCoordinator @interface ActivityServiceCoordinator : ChromeCoordinator
// Initializes a coordinator instance configured to share the current tab's URL
// based on |baseViewController| and |browser|, and where |params| contains all
// necessary values to drive the scenario.
- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController - (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
browser:(Browser*)browser browser:(Browser*)browser
scenario:(ActivityScenario)scenario params:(ActivityParams*)params
NS_DESIGNATED_INITIALIZER; NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController - (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
...@@ -29,19 +33,12 @@ class Browser; ...@@ -29,19 +33,12 @@ class Browser;
@property(nonatomic, readwrite, weak) id<ActivityServicePositioner> @property(nonatomic, readwrite, weak) id<ActivityServicePositioner>
positionProvider; positionProvider;
// Image that should be shared via the activity view. When set, will trigger
// the share image experience.
@property(nonatomic, strong) UIImage* image;
// Title of the content that will be shared.
@property(nonatomic, strong) NSString* title;
// Provider of share action presentation. // Provider of share action presentation.
@property(nonatomic, readwrite, weak) id<ActivityServicePresentation> @property(nonatomic, readwrite, weak) id<ActivityServicePresentation>
presentationProvider; presentationProvider;
// Handler for activities that need to be executed within a certain scope. // Handler for activities that need to be executed within a certain scope.
@property(nonatomic, weak) id<QRGenerationCommands> scopedHandler; @property(nonatomic, readwrite, weak) id<QRGenerationCommands> scopedHandler;
@end @end
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/main/browser.h"
#import "ios/chrome/browser/ui/activity_services/activity_params.h"
#import "ios/chrome/browser/ui/activity_services/activity_service_mediator.h" #import "ios/chrome/browser/ui/activity_services/activity_service_mediator.h"
#import "ios/chrome/browser/ui/activity_services/canonical_url_retriever.h" #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_image_source.h"
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
#import "ios/chrome/browser/ui/commands/command_dispatcher.h" #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "net/base/mac/url_conversions.h"
#include "url/gurl.h" #include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
...@@ -47,8 +49,8 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency"; ...@@ -47,8 +49,8 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency";
@property(nonatomic, strong) UIActivityViewController* viewController; @property(nonatomic, strong) UIActivityViewController* viewController;
// Current sharing scenario. // Parameters determining the activity flow and values.
@property(nonatomic, readonly, assign) ActivityScenario scenario; @property(nonatomic, strong) ActivityParams* params;
@end @end
...@@ -56,10 +58,11 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency"; ...@@ -56,10 +58,11 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency";
- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController - (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
browser:(Browser*)browser browser:(Browser*)browser
scenario:(ActivityScenario)scenario { params:(ActivityParams*)params {
DCHECK(params);
if (self = [super initWithBaseViewController:baseViewController if (self = [super initWithBaseViewController:baseViewController
browser:browser]) { browser:browser]) {
_scenario = scenario; _params = params;
} }
return self; return self;
} }
...@@ -79,10 +82,12 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency"; ...@@ -79,10 +82,12 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency";
prefService:browserState->GetPrefs() prefService:browserState->GetPrefs()
bookmarkModel:bookmarkModel]; bookmarkModel:bookmarkModel];
[self.mediator shareStartedWithScenario:self.scenario]; [self.mediator shareStartedWithScenario:self.params.scenario];
if (self.image) { if (self.params.image) {
[self shareImage]; [self shareImage];
} else if (!self.params.URL.is_empty()) {
[self shareURL];
} else { } else {
[self shareCurrentPage]; [self shareCurrentPage];
} }
...@@ -128,7 +133,7 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency"; ...@@ -128,7 +133,7 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency";
} }
// Delegate post-activity processing to the mediator. // Delegate post-activity processing to the mediator.
[strongSelf.mediator shareFinishedWithScenario:strongSelf.scenario [strongSelf.mediator shareFinishedWithScenario:strongSelf.params.scenario
activityType:activityType activityType:activityType
completed:completed]; completed:completed];
...@@ -143,6 +148,8 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency"; ...@@ -143,6 +148,8 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency";
#pragma mark - Private Methods: Current Page #pragma mark - Private Methods: Current Page
// Fetches the current tab's URL, configures activities and items, and shows
// an activity view.
- (void)shareCurrentPage { - (void)shareCurrentPage {
self.sharePageStartTime = base::TimeTicks::Now(); self.sharePageStartTime = base::TimeTicks::Now();
...@@ -176,9 +183,12 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency"; ...@@ -176,9 +183,12 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency";
#pragma mark - Private Methods: Share Image #pragma mark - Private Methods: Share Image
// Configures activities and items for an image and its title, and shows
// an activity view.
- (void)shareImage { - (void)shareImage {
ShareImageData* data = [[ShareImageData alloc] initWithImage:self.image ShareImageData* data =
title:self.title]; [[ShareImageData alloc] initWithImage:self.params.image
title:self.params.title];
NSArray<ChromeActivityImageSource*>* items = NSArray<ChromeActivityImageSource*>* items =
[self.mediator activityItemsForImageData:data]; [self.mediator activityItemsForImageData:data];
...@@ -187,4 +197,19 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency"; ...@@ -187,4 +197,19 @@ const char kSharePageLatencyHistogram[] = "IOS.SharePageLatency";
[self shareItems:items activities:activities]; [self shareItems:items activities:activities];
} }
#pragma mark - Private Methods: Share URL
// Configures activities and items for a URL and its title, and shows
// an activity view.
- (void)shareURL {
ShareToData* data =
activity_services::ShareToDataForURL(self.params.URL, self.params.title);
NSArray<ChromeActivityURLSource*>* items =
[self.mediator activityItemsForData:data];
NSArray* activities = [self.mediator applicationActivitiesForData:data];
[self shareItems:items activities:activities];
}
@end @end
...@@ -70,11 +70,11 @@ ...@@ -70,11 +70,11 @@
- (NSArray<ChromeActivityURLSource*>*)activityItemsForData:(ShareToData*)data { - (NSArray<ChromeActivityURLSource*>*)activityItemsForData:(ShareToData*)data {
// The provider object ChromeActivityURLSource supports the public.url UTType // The provider object ChromeActivityURLSource supports the public.url UTType
// for Share Extensions (e.g. Facebook, Twitter). // for Share Extensions (e.g. Facebook, Twitter).
ChromeActivityURLSource* urlActivitySource = [[ChromeActivityURLSource alloc] ChromeActivityURLSource* activityURLSource =
initWithShareURL:data.shareNSURL [[ChromeActivityURLSource alloc] initWithShareURL:data.shareNSURL
subject:data.title subject:data.title];
thumbnailGenerator:data.thumbnailGenerator]; activityURLSource.thumbnailGenerator = data.thumbnailGenerator;
return @[ urlActivitySource ]; return @[ activityURLSource ];
} }
- (NSArray*)applicationActivitiesForData:(ShareToData*)data { - (NSArray*)applicationActivitiesForData:(ShareToData*)data {
......
...@@ -195,9 +195,8 @@ TEST_F(ActivityServiceMediatorTest, ActivitiesForImageData) { ...@@ -195,9 +195,8 @@ TEST_F(ActivityServiceMediatorTest, ActivitiesForImageData) {
// Tests that computing the list of excluded activities works for one item. // Tests that computing the list of excluded activities works for one item.
TEST_F(ActivityServiceMediatorTest, ExcludedActivityTypes_SingleItem) { TEST_F(ActivityServiceMediatorTest, ExcludedActivityTypes_SingleItem) {
ChromeActivityURLSource* activityURLSource = [[ChromeActivityURLSource alloc] ChromeActivityURLSource* activityURLSource = [[ChromeActivityURLSource alloc]
initWithShareURL:[NSURL URLWithString:@"https://example.com"] initWithShareURL:[NSURL URLWithString:@"https://example.com"]
subject:@"Does not matter" subject:@"Does not matter"];
thumbnailGenerator:mocked_thumbnail_generator_];
NSSet* computedExclusion = NSSet* computedExclusion =
[mediator_ excludedActivityTypesForItems:@[ activityURLSource ]]; [mediator_ excludedActivityTypesForItems:@[ activityURLSource ]];
...@@ -209,9 +208,8 @@ TEST_F(ActivityServiceMediatorTest, ExcludedActivityTypes_SingleItem) { ...@@ -209,9 +208,8 @@ TEST_F(ActivityServiceMediatorTest, ExcludedActivityTypes_SingleItem) {
// Tests that computing the list of excluded activities works for two item. // Tests that computing the list of excluded activities works for two item.
TEST_F(ActivityServiceMediatorTest, ExcludedActivityTypes_TwoItems) { TEST_F(ActivityServiceMediatorTest, ExcludedActivityTypes_TwoItems) {
ChromeActivityURLSource* activityURLSource = [[ChromeActivityURLSource alloc] ChromeActivityURLSource* activityURLSource = [[ChromeActivityURLSource alloc]
initWithShareURL:[NSURL URLWithString:@"https://example.com"] initWithShareURL:[NSURL URLWithString:@"https://example.com"]
subject:@"Does not matter" subject:@"Does not matter"];
thumbnailGenerator:mocked_thumbnail_generator_];
ChromeActivityImageSource* activityImageSource = ChromeActivityImageSource* activityImageSource =
[[ChromeActivityImageSource alloc] initWithImage:[[UIImage alloc] init] [[ChromeActivityImageSource alloc] initWithImage:[[UIImage alloc] init]
title:@"something"]; title:@"something"];
......
...@@ -14,16 +14,16 @@ ...@@ -14,16 +14,16 @@
// This UIActivityItemSource-conforming object conforms to UTType public.url so // This UIActivityItemSource-conforming object conforms to UTType public.url so
// it can be used with other Social Sharing Extensions as well. The |shareURL| // it can be used with other Social Sharing Extensions as well. The |shareURL|
// is the URL shared with Social Sharing Extensions. The |subject| is used by // is the URL shared with Social Sharing Extensions. The |subject| is used by
// Mail applications to pre-fill in the subject line. The |thumbnailGenerator| // Mail applications to pre-fill in the subject line.
// is used to provide thumbnails to extensions that request one.
@interface ChromeActivityURLSource : NSObject <ChromeActivityItemSource> @interface ChromeActivityURLSource : NSObject <ChromeActivityItemSource>
// Default initializer. |shareURL|, |subject|, and |thumbnailGenerator| must not // Default initializer. |shareURL| and |subject| must not be nil.
// be nil. - (instancetype)initWithShareURL:(NSURL*)shareURL subject:(NSString*)subject;
- (instancetype)initWithShareURL:(NSURL*)shareURL
subject:(NSString*)subject // Thumbnail generator used to provide thumbnails to extensions that request
thumbnailGenerator: // one.
(ChromeActivityItemThumbnailGenerator*)thumbnailGenerator; @property(nonatomic, strong)
ChromeActivityItemThumbnailGenerator* thumbnailGenerator;
@end @end
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
@interface ChromeActivityURLSource () { @interface ChromeActivityURLSource () {
NSString* _subject; NSString* _subject;
ChromeActivityItemThumbnailGenerator* _thumbnailGenerator;
} }
// URL to be shared with share extensions. // URL to be shared with share extensions.
...@@ -25,18 +24,13 @@ ...@@ -25,18 +24,13 @@
@implementation ChromeActivityURLSource @implementation ChromeActivityURLSource
- (instancetype)initWithShareURL:(NSURL*)shareURL - (instancetype)initWithShareURL:(NSURL*)shareURL subject:(NSString*)subject {
subject:(NSString*)subject
thumbnailGenerator:
(ChromeActivityItemThumbnailGenerator*)thumbnailGenerator {
DCHECK(shareURL); DCHECK(shareURL);
DCHECK(subject); DCHECK(subject);
DCHECK(thumbnailGenerator);
self = [super init]; self = [super init];
if (self) { if (self) {
_shareURL = shareURL; _shareURL = shareURL;
_subject = [subject copy]; _subject = [subject copy];
_thumbnailGenerator = thumbnailGenerator;
} }
return self; return self;
} }
...@@ -79,7 +73,7 @@ ...@@ -79,7 +73,7 @@
(UIActivityViewController*)activityViewController (UIActivityViewController*)activityViewController
thumbnailImageForActivityType:(UIActivityType)activityType thumbnailImageForActivityType:(UIActivityType)activityType
suggestedSize:(CGSize)size { suggestedSize:(CGSize)size {
return [_thumbnailGenerator thumbnailWithSize:size]; return [self.thumbnailGenerator thumbnailWithSize:size];
} }
@end @end
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_SHARE_TO_DATA_BUILDER_H_ #ifndef IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_SHARE_TO_DATA_BUILDER_H_
#define IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_SHARE_TO_DATA_BUILDER_H_ #define IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_SHARE_TO_DATA_BUILDER_H_
#import <UIKit/UIKit.h>
class GURL; class GURL;
@class ShareToData; @class ShareToData;
...@@ -22,6 +24,10 @@ namespace activity_services { ...@@ -22,6 +24,10 @@ namespace activity_services {
ShareToData* ShareToDataForWebState(web::WebState* web_state, ShareToData* ShareToDataForWebState(web::WebState* web_state,
const GURL& share_url); 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);
} // namespace activity_services } // namespace activity_services
#endif // IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_SHARE_TO_DATA_BUILDER_H_ #endif // IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_SHARE_TO_DATA_BUILDER_H_
...@@ -83,4 +83,16 @@ ShareToData* ShareToDataForWebState(web::WebState* web_state, ...@@ -83,4 +83,16 @@ ShareToData* ShareToDataForWebState(web::WebState* web_state,
thumbnailGenerator:thumbnail_generator]; thumbnailGenerator:thumbnail_generator];
} }
ShareToData* ShareToDataForURL(const GURL& URL, NSString* title) {
return [[ShareToData alloc] initWithShareURL:URL
visibleURL:URL
title:title
isOriginalTitle:YES
isPagePrintable:NO
isPageSearchable:NO
canSendTabToSelf:NO
userAgent:web::UserAgentType::NONE
thumbnailGenerator:nil];
}
} // namespace activity_services } // namespace activity_services
...@@ -126,3 +126,22 @@ TEST_F(ShareToDataBuilderTest, TestSharePageCommandHandlingNoShareUrl) { ...@@ -126,3 +126,22 @@ TEST_F(ShareToDataBuilderTest, TestSharePageCommandHandlingNoShareUrl) {
TEST_F(ShareToDataBuilderTest, TestReturnsNilWhenClosing) { TEST_F(ShareToDataBuilderTest, TestReturnsNilWhenClosing) {
EXPECT_EQ(nil, activity_services::ShareToDataForWebState(nullptr, GURL())); EXPECT_EQ(nil, activity_services::ShareToDataForWebState(nullptr, GURL()));
} }
// Tests that the ShareToDataForURL function creates a ShareToData instance with
// valid properties.
TEST_F(ShareToDataBuilderTest, ShareToDataForURL) {
GURL testURL = GURL("http://www.testurl.com/");
NSString* testTitle = @"Some Title";
ShareToData* data = activity_services::ShareToDataForURL(testURL, testTitle);
EXPECT_EQ(testURL, data.shareURL);
EXPECT_EQ(testURL, data.visibleURL);
EXPECT_EQ(testTitle, data.title);
EXPECT_TRUE(data.isOriginalTitle);
EXPECT_FALSE(data.isPagePrintable);
EXPECT_FALSE(data.isPageSearchable);
EXPECT_FALSE(data.canSendTabToSelf);
EXPECT_EQ(web::UserAgentType::NONE, data.userAgent);
EXPECT_FALSE(data.thumbnailGenerator);
}
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#import "ios/chrome/browser/store_kit/store_kit_coordinator.h" #import "ios/chrome/browser/store_kit/store_kit_coordinator.h"
#import "ios/chrome/browser/store_kit/store_kit_tab_helper.h" #import "ios/chrome/browser/store_kit/store_kit_tab_helper.h"
#import "ios/chrome/browser/tabs/tab_title_util.h" #import "ios/chrome/browser/tabs/tab_title_util.h"
#import "ios/chrome/browser/ui/activity_services/activity_params.h"
#import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h" #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h"
#import "ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.h" #import "ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.h"
#import "ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.h" #import "ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.h"
...@@ -553,9 +554,13 @@ ...@@ -553,9 +554,13 @@
UIView* shareButton = UIView* shareButton =
[self.viewController.activityServicePositioner shareButtonView]; [self.viewController.activityServicePositioner shareButtonView];
ActivityParams* params = [[ActivityParams alloc]
initWithScenario:ActivityScenario::TabShareButton];
self.sharingCoordinator = self.sharingCoordinator =
[[SharingCoordinator alloc] initWithBaseViewController:self.viewController [[SharingCoordinator alloc] initWithBaseViewController:self.viewController
browser:self.browser browser:self.browser
params:params
originView:shareButton]; originView:shareButton];
[self.sharingCoordinator start]; [self.sharingCoordinator start];
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/metrics/user_metrics_action.h" #include "base/metrics/user_metrics_action.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "ios/chrome/browser/main/browser.h" #include "ios/chrome/browser/main/browser.h"
#import "ios/chrome/browser/ui/activity_services/activity_params.h"
#import "ios/chrome/browser/ui/activity_services/activity_scenario.h" #import "ios/chrome/browser/ui/activity_services/activity_scenario.h"
#import "ios/chrome/browser/ui/activity_services/activity_service_coordinator.h" #import "ios/chrome/browser/ui/activity_services/activity_service_coordinator.h"
#import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h" #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h"
...@@ -105,19 +106,23 @@ ...@@ -105,19 +106,23 @@
- (void)confirmationAlertPrimaryAction { - (void)confirmationAlertPrimaryAction {
base::RecordAction(base::UserMetricsAction("MobileShareQRCode")); base::RecordAction(base::UserMetricsAction("MobileShareQRCode"));
NSString* imageTitle = l10n_util::GetNSStringF(
IDS_IOS_QR_CODE_ACTIVITY_TITLE, base::SysNSStringToUTF16(self.title));
ActivityParams* params =
[[ActivityParams alloc] initWithImage:self.viewController.content
title:imageTitle
scenario:ActivityScenario::QRCodeImage];
// Configure the image sharing scenario.
self.activityServiceCoordinator = [[ActivityServiceCoordinator alloc] self.activityServiceCoordinator = [[ActivityServiceCoordinator alloc]
initWithBaseViewController:self.viewController initWithBaseViewController:self.viewController
browser:self.browser browser:self.browser
scenario:ActivityScenario::QRCodeImage]; params:params];
self.activityServiceCoordinator.positionProvider = self; self.activityServiceCoordinator.positionProvider = self;
self.activityServiceCoordinator.presentationProvider = self; self.activityServiceCoordinator.presentationProvider = self;
// Configure the image sharing scenario.
self.activityServiceCoordinator.image = self.viewController.content;
self.activityServiceCoordinator.title = l10n_util::GetNSStringF(
IDS_IOS_QR_CODE_ACTIVITY_TITLE, base::SysNSStringToUTF16(self.title));
[self.activityServiceCoordinator start]; [self.activityServiceCoordinator start];
} }
......
...@@ -7,18 +7,23 @@ ...@@ -7,18 +7,23 @@
#include <UIKit/UIKit.h> #include <UIKit/UIKit.h>
#import "ios/chrome/browser/ui/activity_services/activity_scenario.h"
#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
@class ActivityParams;
class Browser; class Browser;
// Coordinator of sharing scenarios. Its default scenario is to share the // Coordinator of sharing scenarios. Its default scenario is to share the
// current tab's URL. // current tab's URL.
@interface SharingCoordinator : ChromeCoordinator @interface SharingCoordinator : ChromeCoordinator
// Creates a coordinator using the base |viewController|, a |browser| and an // Creates a coordinator configured to share the current tab's URL using the
// |originView| from which the sharing scenario was triggered. // base |viewController|, a |browser|, |params| with all the necessary values
// to drive the scenario, and an |originView| from which the scenario was
// triggered.
- (instancetype)initWithBaseViewController:(UIViewController*)viewController - (instancetype)initWithBaseViewController:(UIViewController*)viewController
browser:(Browser*)browser browser:(Browser*)browser
params:(ActivityParams*)params
originView:(UIView*)originView originView:(UIView*)originView
NS_DESIGNATED_INITIALIZER; NS_DESIGNATED_INITIALIZER;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#import "ios/chrome/browser/ui/sharing/sharing_coordinator.h" #import "ios/chrome/browser/ui/sharing/sharing_coordinator.h"
#import "ios/chrome/browser/ui/activity_services/activity_scenario.h" #import "ios/chrome/browser/ui/activity_services/activity_params.h"
#import "ios/chrome/browser/ui/activity_services/activity_service_coordinator.h" #import "ios/chrome/browser/ui/activity_services/activity_service_coordinator.h"
#import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h" #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h"
#import "ios/chrome/browser/ui/activity_services/requirements/activity_service_presentation.h" #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_presentation.h"
...@@ -19,12 +19,13 @@ ...@@ -19,12 +19,13 @@
@interface SharingCoordinator () <ActivityServicePositioner, @interface SharingCoordinator () <ActivityServicePositioner,
ActivityServicePresentation, ActivityServicePresentation,
QRGenerationCommands> QRGenerationCommands>
@property(nonatomic, strong) @property(nonatomic, strong)
ActivityServiceCoordinator* activityServiceCoordinator; ActivityServiceCoordinator* activityServiceCoordinator;
@property(nonatomic, strong) QRGeneratorCoordinator* qrGeneratorCoordinator; @property(nonatomic, strong) QRGeneratorCoordinator* qrGeneratorCoordinator;
@property(nonatomic, strong) ActivityParams* params;
@property(nonatomic, weak) UIView* originView; @property(nonatomic, weak) UIView* originView;
@end @end
...@@ -33,9 +34,12 @@ ...@@ -33,9 +34,12 @@
- (instancetype)initWithBaseViewController:(UIViewController*)viewController - (instancetype)initWithBaseViewController:(UIViewController*)viewController
browser:(Browser*)browser browser:(Browser*)browser
params:(ActivityParams*)params
originView:(UIView*)originView { originView:(UIView*)originView {
DCHECK(params);
if (self = [super initWithBaseViewController:viewController if (self = [super initWithBaseViewController:viewController
browser:browser]) { browser:browser]) {
_params = params;
_originView = originView; _originView = originView;
} }
return self; return self;
...@@ -47,7 +51,7 @@ ...@@ -47,7 +51,7 @@
self.activityServiceCoordinator = [[ActivityServiceCoordinator alloc] self.activityServiceCoordinator = [[ActivityServiceCoordinator alloc]
initWithBaseViewController:self.baseViewController initWithBaseViewController:self.baseViewController
browser:self.browser browser:self.browser
scenario:ActivityScenario::TabShareButton]; params:self.params];
self.activityServiceCoordinator.positionProvider = self; self.activityServiceCoordinator.positionProvider = self;
self.activityServiceCoordinator.presentationProvider = self; self.activityServiceCoordinator.presentationProvider = self;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/values.h" #include "base/values.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/main/test_browser.h" #include "ios/chrome/browser/main/test_browser.h"
#import "ios/chrome/browser/ui/activity_services/activity_params.h"
#import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h" #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h"
#import "ios/chrome/browser/ui/activity_services/requirements/activity_service_presentation.h" #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_presentation.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h" #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
...@@ -49,17 +50,11 @@ class SharingCoordinatorTest : public PlatformTest { ...@@ -49,17 +50,11 @@ class SharingCoordinatorTest : public PlatformTest {
SharingCoordinatorTest() SharingCoordinatorTest()
: base_view_controller_([[UIViewController alloc] init]), : base_view_controller_([[UIViewController alloc] init]),
browser_(std::make_unique<TestBrowser>()), browser_(std::make_unique<TestBrowser>()),
fake_origin_view_([[UIView alloc] init]) { fake_origin_view_([[UIView alloc] init]),
test_scenario_(ActivityScenario::TabShareButton) {
[scoped_key_window_.Get() setRootViewController:base_view_controller_]; [scoped_key_window_.Get() setRootViewController:base_view_controller_];
} }
SharingCoordinator* GetCoordinator() {
return [[SharingCoordinator alloc]
initWithBaseViewController:base_view_controller_
browser:browser_.get()
originView:fake_origin_view_];
}
void AppendNewWebState(std::unique_ptr<web::TestWebState> web_state) { void AppendNewWebState(std::unique_ptr<web::TestWebState> web_state) {
browser_->GetWebStateList()->InsertWebState( browser_->GetWebStateList()->InsertWebState(
WebStateList::kInvalidIndex, std::move(web_state), WebStateList::kInvalidIndex, std::move(web_state),
...@@ -71,6 +66,7 @@ class SharingCoordinatorTest : public PlatformTest { ...@@ -71,6 +66,7 @@ class SharingCoordinatorTest : public PlatformTest {
UIViewController* base_view_controller_; UIViewController* base_view_controller_;
std::unique_ptr<TestBrowser> browser_; std::unique_ptr<TestBrowser> browser_;
UIView* fake_origin_view_; UIView* fake_origin_view_;
ActivityScenario test_scenario_;
}; };
// Tests that the start method shares the current page and ends up presenting // Tests that the start method shares the current page and ends up presenting
...@@ -92,7 +88,14 @@ TEST_F(SharingCoordinatorTest, Start_ShareCurrentPage) { ...@@ -92,7 +88,14 @@ TEST_F(SharingCoordinatorTest, Start_ShareCurrentPage) {
AppendNewWebState(std::move(test_web_state)); AppendNewWebState(std::move(test_web_state));
SharingCoordinator* coordinator = GetCoordinator(); ActivityParams* params =
[[ActivityParams alloc] initWithScenario:test_scenario_];
SharingCoordinator* coordinator = [[SharingCoordinator alloc]
initWithBaseViewController:base_view_controller_
browser:browser_.get()
params:params
originView:fake_origin_view_];
// Pointer to allow us to grab the VC instance in our validation callback. // Pointer to allow us to grab the VC instance in our validation callback.
__block UIActivityViewController* activityViewController; __block UIActivityViewController* activityViewController;
...@@ -132,7 +135,13 @@ TEST_F(SharingCoordinatorTest, Start_ShareCurrentPage) { ...@@ -132,7 +135,13 @@ TEST_F(SharingCoordinatorTest, Start_ShareCurrentPage) {
// Tests that the coordinator handles the QRGenerationCommands protocol. // Tests that the coordinator handles the QRGenerationCommands protocol.
TEST_F(SharingCoordinatorTest, GenerateQRCode) { TEST_F(SharingCoordinatorTest, GenerateQRCode) {
SharingCoordinator* coordinator = GetCoordinator(); ActivityParams* params =
[[ActivityParams alloc] initWithScenario:test_scenario_];
SharingCoordinator* coordinator = [[SharingCoordinator alloc]
initWithBaseViewController:base_view_controller_
browser:browser_.get()
params:params
originView:fake_origin_view_];
id vc_partial_mock = OCMPartialMock(base_view_controller_); id vc_partial_mock = OCMPartialMock(base_view_controller_);
[[vc_partial_mock expect] presentViewController:[OCMArg any] [[vc_partial_mock expect] presentViewController:[OCMArg any]
...@@ -152,3 +161,38 @@ TEST_F(SharingCoordinatorTest, GenerateQRCode) { ...@@ -152,3 +161,38 @@ TEST_F(SharingCoordinatorTest, GenerateQRCode) {
[vc_partial_mock verify]; [vc_partial_mock verify];
} }
// Tests that the start method shares the given URL and ends up presenting
// a UIActivityViewController.
TEST_F(SharingCoordinatorTest, Start_ShareURL) {
GURL testURL = GURL("https://example.com");
NSString* testTitle = @"Some title";
ActivityParams* params = [[ActivityParams alloc] initWithURL:testURL
title:testTitle
scenario:test_scenario_];
SharingCoordinator* coordinator = [[SharingCoordinator alloc]
initWithBaseViewController:base_view_controller_
browser:browser_.get()
params:params
originView:fake_origin_view_];
// Pointer to allow us to grab the VC instance in our validation callback.
__block UIActivityViewController* activityViewController;
id vc_partial_mock = OCMPartialMock(base_view_controller_);
[[vc_partial_mock expect]
presentViewController:[OCMArg checkWithBlock:^BOOL(
UIViewController* viewController) {
if ([viewController isKindOfClass:[UIActivityViewController class]]) {
activityViewController = (UIActivityViewController*)viewController;
return YES;
}
return NO;
}]
animated:YES
completion:nil];
[coordinator start];
[vc_partial_mock verify];
}
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