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

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: Resolving Review comments. 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 // TODO(tedchoc): Change shortcutToBookmark to
129 // createHomeScreenBookmarkShortcut once the ntp js code lands.
130 web_ui()->RegisterMessageCallback("shortcutToBookmark",
131 base::Bind(&BookmarksHandler::HandleCreateHomeScreenBookmarkShortcut,
132 base::Unretained(this)));
133 }
134
135 void BookmarksHandler::HandleGetBookmarks(const ListValue* args) {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
137
138 bookmark_data_requested_ = true;
139 Profile* profile = Profile::FromBrowserContext(
140 web_ui()->GetWebContents()->GetBrowserContext());
141 if (!BookmarkModelFactory::GetForProfile(profile)->IsLoaded())
142 return; // is handled in Loaded().
143
144 // Attach the Partner Bookmarks shim under the Mobile Bookmarks.
145 // Cannot do this earlier because mobile_node is not yet set.
146 DCHECK(partner_bookmarks_shim_ != NULL);
147 if (bookmark_model_) {
148 partner_bookmarks_shim_->AttachTo(
149 bookmark_model_, bookmark_model_->mobile_node());
150 }
151 if (!partner_bookmarks_shim_->IsLoaded())
152 return; // is handled with a PartnerShimLoaded() callback
Evan Stade 2012/08/15 22:57:27 2 spaces here too (presubmit should catch this)
Ted C 2012/08/16 00:33:04 two spaces after the ; or after the // ?
Ted C 2012/08/16 00:44:08 seeing that: git grep "; // " --> 5 matches whil
Dan Beam 2012/08/16 00:47:16 the presubmit checks for \s{2,} only after {, but
Evan Stade 2012/08/16 03:02:29 Dan, I think you have that backwards.
Dan Beam 2012/08/16 03:30:34 Whoops, yeah, you're right.
153
154 int64 id;
155 bool is_partner;
156 if (args && !args->empty() && ParseNtpBookmarkId(args, &id, &is_partner))
157 QueryBookmarkFolder(id, is_partner);
158 else
159 QueryInitialBookmarks();
160 }
161
162 void BookmarksHandler::HandleDeleteBookmark(const ListValue* args) {
163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
164 int64 id;
165 bool is_partner;
166 if (args && !args->empty() && ParseNtpBookmarkId(args, &id, &is_partner)) {
167 DCHECK(!is_partner);
168 const BookmarkNode* node = bookmark_model_->GetNodeByID(id);
169 if (node && node->parent()) {
170 const BookmarkNode* parent_node = node->parent();
171 bookmark_model_->Remove(parent_node, parent_node->GetIndexOf(node));
172 }
173 }
174 }
175
176 std::string BookmarksHandler::GetBookmarkIdForNtp(const BookmarkNode* node) {
177 return (partner_bookmarks_shim_->IsPartnerBookmark(node) ? "p" : "") +
178 Int64ToString(node->id());
179 }
180
181 void BookmarksHandler::SetParentInBookmarksResult(const BookmarkNode& parent,
182 DictionaryValue* result) {
183 result->SetString(kParentIdParam, GetBookmarkIdForNtp(&parent));
184 }
185
186 void BookmarksHandler::PopulateBookmark(const BookmarkNode* node,
187 ListValue* result) {
188 if (!result)
189 return;
190
191 DictionaryValue* filler_value = new DictionaryValue();
192 filler_value->SetString("title", node->GetTitle());
193 // Mark reserved system nodes and partner bookmarks as uneditable
194 // (i.e. the bookmark bar along with the "Other Bookmarks" folder).
195 filler_value->SetBoolean("editable",
196 partner_bookmarks_shim_->IsBookmarkEditable(node));
197 if (node->is_url()) {
198 filler_value->SetBoolean("folder", false);
199 filler_value->SetString("url", node->url().spec());
200 } else {
201 filler_value->SetBoolean("folder", true);
202 }
203 filler_value->SetString("id", GetBookmarkIdForNtp(node));
204 filler_value->SetString("type", BookmarkTypeAsString(node->type()));
205 result->Append(filler_value);
206 }
207
208 void BookmarksHandler::PopulateBookmarksInFolder(
209 const BookmarkNode* folder,
210 DictionaryValue& result) {
211 ListValue bookmarks;
212
213 for (int i = 0; i < folder->child_count(); i++) {
214 const BookmarkNode* bookmark= folder->GetChild(i);
215 PopulateBookmark(bookmark, &bookmarks);
216 }
217
218 // Make sure we iterate over the partner's attach point
219 DCHECK(partner_bookmarks_shim_ != NULL);
220 if (partner_bookmarks_shim_->HasPartnerBookmarks() &&
221 folder == partner_bookmarks_shim_->get_attach_point()) {
222 PopulateBookmark(
223 partner_bookmarks_shim_->GetPartnerBookmarksRoot(), &bookmarks);
224 }
225
226 ListValue folder_hierarchy;
227 const BookmarkNode* parent = partner_bookmarks_shim_->GetParentOf(folder);
228
229 while (parent != NULL) {
230 DictionaryValue hierarchy_entry;
231 if (partner_bookmarks_shim_->IsRootNode(parent))
232 hierarchy_entry.SetBoolean("root", true);
233
234 hierarchy_entry.SetString("title", parent->GetTitle());
235 hierarchy_entry.SetString("id", GetBookmarkIdForNtp(parent));
236 folder_hierarchy.Append(&hierarchy_entry);
237 parent = partner_bookmarks_shim_->GetParentOf(parent);
238 }
239
240 result.SetString("title", folder->GetTitle());
241 result.SetString("id", GetBookmarkIdForNtp(folder));
242 result.SetBoolean("root", partner_bookmarks_shim_->IsRootNode(folder));
243 result.Set("bookmarks", &bookmarks);
244 result.Set("hierarchy", &folder_hierarchy);
245 }
246
247 void BookmarksHandler::QueryBookmarkFolder(const int64& folder_id,
248 bool is_partner_bookmark) {
249 DCHECK(partner_bookmarks_shim_ != NULL);
250 const BookmarkNode* bookmarks =
251 partner_bookmarks_shim_->GetNodeByID(folder_id, is_partner_bookmark);
252 if (bookmarks) {
253 DictionaryValue result;
254 PopulateBookmarksInFolder(bookmarks, result);
255 SendResult(result);
256 } else {
257 // If we receive an ID that no longer maps to a bookmark folder, just
258 // return the initial bookmark folder.
259 QueryInitialBookmarks();
260 }
261 }
262
263 void BookmarksHandler::QueryInitialBookmarks() {
264 DictionaryValue result;
265 DCHECK(partner_bookmarks_shim_ != NULL);
266 PopulateBookmarksInFolder(
267 // We have to go to the partner Root if it exists
268 partner_bookmarks_shim_->HasPartnerBookmarks() ?
269 partner_bookmarks_shim_->GetPartnerBookmarksRoot() :
270 bookmark_model_->mobile_node(),
271 result);
272 SendResult(result);
273 }
274
275 void BookmarksHandler::SendResult(const DictionaryValue& result) {
276 web_ui()->CallJavascriptFunction("ntp.bookmarks", result);
277 }
278
279 void BookmarksHandler::Loaded(BookmarkModel* model, bool ids_reassigned) {
280 BookmarkModelChanged();
281 }
282
283 void BookmarksHandler::PartnerShimLoaded(PartnerBookmarksShim* shim) {
284 BookmarkModelChanged();
285 }
286
287 void BookmarksHandler::ShimBeingDeleted(PartnerBookmarksShim* shim) {
288 partner_bookmarks_shim_ = NULL;
289 }
290
291 void BookmarksHandler::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
292 extensive_changes_ = true;
293 }
294
295 void BookmarksHandler::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
296 extensive_changes_ = false;
297 BookmarkModelChanged();
298 }
299
300 void BookmarksHandler::BookmarkNodeRemoved(BookmarkModel* model,
301 const BookmarkNode* parent,
302 int old_index,
303 const BookmarkNode* node) {
304 DictionaryValue result;
305 SetParentInBookmarksResult(*parent, &result);
306 result.SetString(kNodeIdParam, Int64ToString(node->id()));
307 NotifyModelChanged(result);
308 }
309
310 void BookmarksHandler::BookmarkNodeAdded(BookmarkModel* model,
311 const BookmarkNode* parent,
312 int index) {
313 DictionaryValue result;
314 SetParentInBookmarksResult(*parent, &result);
315 NotifyModelChanged(result);
316 }
317
318 void BookmarksHandler::BookmarkNodeChanged(BookmarkModel* model,
319 const BookmarkNode* node) {
320 DCHECK(partner_bookmarks_shim_);
321 DCHECK(!partner_bookmarks_shim_->IsPartnerBookmark(node));
322 DictionaryValue result;
323 SetParentInBookmarksResult(*node->parent(), &result);
324 result.SetString(kNodeIdParam, Int64ToString(node->id()));
325 NotifyModelChanged(result);
326 }
327
328 void BookmarksHandler::BookmarkModelChanged() {
329 if (bookmark_data_requested_ && !extensive_changes_)
330 web_ui()->CallJavascriptFunction("ntp.bookmarkChanged");
331 }
332
333 void BookmarksHandler::NotifyModelChanged(const DictionaryValue& status) {
334 if (bookmark_data_requested_ && !extensive_changes_)
335 web_ui()->CallJavascriptFunction("ntp.bookmarkChanged", status);
336 }
337
338 void BookmarksHandler::HandleCreateHomeScreenBookmarkShortcut(
339 const ListValue* args) {
340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
341 Profile* profile = Profile::FromBrowserContext(
342 web_ui()->GetWebContents()->GetBrowserContext());
343 if (!profile)
344 return;
345
346 int64 id;
347 bool is_partner;
348 if (args && !args->empty() && ParseNtpBookmarkId(args, &id, &is_partner)) {
349 DCHECK(partner_bookmarks_shim_ != NULL);
350 const BookmarkNode* node =
351 partner_bookmarks_shim_->GetNodeByID(id, is_partner);
352 if (!node)
353 return;
354
355 FaviconService* favicon_service = profile->GetFaviconService(
356 Profile::EXPLICIT_ACCESS);
357 FaviconService::Handle handle = favicon_service->GetFaviconForURL(
358 node->url(),
359 history::FAVICON | history::TOUCH_ICON,
360 &cancelable_consumer_,
361 base::Bind(&BookmarksHandler::OnShortcutFaviconDataAvailable,
362 base::Unretained(this)));
363 cancelable_consumer_.SetClientData(favicon_service, handle, node);
364 }
365 }
366
367 void BookmarksHandler::OnShortcutFaviconDataAvailable(
368 FaviconService::Handle handle,
369 history::FaviconData favicon) {
370 SkColor color = SK_ColorWHITE;
371 SkBitmap favicon_bitmap;
372 if (favicon.is_valid()) {
373 color = GetDominantColorForFavicon(favicon.image_data);
374 gfx::PNGCodec::Decode(favicon.image_data->front(),
375 favicon.image_data->size(),
376 &favicon_bitmap);
377 }
378
379 Profile* profile = Profile::FromBrowserContext(
380 web_ui()->GetWebContents()->GetBrowserContext());
381 const BookmarkNode* node = cancelable_consumer_.GetClientData(
382 profile->GetFaviconService(Profile::EXPLICIT_ACCESS), handle);
383
384 TabAndroid* tab = TabAndroid::FromWebContents(
385 web_ui()->GetWebContents());
386 if (tab) {
387 tab->AddShortcutToBookmark(node->url(), node->GetTitle(),
388 favicon_bitmap, SkColorGetR(color),
389 SkColorGetG(color), SkColorGetB(color));
390 }
391 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698