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/favicon/favicon_service.h"
27 #include "chrome/browser/favicon/favicon_service_factory.h"
28 #include "chrome/browser/history/android/sqlite_cursor.h"
29 #include "chrome/browser/history/history_service.h"
30 #include "chrome/browser/history/history_service_factory.h"
31 #include "chrome/browser/history/top_sites_factory.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/browser/android/android_history_types.h"
38 #include "components/history/core/browser/top_sites.h"
39 #include "components/search_engines/template_url.h"
40 #include "components/search_engines/template_url_service.h"
41 #include "content/public/browser/browser_thread.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 bookmarks::BookmarkModel
;
61 using bookmarks::BookmarkNode
;
62 using content::BrowserThread
;
64 // After refactoring the following class hierarchy has been created in order
65 // to avoid repeating code again for the same basic kind of tasks, to enforce
66 // the correct thread usage and to prevent known race conditions and deadlocks.
68 // - RunOnUIThreadBlocking: auxiliary class to run methods in the UI thread
69 // blocking the current one until finished. Because of the provider threading
70 // expectations this cannot be used from the UI thread.
72 // - BookmarkModelTask: base class for all tasks that operate in any way with
73 // the bookmark model. This class ensures that the model is loaded and
74 // prevents possible deadlocks. Derived classes should make use of
75 // RunOnUIThreadBlocking to perform any manipulation of the bookmark model in
76 // the UI thread. The Run method of these tasks cannot be invoked directly
77 // from the UI thread, but RunOnUIThread can be safely used from the UI
78 // thread code of other BookmarkModelTasks.
80 // - AsyncServiceRequest: base class for any asynchronous requests made to a
81 // Chromium service that require to block the current thread until completed.
82 // Derived classes should make use of RunAsyncRequestOnUIThreadBlocking to
83 // post their requests in the UI thread and return the results synchronously.
84 // All derived classes MUST ALWAYS call RequestCompleted when receiving the
85 // request response. These tasks cannot be invoked from the UI thread.
87 // - FaviconServiceTask: base class for asynchronous requests that make use of
88 // Chromium's favicon service. See AsyncServiceRequest for more details.
90 // - HistoryProviderTask: base class for asynchronous requests that make use of
91 // AndroidHistoryProviderService. See AsyncServiceRequest for mode details.
93 // - SearchTermTask: base class for asynchronous requests that involve the
94 // search term API. Works in the same way as HistoryProviderTask.
98 const char kDefaultUrlScheme
[] = "http://";
99 const int64 kInvalidContentProviderId
= 0;
100 const int64 kInvalidBookmarkId
= -1;
102 // ------------- Java-related utility methods ------------- //
104 // Convert a BookmarkNode, |node|, to the java representation of a bookmark node
105 // stored in |*jnode|. Parent node information is optional.
106 void ConvertBookmarkNode(
107 const BookmarkNode
* node
,
108 const JavaRef
<jobject
>& parent_node
,
109 ScopedJavaGlobalRef
<jobject
>* jnode
) {
114 JNIEnv
* env
= AttachCurrentThread();
115 ScopedJavaLocalRef
<jstring
> url
;
117 url
.Reset(ConvertUTF8ToJavaString(env
, node
->url().spec()));
118 ScopedJavaLocalRef
<jstring
> title(
119 ConvertUTF16ToJavaString(env
, node
->GetTitle()));
122 Java_BookmarkNode_create(
123 env
, node
->id(), (jint
) node
->type(), title
.obj(), url
.obj(),
127 jlong
ConvertJLongObjectToPrimitive(JNIEnv
* env
, jobject long_obj
) {
128 ScopedJavaLocalRef
<jclass
> jlong_clazz
= GetClass(env
, "java/lang/Long");
129 jmethodID long_value
= MethodID::Get
<MethodID::TYPE_INSTANCE
>(
130 env
, jlong_clazz
.obj(), "longValue", "()J");
131 return env
->CallLongMethod(long_obj
, long_value
, NULL
);
134 jboolean
ConvertJBooleanObjectToPrimitive(JNIEnv
* env
, jobject boolean_object
) {
135 ScopedJavaLocalRef
<jclass
> jboolean_clazz
=
136 GetClass(env
, "java/lang/Boolean");
137 jmethodID boolean_value
= MethodID::Get
<MethodID::TYPE_INSTANCE
>(
138 env
, jboolean_clazz
.obj(), "booleanValue", "()Z");
139 return env
->CallBooleanMethod(boolean_object
, boolean_value
, NULL
);
142 base::Time
ConvertJlongToTime(jlong value
) {
143 return base::Time::UnixEpoch() +
144 base::TimeDelta::FromMilliseconds((int64
)value
);
147 jint
ConvertJIntegerToJint(JNIEnv
* env
, jobject integer_obj
) {
148 ScopedJavaLocalRef
<jclass
> jinteger_clazz
=
149 GetClass(env
, "java/lang/Integer");
150 jmethodID int_value
= MethodID::Get
<MethodID::TYPE_INSTANCE
>(
151 env
, jinteger_clazz
.obj(), "intValue", "()I");
152 return env
->CallIntMethod(integer_obj
, int_value
, NULL
);
155 std::vector
<base::string16
> ConvertJStringArrayToString16Array(
157 jobjectArray array
) {
158 std::vector
<base::string16
> results
;
160 jsize len
= env
->GetArrayLength(array
);
161 for (int i
= 0; i
< len
; i
++) {
162 results
.push_back(ConvertJavaStringToUTF16(env
,
163 static_cast<jstring
>(env
->GetObjectArrayElement(array
, i
))));
169 // ------------- Utility methods used by tasks ------------- //
171 // Parse the given url and return a GURL, appending the default scheme
172 // if one is not present.
173 GURL
ParseAndMaybeAppendScheme(const base::string16
& url
,
174 const char* default_scheme
) {
176 if (!gurl
.is_valid() && !gurl
.has_scheme()) {
177 base::string16
refined_url(base::ASCIIToUTF16(default_scheme
));
178 refined_url
.append(url
);
179 gurl
= GURL(refined_url
);
184 const BookmarkNode
* GetChildFolderByTitle(const BookmarkNode
* parent
,
185 const base::string16
& title
) {
186 for (int i
= 0; i
< parent
->child_count(); ++i
) {
187 if (parent
->GetChild(i
)->is_folder() &&
188 parent
->GetChild(i
)->GetTitle() == title
) {
189 return parent
->GetChild(i
);
195 // ------------- Synchronous task classes ------------- //
197 // Utility task to add a bookmark.
198 class AddBookmarkTask
: public BookmarkModelTask
{
200 explicit AddBookmarkTask(BookmarkModel
* model
) : BookmarkModelTask(model
) {}
202 int64
Run(const base::string16
& title
,
203 const base::string16
& url
,
204 const bool is_folder
,
205 const int64 parent_id
) {
206 int64 result
= kInvalidBookmarkId
;
207 RunOnUIThreadBlocking::Run(
208 base::Bind(&AddBookmarkTask::RunOnUIThread
,
209 model(), title
, url
, is_folder
, parent_id
, &result
));
213 static void RunOnUIThread(BookmarkModel
* model
,
214 const base::string16
& title
,
215 const base::string16
& url
,
216 const bool is_folder
,
217 const int64 parent_id
,
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
221 GURL gurl
= ParseAndMaybeAppendScheme(url
, kDefaultUrlScheme
);
223 // Check if the bookmark already exists.
224 const BookmarkNode
* node
= model
->GetMostRecentlyAddedUserNodeForURL(gurl
);
226 const BookmarkNode
* parent_node
= NULL
;
228 parent_node
= bookmarks::GetBookmarkNodeByID(model
, parent_id
);
230 parent_node
= model
->bookmark_bar_node();
233 node
= model
->AddFolder(parent_node
, parent_node
->child_count(), title
);
235 node
= model
->AddURL(parent_node
, 0, title
, gurl
);
238 *result
= node
? node
->id() : kInvalidBookmarkId
;
242 DISALLOW_COPY_AND_ASSIGN(AddBookmarkTask
);
245 // Utility method to remove a bookmark.
246 class RemoveBookmarkTask
: public BookmarkModelObserverTask
{
248 explicit RemoveBookmarkTask(BookmarkModel
* model
)
249 : BookmarkModelObserverTask(model
),
251 id_to_delete_(kInvalidBookmarkId
) {}
252 ~RemoveBookmarkTask() override
{}
254 int Run(const int64 id
) {
256 RunOnUIThreadBlocking::Run(
257 base::Bind(&RemoveBookmarkTask::RunOnUIThread
, model(), id
));
261 static void RunOnUIThread(BookmarkModel
* model
, const int64 id
) {
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
263 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(model
, id
);
264 if (node
&& node
->parent()) {
265 const BookmarkNode
* parent_node
= node
->parent();
266 model
->Remove(parent_node
, parent_node
->GetIndexOf(node
));
270 // Verify that the bookmark was actually removed. Called synchronously.
271 void BookmarkNodeRemoved(BookmarkModel
* bookmark_model
,
272 const BookmarkNode
* parent
,
274 const BookmarkNode
* node
,
275 const std::set
<GURL
>& removed_urls
) override
{
276 if (bookmark_model
== model() && node
->id() == id_to_delete_
)
284 DISALLOW_COPY_AND_ASSIGN(RemoveBookmarkTask
);
287 // Utility method to remove all bookmarks that the user can edit.
288 class RemoveAllUserBookmarksTask
: public BookmarkModelObserverTask
{
290 explicit RemoveAllUserBookmarksTask(BookmarkModel
* model
)
291 : BookmarkModelObserverTask(model
) {}
293 ~RemoveAllUserBookmarksTask() override
{}
296 RunOnUIThreadBlocking::Run(
297 base::Bind(&RemoveAllUserBookmarksTask::RunOnUIThread
, model()));
300 static void RunOnUIThread(BookmarkModel
* model
) {
301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
302 LOG(ERROR
) << "begin model->RemoveAllUserBookmarks";
303 model
->RemoveAllUserBookmarks();
304 LOG(ERROR
) << "after model->RemoveAllUserBookmarks";
308 DISALLOW_COPY_AND_ASSIGN(RemoveAllUserBookmarksTask
);
311 // Utility method to update a bookmark.
312 class UpdateBookmarkTask
: public BookmarkModelObserverTask
{
314 explicit UpdateBookmarkTask(BookmarkModel
* model
)
315 : BookmarkModelObserverTask(model
),
317 id_to_update_(kInvalidBookmarkId
){}
318 ~UpdateBookmarkTask() override
{}
320 int Run(const int64 id
,
321 const base::string16
& title
,
322 const base::string16
& url
,
323 const int64 parent_id
) {
325 RunOnUIThreadBlocking::Run(
326 base::Bind(&UpdateBookmarkTask::RunOnUIThread
,
327 model(), id
, title
, url
, parent_id
));
331 static void RunOnUIThread(BookmarkModel
* model
,
333 const base::string16
& title
,
334 const base::string16
& url
,
335 const int64 parent_id
) {
336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
337 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(model
, id
);
339 if (node
->GetTitle() != title
)
340 model
->SetTitle(node
, title
);
342 if (node
->type() == BookmarkNode::URL
) {
343 GURL bookmark_url
= ParseAndMaybeAppendScheme(url
, kDefaultUrlScheme
);
344 if (bookmark_url
!= node
->url())
345 model
->SetURL(node
, bookmark_url
);
348 if (parent_id
>= 0 &&
349 (!node
->parent() || parent_id
!= node
->parent()->id())) {
350 const BookmarkNode
* new_parent
=
351 bookmarks::GetBookmarkNodeByID(model
, parent_id
);
354 model
->Move(node
, new_parent
, 0);
359 // Verify that the bookmark was actually updated. Called synchronously.
360 void BookmarkNodeChanged(BookmarkModel
* bookmark_model
,
361 const BookmarkNode
* node
) override
{
362 if (bookmark_model
== model() && node
->id() == id_to_update_
)
370 DISALLOW_COPY_AND_ASSIGN(UpdateBookmarkTask
);
373 // Checks if a node exists in the bookmark model.
374 class BookmarkNodeExistsTask
: public BookmarkModelTask
{
376 explicit BookmarkNodeExistsTask(BookmarkModel
* model
)
377 : BookmarkModelTask(model
) {
380 bool Run(const int64 id
) {
382 RunOnUIThreadBlocking::Run(
383 base::Bind(&BookmarkNodeExistsTask::RunOnUIThread
,
384 model(), id
, &result
));
388 static void RunOnUIThread(BookmarkModel
* model
,
391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
393 *result
= bookmarks::GetBookmarkNodeByID(model
, id
) != NULL
;
397 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeExistsTask
);
400 // Checks if a node belongs to the Mobile Bookmarks hierarchy branch.
401 class IsInMobileBookmarksBranchTask
: public BookmarkModelTask
{
403 explicit IsInMobileBookmarksBranchTask(BookmarkModel
* model
)
404 : BookmarkModelTask(model
) {}
406 bool Run(const int64 id
) {
408 RunOnUIThreadBlocking::Run(
409 base::Bind(&IsInMobileBookmarksBranchTask::RunOnUIThread
,
410 model(), id
, &result
));
414 static void RunOnUIThread(BookmarkModel
* model
,
417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
419 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(model
, id
);
420 const BookmarkNode
* mobile_node
= model
->mobile_node();
421 while (node
&& node
!= mobile_node
)
422 node
= node
->parent();
424 *result
= node
== mobile_node
;
428 DISALLOW_COPY_AND_ASSIGN(IsInMobileBookmarksBranchTask
);
431 // Creates folder or retrieves its id if already exists.
432 // An invalid parent id is assumed to represent the Mobile Bookmarks folder.
433 // Can only be used to create folders inside the Mobile Bookmarks branch.
434 class CreateBookmarksFolderOnceTask
: public BookmarkModelTask
{
436 explicit CreateBookmarksFolderOnceTask(BookmarkModel
* model
)
437 : BookmarkModelTask(model
) {}
439 int64
Run(const base::string16
& title
, const int64 parent_id
) {
440 int64 result
= kInvalidBookmarkId
;
441 RunOnUIThreadBlocking::Run(
442 base::Bind(&CreateBookmarksFolderOnceTask::RunOnUIThread
,
443 model(), title
, parent_id
, &result
));
447 static void RunOnUIThread(BookmarkModel
* model
,
448 const base::string16
& title
,
449 const int64 parent_id
,
451 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
454 // Invalid ids are assumed to refer to the Mobile Bookmarks folder.
455 const BookmarkNode
* parent
=
456 parent_id
>= 0 ? bookmarks::GetBookmarkNodeByID(model
, parent_id
)
457 : model
->mobile_node();
460 bool in_mobile_bookmarks
;
461 IsInMobileBookmarksBranchTask::RunOnUIThread(model
, parent
->id(),
462 &in_mobile_bookmarks
);
463 if (!in_mobile_bookmarks
) {
464 // The parent folder must be inside the Mobile Bookmarks folder.
465 *result
= kInvalidBookmarkId
;
469 const BookmarkNode
* node
= GetChildFolderByTitle(parent
, title
);
471 *result
= node
->id();
475 AddBookmarkTask::RunOnUIThread(model
, title
, base::string16(), true,
476 parent
->id(), result
);
480 DISALLOW_COPY_AND_ASSIGN(CreateBookmarksFolderOnceTask
);
483 // Creates a Java BookmarkNode object for a node given its id.
484 class GetEditableBookmarkFoldersTask
: public BookmarkModelTask
{
486 GetEditableBookmarkFoldersTask(ChromeBookmarkClient
* client
,
487 BookmarkModel
* model
)
488 : BookmarkModelTask(model
), client_(client
) {}
490 void Run(ScopedJavaGlobalRef
<jobject
>* jroot
) {
491 RunOnUIThreadBlocking::Run(
492 base::Bind(&GetEditableBookmarkFoldersTask::RunOnUIThread
,
493 client_
, model(), jroot
));
496 static void RunOnUIThread(ChromeBookmarkClient
* client
,
497 BookmarkModel
* model
,
498 ScopedJavaGlobalRef
<jobject
>* jroot
) {
499 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
500 const BookmarkNode
* root
= model
->root_node();
501 if (!root
|| !root
->is_folder())
504 // The iterative approach is not possible because ScopedGlobalJavaRefs
505 // cannot be copy-constructed, and therefore not used in STL containers.
506 ConvertFolderSubtree(client
, AttachCurrentThread(), root
,
507 ScopedJavaLocalRef
<jobject
>(), jroot
);
511 static void ConvertFolderSubtree(ChromeBookmarkClient
* client
,
513 const BookmarkNode
* node
,
514 const JavaRef
<jobject
>& parent_folder
,
515 ScopedJavaGlobalRef
<jobject
>* jfolder
) {
517 DCHECK(node
->is_folder());
520 // Global refs should be used here for thread-safety reasons as this task
521 // might be invoked from a thread other than UI. All refs are scoped.
522 ConvertBookmarkNode(node
, parent_folder
, jfolder
);
524 for (int i
= 0; i
< node
->child_count(); ++i
) {
525 const BookmarkNode
* child
= node
->GetChild(i
);
526 if (child
->is_folder() && client
->CanBeEditedByUser(child
)) {
527 ScopedJavaGlobalRef
<jobject
> jchild
;
528 ConvertFolderSubtree(client
, env
, child
, *jfolder
, &jchild
);
530 Java_BookmarkNode_addChild(env
, jfolder
->obj(), jchild
.obj());
531 if (ClearException(env
)) {
532 LOG(WARNING
) << "Java exception while adding child node.";
539 ChromeBookmarkClient
* client_
;
541 DISALLOW_COPY_AND_ASSIGN(GetEditableBookmarkFoldersTask
);
544 // Creates a Java BookmarkNode object for a node given its id.
545 class GetBookmarkNodeTask
: public BookmarkModelTask
{
547 explicit GetBookmarkNodeTask(BookmarkModel
* model
)
548 : BookmarkModelTask(model
) {
551 void Run(const int64 id
,
554 ScopedJavaGlobalRef
<jobject
>* jnode
) {
555 return RunOnUIThreadBlocking::Run(
556 base::Bind(&GetBookmarkNodeTask::RunOnUIThread
,
557 model(), id
, get_parent
, get_children
, jnode
));
560 static void RunOnUIThread(BookmarkModel
* model
,
564 ScopedJavaGlobalRef
<jobject
>* jnode
) {
565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
566 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(model
, id
);
570 ScopedJavaGlobalRef
<jobject
> jparent
;
572 ConvertBookmarkNode(node
->parent(), ScopedJavaLocalRef
<jobject
>(),
576 ConvertBookmarkNode(node
, jparent
, jnode
);
578 JNIEnv
* env
= AttachCurrentThread();
579 if (!jparent
.is_null()) {
580 Java_BookmarkNode_addChild(env
, jparent
.obj(), jnode
->obj());
581 if (ClearException(env
)) {
582 LOG(WARNING
) << "Java exception while adding child node.";
588 for (int i
= 0; i
< node
->child_count(); ++i
) {
589 ScopedJavaGlobalRef
<jobject
> jchild
;
590 ConvertBookmarkNode(node
->GetChild(i
), *jnode
, &jchild
);
591 Java_BookmarkNode_addChild(env
, jnode
->obj(), jchild
.obj());
592 if (ClearException(env
)) {
593 LOG(WARNING
) << "Java exception while adding child node.";
601 DISALLOW_COPY_AND_ASSIGN(GetBookmarkNodeTask
);
604 // Gets the Mobile Bookmarks node. Using this task ensures the correct
605 // initialization of the bookmark model.
606 class GetMobileBookmarksNodeTask
: public BookmarkModelTask
{
608 explicit GetMobileBookmarksNodeTask(BookmarkModel
* model
)
609 : BookmarkModelTask(model
) {}
611 const BookmarkNode
* Run() {
612 const BookmarkNode
* result
= NULL
;
613 RunOnUIThreadBlocking::Run(
614 base::Bind(&GetMobileBookmarksNodeTask::RunOnUIThread
,
619 static void RunOnUIThread(BookmarkModel
* model
, const BookmarkNode
** result
) {
620 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
622 *result
= model
->mobile_node();
626 DISALLOW_COPY_AND_ASSIGN(GetMobileBookmarksNodeTask
);
629 // ------------- Aynchronous requests classes ------------- //
631 // Base class for asynchronous blocking requests to Chromium services.
632 // Service: type of the service to use (e.g. HistoryService, FaviconService).
633 template <typename Service
>
634 class AsyncServiceRequest
: protected BlockingUIThreadAsyncRequest
{
636 AsyncServiceRequest(Service
* service
,
637 base::CancelableTaskTracker
* cancelable_tracker
)
638 : service_(service
), cancelable_tracker_(cancelable_tracker
) {}
640 Service
* service() const { return service_
; }
642 base::CancelableTaskTracker
* cancelable_tracker() const {
643 return cancelable_tracker_
;
648 base::CancelableTaskTracker
* cancelable_tracker_
;
650 DISALLOW_COPY_AND_ASSIGN(AsyncServiceRequest
);
653 // Base class for all asynchronous blocking tasks that use the favicon service.
654 class FaviconServiceTask
: public AsyncServiceRequest
<FaviconService
> {
656 FaviconServiceTask(base::CancelableTaskTracker
* cancelable_tracker
,
658 FaviconService
* favicon_service
)
659 : AsyncServiceRequest
<FaviconService
>(favicon_service
,
663 Profile
* profile() const { return profile_
; }
668 DISALLOW_COPY_AND_ASSIGN(FaviconServiceTask
);
671 // Retrieves the favicon or touch icon for a URL from the FaviconService.
672 class BookmarkIconFetchTask
: public FaviconServiceTask
{
674 BookmarkIconFetchTask(base::CancelableTaskTracker
* cancelable_tracker
,
676 FaviconService
* favicon_service
)
677 : FaviconServiceTask(cancelable_tracker
, profile
, favicon_service
) {}
679 favicon_base::FaviconRawBitmapResult
Run(const GURL
& url
) {
680 float max_scale
= ui::GetScaleForScaleFactor(
681 ResourceBundle::GetSharedInstance().GetMaxScaleFactor());
682 int desired_size_in_pixel
= std::ceil(gfx::kFaviconSize
* max_scale
);
684 if (service() == NULL
)
685 return favicon_base::FaviconRawBitmapResult();
687 RunAsyncRequestOnUIThreadBlocking(
688 base::Bind(&FaviconService::GetRawFaviconForPageURL
,
689 base::Unretained(service()),
691 favicon_base::FAVICON
| favicon_base::TOUCH_ICON
,
692 desired_size_in_pixel
,
693 base::Bind(&BookmarkIconFetchTask::OnFaviconRetrieved
,
694 base::Unretained(this)),
695 cancelable_tracker()));
700 void OnFaviconRetrieved(
701 const favicon_base::FaviconRawBitmapResult
& bitmap_result
) {
702 result_
= bitmap_result
;
706 favicon_base::FaviconRawBitmapResult result_
;
708 DISALLOW_COPY_AND_ASSIGN(BookmarkIconFetchTask
);
711 // Base class for all asynchronous blocking tasks that use the Android history
713 class HistoryProviderTask
714 : public AsyncServiceRequest
<AndroidHistoryProviderService
> {
716 HistoryProviderTask(AndroidHistoryProviderService
* service
,
717 base::CancelableTaskTracker
* cancelable_tracker
)
718 : AsyncServiceRequest
<AndroidHistoryProviderService
>(service
,
719 cancelable_tracker
) {
723 DISALLOW_COPY_AND_ASSIGN(HistoryProviderTask
);
726 // Adds a bookmark from the API.
727 class AddBookmarkFromAPITask
: public HistoryProviderTask
{
729 AddBookmarkFromAPITask(AndroidHistoryProviderService
* service
,
730 base::CancelableTaskTracker
* cancelable_tracker
)
731 : HistoryProviderTask(service
, cancelable_tracker
) {}
733 history::URLID
Run(const history::HistoryAndBookmarkRow
& row
) {
734 RunAsyncRequestOnUIThreadBlocking(
735 base::Bind(&AndroidHistoryProviderService::InsertHistoryAndBookmark
,
736 base::Unretained(service()),
738 base::Bind(&AddBookmarkFromAPITask::OnBookmarkInserted
,
739 base::Unretained(this)),
740 cancelable_tracker()));
745 void OnBookmarkInserted(history::URLID id
) {
746 // Note that here 0 means an invalid id.
747 // This is because it represents a SQLite database row id.
752 history::URLID result_
;
754 DISALLOW_COPY_AND_ASSIGN(AddBookmarkFromAPITask
);
757 // Queries bookmarks from the API.
758 class QueryBookmarksFromAPITask
: public HistoryProviderTask
{
760 QueryBookmarksFromAPITask(AndroidHistoryProviderService
* service
,
761 base::CancelableTaskTracker
* cancelable_tracker
)
762 : HistoryProviderTask(service
, cancelable_tracker
), result_(NULL
) {}
764 history::AndroidStatement
* Run(
765 const std::vector
<history::HistoryAndBookmarkRow::ColumnID
>& projections
,
766 const std::string
& selection
,
767 const std::vector
<base::string16
>& selection_args
,
768 const std::string
& sort_order
) {
769 RunAsyncRequestOnUIThreadBlocking(
770 base::Bind(&AndroidHistoryProviderService::QueryHistoryAndBookmarks
,
771 base::Unretained(service()),
776 base::Bind(&QueryBookmarksFromAPITask::OnBookmarksQueried
,
777 base::Unretained(this)),
778 cancelable_tracker()));
783 void OnBookmarksQueried(history::AndroidStatement
* statement
) {
788 history::AndroidStatement
* result_
;
790 DISALLOW_COPY_AND_ASSIGN(QueryBookmarksFromAPITask
);
793 // Updates bookmarks from the API.
794 class UpdateBookmarksFromAPITask
: public HistoryProviderTask
{
796 UpdateBookmarksFromAPITask(AndroidHistoryProviderService
* service
,
797 base::CancelableTaskTracker
* cancelable_tracker
)
798 : HistoryProviderTask(service
, cancelable_tracker
), result_(0) {}
800 int Run(const history::HistoryAndBookmarkRow
& row
,
801 const std::string
& selection
,
802 const std::vector
<base::string16
>& selection_args
) {
803 RunAsyncRequestOnUIThreadBlocking(
804 base::Bind(&AndroidHistoryProviderService::UpdateHistoryAndBookmarks
,
805 base::Unretained(service()),
809 base::Bind(&UpdateBookmarksFromAPITask::OnBookmarksUpdated
,
810 base::Unretained(this)),
811 cancelable_tracker()));
816 void OnBookmarksUpdated(int updated_row_count
) {
817 result_
= updated_row_count
;
823 DISALLOW_COPY_AND_ASSIGN(UpdateBookmarksFromAPITask
);
826 // Removes bookmarks from the API.
827 class RemoveBookmarksFromAPITask
: public HistoryProviderTask
{
829 RemoveBookmarksFromAPITask(AndroidHistoryProviderService
* service
,
830 base::CancelableTaskTracker
* cancelable_tracker
)
831 : HistoryProviderTask(service
, cancelable_tracker
), result_(0) {}
833 int Run(const std::string
& selection
,
834 const std::vector
<base::string16
>& selection_args
) {
835 RunAsyncRequestOnUIThreadBlocking(
836 base::Bind(&AndroidHistoryProviderService::DeleteHistoryAndBookmarks
,
837 base::Unretained(service()),
840 base::Bind(&RemoveBookmarksFromAPITask::OnBookmarksRemoved
,
841 base::Unretained(this)),
842 cancelable_tracker()));
847 void OnBookmarksRemoved(int removed_row_count
) {
848 result_
= removed_row_count
;
854 DISALLOW_COPY_AND_ASSIGN(RemoveBookmarksFromAPITask
);
857 // Removes history from the API.
858 class RemoveHistoryFromAPITask
: public HistoryProviderTask
{
860 RemoveHistoryFromAPITask(AndroidHistoryProviderService
* service
,
861 base::CancelableTaskTracker
* cancelable_tracker
)
862 : HistoryProviderTask(service
, cancelable_tracker
), result_(0) {}
864 int Run(const std::string
& selection
,
865 const std::vector
<base::string16
>& selection_args
) {
866 RunAsyncRequestOnUIThreadBlocking(
867 base::Bind(&AndroidHistoryProviderService::DeleteHistory
,
868 base::Unretained(service()),
871 base::Bind(&RemoveHistoryFromAPITask::OnHistoryRemoved
,
872 base::Unretained(this)),
873 cancelable_tracker()));
878 void OnHistoryRemoved(int removed_row_count
) {
879 result_
= removed_row_count
;
885 DISALLOW_COPY_AND_ASSIGN(RemoveHistoryFromAPITask
);
888 // This class provides the common method for the SearchTermAPIHelper.
889 class SearchTermTask
: public HistoryProviderTask
{
891 SearchTermTask(AndroidHistoryProviderService
* service
,
892 base::CancelableTaskTracker
* cancelable_tracker
,
894 : HistoryProviderTask(service
, cancelable_tracker
), profile_(profile
) {}
896 // Fill SearchRow's keyword_id and url fields according the given
897 // search_term. Return true if succeeded.
898 void BuildSearchRow(history::SearchRow
* row
) {
899 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
901 TemplateURLService
* template_service
=
902 TemplateURLServiceFactory::GetForProfile(profile_
);
903 template_service
->Load();
905 const TemplateURL
* search_engine
=
906 template_service
->GetDefaultSearchProvider();
908 const TemplateURLRef
* search_url
= &search_engine
->url_ref();
909 TemplateURLRef::SearchTermsArgs
search_terms_args(row
->search_term());
910 search_terms_args
.append_extra_query_params
= true;
911 std::string url
= search_url
->ReplaceSearchTerms(
912 search_terms_args
, template_service
->search_terms_data());
914 row
->set_url(GURL(url
));
915 row
->set_keyword_id(search_engine
->id());
923 DISALLOW_COPY_AND_ASSIGN(SearchTermTask
);
926 // Adds a search term from the API.
927 class AddSearchTermFromAPITask
: public SearchTermTask
{
929 AddSearchTermFromAPITask(AndroidHistoryProviderService
* service
,
930 base::CancelableTaskTracker
* cancelable_tracker
,
932 : SearchTermTask(service
, cancelable_tracker
, profile
) {}
934 history::URLID
Run(const history::SearchRow
& row
) {
935 RunAsyncRequestOnUIThreadBlocking(
936 base::Bind(&AddSearchTermFromAPITask::MakeRequestOnUIThread
,
937 base::Unretained(this), row
));
942 void MakeRequestOnUIThread(const history::SearchRow
& row
) {
943 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
944 history::SearchRow internal_row
= row
;
945 BuildSearchRow(&internal_row
);
946 service()->InsertSearchTerm(
948 base::Bind(&AddSearchTermFromAPITask::OnSearchTermInserted
,
949 base::Unretained(this)),
950 cancelable_tracker());
953 void OnSearchTermInserted(history::URLID id
) {
954 // Note that here 0 means an invalid id.
955 // This is because it represents a SQLite database row id.
960 history::URLID result_
;
962 DISALLOW_COPY_AND_ASSIGN(AddSearchTermFromAPITask
);
965 // Queries search terms from the API.
966 class QuerySearchTermsFromAPITask
: public SearchTermTask
{
968 QuerySearchTermsFromAPITask(AndroidHistoryProviderService
* service
,
969 base::CancelableTaskTracker
* cancelable_tracker
,
971 : SearchTermTask(service
, cancelable_tracker
, profile
), result_(NULL
) {}
973 history::AndroidStatement
* Run(
974 const std::vector
<history::SearchRow::ColumnID
>& projections
,
975 const std::string
& selection
,
976 const std::vector
<base::string16
>& selection_args
,
977 const std::string
& sort_order
) {
978 RunAsyncRequestOnUIThreadBlocking(base::Bind(
979 &AndroidHistoryProviderService::QuerySearchTerms
,
980 base::Unretained(service()),
985 base::Bind(&QuerySearchTermsFromAPITask::OnSearchTermsQueried
,
986 base::Unretained(this)),
987 cancelable_tracker()));
992 // Callback to return the result.
993 void OnSearchTermsQueried(history::AndroidStatement
* statement
) {
998 history::AndroidStatement
* result_
;
1000 DISALLOW_COPY_AND_ASSIGN(QuerySearchTermsFromAPITask
);
1003 // Updates search terms from the API.
1004 class UpdateSearchTermsFromAPITask
: public SearchTermTask
{
1006 UpdateSearchTermsFromAPITask(AndroidHistoryProviderService
* service
,
1007 base::CancelableTaskTracker
* cancelable_tracker
,
1009 : SearchTermTask(service
, cancelable_tracker
, profile
), result_(0) {}
1011 int Run(const history::SearchRow
& row
,
1012 const std::string
& selection
,
1013 const std::vector
<base::string16
>& selection_args
) {
1014 RunAsyncRequestOnUIThreadBlocking(
1015 base::Bind(&UpdateSearchTermsFromAPITask::MakeRequestOnUIThread
,
1016 base::Unretained(this), row
, selection
, selection_args
));
1021 void MakeRequestOnUIThread(
1022 const history::SearchRow
& row
,
1023 const std::string
& selection
,
1024 const std::vector
<base::string16
>& selection_args
) {
1025 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1026 history::SearchRow internal_row
= row
;
1027 BuildSearchRow(&internal_row
);
1028 service()->UpdateSearchTerms(
1032 base::Bind(&UpdateSearchTermsFromAPITask::OnSearchTermsUpdated
,
1033 base::Unretained(this)),
1034 cancelable_tracker());
1037 void OnSearchTermsUpdated(int updated_row_count
) {
1038 result_
= updated_row_count
;
1044 DISALLOW_COPY_AND_ASSIGN(UpdateSearchTermsFromAPITask
);
1047 // Removes search terms from the API.
1048 class RemoveSearchTermsFromAPITask
: public SearchTermTask
{
1050 RemoveSearchTermsFromAPITask(AndroidHistoryProviderService
* service
,
1051 base::CancelableTaskTracker
* cancelable_tracker
,
1053 : SearchTermTask(service
, cancelable_tracker
, profile
), result_() {}
1055 int Run(const std::string
& selection
,
1056 const std::vector
<base::string16
>& selection_args
) {
1057 RunAsyncRequestOnUIThreadBlocking(base::Bind(
1058 &AndroidHistoryProviderService::DeleteSearchTerms
,
1059 base::Unretained(service()),
1062 base::Bind(&RemoveSearchTermsFromAPITask::OnSearchTermsDeleted
,
1063 base::Unretained(this)),
1064 cancelable_tracker()));
1069 void OnSearchTermsDeleted(int deleted_row_count
) {
1070 result_
= deleted_row_count
;
1076 DISALLOW_COPY_AND_ASSIGN(RemoveSearchTermsFromAPITask
);
1079 // ------------- Other utility methods (may use tasks) ------------- //
1081 // Fills the bookmark |row| with the given java objects.
1082 void FillBookmarkRow(JNIEnv
* env
,
1092 history::HistoryAndBookmarkRow
* row
,
1093 BookmarkModel
* model
) {
1094 // Needed because of the internal bookmark model task invocation.
1095 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI
));
1098 base::string16 raw_url
= ConvertJavaStringToUTF16(env
, url
);
1099 // GURL doesn't accept the URL without protocol, but the Android CTS
1100 // allows it. We are trying to prefix with 'http://' to see whether
1101 // GURL thinks it is a valid URL. The original url will be stored in
1102 // history::BookmarkRow.raw_url_.
1103 GURL gurl
= ParseAndMaybeAppendScheme(raw_url
, kDefaultUrlScheme
);
1105 row
->set_raw_url(base::UTF16ToUTF8(raw_url
));
1109 row
->set_created(ConvertJlongToTime(
1110 ConvertJLongObjectToPrimitive(env
, created
)));
1113 row
->set_is_bookmark(ConvertJBooleanObjectToPrimitive(env
, isBookmark
));
1116 row
->set_last_visit_time(ConvertJlongToTime(ConvertJLongObjectToPrimitive(
1120 std::vector
<uint8
> bytes
;
1121 base::android::JavaByteArrayToByteVector(env
, favicon
, &bytes
);
1122 row
->set_favicon(base::RefCountedBytes::TakeVector(&bytes
));
1126 row
->set_title(ConvertJavaStringToUTF16(env
, title
));
1129 row
->set_visit_count(ConvertJIntegerToJint(env
, visits
));
1131 // Make sure parent_id is always in the mobile_node branch.
1132 IsInMobileBookmarksBranchTask
task(model
);
1133 if (task
.Run(parent_id
))
1134 row
->set_parent_id(parent_id
);
1137 // Fills the bookmark |row| with the given java objects if it is not null.
1138 void FillSearchRow(JNIEnv
* env
,
1140 jstring search_term
,
1142 history::SearchRow
* row
) {
1144 row
->set_search_term(ConvertJavaStringToUTF16(env
, search_term
));
1147 row
->set_search_time(ConvertJlongToTime(ConvertJLongObjectToPrimitive(
1153 // ------------- Native initialization and destruction ------------- //
1155 static jlong
Init(JNIEnv
* env
, jobject obj
) {
1156 ChromeBrowserProvider
* provider
= new ChromeBrowserProvider(env
, obj
);
1157 return reinterpret_cast<intptr_t>(provider
);
1160 bool ChromeBrowserProvider::RegisterChromeBrowserProvider(JNIEnv
* env
) {
1161 return RegisterNativesImpl(env
);
1164 ChromeBrowserProvider::ChromeBrowserProvider(JNIEnv
* env
, jobject obj
)
1165 : weak_java_provider_(env
, obj
),
1166 history_service_observer_(this),
1167 handling_extensive_changes_(false) {
1168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1169 profile_
= g_browser_process
->profile_manager()->GetLastUsedProfile();
1170 bookmark_model_
= BookmarkModelFactory::GetForProfile(profile_
);
1171 top_sites_
= TopSitesFactory::GetForProfile(profile_
);
1172 favicon_service_
= FaviconServiceFactory::GetForProfile(
1173 profile_
, ServiceAccessType::EXPLICIT_ACCESS
),
1174 service_
.reset(new AndroidHistoryProviderService(profile_
));
1176 // Register as observer for service we are interested.
1177 bookmark_model_
->AddObserver(this);
1178 history_service_observer_
.Add(HistoryServiceFactory::GetForProfile(
1179 profile_
, ServiceAccessType::EXPLICIT_ACCESS
));
1180 TemplateURLService
* template_service
=
1181 TemplateURLServiceFactory::GetForProfile(profile_
);
1182 if (!template_service
->loaded())
1183 template_service
->Load();
1186 ChromeBrowserProvider::~ChromeBrowserProvider() {
1187 bookmark_model_
->RemoveObserver(this);
1190 void ChromeBrowserProvider::Destroy(JNIEnv
*, jobject
) {
1191 history_service_observer_
.RemoveAll();
1195 // ------------- Provider public APIs ------------- //
1197 jlong
ChromeBrowserProvider::AddBookmark(JNIEnv
* env
,
1205 url
= ConvertJavaStringToUTF16(env
, jurl
);
1206 base::string16 title
= ConvertJavaStringToUTF16(env
, jtitle
);
1208 AddBookmarkTask
task(bookmark_model_
);
1209 return task
.Run(title
, url
, is_folder
, parent_id
);
1212 jint
ChromeBrowserProvider::RemoveBookmark(JNIEnv
*, jobject
, jlong id
) {
1213 RemoveBookmarkTask
task(bookmark_model_
);
1214 return task
.Run(id
);
1217 jint
ChromeBrowserProvider::UpdateBookmark(JNIEnv
* env
,
1225 url
= ConvertJavaStringToUTF16(env
, jurl
);
1226 base::string16 title
= ConvertJavaStringToUTF16(env
, jtitle
);
1228 UpdateBookmarkTask
task(bookmark_model_
);
1229 return task
.Run(id
, title
, url
, parent_id
);
1232 // Add the bookmark with the given column values.
1233 jlong
ChromeBrowserProvider::AddBookmarkFromAPI(JNIEnv
* env
,
1245 history::HistoryAndBookmarkRow row
;
1246 FillBookmarkRow(env
, obj
, url
, created
, isBookmark
, date
, favicon
, title
,
1247 visits
, parent_id
, &row
, bookmark_model_
);
1249 // URL must be valid.
1250 if (row
.url().is_empty()) {
1251 LOG(ERROR
) << "Not a valid URL " << row
.raw_url();
1252 return kInvalidContentProviderId
;
1255 AddBookmarkFromAPITask
task(service_
.get(), &cancelable_task_tracker_
);
1256 return task
.Run(row
);
1259 ScopedJavaLocalRef
<jobject
> ChromeBrowserProvider::QueryBookmarkFromAPI(
1262 jobjectArray projection
,
1264 jobjectArray selection_args
,
1265 jstring sort_order
) {
1266 // Converts the projection to array of ColumnID and column name.
1267 // Used to store the projection column ID according their sequence.
1268 std::vector
<history::HistoryAndBookmarkRow::ColumnID
> query_columns
;
1269 // Used to store the projection column names according their sequence.
1270 std::vector
<std::string
> columns_name
;
1272 jsize len
= env
->GetArrayLength(projection
);
1273 for (int i
= 0; i
< len
; i
++) {
1274 std::string name
= ConvertJavaStringToUTF8(env
, static_cast<jstring
>(
1275 env
->GetObjectArrayElement(projection
, i
)));
1276 history::HistoryAndBookmarkRow::ColumnID id
=
1277 history::HistoryAndBookmarkRow::GetColumnID(name
);
1278 if (id
== history::HistoryAndBookmarkRow::COLUMN_END
) {
1279 // Ignore the unknown column; As Android platform will send us
1280 // the non public column.
1283 query_columns
.push_back(id
);
1284 columns_name
.push_back(name
);
1288 std::vector
<base::string16
> where_args
=
1289 ConvertJStringArrayToString16Array(env
, selection_args
);
1291 std::string where_clause
;
1293 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1296 std::string sort_clause
;
1298 sort_clause
= ConvertJavaStringToUTF8(env
, sort_order
);
1301 QueryBookmarksFromAPITask
task(service_
.get(), &cancelable_task_tracker_
);
1302 history::AndroidStatement
* statement
= task
.Run(
1303 query_columns
, where_clause
, where_args
, sort_clause
);
1305 return ScopedJavaLocalRef
<jobject
>();
1307 // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
1309 return SQLiteCursor::NewJavaSqliteCursor(env
, columns_name
, statement
,
1313 // Updates the bookmarks with the given column values. The value is not given if
1315 jint
ChromeBrowserProvider::UpdateBookmarkFromAPI(JNIEnv
* env
,
1326 jobjectArray selection_args
) {
1327 history::HistoryAndBookmarkRow row
;
1328 FillBookmarkRow(env
, obj
, url
, created
, isBookmark
, date
, favicon
, title
,
1329 visits
, parent_id
, &row
, bookmark_model_
);
1331 std::vector
<base::string16
> where_args
=
1332 ConvertJStringArrayToString16Array(env
, selection_args
);
1334 std::string where_clause
;
1336 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1338 UpdateBookmarksFromAPITask
task(service_
.get(), &cancelable_task_tracker_
);
1339 return task
.Run(row
, where_clause
, where_args
);
1342 jint
ChromeBrowserProvider::RemoveBookmarkFromAPI(JNIEnv
* env
,
1345 jobjectArray selection_args
) {
1346 std::vector
<base::string16
> where_args
=
1347 ConvertJStringArrayToString16Array(env
, selection_args
);
1349 std::string where_clause
;
1351 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1353 RemoveBookmarksFromAPITask
task(service_
.get(), &cancelable_task_tracker_
);
1354 return task
.Run(where_clause
, where_args
);
1357 jint
ChromeBrowserProvider::RemoveHistoryFromAPI(JNIEnv
* env
,
1360 jobjectArray selection_args
) {
1361 std::vector
<base::string16
> where_args
=
1362 ConvertJStringArrayToString16Array(env
, selection_args
);
1364 std::string where_clause
;
1366 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1368 RemoveHistoryFromAPITask
task(service_
.get(), &cancelable_task_tracker_
);
1369 return task
.Run(where_clause
, where_args
);
1372 // Add the search term with the given column values. The value is not given if
1374 jlong
ChromeBrowserProvider::AddSearchTermFromAPI(JNIEnv
* env
,
1376 jstring search_term
,
1378 DCHECK(search_term
);
1380 history::SearchRow row
;
1381 FillSearchRow(env
, obj
, search_term
, date
, &row
);
1383 // URL must be valid.
1384 if (row
.search_term().empty()) {
1385 LOG(ERROR
) << "Search term is empty.";
1386 return kInvalidContentProviderId
;
1389 AddSearchTermFromAPITask
task(service_
.get(),
1390 &cancelable_task_tracker_
,
1392 return task
.Run(row
);
1395 ScopedJavaLocalRef
<jobject
> ChromeBrowserProvider::QuerySearchTermFromAPI(
1398 jobjectArray projection
,
1400 jobjectArray selection_args
,
1401 jstring sort_order
) {
1402 // Converts the projection to array of ColumnID and column name.
1403 // Used to store the projection column ID according their sequence.
1404 std::vector
<history::SearchRow::ColumnID
> query_columns
;
1405 // Used to store the projection column names according their sequence.
1406 std::vector
<std::string
> columns_name
;
1408 jsize len
= env
->GetArrayLength(projection
);
1409 for (int i
= 0; i
< len
; i
++) {
1410 std::string name
= ConvertJavaStringToUTF8(env
, static_cast<jstring
>(
1411 env
->GetObjectArrayElement(projection
, i
)));
1412 history::SearchRow::ColumnID id
=
1413 history::SearchRow::GetColumnID(name
);
1414 if (id
== history::SearchRow::COLUMN_END
) {
1415 LOG(ERROR
) << "Can not find " << name
;
1416 return ScopedJavaLocalRef
<jobject
>();
1418 query_columns
.push_back(id
);
1419 columns_name
.push_back(name
);
1423 std::vector
<base::string16
> where_args
=
1424 ConvertJStringArrayToString16Array(env
, selection_args
);
1426 std::string where_clause
;
1428 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1431 std::string sort_clause
;
1433 sort_clause
= ConvertJavaStringToUTF8(env
, sort_order
);
1436 QuerySearchTermsFromAPITask
task(service_
.get(),
1437 &cancelable_task_tracker_
,
1439 history::AndroidStatement
* statement
= task
.Run(
1440 query_columns
, where_clause
, where_args
, sort_clause
);
1442 return ScopedJavaLocalRef
<jobject
>();
1443 // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
1445 return SQLiteCursor::NewJavaSqliteCursor(env
, columns_name
, statement
,
1449 // Updates the search terms with the given column values. The value is not
1450 // given if it is NULL.
1451 jint
ChromeBrowserProvider::UpdateSearchTermFromAPI(
1452 JNIEnv
* env
, jobject obj
, jstring search_term
, jobject date
,
1453 jstring selections
, jobjectArray selection_args
) {
1454 history::SearchRow row
;
1455 FillSearchRow(env
, obj
, search_term
, date
, &row
);
1457 std::vector
<base::string16
> where_args
= ConvertJStringArrayToString16Array(
1458 env
, selection_args
);
1460 std::string where_clause
;
1462 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1464 UpdateSearchTermsFromAPITask
task(service_
.get(),
1465 &cancelable_task_tracker_
,
1467 return task
.Run(row
, where_clause
, where_args
);
1470 jint
ChromeBrowserProvider::RemoveSearchTermFromAPI(
1471 JNIEnv
* env
, jobject obj
, jstring selections
, jobjectArray selection_args
) {
1472 std::vector
<base::string16
> where_args
=
1473 ConvertJStringArrayToString16Array(env
, selection_args
);
1475 std::string where_clause
;
1477 where_clause
= ConvertJavaStringToUTF8(env
, selections
);
1479 RemoveSearchTermsFromAPITask
task(service_
.get(),
1480 &cancelable_task_tracker_
,
1482 return task
.Run(where_clause
, where_args
);
1485 // ------------- Provider custom APIs ------------- //
1487 jboolean
ChromeBrowserProvider::BookmarkNodeExists(
1491 BookmarkNodeExistsTask
task(bookmark_model_
);
1492 return task
.Run(id
);
1495 jlong
ChromeBrowserProvider::CreateBookmarksFolderOnce(
1500 base::string16 title
= ConvertJavaStringToUTF16(env
, jtitle
);
1502 return kInvalidBookmarkId
;
1504 CreateBookmarksFolderOnceTask
task(bookmark_model_
);
1505 return task
.Run(title
, parent_id
);
1508 ScopedJavaLocalRef
<jobject
> ChromeBrowserProvider::GetEditableBookmarkFolders(
1511 ScopedJavaGlobalRef
<jobject
> jroot
;
1512 ChromeBookmarkClient
* client
=
1513 ChromeBookmarkClientFactory::GetForProfile(profile_
);
1514 BookmarkModel
* model
= BookmarkModelFactory::GetForProfile(profile_
);
1515 GetEditableBookmarkFoldersTask
task(client
, model
);
1517 return ScopedJavaLocalRef
<jobject
>(jroot
);
1520 void ChromeBrowserProvider::RemoveAllUserBookmarks(JNIEnv
* env
, jobject obj
) {
1521 LOG(ERROR
) << "begin ChromeBrowserProvider::RemoveAllUserBookmarks";
1522 RemoveAllUserBookmarksTask
task(bookmark_model_
);
1524 LOG(ERROR
) << "end ChromeBrowserProvider::RemoveAllUserBookmarks";
1527 ScopedJavaLocalRef
<jobject
> ChromeBrowserProvider::GetBookmarkNode(
1528 JNIEnv
* env
, jobject obj
, jlong id
, jboolean get_parent
,
1529 jboolean get_children
) {
1530 ScopedJavaGlobalRef
<jobject
> jnode
;
1531 GetBookmarkNodeTask
task(bookmark_model_
);
1532 task
.Run(id
, get_parent
, get_children
, &jnode
);
1533 return ScopedJavaLocalRef
<jobject
>(jnode
);
1536 ScopedJavaLocalRef
<jobject
> ChromeBrowserProvider::GetMobileBookmarksFolder(
1539 ScopedJavaGlobalRef
<jobject
> jnode
;
1540 GetMobileBookmarksNodeTask
task(bookmark_model_
);
1541 ConvertBookmarkNode(task
.Run(), ScopedJavaLocalRef
<jobject
>(), &jnode
);
1542 return ScopedJavaLocalRef
<jobject
>(jnode
);
1545 jboolean
ChromeBrowserProvider::IsBookmarkInMobileBookmarksBranch(
1549 IsInMobileBookmarksBranchTask
task(bookmark_model_
);
1550 return task
.Run(id
);
1553 ScopedJavaLocalRef
<jbyteArray
> ChromeBrowserProvider::GetFaviconOrTouchIcon(
1554 JNIEnv
* env
, jobject obj
, jstring jurl
) {
1556 return ScopedJavaLocalRef
<jbyteArray
>();
1558 GURL url
= GURL(ConvertJavaStringToUTF16(env
, jurl
));
1559 BookmarkIconFetchTask
favicon_task(&cancelable_task_tracker_
, profile_
,
1561 favicon_base::FaviconRawBitmapResult bitmap_result
= favicon_task
.Run(url
);
1563 if (!bitmap_result
.is_valid() || !bitmap_result
.bitmap_data
.get())
1564 return ScopedJavaLocalRef
<jbyteArray
>();
1566 return base::android::ToJavaByteArray(env
, bitmap_result
.bitmap_data
->front(),
1567 bitmap_result
.bitmap_data
->size());
1570 ScopedJavaLocalRef
<jbyteArray
> ChromeBrowserProvider::GetThumbnail(
1571 JNIEnv
* env
, jobject obj
, jstring jurl
) {
1573 return ScopedJavaLocalRef
<jbyteArray
>();
1574 GURL url
= GURL(ConvertJavaStringToUTF16(env
, jurl
));
1576 // GetPageThumbnail is synchronous and can be called from any thread.
1577 scoped_refptr
<base::RefCountedMemory
> thumbnail
;
1579 top_sites_
->GetPageThumbnail(url
, false, &thumbnail
);
1581 if (!thumbnail
.get() || !thumbnail
->front()) {
1582 return ScopedJavaLocalRef
<jbyteArray
>();
1585 return base::android::ToJavaByteArray(env
, thumbnail
->front(),
1589 // ------------- Observer-related methods ------------- //
1591 void ChromeBrowserProvider::ExtensiveBookmarkChangesBeginning(
1592 BookmarkModel
* model
) {
1593 handling_extensive_changes_
= true;
1596 void ChromeBrowserProvider::ExtensiveBookmarkChangesEnded(
1597 BookmarkModel
* model
) {
1598 handling_extensive_changes_
= false;
1599 BookmarkModelChanged();
1602 void ChromeBrowserProvider::BookmarkModelChanged() {
1603 if (handling_extensive_changes_
)
1606 JNIEnv
* env
= AttachCurrentThread();
1607 ScopedJavaLocalRef
<jobject
> obj
= weak_java_provider_
.get(env
);
1611 Java_ChromeBrowserProvider_onBookmarkChanged(env
, obj
.obj());
1614 void ChromeBrowserProvider::OnHistoryChanged() {
1615 JNIEnv
* env
= AttachCurrentThread();
1616 ScopedJavaLocalRef
<jobject
> obj
= weak_java_provider_
.get(env
);
1619 Java_ChromeBrowserProvider_onHistoryChanged(env
, obj
.obj());
1622 void ChromeBrowserProvider::OnURLVisited(HistoryService
* history_service
,
1623 ui::PageTransition transition
,
1624 const history::URLRow
& row
,
1625 const history::RedirectList
& redirects
,
1626 base::Time visit_time
) {
1630 void ChromeBrowserProvider::OnURLsDeleted(HistoryService
* history_service
,
1633 const history::URLRows
& deleted_rows
,
1634 const std::set
<GURL
>& favicon_urls
) {
1638 void ChromeBrowserProvider::OnKeywordSearchTermUpdated(
1639 HistoryService
* history_service
,
1640 const history::URLRow
& row
,
1641 history::KeywordID keyword_id
,
1642 const base::string16
& term
) {
1643 JNIEnv
* env
= AttachCurrentThread();
1644 ScopedJavaLocalRef
<jobject
> obj
= weak_java_provider_
.get(env
);
1647 Java_ChromeBrowserProvider_onSearchTermChanged(env
, obj
.obj());
1650 void ChromeBrowserProvider::OnKeywordSearchTermDeleted(
1651 HistoryService
* history_service
,
1652 history::URLID url_id
) {