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.
5 #include "chrome/browser/android/provider/chrome_browser_provider.h"
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/strings/utf_string_conversions.h"
16 #include "base/time/time.h"
17 #include "chrome/browser/android/provider/blocking_ui_thread_async_request.h"
18 #include "chrome/browser/android/provider/bookmark_model_observer_task.h"
19 #include "chrome/browser/android/provider/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/chrome_notification_types.h"
24 #include "chrome/browser/favicon/favicon_service.h"
25 #include "chrome/browser/favicon/favicon_service_factory.h"
26 #include "chrome/browser/history/android/android_history_types.h"
27 #include "chrome/browser/history/android/sqlite_cursor.h"
28 #include "chrome/browser/history/top_sites.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/profiles/profile_manager.h"
31 #include "chrome/browser/search_engines/template_url.h"
32 #include "chrome/browser/search_engines/template_url_service.h"
33 #include "chrome/browser/search_engines/template_url_service_factory.h"
34 #include "chrome/common/cancelable_task_tracker.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/notification_service.h"
37 #include "grit/generated_resources.h"
38 #include "jni/ChromeBrowserProvider_jni.h"
39 #include "sql/statement.h"
40 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/base/layout.h"
42 #include "ui/base/resource/resource_bundle.h"
43 #include "ui/gfx/favicon_size.h"
45 using base::android::AttachCurrentThread;
46 using base::android::CheckException;
47 using base::android::ClearException;
48 using base::android::ConvertJavaStringToUTF16;
49 using base::android::ConvertJavaStringToUTF8;
50 using base::android::ConvertUTF8ToJavaString;
51 using base::android::ConvertUTF16ToJavaString;
52 using base::android::GetClass;
53 using base::android::MethodID;
54 using base::android::JavaRef;
55 using base::android::ScopedJavaGlobalRef;
56 using base::android::ScopedJavaLocalRef;
57 using content::BrowserThread;
59 // After refactoring the following class hierarchy has been created in order
60 // to avoid repeating code again for the same basic kind of tasks, to enforce
61 // the correct thread usage and to prevent known race conditions and deadlocks.
63 // - RunOnUIThreadBlocking: auxiliary class to run methods in the UI thread
64 // blocking the current one until finished. Because of the provider threading
65 // expectations this cannot be used from the UI thread.
67 // - BookmarkModelTask: base class for all tasks that operate in any way with
68 // the bookmark model. This class ensures that the model is loaded and
69 // prevents possible deadlocks. Derived classes should make use of
70 // RunOnUIThreadBlocking to perform any manipulation of the bookmark model in
71 // the UI thread. The Run method of these tasks cannot be invoked directly
72 // from the UI thread, but RunOnUIThread can be safely used from the UI
73 // thread code of other BookmarkModelTasks.
75 // - AsyncServiceRequest: base class for any asynchronous requests made to a
76 // Chromium service that require to block the current thread until completed.
77 // Derived classes should make use of RunAsyncRequestOnUIThreadBlocking to
78 // post their requests in the UI thread and return the results synchronously.
79 // All derived classes MUST ALWAYS call RequestCompleted when receiving the
80 // request response. These tasks cannot be invoked from the UI thread.
82 // - FaviconServiceTask: base class for asynchronous requests that make use of
83 // Chromium's favicon service. See AsyncServiceRequest for more details.
85 // - HistoryProviderTask: base class for asynchronous requests that make use of
86 // AndroidHistoryProviderService. See AsyncServiceRequest for mode details.
88 // - SearchTermTask: base class for asynchronous requests that involve the
89 // search term API. Works in the same way as HistoryProviderTask.
93 const char kDefaultUrlScheme[] = "http://";
94 const int64 kInvalidContentProviderId = 0;
95 const int64 kInvalidBookmarkId = -1;
97 // ------------- Java-related utility methods ------------- //
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) {
109 JNIEnv* env = AttachCurrentThread();
110 ScopedJavaLocalRef<jstring> url;
112 url.Reset(ConvertUTF8ToJavaString(env, node->url().spec()));
113 ScopedJavaLocalRef<jstring> title(
114 ConvertUTF16ToJavaString(env, node->GetTitle()));
117 Java_BookmarkNode_create(
118 env, node->id(), (jint) node->type(), title.obj(), url.obj(),
122 jlong ConvertJLongObjectToPrimitive(JNIEnv* env, jobject long_obj) {
123 ScopedJavaLocalRef<jclass> jlong_clazz = GetClass(env, "java/lang/Long");
124 jmethodID long_value = MethodID::Get<MethodID::TYPE_INSTANCE>(
125 env, jlong_clazz.obj(), "longValue", "()J");
126 return env->CallLongMethod(long_obj, long_value, NULL);
129 jboolean ConvertJBooleanObjectToPrimitive(JNIEnv* env, jobject boolean_object) {
130 ScopedJavaLocalRef<jclass> jboolean_clazz =
131 GetClass(env, "java/lang/Boolean");
132 jmethodID boolean_value = MethodID::Get<MethodID::TYPE_INSTANCE>(
133 env, jboolean_clazz.obj(), "booleanValue", "()Z");
134 return env->CallBooleanMethod(boolean_object, boolean_value, NULL);
137 base::Time ConvertJlongToTime(jlong value) {
138 return base::Time::UnixEpoch() +
139 base::TimeDelta::FromMilliseconds((int64)value);
142 jint ConvertJIntegerToJint(JNIEnv* env, jobject integer_obj) {
143 ScopedJavaLocalRef<jclass> jinteger_clazz =
144 GetClass(env, "java/lang/Integer");
145 jmethodID int_value = MethodID::Get<MethodID::TYPE_INSTANCE>(
146 env, jinteger_clazz.obj(), "intValue", "()I");
147 return env->CallIntMethod(integer_obj, int_value, NULL);
150 std::vector<string16> ConvertJStringArrayToString16Array(JNIEnv* env,
151 jobjectArray array) {
152 std::vector<string16> results;
154 jsize len = env->GetArrayLength(array);
155 for (int i = 0; i < len; i++) {
156 results.push_back(ConvertJavaStringToUTF16(env,
157 static_cast<jstring>(env->GetObjectArrayElement(array, i))));
163 // ------------- Utility methods used by tasks ------------- //
165 // Parse the given url and return a GURL, appending the default scheme
166 // if one is not present.
167 GURL ParseAndMaybeAppendScheme(const string16& url,
168 const char* default_scheme) {
170 if (!gurl.is_valid() && !gurl.has_scheme()) {
171 string16 refined_url(ASCIIToUTF16(default_scheme));
172 refined_url.append(url);
173 gurl = GURL(refined_url);
178 const BookmarkNode* GetChildFolderByTitle(const BookmarkNode* parent,
179 const string16& title) {
180 for (int i = 0; i < parent->child_count(); ++i) {
181 if (parent->GetChild(i)->is_folder() &&
182 parent->GetChild(i)->GetTitle() == title) {
183 return parent->GetChild(i);
189 // ------------- Synchronous task classes ------------- //
191 // Utility task to add a bookmark.
192 class AddBookmarkTask : public BookmarkModelTask {
194 explicit AddBookmarkTask(BookmarkModel* model) : BookmarkModelTask(model) {}
196 int64 Run(const string16& title,
198 const bool is_folder,
199 const int64 parent_id) {
200 int64 result = kInvalidBookmarkId;
201 RunOnUIThreadBlocking::Run(
202 base::Bind(&AddBookmarkTask::RunOnUIThread,
203 model(), title, url, is_folder, parent_id, &result));
207 static void RunOnUIThread(BookmarkModel* model,
208 const string16& title,
210 const bool is_folder,
211 const int64 parent_id,
213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
215 GURL gurl = ParseAndMaybeAppendScheme(url, kDefaultUrlScheme);
217 // Check if the bookmark already exists.
218 const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(gurl);
220 const BookmarkNode* parent_node = NULL;
222 parent_node = model->GetNodeByID(parent_id);
224 parent_node = model->bookmark_bar_node();
227 node = model->AddFolder(parent_node, parent_node->child_count(), title);
229 node = model->AddURL(parent_node, 0, title, gurl);
232 *result = node ? node ->id() : kInvalidBookmarkId;
236 DISALLOW_COPY_AND_ASSIGN(AddBookmarkTask);
239 // Utility method to remove a bookmark.
240 class RemoveBookmarkTask : public BookmarkModelObserverTask {
242 explicit RemoveBookmarkTask(BookmarkModel* model)
243 : BookmarkModelObserverTask(model),
245 id_to_delete_(kInvalidBookmarkId) {}
246 virtual ~RemoveBookmarkTask() {}
248 int Run(const int64 id) {
250 RunOnUIThreadBlocking::Run(
251 base::Bind(&RemoveBookmarkTask::RunOnUIThread, model(), id));
255 static void RunOnUIThread(BookmarkModel* model, const int64 id) {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
257 const BookmarkNode* node = model->GetNodeByID(id);
258 if (node && node->parent()) {
259 const BookmarkNode* parent_node = node->parent();
260 model->Remove(parent_node, parent_node->GetIndexOf(node));
264 // Verify that the bookmark was actually removed. Called synchronously.
265 virtual void BookmarkNodeRemoved(BookmarkModel* bookmark_model,
266 const BookmarkNode* parent,
268 const BookmarkNode* node) OVERRIDE {
269 if (bookmark_model == model() && node->id() == id_to_delete_)
277 DISALLOW_COPY_AND_ASSIGN(RemoveBookmarkTask);
280 // Utility method to remove all bookmarks.
281 class RemoveAllBookmarksTask : public BookmarkModelObserverTask {
283 explicit RemoveAllBookmarksTask(BookmarkModel* model)
284 : BookmarkModelObserverTask(model) {}
286 virtual ~RemoveAllBookmarksTask() {}
289 RunOnUIThreadBlocking::Run(
290 base::Bind(&RemoveAllBookmarksTask::RunOnUIThread, model()));
293 static void RunOnUIThread(BookmarkModel* model) {
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
299 DISALLOW_COPY_AND_ASSIGN(RemoveAllBookmarksTask);
302 // Utility method to update a bookmark.
303 class UpdateBookmarkTask : public BookmarkModelObserverTask {
305 explicit UpdateBookmarkTask(BookmarkModel* model)
306 : BookmarkModelObserverTask(model),
308 id_to_update_(kInvalidBookmarkId){}
309 virtual ~UpdateBookmarkTask() {}
311 int Run(const int64 id,
312 const string16& title,
314 const int64 parent_id) {
316 RunOnUIThreadBlocking::Run(
317 base::Bind(&UpdateBookmarkTask::RunOnUIThread,
318 model(), id, title, url, parent_id));
322 static void RunOnUIThread(BookmarkModel* model,
324 const string16& title,
326 const int64 parent_id) {
327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
328 const BookmarkNode* node = model->GetNodeByID(id);
330 if (node->GetTitle() != title)
331 model->SetTitle(node, title);
333 if (node->type() == BookmarkNode::URL) {
334 GURL bookmark_url = ParseAndMaybeAppendScheme(url, kDefaultUrlScheme);
335 if (bookmark_url != node->url())
336 model->SetURL(node, bookmark_url);
339 if (parent_id >= 0 &&
340 (!node->parent() || parent_id != node->parent()->id())) {
341 const BookmarkNode* new_parent = model->GetNodeByID(parent_id);
344 model->Move(node, new_parent, 0);
349 // Verify that the bookmark was actually updated. Called synchronously.
350 virtual void BookmarkNodeChanged(BookmarkModel* bookmark_model,
351 const BookmarkNode* node) OVERRIDE {
352 if (bookmark_model == model() && node->id() == id_to_update_)
360 DISALLOW_COPY_AND_ASSIGN(UpdateBookmarkTask);
363 // Checks if a node exists in the bookmark model.
364 class BookmarkNodeExistsTask : public BookmarkModelTask {
366 explicit BookmarkNodeExistsTask(BookmarkModel* model)
367 : BookmarkModelTask(model) {
370 bool Run(const int64 id) {
372 RunOnUIThreadBlocking::Run(
373 base::Bind(&BookmarkNodeExistsTask::RunOnUIThread,
374 model(), id, &result));
378 static void RunOnUIThread(BookmarkModel* model,
381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
383 *result = model->GetNodeByID(id) != NULL;
387 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeExistsTask);
390 // Checks if a node belongs to the Mobile Bookmarks hierarchy branch.
391 class IsInMobileBookmarksBranchTask : public BookmarkModelTask {
393 explicit IsInMobileBookmarksBranchTask(BookmarkModel* model)
394 : BookmarkModelTask(model) {}
396 bool Run(const int64 id) {
398 RunOnUIThreadBlocking::Run(
399 base::Bind(&IsInMobileBookmarksBranchTask::RunOnUIThread,
400 model(), id, &result));
404 static void RunOnUIThread(BookmarkModel* model,
407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
409 const BookmarkNode* node = model->GetNodeByID(id);
410 const BookmarkNode* mobile_node = model->mobile_node();
411 while (node && node != mobile_node)
412 node = node->parent();
414 *result = node == mobile_node;
418 DISALLOW_COPY_AND_ASSIGN(IsInMobileBookmarksBranchTask);
421 // Creates folder or retrieves its id if already exists.
422 // An invalid parent id is assumed to represent the Mobile Bookmarks folder.
423 // Can only be used to create folders inside the Mobile Bookmarks branch.
424 class CreateBookmarksFolderOnceTask : public BookmarkModelTask {
426 explicit CreateBookmarksFolderOnceTask(BookmarkModel* model)
427 : BookmarkModelTask(model) {}
429 int64 Run(const string16& title, const int64 parent_id) {
430 int64 result = kInvalidBookmarkId;
431 RunOnUIThreadBlocking::Run(
432 base::Bind(&CreateBookmarksFolderOnceTask::RunOnUIThread,
433 model(), title, parent_id, &result));
437 static void RunOnUIThread(BookmarkModel* model,
438 const string16& title,
439 const int64 parent_id,
441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
444 // Invalid ids are assumed to refer to the Mobile Bookmarks folder.
445 const BookmarkNode* parent = parent_id >= 0 ?
446 model->GetNodeByID(parent_id) : model->mobile_node();
449 bool in_mobile_bookmarks;
450 IsInMobileBookmarksBranchTask::RunOnUIThread(model, parent->id(),
451 &in_mobile_bookmarks);
452 if (!in_mobile_bookmarks) {
453 // The parent folder must be inside the Mobile Bookmarks folder.
454 *result = kInvalidBookmarkId;
458 const BookmarkNode* node = GetChildFolderByTitle(parent, title);
460 *result = node->id();
464 AddBookmarkTask::RunOnUIThread(model, title, string16(), true,
465 parent->id(), result);
469 DISALLOW_COPY_AND_ASSIGN(CreateBookmarksFolderOnceTask);
472 // Creates a Java BookmarkNode object for a node given its id.
473 class GetAllBookmarkFoldersTask : public BookmarkModelTask {
475 explicit GetAllBookmarkFoldersTask(BookmarkModel* model)
476 : BookmarkModelTask(model) {
479 void Run(ScopedJavaGlobalRef<jobject>* jroot) {
480 RunOnUIThreadBlocking::Run(
481 base::Bind(&GetAllBookmarkFoldersTask::RunOnUIThread, model(), jroot));
484 static void RunOnUIThread(BookmarkModel* model,
485 ScopedJavaGlobalRef<jobject>* jroot) {
486 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
487 const BookmarkNode* root = model->root_node();
488 if (!root || !root->is_folder())
491 // The iterative approach is not possible because ScopedGlobalJavaRefs
492 // cannot be copy-constructed, and therefore not used in STL containers.
493 ConvertFolderSubtree(AttachCurrentThread(), root,
494 ScopedJavaLocalRef<jobject>(), jroot);
498 static void ConvertFolderSubtree(JNIEnv* env,
499 const BookmarkNode* node,
500 const JavaRef<jobject>& parent_folder,
501 ScopedJavaGlobalRef<jobject>* jfolder) {
503 DCHECK(node->is_folder());
506 // Global refs should be used here for thread-safety reasons as this task
507 // might be invoked from a thread other than UI. All refs are scoped.
508 ConvertBookmarkNode(node, parent_folder, jfolder);
510 for (int i = 0; i < node->child_count(); ++i) {
511 const BookmarkNode* child = node->GetChild(i);
512 if (child->is_folder()) {
513 ScopedJavaGlobalRef<jobject> jchild;
514 ConvertFolderSubtree(env, child, *jfolder, &jchild);
516 Java_BookmarkNode_addChild(env, jfolder->obj(), jchild.obj());
517 if (ClearException(env)) {
518 LOG(WARNING) << "Java exception while adding child node.";
525 DISALLOW_COPY_AND_ASSIGN(GetAllBookmarkFoldersTask);
528 // Creates a Java BookmarkNode object for a node given its id.
529 class GetBookmarkNodeTask : public BookmarkModelTask {
531 explicit GetBookmarkNodeTask(BookmarkModel* model)
532 : BookmarkModelTask(model) {
535 void Run(const int64 id,
538 ScopedJavaGlobalRef<jobject>* jnode) {
539 return RunOnUIThreadBlocking::Run(
540 base::Bind(&GetBookmarkNodeTask::RunOnUIThread,
541 model(), id, get_parent, get_children, jnode));
544 static void RunOnUIThread(BookmarkModel* model,
548 ScopedJavaGlobalRef<jobject>* jnode) {
549 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
550 const BookmarkNode* node = model->GetNodeByID(id);
554 ScopedJavaGlobalRef<jobject> jparent;
556 ConvertBookmarkNode(node->parent(), ScopedJavaLocalRef<jobject>(),
560 ConvertBookmarkNode(node, jparent, jnode);
562 JNIEnv* env = AttachCurrentThread();
563 if (!jparent.is_null()) {
564 Java_BookmarkNode_addChild(env, jparent.obj(), jnode->obj());
565 if (ClearException(env)) {
566 LOG(WARNING) << "Java exception while adding child node.";
572 for (int i = 0; i < node->child_count(); ++i) {
573 ScopedJavaGlobalRef<jobject> jchild;
574 ConvertBookmarkNode(node->GetChild(i), *jnode, &jchild);
575 Java_BookmarkNode_addChild(env, jnode->obj(), jchild.obj());
576 if (ClearException(env)) {
577 LOG(WARNING) << "Java exception while adding child node.";
585 DISALLOW_COPY_AND_ASSIGN(GetBookmarkNodeTask);
588 // Gets the Mobile Bookmarks node. Using this task ensures the correct
589 // initialization of the bookmark model.
590 class GetMobileBookmarksNodeTask : public BookmarkModelTask {
592 explicit GetMobileBookmarksNodeTask(BookmarkModel* model)
593 : BookmarkModelTask(model) {}
595 const BookmarkNode* Run() {
596 const BookmarkNode* result = NULL;
597 RunOnUIThreadBlocking::Run(
598 base::Bind(&GetMobileBookmarksNodeTask::RunOnUIThread,
603 static void RunOnUIThread(BookmarkModel* model, const BookmarkNode** result) {
604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
606 *result = model->mobile_node();
610 DISALLOW_COPY_AND_ASSIGN(GetMobileBookmarksNodeTask);
613 // ------------- Aynchronous requests classes ------------- //
615 // Base class for asynchronous blocking requests to Chromium services.
616 // Service: type of the service to use (e.g. HistoryService, FaviconService).
617 template <typename Service>
618 class AsyncServiceRequest : protected BlockingUIThreadAsyncRequest {
620 AsyncServiceRequest(Service* service,
621 CancelableRequestConsumer* cancelable_consumer)
622 : service_(service), cancelable_consumer_(cancelable_consumer) {}
624 Service* service() const { return service_; }
626 CancelableRequestConsumer* cancelable_consumer() const {
627 return cancelable_consumer_;
632 CancelableRequestConsumer* cancelable_consumer_;
634 DISALLOW_COPY_AND_ASSIGN(AsyncServiceRequest);
637 // Base class for all asynchronous blocking tasks that use the favicon service.
638 class FaviconServiceTask : public AsyncServiceRequest<FaviconService> {
640 FaviconServiceTask(FaviconService* service,
642 CancelableRequestConsumer* cancelable_consumer,
643 CancelableTaskTracker* cancelable_tracker)
644 : AsyncServiceRequest<FaviconService>(service, cancelable_consumer),
646 cancelable_tracker_(cancelable_tracker) {}
648 Profile* profile() const { return profile_; }
649 CancelableTaskTracker* cancelable_tracker() const {
650 return cancelable_tracker_;
655 CancelableTaskTracker* cancelable_tracker_;
657 DISALLOW_COPY_AND_ASSIGN(FaviconServiceTask);
660 // Retrieves the favicon or touch icon for a URL from the FaviconService.
661 class BookmarkIconFetchTask : public FaviconServiceTask {
663 BookmarkIconFetchTask(
664 FaviconService* favicon_service,
666 CancelableRequestConsumer* cancelable_consumer,
667 CancelableTaskTracker* cancelable_tracker)
668 : FaviconServiceTask(favicon_service, profile,
669 cancelable_consumer, cancelable_tracker) {}
671 chrome::FaviconBitmapResult Run(const GURL& url) {
672 RunAsyncRequestOnUIThreadBlocking(
673 base::Bind(&FaviconService::GetRawFaviconForURL,
674 base::Unretained(service()),
675 FaviconService::FaviconForURLParams(
678 chrome::FAVICON | chrome::TOUCH_ICON,
680 ResourceBundle::GetSharedInstance().GetMaxScaleFactor(),
682 &BookmarkIconFetchTask::OnFaviconRetrieved,
683 base::Unretained(this)),
684 cancelable_tracker()));
689 void OnFaviconRetrieved(const chrome::FaviconBitmapResult& bitmap_result) {
690 result_ = bitmap_result;
694 chrome::FaviconBitmapResult result_;
696 DISALLOW_COPY_AND_ASSIGN(BookmarkIconFetchTask);
699 // Base class for all asynchronous blocking tasks that use the Android history
701 class HistoryProviderTask
702 : public AsyncServiceRequest<AndroidHistoryProviderService> {
704 HistoryProviderTask(AndroidHistoryProviderService* service,
705 CancelableRequestConsumer* cancelable_consumer)
706 : AsyncServiceRequest<AndroidHistoryProviderService>
707 (service, cancelable_consumer) {}
710 DISALLOW_COPY_AND_ASSIGN(HistoryProviderTask);
713 // Adds a bookmark from the API.
714 class AddBookmarkFromAPITask : public HistoryProviderTask {
716 AddBookmarkFromAPITask(AndroidHistoryProviderService* service,
717 CancelableRequestConsumer* cancelable_consumer)
718 : HistoryProviderTask(service, cancelable_consumer) {}
720 history::URLID Run(const history::HistoryAndBookmarkRow& row) {
721 RunAsyncRequestOnUIThreadBlocking(
722 base::Bind(&AndroidHistoryProviderService::InsertHistoryAndBookmark,
723 base::Unretained(service()), row, cancelable_consumer(),
724 base::Bind(&AddBookmarkFromAPITask::OnBookmarkInserted,
725 base::Unretained(this))));
730 void OnBookmarkInserted(AndroidHistoryProviderService::Handle handle,
733 // Note that here 0 means an invalid id too.
734 // This is because it represents a SQLite database row id.
739 history::URLID result_;
741 DISALLOW_COPY_AND_ASSIGN(AddBookmarkFromAPITask);
744 // Queries bookmarks from the API.
745 class QueryBookmarksFromAPITask : public HistoryProviderTask {
747 QueryBookmarksFromAPITask(AndroidHistoryProviderService* service,
748 CancelableRequestConsumer* cancelable_consumer)
749 : HistoryProviderTask(service, cancelable_consumer),
752 history::AndroidStatement* Run(
753 const std::vector<history::HistoryAndBookmarkRow::ColumnID>& projections,
754 const std::string& selection,
755 const std::vector<string16>& selection_args,
756 const std::string& sort_order) {
757 RunAsyncRequestOnUIThreadBlocking(
758 base::Bind(&AndroidHistoryProviderService::QueryHistoryAndBookmarks,
759 base::Unretained(service()), projections, selection,
760 selection_args, sort_order, cancelable_consumer(),
761 base::Bind(&QueryBookmarksFromAPITask::OnBookmarksQueried,
762 base::Unretained(this))));
767 void OnBookmarksQueried(AndroidHistoryProviderService::Handle handle,
769 history::AndroidStatement* statement) {
774 history::AndroidStatement* result_;
776 DISALLOW_COPY_AND_ASSIGN(QueryBookmarksFromAPITask);
779 // Updates bookmarks from the API.
780 class UpdateBookmarksFromAPITask : public HistoryProviderTask {
782 UpdateBookmarksFromAPITask(AndroidHistoryProviderService* service,
783 CancelableRequestConsumer* cancelable_consumer)
784 : HistoryProviderTask(service, cancelable_consumer),
787 int Run(const history::HistoryAndBookmarkRow& row,
788 const std::string& selection,
789 const std::vector<string16>& selection_args) {
790 RunAsyncRequestOnUIThreadBlocking(
791 base::Bind(&AndroidHistoryProviderService::UpdateHistoryAndBookmarks,
792 base::Unretained(service()), row, selection,
793 selection_args, cancelable_consumer(),
794 base::Bind(&UpdateBookmarksFromAPITask::OnBookmarksUpdated,
795 base::Unretained(this))));
800 void OnBookmarksUpdated(AndroidHistoryProviderService::Handle handle,
802 int updated_row_count) {
803 result_ = updated_row_count;
809 DISALLOW_COPY_AND_ASSIGN(UpdateBookmarksFromAPITask);
812 // Removes bookmarks from the API.
813 class RemoveBookmarksFromAPITask : public HistoryProviderTask {
815 RemoveBookmarksFromAPITask(AndroidHistoryProviderService* service,
816 CancelableRequestConsumer* cancelable_consumer)
817 : HistoryProviderTask(service, cancelable_consumer),
820 int Run(const std::string& selection,
821 const std::vector<string16>& selection_args) {
822 RunAsyncRequestOnUIThreadBlocking(
823 base::Bind(&AndroidHistoryProviderService::DeleteHistoryAndBookmarks,
824 base::Unretained(service()), selection, selection_args,
825 cancelable_consumer(),
826 base::Bind(&RemoveBookmarksFromAPITask::OnBookmarksRemoved,
827 base::Unretained(this))));
832 void OnBookmarksRemoved(AndroidHistoryProviderService::Handle handle,
834 int removed_row_count) {
835 result_ = removed_row_count;
841 DISALLOW_COPY_AND_ASSIGN(RemoveBookmarksFromAPITask);
844 // Removes history from the API.
845 class RemoveHistoryFromAPITask : public HistoryProviderTask {
847 RemoveHistoryFromAPITask(AndroidHistoryProviderService* service,
848 CancelableRequestConsumer* cancelable_consumer)
849 : HistoryProviderTask(service, cancelable_consumer),
852 int Run(const std::string& selection,
853 const std::vector<string16>& selection_args) {
854 RunAsyncRequestOnUIThreadBlocking(
855 base::Bind(&AndroidHistoryProviderService::DeleteHistory,
856 base::Unretained(service()), selection,
857 selection_args, cancelable_consumer(),
858 base::Bind(&RemoveHistoryFromAPITask::OnHistoryRemoved,
859 base::Unretained(this))));
864 void OnHistoryRemoved(AndroidHistoryProviderService::Handle handle,
866 int removed_row_count) {
867 result_ = removed_row_count;
873 DISALLOW_COPY_AND_ASSIGN(RemoveHistoryFromAPITask);
876 // This class provides the common method for the SearchTermAPIHelper.
877 class SearchTermTask : public HistoryProviderTask {
879 SearchTermTask(AndroidHistoryProviderService* service,
880 CancelableRequestConsumer* cancelable_consumer,
882 : HistoryProviderTask(service, cancelable_consumer),
885 // Fill SearchRow's template_url_id and url fields according the given
886 // search_term. Return true if succeeded.
887 void BuildSearchRow(history::SearchRow* row) {
888 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
890 TemplateURLService* template_service =
891 TemplateURLServiceFactory::GetForProfile(profile_);
892 template_service->Load();
894 const TemplateURL* search_engine =
895 template_service->GetDefaultSearchProvider();
897 const TemplateURLRef* search_url = &search_engine->url_ref();
898 TemplateURLRef::SearchTermsArgs search_terms_args(row->search_term());
899 search_terms_args.append_extra_query_params = true;
900 std::string url = search_url->ReplaceSearchTerms(search_terms_args);
902 row->set_url(GURL(url));
903 row->set_template_url_id(search_engine->id());
911 DISALLOW_COPY_AND_ASSIGN(SearchTermTask);
914 // Adds a search term from the API.
915 class AddSearchTermFromAPITask : public SearchTermTask {
917 AddSearchTermFromAPITask(AndroidHistoryProviderService* service,
918 CancelableRequestConsumer* cancelable_consumer,
920 : SearchTermTask(service, cancelable_consumer, profile) {}
922 history::URLID Run(const history::SearchRow& row) {
923 RunAsyncRequestOnUIThreadBlocking(
924 base::Bind(&AddSearchTermFromAPITask::MakeRequestOnUIThread,
925 base::Unretained(this), row));
930 void MakeRequestOnUIThread(const history::SearchRow& row) {
931 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
932 history::SearchRow internal_row = row;
933 BuildSearchRow(&internal_row);
934 service()->InsertSearchTerm(internal_row, cancelable_consumer(),
935 base::Bind(&AddSearchTermFromAPITask::OnSearchTermInserted,
936 base::Unretained(this)));
939 void OnSearchTermInserted(AndroidHistoryProviderService::Handle handle,
942 // Note that here 0 means an invalid id too.
943 // This is because it represents a SQLite database row id.
948 history::URLID result_;
950 DISALLOW_COPY_AND_ASSIGN(AddSearchTermFromAPITask);
953 // Queries search terms from the API.
954 class QuerySearchTermsFromAPITask : public SearchTermTask {
956 QuerySearchTermsFromAPITask(AndroidHistoryProviderService* service,
957 CancelableRequestConsumer* cancelable_consumer,
959 : SearchTermTask(service, cancelable_consumer, profile),
962 history::AndroidStatement* Run(
963 const std::vector<history::SearchRow::ColumnID>& projections,
964 const std::string& selection,
965 const std::vector<string16>& selection_args,
966 const std::string& sort_order) {
967 RunAsyncRequestOnUIThreadBlocking(
968 base::Bind(&AndroidHistoryProviderService::QuerySearchTerms,
969 base::Unretained(service()), projections, selection,
970 selection_args, sort_order, cancelable_consumer(),
972 &QuerySearchTermsFromAPITask::OnSearchTermsQueried,
973 base::Unretained(this))));
978 // Callback to return the result.
979 void OnSearchTermsQueried(AndroidHistoryProviderService::Handle handle,
981 history::AndroidStatement* statement) {
986 history::AndroidStatement* result_;
988 DISALLOW_COPY_AND_ASSIGN(QuerySearchTermsFromAPITask);
991 // Updates search terms from the API.
992 class UpdateSearchTermsFromAPITask : public SearchTermTask {
994 UpdateSearchTermsFromAPITask(AndroidHistoryProviderService* service,
995 CancelableRequestConsumer* cancelable_consumer,
997 : SearchTermTask(service, cancelable_consumer, profile),
1000 int Run(const history::SearchRow& row,
1001 const std::string& selection,
1002 const std::vector<string16>& selection_args) {
1003 RunAsyncRequestOnUIThreadBlocking(
1004 base::Bind(&UpdateSearchTermsFromAPITask::MakeRequestOnUIThread,
1005 base::Unretained(this), row, selection, selection_args));
1010 void MakeRequestOnUIThread(const history::SearchRow& row,
1011 const std::string& selection,
1012 const std::vector<string16>& selection_args) {
1013 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1014 history::SearchRow internal_row = row;
1015 BuildSearchRow(&internal_row);
1016 service()->UpdateSearchTerms(
1020 cancelable_consumer(),
1021 base::Bind(&UpdateSearchTermsFromAPITask::OnSearchTermsUpdated,
1022 base::Unretained(this)));
1026 void OnSearchTermsUpdated(AndroidHistoryProviderService::Handle handle,
1028 int updated_row_count) {
1029 result_ = updated_row_count;
1035 DISALLOW_COPY_AND_ASSIGN(UpdateSearchTermsFromAPITask);
1038 // Removes search terms from the API.
1039 class RemoveSearchTermsFromAPITask : public SearchTermTask {
1041 RemoveSearchTermsFromAPITask(AndroidHistoryProviderService* service,
1042 CancelableRequestConsumer* cancelable_consumer,
1044 : SearchTermTask(service, cancelable_consumer, profile), result_() {}
1046 int Run(const std::string& selection,
1047 const std::vector<string16>& selection_args) {
1048 RunAsyncRequestOnUIThreadBlocking(
1049 base::Bind(&AndroidHistoryProviderService::DeleteSearchTerms,
1050 base::Unretained(service()), selection, selection_args,
1051 cancelable_consumer(),
1053 &RemoveSearchTermsFromAPITask::OnSearchTermsDeleted,
1054 base::Unretained(this))));
1059 void OnSearchTermsDeleted(AndroidHistoryProviderService::Handle handle,
1061 int deleted_row_count) {
1062 result_ = deleted_row_count;
1068 DISALLOW_COPY_AND_ASSIGN(RemoveSearchTermsFromAPITask);
1071 // ------------- Other utility methods (may use tasks) ------------- //
1073 // Fills the bookmark |row| with the given java objects.
1074 void FillBookmarkRow(JNIEnv* env,
1084 history::HistoryAndBookmarkRow* row,
1085 BookmarkModel* model) {
1086 // Needed because of the internal bookmark model task invocation.
1087 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
1090 string16 raw_url = ConvertJavaStringToUTF16(env, url);
1091 // GURL doesn't accept the URL without protocol, but the Android CTS
1092 // allows it. We are trying to prefix with 'http://' to see whether
1093 // GURL thinks it is a valid URL. The original url will be stored in
1094 // history::BookmarkRow.raw_url_.
1095 GURL gurl = ParseAndMaybeAppendScheme(raw_url, kDefaultUrlScheme);
1097 row->set_raw_url(UTF16ToUTF8(raw_url));
1101 row->set_created(ConvertJlongToTime(
1102 ConvertJLongObjectToPrimitive(env, created)));
1105 row->set_is_bookmark(ConvertJBooleanObjectToPrimitive(env, isBookmark));
1108 row->set_last_visit_time(ConvertJlongToTime(ConvertJLongObjectToPrimitive(
1112 std::vector<uint8> bytes;
1113 base::android::JavaByteArrayToByteVector(env, favicon, &bytes);
1114 row->set_favicon(base::RefCountedBytes::TakeVector(&bytes));
1118 row->set_title(ConvertJavaStringToUTF16(env, title));
1121 row->set_visit_count(ConvertJIntegerToJint(env, visits));
1123 // Make sure parent_id is always in the mobile_node branch.
1124 IsInMobileBookmarksBranchTask task(model);
1125 if (task.Run(parent_id))
1126 row->set_parent_id(parent_id);
1129 // Fills the bookmark |row| with the given java objects if it is not null.
1130 void FillSearchRow(JNIEnv* env,
1132 jstring search_term,
1134 history::SearchRow* row) {
1136 row->set_search_term(ConvertJavaStringToUTF16(env, search_term));
1139 row->set_search_time(ConvertJlongToTime(ConvertJLongObjectToPrimitive(
1145 // ------------- Native initialization and destruction ------------- //
1147 static jint Init(JNIEnv* env, jobject obj) {
1148 ChromeBrowserProvider* provider = new ChromeBrowserProvider(env, obj);
1149 return reinterpret_cast<jint>(provider);
1152 bool ChromeBrowserProvider::RegisterChromeBrowserProvider(JNIEnv* env) {
1153 return RegisterNativesImpl(env);
1156 ChromeBrowserProvider::ChromeBrowserProvider(JNIEnv* env, jobject obj)
1157 : weak_java_provider_(env, obj),
1158 handling_extensive_changes_(false) {
1159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1160 profile_ = g_browser_process->profile_manager()->GetLastUsedProfile();
1161 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile_);
1162 top_sites_ = profile_->GetTopSites();
1163 service_.reset(new AndroidHistoryProviderService(profile_));
1164 favicon_service_.reset(FaviconServiceFactory::GetForProfile(profile_,
1165 Profile::EXPLICIT_ACCESS));
1167 // Registers the notifications we are interested.
1168 bookmark_model_->AddObserver(this);
1169 notification_registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED,
1170 content::NotificationService::AllSources());
1171 notification_registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
1172 content::NotificationService::AllSources());
1173 notification_registrar_.Add(this,
1174 chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
1175 content::NotificationService::AllSources());
1176 TemplateURLService* template_service =
1177 TemplateURLServiceFactory::GetForProfile(profile_);
1178 if (!template_service->loaded())
1179 template_service->Load();
1182 ChromeBrowserProvider::~ChromeBrowserProvider() {
1183 bookmark_model_->RemoveObserver(this);
1186 void ChromeBrowserProvider::Destroy(JNIEnv*, jobject) {
1190 // ------------- Provider public APIs ------------- //
1192 jlong ChromeBrowserProvider::AddBookmark(JNIEnv* env,
1200 url = ConvertJavaStringToUTF16(env, jurl);
1201 string16 title = ConvertJavaStringToUTF16(env, jtitle);
1203 AddBookmarkTask task(bookmark_model_);
1204 return task.Run(title, url, is_folder, parent_id);
1207 jint ChromeBrowserProvider::RemoveBookmark(JNIEnv*, jobject, jlong id) {
1208 RemoveBookmarkTask task(bookmark_model_);
1209 return task.Run(id);
1212 jint ChromeBrowserProvider::UpdateBookmark(JNIEnv* env,
1220 url = ConvertJavaStringToUTF16(env, jurl);
1221 string16 title = ConvertJavaStringToUTF16(env, jtitle);
1223 UpdateBookmarkTask task(bookmark_model_);
1224 return task.Run(id, title, url, parent_id);
1227 // Add the bookmark with the given column values.
1228 jlong ChromeBrowserProvider::AddBookmarkFromAPI(JNIEnv* env,
1240 history::HistoryAndBookmarkRow row;
1241 FillBookmarkRow(env, obj, url, created, isBookmark, date, favicon, title,
1242 visits, parent_id, &row, bookmark_model_);
1244 // URL must be valid.
1245 if (row.url().is_empty()) {
1246 LOG(ERROR) << "Not a valid URL " << row.raw_url();
1247 return kInvalidContentProviderId;
1250 AddBookmarkFromAPITask task(service_.get(), &android_history_consumer_);
1251 return task.Run(row);
1254 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::QueryBookmarkFromAPI(
1257 jobjectArray projection,
1259 jobjectArray selection_args,
1260 jstring sort_order) {
1261 // Converts the projection to array of ColumnID and column name.
1262 // Used to store the projection column ID according their sequence.
1263 std::vector<history::HistoryAndBookmarkRow::ColumnID> query_columns;
1264 // Used to store the projection column names according their sequence.
1265 std::vector<std::string> columns_name;
1267 jsize len = env->GetArrayLength(projection);
1268 for (int i = 0; i < len; i++) {
1269 std::string name = ConvertJavaStringToUTF8(env, static_cast<jstring>(
1270 env->GetObjectArrayElement(projection, i)));
1271 history::HistoryAndBookmarkRow::ColumnID id =
1272 history::HistoryAndBookmarkRow::GetColumnID(name);
1273 if (id == history::HistoryAndBookmarkRow::COLUMN_END) {
1274 // Ignore the unknown column; As Android platform will send us
1275 // the non public column.
1278 query_columns.push_back(id);
1279 columns_name.push_back(name);
1283 std::vector<string16> where_args =
1284 ConvertJStringArrayToString16Array(env, selection_args);
1286 std::string where_clause;
1288 where_clause = ConvertJavaStringToUTF8(env, selections);
1291 std::string sort_clause;
1293 sort_clause = ConvertJavaStringToUTF8(env, sort_order);
1296 QueryBookmarksFromAPITask task(service_.get(), &android_history_consumer_);
1297 history::AndroidStatement* statement = task.Run(
1298 query_columns, where_clause, where_args, sort_clause);
1300 return ScopedJavaLocalRef<jobject>();
1302 // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
1304 return SQLiteCursor::NewJavaSqliteCursor(env, columns_name, statement,
1305 service_.get(), favicon_service_.get());
1308 // Updates the bookmarks with the given column values. The value is not given if
1310 jint ChromeBrowserProvider::UpdateBookmarkFromAPI(JNIEnv* env,
1321 jobjectArray selection_args) {
1322 history::HistoryAndBookmarkRow row;
1323 FillBookmarkRow(env, obj, url, created, isBookmark, date, favicon, title,
1324 visits, parent_id, &row, bookmark_model_);
1326 std::vector<string16> where_args =
1327 ConvertJStringArrayToString16Array(env, selection_args);
1329 std::string where_clause;
1331 where_clause = ConvertJavaStringToUTF8(env, selections);
1333 UpdateBookmarksFromAPITask task(service_.get(), &android_history_consumer_);
1334 return task.Run(row, where_clause, where_args);
1337 jint ChromeBrowserProvider::RemoveBookmarkFromAPI(JNIEnv* env,
1340 jobjectArray selection_args) {
1341 std::vector<string16> where_args =
1342 ConvertJStringArrayToString16Array(env, selection_args);
1344 std::string where_clause;
1346 where_clause = ConvertJavaStringToUTF8(env, selections);
1348 RemoveBookmarksFromAPITask task(service_.get(), &android_history_consumer_);
1349 return task.Run(where_clause, where_args);
1352 jint ChromeBrowserProvider::RemoveHistoryFromAPI(JNIEnv* env,
1355 jobjectArray selection_args) {
1356 std::vector<string16> where_args =
1357 ConvertJStringArrayToString16Array(env, selection_args);
1359 std::string where_clause;
1361 where_clause = ConvertJavaStringToUTF8(env, selections);
1363 RemoveHistoryFromAPITask task(service_.get(), &android_history_consumer_);
1364 return task.Run(where_clause, where_args);
1367 // Add the search term with the given column values. The value is not given if
1369 jlong ChromeBrowserProvider::AddSearchTermFromAPI(JNIEnv* env,
1371 jstring search_term,
1373 DCHECK(search_term);
1375 history::SearchRow row;
1376 FillSearchRow(env, obj, search_term, date, &row);
1378 // URL must be valid.
1379 if (row.search_term().empty()) {
1380 LOG(ERROR) << "Search term is empty.";
1381 return kInvalidContentProviderId;
1384 AddSearchTermFromAPITask task(service_.get(), &android_history_consumer_,
1386 return task.Run(row);
1389 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::QuerySearchTermFromAPI(
1392 jobjectArray projection,
1394 jobjectArray selection_args,
1395 jstring sort_order) {
1396 // Converts the projection to array of ColumnID and column name.
1397 // Used to store the projection column ID according their sequence.
1398 std::vector<history::SearchRow::ColumnID> query_columns;
1399 // Used to store the projection column names according their sequence.
1400 std::vector<std::string> columns_name;
1402 jsize len = env->GetArrayLength(projection);
1403 for (int i = 0; i < len; i++) {
1404 std::string name = ConvertJavaStringToUTF8(env, static_cast<jstring>(
1405 env->GetObjectArrayElement(projection, i)));
1406 history::SearchRow::ColumnID id =
1407 history::SearchRow::GetColumnID(name);
1408 if (id == history::SearchRow::COLUMN_END) {
1409 LOG(ERROR) << "Can not find " << name;
1410 return ScopedJavaLocalRef<jobject>();
1412 query_columns.push_back(id);
1413 columns_name.push_back(name);
1417 std::vector<string16> where_args =
1418 ConvertJStringArrayToString16Array(env, selection_args);
1420 std::string where_clause;
1422 where_clause = ConvertJavaStringToUTF8(env, selections);
1425 std::string sort_clause;
1427 sort_clause = ConvertJavaStringToUTF8(env, sort_order);
1430 QuerySearchTermsFromAPITask task(service_.get(), &android_history_consumer_,
1432 history::AndroidStatement* statement = task.Run(
1433 query_columns, where_clause, where_args, sort_clause);
1435 return ScopedJavaLocalRef<jobject>();
1436 // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
1438 return SQLiteCursor::NewJavaSqliteCursor(env, columns_name, statement,
1439 service_.get(), favicon_service_.get());
1442 // Updates the search terms with the given column values. The value is not
1443 // given if it is NULL.
1444 jint ChromeBrowserProvider::UpdateSearchTermFromAPI(
1445 JNIEnv* env, jobject obj, jstring search_term, jobject date,
1446 jstring selections, jobjectArray selection_args) {
1447 history::SearchRow row;
1448 FillSearchRow(env, obj, search_term, date, &row);
1450 std::vector<string16> where_args = ConvertJStringArrayToString16Array(
1451 env, selection_args);
1453 std::string where_clause;
1455 where_clause = ConvertJavaStringToUTF8(env, selections);
1457 UpdateSearchTermsFromAPITask task(service_.get(), &android_history_consumer_,
1459 return task.Run(row, where_clause, where_args);
1462 jint ChromeBrowserProvider::RemoveSearchTermFromAPI(
1463 JNIEnv* env, jobject obj, jstring selections, jobjectArray selection_args) {
1464 std::vector<string16> where_args =
1465 ConvertJStringArrayToString16Array(env, selection_args);
1467 std::string where_clause;
1469 where_clause = ConvertJavaStringToUTF8(env, selections);
1471 RemoveSearchTermsFromAPITask task(service_.get(), &android_history_consumer_,
1473 return task.Run(where_clause, where_args);
1476 // ------------- Provider custom APIs ------------- //
1478 jboolean ChromeBrowserProvider::BookmarkNodeExists(
1482 BookmarkNodeExistsTask task(bookmark_model_);
1483 return task.Run(id);
1486 jlong ChromeBrowserProvider::CreateBookmarksFolderOnce(
1491 string16 title = ConvertJavaStringToUTF16(env, jtitle);
1493 return kInvalidBookmarkId;
1495 CreateBookmarksFolderOnceTask task(bookmark_model_);
1496 return task.Run(title, parent_id);
1499 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::GetAllBookmarkFolders(
1502 ScopedJavaGlobalRef<jobject> jroot;
1503 GetAllBookmarkFoldersTask task(bookmark_model_);
1505 return ScopedJavaLocalRef<jobject>(jroot);
1508 void ChromeBrowserProvider::RemoveAllBookmarks(JNIEnv* env, jobject obj) {
1509 RemoveAllBookmarksTask task(bookmark_model_);
1513 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::GetBookmarkNode(
1514 JNIEnv* env, jobject obj, jlong id, jboolean get_parent,
1515 jboolean get_children) {
1516 ScopedJavaGlobalRef<jobject> jnode;
1517 GetBookmarkNodeTask task(bookmark_model_);
1518 task.Run(id, get_parent, get_children, &jnode);
1519 return ScopedJavaLocalRef<jobject>(jnode);
1522 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::GetMobileBookmarksFolder(
1525 ScopedJavaGlobalRef<jobject> jnode;
1526 GetMobileBookmarksNodeTask task(bookmark_model_);
1527 ConvertBookmarkNode(task.Run(), ScopedJavaLocalRef<jobject>(), &jnode);
1528 return ScopedJavaLocalRef<jobject>(jnode);
1531 jboolean ChromeBrowserProvider::IsBookmarkInMobileBookmarksBranch(
1535 IsInMobileBookmarksBranchTask task(bookmark_model_);
1536 return task.Run(id);
1539 ScopedJavaLocalRef<jbyteArray> ChromeBrowserProvider::GetFaviconOrTouchIcon(
1540 JNIEnv* env, jobject obj, jstring jurl) {
1542 return ScopedJavaLocalRef<jbyteArray>();
1544 GURL url = GURL(ConvertJavaStringToUTF16(env, jurl));
1545 BookmarkIconFetchTask favicon_task(favicon_service_.get(),
1548 &cancelable_task_tracker_);
1549 chrome::FaviconBitmapResult bitmap_result = favicon_task.Run(url);
1551 if (!bitmap_result.is_valid() || !bitmap_result.bitmap_data.get())
1552 return ScopedJavaLocalRef<jbyteArray>();
1554 return base::android::ToJavaByteArray(env, bitmap_result.bitmap_data->front(),
1555 bitmap_result.bitmap_data->size());
1558 ScopedJavaLocalRef<jbyteArray> ChromeBrowserProvider::GetThumbnail(
1559 JNIEnv* env, jobject obj, jstring jurl) {
1561 return ScopedJavaLocalRef<jbyteArray>();
1562 GURL url = GURL(ConvertJavaStringToUTF16(env, jurl));
1564 // GetPageThumbnail is synchronous and can be called from any thread.
1565 scoped_refptr<base::RefCountedMemory> thumbnail;
1567 top_sites_->GetPageThumbnail(url, false, &thumbnail);
1569 if (!thumbnail.get() || !thumbnail->front()) {
1570 return ScopedJavaLocalRef<jbyteArray>();
1573 return base::android::ToJavaByteArray(env, thumbnail->front(),
1577 // ------------- Observer-related methods ------------- //
1579 void ChromeBrowserProvider::ExtensiveBookmarkChangesBeginning(
1580 BookmarkModel* model) {
1581 handling_extensive_changes_ = true;
1584 void ChromeBrowserProvider::ExtensiveBookmarkChangesEnded(
1585 BookmarkModel* model) {
1586 handling_extensive_changes_ = false;
1587 BookmarkModelChanged();
1590 void ChromeBrowserProvider::BookmarkModelChanged() {
1591 if (handling_extensive_changes_)
1594 JNIEnv* env = AttachCurrentThread();
1595 ScopedJavaLocalRef<jobject> obj = weak_java_provider_.get(env);
1599 Java_ChromeBrowserProvider_onBookmarkChanged(env, obj.obj());
1602 void ChromeBrowserProvider::Observe(
1604 const content::NotificationSource& source,
1605 const content::NotificationDetails& details) {
1606 if (type == chrome::NOTIFICATION_HISTORY_URL_VISITED ||
1607 type == chrome::NOTIFICATION_HISTORY_URLS_DELETED) {
1608 JNIEnv* env = AttachCurrentThread();
1609 ScopedJavaLocalRef<jobject> obj = weak_java_provider_.get(env);
1612 Java_ChromeBrowserProvider_onBookmarkChanged(env, obj.obj());
1614 chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED) {
1615 JNIEnv* env = AttachCurrentThread();
1616 ScopedJavaLocalRef<jobject> obj = weak_java_provider_.get(env);
1619 Java_ChromeBrowserProvider_onSearchTermChanged(env, obj.obj());