Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: ios/chrome/app/spotlight/bookmarks_spotlight_manager.mm

Issue 2580363002: Upstream Chrome on iOS source code [1/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "ios/chrome/app/spotlight/bookmarks_spotlight_manager.h"
6
7 #include <memory>
8
9 #import <CoreSpotlight/CoreSpotlight.h>
10
11 #include "base/ios/weak_nsobject.h"
12 #include "base/metrics/histogram.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "base/version.h"
15 #include "components/bookmarks/browser/base_bookmark_model_observer.h"
16 #include "components/bookmarks/browser/bookmark_model.h"
17 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
18 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
19
20 namespace {
21 // Limit the size of the initial indexing. This will not limit the size of the
22 // index as new bookmarks can be added afterwards.
23 const int kMaxInitialIndexSize = 1000;
24
25 // Minimum delay between two global indexing of bookmarks.
26 const int kDelayBetweenTwoIndexingInSeconds = 7 * 86400; // One week.
27
28 } // namespace
29
30 class SpotlightBookmarkModelBridge;
31
32 // Called from the BrowserBookmarkModelBridge from C++ -> ObjC.
33 @interface BookmarksSpotlightManager () {
34 base::WeakNSProtocol<id<BookmarkUpdatedDelegate>> _delegate;
35
36 // Bridge to register for bookmark changes.
37 std::unique_ptr<SpotlightBookmarkModelBridge> _bookmarkModelBridge;
38
39 // Keep a reference to detach before deallocing. Life cycle of _bookmarkModel
40 // is longer than life cycle of a SpotlightManager as
41 // |BookmarkModelBeingDeleted| will cause deletion of SpotlightManager.
42 bookmarks::BookmarkModel* _bookmarkModel; // weak
43
44 // Number of nodes indexed in initial scan.
45 NSUInteger _nodesIndexed;
46
47 // Tracks whether initial indexing has been done.
48 BOOL _initialIndexDone;
49 }
50
51 // Detaches the |SpotlightBookmarkModelBridge| from the bookmark model. The
52 // manager must not be used after calling this method.
53 - (void)detachBookmarkModel;
54
55 // Removes the node from the Spotlight index.
56 - (void)removeNodeFromIndex:(const bookmarks::BookmarkNode*)node;
57
58 // Clears all the bookmarks in the Spotlight index then index the bookmarks in
59 // the model.
60 - (void)clearAndReindexModel;
61
62 // Refreshes all nodes in the subtree of node.
63 // If |initial| is YES, limit the number of nodes to kMaxInitialIndexSize.
64 - (void)refreshNodeInIndex:(const bookmarks::BookmarkNode*)node
65 initial:(BOOL)initial;
66
67 // Returns true is the current index is too old or from an incompatible version.
68 - (BOOL)shouldReindex;
69
70 @end
71
72 // Handles notification that bookmarks has been removed changed so we can update
73 // the Spotlight index.
74 class SpotlightBookmarkModelBridge : public bookmarks::BookmarkModelObserver {
75 public:
76 explicit SpotlightBookmarkModelBridge(BookmarksSpotlightManager* owner)
77 : owner_(owner){};
78
79 ~SpotlightBookmarkModelBridge() override{};
80
81 void BookmarkNodeRemoved(bookmarks::BookmarkModel* model,
82 const bookmarks::BookmarkNode* parent,
83 int old_index,
84 const bookmarks::BookmarkNode* node,
85 const std::set<GURL>& removed_urls) override {}
86
87 void OnWillRemoveBookmarks(bookmarks::BookmarkModel* model,
88 const bookmarks::BookmarkNode* parent,
89 int old_index,
90 const bookmarks::BookmarkNode* node) override {
91 [owner_ removeNodeFromIndex:node];
92 }
93
94 void BookmarkModelBeingDeleted(bookmarks::BookmarkModel* model) override {
95 [owner_ detachBookmarkModel];
96 };
97
98 void BookmarkModelLoaded(bookmarks::BookmarkModel* model,
99 bool ids_reassigned) override {
100 [owner_ reindexBookmarksIfNeeded];
101 }
102
103 void BookmarkNodeAdded(bookmarks::BookmarkModel* model,
104 const bookmarks::BookmarkNode* parent,
105 int index) override {
106 [owner_ refreshNodeInIndex:parent->GetChild(index) initial:NO];
107 }
108
109 void OnWillChangeBookmarkNode(bookmarks::BookmarkModel* model,
110 const bookmarks::BookmarkNode* node) override {
111 [owner_ removeNodeFromIndex:node];
112 }
113
114 void BookmarkNodeChanged(bookmarks::BookmarkModel* model,
115 const bookmarks::BookmarkNode* node) override {
116 [owner_ refreshNodeInIndex:node initial:NO];
117 }
118
119 void BookmarkNodeFaviconChanged(
120 bookmarks::BookmarkModel* model,
121 const bookmarks::BookmarkNode* node) override {
122 [owner_ refreshNodeInIndex:node initial:NO];
123 }
124
125 void BookmarkAllUserNodesRemoved(
126 bookmarks::BookmarkModel* model,
127 const std::set<GURL>& removed_urls) override {
128 [owner_ clearAllSpotlightItems:nil];
129 }
130
131 void BookmarkNodeChildrenReordered(
132 bookmarks::BookmarkModel* model,
133 const bookmarks::BookmarkNode* node) override{};
134
135 void BookmarkNodeMoved(bookmarks::BookmarkModel* model,
136 const bookmarks::BookmarkNode* old_parent,
137 int old_index,
138 const bookmarks::BookmarkNode* new_parent,
139 int new_index) override {
140 [owner_ refreshNodeInIndex:new_parent->GetChild(new_index) initial:NO];
141 };
142
143 private:
144 __unsafe_unretained BookmarksSpotlightManager* owner_; // Weak.
145 };
146
147 @implementation BookmarksSpotlightManager
148
149 + (BookmarksSpotlightManager*)bookmarksSpotlightManagerWithBrowserState:
150 (ios::ChromeBrowserState*)browserState {
151 return [[[BookmarksSpotlightManager alloc]
152 initWithLargeIconService:IOSChromeLargeIconServiceFactory::
153 GetForBrowserState(browserState)
154 bookmarkModel:ios::BookmarkModelFactory::GetForBrowserState(
155 browserState)] autorelease];
156 }
157
158 - (instancetype)
159 initWithLargeIconService:(favicon::LargeIconService*)largeIconService
160 bookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel {
161 self = [super initWithLargeIconService:largeIconService
162 domain:spotlight::DOMAIN_BOOKMARKS];
163 if (self) {
164 _bookmarkModelBridge.reset(new SpotlightBookmarkModelBridge(self));
165 _bookmarkModel = bookmarkModel;
166 bookmarkModel->AddObserver(_bookmarkModelBridge.get());
167 }
168 return self;
169 }
170
171 - (void)dealloc {
172 [self detachBookmarkModel];
173 [super dealloc];
174 }
175
176 - (void)detachBookmarkModel {
177 [self cancelAllLargeIconPendingTasks];
178 if (_bookmarkModelBridge.get()) {
179 _bookmarkModel->RemoveObserver(_bookmarkModelBridge.get());
180 _bookmarkModelBridge.reset();
181 }
182 }
183
184 - (id<BookmarkUpdatedDelegate>)delegate {
185 return _delegate;
186 }
187
188 - (void)setDelegate:(id<BookmarkUpdatedDelegate>)delegate {
189 _delegate.reset(delegate);
190 }
191
192 - (void)getParentKeywordsForNode:(const bookmarks::BookmarkNode*)node
193 inArray:(NSMutableArray*)keywords {
194 if (!node) {
195 return;
196 }
197 if (node->is_folder() && !_bookmarkModel->is_permanent_node(node)) {
198 [keywords addObject:base::SysUTF16ToNSString(node->GetTitle())];
199 }
200 [self getParentKeywordsForNode:node->parent() inArray:keywords];
201 }
202
203 - (void)removeNodeFromIndex:(const bookmarks::BookmarkNode*)node {
204 if (node->is_url()) {
205 GURL url(node->url());
206 NSString* title = base::SysUTF16ToNSString(node->GetTitle());
207 NSString* spotlightID = [self spotlightIDForURL:url title:title];
208 base::WeakNSObject<BookmarksSpotlightManager> weakself(self);
209 BlockWithError completion = ^(NSError* error) {
210 dispatch_async(dispatch_get_main_queue(), ^{
211 [weakself refreshItemsWithURL:url title:nil];
212 [_delegate bookmarkUpdated];
213 });
214 };
215 spotlight::DeleteItemsWithIdentifiers(@[ spotlightID ], completion);
216 return;
217 }
218 int childCount = node->child_count();
219 for (int child = 0; child < childCount; child++) {
220 [self removeNodeFromIndex:node->GetChild(child)];
221 }
222 }
223
224 - (BOOL)shouldReindex {
225 NSDate* date = [[NSUserDefaults standardUserDefaults]
226 objectForKey:@(spotlight::kSpotlightLastIndexingDateKey)];
227 if (!date) {
228 return YES;
229 }
230 NSDate* expirationDate =
231 [date dateByAddingTimeInterval:kDelayBetweenTwoIndexingInSeconds];
232 if ([expirationDate compare:[NSDate date]] == NSOrderedAscending) {
233 return YES;
234 }
235 NSNumber* lastIndexedVersionString = [[NSUserDefaults standardUserDefaults]
236 objectForKey:@(spotlight::kSpotlightLastIndexingVersionKey)];
237 if (!lastIndexedVersionString) {
238 return YES;
239 }
240
241 if ([lastIndexedVersionString integerValue] <
242 spotlight::kCurrentSpotlightIndexVersion) {
243 return YES;
244 }
245 return NO;
246 }
247
248 - (void)reindexBookmarksIfNeeded {
249 if (!_bookmarkModel->loaded() || _initialIndexDone) {
250 return;
251 }
252 _initialIndexDone = YES;
253 if ([self shouldReindex]) {
254 [self clearAndReindexModel];
255 }
256 }
257
258 - (void)addKeywords:(NSArray*)keywords
259 toSearchableItem:(CSSearchableItem*)item {
260 NSSet* itemKeywords = [NSSet setWithArray:[[item attributeSet] keywords]];
261 itemKeywords = [itemKeywords setByAddingObjectsFromArray:keywords];
262 [[item attributeSet] setKeywords:[itemKeywords allObjects]];
263 }
264
265 - (void)refreshNodeInIndex:(const bookmarks::BookmarkNode*)node
266 initial:(BOOL)initial {
267 if (initial && _nodesIndexed > kMaxInitialIndexSize) {
268 return;
269 }
270 if (node->is_url()) {
271 _nodesIndexed++;
272 [self refreshItemsWithURL:node->url() title:nil];
273 if (!initial) {
274 [_delegate bookmarkUpdated];
275 }
276 return;
277 }
278 int childCount = node->child_count();
279 for (int child = 0; child < childCount; child++) {
280 [self refreshNodeInIndex:node->GetChild(child) initial:initial];
281 }
282 }
283
284 - (NSArray*)spotlightItemsWithURL:(const GURL&)URL
285 favicon:(UIImage*)favicon
286 defaultTitle:(NSString*)defaultTitle {
287 base::scoped_nsobject<NSMutableDictionary> spotlightItems(
288 [[NSMutableDictionary alloc] init]);
289 std::vector<const bookmarks::BookmarkNode*> nodes;
290 _bookmarkModel->GetNodesByURL(URL, &nodes);
291 for (auto node : nodes) {
292 NSString* nodeTitle = base::SysUTF16ToNSString(node->GetTitle());
293 NSString* spotlightID = [self spotlightIDForURL:URL title:nodeTitle];
294 CSSearchableItem* item = [spotlightItems objectForKey:spotlightID];
295 if (!item) {
296 item = [[super spotlightItemsWithURL:URL
297 favicon:favicon
298 defaultTitle:nodeTitle] objectAtIndex:0];
299 }
300 base::scoped_nsobject<NSMutableArray> nodeKeywords(
301 [[NSMutableArray alloc] init]);
302 [self getParentKeywordsForNode:node inArray:nodeKeywords.get()];
303 [self addKeywords:nodeKeywords toSearchableItem:item];
304 [spotlightItems setObject:item forKey:spotlightID];
305 }
306 return [spotlightItems allValues];
307 }
308
309 - (void)clearAndReindexModel {
310 [self cancelAllLargeIconPendingTasks];
311 base::WeakNSObject<BookmarksSpotlightManager> weakself(self);
312 BlockWithError completion = ^(NSError* error) {
313 if (!error) {
314 dispatch_async(dispatch_get_main_queue(), ^{
315 base::scoped_nsobject<BookmarksSpotlightManager> strongSelf(
316 [weakself retain]);
317 if (!strongSelf)
318 return;
319
320 NSDate* startOfReindexing = [NSDate date];
321 strongSelf.get()->_nodesIndexed = 0;
322 [strongSelf
323 refreshNodeInIndex:strongSelf.get()->_bookmarkModel->root_node()
324 initial:YES];
325 NSDate* endOfReindexing = [NSDate date];
326 NSTimeInterval indexingDuration =
327 [endOfReindexing timeIntervalSinceDate:startOfReindexing];
328 UMA_HISTOGRAM_TIMES(
329 "IOS.Spotlight.BookmarksIndexingDuration",
330 base::TimeDelta::FromMillisecondsD(1000 * indexingDuration));
331 UMA_HISTOGRAM_COUNTS_1000("IOS.Spotlight.BookmarksInitialIndexSize",
332 [strongSelf pendingLargeIconTasksCount]);
333 [[NSUserDefaults standardUserDefaults]
334 setObject:endOfReindexing
335 forKey:@(spotlight::kSpotlightLastIndexingDateKey)];
336
337 [[NSUserDefaults standardUserDefaults]
338 setObject:[NSNumber numberWithInteger:
339 spotlight::kCurrentSpotlightIndexVersion]
340 forKey:@(spotlight::kSpotlightLastIndexingVersionKey)];
341 [_delegate bookmarkUpdated];
342 });
343 }
344 };
345 [self clearAllSpotlightItems:completion];
346 }
347
348 @end
OLDNEW
« no previous file with comments | « ios/chrome/app/spotlight/bookmarks_spotlight_manager.h ('k') | ios/chrome/app/spotlight/spotlight_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698