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.h"
13 #include "chrome/browser/favicon/favicon_service_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/profiles/profile_manager.h"
16 #include "components/bookmarks/browser/bookmark_model.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(BrowserThread::CurrentlyOn(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 FaviconService
* favicon_service
= FaviconServiceFactory::GetForProfile(
42 ProfileManager::GetActiveUserProfile(),
43 ServiceAccessType::EXPLICIT_ACCESS
);
47 favicon_service
->MergeFavicon(
48 page_url
, page_url
, icon_type
, bitmap_data
, pixel_size
);
51 void SetFaviconCallback(Profile
* profile
,
52 const GURL
& page_url
, const GURL
& icon_url
,
53 const std::vector
<unsigned char>& image_data
,
54 favicon_base::IconType icon_type
,
55 base::WaitableEvent
* bookmark_added_event
) {
56 SetFaviconTask(profile
, page_url
, icon_url
, image_data
, icon_type
);
57 if (bookmark_added_event
)
58 bookmark_added_event
->Signal();
61 void PrepareAndSetFavicon(JNIEnv
* env
, jbyte
* icon_bytes
, int icon_len
,
62 BookmarkNode
* node
, Profile
* profile
,
63 favicon_base::IconType icon_type
) {
65 if (!gfx::PNGCodec::Decode(
66 reinterpret_cast<const unsigned char*>(icon_bytes
),
67 icon_len
, &icon_bitmap
))
69 std::vector
<unsigned char> image_data
;
70 if (!gfx::PNGCodec::EncodeBGRASkBitmap(icon_bitmap
, false, &image_data
))
72 // TODO(aruslan): TODO(tedchoc): Follow up on how to avoid this through js.
73 // Since the favicon URL is used as a key in the history's thumbnail DB,
74 // this gives us a value which does not collide with others.
75 GURL fake_icon_url
= node
->url();
76 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
77 SetFaviconTask(profile
,
78 node
->url(), fake_icon_url
,
79 image_data
, icon_type
);
81 base::WaitableEvent
event(false, false);
82 BrowserThread::PostTask(
85 base::Bind(&SetFaviconCallback
,
86 profile
, node
->url(), fake_icon_url
,
87 image_data
, icon_type
, &event
));
88 // TODO(aruslan): http://b/6397072 If possible - avoid using favicon service
93 const BookmarkNode
* GetNodeByID(const BookmarkNode
* parent
, int64 id
) {
94 if (parent
->id() == id
)
96 for (int i
= 0, child_count
= parent
->child_count(); i
< child_count
; ++i
) {
97 const BookmarkNode
* result
= GetNodeByID(parent
->GetChild(i
), id
);
106 PartnerBookmarksReader::PartnerBookmarksReader(
107 PartnerBookmarksShim
* partner_bookmarks_shim
,
109 : partner_bookmarks_shim_(partner_bookmarks_shim
),
111 wip_next_available_id_(0) {
114 PartnerBookmarksReader::~PartnerBookmarksReader() {}
116 void PartnerBookmarksReader::PartnerBookmarksCreationComplete(JNIEnv
*,
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
119 partner_bookmarks_shim_
->SetPartnerBookmarksRoot(
120 wip_partner_bookmarks_root_
.release());
121 wip_next_available_id_
= 0;
124 void PartnerBookmarksReader::Destroy(JNIEnv
* env
, jobject obj
) {
128 void PartnerBookmarksReader::Reset(JNIEnv
* env
, jobject obj
) {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
130 wip_partner_bookmarks_root_
.reset();
131 wip_next_available_id_
= 0;
134 jlong
PartnerBookmarksReader::AddPartnerBookmark(JNIEnv
* env
,
141 jbyteArray touchicon
) {
143 base::string16 title
;
145 url
= ConvertJavaStringToUTF16(env
, jurl
);
147 title
= ConvertJavaStringToUTF16(env
, jtitle
);
149 BookmarkNode
* node
= NULL
;
150 if (wip_partner_bookmarks_root_
.get()) {
151 node
= new BookmarkNode(wip_next_available_id_
++, GURL(url
));
152 node
->set_type(is_folder
? BookmarkNode::FOLDER
: BookmarkNode::URL
);
153 node
->SetTitle(title
);
155 // Handle favicon and touchicon
156 if (profile_
!= NULL
&& (favicon
!= NULL
|| touchicon
!= NULL
)) {
157 jbyteArray icon
= (touchicon
!= NULL
) ? touchicon
: favicon
;
158 const favicon_base::IconType icon_type
=
159 touchicon
? favicon_base::TOUCH_ICON
: favicon_base::FAVICON
;
160 const int icon_len
= env
->GetArrayLength(icon
);
161 jbyte
* icon_bytes
= env
->GetByteArrayElements(icon
, NULL
);
163 PrepareAndSetFavicon(env
, icon_bytes
, icon_len
,
164 node
, profile_
, icon_type
);
165 env
->ReleaseByteArrayElements(icon
, icon_bytes
, JNI_ABORT
);
168 const BookmarkNode
* parent
=
169 GetNodeByID(wip_partner_bookmarks_root_
.get(), parent_id
);
171 LOG(WARNING
) << "partner_bookmarks_shim: invalid/unknown parent_id="
172 << parent_id
<< ": adding to the root";
173 parent
= wip_partner_bookmarks_root_
.get();
175 const_cast<BookmarkNode
*>(parent
)->Add(node
, parent
->child_count());
177 node
= new BookmarkPermanentNode(wip_next_available_id_
++);
178 node
->SetTitle(title
);
179 wip_partner_bookmarks_root_
.reset(node
);
185 static void DisablePartnerBookmarksEditing(JNIEnv
* env
, jclass clazz
) {
186 PartnerBookmarksShim::DisablePartnerBookmarksEditing();
190 bool PartnerBookmarksReader::RegisterPartnerBookmarksReader(JNIEnv
* env
) {
191 return RegisterNativesImpl(env
);
194 // ----------------------------------------------------------------
196 static jlong
Init(JNIEnv
* env
, jobject obj
) {
197 Profile
* profile
= ProfileManager::GetActiveUserProfile();
198 PartnerBookmarksShim
* partner_bookmarks_shim
=
199 PartnerBookmarksShim::BuildForBrowserContext(profile
);
200 PartnerBookmarksReader
* reader
= new PartnerBookmarksReader(
201 partner_bookmarks_shim
, profile
);
202 return reinterpret_cast<intptr_t>(reader
);