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

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

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

Powered by Google App Engine
This is Rietveld 408576698