| Index: chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
|
| diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc b/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1434b6ae4576b1695024e7da1480510eee08950f
|
| --- /dev/null
|
| +++ b/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
|
| @@ -0,0 +1,201 @@
|
| +// Copyright 2015 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/bookmarks/partner_bookmarks_reader.h"
|
| +
|
| +#include "base/android/jni_android.h"
|
| +#include "base/android/jni_string.h"
|
| +#include "base/logging.h"
|
| +#include "chrome/browser/android/bookmarks/partner_bookmarks_shim.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/profiles/profile.h"
|
| +#include "chrome/browser/profiles/profile_manager.h"
|
| +#include "components/bookmarks/browser/bookmark_model.h"
|
| +#include "components/favicon_base/favicon_types.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "jni/PartnerBookmarksReader_jni.h"
|
| +#include "third_party/skia/include/core/SkBitmap.h"
|
| +#include "ui/gfx/codec/png_codec.h"
|
| +#include "ui/gfx/favicon_size.h"
|
| +
|
| +using base::android::AttachCurrentThread;
|
| +using base::android::CheckException;
|
| +using base::android::ConvertJavaStringToUTF16;
|
| +using content::BrowserThread;
|
| +
|
| +namespace {
|
| +
|
| +void SetFaviconTask(Profile* profile,
|
| + const GURL& page_url, const GURL& icon_url,
|
| + const std::vector<unsigned char>& image_data,
|
| + favicon_base::IconType icon_type) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + scoped_refptr<base::RefCountedMemory> bitmap_data(
|
| + new base::RefCountedBytes(image_data));
|
| + gfx::Size pixel_size(gfx::kFaviconSize, gfx::kFaviconSize);
|
| + FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
|
| + ProfileManager::GetActiveUserProfile(),
|
| + ServiceAccessType::EXPLICIT_ACCESS);
|
| + if (!favicon_service)
|
| + return;
|
| +
|
| + favicon_service->MergeFavicon(
|
| + page_url, page_url, icon_type, bitmap_data, pixel_size);
|
| +}
|
| +
|
| +void SetFaviconCallback(Profile* profile,
|
| + const GURL& page_url, const GURL& icon_url,
|
| + const std::vector<unsigned char>& image_data,
|
| + favicon_base::IconType icon_type,
|
| + base::WaitableEvent* bookmark_added_event) {
|
| + SetFaviconTask(profile, page_url, icon_url, image_data, icon_type);
|
| + if (bookmark_added_event)
|
| + bookmark_added_event->Signal();
|
| +}
|
| +
|
| +void PrepareAndSetFavicon(JNIEnv* env, jbyte* icon_bytes, int icon_len,
|
| + BookmarkNode* node, Profile* profile,
|
| + favicon_base::IconType icon_type) {
|
| + SkBitmap icon_bitmap;
|
| + if (!gfx::PNGCodec::Decode(
|
| + reinterpret_cast<const unsigned char*>(icon_bytes),
|
| + icon_len, &icon_bitmap))
|
| + return;
|
| + std::vector<unsigned char> image_data;
|
| + if (!gfx::PNGCodec::EncodeBGRASkBitmap(icon_bitmap, false, &image_data))
|
| + return;
|
| + // TODO(aruslan): TODO(tedchoc): Follow up on how to avoid this through js.
|
| + // Since the favicon URL is used as a key in the history's thumbnail DB,
|
| + // this gives us a value which does not collide with others.
|
| + GURL fake_icon_url = node->url();
|
| + if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
|
| + SetFaviconTask(profile,
|
| + node->url(), fake_icon_url,
|
| + image_data, icon_type);
|
| + } else {
|
| + base::WaitableEvent event(false, false);
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(&SetFaviconCallback,
|
| + profile, node->url(), fake_icon_url,
|
| + image_data, icon_type, &event));
|
| + // TODO(aruslan): http://b/6397072 If possible - avoid using favicon service
|
| + event.Wait();
|
| + }
|
| +}
|
| +
|
| +const BookmarkNode* GetNodeByID(const BookmarkNode* parent, int64 id) {
|
| + if (parent->id() == id)
|
| + return parent;
|
| + for (int i= 0, child_count = parent->child_count(); i < child_count; ++i) {
|
| + const BookmarkNode* result = GetNodeByID(parent->GetChild(i), id);
|
| + if (result)
|
| + return result;
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +PartnerBookmarksReader::PartnerBookmarksReader(
|
| + PartnerBookmarksShim* partner_bookmarks_shim,
|
| + Profile* profile)
|
| + : partner_bookmarks_shim_(partner_bookmarks_shim),
|
| + profile_(profile),
|
| + wip_next_available_id_(0) {
|
| +}
|
| +
|
| +PartnerBookmarksReader::~PartnerBookmarksReader() {}
|
| +
|
| +void PartnerBookmarksReader::PartnerBookmarksCreationComplete(JNIEnv*,
|
| + jobject) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + partner_bookmarks_shim_->SetPartnerBookmarksRoot(
|
| + wip_partner_bookmarks_root_.release());
|
| + wip_next_available_id_ = 0;
|
| +}
|
| +
|
| +void PartnerBookmarksReader::Destroy(JNIEnv* env, jobject obj) {
|
| + delete this;
|
| +}
|
| +
|
| +void PartnerBookmarksReader::Reset(JNIEnv* env, jobject obj) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + wip_partner_bookmarks_root_.reset();
|
| + wip_next_available_id_ = 0;
|
| +}
|
| +
|
| +jlong PartnerBookmarksReader::AddPartnerBookmark(JNIEnv* env,
|
| + jobject obj,
|
| + jstring jurl,
|
| + jstring jtitle,
|
| + jboolean is_folder,
|
| + jlong parent_id,
|
| + jbyteArray favicon,
|
| + jbyteArray touchicon) {
|
| + base::string16 url;
|
| + base::string16 title;
|
| + if (jurl)
|
| + url = ConvertJavaStringToUTF16(env, jurl);
|
| + if (jtitle)
|
| + title = ConvertJavaStringToUTF16(env, jtitle);
|
| +
|
| + BookmarkNode* node = NULL;
|
| + if (wip_partner_bookmarks_root_.get()) {
|
| + node = new BookmarkNode(wip_next_available_id_++, GURL(url));
|
| + node->set_type(is_folder ? BookmarkNode::FOLDER : BookmarkNode::URL);
|
| + node->SetTitle(title);
|
| +
|
| + // Handle favicon and touchicon
|
| + if (profile_ != NULL && (favicon != NULL || touchicon != NULL)) {
|
| + jbyteArray icon = (touchicon != NULL) ? touchicon : favicon;
|
| + const favicon_base::IconType icon_type =
|
| + touchicon ? favicon_base::TOUCH_ICON : favicon_base::FAVICON;
|
| + const int icon_len = env->GetArrayLength(icon);
|
| + jbyte* icon_bytes = env->GetByteArrayElements(icon, NULL);
|
| + if (icon_bytes)
|
| + PrepareAndSetFavicon(env, icon_bytes, icon_len,
|
| + node, profile_, icon_type);
|
| + env->ReleaseByteArrayElements(icon, icon_bytes, JNI_ABORT);
|
| + }
|
| +
|
| + const BookmarkNode* parent =
|
| + GetNodeByID(wip_partner_bookmarks_root_.get(), parent_id);
|
| + if (!parent) {
|
| + LOG(WARNING) << "partner_bookmarks_shim: invalid/unknown parent_id="
|
| + << parent_id << ": adding to the root";
|
| + parent = wip_partner_bookmarks_root_.get();
|
| + }
|
| + const_cast<BookmarkNode*>(parent)->Add(node, parent->child_count());
|
| + } else {
|
| + node = new BookmarkPermanentNode(wip_next_available_id_++);
|
| + node->SetTitle(title);
|
| + wip_partner_bookmarks_root_.reset(node);
|
| + }
|
| + return node->id();
|
| +}
|
| +
|
| +// static
|
| +static void DisablePartnerBookmarksEditing(JNIEnv* env, jclass clazz) {
|
| + PartnerBookmarksShim::DisablePartnerBookmarksEditing();
|
| +}
|
| +
|
| +// static
|
| +bool PartnerBookmarksReader::RegisterPartnerBookmarksReader(JNIEnv* env) {
|
| + return RegisterNativesImpl(env);
|
| +}
|
| +
|
| +// ----------------------------------------------------------------
|
| +
|
| +static jlong Init(JNIEnv* env, jobject obj) {
|
| + Profile* profile = ProfileManager::GetActiveUserProfile();
|
| + PartnerBookmarksShim* partner_bookmarks_shim =
|
| + PartnerBookmarksShim::BuildForBrowserContext(profile);
|
| + PartnerBookmarksReader* reader = new PartnerBookmarksReader(
|
| + partner_bookmarks_shim, profile);
|
| + return reinterpret_cast<intptr_t>(reader);
|
| +}
|
|
|