| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/chrome/app/spotlight/bookmarks_spotlight_manager.h" | 5 #import "ios/chrome/app/spotlight/bookmarks_spotlight_manager.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #import <CoreSpotlight/CoreSpotlight.h> | 9 #import <CoreSpotlight/CoreSpotlight.h> |
| 10 | 10 |
| 11 #include "base/ios/weak_nsobject.h" | |
| 12 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
| 13 #include "base/strings/sys_string_conversions.h" | 12 #include "base/strings/sys_string_conversions.h" |
| 14 #include "base/version.h" | 13 #include "base/version.h" |
| 15 #include "components/bookmarks/browser/base_bookmark_model_observer.h" | 14 #include "components/bookmarks/browser/base_bookmark_model_observer.h" |
| 16 #include "components/bookmarks/browser/bookmark_model.h" | 15 #include "components/bookmarks/browser/bookmark_model.h" |
| 17 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" | 16 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" |
| 18 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h" | 17 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h" |
| 19 | 18 |
| 19 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 20 #error "This file requires ARC support." |
| 21 #endif |
| 22 |
| 20 namespace { | 23 namespace { |
| 21 // Limit the size of the initial indexing. This will not limit the size of the | 24 // Limit the size of the initial indexing. This will not limit the size of the |
| 22 // index as new bookmarks can be added afterwards. | 25 // index as new bookmarks can be added afterwards. |
| 23 const int kMaxInitialIndexSize = 1000; | 26 const int kMaxInitialIndexSize = 1000; |
| 24 | 27 |
| 25 // Minimum delay between two global indexing of bookmarks. | 28 // Minimum delay between two global indexing of bookmarks. |
| 26 const int kDelayBetweenTwoIndexingInSeconds = 7 * 86400; // One week. | 29 const int kDelayBetweenTwoIndexingInSeconds = 7 * 86400; // One week. |
| 27 | 30 |
| 28 } // namespace | 31 } // namespace |
| 29 | 32 |
| 30 class SpotlightBookmarkModelBridge; | 33 class SpotlightBookmarkModelBridge; |
| 31 | 34 |
| 32 // Called from the BrowserBookmarkModelBridge from C++ -> ObjC. | 35 // Called from the BrowserBookmarkModelBridge from C++ -> ObjC. |
| 33 @interface BookmarksSpotlightManager () { | 36 @interface BookmarksSpotlightManager () { |
| 34 base::WeakNSProtocol<id<BookmarkUpdatedDelegate>> _delegate; | 37 __weak id<BookmarkUpdatedDelegate> _delegate; |
| 35 | 38 |
| 36 // Bridge to register for bookmark changes. | 39 // Bridge to register for bookmark changes. |
| 37 std::unique_ptr<SpotlightBookmarkModelBridge> _bookmarkModelBridge; | 40 std::unique_ptr<SpotlightBookmarkModelBridge> _bookmarkModelBridge; |
| 38 | 41 |
| 39 // Keep a reference to detach before deallocing. Life cycle of _bookmarkModel | 42 // Keep a reference to detach before deallocing. Life cycle of _bookmarkModel |
| 40 // is longer than life cycle of a SpotlightManager as | 43 // is longer than life cycle of a SpotlightManager as |
| 41 // |BookmarkModelBeingDeleted| will cause deletion of SpotlightManager. | 44 // |BookmarkModelBeingDeleted| will cause deletion of SpotlightManager. |
| 42 bookmarks::BookmarkModel* _bookmarkModel; // weak | 45 bookmarks::BookmarkModel* _bookmarkModel; // weak |
| 43 | 46 |
| 44 // Number of nodes indexed in initial scan. | 47 // Number of nodes indexed in initial scan. |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 | 137 |
| 135 void BookmarkNodeMoved(bookmarks::BookmarkModel* model, | 138 void BookmarkNodeMoved(bookmarks::BookmarkModel* model, |
| 136 const bookmarks::BookmarkNode* old_parent, | 139 const bookmarks::BookmarkNode* old_parent, |
| 137 int old_index, | 140 int old_index, |
| 138 const bookmarks::BookmarkNode* new_parent, | 141 const bookmarks::BookmarkNode* new_parent, |
| 139 int new_index) override { | 142 int new_index) override { |
| 140 [owner_ refreshNodeInIndex:new_parent->GetChild(new_index) initial:NO]; | 143 [owner_ refreshNodeInIndex:new_parent->GetChild(new_index) initial:NO]; |
| 141 }; | 144 }; |
| 142 | 145 |
| 143 private: | 146 private: |
| 144 __unsafe_unretained BookmarksSpotlightManager* owner_; // Weak. | 147 __weak BookmarksSpotlightManager* owner_; |
| 145 }; | 148 }; |
| 146 | 149 |
| 147 @implementation BookmarksSpotlightManager | 150 @implementation BookmarksSpotlightManager |
| 148 | 151 |
| 149 + (BookmarksSpotlightManager*)bookmarksSpotlightManagerWithBrowserState: | 152 + (BookmarksSpotlightManager*)bookmarksSpotlightManagerWithBrowserState: |
| 150 (ios::ChromeBrowserState*)browserState { | 153 (ios::ChromeBrowserState*)browserState { |
| 151 return [[[BookmarksSpotlightManager alloc] | 154 return [[BookmarksSpotlightManager alloc] |
| 152 initWithLargeIconService:IOSChromeLargeIconServiceFactory:: | 155 initWithLargeIconService:IOSChromeLargeIconServiceFactory:: |
| 153 GetForBrowserState(browserState) | 156 GetForBrowserState(browserState) |
| 154 bookmarkModel:ios::BookmarkModelFactory::GetForBrowserState( | 157 bookmarkModel:ios::BookmarkModelFactory::GetForBrowserState( |
| 155 browserState)] autorelease]; | 158 browserState)]; |
| 156 } | 159 } |
| 157 | 160 |
| 158 - (instancetype) | 161 - (instancetype) |
| 159 initWithLargeIconService:(favicon::LargeIconService*)largeIconService | 162 initWithLargeIconService:(favicon::LargeIconService*)largeIconService |
| 160 bookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel { | 163 bookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel { |
| 161 self = [super initWithLargeIconService:largeIconService | 164 self = [super initWithLargeIconService:largeIconService |
| 162 domain:spotlight::DOMAIN_BOOKMARKS]; | 165 domain:spotlight::DOMAIN_BOOKMARKS]; |
| 163 if (self) { | 166 if (self) { |
| 164 _bookmarkModelBridge.reset(new SpotlightBookmarkModelBridge(self)); | 167 _bookmarkModelBridge.reset(new SpotlightBookmarkModelBridge(self)); |
| 165 _bookmarkModel = bookmarkModel; | 168 _bookmarkModel = bookmarkModel; |
| 166 bookmarkModel->AddObserver(_bookmarkModelBridge.get()); | 169 bookmarkModel->AddObserver(_bookmarkModelBridge.get()); |
| 167 } | 170 } |
| 168 return self; | 171 return self; |
| 169 } | 172 } |
| 170 | 173 |
| 171 - (void)dealloc { | 174 - (void)dealloc { |
| 172 [self detachBookmarkModel]; | 175 [self detachBookmarkModel]; |
| 173 [super dealloc]; | |
| 174 } | 176 } |
| 175 | 177 |
| 176 - (void)detachBookmarkModel { | 178 - (void)detachBookmarkModel { |
| 177 [self cancelAllLargeIconPendingTasks]; | 179 [self cancelAllLargeIconPendingTasks]; |
| 178 if (_bookmarkModelBridge.get()) { | 180 if (_bookmarkModelBridge.get()) { |
| 179 _bookmarkModel->RemoveObserver(_bookmarkModelBridge.get()); | 181 _bookmarkModel->RemoveObserver(_bookmarkModelBridge.get()); |
| 180 _bookmarkModelBridge.reset(); | 182 _bookmarkModelBridge.reset(); |
| 181 } | 183 } |
| 182 } | 184 } |
| 183 | 185 |
| 184 - (id<BookmarkUpdatedDelegate>)delegate { | 186 - (id<BookmarkUpdatedDelegate>)delegate { |
| 185 return _delegate; | 187 return _delegate; |
| 186 } | 188 } |
| 187 | 189 |
| 188 - (void)setDelegate:(id<BookmarkUpdatedDelegate>)delegate { | 190 - (void)setDelegate:(id<BookmarkUpdatedDelegate>)delegate { |
| 189 _delegate.reset(delegate); | 191 _delegate = delegate; |
| 190 } | 192 } |
| 191 | 193 |
| 192 - (void)getParentKeywordsForNode:(const bookmarks::BookmarkNode*)node | 194 - (void)getParentKeywordsForNode:(const bookmarks::BookmarkNode*)node |
| 193 inArray:(NSMutableArray*)keywords { | 195 inArray:(NSMutableArray*)keywords { |
| 194 if (!node) { | 196 if (!node) { |
| 195 return; | 197 return; |
| 196 } | 198 } |
| 197 if (node->is_folder() && !_bookmarkModel->is_permanent_node(node)) { | 199 if (node->is_folder() && !_bookmarkModel->is_permanent_node(node)) { |
| 198 [keywords addObject:base::SysUTF16ToNSString(node->GetTitle())]; | 200 [keywords addObject:base::SysUTF16ToNSString(node->GetTitle())]; |
| 199 } | 201 } |
| 200 [self getParentKeywordsForNode:node->parent() inArray:keywords]; | 202 [self getParentKeywordsForNode:node->parent() inArray:keywords]; |
| 201 } | 203 } |
| 202 | 204 |
| 203 - (void)removeNodeFromIndex:(const bookmarks::BookmarkNode*)node { | 205 - (void)removeNodeFromIndex:(const bookmarks::BookmarkNode*)node { |
| 204 if (node->is_url()) { | 206 if (node->is_url()) { |
| 205 GURL url(node->url()); | 207 GURL url(node->url()); |
| 206 NSString* title = base::SysUTF16ToNSString(node->GetTitle()); | 208 NSString* title = base::SysUTF16ToNSString(node->GetTitle()); |
| 207 NSString* spotlightID = [self spotlightIDForURL:url title:title]; | 209 NSString* spotlightID = [self spotlightIDForURL:url title:title]; |
| 208 base::WeakNSObject<BookmarksSpotlightManager> weakself(self); | 210 __weak BookmarksSpotlightManager* weakself = self; |
| 209 BlockWithError completion = ^(NSError* error) { | 211 BlockWithError completion = ^(NSError* error) { |
| 210 dispatch_async(dispatch_get_main_queue(), ^{ | 212 dispatch_async(dispatch_get_main_queue(), ^{ |
| 211 [weakself refreshItemsWithURL:url title:nil]; | 213 [weakself refreshItemsWithURL:url title:nil]; |
| 212 [_delegate bookmarkUpdated]; | 214 [_delegate bookmarkUpdated]; |
| 213 }); | 215 }); |
| 214 }; | 216 }; |
| 215 spotlight::DeleteItemsWithIdentifiers(@[ spotlightID ], completion); | 217 spotlight::DeleteItemsWithIdentifiers(@[ spotlightID ], completion); |
| 216 return; | 218 return; |
| 217 } | 219 } |
| 218 int childCount = node->child_count(); | 220 int childCount = node->child_count(); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 } | 279 } |
| 278 int childCount = node->child_count(); | 280 int childCount = node->child_count(); |
| 279 for (int child = 0; child < childCount; child++) { | 281 for (int child = 0; child < childCount; child++) { |
| 280 [self refreshNodeInIndex:node->GetChild(child) initial:initial]; | 282 [self refreshNodeInIndex:node->GetChild(child) initial:initial]; |
| 281 } | 283 } |
| 282 } | 284 } |
| 283 | 285 |
| 284 - (NSArray*)spotlightItemsWithURL:(const GURL&)URL | 286 - (NSArray*)spotlightItemsWithURL:(const GURL&)URL |
| 285 favicon:(UIImage*)favicon | 287 favicon:(UIImage*)favicon |
| 286 defaultTitle:(NSString*)defaultTitle { | 288 defaultTitle:(NSString*)defaultTitle { |
| 287 base::scoped_nsobject<NSMutableDictionary> spotlightItems( | 289 NSMutableDictionary* spotlightItems = [[NSMutableDictionary alloc] init]; |
| 288 [[NSMutableDictionary alloc] init]); | |
| 289 std::vector<const bookmarks::BookmarkNode*> nodes; | 290 std::vector<const bookmarks::BookmarkNode*> nodes; |
| 290 _bookmarkModel->GetNodesByURL(URL, &nodes); | 291 _bookmarkModel->GetNodesByURL(URL, &nodes); |
| 291 for (auto node : nodes) { | 292 for (auto node : nodes) { |
| 292 NSString* nodeTitle = base::SysUTF16ToNSString(node->GetTitle()); | 293 NSString* nodeTitle = base::SysUTF16ToNSString(node->GetTitle()); |
| 293 NSString* spotlightID = [self spotlightIDForURL:URL title:nodeTitle]; | 294 NSString* spotlightID = [self spotlightIDForURL:URL title:nodeTitle]; |
| 294 CSSearchableItem* item = [spotlightItems objectForKey:spotlightID]; | 295 CSSearchableItem* item = [spotlightItems objectForKey:spotlightID]; |
| 295 if (!item) { | 296 if (!item) { |
| 296 item = [[super spotlightItemsWithURL:URL | 297 item = [[super spotlightItemsWithURL:URL |
| 297 favicon:favicon | 298 favicon:favicon |
| 298 defaultTitle:nodeTitle] objectAtIndex:0]; | 299 defaultTitle:nodeTitle] objectAtIndex:0]; |
| 299 } | 300 } |
| 300 base::scoped_nsobject<NSMutableArray> nodeKeywords( | 301 NSMutableArray* nodeKeywords = [[NSMutableArray alloc] init]; |
| 301 [[NSMutableArray alloc] init]); | 302 [self getParentKeywordsForNode:node inArray:nodeKeywords]; |
| 302 [self getParentKeywordsForNode:node inArray:nodeKeywords.get()]; | |
| 303 [self addKeywords:nodeKeywords toSearchableItem:item]; | 303 [self addKeywords:nodeKeywords toSearchableItem:item]; |
| 304 [spotlightItems setObject:item forKey:spotlightID]; | 304 [spotlightItems setObject:item forKey:spotlightID]; |
| 305 } | 305 } |
| 306 return [spotlightItems allValues]; | 306 return [spotlightItems allValues]; |
| 307 } | 307 } |
| 308 | 308 |
| 309 - (void)clearAndReindexModel { | 309 - (void)clearAndReindexModel { |
| 310 [self cancelAllLargeIconPendingTasks]; | 310 [self cancelAllLargeIconPendingTasks]; |
| 311 base::WeakNSObject<BookmarksSpotlightManager> weakself(self); | 311 __weak BookmarksSpotlightManager* weakself = self; |
| 312 BlockWithError completion = ^(NSError* error) { | 312 BlockWithError completion = ^(NSError* error) { |
| 313 if (!error) { | 313 if (!error) { |
| 314 dispatch_async(dispatch_get_main_queue(), ^{ | 314 dispatch_async(dispatch_get_main_queue(), ^{ |
| 315 base::scoped_nsobject<BookmarksSpotlightManager> strongSelf( | 315 BookmarksSpotlightManager* strongSelf = weakself; |
| 316 [weakself retain]); | |
| 317 if (!strongSelf) | 316 if (!strongSelf) |
| 318 return; | 317 return; |
| 319 | 318 |
| 320 NSDate* startOfReindexing = [NSDate date]; | 319 NSDate* startOfReindexing = [NSDate date]; |
| 321 strongSelf.get()->_nodesIndexed = 0; | 320 strongSelf->_nodesIndexed = 0; |
| 322 [strongSelf | 321 [strongSelf refreshNodeInIndex:strongSelf->_bookmarkModel->root_node() |
| 323 refreshNodeInIndex:strongSelf.get()->_bookmarkModel->root_node() | 322 initial:YES]; |
| 324 initial:YES]; | |
| 325 NSDate* endOfReindexing = [NSDate date]; | 323 NSDate* endOfReindexing = [NSDate date]; |
| 326 NSTimeInterval indexingDuration = | 324 NSTimeInterval indexingDuration = |
| 327 [endOfReindexing timeIntervalSinceDate:startOfReindexing]; | 325 [endOfReindexing timeIntervalSinceDate:startOfReindexing]; |
| 328 UMA_HISTOGRAM_TIMES( | 326 UMA_HISTOGRAM_TIMES( |
| 329 "IOS.Spotlight.BookmarksIndexingDuration", | 327 "IOS.Spotlight.BookmarksIndexingDuration", |
| 330 base::TimeDelta::FromMillisecondsD(1000 * indexingDuration)); | 328 base::TimeDelta::FromMillisecondsD(1000 * indexingDuration)); |
| 331 UMA_HISTOGRAM_COUNTS_1000("IOS.Spotlight.BookmarksInitialIndexSize", | 329 UMA_HISTOGRAM_COUNTS_1000("IOS.Spotlight.BookmarksInitialIndexSize", |
| 332 [strongSelf pendingLargeIconTasksCount]); | 330 [strongSelf pendingLargeIconTasksCount]); |
| 333 [[NSUserDefaults standardUserDefaults] | 331 [[NSUserDefaults standardUserDefaults] |
| 334 setObject:endOfReindexing | 332 setObject:endOfReindexing |
| 335 forKey:@(spotlight::kSpotlightLastIndexingDateKey)]; | 333 forKey:@(spotlight::kSpotlightLastIndexingDateKey)]; |
| 336 | 334 |
| 337 [[NSUserDefaults standardUserDefaults] | 335 [[NSUserDefaults standardUserDefaults] |
| 338 setObject:[NSNumber numberWithInteger: | 336 setObject:[NSNumber numberWithInteger: |
| 339 spotlight::kCurrentSpotlightIndexVersion] | 337 spotlight::kCurrentSpotlightIndexVersion] |
| 340 forKey:@(spotlight::kSpotlightLastIndexingVersionKey)]; | 338 forKey:@(spotlight::kSpotlightLastIndexingVersionKey)]; |
| 341 [_delegate bookmarkUpdated]; | 339 [_delegate bookmarkUpdated]; |
| 342 }); | 340 }); |
| 343 } | 341 } |
| 344 }; | 342 }; |
| 345 [self clearAllSpotlightItems:completion]; | 343 [self clearAllSpotlightItems:completion]; |
| 346 } | 344 } |
| 347 | 345 |
| 348 @end | 346 @end |
| OLD | NEW |