1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/android/bookmarks/partner_bookmarks_reader.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/logging.h"
10 #include "chrome/browser/android/bookmarks/partner_bookmarks_shim.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/favicon/favicon_service_factory.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "components/bookmarks/browser/bookmark_model.h"
16 #include "components/favicon/core/favicon_service.h"
17 #include "components/favicon_base/favicon_types.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "jni/PartnerBookmarksReader_jni.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
21 #include "ui/gfx/codec/png_codec.h"
22 #include "ui/gfx/favicon_size.h"
24 using base::android::AttachCurrentThread
;
25 using base::android::CheckException
;
26 using base::android::ConvertJavaStringToUTF16
;
27 using bookmarks::BookmarkNode
;
28 using bookmarks::BookmarkPermanentNode
;
29 using content::BrowserThread
;
33 void SetFaviconTask(Profile
* profile
,
34 const GURL
& page_url
, const GURL
& icon_url
,
35 const std::vector
<unsigned char>& image_data
,
36 favicon_base::IconType icon_type
) {
37 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
38 scoped_refptr
<base::RefCountedMemory
> bitmap_data(
39 new base::RefCountedBytes(image_data
));
40 gfx::Size
pixel_size(gfx::kFaviconSize
, gfx::kFaviconSize
);
41 favicon::FaviconService
* favicon_service
=
42 FaviconServiceFactory::GetForProfile(
43 ProfileManager::GetActiveUserProfile(),
44 ServiceAccessType::EXPLICIT_ACCESS
);
48 favicon_service
->MergeFavicon(
49 page_url
, page_url
, icon_type
, bitmap_data
, pixel_size
);
52 void SetFaviconCallback(Profile
* profile
,
53 const GURL
& page_url
, const GURL
& icon_url
,
54 const std::vector
<unsigned char>& image_data
,
55 favicon_base::IconType icon_type
,
56 base::WaitableEvent
* bookmark_added_event
) {
57 SetFaviconTask(profile
, page_url
, icon_url
, image_data
, icon_type
);
58 if (bookmark_added_event
)
59 bookmark_added_event
->Signal();
62 void PrepareAndSetFavicon(JNIEnv
* env
, jbyte
* icon_bytes
, int icon_len
,
63 BookmarkNode
* node
, Profile
* profile
,
64 favicon_base::IconType icon_type
) {
66 if (!gfx::PNGCodec::Decode(
67 reinterpret_cast<const unsigned char*>(icon_bytes
),
68 icon_len
, &icon_bitmap
))
70 std::vector
<unsigned char> image_data
;
71 if (!gfx::PNGCodec::EncodeBGRASkBitmap(icon_bitmap
, false, &image_data
))
73 // TODO(aruslan): TODO(tedchoc): Follow up on how to avoid this through js.
74 // Since the favicon URL is used as a key in the history's thumbnail DB,
75 // this gives us a value which does not collide with others.
76 GURL fake_icon_url
= node
->url();
77 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
78 SetFaviconTask(profile
,
79 node
->url(), fake_icon_url
,
80 image_data
, icon_type
);
82 base::WaitableEvent
event(false, false);
83 BrowserThread::PostTask(
86 base::Bind(&SetFaviconCallback
,
87 profile
, node
->url(), fake_icon_url
,
88 image_data
, icon_type
, &event
));
89 // TODO(aruslan): http://b/6397072 If possible - avoid using favicon service
94 const BookmarkNode
* GetNodeByID(const BookmarkNode
* parent
, int64 id
) {
95 if (parent
->id() == id
)
97 for (int i
= 0, child_count
= parent
->child_count(); i
< child_count
; ++i
) {
98 const BookmarkNode
* result
= GetNodeByID(parent
->GetChild(i
), id
);
107 PartnerBookmarksReader::PartnerBookmarksReader(
108 PartnerBookmarksShim
* partner_bookmarks_shim
,
110 : partner_bookmarks_shim_(partner_bookmarks_shim
),
112 wip_next_available_id_(0) {
115 PartnerBookmarksReader::~PartnerBookmarksReader() {}
117 void PartnerBookmarksReader::PartnerBookmarksCreationComplete(JNIEnv
*,
119 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
120 partner_bookmarks_shim_
->SetPartnerBookmarksRoot(
121 wip_partner_bookmarks_root_
.release());
122 wip_next_available_id_
= 0;
125 void PartnerBookmarksReader::Destroy(JNIEnv
* env
, jobject obj
) {
129 void PartnerBookmarksReader::Reset(JNIEnv
* env
, jobject obj
) {
130 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
131 wip_partner_bookmarks_root_
.reset();
132 wip_next_available_id_
= 0;
135 jlong
PartnerBookmarksReader::AddPartnerBookmark(JNIEnv
* env
,
142 jbyteArray touchicon
) {
144 base::string16 title
;
146 url
= ConvertJavaStringToUTF16(env
, jurl
);
148 title
= ConvertJavaStringToUTF16(env
, jtitle
);
150 BookmarkNode
* node
= NULL
;
151 if (wip_partner_bookmarks_root_
.get()) {
152 node
= new BookmarkNode(wip_next_available_id_
++, GURL(url
));
153 node
->set_type(is_folder
? BookmarkNode::FOLDER
: BookmarkNode::URL
);
154 node
->SetTitle(title
);
156 // Handle favicon and touchicon
157 if (profile_
!= NULL
&& (favicon
!= NULL
|| touchicon
!= NULL
)) {
158 jbyteArray icon
= (touchicon
!= NULL
) ? touchicon
: favicon
;
159 const favicon_base::IconType icon_type
=
160 touchicon
? favicon_base::TOUCH_ICON
: favicon_base::FAVICON
;
161 const int icon_len
= env
->GetArrayLength(icon
);
162 jbyte
* icon_bytes
= env
->GetByteArrayElements(icon
, NULL
);
164 PrepareAndSetFavicon(env
, icon_bytes
, icon_len
,
165 node
, profile_
, icon_type
);
166 env
->ReleaseByteArrayElements(icon
, icon_bytes
, JNI_ABORT
);
169 const BookmarkNode
* parent
=
170 GetNodeByID(wip_partner_bookmarks_root_
.get(), parent_id
);
172 LOG(WARNING
) << "partner_bookmarks_shim: invalid/unknown parent_id="
173 << parent_id
<< ": adding to the root";
174 parent
= wip_partner_bookmarks_root_
.get();
176 const_cast<BookmarkNode
*>(parent
)->Add(node
, parent
->child_count());
178 node
= new BookmarkPermanentNode(wip_next_available_id_
++);
179 node
->SetTitle(title
);
180 wip_partner_bookmarks_root_
.reset(node
);
186 static void DisablePartnerBookmarksEditing(JNIEnv
* env
, jclass clazz
) {
187 PartnerBookmarksShim::DisablePartnerBookmarksEditing();
191 bool PartnerBookmarksReader::RegisterPartnerBookmarksReader(JNIEnv
* env
) {
192 return RegisterNativesImpl(env
);
195 // ----------------------------------------------------------------
197 static jlong
Init(JNIEnv
* env
, jobject obj
) {
198 Profile
* profile
= ProfileManager::GetActiveUserProfile();
199 PartnerBookmarksShim
* partner_bookmarks_shim
=
200 PartnerBookmarksShim::BuildForBrowserContext(profile
);
201 PartnerBookmarksReader
* reader
= new PartnerBookmarksReader(
202 partner_bookmarks_shim
, profile
);
203 return reinterpret_cast<intptr_t>(reader
);