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"
11 #include "base/android/jni_android.h"
12 #include "base/android/jni_array.h"
13 #include "base/android/jni_string.h"
14 #include "base/logging.h"
15 #include "base/memory/ref_counted_memory.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/task/cancelable_task_tracker.h"
18 #include "base/time/time.h"
19 #include "chrome/browser/android/provider/blocking_ui_thread_async_request.h"
20 #include "chrome/browser/android/provider/bookmark_model_observer_task.h"
21 #include "chrome/browser/android/provider/run_on_ui_thread_blocking.h"
22 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
23 #include "chrome/browser/bookmarks/chrome_bookmark_client.h"
24 #include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
25 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/chrome_notification_types.h"
27 #include "chrome/browser/favicon/favicon_service.h"
28 #include "chrome/browser/favicon/favicon_service_factory.h"
29 #include "chrome/browser/history/android/sqlite_cursor.h"
30 #include "chrome/browser/history/history_service_factory.h"
31 #include "chrome/browser/history/top_sites.h"
32 #include "chrome/browser/profiles/profile.h"
33 #include "chrome/browser/profiles/profile_manager.h"
34 #include "chrome/browser/search_engines/template_url_service_factory.h"
35 #include "components/bookmarks/browser/bookmark_model.h"
36 #include "components/bookmarks/browser/bookmark_utils.h"
37 #include "components/history/core/android/android_history_types.h"
38 #include "components/search_engines/template_url.h"
39 #include "components/search_engines/template_url_service.h"
40 #include "content/public/browser/browser_thread.h"
41 #include "content/public/browser/notification_service.h"
42 #include "jni/ChromeBrowserProvider_jni.h"
43 #include "sql/statement.h"
44 #include "ui/base/layout.h"
45 #include "ui/base/resource/resource_bundle.h"
46 #include "ui/gfx/favicon_size.h"
48 using base::android::AttachCurrentThread
;
49 using base::android::CheckException
;
50 using base::android::ClearException
;
51 using base::android::ConvertJavaStringToUTF16
;
52 using base::android::ConvertJavaStringToUTF8
;
53 using base::android::ConvertUTF8ToJavaString
;
54 using base::android::ConvertUTF16ToJavaString
;
55 using base::android::GetClass
;
56 using base::android::MethodID
;
57 using base::android::JavaRef
;
58 using base::android::ScopedJavaGlobalRef
;
59 using base::android::ScopedJavaLocalRef
;
60 using content::BrowserThread
;
62 // After refactoring the following class hierarchy has been created in order
63 // to avoid repeating code again for the same basic kind of tasks, to enforce
64 // the correct thread usage and to prevent known race conditions and deadlocks.
66 // - RunOnUIThreadBlocking: auxiliary class to run methods in the UI thread
67 // blocking the current one until finished. Because of the provider threading
68 // expectations this cannot be used from the UI thread.
70 // - BookmarkModelTask: base class for all tasks that operate in any way with
71 // the bookmark model. This class ensures that the model is loaded and
72 // prevents possible deadlocks. Derived classes should make use of
73 // RunOnUIThreadBlocking to perform any manipulation of the bookmark model in
74 // the UI thread. The Run method of these tasks cannot be invoked directly
75 // from the UI thread, but RunOnUIThread can be safely used from the UI
76 // thread code of other BookmarkModelTasks.
78 // - AsyncServiceRequest: base class for any asynchronous requests made to a
79 // Chromium service that require to block the current thread until completed.
80 // Derived classes should make use of RunAsyncRequestOnUIThreadBlocking to
81 // post their requests in the UI thread and return the results synchronously.
82 // All derived classes MUST ALWAYS call RequestCompleted when receiving the
83 // request response. These tasks cannot be invoked from the UI thread.
85 // - FaviconServiceTask: base class for asynchronous requests that make use of
86 // Chromium's favicon service. See AsyncServiceRequest for more details.
88 // - HistoryProviderTask: base class for asynchronous requests that make use of
89 // AndroidHistoryProviderService. See AsyncServiceRequest for mode details.
91 // - SearchTermTask: base class for asynchronous requests that involve the
92 // search term API. Works in the same way as HistoryProviderTask.
96 const char kDefaultUrlScheme
[] = "http://";
97 const int64 kInvalidContentProviderId
= 0;
98 const int64 kInvalidBookmarkId
= -1;
100 // ------------- Java-related utility methods ------------- //
102 // Convert a BookmarkNode, |node|, to the java representation of a bookmark node
103 // stored in |*jnode|. Parent node information is optional.
104 void ConvertBookmarkNode(
105 const BookmarkNode
* node
,
106 const JavaRef
<jobject
>& parent_node
,
107 ScopedJavaGlobalRef
<jobject
>* jnode
) {
112 JNIEnv
* env
= AttachCurrentThread();
113 ScopedJavaLocalRef
<jstring
> url
;
115 url
.Reset(ConvertUTF8ToJavaString(env
, node
->url().spec()));
116 ScopedJavaLocalRef
<jstring
> title(
117 ConvertUTF16ToJavaString(env
, node
->GetTitle()));
120 Java_BookmarkNode_create(
121 env
, node
->id(), (jint
) node
->type(), title
.obj(), url
.obj(),
125 jlong
ConvertJLongObjectToPrimitive(JNIEnv
* env
, jobject long_obj
) {
126 ScopedJavaLocalRef
<jclass
> jlong_clazz
= GetClass(env
, "java/lang/Long");
127 jmethodID long_value
= MethodID::Get
<MethodID::TYPE_INSTANCE
>(
128 env
, jlong_clazz
.obj(), "longValue", "()J");
129 return env
->CallLongMethod(long_obj
, long_value
, NULL
);
132 jboolean
ConvertJBooleanObjectToPrimitive(JNIEnv
* env
, jobject boolean_object
) {
133 ScopedJavaLocalRef
<jclass
> jboolean_clazz
=
134 GetClass(env
, "java/lang/Boolean");
135 jmethodID boolean_value
= MethodID::Get
<MethodID::TYPE_INSTANCE
>(
136 env
, jboolean_clazz
.obj(), "booleanValue", "()Z");
137 return env
->CallBooleanMethod(boolean_object
, boolean_value
, NULL
);
140 base::Time
ConvertJlongToTime(jlong value
) {
141 return base::Time::UnixEpoch() +
142 base::TimeDelta::FromMilliseconds((int64
)value
);
145 jint
ConvertJIntegerToJint(JNIEnv
* env
, jobject integer_obj
) {
146 ScopedJavaLocalRef
<jclass
> jinteger_clazz
=
147 GetClass(env
, "java/lang/Integer");
148 jmethodID int_value
= MethodID::Get
<MethodID::TYPE_INSTANCE
>(
149 env
, jinteger_clazz
.obj(), "intValue", "()I");
150 return env
->CallIntMethod(integer_obj
, int_value
, NULL
);
153 std::vector
<base::string16
> ConvertJStringArrayToString16Array(
155 jobjectArray array
) {
156 std::vector
<base::string16
> results
;
158 jsize len
= env
->GetArrayLength(array
);
159 for (int i
= 0; i
< len
; i
++) {
160 results
.push_back(ConvertJavaStringToUTF16(env
,
161 static_cast<jstring
>(env
->GetObjectArrayElement(array
, i
))));
167 // ------------- Utility methods used by tasks ------------- //
169 // Parse the given url and return a GURL, appending the default scheme
170 // if one is not present.
171 GURL
ParseAndMaybeAppendScheme(const base::string16
& url
,
172 const char* default_scheme
) {
174 if (!gurl
.is_valid() && !gurl
.has_scheme()) {
175 base::string16
refined_url(base::ASCIIToUTF16(default_scheme
));
176 refined_url
.append(url
);
177 gurl
= GURL(refined_url
);
182 const BookmarkNode
* GetChildFolderByTitle(const BookmarkNode
* parent
,
183 const base::string16
& title
) {
184 for (int i
= 0; i
< parent
->child_count(); ++i
) {
185 if (parent
->GetChild(i
)->is_folder() &&
186 parent
->GetChild(i
)->GetTitle() == title
) {
187 return parent
->GetChild(i
);
193 // ------------- Synchronous task classes ------------- //
195 // Utility task to add a bookmark.
196 class AddBookmarkTask
: public BookmarkModelTask
{
198 explicit AddBookmarkTask(BookmarkModel
* model
) : BookmarkModelTask(model
) {}
200 int64
Run(const base::string16
& title
,
201 const base::string16
& url
,
202 const bool is_folder
,
203 const int64 parent_id
) {
204 int64 result
= kInvalidBookmarkId
;
205 RunOnUIThreadBlocking::Run(
206 base::Bind(&AddBookmarkTask::RunOnUIThread
,
207 model(), title
, url
, is_folder
, parent_id
, &result
));
211 static void RunOnUIThread(BookmarkModel
* model
,
212 const base::string16
& title
,
213 const base::string16
& url
,
214 const bool is_folder
,
215 const int64 parent_id
,
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
219 GURL gurl
= ParseAndMaybeAppendScheme(url
, kDefaultUrlScheme
);
221 // Check if the bookmark already exists.
222 const BookmarkNode
* node
= model
->GetMostRecentlyAddedUserNodeForURL(gurl
);
224 const BookmarkNode
* parent_node
= NULL
;
226 parent_node
= bookmarks::GetBookmarkNodeByID(model
, parent_id
);
228 parent_node
= model
->bookmark_bar_node();
231 node
= model
->AddFolder(parent_node
, parent_node
->child_count(), title
);
233 node
= model
->AddURL(parent_node
, 0, title
, gurl
);
236 *result
= node
? node
->id() : kInvalidBookmarkId
;
240 DISALLOW_COPY_AND_ASSIGN(AddBookmarkTask
);
243 // Utility method to remove a bookmark.
244 class RemoveBookmarkTask
: public BookmarkModelObserverTask
{
246 explicit RemoveBookmarkTask(BookmarkModel
* model
)
247 : BookmarkModelObserverTask(model
),
249 id_to_delete_(kInvalidBookmarkId
) {}
250 virtual ~RemoveBookmarkTask() {}
252 int Run(const int64 id
) {
254 RunOnUIThreadBlocking::Run(
255 base::Bind(&RemoveBookmarkTask::RunOnUIThread
, model(), id
));
259 static void RunOnUIThread(BookmarkModel
* model
, const int64 id
) {
260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
261 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(model
, id
);
262 if (node
&& node
->parent()) {
263 const BookmarkNode
* parent_node
= node
->parent();
264 model
->Remove(parent_node
, parent_node
->GetIndexOf(node
));
268 // Verify that the bookmark was actually removed. Called synchronously.
269 virtual void BookmarkNodeRemoved(
270 BookmarkModel
* bookmark_model
,
271 const BookmarkNode
* parent
,
273 const BookmarkNode
* node
,
274 const std::set
<GURL
>& removed_urls
) override
{
275 if (bookmark_model
== model() && node
->id() == id_to_delete_
)
283 DISALLOW_COPY_AND_ASSIGN(RemoveBookmarkTask
);
286 // Utility method to remove all bookmarks that the user can edit.
287 class RemoveAllUserBookmarksTask
: public BookmarkModelObserverTask
{
289 explicit RemoveAllUserBookmarksTask(BookmarkModel
* model
)
290 : BookmarkModelObserverTask(model
) {}
292 virtual ~RemoveAllUserBookmarksTask() {}
295 RunOnUIThreadBlocking::Run(
296 base::Bind(&RemoveAllUserBookmarksTask::RunOnUIThread
, model()));
299 static void RunOnUIThread(BookmarkModel
* model
) {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
301 model
->RemoveAllUserBookmarks();
305 DISALLOW_COPY_AND_ASSIGN(RemoveAllUserBookmarksTask
);
308 // Utility method to update a bookmark.
309 class UpdateBookmarkTask
: public BookmarkModelObserverTask
{
311 explicit UpdateBookmarkTask(BookmarkModel
* model
)
312 : BookmarkModelObserverTask(model
),
314 id_to_update_(kInvalidBookmarkId
){}
315 virtual ~UpdateBookmarkTask() {}
317 int Run(const int64 id
,
318 const base::string16
& title
,
319 const base::string16
& url
,
320 const int64 parent_id
) {
322 RunOnUIThreadBlocking::Run(
323 base::Bind(&UpdateBookmarkTask::RunOnUIThread
,
324 model(), id
, title
, url
, parent_id
));
328 static void RunOnUIThread(BookmarkModel
* model
,
330 const base::string16
& title
,
331 const base::string16
& url
,
332 const int64 parent_id
) {
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
334 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(model
, id
);
336 if (node
->GetTitle() != title
)
337 model
->SetTitle(node
, title
);
339 if (node
->type() == BookmarkNode::URL
) {
340 GURL bookmark_url
= ParseAndMaybeAppendScheme(url
, kDefaultUrlScheme
);
341 if (bookmark_url
!= node
->url())
342 model
->SetURL(node
, bookmark_url
);
345 if (parent_id
>= 0 &&
346 (!node
->parent() || parent_id
!= node
->parent()->id())) {
347 const BookmarkNode
* new_parent
=
348 bookmarks::GetBookmarkNodeByID(model
, parent_id
);
351 model
->Move(node
, new_parent
, 0);
356 // Verify that the bookmark was actually updated. Called synchronously.
357 virtual void BookmarkNodeChanged(BookmarkModel
* bookmark_model
,
358 const BookmarkNode
* node
) override
{
359 if (bookmark_model
== model() && node
->id() == id_to_update_
)
367 DISALLOW_COPY_AND_ASSIGN(UpdateBookmarkTask
);
370 // Checks if a node exists in the bookmark model.
371 class BookmarkNodeExistsTask
: public BookmarkModelTask
{
373 explicit BookmarkNodeExistsTask(BookmarkModel
* model
)
374 : BookmarkModelTask(model
) {
377 bool Run(const int64 id
) {
379 RunOnUIThreadBlocking::Run(
380 base::Bind(&BookmarkNodeExistsTask::RunOnUIThread
,
381 model(), id
, &result
));
385 static void RunOnUIThread(BookmarkModel
* model
,
388 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
390 *result
= bookmarks::GetBookmarkNodeByID(model
, id
) != NULL
;
394 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeExistsTask
);
397 // Checks if a node belongs to the Mobile Bookmarks hierarchy branch.
398 class IsInMobileBookmarksBranchTask
: public BookmarkModelTask
{
400 explicit IsInMobileBookmarksBranchTask(BookmarkModel
* model
)
401 : BookmarkModelTask(model
) {}
403 bool Run(const int64 id
) {
405 RunOnUIThreadBlocking::Run(
406 base::Bind(&IsInMobileBookmarksBranchTask::RunOnUIThread
,
407 model(), id
, &result
));
411 static void RunOnUIThread(BookmarkModel
* model
,
414 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
416 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(model
, id
);
417 const BookmarkNode
* mobile_node
= model
->mobile_node();
418 while (node
&& node
!= mobile_node
)
419 node
= node
->parent();
421 *result
= node
== mobile_node
;
425 DISALLOW_COPY_AND_ASSIGN(IsInMobileBookmarksBranchTask
);
428 // Creates folder or retrieves its id if already exists.
429 // An invalid parent id is assumed to represent the Mobile Bookmarks folder.
430 // Can only be used to create folders inside the Mobile Bookmarks branch.
431 class CreateBookmarksFolderOnceTask
: public BookmarkModelTask
{
433 explicit CreateBookmarksFolderOnceTask(BookmarkModel
* model
)
434 : BookmarkModelTask(model
) {}
436 int64
Run(const base::string16
& title
, const int64 parent_id
) {
437 int64 result
= kInvalidBookmarkId
;
438 RunOnUIThreadBlocking::Run(
439 base::Bind(&CreateBookmarksFolderOnceTask::RunOnUIThread
,
440 model(), title
, parent_id
, &result
));
444 static void RunOnUIThread(BookmarkModel
* model
,
445 const base::string16
& title
,
446 const int64 parent_id
,
448 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
451 // Invalid ids are assumed to refer to the Mobile Bookmarks folder.
452 const BookmarkNode
* parent
=
453 parent_id
>= 0 ? bookmarks::GetBookmarkNodeByID(model
, parent_id
)
454 : model
->mobile_node();
457 bool in_mobile_bookmarks
;
458 IsInMobileBookmarksBranchTask::RunOnUIThread(model
, parent
->id(),
459 &in_mobile_bookmarks
);
460 if (!in_mobile_bookmarks
) {
461 // The parent folder must be inside the Mobile Bookmarks folder.
462 *result
= kInvalidBookmarkId
;
466 const BookmarkNode
* node
= GetChildFolderByTitle(parent
, title
);
468 *result
= node
->id();
472 AddBookmarkTask::RunOnUIThread(model
, title
, base::string16(), true,
473 parent
->id(), result
);
477 DISALLOW_COPY_AND_ASSIGN(CreateBookmarksFolderOnceTask
);
480 // Creates a Java BookmarkNode object for a node given its id.
481 class GetEditableBookmarkFoldersTask
: public BookmarkModelTask
{
483 GetEditableBookmarkFoldersTask(ChromeBookmarkClient
* client
,
484 BookmarkModel
* model
)
485 : BookmarkModelTask(model
), client_(client
) {}
487 void Run(ScopedJavaGlobalRef
<jobject
>* jroot
) {
488 RunOnUIThreadBlocking::Run(
489 base::Bind(&GetEditableBookmarkFoldersTask::RunOnUIThread
,
490 client_
, model(), jroot
));
493 static void RunOnUIThread(ChromeBookmarkClient
* client
,
494 BookmarkModel
* model
,
495 ScopedJavaGlobalRef
<jobject
>* jroot
) {
496 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
497 const BookmarkNode
* root
= model
->root_node();
498 if (!root
|| !root
->is_folder())
501 // The iterative approach is not possible because ScopedGlobalJavaRefs
502 // cannot be copy-constructed, and therefore not used in STL containers.
503 ConvertFolderSubtree(client
, AttachCurrentThread(), root
,
504 ScopedJavaLocalRef
<jobject
>(), jroot
);
508 static void ConvertFolderSubtree(ChromeBookmarkClient
* client
,
510 const BookmarkNode
* node
,
511 const JavaRef
<jobject
>& parent_folder
,
512 ScopedJavaGlobalRef
<jobject
>* jfolder
) {
514 DCHECK(node
->is_folder());
517 // Global refs should be used here for thread-safety reasons as this task
518 // might be invoked from a thread other than UI. All refs are scoped.
519 ConvertBookmarkNode(node
, parent_folder
, jfolder
);
521 for (int i
= 0; i
< node
->child_count(); ++i
) {
522 const BookmarkNode
* child
= node
->GetChild(i
);
523 if (child
->is_folder() && client
->CanBeEditedByUser(child
)) {
524 ScopedJavaGlobalRef
<jobject
> jchild
;
525 ConvertFolderSubtree(client
, env
, child
, *jfolder
, &jchild
);
527 Java_BookmarkNode_addChild(env
, jfolder
->obj(), jchild
.obj());
528 if (ClearException(env
)) {
529 LOG(WARNING
) << "Java exception while adding child node.";
536 ChromeBookmarkClient
* client_
;
538 DISALLOW_COPY_AND_ASSIGN(GetEditableBookmarkFoldersTask
);
541 // Creates a Java BookmarkNode object for a node given its id.
542 class GetBookmarkNodeTask
: public BookmarkModelTask
{
544 explicit GetBookmarkNodeTask(BookmarkModel
* model
)
545 : BookmarkModelTask(model
) {
548 void Run(const int64 id
,
551 ScopedJavaGlobalRef
<jobject
>* jnode
) {
552 return RunOnUIThreadBlocking::Run(
553 base::Bind(&GetBookmarkNodeTask::RunOnUIThread
,
554 model(), id
, get_parent
, get_children
, jnode
));
557 static void RunOnUIThread(BookmarkModel
* model
,
561 ScopedJavaGlobalRef
<jobject
>* jnode
) {
562 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
563 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(model
, id
);
567 ScopedJavaGlobalRef
<jobject
> jparent
;
569 ConvertBookmarkNode(node
->parent(), ScopedJavaLocalRef
<jobject
>(),
573 ConvertBookmarkNode(node
, jparent
, jnode
);
575 JNIEnv
* env
= AttachCurrentThread();
576 if (!jparent
.is_null()) {
577 Java_BookmarkNode_addChild(env
, jparent
.obj(), jnode
->obj());
578 if (ClearException(env
)) {
579 LOG(WARNING
) << "Java exception while adding child node.";
585 for (int i
= 0; i
< node
->child_count(); ++i
) {
586 ScopedJavaGlobalRef
<jobject
> jchild
;
587 ConvertBookmarkNode(node
->GetChild(i
), *jnode
, &jchild
);
588 Java_BookmarkNode_addChild(env
, jnode
->obj(), jchild
.obj());
589 if (ClearException(env
)) {
590 LOG(WARNING
) << "Java exception while adding child node.";
598 DISALLOW_COPY_AND_ASSIGN(GetBookmarkNodeTask
);
601 // Gets the Mobile Bookmarks node. Using this task ensures the correct
602 // initialization of the bookmark model.
603 class GetMobileBookmarksNodeTask
: public BookmarkModelTask
{
605 explicit GetMobileBookmarksNodeTask(BookmarkModel
* model
)
606 : BookmarkModelTask(model
) {}
608 const BookmarkNode
* Run() {
609 const BookmarkNode
* result
= NULL
;
610 RunOnUIThreadBlocking::Run(
611 base::Bind(&GetMobileBookmarksNodeTask::RunOnUIThread
,
616 static void RunOnUIThread(BookmarkModel
* model
, const BookmarkNode
** result
) {
617 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
619 *result
= model
->mobile_node();
623 DISALLOW_COPY_AND_ASSIGN(GetMobileBookmarksNodeTask
);
626 // ------------- Aynchronous requests classes ------------- //
628 // Base class for asynchronous blocking requests to Chromium services.
629 // Service: type of the service to use (e.g. HistoryService, FaviconService).
630 template <typename Service
>
631 class AsyncServiceRequest
: protected BlockingUIThreadAsyncRequest
{
633 AsyncServiceRequest(Service
* service
,
634 base::CancelableTaskTracker
* cancelable_tracker
)
635 : service_(service
), cancelable_tracker_(cancelable_tracker
) {}
637 Service
* service() const { return service_
; }
639 base::CancelableTaskTracker
* cancelable_tracker() const {
640 return cancelable_tracker_
;
645 base::CancelableTaskTracker
* cancelable_tracker_
;
647 DISALLOW_COPY_AND_ASSIGN(AsyncServiceRequest
);
650 // Base class for all asynchronous blocking tasks that use the favicon service.
651 class FaviconServiceTask
: public AsyncServiceRequest
<FaviconService
> {
653 FaviconServiceTask(FaviconService
* service
,
654 base::CancelableTaskTracker
* cancelable_tracker
,
656 : AsyncServiceRequest
<FaviconService
>(service
, cancelable_tracker
),
659 Profile
* profile() const { return profile_
; }
664 DISALLOW_COPY_AND_ASSIGN(FaviconServiceTask
);
667 // Retrieves the favicon or touch icon for a URL from the FaviconService.
668 class BookmarkIconFetchTask
: public FaviconServiceTask
{
670 BookmarkIconFetchTask(FaviconService
* favicon_service
,
671 base::CancelableTaskTracker
* cancelable_tracker
,
673 : FaviconServiceTask(favicon_service
, cancelable_tracker
, profile
) {}
675 favicon_base::FaviconRawBitmapResult
Run(const GURL
& url
) {
676 float max_scale
= ui::GetScaleForScaleFactor(
677 ResourceBundle::GetSharedInstance().GetMaxScaleFactor());
678 int desired_size_in_pixel
= std::ceil(gfx::kFaviconSize
* max_scale
);
679 RunAsyncRequestOnUIThreadBlocking(
680 base::Bind(&FaviconService::GetRawFaviconForPageURL
,
681 base::Unretained(service()),
683 favicon_base::FAVICON
| favicon_base::TOUCH_ICON
,
684 desired_size_in_pixel
,
685 base::Bind(&BookmarkIconFetchTask::OnFaviconRetrieved
,
686 base::Unretained(this)),
687 cancelable_tracker()));
692 void OnFaviconRetrieved(
693 const favicon_base::FaviconRawBitmapResult
& bitmap_result
) {
694 result_
= bitmap_result
;
698 favicon_base::FaviconRawBitmapResult result_
;
700 DISALLOW_COPY_AND_ASSIGN(BookmarkIconFetchTask
);
703 // Base class for all asynchronous blocking tasks that use the Android history
705 class HistoryProviderTask
706 : public AsyncServiceRequest
<AndroidHistoryProviderService
> {
708 HistoryProviderTask(AndroidHistoryProviderService
* service
,
709 base::CancelableTaskTracker
* cancelable_tracker
)
710 : AsyncServiceRequest
<AndroidHistoryProviderService
>(service
,
711 cancelable_tracker
) {
715 DISALLOW_COPY_AND_ASSIGN(HistoryProviderTask
);
718 // Adds a bookmark from the API.
719 class AddBookmarkFromAPITask
: public HistoryProviderTask
{
721 AddBookmarkFromAPITask(AndroidHistoryProviderService
* service
,
722 base::CancelableTaskTracker
* cancelable_tracker
)
723 : HistoryProviderTask(service
, cancelable_tracker
) {}
725 history::URLID
Run(const history::HistoryAndBookmarkRow
& row
) {
726 RunAsyncRequestOnUIThreadBlocking(
727 base::Bind(&AndroidHistoryProviderService::InsertHistoryAndBookmark
,
728 base::Unretained(service()),
730 base::Bind(&AddBookmarkFromAPITask::OnBookmarkInserted
,
731 base::Unretained(this)),
732 cancelable_tracker()));
737 void OnBookmarkInserted(history::URLID id
) {
738 // Note that here 0 means an invalid id.
739 // This is because it represents a SQLite database row id.
744 history::URLID result_
;
746 DISALLOW_COPY_AND_ASSIGN(AddBookmarkFromAPITask
);
749 // Queries bookmarks from the API.
750 class QueryBookmarksFromAPITask
: public HistoryProviderTask
{
752 QueryBookmarksFromAPITask(AndroidHistoryProviderService
* service
,
753 base::CancelableTaskTracker
* cancelable_tracker
)
754 : HistoryProviderTask(service
, cancelable_tracker
), result_(NULL
) {}
756 history::AndroidStatement
* Run(
757 const std::vector
<history::HistoryAndBookmarkRow::ColumnID
>& projections
,
758 const std::string
& selection
,
759 const std::vector
<base::string16
>& selection_args
,
760 const std::string
& sort_order
) {
761 RunAsyncRequestOnUIThreadBlocking(
762 base::Bind(&AndroidHistoryProviderService::QueryHistoryAndBookmarks
,
763 base::Unretained(service()),
768 base::Bind(&QueryBookmarksFromAPITask::OnBookmarksQueried
,
769 base::Unretained(this)),
770 cancelable_tracker()));
775 void OnBookmarksQueried(history::AndroidStatement
* statement
) {
780 history::AndroidStatement
* result_
;
782 DISALLOW_COPY_AND_ASSIGN(QueryBookmarksFromAPITask
);
785 // Updates bookmarks from the API.
786 class UpdateBookmarksFromAPITask
: public HistoryProviderTask
{
788 UpdateBookmarksFromAPITask(AndroidHistoryProviderService
* service
,
789 base::CancelableTaskTracker
* cancelable_tracker
)
790 : HistoryProviderTask(service
, cancelable_tracker
), result_(0) {}
792 int Run(const history::HistoryAndBookmarkRow
& row
,
793 const std::string
& selection
,
794 const std::vector
<base::string16
>& selection_args
) {
795 RunAsyncRequestOnUIThreadBlocking(
796 base::Bind(&AndroidHistoryProviderService::UpdateHistoryAndBookmarks
,
797 base::Unretained(service()),
801 base::Bind(&UpdateBookmarksFromAPITask::OnBookmarksUpdated
,
802 base::Unretained(this)),
803 cancelable_tracker()));
808 void OnBookmarksUpdated(int updated_row_count
) {
809 result_
= updated_row_count
;
815 DISALLOW_COPY_AND_ASSIGN(UpdateBookmarksFromAPITask
);
818 // Removes bookmarks from the API.
819 class RemoveBookmarksFromAPITask
: public HistoryProviderTask
{
821 RemoveBookmarksFromAPITask(AndroidHistoryProviderService
* service
,
822 base::CancelableTaskTracker
* cancelable_tracker
)
823 : HistoryProviderTask(service
, cancelable_tracker
), result_(0) {}
825 int Run(const std::string
& selection
,
826 const std::vector
<base::string16
>& selection_args
) {
827 RunAsyncRequestOnUIThreadBlocking(
828 base::Bind(&AndroidHistoryProviderService::DeleteHistoryAndBookmarks
,
829 base::Unretained(service()),
832 base::Bind(&RemoveBookmarksFromAPITask::OnBookmarksRemoved
,
833 base::Unretained(this)),
834 cancelable_tracker()));
839 void OnBookmarksRemoved(int removed_row_count
) {
840 result_
= removed_row_count
;
846 DISALLOW_COPY_AND_ASSIGN(RemoveBookmarksFromAPITask
);
849 // Removes history from the API.
850 class RemoveHistoryFromAPITask
: public HistoryProviderTask
{
852 RemoveHistoryFromAPITask(AndroidHistoryProviderService
* service
,
853 base::CancelableTaskTracker
* cancelable_tracker
)
854 : HistoryProviderTask(service
, cancelable_tracker
), result_(0) {}
856 int Run(const std::string
& selection
,
857 const std::vector
<base::string16
>& selection_args
) {
858 RunAsyncRequestOnUIThreadBlocking(
859 base::Bind(&AndroidHistoryProviderService::DeleteHistory
,
860 base::Unretained(service()),
863 base::Bind(&RemoveHistoryFromAPITask::OnHistoryRemoved
,
864 base::Unretained(this)),
865 cancelable_tracker()));
870 void OnHistoryRemoved(int removed_row_count
) {
871 result_
= removed_row_count
;
877 DISALLOW_COPY_AND_ASSIGN(RemoveHistoryFromAPITask
);
880 // This class provides the common method for the SearchTermAPIHelper.
881 class SearchTermTask
: public HistoryProviderTask
{
883 SearchTermTask(AndroidHistoryProviderService
* service
,
884 base::CancelableTaskTracker
* cancelable_tracker
,
886 : HistoryProviderTask(service
, cancelable_tracker
), profile_(profile
) {}
888 // Fill SearchRow's keyword_id and url fields according the given
889 // search_term. Return true if succeeded.
890 void BuildSearchRow(history::SearchRow
* row
) {
891 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
893 TemplateURLService
* template_service
=
894 TemplateURLServiceFactory::GetForProfile(profile_
);
895 template_service
->Load();
897 const TemplateURL
* search_engine
=
898 template_service
->GetDefaultSearchProvider();
900 const TemplateURLRef
* search_url
= &search_engine
->url_ref();
901 TemplateURLRef::SearchTermsArgs
search_terms_args(row
->search_term());
902 search_terms_args
.append_extra_query_params
= true;
903 std::string url
= search_url
->ReplaceSearchTerms(
904 search_terms_args
, template_service
->search_terms_data());
906 row
->set_url(GURL(url
));
907 row
->set_keyword_id(search_engine
->id());
915 DISALLOW_COPY_AND_ASSIGN(SearchTermTask
);
918 // Adds a search term from the API.
919 class AddSearchTermFromAPITask
: public SearchTermTask
{
921 AddSearchTermFromAPITask(AndroidHistoryProviderService
* service
,
922 base::CancelableTaskTracker
* cancelable_tracker
,
924 : SearchTermTask(service
, cancelable_tracker
, profile
) {}
926 history::URLID
Run(const history::SearchRow
& row
) {
927 RunAsyncRequestOnUIThreadBlocking(
928 base::Bind(&AddSearchTermFromAPITask::MakeRequestOnUIThread
,
929 base::Unretained(this), row
));
934 void MakeRequestOnUIThread(const history::SearchRow
& row
) {
935 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
936 history::SearchRow internal_row
= row
;
937 BuildSearchRow(&internal_row
);
938 service()->InsertSearchTerm(
940 base::Bind(&AddSearchTermFromAPITask::OnSearchTermInserted
,
941 base::Unretained(this)),
942 cancelable_tracker());
945 void OnSearchTermInserted(history::URLID id
) {
946 // Note that here 0 means an invalid id.
947 // This is because it represents a SQLite database row id.
952 history::URLID result_
;
954 DISALLOW_COPY_AND_ASSIGN(AddSearchTermFromAPITask
);
957 // Queries search terms from the API.
958 class QuerySearchTermsFromAPITask
: public SearchTermTask
{
960 QuerySearchTermsFromAPITask(AndroidHistoryProviderService
* service
,
961 base::CancelableTaskTracker
* cancelable_tracker
,
963 : SearchTermTask(service
, cancelable_tracker
, profile
), result_(NULL
) {}
965 history::AndroidStatement
* Run(
966 const std::vector
<history::SearchRow::ColumnID
>& projections
,
967 const std::string
& selection
,
968 const std::vector
<base::string16
>& selection_args
,
969 const std::string
& sort_order
) {
970 RunAsyncRequestOnUIThreadBlocking(base::Bind(
971 &AndroidHistoryProviderService::QuerySearchTerms
,
972 base::Unretained(service()),
977 base::Bind(&QuerySearchTermsFromAPITask::OnSearchTermsQueried
,
978 base::Unretained(this)),
979 cancelable_tracker()));
984 // Callback to return the result.
985 void OnSearchTermsQueried(history::AndroidStatement
* statement
) {
990 history::AndroidStatement
* result_
;
992 DISALLOW_COPY_AND_ASSIGN(QuerySearchTermsFromAPITask
);
995 // Updates search terms from the API.
996 class UpdateSearchTermsFromAPITask
: public SearchTermTask
{
998 UpdateSearchTermsFromAPITask(AndroidHistoryProviderService
* service
,
999 base::CancelableTaskTracker
* cancelable_tracker
,
1001 : SearchTermTask(service
, cancelable_tracker
, profile
), result_(0) {}
1003 int Run(const history::SearchRow
& row
,
1004 const std::string
& selection
,
1005 const std::vector
<base::string16
>& selection_args
) {
1006 RunAsyncRequestOnUIThreadBlocking(
1007 base::Bind(&UpdateSearchTermsFromAPITask::MakeRequestOnUIThread
,
1008 base::Unretained(this), row
, selection
, selection_args
));
1013 void MakeRequestOnUIThread(
1014 const history::SearchRow
& row
,
1015 const std::string
& selection
,
1016 const std::vector
<base::string16
>& selection_args
) {
1017 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1018 history::SearchRow internal_row
= row
;
1019 BuildSearchRow(&internal_row
);
1020 service()->UpdateSearchTerms(
1024 base::Bind(&UpdateSearchTermsFromAPITask::OnSearchTermsUpdated
,
1025 base::Unretained(this)),
1026 cancelable_tracker());
1029 void OnSearchTermsUpdated(int updated_row_count
) {
1030 result_
= updated_row_count
;
1036 DISALLOW_COPY_AND_ASSIGN(UpdateSearchTermsFromAPITask
);
1039 // Removes search terms from the API.
1040 class RemoveSearchTermsFromAPITask
: public SearchTermTask
{
1042 RemoveSearchTermsFromAPITask(AndroidHistoryProviderService
* service
,
1043 base::CancelableTaskTracker
* cancelable_tracker
,
1045 : SearchTermTask(service
, cancelable_tracker
, profile
), result_() {}
1047 int Run(const std::string
& selection
,
1048 const std::vector
<base::string16
>& selection_args
) {
1049 RunAsyncRequestOnUIThreadBlocking(base::Bind(
1050 &AndroidHistoryProviderService::DeleteSearchTerms
,
1051 base::Unretained(service()),
1054 base::Bind(&RemoveSearchTermsFromAPITask::OnSearchTermsDeleted
,
1055 base::Unretained(this)),
1056 cancelable_tracker()));
1061 void OnSearchTermsDeleted(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 base::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(base::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 jlong
Init(JNIEnv
* env
, jobject obj
) {
1148 ChromeBrowserProvider
* provider
= new ChromeBrowserProvider(env
, obj
);
1149 return reinterpret_cast<intptr_t>(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 history_service_observer_(this),
1159 handling_extensive_changes_(false) {
1160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1161 profile_
= g_browser_process
->profile_manager()->GetLastUsedProfile();
1162 bookmark_model_
= BookmarkModelFactory::GetForProfile(profile_
);
1163 top_sites_
= profile_
->GetTopSites();
1164 service_
.reset(new AndroidHistoryProviderService(profile_
));
1165 favicon_service_
.reset(FaviconServiceFactory::GetForProfile(profile_
,
1166 Profile::EXPLICIT_ACCESS
));
1168 // Registers the notifications we are interested.
1169 bookmark_model_
->AddObserver(this);
1170 history_service_observer_
.Add(
1171 HistoryServiceFactory::GetForProfile(profile_
, Profile::EXPLICIT_ACCESS
));
1172 notification_registrar_
.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED
,
1173 content::NotificationService::AllSources());
1174 notification_registrar_
.Add(this,
1175 chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED
,
1176 content::NotificationService::AllSources());
1177 TemplateURLService
* template_service
=
1178 TemplateURLServiceFactory::GetForProfile(profile_
);
1179 if (!template_service
->loaded())
1180 template_service
->Load();
1183 ChromeBrowserProvider::~ChromeBrowserProvider() {
1184 bookmark_model_
->RemoveObserver(this);
1187 void ChromeBrowserProvider::Destroy(JNIEnv
*, jobject
) {
1191 // ------------- Provider public APIs ------------- //
1193 jlong
ChromeBrowserProvider::AddBookmark(JNIEnv
* env
,
1201 url
= ConvertJavaStringToUTF16(env
, jurl
);
1202 base::string16 title
= ConvertJavaStringToUTF16(env
, jtitle
);
1204 AddBookmarkTask
task(bookmark_model_
);
1205 return task
.Run(title
, url
, is_folder
, parent_id
);
1208 jint
ChromeBrowserProvider::RemoveBookmark(JNIEnv
*, jobject
, jlong id
) {
1209 RemoveBookmarkTask
task(bookmark_model_
);
1210 return task
.Run(id
);
1213 jint
ChromeBrowserProvider::UpdateBookmark(JNIEnv
* env
,
1221 url
= ConvertJavaStringToUTF16(env
, jurl
);
1222 base::string16 title
= ConvertJavaStringToUTF16(env
, jtitle
);
1224 UpdateBookmarkTask
task(bookmark_model_
);
1225 return task
.Run(id
, title
, url
, parent_id
);
1228 // Add the bookmark with the given column values.
1229 jlong
ChromeBrowserProvider::AddBookmarkFromAPI(JNIEnv
* env
,
1241 history::HistoryAndBookmarkRow row
;
1242 FillBookmarkRow(env
, obj
, url
, created
, isBookmark
, date
, favicon
, title
,
1243 visits
, parent_id
, &row
, bookmark_model_
);
1245 // URL must be valid.
1246 if (row
.url().is_empty()) {
1247 LOG(ERROR
) << "Not a valid URL " << row
.raw_url();
1248 return kInvalidContentProviderId
;
1251 AddBookmarkFromAPITask
task(service_
.get(), &cancelable_task_tracker_
);
1252 return task
.Run(row
);
1255 ScopedJavaLocalRef
<jobject
> ChromeBrowserProvider::QueryBookmarkFromAPI(
1258 jobjectArray projection
,
1260 jobjectArray selection_args
,
1261 jstring sort_order
) {
1262 // Converts the projection to array of ColumnID and column name.
1263 // Used to store the projection column ID according their sequence.
1264 std::vector
<history::HistoryAndBookmarkRow::ColumnID
> query_columns
;
1265 // Used to store the projection column names according their sequence.
1266 std::vector
<std::string
> columns_name
;
1268 jsize len
= env
->GetArrayLength(projection
);
1269 for (int i
= 0; i
< len
; i
++) {
1270 std::string name
= ConvertJavaStringToUTF8(env
, static_cast<jstring
>(
1271 env
->GetObjectArrayElement(projection
, i
)));
1272 history::HistoryAndBookmarkRow::ColumnID id
=
1273 history::HistoryAndBookmarkRow::GetColumnID(name
);
1274 if (id
== history::HistoryAndBookmarkRow::COLUMN_END
) {
1275 // Ignore the unknown column; As Android platform will send us
1276 // the non public column.
1279 query_columns
.push_back(id
);
1280 columns_name
.push_back(name
);
1284 std::vector
<base::string16
> where_args
=
1285 ConvertJStringArrayToString16Array(env
, selection_args
);
1287 std::string where_clause
;
1289 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1292 std::string sort_clause
;
1294 sort_clause
= ConvertJavaStringToUTF8(env
, sort_order
);
1297 QueryBookmarksFromAPITask
task(service_
.get(), &cancelable_task_tracker_
);
1298 history::AndroidStatement
* statement
= task
.Run(
1299 query_columns
, where_clause
, where_args
, sort_clause
);
1301 return ScopedJavaLocalRef
<jobject
>();
1303 // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
1305 return SQLiteCursor::NewJavaSqliteCursor(env
, columns_name
, statement
,
1306 service_
.get(), favicon_service_
.get());
1309 // Updates the bookmarks with the given column values. The value is not given if
1311 jint
ChromeBrowserProvider::UpdateBookmarkFromAPI(JNIEnv
* env
,
1322 jobjectArray selection_args
) {
1323 history::HistoryAndBookmarkRow row
;
1324 FillBookmarkRow(env
, obj
, url
, created
, isBookmark
, date
, favicon
, title
,
1325 visits
, parent_id
, &row
, bookmark_model_
);
1327 std::vector
<base::string16
> where_args
=
1328 ConvertJStringArrayToString16Array(env
, selection_args
);
1330 std::string where_clause
;
1332 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1334 UpdateBookmarksFromAPITask
task(service_
.get(), &cancelable_task_tracker_
);
1335 return task
.Run(row
, where_clause
, where_args
);
1338 jint
ChromeBrowserProvider::RemoveBookmarkFromAPI(JNIEnv
* env
,
1341 jobjectArray selection_args
) {
1342 std::vector
<base::string16
> where_args
=
1343 ConvertJStringArrayToString16Array(env
, selection_args
);
1345 std::string where_clause
;
1347 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1349 RemoveBookmarksFromAPITask
task(service_
.get(), &cancelable_task_tracker_
);
1350 return task
.Run(where_clause
, where_args
);
1353 jint
ChromeBrowserProvider::RemoveHistoryFromAPI(JNIEnv
* env
,
1356 jobjectArray selection_args
) {
1357 std::vector
<base::string16
> where_args
=
1358 ConvertJStringArrayToString16Array(env
, selection_args
);
1360 std::string where_clause
;
1362 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1364 RemoveHistoryFromAPITask
task(service_
.get(), &cancelable_task_tracker_
);
1365 return task
.Run(where_clause
, where_args
);
1368 // Add the search term with the given column values. The value is not given if
1370 jlong
ChromeBrowserProvider::AddSearchTermFromAPI(JNIEnv
* env
,
1372 jstring search_term
,
1374 DCHECK(search_term
);
1376 history::SearchRow row
;
1377 FillSearchRow(env
, obj
, search_term
, date
, &row
);
1379 // URL must be valid.
1380 if (row
.search_term().empty()) {
1381 LOG(ERROR
) << "Search term is empty.";
1382 return kInvalidContentProviderId
;
1385 AddSearchTermFromAPITask
task(service_
.get(),
1386 &cancelable_task_tracker_
,
1388 return task
.Run(row
);
1391 ScopedJavaLocalRef
<jobject
> ChromeBrowserProvider::QuerySearchTermFromAPI(
1394 jobjectArray projection
,
1396 jobjectArray selection_args
,
1397 jstring sort_order
) {
1398 // Converts the projection to array of ColumnID and column name.
1399 // Used to store the projection column ID according their sequence.
1400 std::vector
<history::SearchRow::ColumnID
> query_columns
;
1401 // Used to store the projection column names according their sequence.
1402 std::vector
<std::string
> columns_name
;
1404 jsize len
= env
->GetArrayLength(projection
);
1405 for (int i
= 0; i
< len
; i
++) {
1406 std::string name
= ConvertJavaStringToUTF8(env
, static_cast<jstring
>(
1407 env
->GetObjectArrayElement(projection
, i
)));
1408 history::SearchRow::ColumnID id
=
1409 history::SearchRow::GetColumnID(name
);
1410 if (id
== history::SearchRow::COLUMN_END
) {
1411 LOG(ERROR
) << "Can not find " << name
;
1412 return ScopedJavaLocalRef
<jobject
>();
1414 query_columns
.push_back(id
);
1415 columns_name
.push_back(name
);
1419 std::vector
<base::string16
> where_args
=
1420 ConvertJStringArrayToString16Array(env
, selection_args
);
1422 std::string where_clause
;
1424 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1427 std::string sort_clause
;
1429 sort_clause
= ConvertJavaStringToUTF8(env
, sort_order
);
1432 QuerySearchTermsFromAPITask
task(service_
.get(),
1433 &cancelable_task_tracker_
,
1435 history::AndroidStatement
* statement
= task
.Run(
1436 query_columns
, where_clause
, where_args
, sort_clause
);
1438 return ScopedJavaLocalRef
<jobject
>();
1439 // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
1441 return SQLiteCursor::NewJavaSqliteCursor(env
, columns_name
, statement
,
1442 service_
.get(), favicon_service_
.get());
1445 // Updates the search terms with the given column values. The value is not
1446 // given if it is NULL.
1447 jint
ChromeBrowserProvider::UpdateSearchTermFromAPI(
1448 JNIEnv
* env
, jobject obj
, jstring search_term
, jobject date
,
1449 jstring selections
, jobjectArray selection_args
) {
1450 history::SearchRow row
;
1451 FillSearchRow(env
, obj
, search_term
, date
, &row
);
1453 std::vector
<base::string16
> where_args
= ConvertJStringArrayToString16Array(
1454 env
, selection_args
);
1456 std::string where_clause
;
1458 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1460 UpdateSearchTermsFromAPITask
task(service_
.get(),
1461 &cancelable_task_tracker_
,
1463 return task
.Run(row
, where_clause
, where_args
);
1466 jint
ChromeBrowserProvider::RemoveSearchTermFromAPI(
1467 JNIEnv
* env
, jobject obj
, jstring selections
, jobjectArray selection_args
) {
1468 std::vector
<base::string16
> where_args
=
1469 ConvertJStringArrayToString16Array(env
, selection_args
);
1471 std::string where_clause
;
1473 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1475 RemoveSearchTermsFromAPITask
task(service_
.get(),
1476 &cancelable_task_tracker_
,
1478 return task
.Run(where_clause
, where_args
);
1481 // ------------- Provider custom APIs ------------- //
1483 jboolean
ChromeBrowserProvider::BookmarkNodeExists(
1487 BookmarkNodeExistsTask
task(bookmark_model_
);
1488 return task
.Run(id
);
1491 jlong
ChromeBrowserProvider::CreateBookmarksFolderOnce(
1496 base::string16 title
= ConvertJavaStringToUTF16(env
, jtitle
);
1498 return kInvalidBookmarkId
;
1500 CreateBookmarksFolderOnceTask
task(bookmark_model_
);
1501 return task
.Run(title
, parent_id
);
1504 ScopedJavaLocalRef
<jobject
> ChromeBrowserProvider::GetEditableBookmarkFolders(
1507 ScopedJavaGlobalRef
<jobject
> jroot
;
1508 ChromeBookmarkClient
* client
=
1509 ChromeBookmarkClientFactory::GetForProfile(profile_
);
1510 BookmarkModel
* model
= BookmarkModelFactory::GetForProfile(profile_
);
1511 GetEditableBookmarkFoldersTask
task(client
, model
);
1513 return ScopedJavaLocalRef
<jobject
>(jroot
);
1516 void ChromeBrowserProvider::RemoveAllUserBookmarks(JNIEnv
* env
, jobject obj
) {
1517 RemoveAllUserBookmarksTask
task(bookmark_model_
);
1521 ScopedJavaLocalRef
<jobject
> ChromeBrowserProvider::GetBookmarkNode(
1522 JNIEnv
* env
, jobject obj
, jlong id
, jboolean get_parent
,
1523 jboolean get_children
) {
1524 ScopedJavaGlobalRef
<jobject
> jnode
;
1525 GetBookmarkNodeTask
task(bookmark_model_
);
1526 task
.Run(id
, get_parent
, get_children
, &jnode
);
1527 return ScopedJavaLocalRef
<jobject
>(jnode
);
1530 ScopedJavaLocalRef
<jobject
> ChromeBrowserProvider::GetMobileBookmarksFolder(
1533 ScopedJavaGlobalRef
<jobject
> jnode
;
1534 GetMobileBookmarksNodeTask
task(bookmark_model_
);
1535 ConvertBookmarkNode(task
.Run(), ScopedJavaLocalRef
<jobject
>(), &jnode
);
1536 return ScopedJavaLocalRef
<jobject
>(jnode
);
1539 jboolean
ChromeBrowserProvider::IsBookmarkInMobileBookmarksBranch(
1543 IsInMobileBookmarksBranchTask
task(bookmark_model_
);
1544 return task
.Run(id
);
1547 ScopedJavaLocalRef
<jbyteArray
> ChromeBrowserProvider::GetFaviconOrTouchIcon(
1548 JNIEnv
* env
, jobject obj
, jstring jurl
) {
1550 return ScopedJavaLocalRef
<jbyteArray
>();
1552 GURL url
= GURL(ConvertJavaStringToUTF16(env
, jurl
));
1553 BookmarkIconFetchTask
favicon_task(
1554 favicon_service_
.get(), &cancelable_task_tracker_
, profile_
);
1555 favicon_base::FaviconRawBitmapResult bitmap_result
= favicon_task
.Run(url
);
1557 if (!bitmap_result
.is_valid() || !bitmap_result
.bitmap_data
.get())
1558 return ScopedJavaLocalRef
<jbyteArray
>();
1560 return base::android::ToJavaByteArray(env
, bitmap_result
.bitmap_data
->front(),
1561 bitmap_result
.bitmap_data
->size());
1564 ScopedJavaLocalRef
<jbyteArray
> ChromeBrowserProvider::GetThumbnail(
1565 JNIEnv
* env
, jobject obj
, jstring jurl
) {
1567 return ScopedJavaLocalRef
<jbyteArray
>();
1568 GURL url
= GURL(ConvertJavaStringToUTF16(env
, jurl
));
1570 // GetPageThumbnail is synchronous and can be called from any thread.
1571 scoped_refptr
<base::RefCountedMemory
> thumbnail
;
1573 top_sites_
->GetPageThumbnail(url
, false, &thumbnail
);
1575 if (!thumbnail
.get() || !thumbnail
->front()) {
1576 return ScopedJavaLocalRef
<jbyteArray
>();
1579 return base::android::ToJavaByteArray(env
, thumbnail
->front(),
1583 // ------------- Observer-related methods ------------- //
1585 void ChromeBrowserProvider::ExtensiveBookmarkChangesBeginning(
1586 BookmarkModel
* model
) {
1587 handling_extensive_changes_
= true;
1590 void ChromeBrowserProvider::ExtensiveBookmarkChangesEnded(
1591 BookmarkModel
* model
) {
1592 handling_extensive_changes_
= false;
1593 BookmarkModelChanged();
1596 void ChromeBrowserProvider::BookmarkModelChanged() {
1597 if (handling_extensive_changes_
)
1600 JNIEnv
* env
= AttachCurrentThread();
1601 ScopedJavaLocalRef
<jobject
> obj
= weak_java_provider_
.get(env
);
1605 Java_ChromeBrowserProvider_onBookmarkChanged(env
, obj
.obj());
1608 void ChromeBrowserProvider::OnHistoryChanged() {
1609 JNIEnv
* env
= AttachCurrentThread();
1610 ScopedJavaLocalRef
<jobject
> obj
= weak_java_provider_
.get(env
);
1613 Java_ChromeBrowserProvider_onHistoryChanged(env
, obj
.obj());
1616 void ChromeBrowserProvider::OnURLVisited(HistoryService
* history_service
,
1617 ui::PageTransition transition
,
1618 const history::URLRow
& row
,
1619 const history::RedirectList
& redirects
,
1620 base::Time visit_time
) {
1624 void ChromeBrowserProvider::Observe(
1626 const content::NotificationSource
& source
,
1627 const content::NotificationDetails
& details
) {
1628 if (type
== chrome::NOTIFICATION_HISTORY_URLS_DELETED
) {
1631 chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED
) {
1632 JNIEnv
* env
= AttachCurrentThread();
1633 ScopedJavaLocalRef
<jobject
> obj
= weak_java_provider_
.get(env
);
1636 Java_ChromeBrowserProvider_onSearchTermChanged(env
, obj
.obj());