OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ios/chrome/app/spotlight/actions_spotlight_manager.h" |
| 6 |
| 7 #import <CoreSpotlight/CoreSpotlight.h> |
| 8 |
| 9 #include "base/ios/weak_nsobject.h" |
| 10 #include "base/mac/foundation_util.h" |
| 11 #include "base/metrics/histogram.h" |
| 12 #include "base/strings/sys_string_conversions.h" |
| 13 #include "ios/chrome/browser/app_startup_parameters.h" |
| 14 #include "ios/chrome/browser/experimental_flags.h" |
| 15 #include "ios/chrome/common/app_group/app_group_constants.h" |
| 16 #include "ios/chrome/grit/ios_strings.h" |
| 17 #include "net/base/mac/url_conversions.h" |
| 18 #include "ui/base/l10n/l10n_util.h" |
| 19 #include "url/gurl.h" |
| 20 |
| 21 namespace { |
| 22 |
| 23 NSString* SpotlightActionFromString(NSString* query) { |
| 24 NSString* domain = |
| 25 [NSString stringWithFormat:@"%@.", spotlight::StringFromSpotlightDomain( |
| 26 spotlight::DOMAIN_ACTIONS)]; |
| 27 DCHECK([query hasPrefix:domain]); |
| 28 return |
| 29 [query substringWithRange:NSMakeRange([domain length], |
| 30 [query length] - [domain length])]; |
| 31 } |
| 32 |
| 33 } // namespace |
| 34 |
| 35 namespace spotlight { |
| 36 |
| 37 // Constants for Spotlight action links. |
| 38 const char kSpotlightActionNewTab[] = "OpenNewTab"; |
| 39 const char kSpotlightActionNewIncognitoTab[] = "OpenIncognitoTab"; |
| 40 const char kSpotlightActionVoiceSearch[] = "OpenVoiceSearch"; |
| 41 const char kSpotlightActionQRScanner[] = "OpenQRScanner"; |
| 42 |
| 43 // Enum is used to record the actions performed by the user. |
| 44 enum { |
| 45 // Recorded when a user pressed the New Tab spotlight action. |
| 46 SPOTLIGHT_ACTION_NEW_TAB_PRESSED, |
| 47 // Recorded when a user pressed the New Incognito Tab spotlight action. |
| 48 SPOTLIGHT_ACTION_NEW_INCOGNITO_TAB_PRESSED, |
| 49 // Recorded when a user pressed the Voice Search spotlight action. |
| 50 SPOTLIGHT_ACTION_VOICE_SEARCH_PRESSED, |
| 51 // Recorded when a user pressed the QR scanner spotlight action. |
| 52 SPOTLIGHT_ACTION_QR_CODE_SCANNER_PRESSED, |
| 53 // NOTE: Add new spotlight actions in sources only immediately above this |
| 54 // line. Also, make sure the enum list for histogram |SpotlightActions| in |
| 55 // histograms.xml is updated with any change in here. |
| 56 SPOTLIGHT_ACTION_COUNT |
| 57 }; |
| 58 |
| 59 // The histogram used to record user actions performed on the spotlight actions. |
| 60 const char kSpotlightActionsHistogram[] = "IOS.Spotlight.Action"; |
| 61 |
| 62 BOOL SetStartupParametersForSpotlightAction( |
| 63 NSString* query, |
| 64 AppStartupParameters* startupParams) { |
| 65 DCHECK(startupParams); |
| 66 NSString* action = SpotlightActionFromString(query); |
| 67 if ([action isEqualToString:base::SysUTF8ToNSString( |
| 68 kSpotlightActionNewIncognitoTab)]) { |
| 69 UMA_HISTOGRAM_ENUMERATION(kSpotlightActionsHistogram, |
| 70 SPOTLIGHT_ACTION_NEW_INCOGNITO_TAB_PRESSED, |
| 71 SPOTLIGHT_ACTION_COUNT); |
| 72 [startupParams setLaunchInIncognito:YES]; |
| 73 } else if ([action isEqualToString:base::SysUTF8ToNSString( |
| 74 kSpotlightActionVoiceSearch)]) { |
| 75 UMA_HISTOGRAM_ENUMERATION(kSpotlightActionsHistogram, |
| 76 SPOTLIGHT_ACTION_VOICE_SEARCH_PRESSED, |
| 77 SPOTLIGHT_ACTION_COUNT); |
| 78 [startupParams setLaunchVoiceSearch:YES]; |
| 79 } else if ([action isEqualToString:base::SysUTF8ToNSString( |
| 80 kSpotlightActionQRScanner)]) { |
| 81 UMA_HISTOGRAM_ENUMERATION(kSpotlightActionsHistogram, |
| 82 SPOTLIGHT_ACTION_QR_CODE_SCANNER_PRESSED, |
| 83 SPOTLIGHT_ACTION_COUNT); |
| 84 [startupParams setLaunchQRScanner:YES]; |
| 85 } else if ([action isEqualToString:base::SysUTF8ToNSString( |
| 86 kSpotlightActionNewTab)]) { |
| 87 UMA_HISTOGRAM_ENUMERATION(kSpotlightActionsHistogram, |
| 88 SPOTLIGHT_ACTION_NEW_TAB_PRESSED, |
| 89 SPOTLIGHT_ACTION_COUNT); |
| 90 } else { |
| 91 return NO; |
| 92 } |
| 93 return YES; |
| 94 } |
| 95 |
| 96 } // namespace spotlight |
| 97 |
| 98 @interface ActionsSpotlightManager () |
| 99 |
| 100 // Creates a new Spotlight entry with title |title| for the given |action|. |
| 101 - (CSSearchableItem*)getItemForAction:(NSString*)action title:(NSString*)title; |
| 102 |
| 103 // Clears and re-inserts all Spotlight actions. |
| 104 - (void)clearAndAddSpotlightActions; |
| 105 |
| 106 @end |
| 107 |
| 108 @implementation ActionsSpotlightManager |
| 109 |
| 110 + (ActionsSpotlightManager*)actionsSpotlightManager { |
| 111 return [[[ActionsSpotlightManager alloc] |
| 112 initWithLargeIconService:nil |
| 113 domain:spotlight::DOMAIN_ACTIONS] autorelease]; |
| 114 } |
| 115 |
| 116 #pragma mark public methods |
| 117 |
| 118 - (void)indexActions { |
| 119 base::WeakNSObject<ActionsSpotlightManager> weakSelf(self); |
| 120 dispatch_after( |
| 121 dispatch_time(DISPATCH_TIME_NOW, static_cast<int64_t>(1 * NSEC_PER_SEC)), |
| 122 dispatch_get_main_queue(), ^{ |
| 123 base::scoped_nsobject<ActionsSpotlightManager> strongSelf( |
| 124 [weakSelf retain]); |
| 125 [strongSelf clearAndAddSpotlightActions]; |
| 126 }); |
| 127 } |
| 128 |
| 129 #pragma mark private methods |
| 130 |
| 131 - (void)clearAndAddSpotlightActions { |
| 132 [self clearAllSpotlightItems:^(NSError* error) { |
| 133 if (!experimental_flags::IsSpotlightActionsEnabled()) { |
| 134 return; |
| 135 } |
| 136 base::WeakNSObject<ActionsSpotlightManager> weakSelf(self); |
| 137 dispatch_after( |
| 138 dispatch_time(DISPATCH_TIME_NOW, |
| 139 static_cast<int64_t>(1 * NSEC_PER_SEC)), |
| 140 dispatch_get_main_queue(), ^{ |
| 141 base::scoped_nsobject<ActionsSpotlightManager> strongSelf( |
| 142 [weakSelf retain]); |
| 143 |
| 144 if (!strongSelf) { |
| 145 return; |
| 146 } |
| 147 |
| 148 NSString* voiceSearchTitle = l10n_util::GetNSString( |
| 149 IDS_IOS_APPLICATION_SHORTCUT_VOICE_SEARCH_TITLE); |
| 150 NSString* voiceSearchAction = |
| 151 base::SysUTF8ToNSString(spotlight::kSpotlightActionVoiceSearch); |
| 152 |
| 153 NSString* newTabTitle = |
| 154 l10n_util::GetNSString(IDS_IOS_APPLICATION_SHORTCUT_NEWTAB_TITLE); |
| 155 NSString* newTabAction = |
| 156 base::SysUTF8ToNSString(spotlight::kSpotlightActionNewTab); |
| 157 |
| 158 NSString* incognitoTitle = l10n_util::GetNSString( |
| 159 IDS_IOS_APPLICATION_SHORTCUT_NEWINCOGNITOTAB_TITLE); |
| 160 NSString* incognitoAction = base::SysUTF8ToNSString( |
| 161 spotlight::kSpotlightActionNewIncognitoTab); |
| 162 |
| 163 NSMutableArray* spotlightItems = [NSMutableArray |
| 164 arrayWithObjects:[strongSelf getItemForAction:voiceSearchAction |
| 165 title:voiceSearchTitle], |
| 166 [strongSelf getItemForAction:newTabAction |
| 167 title:newTabTitle], |
| 168 [strongSelf getItemForAction:incognitoAction |
| 169 title:incognitoTitle], |
| 170 nil]; |
| 171 |
| 172 if (experimental_flags::IsQRCodeReaderEnabled()) { |
| 173 NSString* qrScannerTitle = l10n_util::GetNSString( |
| 174 IDS_IOS_APPLICATION_SHORTCUT_QR_SCANNER_TITLE); |
| 175 NSString* qrScannerAction = |
| 176 base::SysUTF8ToNSString(spotlight::kSpotlightActionQRScanner); |
| 177 |
| 178 [spotlightItems |
| 179 addObject:[strongSelf getItemForAction:qrScannerAction |
| 180 title:qrScannerTitle]]; |
| 181 } |
| 182 |
| 183 [[CSSearchableIndex defaultSearchableIndex] |
| 184 indexSearchableItems:spotlightItems |
| 185 completionHandler:nil]; |
| 186 }); |
| 187 }]; |
| 188 } |
| 189 |
| 190 - (CSSearchableItem*)getItemForAction:(NSString*)action title:(NSString*)title { |
| 191 base::scoped_nsobject<CSSearchableItemAttributeSet> attributeSet( |
| 192 [[CSSearchableItemAttributeSet alloc] |
| 193 initWithItemContentType:spotlight::StringFromSpotlightDomain( |
| 194 spotlight::DOMAIN_ACTIONS)]); |
| 195 [attributeSet setTitle:title]; |
| 196 [attributeSet setDisplayName:title]; |
| 197 |
| 198 NSString* domainID = |
| 199 spotlight::StringFromSpotlightDomain(spotlight::DOMAIN_ACTIONS); |
| 200 NSString* itemID = [NSString stringWithFormat:@"%@.%@", domainID, action]; |
| 201 |
| 202 return [self spotlightItemWithItemID:itemID attributeSet:attributeSet]; |
| 203 } |
| 204 |
| 205 @end |
OLD | NEW |