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

Side by Side Diff: chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc

Issue 10829326: Add the webui handler for Android's bookmark section on the NTP. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 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/ui/webui/ntp/android/bookmarks_handler.h"
6
7 #include "base/logging.h"
8 #include "base/memory/ref_counted_memory.h"
9 #include "base/string_number_conversions.h"
10 #include "base/string_util.h"
11 #include "chrome/browser/android/tab_android.h"
12 #include "chrome/browser/bookmarks/bookmark_model.h"
13 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/profiles/profile_manager.h"
16 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
17 #include "chrome/browser/ui/webui/favicon_source.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/web_contents.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
21 #include "ui/gfx/codec/png_codec.h"
22 #include "ui/gfx/color_analysis.h"
23
24 using base::Int64ToString;
25 using content::BrowserThread;
26
27 namespace {
28
29 static const char* kParentIdParam = "parent_id";
30 static const char* kNodeIdParam = "node_id";
31
32 // Parses a bookmark ID passed back from the NTP. The IDs differ from the
33 // normal int64 bookmark ID because we prepend a "p" if the ID represents a
34 // partner bookmark.
35 bool ParseNtpBookmarkId(const ListValue* args,
36 int64* out_id,
37 bool* out_is_partner) {
38 std::string string_id;
39 if (!args->GetString(0, &string_id))
40 return false;
41
42 if (string_id.empty())
43 return false;
44
45 if (StartsWithASCII(string_id, "p", true)) {
46 *out_is_partner = true;
47 return base::StringToInt64(string_id.substr(1), out_id);
48 }
49
50 *out_is_partner = false;
51 return base::StringToInt64(string_id, out_id);
52 }
53
54 std::string BookmarkTypeAsString(BookmarkNode::Type type) {
55 switch (type) {
56 case BookmarkNode::URL:
57 return "URL";
58 case BookmarkNode::FOLDER:
59 return "FOLDER";
60 case BookmarkNode::BOOKMARK_BAR:
61 return "BOOKMARK_BAR";
62 case BookmarkNode::OTHER_NODE:
63 return "OTHER_NODE";
64 case BookmarkNode::MOBILE:
65 return "MOBILE";
66 default:
67 return "UNKNOWN";
68 }
69 }
70
71 SkColor GetDominantColorForFavicon(scoped_refptr<base::RefCountedMemory> png) {
72 color_utils::GridSampler sampler;
73 // 100 here is the darkness_limit which represents the minimum sum of the RGB
74 // components that is acceptable as a color choice. This can be from 0 to 765.
75 // 665 here is the brightness_limit represents the maximum sum of the RGB
76 // components that is acceptable as a color choice. This can be from 0 to 765.
77 return color_utils::CalculateKMeanColorOfPNG(png, 100, 665, sampler);
78 }
79
80 } // namespace
81
82 BookmarksHandler::BookmarksHandler()
83 : bookmark_model_(NULL),
84 partner_bookmarks_shim_(NULL),
85 bookmark_data_requested_(false),
86 extensive_changes_(false) {
87 }
88
89 BookmarksHandler::~BookmarksHandler() {
90 if (bookmark_model_)
91 bookmark_model_->RemoveObserver(this);
92
93 if (partner_bookmarks_shim_)
94 partner_bookmarks_shim_->RemoveObserver(this);
95 }
96
97 void BookmarksHandler::RegisterMessages() {
98 // Listen for the bookmark change. We need the both bookmark and folder
99 // change, the NotificationService is not sufficient.
100 Profile* profile = Profile::FromBrowserContext(
101 web_ui()->GetWebContents()->GetBrowserContext());
102
103 ChromeURLDataManager::AddDataSource(profile,
104 new FaviconSource(profile, FaviconSource::ANY));
105
106 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile);
107 if (bookmark_model_) {
108 bookmark_model_->AddObserver(this);
109 // Since a sync or import could have started before this class is
110 // initialized, we need to make sure that our initial state is
111 // up to date.
112 extensive_changes_ = bookmark_model_->IsDoingExtensiveChanges();
113 }
114
115 // Create the partner Bookmarks shim as early as possible (but don't attach).
116 if (!partner_bookmarks_shim_) {
117 partner_bookmarks_shim_ = PartnerBookmarksShim::GetInstance();
118 partner_bookmarks_shim_->AddObserver(this);
119 }
120
121 // Register ourselves as the handler for the bookmark javascript callbacks.
122 web_ui()->RegisterMessageCallback("getBookmarks",
123 base::Bind(&BookmarksHandler::HandleGetBookmarks,
124 base::Unretained(this)));
125 web_ui()->RegisterMessageCallback("deleteBookmark",
126 base::Bind(&BookmarksHandler::HandleDeleteBookmark,
127 base::Unretained(this)));
128 web_ui()->RegisterMessageCallback("createHomeScreenBookmarkShortcut",
129 base::Bind(&BookmarksHandler::HandleCreateHomeScreenBookmarkShortcut,
130 base::Unretained(this)));
131 }
132
133 void BookmarksHandler::HandleGetBookmarks(const ListValue* args) {
134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
135
136 bookmark_data_requested_ = true;
137 Profile* profile = Profile::FromBrowserContext(
138 web_ui()->GetWebContents()->GetBrowserContext());
139 if (!BookmarkModelFactory::GetForProfile(profile)->IsLoaded())
140 return; // is handled in Loaded().
141
142 // Attach the Partner Bookmarks shim under the Mobile Bookmarks.
143 // Cannot do this earlier because mobile_node is not yet set.
144 DCHECK(partner_bookmarks_shim_ != NULL);
145 if (bookmark_model_) {
146 partner_bookmarks_shim_->AttachTo(
147 bookmark_model_, bookmark_model_->mobile_node());
148 }
149 if (!partner_bookmarks_shim_->IsLoaded())
150 return; // is handled with a PartnerShimLoaded() callback
151
152 int64 id;
153 bool is_partner;
154 if (args && !args->empty() && ParseNtpBookmarkId(args, &id, &is_partner))
155 QueryBookmarkFolder(id, is_partner);
156 else
157 QueryInitialBookmarks();
158 }
159
160 void BookmarksHandler::HandleDeleteBookmark(const ListValue* args) {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
162 int64 id;
163 bool is_partner;
164 if (args && !args->empty() && ParseNtpBookmarkId(args, &id, &is_partner)) {
165 DCHECK(!is_partner);
166 const BookmarkNode* node = bookmark_model_->GetNodeByID(id);
167 if (node && node->parent()) {
168 const BookmarkNode* parent_node = node->parent();
169 bookmark_model_->Remove(parent_node, parent_node->GetIndexOf(node));
170 }
171 }
172 }
173
174 std::string BookmarksHandler::GetBookmarkIdForNtp(const BookmarkNode* node) {
175 return (partner_bookmarks_shim_->IsPartnerBookmark(node) ? "p" : "") +
176 Int64ToString(node->id());
177 }
178
179 void BookmarksHandler::SetParentInBookmarksResult(const BookmarkNode* parent,
180 DictionaryValue* result) {
181 result->SetString(kParentIdParam, GetBookmarkIdForNtp(parent));
182 }
183
184 void BookmarksHandler::PopulateBookmark(const BookmarkNode* node,
185 ListValue* result) {
186 if (!result)
187 return;
188
189 DictionaryValue* filler_value = new DictionaryValue();
190 filler_value->SetString("title", node->GetTitle());
191 // Mark reserved system nodes and partner bookmarks as uneditable
192 // (i.e. the bookmark bar along with the "Other Bookmarks" folder).
193 filler_value->SetBoolean("editable",
194 partner_bookmarks_shim_->IsBookmarkEditable(node));
195 if (node->is_url()) {
196 filler_value->SetBoolean("folder", false);
197 filler_value->SetString("url", node->url().spec());
198 } else {
199 filler_value->SetBoolean("folder", true);
200 }
201 filler_value->SetString("id", GetBookmarkIdForNtp(node));
202 filler_value->SetString("type", BookmarkTypeAsString(node->type()));
203 result->Append(filler_value);
204 }
205
206 void BookmarksHandler::PopulateBookmarksInFolder(
207 const BookmarkNode* folder,
208 DictionaryValue* result) {
209 ListValue* bookmarks = new ListValue();
210
211 for (int i = 0; i < folder->child_count(); i++) {
212 const BookmarkNode* bookmark= folder->GetChild(i);
213 PopulateBookmark(bookmark, bookmarks);
214 }
215
216 // Make sure we iterate over the partner's attach point
217 DCHECK(partner_bookmarks_shim_ != NULL);
218 if (partner_bookmarks_shim_->HasPartnerBookmarks() &&
219 folder == partner_bookmarks_shim_->get_attach_point()) {
220 PopulateBookmark(
221 partner_bookmarks_shim_->GetPartnerBookmarksRoot(), bookmarks);
222 }
223
224 ListValue* folder_hierarchy = new ListValue();
225 const BookmarkNode* parent = partner_bookmarks_shim_->GetParentOf(folder);
226
227 while (parent != NULL) {
228 DictionaryValue* hierarchy_entry = new DictionaryValue();
229 if (partner_bookmarks_shim_->IsRootNode(parent))
230 hierarchy_entry->SetBoolean("root", true);
231
232 hierarchy_entry->SetString("title", parent->GetTitle());
233 hierarchy_entry->SetString("id", GetBookmarkIdForNtp(parent));
234 folder_hierarchy->Append(hierarchy_entry);
235 parent = partner_bookmarks_shim_->GetParentOf(parent);
236 }
237
238 result->SetString("title", folder->GetTitle());
239 result->SetString("id", GetBookmarkIdForNtp(folder));
240 result->SetBoolean("root", partner_bookmarks_shim_->IsRootNode(folder));
241 result->Set("bookmarks", bookmarks);
242 result->Set("hierarchy", folder_hierarchy);
243 }
244
245 void BookmarksHandler::QueryBookmarkFolder(const int64& folder_id,
246 bool is_partner_bookmark) {
247 DCHECK(partner_bookmarks_shim_ != NULL);
248 const BookmarkNode* bookmarks =
249 partner_bookmarks_shim_->GetNodeByID(folder_id, is_partner_bookmark);
250 if (bookmarks) {
251 DictionaryValue result;
252 PopulateBookmarksInFolder(bookmarks, &result);
253 SendResult(result);
254 } else {
255 // If we receive an ID that no longer maps to a bookmark folder, just
256 // return the initial bookmark folder.
257 QueryInitialBookmarks();
258 }
259 }
260
261 void BookmarksHandler::QueryInitialBookmarks() {
262 DictionaryValue result;
263 DCHECK(partner_bookmarks_shim_ != NULL);
264 PopulateBookmarksInFolder(
265 // We have to go to the partner Root if it exists
266 partner_bookmarks_shim_->HasPartnerBookmarks() ?
267 partner_bookmarks_shim_->GetPartnerBookmarksRoot() :
268 bookmark_model_->mobile_node(),
269 &result);
270 SendResult(result);
271 }
272
273 void BookmarksHandler::SendResult(const DictionaryValue& result) {
274 web_ui()->CallJavascriptFunction("ntp.bookmarks", result);
275 }
276
277 void BookmarksHandler::Loaded(BookmarkModel* model, bool ids_reassigned) {
278 BookmarkModelChanged();
279 }
280
281 void BookmarksHandler::PartnerShimLoaded(PartnerBookmarksShim* shim) {
282 BookmarkModelChanged();
283 }
284
285 void BookmarksHandler::ShimBeingDeleted(PartnerBookmarksShim* shim) {
286 partner_bookmarks_shim_ = NULL;
287 }
288
289 void BookmarksHandler::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
290 extensive_changes_ = true;
291 }
292
293 void BookmarksHandler::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
294 extensive_changes_ = false;
295 BookmarkModelChanged();
296 }
297
298 void BookmarksHandler::BookmarkNodeRemoved(BookmarkModel* model,
299 const BookmarkNode* parent,
300 int old_index,
301 const BookmarkNode* node) {
302 DictionaryValue result;
303 SetParentInBookmarksResult(parent, &result);
304 result.SetString(kNodeIdParam, Int64ToString(node->id()));
305 NotifyModelChanged(result);
306 }
307
308 void BookmarksHandler::BookmarkNodeAdded(BookmarkModel* model,
309 const BookmarkNode* parent,
310 int index) {
311 DictionaryValue result;
312 SetParentInBookmarksResult(parent, &result);
313 NotifyModelChanged(result);
314 }
315
316 void BookmarksHandler::BookmarkNodeChanged(BookmarkModel* model,
317 const BookmarkNode* node) {
318 DCHECK(partner_bookmarks_shim_);
319 DCHECK(!partner_bookmarks_shim_->IsPartnerBookmark(node));
320 DictionaryValue result;
321 SetParentInBookmarksResult(node->parent(), &result);
322 result.SetString(kNodeIdParam, Int64ToString(node->id()));
323 NotifyModelChanged(result);
324 }
325
326 void BookmarksHandler::BookmarkModelChanged() {
327 if (bookmark_data_requested_ && !extensive_changes_)
328 web_ui()->CallJavascriptFunction("ntp.bookmarkChanged");
329 }
330
331 void BookmarksHandler::NotifyModelChanged(const DictionaryValue& status) {
332 if (bookmark_data_requested_ && !extensive_changes_)
333 web_ui()->CallJavascriptFunction("ntp.bookmarkChanged", status);
334 }
335
336 void BookmarksHandler::HandleCreateHomeScreenBookmarkShortcut(
337 const ListValue* args) {
338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
339 Profile* profile = Profile::FromBrowserContext(
340 web_ui()->GetWebContents()->GetBrowserContext());
341 if (!profile)
342 return;
343
344 int64 id;
345 bool is_partner;
346 if (args && !args->empty() && ParseNtpBookmarkId(args, &id, &is_partner)) {
347 DCHECK(partner_bookmarks_shim_ != NULL);
348 const BookmarkNode* node =
349 partner_bookmarks_shim_->GetNodeByID(id, is_partner);
350 if (!node)
351 return;
352
353 FaviconService* favicon_service = profile->GetFaviconService(
354 Profile::EXPLICIT_ACCESS);
355 FaviconService::Handle handle = favicon_service->GetFaviconForURL(
356 node->url(),
357 history::FAVICON | history::TOUCH_ICON,
358 &cancelable_consumer_,
359 base::Bind(&BookmarksHandler::OnShortcutFaviconDataAvailable,
360 base::Unretained(this)));
361 cancelable_consumer_.SetClientData(favicon_service, handle, node);
362 }
363 }
364
365 void BookmarksHandler::OnShortcutFaviconDataAvailable(
366 FaviconService::Handle handle,
367 history::FaviconData favicon) {
368 SkColor color = SK_ColorWHITE;
369 SkBitmap favicon_bitmap;
370 if (favicon.is_valid()) {
371 color = GetDominantColorForFavicon(favicon.image_data);
372 gfx::PNGCodec::Decode(favicon.image_data->front(),
373 favicon.image_data->size(),
374 &favicon_bitmap);
375 }
376
377 Profile* profile = Profile::FromBrowserContext(
378 web_ui()->GetWebContents()->GetBrowserContext());
379 const BookmarkNode* node = cancelable_consumer_.GetClientData(
380 profile->GetFaviconService(Profile::EXPLICIT_ACCESS), handle);
381
382 TabAndroid* tab = TabAndroid::FromWebContents(
383 web_ui()->GetWebContents());
384 if (tab) {
385 tab->AddShortcutToBookmark(node->url(), node->GetTitle(),
386 favicon_bitmap, SkColorGetR(color),
387 SkColorGetG(color), SkColorGetB(color));
388 }
389 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/webui/ntp/android/bookmarks_handler.h ('k') | chrome/browser/ui/webui/ntp/new_tab_ui.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698