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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/android/provider/chrome_browser_provider.cc
diff --git a/chrome/browser/android/provider/chrome_browser_provider.cc b/chrome/browser/android/provider/chrome_browser_provider.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fd10a9fa9d21916e0f078e036e1e9fcbfcff7b9b
--- /dev/null
+++ b/chrome/browser/android/provider/chrome_browser_provider.cc
@@ -0,0 +1,1576 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/provider/chrome_browser_provider.h"
+
+#include <list>
+#include <utility>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/android/provider/blocking_ui_thread_async_request.h"
+#include "chrome/browser/android/provider/bookmark_model_observer_task.h"
+#include "chrome/browser/android/provider/run_on_ui_thread_blocking.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/favicon/favicon_service.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
+#include "chrome/browser/history/android/android_history_types.h"
+#include "chrome/browser/history/android/sqlite_cursor.h"
+#include "chrome/browser/history/top_sites.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
+#include "grit/generated_resources.h"
+#include "jni/ChromeBrowserProvider_jni.h"
+#include "sql/statement.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/layout.h"
+#include "ui/gfx/favicon_size.h"
+
+using base::android::AttachCurrentThread;
+using base::android::CheckException;
+using base::android::ClearException;
+using base::android::ConvertJavaStringToUTF16;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::GetClass;
+using base::android::GetMethodID;
+using base::android::JavaRef;
+using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
+using content::BrowserThread;
+
+// After refactoring the following class hierarchy has been created in order
+// to avoid repeating code again for the same basic kind of tasks, to enforce
+// the correct thread usage and to prevent known race conditions and deadlocks.
+//
+// - RunOnUIThreadBlocking: auxiliary class to run methods in the UI thread
+// blocking the current one until finished. Because of the provider threading
+// expectations this cannot be used from the UI thread.
+//
+// - BookmarkModelTask: base class for all tasks that operate in any way with
+// the bookmark model. This class ensures that the model is loaded and
+// prevents possible deadlocks. Derived classes should make use of
+// RunOnUIThreadBlocking to perform any manipulation of the bookmark model in
+// the UI thread. The Run method of these tasks cannot be invoked directly
+// from the UI thread, but RunOnUIThread can be safely used from the UI
+// thread code of other BookmarkModelTasks.
+//
+// - AsyncServiceRequest: base class for any asynchronous requests made to a
+// Chromium service that require to block the current thread until completed.
+// Derived classes should make use of RunAsyncRequestOnUIThreadBlocking to
+// post their requests in the UI thread and return the results synchronously.
+// All derived classes MUST ALWAYS call RequestCompleted when receiving the
+// request response. These tasks cannot be invoked from the UI thread.
+//
+// - FaviconServiceTask: base class for asynchronous requests that make use of
+// Chromium's favicon service. See AsyncServiceRequest for more details.
+//
+// - HistoryProviderTask: base class for asynchronous requests that make use of
+// AndroidHistoryProviderService. See AsyncServiceRequest for mode details.
+//
+// - SearchTermTask: base class for asynchronous requests that involve the
+// search term API. Works in the same way as HistoryProviderTask.
+
+namespace {
+
+const char kDefaultUrlScheme[] = "http://";
+const int64 kInvalidContentProviderId = 0;
+const int64 kInvalidBookmarkId = -1;
+
+// ------------- Java-related utility methods ------------- //
+
+// Convert a BookmarkNode, |node|, to the java representation of a bookmark node
+// stored in |*jnode|. Parent node information is optional.
+void ConvertBookmarkNode(
+ const BookmarkNode* node,
+ const JavaRef<jobject>& parent_node,
+ ScopedJavaGlobalRef<jobject>* jnode) {
+ DCHECK(jnode);
+ if (!node)
+ return;
+
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> url;
+ if (node->is_url())
+ url.Reset(ConvertUTF8ToJavaString(env, node->url().spec()));
+ ScopedJavaLocalRef<jstring> title(
+ ConvertUTF16ToJavaString(env, node->GetTitle()));
+
+ jnode->Reset(
+ Java_BookmarkNode_create(
+ env, node->id(), (jint) node->type(), title.obj(), url.obj(),
+ parent_node.obj()));
+}
+
+jlong ConvertJLongObjectToPrimitive(JNIEnv* env, jobject long_obj) {
+ ScopedJavaLocalRef<jclass> jlong_clazz = GetClass(env, "java/lang/Long");
+ jmethodID long_value = GetMethodID(env, jlong_clazz, "longValue", "()J");
+ return env->CallLongMethod(long_obj, long_value, NULL);
+}
+
+jboolean ConvertJBooleanObjectToPrimitive(JNIEnv* env, jobject boolean_object) {
+ ScopedJavaLocalRef<jclass> jboolean_clazz =
+ GetClass(env, "java/lang/Boolean");
+ jmethodID boolean_value =
+ GetMethodID(env, jboolean_clazz, "booleanValue", "()Z");
+ return env->CallBooleanMethod(boolean_object, boolean_value, NULL);
+}
+
+base::Time ConvertJlongToTime(jlong value) {
+ return base::Time::UnixEpoch() +
+ base::TimeDelta::FromMilliseconds((int64)value);
+}
+
+jint ConvertJIntegerToJint(JNIEnv* env, jobject integer_obj) {
+ ScopedJavaLocalRef<jclass> jinteger_clazz =
+ GetClass(env, "java/lang/Integer");
+ jmethodID int_value = GetMethodID(env, jinteger_clazz, "intValue", "()I");
+ return env->CallIntMethod(integer_obj, int_value, NULL);
+}
+
+std::vector<string16> ConvertJStringArrayToString16Array(JNIEnv* env,
+ jobjectArray array) {
+ std::vector<string16> results;
+ if (array) {
+ jsize len = env->GetArrayLength(array);
+ for (int i = 0; i < len; i++) {
+ results.push_back(ConvertJavaStringToUTF16(env,
+ static_cast<jstring>(env->GetObjectArrayElement(array, i))));
+ }
+ }
+ return results;
+}
+
+// ------------- Utility methods used by tasks ------------- //
+
+// Parse the given url and return a GURL, appending the default scheme
+// if one is not present.
+GURL ParseAndMaybeAppendScheme(const string16& url,
+ const char* default_scheme) {
+ GURL gurl(url);
+ if (!gurl.is_valid() && !gurl.has_scheme()) {
+ string16 refined_url(ASCIIToUTF16(default_scheme));
+ refined_url.append(url);
+ gurl = GURL(refined_url);
+ }
+ return gurl;
+}
+
+const BookmarkNode* GetChildFolderByTitle(const BookmarkNode* parent,
+ const string16& title) {
+ for (int i = 0; i < parent->child_count(); ++i) {
+ if (parent->GetChild(i)->is_folder() &&
+ parent->GetChild(i)->GetTitle() == title) {
+ return parent->GetChild(i);
+ }
+ }
+ return NULL;
+}
+
+// ------------- Synchronous task classes ------------- //
+
+// Utility task to add a bookmark.
+class AddBookmarkTask : public BookmarkModelTask {
+ public:
+ explicit AddBookmarkTask(BookmarkModel* model) : BookmarkModelTask(model) {}
+
+ int64 Run(const string16& title,
+ const string16& url,
+ const bool is_folder,
+ const int64 parent_id) {
+ int64 result = kInvalidBookmarkId;
+ RunOnUIThreadBlocking::Run(
+ base::Bind(&AddBookmarkTask::RunOnUIThread,
+ model(), title, url, is_folder, parent_id, &result));
+ return result;
+ }
+
+ static void RunOnUIThread(BookmarkModel* model,
+ const string16& title,
+ const string16& url,
+ const bool is_folder,
+ const int64 parent_id,
+ int64* result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(result);
+ GURL gurl = ParseAndMaybeAppendScheme(url, kDefaultUrlScheme);
+
+ // Check if the bookmark already exists.
+ const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(gurl);
+ if (!node) {
+ const BookmarkNode* parent_node = NULL;
+ if (parent_id >= 0)
+ parent_node = model->GetNodeByID(parent_id);
+ if (!parent_node)
+ parent_node = model->bookmark_bar_node();
+
+ if (is_folder)
+ node = model->AddFolder(parent_node, parent_node->child_count(), title);
+ else
+ node = model->AddURL(parent_node, 0, title, gurl);
+ }
+
+ *result = node ? node ->id() : kInvalidBookmarkId;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AddBookmarkTask);
+};
+
+// Utility method to remove a bookmark.
+class RemoveBookmarkTask : public BookmarkModelObserverTask {
+ public:
+ explicit RemoveBookmarkTask(BookmarkModel* model)
+ : BookmarkModelObserverTask(model),
+ deleted_(0),
+ id_to_delete_(kInvalidBookmarkId) {}
+ virtual ~RemoveBookmarkTask() {}
+
+ int Run(const int64 id) {
+ id_to_delete_ = id;
+ RunOnUIThreadBlocking::Run(
+ base::Bind(&RemoveBookmarkTask::RunOnUIThread, model(), id));
+ return deleted_;
+ }
+
+ static void RunOnUIThread(BookmarkModel* model, const int64 id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const BookmarkNode* node = model->GetNodeByID(id);
+ if (node && node->parent()) {
+ const BookmarkNode* parent_node = node->parent();
+ model->Remove(parent_node, parent_node->GetIndexOf(node));
+ }
+ }
+
+ // Verify that the bookmark was actually removed. Called synchronously.
+ virtual void BookmarkNodeRemoved(BookmarkModel* bookmark_model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) OVERRIDE {
+ if (bookmark_model == model() && node->id() == id_to_delete_)
+ ++deleted_;
+ }
+
+ private:
+ int deleted_;
+ int64 id_to_delete_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoveBookmarkTask);
+};
+
+// Utility method to update a bookmark.
+class UpdateBookmarkTask : public BookmarkModelObserverTask {
+ public:
+ explicit UpdateBookmarkTask(BookmarkModel* model)
+ : BookmarkModelObserverTask(model),
+ updated_(0),
+ id_to_update_(kInvalidBookmarkId){}
+ virtual ~UpdateBookmarkTask() {}
+
+ int Run(const int64 id,
+ const string16& title,
+ const string16& url,
+ const int64 parent_id) {
+ id_to_update_ = id;
+ RunOnUIThreadBlocking::Run(
+ base::Bind(&UpdateBookmarkTask::RunOnUIThread,
+ model(), id, title, url, parent_id));
+ return updated_;
+ }
+
+ static void RunOnUIThread(BookmarkModel* model,
+ const int64 id,
+ const string16& title,
+ const string16& url,
+ const int64 parent_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const BookmarkNode* node = model->GetNodeByID(id);
+ if (node) {
+ if (node->GetTitle() != title)
+ model->SetTitle(node, title);
+
+ if (node->type() == BookmarkNode::URL) {
+ GURL bookmark_url = ParseAndMaybeAppendScheme(url, kDefaultUrlScheme);
+ if (bookmark_url != node->url())
+ model->SetURL(node, bookmark_url);
+ }
+
+ if (parent_id >= 0 &&
+ (!node->parent() || parent_id != node->parent()->id())) {
+ const BookmarkNode* new_parent = model->GetNodeByID(parent_id);
+
+ if (new_parent)
+ model->Move(node, new_parent, 0);
+ }
+ }
+ }
+
+ // Verify that the bookmark was actually updated. Called synchronously.
+ virtual void BookmarkNodeChanged(BookmarkModel* bookmark_model,
+ const BookmarkNode* node) OVERRIDE {
+ if (bookmark_model == model() && node->id() == id_to_update_)
+ ++updated_;
+ }
+
+ private:
+ int updated_;
+ int64 id_to_update_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateBookmarkTask);
+};
+
+// Checks if a node exists in the bookmark model.
+class BookmarkNodeExistsTask : public BookmarkModelTask {
+ public:
+ explicit BookmarkNodeExistsTask(BookmarkModel* model)
+ : BookmarkModelTask(model) {
+ }
+
+ bool Run(const int64 id) {
+ bool result = false;
+ RunOnUIThreadBlocking::Run(
+ base::Bind(&BookmarkNodeExistsTask::RunOnUIThread,
+ model(), id, &result));
+ return result;
+ }
+
+ static void RunOnUIThread(BookmarkModel* model,
+ const int64 id,
+ bool* result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(result);
+ *result = model->GetNodeByID(id) != NULL;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BookmarkNodeExistsTask);
+};
+
+// Checks if a node belongs to the Mobile Bookmarks hierarchy branch.
+class IsInMobileBookmarksBranchTask : public BookmarkModelTask {
+ public:
+ explicit IsInMobileBookmarksBranchTask(BookmarkModel* model)
+ : BookmarkModelTask(model) {}
+
+ bool Run(const int64 id) {
+ bool result = false;
+ RunOnUIThreadBlocking::Run(
+ base::Bind(&IsInMobileBookmarksBranchTask::RunOnUIThread,
+ model(), id, &result));
+ return result;
+ }
+
+ static void RunOnUIThread(BookmarkModel* model,
+ const int64 id,
+ bool *result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(result);
+ const BookmarkNode* node = model->GetNodeByID(id);
+ const BookmarkNode* mobile_node = model->mobile_node();
+ while (node && node != mobile_node)
+ node = node->parent();
+
+ *result = node == mobile_node;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IsInMobileBookmarksBranchTask);
+};
+
+// Creates folder or retrieves its id if already exists.
+// An invalid parent id is assumed to represent the Mobile Bookmarks folder.
+// Can only be used to create folders inside the Mobile Bookmarks branch.
+class CreateBookmarksFolderOnceTask : public BookmarkModelTask {
+ public:
+ explicit CreateBookmarksFolderOnceTask(BookmarkModel* model)
+ : BookmarkModelTask(model) {}
+
+ int64 Run(const string16& title, const int64 parent_id) {
+ int64 result = kInvalidBookmarkId;
+ RunOnUIThreadBlocking::Run(
+ base::Bind(&CreateBookmarksFolderOnceTask::RunOnUIThread,
+ model(), title, parent_id, &result));
+ return result;
+ }
+
+ static void RunOnUIThread(BookmarkModel* model,
+ const string16& title,
+ const int64 parent_id,
+ int64* result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(result);
+
+ // Invalid ids are assumed to refer to the Mobile Bookmarks folder.
+ const BookmarkNode* parent = parent_id >= 0 ?
+ model->GetNodeByID(parent_id) : model->mobile_node();
+ DCHECK(parent);
+
+ bool in_mobile_bookmarks;
+ IsInMobileBookmarksBranchTask::RunOnUIThread(model, parent->id(),
+ &in_mobile_bookmarks);
+ if (in_mobile_bookmarks) {
+ *result = kInvalidBookmarkId;
+ return;
+ }
+
+ const BookmarkNode* node = GetChildFolderByTitle(parent, title);
+ if (node) {
+ *result = node->id();
+ return;
+ }
+
+ AddBookmarkTask::RunOnUIThread(model, title, string16(), true,
+ parent->id(), result);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CreateBookmarksFolderOnceTask);
+};
+
+// Creates a Java BookmarkNode object for a node given its id.
+class GetAllBookmarkFoldersTask : public BookmarkModelTask {
+ public:
+ explicit GetAllBookmarkFoldersTask(BookmarkModel* model)
+ : BookmarkModelTask(model) {
+ }
+
+ void Run(ScopedJavaGlobalRef<jobject>* jroot) {
+ RunOnUIThreadBlocking::Run(
+ base::Bind(&GetAllBookmarkFoldersTask::RunOnUIThread, model(), jroot));
+ }
+
+ static void RunOnUIThread(BookmarkModel* model,
+ ScopedJavaGlobalRef<jobject>* jroot) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const BookmarkNode* root = model->root_node();
+ if (!root || !root->is_folder())
+ return;
+
+ // The iterative approach is not possible because ScopedGlobalJavaRefs
+ // cannot be copy-constructed, and therefore not used in STL containers.
+ ConvertFolderSubtree(AttachCurrentThread(), root,
+ ScopedJavaLocalRef<jobject>(), jroot);
+ }
+
+ private:
+ static void ConvertFolderSubtree(JNIEnv* env,
+ const BookmarkNode* node,
+ const JavaRef<jobject>& parent_folder,
+ ScopedJavaGlobalRef<jobject>* jfolder) {
+ DCHECK(node);
+ DCHECK(node->is_folder());
+ DCHECK(jfolder);
+
+ // Global refs should be used here for thread-safety reasons as this task
+ // might be invoked from a thread other than UI. All refs are scoped.
+ ConvertBookmarkNode(node, parent_folder, jfolder);
+
+ for (int i = 0; i < node->child_count(); ++i) {
+ const BookmarkNode* child = node->GetChild(i);
+ if (child->is_folder()) {
+ ScopedJavaGlobalRef<jobject> jchild;
+ ConvertFolderSubtree(env, child, *jfolder, &jchild);
+
+ Java_BookmarkNode_addChild(env, jfolder->obj(), jchild.obj());
+ if (ClearException(env)) {
+ LOG(WARNING) << "Java exception while adding child node.";
+ return;
+ }
+ }
+ }
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(GetAllBookmarkFoldersTask);
+};
+
+// Creates a Java BookmarkNode object for a node given its id.
+class GetBookmarkNodeTask : public BookmarkModelTask {
+ public:
+ explicit GetBookmarkNodeTask(BookmarkModel* model)
+ : BookmarkModelTask(model) {
+ }
+
+ void Run(const int64 id,
+ bool get_parent,
+ bool get_children,
+ ScopedJavaGlobalRef<jobject>* jnode) {
+ return RunOnUIThreadBlocking::Run(
+ base::Bind(&GetBookmarkNodeTask::RunOnUIThread,
+ model(), id, get_parent, get_children, jnode));
+ }
+
+ static void RunOnUIThread(BookmarkModel* model,
+ const int64 id,
+ bool get_parent,
+ bool get_children,
+ ScopedJavaGlobalRef<jobject>* jnode) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const BookmarkNode* node = model->GetNodeByID(id);
+ if (!node || !jnode)
+ return;
+
+ ScopedJavaGlobalRef<jobject> jparent;
+ if (get_parent) {
+ ConvertBookmarkNode(node->parent(), ScopedJavaLocalRef<jobject>(),
+ &jparent);
+ }
+
+ ConvertBookmarkNode(node, jparent, jnode);
+
+ JNIEnv* env = AttachCurrentThread();
+ if (!jparent.is_null()) {
+ Java_BookmarkNode_addChild(env, jparent.obj(), jnode->obj());
+ if (ClearException(env)) {
+ LOG(WARNING) << "Java exception while adding child node.";
+ return;
+ }
+ }
+
+ if (get_children) {
+ for (int i = 0; i < node->child_count(); ++i) {
+ ScopedJavaGlobalRef<jobject> jchild;
+ ConvertBookmarkNode(node->GetChild(i), *jnode, &jchild);
+ Java_BookmarkNode_addChild(env, jnode->obj(), jchild.obj());
+ if (ClearException(env)) {
+ LOG(WARNING) << "Java exception while adding child node.";
+ return;
+ }
+ }
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GetBookmarkNodeTask);
+};
+
+// Gets the Mobile Bookmarks node. Using this task ensures the correct
+// initialization of the bookmark model.
+class GetMobileBookmarksNodeTask : public BookmarkModelTask {
+ public:
+ explicit GetMobileBookmarksNodeTask(BookmarkModel* model)
+ : BookmarkModelTask(model) {}
+
+ const BookmarkNode* Run() {
+ const BookmarkNode* result = NULL;
+ RunOnUIThreadBlocking::Run(
+ base::Bind(&GetMobileBookmarksNodeTask::RunOnUIThread,
+ model(), &result));
+ return result;
+ }
+
+ static void RunOnUIThread(BookmarkModel* model, const BookmarkNode** result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(result);
+ *result = model->mobile_node();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GetMobileBookmarksNodeTask);
+};
+
+// ------------- Aynchronous requests classes ------------- //
+
+// Base class for asynchronous blocking requests to Chromium services.
+// Service: type of the service to use (e.g. HistoryService, FaviconService).
+template <typename Service>
+class AsyncServiceRequest : protected BlockingUIThreadAsyncRequest {
+ public:
+ AsyncServiceRequest(Service* service,
+ CancelableRequestConsumer* cancelable_consumer)
+ : service_(service), cancelable_consumer_(cancelable_consumer) {}
+
+ Service* service() const { return service_; }
+
+ CancelableRequestConsumer* cancelable_consumer() const {
+ return cancelable_consumer_;
+ }
+
+ private:
+ Service* service_;
+ CancelableRequestConsumer* cancelable_consumer_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncServiceRequest);
+};
+
+// Base class for all asynchronous blocking tasks that use the favicon service.
+class FaviconServiceTask : public AsyncServiceRequest<FaviconService> {
+ public:
+ FaviconServiceTask(FaviconService* service,
+ Profile* profile,
+ CancelableRequestConsumer* cancelable_consumer)
+ : AsyncServiceRequest<FaviconService>(service, cancelable_consumer),
+ profile_(profile) {}
+
+ Profile* profile() const { return profile_; }
+
+ private:
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(FaviconServiceTask);
+};
+
+// Retrieves the favicon or touch icon for a URL from the FaviconService.
+class BookmarkIconFetchTask : public FaviconServiceTask {
+ public:
+ BookmarkIconFetchTask(
+ FaviconService* favicon_service,
+ Profile* profile,
+ CancelableRequestConsumer* cancelable_consumer)
+ : FaviconServiceTask(favicon_service, profile, cancelable_consumer) {}
+
+ history::FaviconBitmapResult Run(const GURL& url) {
+ RunAsyncRequestOnUIThreadBlocking(
+ base::Bind(&FaviconService::GetRawFaviconForURL,
+ base::Unretained(service()),
+ FaviconService::FaviconForURLParams(
+ profile(),
+ url,
+ history::FAVICON | history::TOUCH_ICON,
+ gfx::kFaviconSize,
+ cancelable_consumer()),
+ ui::SCALE_FACTOR_100P,
+ base::Bind(
+ &BookmarkIconFetchTask::OnFaviconRetrieved,
+ base::Unretained(this))));
+ return result_;
+ }
+
+ private:
+ void OnFaviconRetrieved(FaviconService::Handle handle,
+ const history::FaviconBitmapResult& bitmap_result) {
+ result_ = bitmap_result;
+ RequestCompleted();
+ }
+
+ history::FaviconBitmapResult result_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkIconFetchTask);
+};
+
+// Base class for all asynchronous blocking tasks that use the Android history
+// provider service.
+class HistoryProviderTask
+ : public AsyncServiceRequest<AndroidHistoryProviderService> {
+ public:
+ HistoryProviderTask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer)
+ : AsyncServiceRequest<AndroidHistoryProviderService>
+ (service, cancelable_consumer) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HistoryProviderTask);
+};
+
+// Adds a bookmark from the API.
+class AddBookmarkFromAPITask : public HistoryProviderTask {
+ public:
+ AddBookmarkFromAPITask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer)
+ : HistoryProviderTask(service, cancelable_consumer) {}
+
+ history::URLID Run(const history::HistoryAndBookmarkRow& row) {
+ RunAsyncRequestOnUIThreadBlocking(
+ base::Bind(&AndroidHistoryProviderService::InsertHistoryAndBookmark,
+ base::Unretained(service()), row, cancelable_consumer(),
+ base::Bind(&AddBookmarkFromAPITask::OnBookmarkInserted,
+ base::Unretained(this))));
+ return result_;
+ }
+
+ private:
+ void OnBookmarkInserted(AndroidHistoryProviderService::Handle handle,
+ bool succeeded,
+ history::URLID id) {
+ // Note that here 0 means an invalid id too.
+ // This is because it represents a SQLite database row id.
+ result_ = id;
+ RequestCompleted();
+ }
+
+ history::URLID result_;
+
+ DISALLOW_COPY_AND_ASSIGN(AddBookmarkFromAPITask);
+};
+
+// Queries bookmarks from the API.
+class QueryBookmarksFromAPITask : public HistoryProviderTask {
+ public:
+ QueryBookmarksFromAPITask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer)
+ : HistoryProviderTask(service, cancelable_consumer),
+ result_(NULL) {}
+
+ history::AndroidStatement* Run(
+ const std::vector<history::HistoryAndBookmarkRow::ColumnID>& projections,
+ const std::string& selection,
+ const std::vector<string16>& selection_args,
+ const std::string& sort_order) {
+ RunAsyncRequestOnUIThreadBlocking(
+ base::Bind(&AndroidHistoryProviderService::QueryHistoryAndBookmarks,
+ base::Unretained(service()), projections, selection,
+ selection_args, sort_order, cancelable_consumer(),
+ base::Bind(&QueryBookmarksFromAPITask::OnBookmarksQueried,
+ base::Unretained(this))));
+ return result_;
+ }
+
+ private:
+ void OnBookmarksQueried(AndroidHistoryProviderService::Handle handle,
+ bool succeeded,
+ history::AndroidStatement* statement) {
+ result_ = statement;
+ RequestCompleted();
+ }
+
+ history::AndroidStatement* result_;
+
+ DISALLOW_COPY_AND_ASSIGN(QueryBookmarksFromAPITask);
+};
+
+// Updates bookmarks from the API.
+class UpdateBookmarksFromAPITask : public HistoryProviderTask {
+ public:
+ UpdateBookmarksFromAPITask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer)
+ : HistoryProviderTask(service, cancelable_consumer),
+ result_(0) {}
+
+ int Run(const history::HistoryAndBookmarkRow& row,
+ const std::string& selection,
+ const std::vector<string16>& selection_args) {
+ RunAsyncRequestOnUIThreadBlocking(
+ base::Bind(&AndroidHistoryProviderService::UpdateHistoryAndBookmarks,
+ base::Unretained(service()), row, selection,
+ selection_args, cancelable_consumer(),
+ base::Bind(&UpdateBookmarksFromAPITask::OnBookmarksUpdated,
+ base::Unretained(this))));
+ return result_;
+ }
+
+ private:
+ void OnBookmarksUpdated(AndroidHistoryProviderService::Handle handle,
+ bool succeeded,
+ int updated_row_count) {
+ result_ = updated_row_count;
+ RequestCompleted();
+ }
+
+ int result_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateBookmarksFromAPITask);
+};
+
+// Removes bookmarks from the API.
+class RemoveBookmarksFromAPITask : public HistoryProviderTask {
+ public:
+ RemoveBookmarksFromAPITask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer)
+ : HistoryProviderTask(service, cancelable_consumer),
+ result_(0) {}
+
+ int Run(const std::string& selection,
+ const std::vector<string16>& selection_args) {
+ RunAsyncRequestOnUIThreadBlocking(
+ base::Bind(&AndroidHistoryProviderService::DeleteHistoryAndBookmarks,
+ base::Unretained(service()), selection, selection_args,
+ cancelable_consumer(),
+ base::Bind(&RemoveBookmarksFromAPITask::OnBookmarksRemoved,
+ base::Unretained(this))));
+ return result_;
+ }
+
+ private:
+ void OnBookmarksRemoved(AndroidHistoryProviderService::Handle handle,
+ bool succeeded,
+ int removed_row_count) {
+ result_ = removed_row_count;
+ RequestCompleted();
+ }
+
+ int result_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoveBookmarksFromAPITask);
+};
+
+// Removes history from the API.
+class RemoveHistoryFromAPITask : public HistoryProviderTask {
+ public:
+ RemoveHistoryFromAPITask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer)
+ : HistoryProviderTask(service, cancelable_consumer),
+ result_(0) {}
+
+ int Run(const std::string& selection,
+ const std::vector<string16>& selection_args) {
+ RunAsyncRequestOnUIThreadBlocking(
+ base::Bind(&AndroidHistoryProviderService::DeleteHistory,
+ base::Unretained(service()), selection,
+ selection_args, cancelable_consumer(),
+ base::Bind(&RemoveHistoryFromAPITask::OnHistoryRemoved,
+ base::Unretained(this))));
+ return result_;
+ }
+
+ private:
+ void OnHistoryRemoved(AndroidHistoryProviderService::Handle handle,
+ bool succeeded,
+ int removed_row_count) {
+ result_ = removed_row_count;
+ RequestCompleted();
+ }
+
+ int result_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoveHistoryFromAPITask);
+};
+
+// This class provides the common method for the SearchTermAPIHelper.
+class SearchTermTask : public HistoryProviderTask {
+ protected:
+ SearchTermTask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer,
+ Profile* profile)
+ : HistoryProviderTask(service, cancelable_consumer),
+ profile_(profile) {}
+
+ // Fill SearchRow's template_url_id and url fields according the given
+ // search_term. Return true if succeeded.
+ void BuildSearchRow(history::SearchRow* row) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ TemplateURLService* template_service =
+ TemplateURLServiceFactory::GetForProfile(profile_);
+ template_service->Load();
+
+ const TemplateURL* search_engine =
+ template_service->GetDefaultSearchProvider();
+ if (search_engine) {
+ const TemplateURLRef* search_url = &search_engine->url_ref();
+ std::string url = search_url->ReplaceSearchTerms(
+ TemplateURLRef::SearchTermsArgs(row->search_term()));
+ if (!url.empty()) {
+ row->set_url(GURL(url));
+ row->set_template_url_id(search_engine->id());
+ }
+ }
+ }
+
+ private:
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(SearchTermTask);
+};
+
+// Adds a search term from the API.
+class AddSearchTermFromAPITask : public SearchTermTask {
+ public:
+ AddSearchTermFromAPITask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer,
+ Profile* profile)
+ : SearchTermTask(service, cancelable_consumer, profile) {}
+
+ history::URLID Run(const history::SearchRow& row) {
+ RunAsyncRequestOnUIThreadBlocking(
+ base::Bind(&AddSearchTermFromAPITask::MakeRequestOnUIThread,
+ base::Unretained(this), row));
+ return result_;
+ }
+
+ private:
+ void MakeRequestOnUIThread(const history::SearchRow& row) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ history::SearchRow internal_row = row;
+ BuildSearchRow(&internal_row);
+ service()->InsertSearchTerm(internal_row, cancelable_consumer(),
+ base::Bind(&AddSearchTermFromAPITask::OnSearchTermInserted,
+ base::Unretained(this)));
+ }
+
+ void OnSearchTermInserted(AndroidHistoryProviderService::Handle handle,
+ bool succeeded,
+ history::URLID id) {
+ // Note that here 0 means an invalid id too.
+ // This is because it represents a SQLite database row id.
+ result_ = id;
+ RequestCompleted();
+ }
+
+ history::URLID result_;
+
+ DISALLOW_COPY_AND_ASSIGN(AddSearchTermFromAPITask);
+};
+
+// Queries search terms from the API.
+class QuerySearchTermsFromAPITask : public SearchTermTask {
+ public:
+ QuerySearchTermsFromAPITask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer,
+ Profile* profile)
+ : SearchTermTask(service, cancelable_consumer, profile),
+ result_(NULL) {}
+
+ history::AndroidStatement* Run(
+ const std::vector<history::SearchRow::ColumnID>& projections,
+ const std::string& selection,
+ const std::vector<string16>& selection_args,
+ const std::string& sort_order) {
+ RunAsyncRequestOnUIThreadBlocking(
+ base::Bind(&AndroidHistoryProviderService::QuerySearchTerms,
+ base::Unretained(service()), projections, selection,
+ selection_args, sort_order, cancelable_consumer(),
+ base::Bind(
+ &QuerySearchTermsFromAPITask::OnSearchTermsQueried,
+ base::Unretained(this))));
+ return result_;
+ }
+
+ private:
+ // Callback to return the result.
+ void OnSearchTermsQueried(AndroidHistoryProviderService::Handle handle,
+ bool succeeded,
+ history::AndroidStatement* statement) {
+ result_ = statement;
+ RequestCompleted();
+ }
+
+ history::AndroidStatement* result_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuerySearchTermsFromAPITask);
+};
+
+// Updates search terms from the API.
+class UpdateSearchTermsFromAPITask : public SearchTermTask {
+ public:
+ UpdateSearchTermsFromAPITask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer,
+ Profile* profile)
+ : SearchTermTask(service, cancelable_consumer, profile),
+ result_(0) {}
+
+ int Run(const history::SearchRow& row,
+ const std::string& selection,
+ const std::vector<string16>& selection_args) {
+ RunAsyncRequestOnUIThreadBlocking(
+ base::Bind(&UpdateSearchTermsFromAPITask::MakeRequestOnUIThread,
+ base::Unretained(this), row, selection, selection_args));
+ return result_;
+ }
+
+ private:
+ void MakeRequestOnUIThread(const history::SearchRow& row,
+ const std::string& selection,
+ const std::vector<string16>& selection_args) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ history::SearchRow internal_row = row;
+ BuildSearchRow(&internal_row);
+ service()->UpdateSearchTerms(
+ internal_row,
+ selection,
+ selection_args,
+ cancelable_consumer(),
+ base::Bind(&UpdateSearchTermsFromAPITask::OnSearchTermsUpdated,
+ base::Unretained(this)));
+ }
+
+
+ void OnSearchTermsUpdated(AndroidHistoryProviderService::Handle handle,
+ bool succeeded,
+ int updated_row_count) {
+ result_ = updated_row_count;
+ RequestCompleted();
+ }
+
+ int result_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateSearchTermsFromAPITask);
+};
+
+// Removes search terms from the API.
+class RemoveSearchTermsFromAPITask : public SearchTermTask {
+ public:
+ RemoveSearchTermsFromAPITask(AndroidHistoryProviderService* service,
+ CancelableRequestConsumer* cancelable_consumer,
+ Profile* profile)
+ : SearchTermTask(service, cancelable_consumer, profile) {}
+
+ int Run(const std::string& selection,
+ const std::vector<string16>& selection_args) {
+ RunAsyncRequestOnUIThreadBlocking(
+ base::Bind(&AndroidHistoryProviderService::DeleteSearchTerms,
+ base::Unretained(service()), selection, selection_args,
+ cancelable_consumer(),
+ base::Bind(
+ &RemoveSearchTermsFromAPITask::OnSearchTermsDeleted,
+ base::Unretained(this))));
+ return result_;
+ }
+
+ private:
+ void OnSearchTermsDeleted(AndroidHistoryProviderService::Handle handle,
+ bool succeeded,
+ int deleted_row_count) {
+ result_ = deleted_row_count;
+ RequestCompleted();
+ }
+
+ int result_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoveSearchTermsFromAPITask);
+};
+
+// ------------- Other utility methods (may use tasks) ------------- //
+
+// Fills the bookmark |row| with the given java objects.
+void FillBookmarkRow(JNIEnv* env,
+ jobject obj,
+ jstring url,
+ jobject created,
+ jobject isBookmark,
+ jobject date,
+ jbyteArray favicon,
+ jstring title,
+ jobject visits,
+ jlong parent_id,
+ history::HistoryAndBookmarkRow* row,
+ BookmarkModel* model) {
+ // Needed because of the internal bookmark model task invocation.
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (url) {
+ string16 raw_url = ConvertJavaStringToUTF16(env, url);
+ // GURL doesn't accept the URL without protocol, but the Android CTS
+ // allows it. We are trying to prefix with 'http://' to see whether
+ // GURL thinks it is a valid URL. The original url will be stored in
+ // history::BookmarkRow.raw_url_.
+ GURL gurl = ParseAndMaybeAppendScheme(raw_url, kDefaultUrlScheme);
+ row->set_url(gurl);
+ row->set_raw_url(UTF16ToUTF8(raw_url));
+ }
+
+ if (created)
+ row->set_created(ConvertJlongToTime(
+ ConvertJLongObjectToPrimitive(env, created)));
+
+ if (isBookmark)
+ row->set_is_bookmark(ConvertJBooleanObjectToPrimitive(env, isBookmark));
+
+ if (date)
+ row->set_last_visit_time(ConvertJlongToTime(ConvertJLongObjectToPrimitive(
+ env, date)));
+
+ if (favicon) {
+ std::vector<uint8> bytes;
+ base::android::JavaByteArrayToByteVector(env, favicon, &bytes);
+ row->set_favicon(base::RefCountedBytes::TakeVector(&bytes));
+ }
+
+ if (title)
+ row->set_title(ConvertJavaStringToUTF16(env, title));
+
+ if (visits)
+ row->set_visit_count(ConvertJIntegerToJint(env, visits));
+
+ // Make sure parent_id is always in the mobile_node branch.
+ IsInMobileBookmarksBranchTask task(model);
+ if (task.Run(parent_id))
+ row->set_parent_id(parent_id);
+}
+
+// Fills the bookmark |row| with the given java objects if it is not null.
+void FillSearchRow(JNIEnv* env,
+ jobject obj,
+ jstring search_term,
+ jobject date,
+ history::SearchRow* row) {
+ if (search_term)
+ row->set_search_term(ConvertJavaStringToUTF16(env, search_term));
+
+ if (date)
+ row->set_search_time(ConvertJlongToTime(ConvertJLongObjectToPrimitive(
+ env, date)));
+}
+
+} // namespace
+
+// ------------- Native initialization and destruction ------------- //
+
+static jint Init(JNIEnv* env, jobject obj) {
+ ChromeBrowserProvider* provider = new ChromeBrowserProvider(env, obj);
+ return reinterpret_cast<jint>(provider);
+}
+
+bool ChromeBrowserProvider::RegisterChromeBrowserProvider(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+ChromeBrowserProvider::ChromeBrowserProvider(JNIEnv* env, jobject obj)
+ : weak_java_provider_(env, obj),
+ template_loaded_event_(true, false) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ profile_ = g_browser_process->profile_manager()->GetLastUsedProfile();
+ bookmark_model_ = BookmarkModelFactory::GetForProfile(profile_);
+ top_sites_ = profile_->GetTopSites();
+ service_.reset(new AndroidHistoryProviderService(profile_));
+ favicon_service_.reset(FaviconServiceFactory::GetForProfile(profile_,
+ Profile::EXPLICIT_ACCESS));
+
+ // Registers the notifications we are interested.
+ bookmark_model_->AddObserver(this);
+ notification_registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED,
+ content::NotificationService::AllSources());
+ notification_registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
+ content::NotificationService::AllSources());
+ notification_registrar_.Add(this,
+ chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
+ content::NotificationService::AllSources());
+ notification_registrar_.Add(this,
+ chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED,
+ content::NotificationService::AllSources());
+ TemplateURLService* template_service =
+ TemplateURLServiceFactory::GetForProfile(profile_);
+ if (template_service->loaded())
+ template_loaded_event_.Signal();
+ else
+ template_service->Load();
+}
+
+ChromeBrowserProvider::~ChromeBrowserProvider() {
+ bookmark_model_->RemoveObserver(this);
+}
+
+void ChromeBrowserProvider::Destroy(JNIEnv*, jobject) {
+ delete this;
+}
+
+// ------------- Provider public APIs ------------- //
+
+jlong ChromeBrowserProvider::AddBookmark(JNIEnv* env,
+ jobject,
+ jstring jurl,
+ jstring jtitle,
+ jboolean is_folder,
+ jlong parent_id) {
+ string16 url;
+ if (jurl)
+ url = ConvertJavaStringToUTF16(env, jurl);
+ string16 title = ConvertJavaStringToUTF16(env, jtitle);
+
+ AddBookmarkTask task(bookmark_model_);
+ return task.Run(title, url, is_folder, parent_id);
+}
+
+jint ChromeBrowserProvider::RemoveBookmark(JNIEnv*, jobject, jlong id) {
+ RemoveBookmarkTask task(bookmark_model_);
+ return task.Run(id);
+}
+
+jint ChromeBrowserProvider::UpdateBookmark(JNIEnv* env,
+ jobject,
+ jlong id,
+ jstring jurl,
+ jstring jtitle,
+ jlong parent_id) {
+ string16 url;
+ if (jurl)
+ url = ConvertJavaStringToUTF16(env, jurl);
+ string16 title = ConvertJavaStringToUTF16(env, jtitle);
+
+ UpdateBookmarkTask task(bookmark_model_);
+ return task.Run(id, title, url, parent_id);
+}
+
+// Add the bookmark with the given column values.
+jlong ChromeBrowserProvider::AddBookmarkFromAPI(JNIEnv* env,
+ jobject obj,
+ jstring url,
+ jobject created,
+ jobject isBookmark,
+ jobject date,
+ jbyteArray favicon,
+ jstring title,
+ jobject visits,
+ jlong parent_id) {
+ DCHECK(url);
+
+ history::HistoryAndBookmarkRow row;
+ FillBookmarkRow(env, obj, url, created, isBookmark, date, favicon, title,
+ visits, parent_id, &row, bookmark_model_);
+
+ // URL must be valid.
+ if (row.url().is_empty()) {
+ LOG(ERROR) << "Not a valid URL " << row.raw_url();
+ return kInvalidContentProviderId;
+ }
+
+ AddBookmarkFromAPITask task(service_.get(), &android_history_consumer_);
+ return task.Run(row);
+}
+
+ScopedJavaLocalRef<jobject> ChromeBrowserProvider::QueryBookmarkFromAPI(
+ JNIEnv* env,
+ jobject obj,
+ jobjectArray projection,
+ jstring selections,
+ jobjectArray selection_args,
+ jstring sort_order) {
+ // Converts the projection to array of ColumnID and column name.
+ // Used to store the projection column ID according their sequence.
+ std::vector<history::HistoryAndBookmarkRow::ColumnID> query_columns;
+ // Used to store the projection column names according their sequence.
+ std::vector<std::string> columns_name;
+ if (projection) {
+ jsize len = env->GetArrayLength(projection);
+ for (int i = 0; i < len; i++) {
+ std::string name = ConvertJavaStringToUTF8(env, static_cast<jstring>(
+ env->GetObjectArrayElement(projection, i)));
+ history::HistoryAndBookmarkRow::ColumnID id =
+ history::HistoryAndBookmarkRow::GetColumnID(name);
+ if (id == history::HistoryAndBookmarkRow::COLUMN_END) {
+ // Ignore the unknown column; As Android platform will send us
+ // the non public column.
+ continue;
+ }
+ query_columns.push_back(id);
+ columns_name.push_back(name);
+ }
+ }
+
+ std::vector<string16> where_args =
+ ConvertJStringArrayToString16Array(env, selection_args);
+
+ std::string where_clause;
+ if (selections) {
+ where_clause = ConvertJavaStringToUTF8(env, selections);
+ }
+
+ std::string sort_clause;
+ if (sort_order) {
+ sort_clause = ConvertJavaStringToUTF8(env, sort_order);
+ }
+
+ QueryBookmarksFromAPITask task(service_.get(), &android_history_consumer_);
+ history::AndroidStatement* statement = task.Run(
+ query_columns, where_clause, where_args, sort_clause);
+ if (!statement)
+ return ScopedJavaLocalRef<jobject>();
+
+ // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
+ // Java object.
+ return SQLiteCursor::NewJavaSqliteCursor(env, columns_name, statement,
+ service_.get(), favicon_service_.get());
+}
+
+// Updates the bookmarks with the given column values. The value is not given if
+// it is NULL.
+jint ChromeBrowserProvider::UpdateBookmarkFromAPI(JNIEnv* env,
+ jobject obj,
+ jstring url,
+ jobject created,
+ jobject isBookmark,
+ jobject date,
+ jbyteArray favicon,
+ jstring title,
+ jobject visits,
+ jlong parent_id,
+ jstring selections,
+ jobjectArray selection_args) {
+ history::HistoryAndBookmarkRow row;
+ FillBookmarkRow(env, obj, url, created, isBookmark, date, favicon, title,
+ visits, parent_id, &row, bookmark_model_);
+
+ std::vector<string16> where_args =
+ ConvertJStringArrayToString16Array(env, selection_args);
+
+ std::string where_clause;
+ if (selections)
+ where_clause = ConvertJavaStringToUTF8(env, selections);
+
+ UpdateBookmarksFromAPITask task(service_.get(), &android_history_consumer_);
+ return task.Run(row, where_clause, where_args);
+}
+
+jint ChromeBrowserProvider::RemoveBookmarkFromAPI(JNIEnv* env,
+ jobject obj,
+ jstring selections,
+ jobjectArray selection_args) {
+ std::vector<string16> where_args =
+ ConvertJStringArrayToString16Array(env, selection_args);
+
+ std::string where_clause;
+ if (selections)
+ where_clause = ConvertJavaStringToUTF8(env, selections);
+
+ RemoveBookmarksFromAPITask task(service_.get(), &android_history_consumer_);
+ return task.Run(where_clause, where_args);
+}
+
+jint ChromeBrowserProvider::RemoveHistoryFromAPI(JNIEnv* env,
+ jobject obj,
+ jstring selections,
+ jobjectArray selection_args) {
+ std::vector<string16> where_args =
+ ConvertJStringArrayToString16Array(env, selection_args);
+
+ std::string where_clause;
+ if (selections)
+ where_clause = ConvertJavaStringToUTF8(env, selections);
+
+ RemoveHistoryFromAPITask task(service_.get(), &android_history_consumer_);
+ return task.Run(where_clause, where_args);
+}
+
+// Add the search term with the given column values. The value is not given if
+// it is NULL.
+jlong ChromeBrowserProvider::AddSearchTermFromAPI(JNIEnv* env,
+ jobject obj,
+ jstring search_term,
+ jobject date) {
+ DCHECK(search_term);
+
+ history::SearchRow row;
+ FillSearchRow(env, obj, search_term, date, &row);
+
+ // URL must be valid.
+ if (row.search_term().empty()) {
+ LOG(ERROR) << "Search term is empty.";
+ return kInvalidContentProviderId;
+ }
+
+ AddSearchTermFromAPITask task(service_.get(), &android_history_consumer_,
+ profile_);
+ return task.Run(row);
+}
+
+ScopedJavaLocalRef<jobject> ChromeBrowserProvider::QuerySearchTermFromAPI(
+ JNIEnv* env,
+ jobject obj,
+ jobjectArray projection,
+ jstring selections,
+ jobjectArray selection_args,
+ jstring sort_order) {
+ // Converts the projection to array of ColumnID and column name.
+ // Used to store the projection column ID according their sequence.
+ std::vector<history::SearchRow::ColumnID> query_columns;
+ // Used to store the projection column names according their sequence.
+ std::vector<std::string> columns_name;
+ if (projection) {
+ jsize len = env->GetArrayLength(projection);
+ for (int i = 0; i < len; i++) {
+ std::string name = ConvertJavaStringToUTF8(env, static_cast<jstring>(
+ env->GetObjectArrayElement(projection, i)));
+ history::SearchRow::ColumnID id =
+ history::SearchRow::GetColumnID(name);
+ if (id == history::SearchRow::COLUMN_END) {
+ LOG(ERROR) << "Can not find " << name;
+ return ScopedJavaLocalRef<jobject>();
+ }
+ query_columns.push_back(id);
+ columns_name.push_back(name);
+ }
+ }
+
+ std::vector<string16> where_args =
+ ConvertJStringArrayToString16Array(env, selection_args);
+
+ std::string where_clause;
+ if (selections) {
+ where_clause = ConvertJavaStringToUTF8(env, selections);
+ }
+
+ std::string sort_clause;
+ if (sort_order) {
+ sort_clause = ConvertJavaStringToUTF8(env, sort_order);
+ }
+
+ QuerySearchTermsFromAPITask task(service_.get(), &android_history_consumer_,
+ profile_);
+ history::AndroidStatement* statement = task.Run(
+ query_columns, where_clause, where_args, sort_clause);
+ if (!statement)
+ return ScopedJavaLocalRef<jobject>();
+ // Creates and returns org.chromium.chrome.browser.database.SQLiteCursor
+ // Java object.
+ return SQLiteCursor::NewJavaSqliteCursor(env, columns_name, statement,
+ service_.get(), favicon_service_.get());
+}
+
+// Updates the search terms with the given column values. The value is not
+// given if it is NULL.
+jint ChromeBrowserProvider::UpdateSearchTermFromAPI(
+ JNIEnv* env, jobject obj, jstring search_term, jobject date,
+ jstring selections, jobjectArray selection_args) {
+ history::SearchRow row;
+ FillSearchRow(env, obj, search_term, date, &row);
+
+ std::vector<string16> where_args = ConvertJStringArrayToString16Array(
+ env, selection_args);
+
+ std::string where_clause;
+ if (selections)
+ where_clause = ConvertJavaStringToUTF8(env, selections);
+
+ UpdateSearchTermsFromAPITask task(service_.get(), &android_history_consumer_,
+ profile_);
+ return task.Run(row, where_clause, where_args);
+}
+
+jint ChromeBrowserProvider::RemoveSearchTermFromAPI(
+ JNIEnv* env, jobject obj, jstring selections, jobjectArray selection_args) {
+ std::vector<string16> where_args =
+ ConvertJStringArrayToString16Array(env, selection_args);
+
+ std::string where_clause;
+ if (selections)
+ where_clause = ConvertJavaStringToUTF8(env, selections);
+
+ RemoveSearchTermsFromAPITask task(service_.get(), &android_history_consumer_,
+ profile_);
+ return task.Run(where_clause, where_args);
+}
+
+// ------------- Provider custom APIs ------------- //
+
+jboolean ChromeBrowserProvider::BookmarkNodeExists(
+ JNIEnv* env,
+ jobject obj,
+ jlong id) {
+ BookmarkNodeExistsTask task(bookmark_model_);
+ return task.Run(id);
+}
+
+jlong ChromeBrowserProvider::CreateBookmarksFolderOnce(
+ JNIEnv* env,
+ jobject obj,
+ jstring jtitle,
+ jlong parent_id) {
+ string16 title = ConvertJavaStringToUTF16(env, jtitle);
+ if (title.empty())
+ return kInvalidBookmarkId;
+
+ CreateBookmarksFolderOnceTask task(bookmark_model_);
+ return task.Run(title, parent_id);
+}
+
+ScopedJavaLocalRef<jobject> ChromeBrowserProvider::GetAllBookmarkFolders(
+ JNIEnv* env,
+ jobject obj) {
+ ScopedJavaGlobalRef<jobject> jroot;
+ GetAllBookmarkFoldersTask task(bookmark_model_);
+ task.Run(&jroot);
+ return ScopedJavaLocalRef<jobject>(jroot);
+}
+
+ScopedJavaLocalRef<jobject> ChromeBrowserProvider::GetBookmarkNode(
+ JNIEnv* env,
+ jobject obj,
+ jlong id,
+ jboolean get_parent,
+ jboolean get_children) {
+ ScopedJavaGlobalRef<jobject> jnode;
+ GetBookmarkNodeTask task(bookmark_model_);
+ task.Run(id, get_parent, get_children, &jnode);
+ return ScopedJavaLocalRef<jobject>(jnode);
+}
+
+ScopedJavaLocalRef<jobject> ChromeBrowserProvider::GetMobileBookmarksFolder(
+ JNIEnv* env,
+ jobject obj) {
+ ScopedJavaGlobalRef<jobject> jnode;
+ GetMobileBookmarksNodeTask task(bookmark_model_);
+ ConvertBookmarkNode(task.Run(), ScopedJavaLocalRef<jobject>(), &jnode);
+ return ScopedJavaLocalRef<jobject>(jnode);
+}
+
+jboolean ChromeBrowserProvider::IsBookmarkInMobileBookmarksBranch(
+ JNIEnv* env,
+ jobject obj,
+ jlong id) {
+ IsInMobileBookmarksBranchTask task(bookmark_model_);
+ return task.Run(id);
+}
+
+ScopedJavaLocalRef<jbyteArray> ChromeBrowserProvider::GetFaviconOrTouchIcon(
+ JNIEnv* env, jobject obj, jstring jurl) {
+ if (!jurl)
+ return ScopedJavaLocalRef<jbyteArray>();
+
+ GURL url = GURL(ConvertJavaStringToUTF16(env, jurl));
+ BookmarkIconFetchTask favicon_task(favicon_service_.get(),
+ profile_,
+ &favicon_consumer_);
+ history::FaviconBitmapResult bitmap_result = favicon_task.Run(url);
+
+ if (!bitmap_result.is_valid() || !bitmap_result.bitmap_data.get())
+ return ScopedJavaLocalRef<jbyteArray>();
+
+ return base::android::ToJavaByteArray(env, bitmap_result.bitmap_data->front(),
+ bitmap_result.bitmap_data->size());
+}
+
+ScopedJavaLocalRef<jbyteArray> ChromeBrowserProvider::GetThumbnail(
+ JNIEnv* env, jobject obj, jstring jurl) {
+ if (!jurl)
+ return ScopedJavaLocalRef<jbyteArray>();
+ GURL url = GURL(ConvertJavaStringToUTF16(env, jurl));
+
+ // GetPageThumbnail is synchronous and can be called from any thread.
+ scoped_refptr<base::RefCountedMemory> thumbnail;
+ if (top_sites_)
+ top_sites_->GetPageThumbnail(url, &thumbnail);
+
+ if (!thumbnail.get() || !thumbnail->front()) {
+ return ScopedJavaLocalRef<jbyteArray>();
+ }
+
+ return base::android::ToJavaByteArray(env, thumbnail->front(),
+ thumbnail->size());
+}
+
+// ------------- Observer-related methods ------------- //
+
+void ChromeBrowserProvider::BookmarkModelChanged() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = weak_java_provider_.get(env);
+ if (obj.is_null())
+ return;
+
+ Java_ChromeBrowserProvider_onBookmarkChanged(env, obj.obj());
+}
+
+void ChromeBrowserProvider::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ if (type == chrome::NOTIFICATION_HISTORY_URL_VISITED ||
+ type == chrome::NOTIFICATION_HISTORY_URLS_DELETED) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = weak_java_provider_.get(env);
+ if (obj.is_null())
+ return;
+ Java_ChromeBrowserProvider_onBookmarkChanged(env, obj.obj());
+ } else if (type ==
+ chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = weak_java_provider_.get(env);
+ if (obj.is_null())
+ return;
+ Java_ChromeBrowserProvider_onSearchTermChanged(env, obj.obj());
+ } else if (type == chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED) {
+ template_loaded_event_.Signal();
+ }
+}
« 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