Add more checks to investigate SupervisedUserPrefStore crash at startup.
[chromium-blink-merge.git] / chrome / browser / android / provider / chrome_browser_provider.cc
blob05667a79bb0feda9d13214f80e1f0ce921566f31
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"
7 #include <cmath>
8 #include <list>
9 #include <utility>
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.
96 namespace {
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) {
110 DCHECK(jnode);
111 if (!node)
112 return;
114 JNIEnv* env = AttachCurrentThread();
115 ScopedJavaLocalRef<jstring> url;
116 if (node->is_url())
117 url.Reset(ConvertUTF8ToJavaString(env, node->url().spec()));
118 ScopedJavaLocalRef<jstring> title(
119 ConvertUTF16ToJavaString(env, node->GetTitle()));
121 jnode->Reset(
122 Java_BookmarkNode_create(
123 env, node->id(), (jint) node->type(), title.obj(), url.obj(),
124 parent_node.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(
156 JNIEnv* env,
157 jobjectArray array) {
158 std::vector<base::string16> results;
159 if (array) {
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))));
166 return results;
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) {
175 GURL gurl(url);
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);
181 return gurl;
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);
192 return NULL;
195 // ------------- Synchronous task classes ------------- //
197 // Utility task to add a bookmark.
198 class AddBookmarkTask : public BookmarkModelTask {
199 public:
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));
210 return 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,
218 int64* result) {
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
220 DCHECK(result);
221 GURL gurl = ParseAndMaybeAppendScheme(url, kDefaultUrlScheme);
223 // Check if the bookmark already exists.
224 const BookmarkNode* node = model->GetMostRecentlyAddedUserNodeForURL(gurl);
225 if (!node) {
226 const BookmarkNode* parent_node = NULL;
227 if (parent_id >= 0)
228 parent_node = bookmarks::GetBookmarkNodeByID(model, parent_id);
229 if (!parent_node)
230 parent_node = model->bookmark_bar_node();
232 if (is_folder)
233 node = model->AddFolder(parent_node, parent_node->child_count(), title);
234 else
235 node = model->AddURL(parent_node, 0, title, gurl);
238 *result = node ? node ->id() : kInvalidBookmarkId;
241 private:
242 DISALLOW_COPY_AND_ASSIGN(AddBookmarkTask);
245 // Utility method to remove a bookmark.
246 class RemoveBookmarkTask : public BookmarkModelObserverTask {
247 public:
248 explicit RemoveBookmarkTask(BookmarkModel* model)
249 : BookmarkModelObserverTask(model),
250 deleted_(0),
251 id_to_delete_(kInvalidBookmarkId) {}
252 ~RemoveBookmarkTask() override {}
254 int Run(const int64 id) {
255 id_to_delete_ = id;
256 RunOnUIThreadBlocking::Run(
257 base::Bind(&RemoveBookmarkTask::RunOnUIThread, model(), id));
258 return deleted_;
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,
273 int old_index,
274 const BookmarkNode* node,
275 const std::set<GURL>& removed_urls) override {
276 if (bookmark_model == model() && node->id() == id_to_delete_)
277 ++deleted_;
280 private:
281 int deleted_;
282 int64 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 {
289 public:
290 explicit RemoveAllUserBookmarksTask(BookmarkModel* model)
291 : BookmarkModelObserverTask(model) {}
293 ~RemoveAllUserBookmarksTask() override {}
295 void Run() {
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";
307 private:
308 DISALLOW_COPY_AND_ASSIGN(RemoveAllUserBookmarksTask);
311 // Utility method to update a bookmark.
312 class UpdateBookmarkTask : public BookmarkModelObserverTask {
313 public:
314 explicit UpdateBookmarkTask(BookmarkModel* model)
315 : BookmarkModelObserverTask(model),
316 updated_(0),
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) {
324 id_to_update_ = id;
325 RunOnUIThreadBlocking::Run(
326 base::Bind(&UpdateBookmarkTask::RunOnUIThread,
327 model(), id, title, url, parent_id));
328 return updated_;
331 static void RunOnUIThread(BookmarkModel* model,
332 const int64 id,
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);
338 if (node) {
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);
353 if (new_parent)
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_)
363 ++updated_;
366 private:
367 int updated_;
368 int64 id_to_update_;
370 DISALLOW_COPY_AND_ASSIGN(UpdateBookmarkTask);
373 // Checks if a node exists in the bookmark model.
374 class BookmarkNodeExistsTask : public BookmarkModelTask {
375 public:
376 explicit BookmarkNodeExistsTask(BookmarkModel* model)
377 : BookmarkModelTask(model) {
380 bool Run(const int64 id) {
381 bool result = false;
382 RunOnUIThreadBlocking::Run(
383 base::Bind(&BookmarkNodeExistsTask::RunOnUIThread,
384 model(), id, &result));
385 return result;
388 static void RunOnUIThread(BookmarkModel* model,
389 const int64 id,
390 bool* result) {
391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
392 DCHECK(result);
393 *result = bookmarks::GetBookmarkNodeByID(model, id) != NULL;
396 private:
397 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeExistsTask);
400 // Checks if a node belongs to the Mobile Bookmarks hierarchy branch.
401 class IsInMobileBookmarksBranchTask : public BookmarkModelTask {
402 public:
403 explicit IsInMobileBookmarksBranchTask(BookmarkModel* model)
404 : BookmarkModelTask(model) {}
406 bool Run(const int64 id) {
407 bool result = false;
408 RunOnUIThreadBlocking::Run(
409 base::Bind(&IsInMobileBookmarksBranchTask::RunOnUIThread,
410 model(), id, &result));
411 return result;
414 static void RunOnUIThread(BookmarkModel* model,
415 const int64 id,
416 bool *result) {
417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
418 DCHECK(result);
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;
427 private:
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 {
435 public:
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));
444 return result;
447 static void RunOnUIThread(BookmarkModel* model,
448 const base::string16& title,
449 const int64 parent_id,
450 int64* result) {
451 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
452 DCHECK(result);
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();
458 DCHECK(parent);
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;
466 return;
469 const BookmarkNode* node = GetChildFolderByTitle(parent, title);
470 if (node) {
471 *result = node->id();
472 return;
475 AddBookmarkTask::RunOnUIThread(model, title, base::string16(), true,
476 parent->id(), result);
479 private:
480 DISALLOW_COPY_AND_ASSIGN(CreateBookmarksFolderOnceTask);
483 // Creates a Java BookmarkNode object for a node given its id.
484 class GetEditableBookmarkFoldersTask : public BookmarkModelTask {
485 public:
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())
502 return;
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);
510 private:
511 static void ConvertFolderSubtree(ChromeBookmarkClient* client,
512 JNIEnv* env,
513 const BookmarkNode* node,
514 const JavaRef<jobject>& parent_folder,
515 ScopedJavaGlobalRef<jobject>* jfolder) {
516 DCHECK(node);
517 DCHECK(node->is_folder());
518 DCHECK(jfolder);
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.";
533 return;
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 {
546 public:
547 explicit GetBookmarkNodeTask(BookmarkModel* model)
548 : BookmarkModelTask(model) {
551 void Run(const int64 id,
552 bool get_parent,
553 bool get_children,
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,
561 const int64 id,
562 bool get_parent,
563 bool get_children,
564 ScopedJavaGlobalRef<jobject>* jnode) {
565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
566 const BookmarkNode* node = bookmarks::GetBookmarkNodeByID(model, id);
567 if (!node || !jnode)
568 return;
570 ScopedJavaGlobalRef<jobject> jparent;
571 if (get_parent) {
572 ConvertBookmarkNode(node->parent(), ScopedJavaLocalRef<jobject>(),
573 &jparent);
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.";
583 return;
587 if (get_children) {
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.";
594 return;
600 private:
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 {
607 public:
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,
615 model(), &result));
616 return result;
619 static void RunOnUIThread(BookmarkModel* model, const BookmarkNode** result) {
620 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
621 DCHECK(result);
622 *result = model->mobile_node();
625 private:
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 {
635 public:
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_;
646 private:
647 Service* service_;
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> {
655 public:
656 FaviconServiceTask(base::CancelableTaskTracker* cancelable_tracker,
657 Profile* profile,
658 FaviconService* favicon_service)
659 : AsyncServiceRequest<FaviconService>(favicon_service,
660 cancelable_tracker),
661 profile_(profile) {}
663 Profile* profile() const { return profile_; }
665 private:
666 Profile* 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 {
673 public:
674 BookmarkIconFetchTask(base::CancelableTaskTracker* cancelable_tracker,
675 Profile* profile,
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()),
690 url,
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()));
696 return result_;
699 private:
700 void OnFaviconRetrieved(
701 const favicon_base::FaviconRawBitmapResult& bitmap_result) {
702 result_ = bitmap_result;
703 RequestCompleted();
706 favicon_base::FaviconRawBitmapResult result_;
708 DISALLOW_COPY_AND_ASSIGN(BookmarkIconFetchTask);
711 // Base class for all asynchronous blocking tasks that use the Android history
712 // provider service.
713 class HistoryProviderTask
714 : public AsyncServiceRequest<AndroidHistoryProviderService> {
715 public:
716 HistoryProviderTask(AndroidHistoryProviderService* service,
717 base::CancelableTaskTracker* cancelable_tracker)
718 : AsyncServiceRequest<AndroidHistoryProviderService>(service,
719 cancelable_tracker) {
722 private:
723 DISALLOW_COPY_AND_ASSIGN(HistoryProviderTask);
726 // Adds a bookmark from the API.
727 class AddBookmarkFromAPITask : public HistoryProviderTask {
728 public:
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()),
737 row,
738 base::Bind(&AddBookmarkFromAPITask::OnBookmarkInserted,
739 base::Unretained(this)),
740 cancelable_tracker()));
741 return result_;
744 private:
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.
748 result_ = id;
749 RequestCompleted();
752 history::URLID result_;
754 DISALLOW_COPY_AND_ASSIGN(AddBookmarkFromAPITask);
757 // Queries bookmarks from the API.
758 class QueryBookmarksFromAPITask : public HistoryProviderTask {
759 public:
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()),
772 projections,
773 selection,
774 selection_args,
775 sort_order,
776 base::Bind(&QueryBookmarksFromAPITask::OnBookmarksQueried,
777 base::Unretained(this)),
778 cancelable_tracker()));
779 return result_;
782 private:
783 void OnBookmarksQueried(history::AndroidStatement* statement) {
784 result_ = statement;
785 RequestCompleted();
788 history::AndroidStatement* result_;
790 DISALLOW_COPY_AND_ASSIGN(QueryBookmarksFromAPITask);
793 // Updates bookmarks from the API.
794 class UpdateBookmarksFromAPITask : public HistoryProviderTask {
795 public:
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()),
806 row,
807 selection,
808 selection_args,
809 base::Bind(&UpdateBookmarksFromAPITask::OnBookmarksUpdated,
810 base::Unretained(this)),
811 cancelable_tracker()));
812 return result_;
815 private:
816 void OnBookmarksUpdated(int updated_row_count) {
817 result_ = updated_row_count;
818 RequestCompleted();
821 int result_;
823 DISALLOW_COPY_AND_ASSIGN(UpdateBookmarksFromAPITask);
826 // Removes bookmarks from the API.
827 class RemoveBookmarksFromAPITask : public HistoryProviderTask {
828 public:
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()),
838 selection,
839 selection_args,
840 base::Bind(&RemoveBookmarksFromAPITask::OnBookmarksRemoved,
841 base::Unretained(this)),
842 cancelable_tracker()));
843 return result_;
846 private:
847 void OnBookmarksRemoved(int removed_row_count) {
848 result_ = removed_row_count;
849 RequestCompleted();
852 int result_;
854 DISALLOW_COPY_AND_ASSIGN(RemoveBookmarksFromAPITask);
857 // Removes history from the API.
858 class RemoveHistoryFromAPITask : public HistoryProviderTask {
859 public:
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()),
869 selection,
870 selection_args,
871 base::Bind(&RemoveHistoryFromAPITask::OnHistoryRemoved,
872 base::Unretained(this)),
873 cancelable_tracker()));
874 return result_;
877 private:
878 void OnHistoryRemoved(int removed_row_count) {
879 result_ = removed_row_count;
880 RequestCompleted();
883 int result_;
885 DISALLOW_COPY_AND_ASSIGN(RemoveHistoryFromAPITask);
888 // This class provides the common method for the SearchTermAPIHelper.
889 class SearchTermTask : public HistoryProviderTask {
890 protected:
891 SearchTermTask(AndroidHistoryProviderService* service,
892 base::CancelableTaskTracker* cancelable_tracker,
893 Profile* profile)
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();
907 if (search_engine) {
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());
913 if (!url.empty()) {
914 row->set_url(GURL(url));
915 row->set_keyword_id(search_engine->id());
920 private:
921 Profile* profile_;
923 DISALLOW_COPY_AND_ASSIGN(SearchTermTask);
926 // Adds a search term from the API.
927 class AddSearchTermFromAPITask : public SearchTermTask {
928 public:
929 AddSearchTermFromAPITask(AndroidHistoryProviderService* service,
930 base::CancelableTaskTracker* cancelable_tracker,
931 Profile* profile)
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));
938 return result_;
941 private:
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(
947 internal_row,
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.
956 result_ = id;
957 RequestCompleted();
960 history::URLID result_;
962 DISALLOW_COPY_AND_ASSIGN(AddSearchTermFromAPITask);
965 // Queries search terms from the API.
966 class QuerySearchTermsFromAPITask : public SearchTermTask {
967 public:
968 QuerySearchTermsFromAPITask(AndroidHistoryProviderService* service,
969 base::CancelableTaskTracker* cancelable_tracker,
970 Profile* profile)
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()),
981 projections,
982 selection,
983 selection_args,
984 sort_order,
985 base::Bind(&QuerySearchTermsFromAPITask::OnSearchTermsQueried,
986 base::Unretained(this)),
987 cancelable_tracker()));
988 return result_;
991 private:
992 // Callback to return the result.
993 void OnSearchTermsQueried(history::AndroidStatement* statement) {
994 result_ = statement;
995 RequestCompleted();
998 history::AndroidStatement* result_;
1000 DISALLOW_COPY_AND_ASSIGN(QuerySearchTermsFromAPITask);
1003 // Updates search terms from the API.
1004 class UpdateSearchTermsFromAPITask : public SearchTermTask {
1005 public:
1006 UpdateSearchTermsFromAPITask(AndroidHistoryProviderService* service,
1007 base::CancelableTaskTracker* cancelable_tracker,
1008 Profile* profile)
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));
1017 return result_;
1020 private:
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(
1029 internal_row,
1030 selection,
1031 selection_args,
1032 base::Bind(&UpdateSearchTermsFromAPITask::OnSearchTermsUpdated,
1033 base::Unretained(this)),
1034 cancelable_tracker());
1037 void OnSearchTermsUpdated(int updated_row_count) {
1038 result_ = updated_row_count;
1039 RequestCompleted();
1042 int result_;
1044 DISALLOW_COPY_AND_ASSIGN(UpdateSearchTermsFromAPITask);
1047 // Removes search terms from the API.
1048 class RemoveSearchTermsFromAPITask : public SearchTermTask {
1049 public:
1050 RemoveSearchTermsFromAPITask(AndroidHistoryProviderService* service,
1051 base::CancelableTaskTracker* cancelable_tracker,
1052 Profile* profile)
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()),
1060 selection,
1061 selection_args,
1062 base::Bind(&RemoveSearchTermsFromAPITask::OnSearchTermsDeleted,
1063 base::Unretained(this)),
1064 cancelable_tracker()));
1065 return result_;
1068 private:
1069 void OnSearchTermsDeleted(int deleted_row_count) {
1070 result_ = deleted_row_count;
1071 RequestCompleted();
1074 int result_;
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,
1083 jobject obj,
1084 jstring url,
1085 jobject created,
1086 jobject isBookmark,
1087 jobject date,
1088 jbyteArray favicon,
1089 jstring title,
1090 jobject visits,
1091 jlong parent_id,
1092 history::HistoryAndBookmarkRow* row,
1093 BookmarkModel* model) {
1094 // Needed because of the internal bookmark model task invocation.
1095 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
1097 if (url) {
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);
1104 row->set_url(gurl);
1105 row->set_raw_url(base::UTF16ToUTF8(raw_url));
1108 if (created)
1109 row->set_created(ConvertJlongToTime(
1110 ConvertJLongObjectToPrimitive(env, created)));
1112 if (isBookmark)
1113 row->set_is_bookmark(ConvertJBooleanObjectToPrimitive(env, isBookmark));
1115 if (date)
1116 row->set_last_visit_time(ConvertJlongToTime(ConvertJLongObjectToPrimitive(
1117 env, date)));
1119 if (favicon) {
1120 std::vector<uint8> bytes;
1121 base::android::JavaByteArrayToByteVector(env, favicon, &bytes);
1122 row->set_favicon(base::RefCountedBytes::TakeVector(&bytes));
1125 if (title)
1126 row->set_title(ConvertJavaStringToUTF16(env, title));
1128 if (visits)
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,
1139 jobject obj,
1140 jstring search_term,
1141 jobject date,
1142 history::SearchRow* row) {
1143 if (search_term)
1144 row->set_search_term(ConvertJavaStringToUTF16(env, search_term));
1146 if (date)
1147 row->set_search_time(ConvertJlongToTime(ConvertJLongObjectToPrimitive(
1148 env, date)));
1151 } // namespace
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();
1192 delete this;
1195 // ------------- Provider public APIs ------------- //
1197 jlong ChromeBrowserProvider::AddBookmark(JNIEnv* env,
1198 jobject,
1199 jstring jurl,
1200 jstring jtitle,
1201 jboolean is_folder,
1202 jlong parent_id) {
1203 base::string16 url;
1204 if (jurl)
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,
1218 jobject,
1219 jlong id,
1220 jstring jurl,
1221 jstring jtitle,
1222 jlong parent_id) {
1223 base::string16 url;
1224 if (jurl)
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,
1234 jobject obj,
1235 jstring url,
1236 jobject created,
1237 jobject isBookmark,
1238 jobject date,
1239 jbyteArray favicon,
1240 jstring title,
1241 jobject visits,
1242 jlong parent_id) {
1243 DCHECK(url);
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(
1260 JNIEnv* env,
1261 jobject obj,
1262 jobjectArray projection,
1263 jstring selections,
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;
1271 if (projection) {
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.
1281 continue;
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;
1292 if (selections) {
1293 where_clause = ConvertJavaStringToUTF8(env, selections);
1296 std::string sort_clause;
1297 if (sort_order) {
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);
1304 if (!statement)
1305 return ScopedJavaLocalRef<jobject>();
1307 // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
1308 // Java object.
1309 return SQLiteCursor::NewJavaSqliteCursor(env, columns_name, statement,
1310 service_.get());
1313 // Updates the bookmarks with the given column values. The value is not given if
1314 // it is NULL.
1315 jint ChromeBrowserProvider::UpdateBookmarkFromAPI(JNIEnv* env,
1316 jobject obj,
1317 jstring url,
1318 jobject created,
1319 jobject isBookmark,
1320 jobject date,
1321 jbyteArray favicon,
1322 jstring title,
1323 jobject visits,
1324 jlong parent_id,
1325 jstring selections,
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;
1335 if (selections)
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,
1343 jobject obj,
1344 jstring selections,
1345 jobjectArray selection_args) {
1346 std::vector<base::string16> where_args =
1347 ConvertJStringArrayToString16Array(env, selection_args);
1349 std::string where_clause;
1350 if (selections)
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,
1358 jobject obj,
1359 jstring selections,
1360 jobjectArray selection_args) {
1361 std::vector<base::string16> where_args =
1362 ConvertJStringArrayToString16Array(env, selection_args);
1364 std::string where_clause;
1365 if (selections)
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
1373 // it is NULL.
1374 jlong ChromeBrowserProvider::AddSearchTermFromAPI(JNIEnv* env,
1375 jobject obj,
1376 jstring search_term,
1377 jobject date) {
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_,
1391 profile_);
1392 return task.Run(row);
1395 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::QuerySearchTermFromAPI(
1396 JNIEnv* env,
1397 jobject obj,
1398 jobjectArray projection,
1399 jstring selections,
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;
1407 if (projection) {
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;
1427 if (selections) {
1428 where_clause = ConvertJavaStringToUTF8(env, selections);
1431 std::string sort_clause;
1432 if (sort_order) {
1433 sort_clause = ConvertJavaStringToUTF8(env, sort_order);
1436 QuerySearchTermsFromAPITask task(service_.get(),
1437 &cancelable_task_tracker_,
1438 profile_);
1439 history::AndroidStatement* statement = task.Run(
1440 query_columns, where_clause, where_args, sort_clause);
1441 if (!statement)
1442 return ScopedJavaLocalRef<jobject>();
1443 // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
1444 // Java object.
1445 return SQLiteCursor::NewJavaSqliteCursor(env, columns_name, statement,
1446 service_.get());
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;
1461 if (selections)
1462 where_clause = ConvertJavaStringToUTF8(env, selections);
1464 UpdateSearchTermsFromAPITask task(service_.get(),
1465 &cancelable_task_tracker_,
1466 profile_);
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;
1476 if (selections)
1477 where_clause = ConvertJavaStringToUTF8(env, selections);
1479 RemoveSearchTermsFromAPITask task(service_.get(),
1480 &cancelable_task_tracker_,
1481 profile_);
1482 return task.Run(where_clause, where_args);
1485 // ------------- Provider custom APIs ------------- //
1487 jboolean ChromeBrowserProvider::BookmarkNodeExists(
1488 JNIEnv* env,
1489 jobject obj,
1490 jlong id) {
1491 BookmarkNodeExistsTask task(bookmark_model_);
1492 return task.Run(id);
1495 jlong ChromeBrowserProvider::CreateBookmarksFolderOnce(
1496 JNIEnv* env,
1497 jobject obj,
1498 jstring jtitle,
1499 jlong parent_id) {
1500 base::string16 title = ConvertJavaStringToUTF16(env, jtitle);
1501 if (title.empty())
1502 return kInvalidBookmarkId;
1504 CreateBookmarksFolderOnceTask task(bookmark_model_);
1505 return task.Run(title, parent_id);
1508 ScopedJavaLocalRef<jobject> ChromeBrowserProvider::GetEditableBookmarkFolders(
1509 JNIEnv* env,
1510 jobject obj) {
1511 ScopedJavaGlobalRef<jobject> jroot;
1512 ChromeBookmarkClient* client =
1513 ChromeBookmarkClientFactory::GetForProfile(profile_);
1514 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile_);
1515 GetEditableBookmarkFoldersTask task(client, model);
1516 task.Run(&jroot);
1517 return ScopedJavaLocalRef<jobject>(jroot);
1520 void ChromeBrowserProvider::RemoveAllUserBookmarks(JNIEnv* env, jobject obj) {
1521 LOG(ERROR) << "begin ChromeBrowserProvider::RemoveAllUserBookmarks";
1522 RemoveAllUserBookmarksTask task(bookmark_model_);
1523 task.Run();
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(
1537 JNIEnv* env,
1538 jobject obj) {
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(
1546 JNIEnv* env,
1547 jobject obj,
1548 jlong id) {
1549 IsInMobileBookmarksBranchTask task(bookmark_model_);
1550 return task.Run(id);
1553 ScopedJavaLocalRef<jbyteArray> ChromeBrowserProvider::GetFaviconOrTouchIcon(
1554 JNIEnv* env, jobject obj, jstring jurl) {
1555 if (!jurl)
1556 return ScopedJavaLocalRef<jbyteArray>();
1558 GURL url = GURL(ConvertJavaStringToUTF16(env, jurl));
1559 BookmarkIconFetchTask favicon_task(&cancelable_task_tracker_, profile_,
1560 favicon_service_);
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) {
1572 if (!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;
1578 if (top_sites_)
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(),
1586 thumbnail->size());
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_)
1604 return;
1606 JNIEnv* env = AttachCurrentThread();
1607 ScopedJavaLocalRef<jobject> obj = weak_java_provider_.get(env);
1608 if (obj.is_null())
1609 return;
1611 Java_ChromeBrowserProvider_onBookmarkChanged(env, obj.obj());
1614 void ChromeBrowserProvider::OnHistoryChanged() {
1615 JNIEnv* env = AttachCurrentThread();
1616 ScopedJavaLocalRef<jobject> obj = weak_java_provider_.get(env);
1617 if (obj.is_null())
1618 return;
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) {
1627 OnHistoryChanged();
1630 void ChromeBrowserProvider::OnURLsDeleted(HistoryService* history_service,
1631 bool all_history,
1632 bool expired,
1633 const history::URLRows& deleted_rows,
1634 const std::set<GURL>& favicon_urls) {
1635 OnHistoryChanged();
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);
1645 if (obj.is_null())
1646 return;
1647 Java_ChromeBrowserProvider_onSearchTermChanged(env, obj.obj());
1650 void ChromeBrowserProvider::OnKeywordSearchTermDeleted(
1651 HistoryService* history_service,
1652 history::URLID url_id) {