Commit 3e726660 authored by Justin Cohen's avatar Justin Cohen Committed by Commit Bot

[ios] Adds a 'Search in Chrome' suggested siri shortcut.

Adds a suggested Siri shortcut 'Search in Chrome'.  As this is the
first Siri shortcut added, also adds some of the framework for
where to place the 'intentdefinition' file and localization.

SearchInChromeIntent.m/.h were generated natively within a sample
Xcode project.

Tbr: marq
No-try: true
Bug: 906693
Change-Id: Ib00b82d94af64ce0b2d8397b8cbd121d2b1345b2
Reviewed-on: https://chromium-review.googlesource.com/c/1351373
Commit-Queue: Justin Cohen <justincohen@chromium.org>
Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611071}
parent de54dcb3
...@@ -175,6 +175,7 @@ source_set("app_internal") { ...@@ -175,6 +175,7 @@ source_set("app_internal") {
"//components/web_resource", "//components/web_resource",
"//ios/chrome/app/application_delegate", "//ios/chrome/app/application_delegate",
"//ios/chrome/app/application_delegate:application_delegate_internal", "//ios/chrome/app/application_delegate:application_delegate_internal",
"//ios/chrome/app/intents",
"//ios/chrome/app/spotlight", "//ios/chrome/app/spotlight",
"//ios/chrome/app/startup", "//ios/chrome/app/startup",
"//ios/chrome/app/startup:startup_basic", "//ios/chrome/app/startup:startup_basic",
......
...@@ -135,6 +135,14 @@ NSString* const kShortcutQRScanner = @"OpenQRScanner"; ...@@ -135,6 +135,14 @@ NSString* const kShortcutQRScanner = @"OpenQRScanner";
}); });
return YES; return YES;
} }
} else if ([userActivity.activityType
isEqualToString:@"SearchInChromeIntent"]) {
base::RecordAction(UserMetricsAction("IOSLaunchedBySearchInChromeIntent"));
AppStartupParameters* startupParams = [[AppStartupParameters alloc]
initWithExternalURL:GURL(kChromeUINewTabURL)];
[startupParams setPostOpeningAction:FOCUS_OMNIBOX];
[startupInformation setStartupParameters:startupParams];
return YES;
} else { } else {
// Do nothing for unknown activity type. // Do nothing for unknown activity type.
return NO; return NO;
......
# Copyright 2018 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.
source_set("intents") {
sources = [
"SearchInChromeIntent.h",
"SearchInChromeIntent.m",
]
deps = [
":resources",
]
libs = [ "Intents.framework" ]
configs += [ "//build/config/compiler:enable_arc" ]
}
bundle_data("resources") {
sources = [
"Intents.intentdefinition",
]
outputs = [
"{{bundle_resources_dir}}/{{source_file_part}}",
]
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>INEnums</key>
<array/>
<key>INIntentDefinitionModelVersion</key>
<string>1.0</string>
<key>INIntentDefinitionSystemVersion</key>
<string>17G65</string>
<key>INIntentDefinitionToolsBuildVersion</key>
<string>10A254a</string>
<key>INIntentDefinitionToolsVersion</key>
<string>10.0</string>
<key>INIntents</key>
<array>
<dict>
<key>INIntentCategory</key>
<string>information</string>
<key>INIntentDescription</key>
<string></string>
<key>INIntentDescriptionID</key>
<string>k0Ho6W</string>
<key>INIntentLastParameterTag</key>
<integer>0</integer>
<key>INIntentName</key>
<string>SearchInChrome</string>
<key>INIntentParameterCombinations</key>
<dict>
<key></key>
<dict>
<key>INIntentParameterCombinationIsPrimary</key>
<true/>
<key>INIntentParameterCombinationSubtitle</key>
<string>SearchInChromeIntentDescription</string>
<key>INIntentParameterCombinationSubtitleID</key>
<string>4nGj7v</string>
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
<false/>
<key>INIntentParameterCombinationTitle</key>
<string>SearchInChromeIntentTitle</string>
<key>INIntentParameterCombinationTitleID</key>
<string>bGBl4a</string>
</dict>
</dict>
<key>INIntentParameters</key>
<array/>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeFormatString</key>
<string></string>
<key>INIntentResponseCodeFormatStringID</key>
<string>dXh5zv</string>
<key>INIntentResponseCodeName</key>
<string>failure</string>
<key>INIntentResponseCodeSuccess</key>
<false/>
</dict>
<dict>
<key>INIntentResponseCodeFormatString</key>
<string></string>
<key>INIntentResponseCodeFormatStringID</key>
<string>c0vj8g</string>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
</array>
<key>INIntentResponseLastParameterTag</key>
<integer>0</integer>
<key>INIntentResponseParameters</key>
<array/>
</dict>
<key>INIntentRestrictions</key>
<integer>0</integer>
<key>INIntentTitle</key>
<string>SearchInChromeIntentTitle</string>
<key>INIntentTitleID</key>
<string>Z6KvRw</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentUserConfirmationRequired</key>
<false/>
<key>INIntentVerb</key>
<string>Open</string>
</dict>
</array>
</dict>
</plist>
// Copyright 2018 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_APP_INTENTS_SEARCHINCHROMEINTENT_H_
#define IOS_CHROME_APP_INTENTS_SEARCHINCHROMEINTENT_H_
//
// SearchInChromeIntent.h
//
// This file was automatically generated and should not be edited.
//
#import <Intents/Intents.h>
NS_ASSUME_NONNULL_BEGIN
API_AVAILABLE(ios(12.0), watchos(5.0))
@interface SearchInChromeIntent : INIntent
@end
@class SearchInChromeIntentResponse;
/*!
@abstract Protocol to declare support for handling a SearchInChromeIntent. By
implementing this protocol, a class can provide logic for resolving, confirming
and handling the intent.
@discussion The minimum requirement for an implementing class is that it should
be able to handle the intent. The confirmation method is optional. The handling
method is always called last, after confirming the intent.
*/
API_AVAILABLE(ios(12.0), watchos(5.0))
@protocol SearchInChromeIntentHandling <NSObject>
@required
/*!
@abstract Handling method - Execute the task represented by the
SearchInChromeIntent that's passed in
@discussion Called to actually execute the intent. The app must return a
response for this intent.
@param intent The input intent
@param completion The response handling block takes a
SearchInChromeIntentResponse containing the details of the result of having
executed the intent
@see SearchInChromeIntentResponse
*/
- (void)handleSearchInChrome:(SearchInChromeIntent*)intent
completion:(void (^)(SearchInChromeIntentResponse* response))
completion
NS_SWIFT_NAME(handle(intent:completion:));
@optional
/*!
@abstract Confirmation method - Validate that this intent is ready for the next
step (i.e. handling)
@discussion Called prior to asking the app to handle the intent. The app should
return a response object that contains additional information about the intent,
which may be relevant for the system to show the user prior to handling. If
unimplemented, the system will assume the intent is valid, and will assume
there is no additional information relevant to this intent.
@param intent The input intent
@param completion The response block contains a SearchInChromeIntentResponse
containing additional details about the intent that may be relevant for the
system to show the user prior to handling.
@see SearchInChromeIntentResponse
*/
- (void)confirmSearchInChrome:(SearchInChromeIntent*)intent
completion:(void (^)(SearchInChromeIntentResponse* response))
completion
NS_SWIFT_NAME(confirm(intent:completion:));
@end
/*!
@abstract Constants indicating the state of the response.
*/
typedef NS_ENUM(NSInteger, SearchInChromeIntentResponseCode) {
SearchInChromeIntentResponseCodeUnspecified = 0,
SearchInChromeIntentResponseCodeReady,
SearchInChromeIntentResponseCodeContinueInApp,
SearchInChromeIntentResponseCodeInProgress,
SearchInChromeIntentResponseCodeSuccess,
SearchInChromeIntentResponseCodeFailure,
SearchInChromeIntentResponseCodeFailureRequiringAppLaunch,
} API_AVAILABLE(ios(12.0), watchos(5.0));
API_AVAILABLE(ios(12.0), watchos(5.0))
@interface SearchInChromeIntentResponse : INIntentResponse
- (instancetype)init NS_UNAVAILABLE;
/*!
@abstract Initializes the response object with the specified code and user
activity object.
@discussion The app extension has the option of capturing its private state as
an NSUserActivity and returning it as the 'currentActivity'. If the app is
launched, an NSUserActivity will be passed in with the private state. The
NSUserActivity may also be used to query the app's UI extension (if provided)
for a view controller representing the current intent handling state. In the
case of app launch, the NSUserActivity will have its activityType set to the
name of the intent. This intent object will also be available in the
NSUserActivity.interaction property.
@param code The response code indicating your success or failure in confirming
or handling the intent.
@param userActivity The user activity object to use when launching your app.
Provide an object if you want to add information that is specific to your app.
If you specify nil, the system automatically creates a user activity object for
you, sets its type to the class name of the intent being handled, and fills it
with an INInteraction object containing the intent and your response.
*/
- (instancetype)initWithCode:(SearchInChromeIntentResponseCode)code
userActivity:(nullable NSUserActivity*)userActivity
NS_DESIGNATED_INITIALIZER;
/*!
@abstract The response code indicating your success or failure in confirming or
handling the intent.
*/
@property(readonly, NS_NONATOMIC_IOSONLY) SearchInChromeIntentResponseCode code;
@end
NS_ASSUME_NONNULL_END
#endif // IOS_CHROME_APP_INTENTS_SEARCHINCHROMEINTENT_H_
// Copyright 2018 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.
//
// SearchInChromeIntent.m
//
// This file was automatically generated and should not be edited.
//
#import "SearchInChromeIntent.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@implementation SearchInChromeIntent
@end
@interface SearchInChromeIntentResponse ()
@property(readwrite, NS_NONATOMIC_IOSONLY)
SearchInChromeIntentResponseCode code;
@end
@implementation SearchInChromeIntentResponse
@synthesize code = _code;
- (instancetype)initWithCode:(SearchInChromeIntentResponseCode)code
userActivity:(nullable NSUserActivity*)userActivity {
self = [super init];
if (self) {
_code = code;
self.userActivity = userActivity;
}
return self;
}
@end
...@@ -1161,6 +1161,7 @@ enum class ShowTabSwitcherSnapshotResult { ...@@ -1161,6 +1161,7 @@ enum class ShowTabSwitcherSnapshotResult {
- (void)scheduleLowPriorityStartupTasks { - (void)scheduleLowPriorityStartupTasks {
[_startupTasks initializeOmaha]; [_startupTasks initializeOmaha];
[_startupTasks donateIntents];
[_startupTasks registerForApplicationWillResignActiveNotification]; [_startupTasks registerForApplicationWillResignActiveNotification];
[self registerForOrientationChangeNotifications]; [self registerForOrientationChangeNotifications];
......
...@@ -143,6 +143,7 @@ generate_localizable_strings("system_strings") { ...@@ -143,6 +143,7 @@ generate_localizable_strings("system_strings") {
output_filenames = [ output_filenames = [
"InfoPlist.strings", "InfoPlist.strings",
"Localizable.strings", "Localizable.strings",
"Intents.strings",
] ]
deps = [ deps = [
ios_packed_resources_target, ios_packed_resources_target,
......
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
<key>NSUserActivityTypes</key> <key>NSUserActivityTypes</key>
<array> <array>
<string>${CHROMIUM_HANDOFF_ID}</string> <string>${CHROMIUM_HANDOFF_ID}</string>
<string>SearchInChromeIntent</string>
</array> </array>
<key>UIBackgroundModes</key> <key>UIBackgroundModes</key>
<array> <array>
......
...@@ -23,6 +23,25 @@ ...@@ -23,6 +23,25 @@
<string>IDS_IOS_SAFE_MODE_AW_SNAP</string> <string>IDS_IOS_SAFE_MODE_AW_SNAP</string>
</array> </array>
</dict> </dict>
<dict>
<key>name</key>
<string>Intents.strings</string>
<key>strings</key>
<array>
<dict>
<key>input</key>
<string>IDS_IOS_INTENTS_SEARCH_IN_CHROME_DESCRIPTION</string>
<key>output</key>
<string>SearchInChromeIntentDescription</string>
</dict>
<dict>
<key>input</key>
<string>IDS_IOS_INTENTS_SEARCH_IN_CHROME_TITLE</string>
<key>output</key>
<string>SearchInChromeIntentTitle</string>
</dict>
</array>
</dict>
<dict> <dict>
<key>name</key> <key>name</key>
<string>InfoPlist.strings</string> <string>InfoPlist.strings</string>
......
...@@ -20,6 +20,8 @@ class ChromeBrowserState; ...@@ -20,6 +20,8 @@ class ChromeBrowserState;
(ios::ChromeBrowserState*)browserState; (ios::ChromeBrowserState*)browserState;
// Starts Omaha and, if first run, sets install time. For official builds only. // Starts Omaha and, if first run, sets install time. For official builds only.
- (void)initializeOmaha; - (void)initializeOmaha;
// Donate initial Intents.
- (void)donateIntents;
// Registers to receive UIApplicationWillResignActiveNotification. // Registers to receive UIApplicationWillResignActiveNotification.
- (void)registerForApplicationWillResignActiveNotification; - (void)registerForApplicationWillResignActiveNotification;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "components/bookmarks/browser/startup_task_runner_service.h" #include "components/bookmarks/browser/startup_task_runner_service.h"
#import "ios/chrome/app/deferred_initialization_runner.h" #import "ios/chrome/app/deferred_initialization_runner.h"
#include "ios/chrome/app/intents/SearchInChromeIntent.h"
#include "ios/chrome/app/tests_hook.h" #include "ios/chrome/app/tests_hook.h"
#include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/application_context.h"
#include "ios/chrome/browser/bookmarks/startup_task_runner_service_factory.h" #include "ios/chrome/browser/bookmarks/startup_task_runner_service_factory.h"
...@@ -19,7 +20,9 @@ ...@@ -19,7 +20,9 @@
#include "ios/chrome/browser/reading_list/reading_list_download_service_factory.h" #include "ios/chrome/browser/reading_list/reading_list_download_service_factory.h"
#import "ios/chrome/browser/ui/main/browser_view_information.h" #import "ios/chrome/browser/ui/main/browser_view_information.h"
#import "ios/chrome/browser/upgrade/upgrade_center.h" #import "ios/chrome/browser/upgrade/upgrade_center.h"
#include "ios/chrome/grit/ios_strings.h"
#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
#include "ui/base/l10n/l10n_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support." #error "This file requires ARC support."
...@@ -79,6 +82,20 @@ NSString* const kStartProfileStartupTaskRunners = ...@@ -79,6 +82,20 @@ NSString* const kStartProfileStartupTaskRunners =
object:nil]; object:nil];
} }
- (void)donateIntents {
if (@available(iOS 12.0, *)) {
SearchInChromeIntent* searchInChromeIntent =
[[SearchInChromeIntent alloc] init];
searchInChromeIntent.suggestedInvocationPhrase = l10n_util::GetNSString(
IDS_IOS_INTENTS_SEARCH_IN_CHROME_INVOCATION_PHRASE);
INInteraction* interaction =
[[INInteraction alloc] initWithIntent:searchInChromeIntent
response:nil];
[interaction donateInteractionWithCompletion:^(NSError* _Nullable error){
}];
}
}
#pragma mark - Private methods. #pragma mark - Private methods.
+ (void)performDeferredInitializationForBrowserState: + (void)performDeferredInitializationForBrowserState:
......
...@@ -804,6 +804,15 @@ locale. The strings in this file are specific to iOS. ...@@ -804,6 +804,15 @@ locale. The strings in this file are specific to iOS.
<message name="IDS_IOS_ICON_SEARCH" desc="Accessibility label for the search icon [iOS only]."> <message name="IDS_IOS_ICON_SEARCH" desc="Accessibility label for the search icon [iOS only].">
Search Search
</message> </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>
<message name="IDS_IOS_INTENTS_SEARCH_IN_CHROME_INVOCATION_PHRASE" desc="Siri Shortcut, spoken suggestion for search in chrome [iOS only].">
Search in Chrome
</message>
<message name="IDS_IOS_INTENTS_SEARCH_IN_CHROME_TITLE" desc="Siri Shortcut for search in chrome title [iOS only].">
Search in Chrome
</message>
<message name="IDS_IOS_JAVA_SCRIPT_DIALOG_BLOCKING_BUTTON_TEXT" desc="The text used for the button added to JavaScript dialogs to prevent a page from spamming the user with endless alerts. [Length:27em]"> <message name="IDS_IOS_JAVA_SCRIPT_DIALOG_BLOCKING_BUTTON_TEXT" desc="The text used for the button added to JavaScript dialogs to prevent a page from spamming the user with endless alerts. [Length:27em]">
Suppress Dialogs Suppress Dialogs
</message> </message>
......
ba1e7ecdef14de6a8ecb3b4e53b80a20f186335d
\ No newline at end of file
ba1e7ecdef14de6a8ecb3b4e53b80a20f186335d
\ No newline at end of file
ba1e7ecdef14de6a8ecb3b4e53b80a20f186335d
\ No newline at end of file
...@@ -7457,6 +7457,13 @@ should be able to be added at any place in this file. ...@@ -7457,6 +7457,13 @@ should be able to be added at any place in this file.
<description>Please enter the description of this user action.</description> <description>Please enter the description of this user action.</description>
</action> </action>
<action name="IOSLaunchedBySearchInChromeIntent">
<owner>justincohen@chromium.org</owner>
<description>
User opened Chrome with a `Search in Chrome` Siri Shortcut.
</description>
</action>
<action name="Italic"> <action name="Italic">
<owner>Please list the metric's owners. Add more owner tags as needed.</owner> <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
<description>Please enter the description of this user action.</description> <description>Please enter the description of this user action.</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