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

Side by Side Diff: chrome/browser/android/chrome_browser_provider.cc

Issue 10912172: [Android] Upstream ChromeBrowserProvider, the Android port ContentProvider implementation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 months 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 #include "chrome/browser/android/chrome_browser_provider.h"
6
7 #include <list>
8 #include <utility>
9
10 #include "base/android/jni_android.h"
11 #include "base/android/jni_array.h"
12 #include "base/android/jni_string.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted_memory.h"
15 #include "base/time.h"
16 #include "base/utf_string_conversions.h"
17 #include "chrome/browser/android/blocking_ui_thread_async_request.h"
18 #include "chrome/browser/android/bookmark_model_observer_task.h"
19 #include "chrome/browser/android/run_on_ui_thread_blocking.h"
20 #include "chrome/browser/bookmarks/bookmark_model.h"
21 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/favicon/favicon_service.h"
24 #include "chrome/browser/favicon/favicon_service_factory.h"
25 #include "chrome/browser/history/android/android_history_types.h"
26 #include "chrome/browser/history/android/sqlite_cursor.h"
27 #include "chrome/browser/history/top_sites.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/profiles/profile_manager.h"
30 #include "chrome/browser/search_engines/template_url.h"
31 #include "chrome/browser/search_engines/template_url_service.h"
32 #include "chrome/browser/search_engines/template_url_service_factory.h"
33 #include "chrome/common/chrome_notification_types.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/notification_service.h"
36 #include "grit/generated_resources.h"
37 #include "jni/ChromeBrowserProvider_jni.h"
38 #include "sql/statement.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/base/layout.h"
41 #include "ui/gfx/favicon_size.h"
42
43 using base::android::AttachCurrentThread;
44 using base::android::CheckException;
45 using base::android::ClearException;
46 using base::android::ConvertJavaStringToUTF16;
47 using base::android::ConvertJavaStringToUTF8;
48 using base::android::ConvertUTF8ToJavaString;
49 using base::android::ConvertUTF16ToJavaString;
50 using base::android::GetClass;
51 using base::android::GetMethodID;
52 using base::android::JavaRef;
53 using base::android::ScopedJavaGlobalRef;
54 using base::android::ScopedJavaLocalRef;
55 using content::BrowserThread;
56
57 // After refactoring the following class hierarchy has been created in order
58 // to avoid repeating code again for the same basic kind of tasks, to enforce
59 // the correct thread usage and to prevent known race conditions and deadlocks.
60 //
61 // - RunOnUIThreadBlocking: auxiliary class to run methods in the UI thread
62 // blocking the current one until finished. Because of the provider threading
63 // expectations this cannot be used from the UI thread.
64 //
65 // - BookmarkModelTask: base class for all tasks that operate in any way with
66 // the bookmark model. This class ensures that the model is loaded and
67 // prevents possible deadlocks. Derived classes should make use of
68 // RunOnUIThreadBlocking to perform any manipulation of the bookmark model in
69 // the UI thread. The Run method of these tasks cannot be invoked directly
70 // from the UI thread, but RunOnUIThread can be safely used from the UI
71 // thread code of other BookmarkModelTasks.
72 //
73 // - AsyncServiceRequest: base class for any asynchronous requests made to a
74 // Chromium service that require to block the current thread until completed.
75 // Derived classes should make use of RunAsyncRequestOnUIThreadBlocking to
76 // post their requests in the UI thread and return the results synchronously.
77 // All derived classes MUST ALWAYS call RequestCompleted when receiving the
78 // request response. These tasks cannot be invoked from the UI thread.
79 //
80 // - FaviconServiceTask: base class for asynchronous requests that make use of
81 // Chromium's favicon service. See AsyncServiceRequest for more details.
82 //
83 // - HistoryProviderTask: base class for asynchronous requests that make use of
84 // AndroidHistoryProviderService. See AsyncServiceRequest for mode details.
85 //
86 // - SearchTermTask: base class for asynchronous requests that involve the
87 // search term API. Works in the same way as HistoryProviderTask.
88
89 namespace {
90
91 const char kClassPathName[] =
92 "org/chromium/chrome/browser/ChromeBrowserProvider";
93 const char kDefaultUrlScheme[] = "http://";
94 const int64 kInvalidContentProviderId = 0;
95 const int64 kInvalidBookmarkId = -1;
96
97 // ------------- Java-related utility methods ------------- //
98
99 // Convert a BookmarkNode, |node|, to the java representation of a bookmark node
100 // stored in |*jnode|. Parent node information is optional.
101 void ConvertBookmarkNode(
102 const BookmarkNode* node,
103 const JavaRef<jobject>& parent_node,
104 ScopedJavaGlobalRef<jobject>* jnode) {
105 DCHECK(jnode);
106 if (!node)
107 return;
108
109 JNIEnv* env = AttachCurrentThread();
110 ScopedJavaLocalRef<jstring> url;
111 if (node->is_url())
112 url.Reset(ConvertUTF8ToJavaString(env, node->url().spec()));
113 ScopedJavaLocalRef<jstring> title(
114 ConvertUTF16ToJavaString(env, node->GetTitle()));
115
116 jnode->Reset(
117 Java_BookmarkNode_create(
118 env, node->id(), (jint) node->type(), title.obj(), url.obj(),
119 parent_node.obj()));
120 }
121
122 jlong ConvertJLongObjectToPrimitive(JNIEnv* env, jobject long_obj) {
123 ScopedJavaLocalRef<jclass> jlong_clazz = GetClass(env, "java/lang/Long");
124 jmethodID long_value = GetMethodID(env, jlong_clazz, "longValue", "()J");
125 return env->CallLongMethod(long_obj, long_value, NULL);
126 }
127
128 jboolean ConvertJBooleanObjectToPrimitive(JNIEnv* env, jobject boolean_object) {
129 ScopedJavaLocalRef<jclass> jboolean_clazz =
130 GetClass(env, "java/lang/Boolean");
131 jmethodID boolean_value =
132 GetMethodID(env, jboolean_clazz, "booleanValue", "()Z");
133 return env->CallBooleanMethod(boolean_object, boolean_value, NULL);
134 }
135
136 base::Time ConvertJlongToTime(jlong value) {
137 return base::Time::UnixEpoch() +
138 base::TimeDelta::FromMilliseconds((int64)value);
139 }
140
141 jint ConvertJIntegerToJint(JNIEnv* env, jobject integer_obj) {
142 ScopedJavaLocalRef<jclass> jinteger_clazz =
143 GetClass(env, "java/lang/Integer");
144 jmethodID int_value = GetMethodID(env, jinteger_clazz, "intValue", "()I");
145 return env->CallIntMethod(integer_obj, int_value, NULL);
146 }
147
148 std::vector<string16> ConvertJStringArrayToString16Array(JNIEnv* env,
149 jobjectArray array) {
150 std::vector<string16> results;
151 if (array) {
152 jsize len = env->GetArrayLength(array);
153 for (int i = 0; i < len; i++) {
154 results.push_back(ConvertJavaStringToUTF16(env,
155 static_cast<jstring>(env->GetObjectArrayElement(array, i))));
156 }
157 }
158 return results;
159 }
160
161 // ------------- Utility methods used by tasks ------------- //
162
163 // Parse the given url and return a GURL, appending the default scheme
164 // if one is not present.
165 GURL ParseAndMaybeAppendScheme(const string16& url,
166 const char* default_scheme) {
167 GURL gurl(url);
168 if (!gurl.is_valid() && !gurl.has_scheme()) {
169 string16 refined_url(ASCIIToUTF16(default_scheme));
170 refined_url.append(url);
171 gurl = GURL(refined_url);
172 }
173 return gurl;
174 }
175
176 const BookmarkNode* GetChildFolderByTitle(const BookmarkNode* parent,
177 const string16& title) {
178 for (int i = 0; i < parent->child_count(); ++i) {
179 if (parent->GetChild(i)->is_folder() &&
180 parent->GetChild(i)->GetTitle() == title) {
181 return parent->GetChild(i);
182 }
183 }
184 return NULL;
185 }
186
187 // ------------- Synchronous task classes ------------- //
188
189 // Utility task to add a bookmark.
190 class AddBookmarkTask : public BookmarkModelTask {
191 public:
192 explicit AddBookmarkTask(BookmarkModel* model) : BookmarkModelTask(model) {}
193
194 int64 Run(const string16& title,
195 const string16& url,
196 const bool is_folder,
197 const int64 parent_id) {
198 int64 result = kInvalidBookmarkId;
199 RunOnUIThreadBlocking::Run(
200 base::Bind(&AddBookmarkTask::RunOnUIThread,
201 model(), title, url, is_folder, parent_id, &result));
202 return result;
203 }
204
205 static void RunOnUIThread(BookmarkModel* model,
206 const string16& title,
207 const string16& url,
208 const bool is_folder,
209 const int64 parent_id,
210 int64* result) {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
212 DCHECK(result);
213 GURL gurl = ParseAndMaybeAppendScheme(url, kDefaultUrlScheme);
214
215 // Check if the bookmark already exists.
216 const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(gurl);
217 if (!node) {
218 const BookmarkNode* parent_node = NULL;
219 if (parent_id >= 0)
220 parent_node = model->GetNodeByID(parent_id);
221 if (!parent_node)
222 parent_node = model->bookmark_bar_node();
223
224 if (is_folder)
225 node = model->AddFolder(parent_node, parent_node->child_count(), title);
226 else
227 node = model->AddURL(parent_node, 0, title, gurl);
228 }
229
230 *result = node ? node ->id() : kInvalidBookmarkId;
231 }
232
233 private:
234 DISALLOW_COPY_AND_ASSIGN(AddBookmarkTask);
235 };
236
237 // Utility method to remove a bookmark.
238 class RemoveBookmarkTask : public BookmarkModelObserverTask {
239 public:
240 explicit RemoveBookmarkTask(BookmarkModel* model)
241 : BookmarkModelObserverTask(model),
242 deleted_(0),
243 id_to_delete_(kInvalidBookmarkId) {}
244 virtual ~RemoveBookmarkTask() {}
245
246 int Run(const int64 id) {
247 id_to_delete_ = id;
248 RunOnUIThreadBlocking::Run(
249 base::Bind(&RemoveBookmarkTask::RunOnUIThread, model(), id));
250 return deleted_;
251 }
252
253 static void RunOnUIThread(BookmarkModel* model, const int64 id) {
254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
255 const BookmarkNode* node = model->GetNodeByID(id);
256 if (node && node->parent()) {
257 const BookmarkNode* parent_node = node->parent();
258 model->Remove(parent_node, parent_node->GetIndexOf(node));
259 }
260 }
261
262 // Verify that the bookmark was actually removed. Called synchronously.
263 virtual void BookmarkNodeRemoved(BookmarkModel* bookmark_model,
264 const BookmarkNode* parent,
265 int old_index,
266 const BookmarkNode* node) OVERRIDE {
267 if (bookmark_model == model() && node->id() == id_to_delete_)
268 ++deleted_;
269 }
270
271 private:
272 int deleted_;
273 int64 id_to_delete_;
274
275 DISALLOW_COPY_AND_ASSIGN(RemoveBookmarkTask);
276 };
277
278 // Utility method to update a bookmark.
279 class UpdateBookmarkTask : public BookmarkModelObserverTask {
280 public:
281 explicit UpdateBookmarkTask(BookmarkModel* model)
282 : BookmarkModelObserverTask(model),
283 updated_(0),
284 id_to_update_(kInvalidBookmarkId){}
285 virtual ~UpdateBookmarkTask() {}
286
287 int Run(const int64 id,
288 const string16& title,
289 const string16& url,
290 const int64 parent_id) {
291 id_to_update_ = id;
292 RunOnUIThreadBlocking::Run(
293 base::Bind(&UpdateBookmarkTask::RunOnUIThread,
294 model(), id, title, url, parent_id));
295 return updated_;
296 }
297
298 static void RunOnUIThread(BookmarkModel* model,
299 const int64 id,
300 const string16& title,
301 const string16& url,
302 const int64 parent_id) {
303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
304 const BookmarkNode* node = model->GetNodeByID(id);
305 if (node) {
306 if (node->GetTitle() != title)
307 model->SetTitle(node, title);
308
309 if (node->type() == BookmarkNode::URL) {
310 GURL bookmark_url = ParseAndMaybeAppendScheme(url, kDefaultUrlScheme);
311 if (bookmark_url != node->url())
312 model->SetURL(node, bookmark_url);
313 }
314
315 if (parent_id >= 0 &&
316 (!node->parent() || parent_id != node->parent()->id())) {
317 const BookmarkNode* new_parent = model->GetNodeByID(parent_id);
318
319 if (new_parent)
320 model->Move(node, new_parent, 0);
321 }
322 }
323 }
324
325 // Verify that the bookmark was actually updated. Called synchronously.
326 virtual void BookmarkNodeChanged(BookmarkModel* bookmark_model,
327 const BookmarkNode* node) OVERRIDE {
328 if (bookmark_model == model() && node->id() == id_to_update_)
329 ++updated_;
330 }
331
332 private:
333 int updated_;
334 int64 id_to_update_;
335
336 DISALLOW_COPY_AND_ASSIGN(UpdateBookmarkTask);
337 };
338
339 // Checks if a node exists in the bookmark model.
340 class BookmarkNodeExistsTask : public BookmarkModelTask {
341 public:
342 explicit BookmarkNodeExistsTask(BookmarkModel* model)
343 : BookmarkModelTask(model) {
344 }
345
346 bool Run(const int64 id) {
347 bool result = false;
348 RunOnUIThreadBlocking::Run(
349 base::Bind(&BookmarkNodeExistsTask::RunOnUIThread,
350 model(), id, &result));
351 return result;
352 }
353
354 static void RunOnUIThread(BookmarkModel* model,
355 const int64 id,
356 bool* result) {
357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
358 DCHECK(result);
359 *result = model->GetNodeByID(id) != NULL;
360 }
361
362 private:
363 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeExistsTask);
364 };
365
366 // Checks if a node belongs to the Mobile Bookmarks hierarchy branch.
367 class IsInMobileBookmarksBranchTask : public BookmarkModelTask {
368 public:
369 explicit IsInMobileBookmarksBranchTask(BookmarkModel* model)
370 : BookmarkModelTask(model) {}
371
372 bool Run(const int64 id) {
373 bool result = false;
374 RunOnUIThreadBlocking::Run(
375 base::Bind(&IsInMobileBookmarksBranchTask::RunOnUIThread,
376 model(), id, &result));
377 return result;
378 }
379
380 static void RunOnUIThread(BookmarkModel* model,
381 const int64 id,
382 bool *result) {
383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
384 DCHECK(result);
385 const BookmarkNode* node = model->GetNodeByID(id);
386 const BookmarkNode* mobile_node = model->mobile_node();
387 while (node && node != mobile_node)
388 node = node->parent();
389
390 *result = node == mobile_node;
391 }
392
393 private:
394 DISALLOW_COPY_AND_ASSIGN(IsInMobileBookmarksBranchTask);
395 };
396
397 // Creates folder or retrieves its id if already exists.
398 // An invalid parent id is assumed to represent the Mobile Bookmarks folder.
399 // Can only be used to create folders inside the Mobile Bookmarks branch.
400 class CreateBookmarksFolderOnceTask : public BookmarkModelTask {
401 public:
402 explicit CreateBookmarksFolderOnceTask(BookmarkModel* model)
403 : BookmarkModelTask(model) {}
404
405 int64 Run(const string16& title, const int64 parent_id) {
406 int64 result = kInvalidBookmarkId;
407 RunOnUIThreadBlocking::Run(
408 base::Bind(&CreateBookmarksFolderOnceTask::RunOnUIThread,
409 model(), title, parent_id, &result));
410 return result;
411 }
412
413 static void RunOnUIThread(BookmarkModel* model,
414 const string16& title,
415 const int64 parent_id,
416 int64* result) {
417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
418 DCHECK(result);
419
420 // Invalid ids are assumed to refer to the Mobile Bookmarks folder.
421 const BookmarkNode* parent = parent_id >= 0 ?
422 model->GetNodeByID(parent_id) : model->mobile_node();
423 DCHECK(parent);
424
425 bool in_mobile_bookmarks;
426 IsInMobileBookmarksBranchTask::RunOnUIThread(model, parent->id(),
427 &in_mobile_bookmarks);
428 if (in_mobile_bookmarks) {
429 *result = kInvalidBookmarkId;
430 return;
431 }
432
433 const BookmarkNode* node = GetChildFolderByTitle(parent, title);
434 if (node) {
435 *result = node->id();
436 return;
437 }
438
439 AddBookmarkTask::RunOnUIThread(model, title, string16(), true,
440 parent->id(), result);
441 }
442
443 private:
444 DISALLOW_COPY_AND_ASSIGN(CreateBookmarksFolderOnceTask);
445 };
446
447 // Creates a Java BookmarkNode object for a node given its id.
448 class GetAllBookmarkFoldersTask : public BookmarkModelTask {
449 public:
450 explicit GetAllBookmarkFoldersTask(BookmarkModel* model)
451 : BookmarkModelTask(model) {
452 }
453
454 void Run(ScopedJavaGlobalRef<jobject>* jroot) {
455 RunOnUIThreadBlocking::Run(
456 base::Bind(&GetAllBookmarkFoldersTask::RunOnUIThread, model(), jroot));
457 }
458
459 static void RunOnUIThread(BookmarkModel* model,
460 ScopedJavaGlobalRef<jobject>* jroot) {
461 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
462 const BookmarkNode* root = model->root_node();
463 if (!root || !root->is_folder())
464 return;
465
466 // The iterative approach is not possible because ScopedGlobalJavaRefs
467 // cannot be copy-constructed, and therefore not used in STL containers.
468 ConvertFolderSubtree(AttachCurrentThread(), root,
469 ScopedJavaLocalRef<jobject>(), jroot);
470 }
471
472 private:
473 static void ConvertFolderSubtree(JNIEnv* env,
474 const BookmarkNode* node,
475 const JavaRef<jobject>& parent_folder,
476 ScopedJavaGlobalRef<jobject>* jfolder) {
477 DCHECK(node);
478 DCHECK(node->is_folder());
479 DCHECK(jfolder);
480
481 // Global refs should be used here for thread-safety reasons as this task
482 // might be invoked from a thread other than UI. All refs are scoped.
483 ConvertBookmarkNode(node, parent_folder, jfolder);
484
485 for (int i = 0; i < node->child_count(); ++i) {
486 const BookmarkNode* child = node->GetChild(i);
487 if (child->is_folder()) {
488 ScopedJavaGlobalRef<jobject> jchild;
489 ConvertFolderSubtree(env, child, *jfolder, &jchild);
490
491 Java_BookmarkNode_addChild(env, jfolder->obj(), jchild.obj());
492 if (ClearException(env)) {
493 LOG(WARNING) << "Java exception while adding child node.";
494 return;
495 }
496 }
497 }
498 }
499
500 DISALLOW_COPY_AND_ASSIGN(GetAllBookmarkFoldersTask);
501 };
502
503 // Creates a Java BookmarkNode object for a node given its id.
504 class GetBookmarkNodeTask : public BookmarkModelTask {
505 public:
506 explicit GetBookmarkNodeTask(BookmarkModel* model)
507 : BookmarkModelTask(model) {
508 }
509
510 void Run(const int64 id,
511 bool get_parent,
512 bool get_children,
513 ScopedJavaGlobalRef<jobject>* jnode) {
514 return RunOnUIThreadBlocking::Run(
515 base::Bind(&GetBookmarkNodeTask::RunOnUIThread,
516 model(), id, get_parent, get_children, jnode));
517 }
518
519 static void RunOnUIThread(BookmarkModel* model,
520 const int64 id,
521 bool get_parent,
522 bool get_children,
523 ScopedJavaGlobalRef<jobject>* jnode) {
524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
525 const BookmarkNode* node = model->GetNodeByID(id);
526 if (!node || !jnode)
527 return;
528
529 ScopedJavaGlobalRef<jobject> jparent;
530 if (get_parent) {
531 ConvertBookmarkNode(node->parent(), ScopedJavaLocalRef<jobject>(),
532 &jparent);
533 }
534
535 ConvertBookmarkNode(node, jparent, jnode);
536
537 JNIEnv* env = AttachCurrentThread();
538 if (!jparent.is_null()) {
539 Java_BookmarkNode_addChild(env, jparent.obj(), jnode->obj());
540 if (ClearException(env)) {
541 LOG(WARNING) << "Java exception while adding child node.";
542 return;
543 }
544 }
545
546 if (get_children) {
547 for (int i = 0; i < node->child_count(); ++i) {
548 ScopedJavaGlobalRef<jobject> jchild;
549 ConvertBookmarkNode(node->GetChild(i), *jnode, &jchild);
550 Java_BookmarkNode_addChild(env, jnode->obj(), jchild.obj());
551 if (ClearException(env)) {
552 LOG(WARNING) << "Java exception while adding child node.";
553 return;
554 }
555 }
556 }
557 }
558
559 private:
560 DISALLOW_COPY_AND_ASSIGN(GetBookmarkNodeTask);
561 };
562
563 // Gets the Mobile Bookmarks node. Using this task ensures the correct
564 // initialization of the bookmark model.
565 class GetMobileBookmarksNodeTask : public BookmarkModelTask {
566 public:
567 explicit GetMobileBookmarksNodeTask(BookmarkModel* model)
568 : BookmarkModelTask(model) {}
569
570 const BookmarkNode* Run() {
571 const BookmarkNode* result = NULL;
572 RunOnUIThreadBlocking::Run(
573 base::Bind(&GetMobileBookmarksNodeTask::RunOnUIThread,
574 model(), &result));
575 return result;
576 }
577
578 static void RunOnUIThread(BookmarkModel* model, const BookmarkNode** result) {
579 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
580 DCHECK(result);
581 *result = model->mobile_node();
582 }
583
584 private:
585 DISALLOW_COPY_AND_ASSIGN(GetMobileBookmarksNodeTask);
586 };
587
588 // ------------- Aynchronous requests classes ------------- //
589
590 // Base class for asynchronous blocking requests to Chromium services.
591 // Service: type of the service to use (e.g. HistoryService, FaviconService).
592 template <typename Service>
593 class AsyncServiceRequest : protected BlockingUIThreadAsyncRequest {
594 public:
595 AsyncServiceRequest(Service* service,
596 CancelableRequestConsumer* cancelable_consumer)
597 : service_(service), cancelable_consumer_(cancelable_consumer) {}
598
599 Service* service() const { return service_; }
600
601 CancelableRequestConsumer* cancelable_consumer() const {
602 return cancelable_consumer_;
603 }
604
605 private:
606 Service* service_;
607 CancelableRequestConsumer* cancelable_consumer_;
608
609 DISALLOW_COPY_AND_ASSIGN(AsyncServiceRequest);
610 };
611
612 // Base class for all asynchronous blocking tasks that use the favicon service.
613 class FaviconServiceTask : public AsyncServiceRequest<FaviconService> {
614 public:
615 FaviconServiceTask(FaviconService* service,
616 Profile* profile,
617 CancelableRequestConsumer* cancelable_consumer)
618 : AsyncServiceRequest<FaviconService>(service, cancelable_consumer),
619 profile_(profile) {}
620
621 Profile* profile() const { return profile_; }
622
623 private:
624 Profile* profile_;
625
626 DISALLOW_COPY_AND_ASSIGN(FaviconServiceTask);
627 };
628
629 // Retrieves the favicon or touch icon for a URL from the FaviconService.
630 class BookmarkIconFetchTask : public FaviconServiceTask {
631 public:
632 BookmarkIconFetchTask(
633 FaviconService* favicon_service,
634 Profile* profile,
635 CancelableRequestConsumer* cancelable_consumer)
636 : FaviconServiceTask(favicon_service, profile, cancelable_consumer) {}
637
638 history::FaviconBitmapResult Run(const GURL& url) {
639 RunAsyncRequestOnUIThreadBlocking(
640 base::Bind(&FaviconService::GetRawFaviconForURL,
641 base::Unretained(service()),
642 FaviconService::FaviconForURLParams(
643 profile(),
644 url,
645 history::FAVICON | history::TOUCH_ICON,
646 gfx::kFaviconSize,
647 cancelable_consumer()),
648 ui::SCALE_FACTOR_100P,
649 base::Bind(
650 &BookmarkIconFetchTask::OnFaviconRetrieved,
651 base::Unretained(this))));
652 return result_;
653 }
654
655 private:
656 void OnFaviconRetrieved(FaviconService::Handle handle,
657 const history::FaviconBitmapResult& bitmap_result) {
658 result_ = bitmap_result;
659 RequestCompleted();
660 }
661
662 history::FaviconBitmapResult result_;
663
664 DISALLOW_COPY_AND_ASSIGN(BookmarkIconFetchTask);
665 };
666
667 // Base class for all asynchronous blocking tasks that use the Android history
668 // provider service.
669 class HistoryProviderTask
670 : public AsyncServiceRequest<AndroidHistoryProviderService> {
671 public:
672 HistoryProviderTask(AndroidHistoryProviderService* service,
673 CancelableRequestConsumer* cancelable_consumer)
674 : AsyncServiceRequest<AndroidHistoryProviderService>
675 (service, cancelable_consumer) {}
676
677 private:
678 DISALLOW_COPY_AND_ASSIGN(HistoryProviderTask);
679 };
680
681 // Adds a bookmark from the API.
682 class AddBookmarkFromAPITask : public HistoryProviderTask {
683 public:
684 AddBookmarkFromAPITask(AndroidHistoryProviderService* service,
685 CancelableRequestConsumer* cancelable_consumer)
686 : HistoryProviderTask(service, cancelable_consumer) {}
687
688 history::URLID Run(const history::HistoryAndBookmarkRow& row) {
689 RunAsyncRequestOnUIThreadBlocking(
690 base::Bind(&AndroidHistoryProviderService::InsertHistoryAndBookmark,
691 base::Unretained(service()), row, cancelable_consumer(),
692 base::Bind(&AddBookmarkFromAPITask::OnBookmarkInserted,
693 base::Unretained(this))));
694 return result_;
695 }
696
697 private:
698 void OnBookmarkInserted(AndroidHistoryProviderService::Handle handle,
699 bool succeeded,
700 history::URLID id) {
701 // Note that here 0 means an invalid id too.
702 // This is because it represents a SQLite database row id.
703 result_ = id;
704 RequestCompleted();
705 }
706
707 history::URLID result_;
708
709 DISALLOW_COPY_AND_ASSIGN(AddBookmarkFromAPITask);
710 };
711
712 // Queries bookmarks from the API.
713 class QueryBookmarksFromAPITask : public HistoryProviderTask {
714 public:
715 QueryBookmarksFromAPITask(AndroidHistoryProviderService* service,
716 CancelableRequestConsumer* cancelable_consumer)
717 : HistoryProviderTask(service, cancelable_consumer),
718 result_(NULL) {}
719
720 history::AndroidStatement* Run(
721 const std::vector<history::HistoryAndBookmarkRow::ColumnID>& projections,
722 const std::string& selection,
723 const std::vector<string16>& selection_args,
724 const std::string& sort_order) {
725 RunAsyncRequestOnUIThreadBlocking(
726 base::Bind(&AndroidHistoryProviderService::QueryHistoryAndBookmarks,
727 base::Unretained(service()), projections, selection,
728 selection_args, sort_order, cancelable_consumer(),
729 base::Bind(&QueryBookmarksFromAPITask::OnBookmarksQueried,
730 base::Unretained(this))));
731 return result_;
732 }
733
734 private:
735 void OnBookmarksQueried(AndroidHistoryProviderService::Handle handle,
736 bool succeeded,
737 history::AndroidStatement* statement) {
738 result_ = statement;
739 RequestCompleted();
740 }
741
742 history::AndroidStatement* result_;
743
744 DISALLOW_COPY_AND_ASSIGN(QueryBookmarksFromAPITask);
745 };
746
747 // Updates bookmarks from the API.
748 class UpdateBookmarksFromAPITask : public HistoryProviderTask {
749 public:
750 UpdateBookmarksFromAPITask(AndroidHistoryProviderService* service,
751 CancelableRequestConsumer* cancelable_consumer)
752 : HistoryProviderTask(service, cancelable_consumer),
753 result_(0) {}
754
755 int Run(const history::HistoryAndBookmarkRow& row,
756 const std::string& selection,
757 const std::vector<string16>& selection_args) {
758 RunAsyncRequestOnUIThreadBlocking(
759 base::Bind(&AndroidHistoryProviderService::UpdateHistoryAndBookmarks,
760 base::Unretained(service()), row, selection,
761 selection_args, cancelable_consumer(),
762 base::Bind(&UpdateBookmarksFromAPITask::OnBookmarksUpdated,
763 base::Unretained(this))));
764 return result_;
765 }
766
767 private:
768 void OnBookmarksUpdated(AndroidHistoryProviderService::Handle handle,
769 bool succeeded,
770 int updated_row_count) {
771 result_ = updated_row_count;
772 RequestCompleted();
773 }
774
775 int result_;
776
777 DISALLOW_COPY_AND_ASSIGN(UpdateBookmarksFromAPITask);
778 };
779
780 // Removes bookmarks from the API.
781 class RemoveBookmarksFromAPITask : public HistoryProviderTask {
782 public:
783 RemoveBookmarksFromAPITask(AndroidHistoryProviderService* service,
784 CancelableRequestConsumer* cancelable_consumer)
785 : HistoryProviderTask(service, cancelable_consumer),
786 result_(0) {}
787
788 int Run(const std::string& selection,
789 const std::vector<string16>& selection_args) {
790 RunAsyncRequestOnUIThreadBlocking(
791 base::Bind(&AndroidHistoryProviderService::DeleteHistoryAndBookmarks,
792 base::Unretained(service()), selection, selection_args,
793 cancelable_consumer(),
794 base::Bind(&RemoveBookmarksFromAPITask::OnBookmarksRemoved,
795 base::Unretained(this))));
796 return result_;
797 }
798
799 private:
800 void OnBookmarksRemoved(AndroidHistoryProviderService::Handle handle,
801 bool succeeded,
802 int removed_row_count) {
803 result_ = removed_row_count;
804 RequestCompleted();
805 }
806
807 int result_;
808
809 DISALLOW_COPY_AND_ASSIGN(RemoveBookmarksFromAPITask);
810 };
811
812 // Removes history from the API.
813 class RemoveHistoryFromAPITask : public HistoryProviderTask {
814 public:
815 RemoveHistoryFromAPITask(AndroidHistoryProviderService* service,
816 CancelableRequestConsumer* cancelable_consumer)
817 : HistoryProviderTask(service, cancelable_consumer),
818 result_(0) {}
819
820 int Run(const std::string& selection,
821 const std::vector<string16>& selection_args) {
822 RunAsyncRequestOnUIThreadBlocking(
823 base::Bind(&AndroidHistoryProviderService::DeleteHistory,
824 base::Unretained(service()), selection,
825 selection_args, cancelable_consumer(),
826 base::Bind(&RemoveHistoryFromAPITask::OnHistoryRemoved,
827 base::Unretained(this))));
828 return result_;
829 }
830
831 private:
832 void OnHistoryRemoved(AndroidHistoryProviderService::Handle handle,
833 bool succeeded,
834 int removed_row_count) {
835 result_ = removed_row_count;
836 RequestCompleted();
837 }
838
839 int result_;
840
841 DISALLOW_COPY_AND_ASSIGN(RemoveHistoryFromAPITask);
842 };
843
844 // This class provides the common method for the SearchTermAPIHelper.
845 class SearchTermTask : public HistoryProviderTask {
846 protected:
847 SearchTermTask(AndroidHistoryProviderService* service,
848 CancelableRequestConsumer* cancelable_consumer,
849 Profile* profile)
850 : HistoryProviderTask(service, cancelable_consumer),
851 profile_(profile) {}
852
853 // Fill SearchRow's template_url_id and url fields according the given
854 // search_term. Return true if succeeded.
855 void BuildSearchRow(history::SearchRow* row) {
856 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
857
858 TemplateURLService* template_service =
859 TemplateURLServiceFactory::GetForProfile(profile_);
860 template_service->Load();
861
862 const TemplateURL* search_engine =
863 template_service->GetDefaultSearchProvider();
864 if (search_engine) {
865 const TemplateURLRef* search_url = &search_engine->url_ref();
866 std::string url = search_url->ReplaceSearchTerms(
867 TemplateURLRef::SearchTermsArgs(row->search_term()));
868 if (!url.empty()) {
869 row->set_url(GURL(url));
870 row->set_template_url_id(search_engine->id());
871 }
872 }
873 }
874
875 private:
876 Profile* profile_;
877
878 DISALLOW_COPY_AND_ASSIGN(SearchTermTask);
879 };
880
881 // Adds a search term from the API.
882 class AddSearchTermFromAPITask : public SearchTermTask {
883 public:
884 AddSearchTermFromAPITask(AndroidHistoryProviderService* service,
885 CancelableRequestConsumer* cancelable_consumer,
886 Profile* profile)
887 : SearchTermTask(service, cancelable_consumer, profile) {}
888
889 history::URLID Run(const history::SearchRow& row) {
890 RunAsyncRequestOnUIThreadBlocking(
891 base::Bind(&AddSearchTermFromAPITask::MakeRequestOnUIThread,
892 base::Unretained(this), row));
893 return result_;
894 }
895
896 private:
897 void MakeRequestOnUIThread(const history::SearchRow& row) {
898 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
899 history::SearchRow internal_row = row;
900 BuildSearchRow(&internal_row);
901 service()->InsertSearchTerm(internal_row, cancelable_consumer(),
902 base::Bind(&AddSearchTermFromAPITask::OnSearchTermInserted,
903 base::Unretained(this)));
904 }
905
906 void OnSearchTermInserted(AndroidHistoryProviderService::Handle handle,
907 bool succeeded,
908 history::URLID id) {
909 // Note that here 0 means an invalid id too.
910 // This is because it represents a SQLite database row id.
911 result_ = id;
912 RequestCompleted();
913 }
914
915 history::URLID result_;
916
917 DISALLOW_COPY_AND_ASSIGN(AddSearchTermFromAPITask);
918 };
919
920 // Queries search terms from the API.
921 class QuerySearchTermsFromAPITask : public SearchTermTask {
922 public:
923 QuerySearchTermsFromAPITask(AndroidHistoryProviderService* service,
924 CancelableRequestConsumer* cancelable_consumer,
925 Profile* profile)
926 : SearchTermTask(service, cancelable_consumer, profile),
927 result_(NULL) {}
928
929 history::AndroidStatement* Run(
930 const std::vector<history::SearchRow::ColumnID>& projections,
931 const std::string& selection,
932 const std::vector<string16>& selection_args,
933 const std::string& sort_order) {
934 RunAsyncRequestOnUIThreadBlocking(
935 base::Bind(&AndroidHistoryProviderService::QuerySearchTerms,
936 base::Unretained(service()), projections, selection,
937 selection_args, sort_order, cancelable_consumer(),
938 base::Bind(
939 &QuerySearchTermsFromAPITask::OnSearchTermsQueried,
940 base::Unretained(this))));
941 return result_;
942 }
943
944 private:
945 // Callback to return the result.
946 void OnSearchTermsQueried(AndroidHistoryProviderService::Handle handle,
947 bool succeeded,
948 history::AndroidStatement* statement) {
949 result_ = statement;
950 RequestCompleted();
951 }
952
953 history::AndroidStatement* result_;
954
955 DISALLOW_COPY_AND_ASSIGN(QuerySearchTermsFromAPITask);
956 };
957
958 // Updates search terms from the API.
959 class UpdateSearchTermsFromAPITask : public SearchTermTask {
960 public:
961 UpdateSearchTermsFromAPITask(AndroidHistoryProviderService* service,
962 CancelableRequestConsumer* cancelable_consumer,
963 Profile* profile)
964 : SearchTermTask(service, cancelable_consumer, profile),
965 result_(0) {}
966
967 int Run(const history::SearchRow& row,
968 const std::string& selection,
969 const std::vector<string16>& selection_args) {
970 RunAsyncRequestOnUIThreadBlocking(
971 base::Bind(&UpdateSearchTermsFromAPITask::MakeRequestOnUIThread,
972 base::Unretained(this), row, selection, selection_args));
973 return result_;
974 }
975
976 private:
977 void MakeRequestOnUIThread(const history::SearchRow& row,
978 const std::string& selection,
979 const std::vector<string16>& selection_args) {
980 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
981 history::SearchRow internal_row = row;
982 BuildSearchRow(&internal_row);
983 service()->UpdateSearchTerms(
984 internal_row,
985 selection,
986 selection_args,
987 cancelable_consumer(),
988 base::Bind(&UpdateSearchTermsFromAPITask::OnSearchTermsUpdated,
989 base::Unretained(this)));
990 }
991
992
993 void OnSearchTermsUpdated(AndroidHistoryProviderService::Handle handle,
994 bool succeeded,
995 int updated_row_count) {
996 result_ = updated_row_count;
997 RequestCompleted();
998 }
999
1000 int result_;
1001
1002 DISALLOW_COPY_AND_ASSIGN(UpdateSearchTermsFromAPITask);
1003 };
1004
1005 // Removes search terms from the API.
1006 class RemoveSearchTermsFromAPITask : public SearchTermTask {
1007 public:
1008 RemoveSearchTermsFromAPITask(AndroidHistoryProviderService* service,
1009 CancelableRequestConsumer* cancelable_consumer,
1010 Profile* profile)
1011 : SearchTermTask(service, cancelable_consumer, profile) {}
1012
1013 int Run(const std::string& selection,
1014 const std::vector<string16>& selection_args) {
1015 RunAsyncRequestOnUIThreadBlocking(
1016 base::Bind(&AndroidHistoryProviderService::DeleteSearchTerms,
1017 base::Unretained(service()), selection, selection_args,
1018 cancelable_consumer(),
1019 base::Bind(
1020 &RemoveSearchTermsFromAPITask::OnSearchTermsDeleted,
1021 base::Unretained(this))));
1022 return result_;
1023 }
1024
1025 private:
1026 void OnSearchTermsDeleted(AndroidHistoryProviderService::Handle handle,
1027 bool succeeded,
1028 int deleted_row_count) {
1029 result_ = deleted_row_count;
1030 RequestCompleted();
1031 }
1032
1033 int result_;
1034
1035 DISALLOW_COPY_AND_ASSIGN(RemoveSearchTermsFromAPITask);
1036 };
1037
1038 // ------------- Other utility methods (may use tasks) ------------- //
1039
1040 // Fills the bookmark |row| with the given java objects.
1041 void FillBookmarkRow(JNIEnv* env,
1042 jobject obj,
1043 jstring url,
1044 jobject created,
1045 jobject isBookmark,
1046 jobject date,
1047 jbyteArray favicon,
1048 jstring title,
1049 jobject visits,
1050 jlong parent_id,
1051 history::HistoryAndBookmarkRow* row,
1052 BookmarkModel* model) {
1053 // Needed because of the internal bookmark model task invocation.
1054 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
1055
1056 if (url) {
1057 string16 raw_url = ConvertJavaStringToUTF16(env, url);
1058 // GURL doesn't accept the URL without protocol, but the Android CTS
1059 // allows it. We are trying to prefix with 'http://' to see whether
1060 // GURL thinks it is a valid URL. The original url will be stored in
1061 // history::BookmarkRow.raw_url_.
1062 GURL gurl = ParseAndMaybeAppendScheme(raw_url, kDefaultUrlScheme);
1063 row->set_url(gurl);
1064 row->set_raw_url(UTF16ToUTF8(raw_url));
1065 }
1066
1067 if (created)
1068 row->set_created(ConvertJlongToTime(
1069 ConvertJLongObjectToPrimitive(env, created)));
1070
1071 if (isBookmark)
1072 row->set_is_bookmark(ConvertJBooleanObjectToPrimitive(env, isBookmark));
1073
1074 if (date)
1075 row->set_last_visit_time(ConvertJlongToTime(ConvertJLongObjectToPrimitive(
1076 env, date)));
1077
1078 if (favicon) {
1079 std::vector<uint8> bytes;
1080 base::android::JavaByteArrayToByteVector(env, favicon, &bytes);
1081 row->set_favicon(base::RefCountedBytes::TakeVector(&bytes));
1082 }
1083
1084 if (title)
1085 row->set_title(ConvertJavaStringToUTF16(env, title));
1086
1087 if (visits)
1088 row->set_visit_count(ConvertJIntegerToJint(env, visits));
1089
1090 // Make sure parent_id is always in the mobile_node branch.
1091 IsInMobileBookmarksBranchTask task(model);
1092 if (task.Run(parent_id))
1093 row->set_parent_id(parent_id);
1094 }
1095
1096 // Fills the bookmark |row| with the given java objects if it is not null.
1097 void FillSearchRow(JNIEnv* env,
1098 jobject obj,
1099 jstring search_term,
1100 jobject date,
1101 history::SearchRow* row) {
1102 if (search_term)
1103 row->set_search_term(ConvertJavaStringToUTF16(env, search_term));
1104
1105 if (date)
1106 row->set_search_time(ConvertJlongToTime(ConvertJLongObjectToPrimitive(
1107 env, date)));
1108 }
1109
1110 } // namespace
1111
1112 // ------------- Native initialization and destruction ------------- //
1113
1114 bool RegisterChromeBrowserProvider(JNIEnv* env) {
1115 return RegisterNativesImpl(env);
1116 }
1117
1118 static jint Init(JNIEnv* env, jobject obj) {
1119 ChromeBrowserProvider* provider = new ChromeBrowserProvider(env, obj);
1120 return reinterpret_cast<jint>(provider);
1121 }
1122
1123 ChromeBrowserProvider::JavaBrowserProviderWeakGlobalRef::
1124 JavaBrowserProviderWeakGlobalRef(JNIEnv* env, jobject obj)
1125 : JavaObjectWeakGlobalRef(env, obj) {
1126 ScopedJavaLocalRef<jclass> clazz = GetClass(env, kClassPathName);
1127 on_bookmark_changed_ = GetMethodID(env, clazz, "onBookmarkChanged", "()V");
Yaron 2012/09/10 19:30:04 Shouldn't these just be @CalledByNative methods an
Leandro Gracia Gil 2012/09/10 22:21:48 Good point. I should have noticed these when refac
1128 on_search_term_changed_ =
1129 GetMethodID(env, clazz, "onSearchTermChanged", "()V");
1130 }
1131
1132 void ChromeBrowserProvider::JavaBrowserProviderWeakGlobalRef::
1133 OnBookmarkChanged() const {
1134 JNIEnv* env = AttachCurrentThread();
1135 DCHECK(get(env).obj());
1136 env->CallVoidMethod(get(env).obj(), on_bookmark_changed_);
1137 CheckException(env);
1138 }
1139
1140 void ChromeBrowserProvider::JavaBrowserProviderWeakGlobalRef::
1141 OnSearchTermChanged() const {
1142 JNIEnv* env = AttachCurrentThread();
1143 DCHECK(get(env).obj());
1144 env->CallVoidMethod(get(env).obj(), on_search_term_changed_);
1145 CheckException(env);
1146 }
1147
1148 ChromeBrowserProvider::ChromeBrowserProvider(JNIEnv* env, jobject obj)
1149 : java_browser_provider_(env, obj),
1150 template_loaded_event_(true, false) {
1151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1152 profile_ = g_browser_process->profile_manager()->GetLastUsedProfile();
1153 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile_);
1154 top_sites_ = profile_->GetTopSites();
1155 service_.reset(new AndroidHistoryProviderService(profile_));
1156 favicon_service_.reset(FaviconServiceFactory::GetForProfile(profile_,
1157 Profile::EXPLICIT_ACCESS));
1158
1159 // Registers the notifications we are interested.
1160 bookmark_model_->AddObserver(this);
1161 notification_registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED,
1162 content::NotificationService::AllSources());
1163 notification_registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
1164 content::NotificationService::AllSources());
1165 notification_registrar_.Add(this,
1166 chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
1167 content::NotificationService::AllSources());
1168 notification_registrar_.Add(this,
1169 chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED,
1170 content::NotificationService::AllSources());
1171 TemplateURLService* template_service =
1172 TemplateURLServiceFactory::GetForProfile(profile_);
1173 if (template_service->loaded())
1174 template_loaded_event_.Signal();
1175 else
1176 template_service->Load();
1177 }
1178
1179 ChromeBrowserProvider::~ChromeBrowserProvider() {
1180 bookmark_model_->RemoveObserver(this);
1181 }
1182
1183 void ChromeBrowserProvider::Destroy(JNIEnv*, jobject) {
1184 delete this;
1185 }
1186
1187 // ------------- Provider public APIs ------------- //
1188
1189 jlong ChromeBrowserProvider::AddBookmark(JNIEnv* env,
1190 jobject,
1191 jstring jurl,
1192 jstring jtitle,
1193 jboolean is_folder,
1194 jlong parent_id) {
1195 string16 url;
1196 if (jurl)
1197 url = ConvertJavaStringToUTF16(env, jurl);
1198 string16 title = ConvertJavaStringToUTF16(env, jtitle);
1199
1200 AddBookmarkTask task(bookmark_model_);
1201 return task.Run(title, url, is_folder, parent_id);
1202 }
1203
1204 jint ChromeBrowserProvider::RemoveBookmark(JNIEnv*, jobject, jlong id) {
1205 RemoveBookmarkTask task(bookmark_model_);
1206 return task.Run(id);
1207 }
1208
1209 jint ChromeBrowserProvider::UpdateBookmark(JNIEnv* env,
1210 jobject,
1211 jlong id,
1212 jstring jurl,
1213 jstring jtitle,
1214 jlong parent_id) {
1215 string16 url;
1216 if (jurl)
1217 url = ConvertJavaStringToUTF16(env, jurl);
1218 string16 title = ConvertJavaStringToUTF16(env, jtitle);
1219
1220 UpdateBookmarkTask task(bookmark_model_);
1221 return task.Run(id, title, url, parent_id);
1222 }
1223
1224 // Add the bookmark with the given column values.
1225 jlong ChromeBrowserProvider::AddBookmarkFromAPI(JNIEnv* env,
1226 jobject obj,
1227 jstring url,
1228 jobject created,
1229 jobject isBookmark,
1230 jobject date,
1231 jbyteArray favicon,
1232 jstring title,
1233 jobject visits,
1234 jlong parent_id) {
1235 DCHECK(url);
1236
1237 history::HistoryAndBookmarkRow row;
1238 FillBookmarkRow(env, obj, url, created, isBookmark, date, favicon, title,
1239 visits, parent_id, &row, bookmark_model_);
1240
1241 // URL must be valid.
1242 if (row.url().is_empty()) {
1243 LOG(ERROR) << "Not a valid URL " << row.raw_url();
1244 return kInvalidContentProviderId;
1245 }
1246
1247 AddBookmarkFromAPITask task(service_.get(), &android_history_consumer_);
1248 return task.Run(row);
1249 }
1250
1251 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::QueryBookmarkFromAPI(
1252 JNIEnv* env,
1253 jobject obj,
1254 jobjectArray projection,
1255 jstring selections,
1256 jobjectArray selection_args,
1257 jstring sort_order) {
1258 // Converts the projection to array of ColumnID and column name.
1259 // Used to store the projection column ID according their sequence.
1260 std::vector<history::HistoryAndBookmarkRow::ColumnID> query_columns;
1261 // Used to store the projection column names according their sequence.
1262 std::vector<std::string> columns_name;
1263 if (projection) {
1264 jsize len = env->GetArrayLength(projection);
1265 for (int i = 0; i < len; i++) {
1266 std::string name = ConvertJavaStringToUTF8(env, static_cast<jstring>(
1267 env->GetObjectArrayElement(projection, i)));
1268 history::HistoryAndBookmarkRow::ColumnID id =
1269 history::HistoryAndBookmarkRow::GetColumnID(name);
1270 if (id == history::HistoryAndBookmarkRow::COLUMN_END) {
1271 // Ignore the unknown column; As Android platform will send us
1272 // the non public column.
1273 continue;
1274 }
1275 query_columns.push_back(id);
1276 columns_name.push_back(name);
1277 }
1278 }
1279
1280 std::vector<string16> where_args =
1281 ConvertJStringArrayToString16Array(env, selection_args);
1282
1283 std::string where_clause;
1284 if (selections) {
1285 where_clause = ConvertJavaStringToUTF8(env, selections);
1286 }
1287
1288 std::string sort_clause;
1289 if (sort_order) {
1290 sort_clause = ConvertJavaStringToUTF8(env, sort_order);
1291 }
1292
1293 QueryBookmarksFromAPITask task(service_.get(), &android_history_consumer_);
1294 history::AndroidStatement* statement = task.Run(
1295 query_columns, where_clause, where_args, sort_clause);
1296 if (!statement)
1297 return ScopedJavaLocalRef<jobject>();
1298
1299 // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
1300 // Java object.
1301 return SQLiteCursor::NewJavaSqliteCursor(env, columns_name, statement,
1302 service_.get(), favicon_service_.get());
1303 }
1304
1305 // Updates the bookmarks with the given column values. The value is not given if
1306 // it is NULL.
1307 jint ChromeBrowserProvider::UpdateBookmarkFromAPI(JNIEnv* env,
1308 jobject obj,
1309 jstring url,
1310 jobject created,
1311 jobject isBookmark,
1312 jobject date,
1313 jbyteArray favicon,
1314 jstring title,
1315 jobject visits,
1316 jlong parent_id,
1317 jstring selections,
1318 jobjectArray selection_args) {
1319 history::HistoryAndBookmarkRow row;
1320 FillBookmarkRow(env, obj, url, created, isBookmark, date, favicon, title,
1321 visits, parent_id, &row, bookmark_model_);
1322
1323 std::vector<string16> where_args =
1324 ConvertJStringArrayToString16Array(env, selection_args);
1325
1326 std::string where_clause;
1327 if (selections)
1328 where_clause = ConvertJavaStringToUTF8(env, selections);
1329
1330 UpdateBookmarksFromAPITask task(service_.get(), &android_history_consumer_);
1331 return task.Run(row, where_clause, where_args);
1332 }
1333
1334 jint ChromeBrowserProvider::RemoveBookmarkFromAPI(JNIEnv* env,
1335 jobject obj,
1336 jstring selections,
1337 jobjectArray selection_args) {
1338 std::vector<string16> where_args =
1339 ConvertJStringArrayToString16Array(env, selection_args);
1340
1341 std::string where_clause;
1342 if (selections)
1343 where_clause = ConvertJavaStringToUTF8(env, selections);
1344
1345 RemoveBookmarksFromAPITask task(service_.get(), &android_history_consumer_);
1346 return task.Run(where_clause, where_args);
1347 }
1348
1349 jint ChromeBrowserProvider::RemoveHistoryFromAPI(JNIEnv* env,
1350 jobject obj,
1351 jstring selections,
1352 jobjectArray selection_args) {
1353 std::vector<string16> where_args =
1354 ConvertJStringArrayToString16Array(env, selection_args);
1355
1356 std::string where_clause;
1357 if (selections)
1358 where_clause = ConvertJavaStringToUTF8(env, selections);
1359
1360 RemoveHistoryFromAPITask task(service_.get(), &android_history_consumer_);
1361 return task.Run(where_clause, where_args);
1362 }
1363
1364 // Add the search term with the given column values. The value is not given if
1365 // it is NULL.
1366 jlong ChromeBrowserProvider::AddSearchTermFromAPI(JNIEnv* env,
1367 jobject obj,
1368 jstring search_term,
1369 jobject date) {
1370 DCHECK(search_term);
1371
1372 history::SearchRow row;
1373 FillSearchRow(env, obj, search_term, date, &row);
1374
1375 // URL must be valid.
1376 if (row.search_term().empty()) {
1377 LOG(ERROR) << "Search term is empty.";
1378 return kInvalidContentProviderId;
1379 }
1380
1381 AddSearchTermFromAPITask task(service_.get(), &android_history_consumer_,
1382 profile_);
1383 return task.Run(row);
1384 }
1385
1386 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::QuerySearchTermFromAPI(
1387 JNIEnv* env,
1388 jobject obj,
1389 jobjectArray projection,
1390 jstring selections,
1391 jobjectArray selection_args,
1392 jstring sort_order) {
1393 // Converts the projection to array of ColumnID and column name.
1394 // Used to store the projection column ID according their sequence.
1395 std::vector<history::SearchRow::ColumnID> query_columns;
1396 // Used to store the projection column names according their sequence.
1397 std::vector<std::string> columns_name;
1398 if (projection) {
1399 jsize len = env->GetArrayLength(projection);
1400 for (int i = 0; i < len; i++) {
1401 std::string name = ConvertJavaStringToUTF8(env, static_cast<jstring>(
1402 env->GetObjectArrayElement(projection, i)));
1403 history::SearchRow::ColumnID id =
1404 history::SearchRow::GetColumnID(name);
1405 if (id == history::SearchRow::COLUMN_END) {
1406 LOG(ERROR) << "Can not find " << name;
1407 return ScopedJavaLocalRef<jobject>();
1408 }
1409 query_columns.push_back(id);
1410 columns_name.push_back(name);
1411 }
1412 }
1413
1414 std::vector<string16> where_args =
1415 ConvertJStringArrayToString16Array(env, selection_args);
1416
1417 std::string where_clause;
1418 if (selections) {
1419 where_clause = ConvertJavaStringToUTF8(env, selections);
1420 }
1421
1422 std::string sort_clause;
1423 if (sort_order) {
1424 sort_clause = ConvertJavaStringToUTF8(env, sort_order);
1425 }
1426
1427 QuerySearchTermsFromAPITask task(service_.get(), &android_history_consumer_,
1428 profile_);
1429 history::AndroidStatement* statement = task.Run(
1430 query_columns, where_clause, where_args, sort_clause);
1431 if (!statement)
1432 return ScopedJavaLocalRef<jobject>();
1433 // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
1434 // Java object.
1435 return SQLiteCursor::NewJavaSqliteCursor(env, columns_name, statement,
1436 service_.get(), favicon_service_.get());
1437 }
1438
1439 // Updates the search terms with the given column values. The value is not
1440 // given if it is NULL.
1441 jint ChromeBrowserProvider::UpdateSearchTermFromAPI(
1442 JNIEnv* env, jobject obj, jstring search_term, jobject date,
1443 jstring selections, jobjectArray selection_args) {
1444 history::SearchRow row;
1445 FillSearchRow(env, obj, search_term, date, &row);
1446
1447 std::vector<string16> where_args = ConvertJStringArrayToString16Array(
1448 env, selection_args);
1449
1450 std::string where_clause;
1451 if (selections)
1452 where_clause = ConvertJavaStringToUTF8(env, selections);
1453
1454 UpdateSearchTermsFromAPITask task(service_.get(), &android_history_consumer_,
1455 profile_);
1456 return task.Run(row, where_clause, where_args);
1457 }
1458
1459 jint ChromeBrowserProvider::RemoveSearchTermFromAPI(
1460 JNIEnv* env, jobject obj, jstring selections, jobjectArray selection_args) {
1461 std::vector<string16> where_args =
1462 ConvertJStringArrayToString16Array(env, selection_args);
1463
1464 std::string where_clause;
1465 if (selections)
1466 where_clause = ConvertJavaStringToUTF8(env, selections);
1467
1468 RemoveSearchTermsFromAPITask task(service_.get(), &android_history_consumer_,
1469 profile_);
1470 return task.Run(where_clause, where_args);
1471 }
1472
1473 // ------------- Provider custom APIs ------------- //
1474
1475 jboolean ChromeBrowserProvider::BookmarkNodeExists(
1476 JNIEnv* env,
1477 jobject obj,
1478 jlong id) {
1479 BookmarkNodeExistsTask task(bookmark_model_);
1480 return task.Run(id);
1481 }
1482
1483 jlong ChromeBrowserProvider::CreateBookmarksFolderOnce(
1484 JNIEnv* env,
1485 jobject obj,
1486 jstring jtitle,
1487 jlong parent_id) {
1488 string16 title = ConvertJavaStringToUTF16(env, jtitle);
1489 if (title.empty())
1490 return kInvalidBookmarkId;
1491
1492 CreateBookmarksFolderOnceTask task(bookmark_model_);
1493 return task.Run(title, parent_id);
1494 }
1495
1496 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::GetAllBookmarkFolders(
1497 JNIEnv* env,
1498 jobject obj) {
1499 ScopedJavaGlobalRef<jobject> jroot;
1500 GetAllBookmarkFoldersTask task(bookmark_model_);
1501 task.Run(&jroot);
1502 return ScopedJavaLocalRef<jobject>(jroot);
1503 }
1504
1505 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::GetBookmarkNode(
1506 JNIEnv* env,
1507 jobject obj,
1508 jlong id,
1509 jboolean get_parent,
1510 jboolean get_children) {
1511 ScopedJavaGlobalRef<jobject> jnode;
1512 GetBookmarkNodeTask task(bookmark_model_);
1513 task.Run(id, get_parent, get_children, &jnode);
1514 return ScopedJavaLocalRef<jobject>(jnode);
1515 }
1516
1517 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::GetMobileBookmarksFolder(
1518 JNIEnv* env,
1519 jobject obj) {
1520 ScopedJavaGlobalRef<jobject> jnode;
1521 GetMobileBookmarksNodeTask task(bookmark_model_);
1522 ConvertBookmarkNode(task.Run(), ScopedJavaLocalRef<jobject>(), &jnode);
1523 return ScopedJavaLocalRef<jobject>(jnode);
1524 }
1525
1526 jboolean ChromeBrowserProvider::IsBookmarkInMobileBookmarksBranch(
1527 JNIEnv* env,
1528 jobject obj,
1529 jlong id) {
1530 IsInMobileBookmarksBranchTask task(bookmark_model_);
1531 return task.Run(id);
1532 }
1533
1534 ScopedJavaLocalRef<jbyteArray> ChromeBrowserProvider::GetFaviconOrTouchIcon(
1535 JNIEnv* env, jobject obj, jstring jurl) {
1536 if (!jurl)
1537 return ScopedJavaLocalRef<jbyteArray>();
1538
1539 GURL url = GURL(ConvertJavaStringToUTF16(env, jurl));
1540 BookmarkIconFetchTask favicon_task(favicon_service_.get(),
1541 profile_,
1542 &favicon_consumer_);
1543 history::FaviconBitmapResult bitmap_result = favicon_task.Run(url);
1544
1545 if (!bitmap_result.is_valid() || !bitmap_result.bitmap_data.get())
1546 return ScopedJavaLocalRef<jbyteArray>();
1547
1548 return base::android::ToJavaByteArray(env, bitmap_result.bitmap_data->front(),
1549 bitmap_result.bitmap_data->size());
1550 }
1551
1552 ScopedJavaLocalRef<jbyteArray> ChromeBrowserProvider::GetThumbnail(
1553 JNIEnv* env, jobject obj, jstring jurl) {
1554 if (!jurl)
1555 return ScopedJavaLocalRef<jbyteArray>();
1556 GURL url = GURL(ConvertJavaStringToUTF16(env, jurl));
1557
1558 // GetPageThumbnail is synchronous and can be called from any thread.
1559 scoped_refptr<base::RefCountedMemory> thumbnail;
1560 if (top_sites_)
1561 top_sites_->GetPageThumbnail(url, &thumbnail);
1562
1563 if (!thumbnail.get() || !thumbnail->front()) {
1564 return ScopedJavaLocalRef<jbyteArray>();
1565 }
1566
1567 return base::android::ToJavaByteArray(env, thumbnail->front(),
1568 thumbnail->size());
1569 }
1570
1571 // ------------- Observer-related methods ------------- //
1572
1573 void ChromeBrowserProvider::BookmarkModelChanged() {
1574 java_browser_provider_.OnBookmarkChanged();
1575 }
1576
1577 void ChromeBrowserProvider::Observe(
1578 int type,
1579 const content::NotificationSource& source,
1580 const content::NotificationDetails& details) {
1581 if (type == chrome::NOTIFICATION_HISTORY_URL_VISITED ||
1582 type == chrome::NOTIFICATION_HISTORY_URLS_DELETED) {
1583 java_browser_provider_.OnBookmarkChanged();
1584 } else if (type ==
1585 chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED) {
1586 java_browser_provider_.OnSearchTermChanged();
1587 } else if (type == chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED) {
1588 template_loaded_event_.Signal();
1589 }
1590 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698