Commit c8ccd58e authored by Andy Lu's avatar Andy Lu Committed by Commit Bot

[ios] Support Open in Incognito for multiple URLs and accept inputs from other actions

The Siri shortcut accepts a list of URLs and open them in Incognito
mode. Also able to accept inputs from scripting actions (i.e. a list)
and open the URLs in it successfully.

Deletions of lines in intentdefinition are auto-generated during build.
No intentional deletion was done.

Bug: 1091764
Change-Id: I7de200803f93434db8608b87d693e84802515d30
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2236243
Commit-Queue: Andy Lu <andyhylu@google.com>
Reviewed-by: default avatarJavier Ernesto Flores Robles <javierrobles@chromium.org>
Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarMark Pearson <mpearson@chromium.org>
Reviewed-by: default avatarSylvain Defresne <sdefresne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#793664}
parent 785e9823
......@@ -36,6 +36,10 @@ class GURL;
// |externalURL|.
@property(nonatomic, readonly, assign) const GURL& completeURL;
// The list of URLs to open. First URL in the vector is the same
// as |externalURL|.
@property(nonatomic, readonly, assign) const std::vector<GURL>& URLs;
// The URL query string parameters in the case that the app was launched as a
// result of Universal Link navigation. The map associates query string
// parameters with their corresponding value.
......@@ -64,6 +68,8 @@ class GURL;
- (instancetype)initWithUniversalLink:(const GURL&)universalLink;
- (instancetype)initWithURLs:(const std::vector<GURL>&)URLs;
@end
#endif // IOS_CHROME_APP_APP_STARTUP_PARAMETERS_H_
......@@ -17,6 +17,7 @@
@implementation AppStartupParameters {
GURL _externalURL;
GURL _completeURL;
std::vector<GURL> _URLs;
}
@synthesize externalURLParams = _externalURLParams;
......@@ -44,6 +45,20 @@
return self;
}
- (instancetype)initWithURLs:(const std::vector<GURL>&)URLs {
if (URLs.empty()) {
self = [self initWithExternalURL:GURL(kChromeUINewTabURL)
completeURL:GURL(kChromeUINewTabURL)];
} else {
self = [self initWithExternalURL:URLs.front() completeURL:URLs.front()];
}
if (self) {
_URLs = URLs;
}
return self;
}
// TODO(crbug.com/1021752): Remove this stub since |universalLink| is unused.
- (instancetype)initWithUniversalLink:(const GURL&)universalLink {
// If a new tab with |_externalURL| needs to be opened after the App
......
......@@ -13,7 +13,8 @@ struct UrlLoadParams;
// Mocks a class adopting the TabOpening protocol. It saves the arguments of
// -dismissModalsAndOpenSelectedTabInMode:withUrlLoadParams:dismissOmnibox:
// completion:.
// completion:. Can also save the arguments of
// -dismissModalsAndOpenMultipleTabsInMode:URLs:dismissOmnibox:completion:.
@interface MockTabOpener : NSObject<TabOpening>
// Arguments for
// -dismissModalsAndOpenSelectedTabInMode:withUrlLoadParams:dismissOmnibox:
......@@ -21,6 +22,9 @@ struct UrlLoadParams;
@property(nonatomic, readonly) UrlLoadParams urlLoadParams;
@property(nonatomic, readonly) ApplicationModeForTabOpening applicationMode;
@property(nonatomic, strong, readonly) void (^completionBlock)(void);
// Argument for
// -dismissModalsAndOpenMultipleTabsInMode:URLs:dismissOmnibox:completion:.
@property(nonatomic, readonly) const std::vector<GURL>& URLs;
// Clear the URL.
- (void)resetURL;
......
......@@ -7,6 +7,7 @@
#include "base/ios/block_types.h"
#include "ios/chrome/app/application_mode.h"
#import "ios/chrome/browser/url_loading/url_loading_params.h"
#import "net/base/mac/url_conversions.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
......@@ -14,7 +15,9 @@
#error "This file requires ARC support."
#endif
@implementation MockTabOpener
@implementation MockTabOpener {
std::vector<GURL> _URLs;
}
- (void)dismissModalsAndOpenSelectedTabInMode:
(ApplicationModeForTabOpening)targetMode
......@@ -25,6 +28,15 @@
_urlLoadParams = urlLoadParams;
_applicationMode = targetMode;
_completionBlock = [completion copy];
_URLs.push_back(urlLoadParams.web_params.url);
}
- (void)dismissModalsAndOpenMultipleTabsInMode:
(ApplicationModeForTabOpening)targetMode
URLs:(const std::vector<GURL>&)URLs
dismissOmnibox:(BOOL)dismissOmnibox
completion:(ProceduralBlock)completion {
_URLs = URLs;
}
- (void)resetURL {
......
......@@ -31,6 +31,15 @@ struct UrlLoadParams;
dismissOmnibox:(BOOL)dismissOmnibox
completion:(ProceduralBlock)completion;
// Dismisses any modal view, excluding the omnibox if |dismissOmnibox| is NO,
// then opens the list of URLs in |URLs| in either normal or incognito.
// After opening the array of URLs, run completion |handler| if it not nil.
- (void)dismissModalsAndOpenMultipleTabsInMode:
(ApplicationModeForTabOpening)targetMode
URLs:(const std::vector<GURL>&)URLs
dismissOmnibox:(BOOL)dismissOmnibox
completion:(ProceduralBlock)completion;
// Creates a new tab if the launch options are not null.
- (void)openTabFromLaunchWithParams:(URLOpenerParams*)params
startupInformation:(id<StartupInformation>)startupInformation
......
......@@ -19,6 +19,7 @@
#import "ios/chrome/app/application_delegate/startup_information.h"
#import "ios/chrome/app/application_delegate/tab_opening.h"
#include "ios/chrome/app/application_mode.h"
#import "ios/chrome/app/intents/OpenInChromeIncognitoIntent.h"
#import "ios/chrome/app/intents/OpenInChromeIntent.h"
#import "ios/chrome/app/intents/SearchInChromeIntent.h"
#import "ios/chrome/app/spotlight/actions_spotlight_manager.h"
......@@ -55,6 +56,11 @@ NSString* const kShortcutNewIncognitoSearch = @"OpenIncognitoSearch";
NSString* const kShortcutVoiceSearch = @"OpenVoiceSearch";
NSString* const kShortcutQRScanner = @"OpenQRScanner";
// Constants for Siri shortcut.
NSString* const kSiriShortcutOpenInChrome = @"OpenInChromeIntent";
NSString* const kSiriShortcutSearchInChrome = @"SearchInChromeIntent";
NSString* const kSiriShortcutOpenInIncognito = @"OpenInChromeIncognitoIntent";
} // namespace
@interface UserActivityHandler ()
......@@ -143,7 +149,7 @@ NSString* const kShortcutQRScanner = @"OpenQRScanner";
return YES;
}
} else if ([userActivity.activityType
isEqualToString:@"SearchInChromeIntent"]) {
isEqualToString:kSiriShortcutSearchInChrome]) {
base::RecordAction(UserMetricsAction("IOSLaunchedBySearchInChromeIntent"));
AppStartupParameters* startupParams = [[AppStartupParameters alloc]
......@@ -166,7 +172,7 @@ NSString* const kShortcutQRScanner = @"OpenQRScanner";
webpageURL =
[NSURL URLWithString:base::SysUTF8ToNSString(kChromeUINewTabURL)];
} else if ([userActivity.activityType
isEqualToString:@"OpenInChromeIntent"]) {
isEqualToString:kSiriShortcutOpenInChrome]) {
base::RecordAction(UserMetricsAction("IOSLaunchedByOpenInChromeIntent"));
OpenInChromeIntent* intent = base::mac::ObjCCastStrict<OpenInChromeIntent>(
userActivity.interaction.intent);
......@@ -182,6 +188,28 @@ NSString* const kShortcutQRScanner = @"OpenQRScanner";
completeURL:webpageGURL];
[connectionInformation setStartupParameters:startupParams];
webpageURL = intent.url;
} else if ([userActivity.activityType
isEqualToString:kSiriShortcutOpenInIncognito]) {
base::RecordAction(UserMetricsAction("IOSLaunchedByOpenInIncognitoIntent"));
OpenInChromeIncognitoIntent* intent =
base::mac::ObjCCastStrict<OpenInChromeIncognitoIntent>(
userActivity.interaction.intent);
if (!intent.urls || intent.urls.count == 0) {
return NO;
}
std::vector<GURL> URLs;
for (NSURL* URL in intent.urls) {
URLs.push_back(net::GURLWithNSURL(URL));
}
AppStartupParameters* startupParams =
[[AppStartupParameters alloc] initWithURLs:URLs];
startupParams.launchInIncognito = YES;
[connectionInformation setStartupParameters:startupParams];
return YES;
} else {
// Do nothing for unknown activity type.
return NO;
......@@ -282,8 +310,39 @@ NSString* const kShortcutQRScanner = @"OpenQRScanner";
// Do not load the external URL if the user has not accepted the terms of
// service. This corresponds to the case when the user installed Chrome,
// has never launched it and attempts to open an external URL in Chrome.
if ([startupInformation isPresentingFirstRunUI])
if ([startupInformation isPresentingFirstRunUI]) {
return;
}
if (!connectionInformation.startupParameters.URLs.empty()) {
ApplicationModeForTabOpening mode =
connectionInformation.startupParameters.launchInIncognito
? ApplicationModeForTabOpening::INCOGNITO
: ApplicationModeForTabOpening::NORMAL;
BOOL dismissOmnibox = [[connectionInformation startupParameters]
postOpeningAction] != FOCUS_OMNIBOX;
// Using a weak reference to |connectionInformation| to solve a memory leak
// issue. |tabOpener| and |connectionInformation| are the same object in
// some cases (SceneController). This retains the object while the block
// exists. Then this block is passed around and in some cases it ends up
// stored in BrowserViewController. This results in a memory leak that looks
// like this: SceneController -> BrowserViewWrangler -> BrowserCoordinator
// -> BrowserViewController -> SceneController
__weak id<ConnectionInformation> weakConnectionInfo = connectionInformation;
[tabOpener
dismissModalsAndOpenMultipleTabsInMode:mode
URLs:weakConnectionInfo
.startupParameters.URLs
dismissOmnibox:dismissOmnibox
completion:^{
weakConnectionInfo.startupParameters =
nil;
}];
return;
}
GURL externalURL = connectionInformation.startupParameters.externalURL;
// Check if it's an U2F call. If so, route it to correct tab.
......
......@@ -20,6 +20,7 @@
#include "ios/chrome/app/application_delegate/startup_information.h"
#include "ios/chrome/app/application_delegate/tab_opening.h"
#include "ios/chrome/app/application_mode.h"
#import "ios/chrome/app/intents/OpenInChromeIncognitoIntent.h"
#import "ios/chrome/app/intents/OpenInChromeIntent.h"
#include "ios/chrome/app/main_controller.h"
#include "ios/chrome/app/spotlight/actions_spotlight_manager.h"
......@@ -451,6 +452,64 @@ TEST_F(UserActivityHandlerTest, ContinueUserActivityShortcutActions) {
}
}
// Tests that Chrome responds to open in incognito intent in the background
TEST_F(UserActivityHandlerTest, ContinueUserActivityIntentIncognitoBackground) {
NSURL* url1 = [[NSURL alloc] initWithString:@"http://www.google.com"];
NSURL* url2 = [[NSURL alloc] initWithString:@"http://www.apple.com"];
NSURL* url3 = [[NSURL alloc] initWithString:@"http://www.espn.com"];
NSArray<NSURL*>* urls = [NSArray arrayWithObjects:url1, url2, url3, nil];
NSUserActivity* userActivity = [[NSUserActivity alloc]
initWithActivityType:@"OpenInChromeIncognitoIntent"];
OpenInChromeIncognitoIntent* intent =
[[OpenInChromeIncognitoIntent alloc] init];
intent.urls = urls;
INInteraction* interaction = [[INInteraction alloc] initWithIntent:intent
response:nil];
userActivity.interaction = interaction;
id startupInformationMock =
[OCMockObject niceMockForProtocol:@protocol(StartupInformation)];
id connectionInformationMock =
[OCMockObject niceMockForProtocol:@protocol(ConnectionInformation)];
[[connectionInformationMock expect]
setStartupParameters:[OCMArg checkWithBlock:^BOOL(id value) {
EXPECT_TRUE([value isKindOfClass:[AppStartupParameters class]] ||
value == nil);
if (value != nil) {
AppStartupParameters* startupParameters =
(AppStartupParameters*)value;
const GURL calledURL = startupParameters.externalURL;
EXPECT_TRUE((int)[intent.urls count] == 3);
return [intent.urls containsObject:(net::NSURLWithGURL(calledURL))];
} else {
return YES;
}
}]];
[[[startupInformationMock stub] andReturnValue:@NO] isPresentingFirstRunUI];
MockTabOpener* tabOpener = [[MockTabOpener alloc] init];
// Action.
BOOL result =
[UserActivityHandler continueUserActivity:userActivity
applicationIsActive:NO
tabOpener:tabOpener
connectionInformation:connectionInformationMock
startupInformation:startupInformationMock];
EXPECT_OCMOCK_VERIFY(startupInformationMock);
EXPECT_TRUE(result);
}
// Tests that Chrome responds to open intents in the background.
TEST_F(UserActivityHandlerTest, ContinueUserActivityIntentBackground) {
NSUserActivity* userActivity =
......@@ -491,6 +550,65 @@ TEST_F(UserActivityHandlerTest, ContinueUserActivityIntentBackground) {
EXPECT_TRUE(result);
}
// Test that Chrome respond to open in incognito intent in the foreground.
TEST_F(UserActivityHandlerTest, ContinueUserActivityIntentIncognitoForeground) {
NSURL* url1 = [[NSURL alloc] initWithString:@"http://www.google.com"];
NSURL* url2 = [[NSURL alloc] initWithString:@"http://www.apple.com"];
NSURL* url3 = [[NSURL alloc] initWithString:@"http://www.espn.com"];
NSArray<NSURL*>* urls = [NSArray arrayWithObjects:url1, url2, url3, nil];
NSUserActivity* userActivity = [[NSUserActivity alloc]
initWithActivityType:@"OpenInChromeIncognitoIntent"];
OpenInChromeIncognitoIntent* intent =
[[OpenInChromeIncognitoIntent alloc] init];
intent.urls = urls;
INInteraction* interaction = [[INInteraction alloc] initWithIntent:intent
response:nil];
userActivity.interaction = interaction;
id startupInformationMock =
[OCMockObject niceMockForProtocol:@protocol(StartupInformation)];
id connectionInformationMock =
[OCMockObject niceMockForProtocol:@protocol(ConnectionInformation)];
[[connectionInformationMock expect]
setStartupParameters:[OCMArg checkWithBlock:^BOOL(id value) {
EXPECT_TRUE([value isKindOfClass:[AppStartupParameters class]] ||
value == nil);
if (value != nil) {
AppStartupParameters* startupParameters =
(AppStartupParameters*)value;
const GURL calledURL = startupParameters.externalURL;
EXPECT_TRUE((int)[intent.urls count] == 3);
return [intent.urls containsObject:(net::NSURLWithGURL(calledURL))];
} else {
return YES;
}
}]];
[[[startupInformationMock stub] andReturnValue:@NO] isPresentingFirstRunUI];
MockTabOpener* tabOpener = [[MockTabOpener alloc] init];
// Action.
BOOL result =
[UserActivityHandler continueUserActivity:userActivity
applicationIsActive:YES
tabOpener:tabOpener
connectionInformation:connectionInformationMock
startupInformation:startupInformationMock];
// Test.
EXPECT_OCMOCK_VERIFY(startupInformationMock);
EXPECT_TRUE(result);
}
// Tests that Chrome responds to open intents in the foreground.
TEST_F(UserActivityHandlerTest, ContinueUserActivityIntentForeground) {
GURL gurl("http://www.google.com");
......
......@@ -8,6 +8,7 @@ intent_definition("intents") {
intent_file = "Intents.intentdefinition"
intent_names = [
"OpenInChromeIntent",
"OpenInChromeIncognitoIntent",
"SearchInChromeIntent",
]
}
......@@ -203,6 +203,98 @@
<key>INIntentVerb</key>
<string>Open</string>
</dict>
<dict>
<key>INIntentCategory</key>
<string>information</string>
<key>INIntentConfigurable</key>
<true/>
<key>INIntentDescriptionID</key>
<string>dYRltF</string>
<key>INIntentEligibleForWidgets</key>
<true/>
<key>INIntentIneligibleForSuggestions</key>
<true/>
<key>INIntentInput</key>
<string>urls</string>
<key>INIntentLastParameterTag</key>
<integer>4</integer>
<key>INIntentManagedParameterCombinations</key>
<dict>
<key>urls</key>
<dict>
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
<true/>
<key>INIntentParameterCombinationTitle</key>
<string>Open ${urls} in Incognito</string>
<key>INIntentParameterCombinationTitleID</key>
<string>6TwrYB</string>
<key>INIntentParameterCombinationUpdatesLinked</key>
<true/>
</dict>
</dict>
<key>INIntentName</key>
<string>OpenInChromeIncognito</string>
<key>INIntentParameters</key>
<array>
<dict>
<key>INIntentParameterConfigurable</key>
<true/>
<key>INIntentParameterDisplayName</key>
<string>URLs</string>
<key>INIntentParameterDisplayNameID</key>
<string>C8MCpv</string>
<key>INIntentParameterDisplayPriority</key>
<integer>1</integer>
<key>INIntentParameterName</key>
<string>urls</string>
<key>INIntentParameterPromptDialogs</key>
<array>
<dict>
<key>INIntentParameterPromptDialogCustom</key>
<true/>
<key>INIntentParameterPromptDialogFormatString</key>
<string>What URLs?</string>
<key>INIntentParameterPromptDialogFormatStringID</key>
<string>sNz7Cu</string>
<key>INIntentParameterPromptDialogType</key>
<string>Primary</string>
</dict>
</array>
<key>INIntentParameterSupportsMultipleValues</key>
<true/>
<key>INIntentParameterSupportsResolution</key>
<true/>
<key>INIntentParameterTag</key>
<integer>4</integer>
<key>INIntentParameterType</key>
<string>URL</string>
</dict>
</array>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
<dict>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Open URLs In Chrome Incognito</string>
<key>INIntentTitleID</key>
<string>LHJwpy</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentVerb</key>
<string>Open</string>
</dict>
</array>
<key>INTypes</key>
<array/>
......
......@@ -95,6 +95,7 @@
<string>${CHROMIUM_HANDOFF_ID}</string>
<string>OpenInChromeIntent</string>
<string>SearchInChromeIntent</string>
<string>OpenInChromeIncognitoIntent</string>
</array>
<key>UIBackgroundModes</key>
<array>
......
......@@ -28,6 +28,24 @@
<string>Intents.strings</string>
<key>strings</key>
<array>
<dict>
<key>input</key>
<string>IDS_IOS_INTENTS_OPEN_IN_CHROME_INCOGNITO_TITLE</string>
<key>output</key>
<string>LHJwpy</string>
</dict>
<dict>
<key>input</key>
<string>IDS_IOS_INTENTS_OPEN_IN_CHROME_INCOGNITO_DESCRIPTION</string>
<key>output</key>
<string>dYRltF</string>
</dict>
<dict>
<key>input</key>
<string>IDS_IOS_INTENTS_OPEN_IN_CHROME_INCOGNITO_PARAMETER_COMBINATION_TITLE</string>
<key>output</key>
<string>6TwrYB</string>
</dict>
<dict>
<key>input</key>
<string>IDS_IOS_INTENTS_SEARCH_IN_CHROME_DESCRIPTION</string>
......
......@@ -932,6 +932,15 @@ Because your account is managed by <ph name="HOSTED_DOMAIN">$1<ex>google.com</ex
<message name="IDS_IOS_INTENTS_OPEN_IN_CHROME_PARAMETER_COMBINATION_TITLE" desc="Apple Shortcuts.app format for displaying the URL input [iOS only].">
Open ${url}
</message>
<message name="IDS_IOS_INTENTS_OPEN_IN_CHROME_INCOGNITO_TITLE" desc="Shortcut name to open URL in Chrome in Incognito [iOS only].">
Open URLs in Chrome in Incognito
</message>
<message name="IDS_IOS_INTENTS_OPEN_IN_CHROME_INCOGNITO_DESCRIPTION" desc="Shortcut description to open URLs in Chrome in Incognito [iOS only].">
Opens the inputted URLs in Google Chrome in Incognito.
</message>
<message name="IDS_IOS_INTENTS_OPEN_IN_CHROME_INCOGNITO_PARAMETER_COMBINATION_TITLE" desc="Apple Shortcuts.app format for displaying the URL input [iOS only].">
Open ${urls} in Incognito
</message>
<message name="IDS_IOS_INTENTS_SEARCH_IN_CHROME_DESCRIPTION" desc="Siri Shortcut for search in chrome description [iOS only].">
Start a search in a new Chrome tab.
</message>
......
8614ba451df59e9955225a99e030b9072e86701e
\ No newline at end of file
931014dc4c94334d3c6a37b6ddfb68cfc7ff7f7f
\ No newline at end of file
......@@ -79,6 +79,7 @@
#import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h"
#include "ios/web/public/thread/web_task_traits.h"
#import "ios/web/public/web_state.h"
#import "net/base/mac/url_conversions.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
......@@ -1353,6 +1354,55 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
dismissOmnibox:dismissOmnibox];
}
- (void)dismissModalsAndOpenMultipleTabsInMode:
(ApplicationModeForTabOpening)targetMode
URLs:(const std::vector<GURL>&)URLs
dismissOmnibox:(BOOL)dismissOmnibox
completion:(ProceduralBlock)completion {
__weak SceneController* weakSelf = self;
std::vector<GURL> copyURLs = URLs;
id<BrowserInterface> targetInterface =
[self extractInterfaceBaseOnMode:targetMode];
web::WebState* currentWebState =
targetInterface.browser->GetWebStateList()->GetActiveWebState();
if (currentWebState) {
web::NavigationManager* navigation_manager =
currentWebState->GetNavigationManager();
// Check if the current tab is in the procress of restoration and whether it
// is an NTP. If so, add the tabs-opening action to the
// RestoreCompletionCallback queue so that the tabs are opened only after
// the NTP finishes restoring. This is to avoid an edge where multiple tabs
// are trying to open in the middle of NTP restoration, as this will cause
// all tabs trying to load into the same NTP, causing a race condition that
// results in wrong behavior.
if (navigation_manager->IsRestoreSessionInProgress() &&
IsURLNtp(currentWebState->GetVisibleURL())) {
navigation_manager->AddRestoreCompletionCallback(base::BindOnce(^{
[self
dismissModalDialogsWithCompletion:^{
[weakSelf openMultipleTabsInMode:targetMode
URLs:copyURLs
completion:completion];
}
dismissOmnibox:dismissOmnibox];
}));
return;
}
}
[self
dismissModalDialogsWithCompletion:^{
[weakSelf openMultipleTabsInMode:targetMode
URLs:copyURLs
completion:completion];
}
dismissOmnibox:dismissOmnibox];
}
- (void)openTabFromLaunchWithParams:(URLOpenerParams*)params
startupInformation:(id<StartupInformation>)startupInformation
appState:(AppState*)appState {
......@@ -1508,6 +1558,61 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
ios::GetChromeBrowserProvider()->LogIfModalViewsArePresented();
}
- (void)openMultipleTabsInMode:
(ApplicationModeForTabOpening)tabOpeningTargetMode
URLs:(const std::vector<GURL>&)URLs
completion:(ProceduralBlock)completion {
[self recursiveOpenURLs:URLs
inMode:tabOpeningTargetMode
currentIndex:0
totalCount:URLs.size()
completion:completion];
}
// Call |dismissModalsAndOpenSelectedTabInMode| recursively to open the list of
// URLs contained in |URLs|. Achieved through chaining
// |dismissModalsAndOpenSelectedTabInMode| in its completion handler.
- (void)recursiveOpenURLs:(const std::vector<GURL>&)URLs
inMode:(ApplicationModeForTabOpening)mode
currentIndex:(size_t)currentIndex
totalCount:(size_t)totalCount
completion:(ProceduralBlock)completion {
if (currentIndex >= totalCount) {
if (completion) {
completion();
}
return;
}
GURL webpageGURL = URLs.at(currentIndex);
__weak SceneController* weakSelf = self;
if (!webpageGURL.is_valid()) {
[self recursiveOpenURLs:URLs
inMode:mode
currentIndex:(currentIndex + 1)
totalCount:totalCount
completion:completion];
return;
}
UrlLoadParams param = UrlLoadParams::InNewTab(webpageGURL, webpageGURL);
std::vector<GURL> copyURLs = URLs;
[self dismissModalsAndOpenSelectedTabInMode:mode
withUrlLoadParams:param
dismissOmnibox:YES
completion:^{
[weakSelf
recursiveOpenURLs:copyURLs
inMode:mode
currentIndex:(currentIndex + 1)
totalCount:totalCount
completion:completion];
}];
}
// Opens a tab in the target BVC, and switches to it in a way that's appropriate
// to the current UI, based on the |dismissModals| flag:
// - If a modal dialog is showing and |dismissModals| is NO, the selected tab of
......@@ -1548,7 +1653,6 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
// Commands are only allowed on NTP.
DCHECK(IsURLNtp(urlLoadParams.web_params.url) || !startupCompletion);
ProceduralBlock tabOpenedCompletion = nil;
if (startupCompletion && completion) {
tabOpenedCompletion = ^{
......@@ -1697,7 +1801,6 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
->Load(newTabParams);
return;
}
// Otherwise, load |urlLoadParams| in the current tab.
UrlLoadParams sameTabParams = urlLoadParams;
sameTabParams.disposition = WindowOpenDisposition::CURRENT_TAB;
......@@ -1973,6 +2076,28 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
}
}
- (id<BrowserInterface>)extractInterfaceBaseOnMode:
(ApplicationModeForTabOpening)targetMode {
ApplicationMode applicationMode;
if (targetMode == ApplicationModeForTabOpening::CURRENT) {
applicationMode = self.interfaceProvider.currentInterface.incognito
? ApplicationMode::INCOGNITO
: ApplicationMode::NORMAL;
} else if (targetMode == ApplicationModeForTabOpening::NORMAL) {
applicationMode = ApplicationMode::NORMAL;
} else {
applicationMode = ApplicationMode::INCOGNITO;
}
id<BrowserInterface> targetInterface =
applicationMode == ApplicationMode::NORMAL
? self.interfaceProvider.mainInterface
: self.interfaceProvider.incognitoInterface;
return targetInterface;
}
#pragma mark - Handling of destroying the incognito BrowserState
// The incognito BrowserState should be closed when the last incognito tab is
......
......@@ -37,6 +37,14 @@ struct UrlLoadParams;
withUrlLoadParams:(const UrlLoadParams&)urlLoadParams
completion:(ProceduralBlock)completion;
// Open the list of URLs contained in |URLs| in mode specified by
// |tabOpeningTargetMode|. |completion| is executed after all the tabs are
// opened.
- (void)openMultipleTabsInMode:
(ApplicationModeForTabOpening)tabOpeningTargetMode
URLs:(const std::vector<GURL>&)URLs
completion:(ProceduralBlock)completion;
// Opens a new tab as if originating from |originPoint| and |focusOmnibox|.
- (void)openNewTabFromOriginPoint:(CGPoint)originPoint
focusOmnibox:(BOOL)focusOmnibox;
......
......@@ -9033,6 +9033,15 @@ should be able to be added at any place in this file.
<description>User opened a URL in Chrome via Apple Shortcuts.</description>
</action>
<action name="IOSLaunchedByOpenInIncognitoIntent">
<owner>gujen@chromium.org</owner>
<owner>rohitrao@chromium.org</owner>
<description>
User opened a URL/a list of URLs in Chrome in Incognito mode via Apple
Shortcuts.
</description>
</action>
<action name="IOSLaunchedBySearchInChromeIntent">
<owner>justincohen@chromium.org</owner>
<description>
......
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