Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / android / bookmarks / bookmarks_bridge.cc
blob9406ddacad6e684a2a987931e6e8dac08054d14b
1 // Copyright 2013 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/bookmarks_bridge.h"
7 #include "base/android/jni_array.h"
8 #include "base/android/jni_string.h"
9 #include "base/containers/stack_container.h"
10 #include "base/i18n/string_compare.h"
11 #include "base/prefs/pref_service.h"
12 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
13 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
14 #include "chrome/browser/bookmarks/managed_bookmark_service_factory.h"
15 #include "chrome/browser/profiles/incognito_helpers.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/profiles/profile_android.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
20 #include "chrome/common/pref_names.h"
21 #include "components/bookmarks/browser/bookmark_match.h"
22 #include "components/bookmarks/browser/bookmark_model.h"
23 #include "components/bookmarks/browser/bookmark_utils.h"
24 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
25 #include "components/bookmarks/common/android/bookmark_type.h"
26 #include "components/bookmarks/managed/managed_bookmark_service.h"
27 #include "components/query_parser/query_parser.h"
28 #include "components/signin/core/browser/signin_manager.h"
29 #include "components/undo/bookmark_undo_service.h"
30 #include "components/undo/undo_manager.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "grit/components_strings.h"
33 #include "jni/BookmarksBridge_jni.h"
34 #include "ui/base/l10n/l10n_util.h"
36 using base::android::AttachCurrentThread;
37 using base::android::ConvertUTF8ToJavaString;
38 using base::android::ConvertUTF16ToJavaString;
39 using base::android::ScopedJavaLocalRef;
40 using base::android::ScopedJavaGlobalRef;
41 using base::android::ToJavaIntArray;
42 using bookmarks::android::JavaBookmarkIdCreateBookmarkId;
43 using bookmarks::android::JavaBookmarkIdGetId;
44 using bookmarks::android::JavaBookmarkIdGetType;
45 using bookmarks::BookmarkModel;
46 using bookmarks::BookmarkNode;
47 using bookmarks::BookmarkPermanentNode;
48 using bookmarks::BookmarkType;
49 using content::BrowserThread;
51 namespace {
53 class BookmarkNodeCreationTimeCompareFunctor {
54 public:
55 bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
56 return lhs->date_added().ToJavaTime() > rhs->date_added().ToJavaTime();
60 class BookmarkTitleComparer {
61 public:
62 explicit BookmarkTitleComparer(BookmarksBridge* bookmarks_bridge,
63 const icu::Collator* collator)
64 : bookmarks_bridge_(bookmarks_bridge),
65 collator_(collator) {}
67 bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
68 if (collator_) {
69 return base::i18n::CompareString16WithCollator(
70 *collator_, bookmarks_bridge_->GetTitle(lhs),
71 bookmarks_bridge_->GetTitle(rhs)) == UCOL_LESS;
72 } else {
73 return lhs->GetTitle() < rhs->GetTitle();
77 private:
78 BookmarksBridge* bookmarks_bridge_; // weak
79 const icu::Collator* collator_;
82 scoped_ptr<icu::Collator> GetICUCollator() {
83 UErrorCode error = U_ZERO_ERROR;
84 scoped_ptr<icu::Collator> collator_;
85 collator_.reset(icu::Collator::createInstance(error));
86 if (U_FAILURE(error))
87 collator_.reset(NULL);
89 return collator_.Pass();
92 } // namespace
94 BookmarksBridge::BookmarksBridge(JNIEnv* env, jobject obj, jobject j_profile)
95 : weak_java_ref_(env, obj),
96 bookmark_model_(NULL),
97 managed_bookmark_service_(NULL),
98 partner_bookmarks_shim_(NULL) {
99 DCHECK_CURRENTLY_ON(BrowserThread::UI);
100 profile_ = ProfileAndroid::FromProfileAndroid(j_profile);
101 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile_);
102 managed_bookmark_service_ =
103 ManagedBookmarkServiceFactory::GetForProfile(profile_);
105 // Registers the notifications we are interested.
106 bookmark_model_->AddObserver(this);
108 // Create the partner Bookmarks shim as early as possible (but don't attach).
109 partner_bookmarks_shim_ = PartnerBookmarksShim::BuildForBrowserContext(
110 chrome::GetBrowserContextRedirectedInIncognito(profile_));
111 partner_bookmarks_shim_->AddObserver(this);
113 NotifyIfDoneLoading();
115 // Since a sync or import could have started before this class is
116 // initialized, we need to make sure that our initial state is
117 // up to date.
118 if (bookmark_model_->IsDoingExtensiveChanges())
119 ExtensiveBookmarkChangesBeginning(bookmark_model_);
122 BookmarksBridge::~BookmarksBridge() {
123 bookmark_model_->RemoveObserver(this);
124 if (partner_bookmarks_shim_)
125 partner_bookmarks_shim_->RemoveObserver(this);
128 void BookmarksBridge::Destroy(JNIEnv*, jobject) {
129 delete this;
132 // static
133 bool BookmarksBridge::RegisterBookmarksBridge(JNIEnv* env) {
134 return RegisterNativesImpl(env);
137 static jlong Init(JNIEnv* env, jobject obj, jobject j_profile) {
138 BookmarksBridge* delegate = new BookmarksBridge(env, obj, j_profile);
139 return reinterpret_cast<intptr_t>(delegate);
142 static jboolean IsEnhancedBookmarksFeatureEnabled(JNIEnv* env,
143 jclass clazz,
144 jobject j_profile) {
145 return IsEnhancedBookmarksEnabled();
148 jboolean BookmarksBridge::IsEditBookmarksEnabled(JNIEnv* env, jobject obj) {
149 return IsEditBookmarksEnabled();
152 void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv* env,
153 jobject obj) {
154 if (partner_bookmarks_shim_->IsLoaded())
155 return;
156 partner_bookmarks_shim_->SetPartnerBookmarksRoot(
157 new BookmarkPermanentNode(0));
158 DCHECK(partner_bookmarks_shim_->IsLoaded());
161 ScopedJavaLocalRef<jobject> BookmarksBridge::GetBookmarkByID(JNIEnv* env,
162 jobject obj,
163 jlong id,
164 jint type) {
165 DCHECK(IsLoaded());
166 const BookmarkNode* node = GetNodeByID(id, type);
167 return node ? CreateJavaBookmark(node) : ScopedJavaLocalRef<jobject>();
170 bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv* env, jobject obj) {
171 return bookmark_model_->IsDoingExtensiveChanges();
174 void BookmarksBridge::GetPermanentNodeIDs(JNIEnv* env,
175 jobject obj,
176 jobject j_result_obj) {
177 // TODO(kkimlabs): Remove this function.
178 DCHECK(IsLoaded());
180 base::StackVector<const BookmarkNode*, 8> permanent_nodes;
182 // Save all the permanent nodes.
183 const BookmarkNode* root_node = bookmark_model_->root_node();
184 permanent_nodes->push_back(root_node);
185 for (int i = 0; i < root_node->child_count(); ++i) {
186 permanent_nodes->push_back(root_node->GetChild(i));
188 permanent_nodes->push_back(
189 partner_bookmarks_shim_->GetPartnerBookmarksRoot());
191 // Write the permanent nodes to |j_result_obj|.
192 for (base::StackVector<const BookmarkNode*, 8>::ContainerType::const_iterator
193 it = permanent_nodes->begin();
194 it != permanent_nodes->end();
195 ++it) {
196 if (*it != NULL) {
197 Java_BookmarksBridge_addToBookmarkIdList(
198 env, j_result_obj, (*it)->id(), GetBookmarkType(*it));
203 void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv* env,
204 jobject obj,
205 jobject j_result_obj) {
206 Java_BookmarksBridge_addToBookmarkIdList(
207 env, j_result_obj, bookmark_model_->root_node()->id(),
208 GetBookmarkType(bookmark_model_->root_node()));
211 void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv* env,
212 jobject obj,
213 jboolean get_special,
214 jboolean get_normal,
215 jobject j_result_obj) {
216 DCHECK(IsLoaded());
217 std::vector<const BookmarkNode*> top_level_folders;
219 if (get_special) {
220 if (managed_bookmark_service_->managed_node() &&
221 managed_bookmark_service_->managed_node()->child_count() > 0) {
222 top_level_folders.push_back(managed_bookmark_service_->managed_node());
224 if (managed_bookmark_service_->supervised_node() &&
225 managed_bookmark_service_->supervised_node()->child_count() > 0) {
226 top_level_folders.push_back(managed_bookmark_service_->supervised_node());
228 if (partner_bookmarks_shim_->HasPartnerBookmarks()
229 && IsReachable(partner_bookmarks_shim_->GetPartnerBookmarksRoot())) {
230 top_level_folders.push_back(
231 partner_bookmarks_shim_->GetPartnerBookmarksRoot());
234 std::size_t special_count = top_level_folders.size();
236 if (get_normal) {
237 DCHECK_EQ(bookmark_model_->root_node()->child_count(), 5);
239 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
240 for (int i = 0; i < mobile_node->child_count(); ++i) {
241 const BookmarkNode* node = mobile_node->GetChild(i);
242 if (node->is_folder()) {
243 top_level_folders.push_back(node);
247 const BookmarkNode* bookmark_bar_node =
248 bookmark_model_->bookmark_bar_node();
249 for (int i = 0; i < bookmark_bar_node->child_count(); ++i) {
250 const BookmarkNode* node = bookmark_bar_node->GetChild(i);
251 if (node->is_folder()) {
252 top_level_folders.push_back(node);
256 const BookmarkNode* other_node = bookmark_model_->other_node();
257 for (int i = 0; i < other_node->child_count(); ++i) {
258 const BookmarkNode* node = other_node->GetChild(i);
259 if (node->is_folder()) {
260 top_level_folders.push_back(node);
264 scoped_ptr<icu::Collator> collator = GetICUCollator();
265 std::stable_sort(top_level_folders.begin() + special_count,
266 top_level_folders.end(),
267 BookmarkTitleComparer(this, collator.get()));
270 for (std::vector<const BookmarkNode*>::const_iterator it =
271 top_level_folders.begin(); it != top_level_folders.end(); ++it) {
272 Java_BookmarksBridge_addToBookmarkIdList(env,
273 j_result_obj,
274 (*it)->id(),
275 GetBookmarkType(*it));
279 void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv* env,
280 jobject obj,
281 jobject j_folders_obj,
282 jobject j_depths_obj) {
283 DCHECK(IsLoaded());
285 scoped_ptr<icu::Collator> collator = GetICUCollator();
287 // Vector to temporarily contain all child bookmarks at same level for sorting
288 std::vector<const BookmarkNode*> bookmarkList;
290 // Stack for Depth-First Search of bookmark model. It stores nodes and their
291 // heights.
292 std::stack<std::pair<const BookmarkNode*, int> > stk;
294 bookmarkList.push_back(bookmark_model_->mobile_node());
295 bookmarkList.push_back(bookmark_model_->bookmark_bar_node());
296 bookmarkList.push_back(bookmark_model_->other_node());
298 // Push all sorted top folders in stack and give them depth of 0.
299 // Note the order to push folders to stack should be opposite to the order in
300 // output.
301 for (std::vector<const BookmarkNode*>::reverse_iterator it =
302 bookmarkList.rbegin();
303 it != bookmarkList.rend();
304 ++it) {
305 stk.push(std::make_pair(*it, 0));
308 while (!stk.empty()) {
309 const BookmarkNode* node = stk.top().first;
310 int depth = stk.top().second;
311 stk.pop();
312 Java_BookmarksBridge_addToBookmarkIdListWithDepth(env,
313 j_folders_obj,
314 node->id(),
315 GetBookmarkType(node),
316 j_depths_obj,
317 depth);
318 bookmarkList.clear();
319 for (int i = 0; i < node->child_count(); ++i) {
320 const BookmarkNode* child = node->GetChild(i);
321 if (child->is_folder() &&
322 managed_bookmark_service_->CanBeEditedByUser(child)) {
323 bookmarkList.push_back(node->GetChild(i));
326 std::stable_sort(bookmarkList.begin(),
327 bookmarkList.end(),
328 BookmarkTitleComparer(this, collator.get()));
329 for (std::vector<const BookmarkNode*>::reverse_iterator it =
330 bookmarkList.rbegin();
331 it != bookmarkList.rend();
332 ++it) {
333 stk.push(std::make_pair(*it, depth + 1));
338 ScopedJavaLocalRef<jobject> BookmarksBridge::GetRootFolderId(JNIEnv* env,
339 jobject obj) {
340 const BookmarkNode* root_node = bookmark_model_->root_node();
341 ScopedJavaLocalRef<jobject> folder_id_obj =
342 JavaBookmarkIdCreateBookmarkId(
343 env, root_node->id(), GetBookmarkType(root_node));
344 return folder_id_obj;
347 ScopedJavaLocalRef<jobject> BookmarksBridge::GetMobileFolderId(JNIEnv* env,
348 jobject obj) {
349 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
350 ScopedJavaLocalRef<jobject> folder_id_obj =
351 JavaBookmarkIdCreateBookmarkId(
352 env, mobile_node->id(), GetBookmarkType(mobile_node));
353 return folder_id_obj;
356 ScopedJavaLocalRef<jobject> BookmarksBridge::GetOtherFolderId(JNIEnv* env,
357 jobject obj) {
358 const BookmarkNode* other_node = bookmark_model_->other_node();
359 ScopedJavaLocalRef<jobject> folder_id_obj =
360 JavaBookmarkIdCreateBookmarkId(
361 env, other_node->id(), GetBookmarkType(other_node));
362 return folder_id_obj;
365 ScopedJavaLocalRef<jobject> BookmarksBridge::GetDesktopFolderId(JNIEnv* env,
366 jobject obj) {
367 const BookmarkNode* desktop_node = bookmark_model_->bookmark_bar_node();
368 ScopedJavaLocalRef<jobject> folder_id_obj =
369 JavaBookmarkIdCreateBookmarkId(
370 env, desktop_node->id(), GetBookmarkType(desktop_node));
371 return folder_id_obj;
374 void BookmarksBridge::GetChildIDs(JNIEnv* env,
375 jobject obj,
376 jlong id,
377 jint type,
378 jboolean get_folders,
379 jboolean get_bookmarks,
380 jobject j_result_obj) {
381 DCHECK(IsLoaded());
383 const BookmarkNode* parent = GetNodeByID(id, type);
384 if (!parent->is_folder() || !IsReachable(parent))
385 return;
387 // Get the folder contents
388 for (int i = 0; i < parent->child_count(); ++i) {
389 const BookmarkNode* child = parent->GetChild(i);
390 if (!IsFolderAvailable(child) || !IsReachable(child))
391 continue;
393 if ((child->is_folder() && get_folders) ||
394 (!child->is_folder() && get_bookmarks)) {
395 Java_BookmarksBridge_addToBookmarkIdList(
396 env, j_result_obj, child->id(), GetBookmarkType(child));
400 // Partner bookmark root node is under mobile node.
401 if (parent == bookmark_model_->mobile_node() && get_folders &&
402 partner_bookmarks_shim_->HasPartnerBookmarks() &&
403 IsReachable(partner_bookmarks_shim_->GetPartnerBookmarksRoot())) {
404 Java_BookmarksBridge_addToBookmarkIdList(
405 env,
406 j_result_obj,
407 partner_bookmarks_shim_->GetPartnerBookmarksRoot()->id(),
408 BookmarkType::BOOKMARK_TYPE_PARTNER);
412 ScopedJavaLocalRef<jobject> BookmarksBridge::GetChildAt(JNIEnv* env,
413 jobject obj,
414 jlong id,
415 jint type,
416 jint index) {
417 DCHECK(IsLoaded());
419 const BookmarkNode* parent = GetNodeByID(id, type);
420 DCHECK(parent);
421 const BookmarkNode* child = parent->GetChild(index);
422 return JavaBookmarkIdCreateBookmarkId(
423 env, child->id(), GetBookmarkType(child));
426 void BookmarksBridge::GetAllBookmarkIDsOrderedByCreationDate(
427 JNIEnv* env,
428 jobject obj,
429 jobject j_result_obj) {
430 DCHECK(IsLoaded());
431 std::list<const BookmarkNode*> folders;
432 std::vector<const BookmarkNode*> result;
433 folders.push_back(bookmark_model_->root_node());
435 for (std::list<const BookmarkNode*>::iterator folder_iter = folders.begin();
436 folder_iter != folders.end(); ++folder_iter) {
437 if (*folder_iter == NULL)
438 continue;
440 std::list<const BookmarkNode*>::iterator insert_iter = folder_iter;
441 ++insert_iter;
443 for (int i = 0; i < (*folder_iter)->child_count(); ++i) {
444 const BookmarkNode* child = (*folder_iter)->GetChild(i);
445 if (!IsReachable(child) ||
446 bookmarks::IsDescendantOf(
447 child, managed_bookmark_service_->managed_node()) ||
448 bookmarks::IsDescendantOf(
449 child, managed_bookmark_service_->supervised_node())) {
450 continue;
453 if (child->is_folder()) {
454 insert_iter = folders.insert(insert_iter, child);
455 } else {
456 result.push_back(child);
461 std::sort(
462 result.begin(), result.end(), BookmarkNodeCreationTimeCompareFunctor());
464 for (std::vector<const BookmarkNode*>::const_iterator iter = result.begin();
465 iter != result.end();
466 ++iter) {
467 const BookmarkNode* bookmark = *iter;
468 Java_BookmarksBridge_addToBookmarkIdList(
469 env, j_result_obj, bookmark->id(), GetBookmarkType(bookmark));
473 void BookmarksBridge::SetBookmarkTitle(JNIEnv* env,
474 jobject obj,
475 jlong id,
476 jint type,
477 jstring j_title) {
478 DCHECK(IsLoaded());
479 const BookmarkNode* bookmark = GetNodeByID(id, type);
480 const base::string16 title =
481 base::android::ConvertJavaStringToUTF16(env, j_title);
483 if (partner_bookmarks_shim_->IsPartnerBookmark(bookmark)) {
484 partner_bookmarks_shim_->RenameBookmark(bookmark, title);
485 } else {
486 bookmark_model_->SetTitle(bookmark, title);
490 void BookmarksBridge::SetBookmarkUrl(JNIEnv* env,
491 jobject obj,
492 jlong id,
493 jint type,
494 jstring url) {
495 DCHECK(IsLoaded());
496 bookmark_model_->SetURL(
497 GetNodeByID(id, type),
498 GURL(base::android::ConvertJavaStringToUTF16(env, url)));
501 bool BookmarksBridge::DoesBookmarkExist(JNIEnv* env,
502 jobject obj,
503 jlong id,
504 jint type) {
505 DCHECK(IsLoaded());
506 return GetNodeByID(id, type);
509 void BookmarksBridge::GetBookmarksForFolder(JNIEnv* env,
510 jobject obj,
511 jobject j_folder_id_obj,
512 jobject j_callback_obj,
513 jobject j_result_obj) {
514 DCHECK(IsLoaded());
515 long folder_id = JavaBookmarkIdGetId(env, j_folder_id_obj);
516 int type = JavaBookmarkIdGetType(env, j_folder_id_obj);
517 const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
519 if (!folder->is_folder() || !IsReachable(folder))
520 return;
522 // Recreate the java bookmarkId object due to fallback.
523 ScopedJavaLocalRef<jobject> folder_id_obj =
524 JavaBookmarkIdCreateBookmarkId(
525 env, folder->id(), GetBookmarkType(folder));
526 j_folder_id_obj = folder_id_obj.obj();
528 // Get the folder contents.
529 for (int i = 0; i < folder->child_count(); ++i) {
530 const BookmarkNode* node = folder->GetChild(i);
531 if (!IsFolderAvailable(node))
532 continue;
533 ExtractBookmarkNodeInformation(node, j_result_obj);
536 if (folder == bookmark_model_->mobile_node() &&
537 partner_bookmarks_shim_->HasPartnerBookmarks()) {
538 ExtractBookmarkNodeInformation(
539 partner_bookmarks_shim_->GetPartnerBookmarksRoot(),
540 j_result_obj);
543 if (j_callback_obj) {
544 Java_BookmarksCallback_onBookmarksAvailable(
545 env, j_callback_obj, j_folder_id_obj, j_result_obj);
549 jboolean BookmarksBridge::IsFolderVisible(JNIEnv* env,
550 jobject obj,
551 jlong id,
552 jint type) {
553 if (type == BookmarkType::BOOKMARK_TYPE_NORMAL) {
554 const BookmarkNode* node = bookmarks::GetBookmarkNodeByID(
555 bookmark_model_, static_cast<int64>(id));
556 return node->IsVisible();
557 } else if (type == BookmarkType::BOOKMARK_TYPE_PARTNER) {
558 const BookmarkNode* node = partner_bookmarks_shim_->GetNodeByID(
559 static_cast<long>(id));
560 return partner_bookmarks_shim_->IsReachable(node);
563 NOTREACHED();
564 return false;
567 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv* env,
568 jobject obj,
569 jobject j_folder_id_obj,
570 jobject j_callback_obj,
571 jobject j_result_obj) {
572 DCHECK(IsLoaded());
573 long folder_id = JavaBookmarkIdGetId(env, j_folder_id_obj);
574 int type = JavaBookmarkIdGetType(env, j_folder_id_obj);
575 const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
577 if (!folder->is_folder() || !IsReachable(folder))
578 return;
580 // Recreate the java bookmarkId object due to fallback.
581 ScopedJavaLocalRef<jobject> folder_id_obj =
582 JavaBookmarkIdCreateBookmarkId(
583 env, folder->id(), GetBookmarkType(folder));
584 j_folder_id_obj = folder_id_obj.obj();
586 // Get the folder hierarchy.
587 const BookmarkNode* node = folder;
588 while (node) {
589 ExtractBookmarkNodeInformation(node, j_result_obj);
590 node = GetParentNode(node);
593 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
594 env, j_callback_obj, j_folder_id_obj, j_result_obj);
597 ScopedJavaLocalRef<jobject> BookmarksBridge::AddFolder(JNIEnv* env,
598 jobject obj,
599 jobject j_parent_id_obj,
600 jint index,
601 jstring j_title) {
602 DCHECK(IsLoaded());
603 long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
604 int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
605 const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
607 const BookmarkNode* new_node = bookmark_model_->AddFolder(
608 parent, index, base::android::ConvertJavaStringToUTF16(env, j_title));
609 if (!new_node) {
610 NOTREACHED();
611 return ScopedJavaLocalRef<jobject>();
613 ScopedJavaLocalRef<jobject> new_java_obj =
614 JavaBookmarkIdCreateBookmarkId(
615 env, new_node->id(), GetBookmarkType(new_node));
616 return new_java_obj;
619 void BookmarksBridge::DeleteBookmark(JNIEnv* env,
620 jobject obj,
621 jobject j_bookmark_id_obj) {
622 DCHECK_CURRENTLY_ON(BrowserThread::UI);
623 DCHECK(IsLoaded());
625 long bookmark_id = JavaBookmarkIdGetId(env, j_bookmark_id_obj);
626 int type = JavaBookmarkIdGetType(env, j_bookmark_id_obj);
627 const BookmarkNode* node = GetNodeByID(bookmark_id, type);
628 if (!IsEditable(node)) {
629 NOTREACHED();
630 return;
633 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
634 partner_bookmarks_shim_->RemoveBookmark(node);
635 else
636 bookmark_model_->Remove(node);
639 void BookmarksBridge::MoveBookmark(JNIEnv* env,
640 jobject obj,
641 jobject j_bookmark_id_obj,
642 jobject j_parent_id_obj,
643 jint index) {
644 DCHECK_CURRENTLY_ON(BrowserThread::UI);
645 DCHECK(IsLoaded());
647 long bookmark_id = JavaBookmarkIdGetId(env, j_bookmark_id_obj);
648 int type = JavaBookmarkIdGetType(env, j_bookmark_id_obj);
649 const BookmarkNode* node = GetNodeByID(bookmark_id, type);
650 if (!IsEditable(node)) {
651 NOTREACHED();
652 return;
654 bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
655 type = JavaBookmarkIdGetType(env, j_parent_id_obj);
656 const BookmarkNode* new_parent_node = GetNodeByID(bookmark_id, type);
657 bookmark_model_->Move(node, new_parent_node, index);
660 ScopedJavaLocalRef<jobject> BookmarksBridge::AddBookmark(
661 JNIEnv* env,
662 jobject obj,
663 jobject j_parent_id_obj,
664 jint index,
665 jstring j_title,
666 jstring j_url) {
667 DCHECK(IsLoaded());
668 long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
669 int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
670 const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
672 const BookmarkNode* new_node = bookmark_model_->AddURL(
673 parent,
674 index,
675 base::android::ConvertJavaStringToUTF16(env, j_title),
676 GURL(base::android::ConvertJavaStringToUTF16(env, j_url)));
677 if (!new_node) {
678 NOTREACHED();
679 return ScopedJavaLocalRef<jobject>();
681 ScopedJavaLocalRef<jobject> new_java_obj =
682 JavaBookmarkIdCreateBookmarkId(
683 env, new_node->id(), GetBookmarkType(new_node));
684 return new_java_obj;
687 void BookmarksBridge::Undo(JNIEnv* env, jobject obj) {
688 DCHECK_CURRENTLY_ON(BrowserThread::UI);
689 DCHECK(IsLoaded());
690 BookmarkUndoService* undo_service =
691 BookmarkUndoServiceFactory::GetForProfile(profile_);
692 UndoManager* undo_manager = undo_service->undo_manager();
693 undo_manager->Undo();
696 void BookmarksBridge::StartGroupingUndos(JNIEnv* env, jobject obj) {
697 DCHECK_CURRENTLY_ON(BrowserThread::UI);
698 DCHECK(IsLoaded());
699 DCHECK(!grouped_bookmark_actions_.get()); // shouldn't have started already
700 grouped_bookmark_actions_.reset(
701 new bookmarks::ScopedGroupBookmarkActions(bookmark_model_));
704 void BookmarksBridge::EndGroupingUndos(JNIEnv* env, jobject obj) {
705 DCHECK_CURRENTLY_ON(BrowserThread::UI);
706 DCHECK(IsLoaded());
707 DCHECK(grouped_bookmark_actions_.get()); // should only call after start
708 grouped_bookmark_actions_.reset();
711 base::string16 BookmarksBridge::GetTitle(const BookmarkNode* node) const {
712 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
713 return partner_bookmarks_shim_->GetTitle(node);
715 if (node == bookmark_model_->bookmark_bar_node()
716 && IsEnhancedBookmarksEnabled()) {
717 return l10n_util::GetStringUTF16(IDS_ENHANCED_BOOKMARK_BAR_FOLDER_NAME);
720 return node->GetTitle();
723 ScopedJavaLocalRef<jobject> BookmarksBridge::CreateJavaBookmark(
724 const BookmarkNode* node) {
725 JNIEnv* env = AttachCurrentThread();
727 const BookmarkNode* parent = GetParentNode(node);
728 int64 parent_id = parent ? parent->id() : -1;
730 std::string url;
731 if (node->is_url())
732 url = node->url().spec();
734 return Java_BookmarksBridge_createBookmarkItem(
735 env,
736 node->id(),
737 GetBookmarkType(node),
738 ConvertUTF16ToJavaString(env, GetTitle(node)).obj(),
739 ConvertUTF8ToJavaString(env, url).obj(),
740 node->is_folder(),
741 parent_id,
742 GetBookmarkType(parent),
743 IsEditable(node),
744 IsManaged(node));
747 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode* node,
748 jobject j_result_obj) {
749 JNIEnv* env = AttachCurrentThread();
750 if (!IsReachable(node))
751 return;
752 Java_BookmarksBridge_addToList(
753 env, j_result_obj, CreateJavaBookmark(node).obj());
756 const BookmarkNode* BookmarksBridge::GetNodeByID(long node_id, int type) {
757 const BookmarkNode* node;
758 if (type == BookmarkType::BOOKMARK_TYPE_PARTNER) {
759 node = partner_bookmarks_shim_->GetNodeByID(
760 static_cast<int64>(node_id));
761 } else {
762 node = bookmarks::GetBookmarkNodeByID(bookmark_model_,
763 static_cast<int64>(node_id));
765 return node;
768 const BookmarkNode* BookmarksBridge::GetFolderWithFallback(long folder_id,
769 int type) {
770 const BookmarkNode* folder = GetNodeByID(folder_id, type);
771 if (!folder || folder->type() == BookmarkNode::URL ||
772 !IsFolderAvailable(folder)) {
773 if (!managed_bookmark_service_->managed_node()->empty())
774 folder = managed_bookmark_service_->managed_node();
775 else
776 folder = bookmark_model_->mobile_node();
778 return folder;
781 bool BookmarksBridge::IsEditBookmarksEnabled() const {
782 return profile_->GetPrefs()->GetBoolean(
783 bookmarks::prefs::kEditBookmarksEnabled);
786 bool BookmarksBridge::IsEditable(const BookmarkNode* node) const {
787 if (!node || (node->type() != BookmarkNode::FOLDER &&
788 node->type() != BookmarkNode::URL)) {
789 return false;
791 if (!IsEditBookmarksEnabled())
792 return false;
793 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
794 return partner_bookmarks_shim_->IsEditable(node);
795 return managed_bookmark_service_->CanBeEditedByUser(node);
798 bool BookmarksBridge::IsManaged(const BookmarkNode* node) const {
799 return bookmarks::IsDescendantOf(node,
800 managed_bookmark_service_->managed_node());
803 const BookmarkNode* BookmarksBridge::GetParentNode(const BookmarkNode* node) {
804 DCHECK(IsLoaded());
805 if (node == partner_bookmarks_shim_->GetPartnerBookmarksRoot()) {
806 return bookmark_model_->mobile_node();
807 } else {
808 return node->parent();
812 int BookmarksBridge::GetBookmarkType(const BookmarkNode* node) {
813 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
814 return BookmarkType::BOOKMARK_TYPE_PARTNER;
815 else
816 return BookmarkType::BOOKMARK_TYPE_NORMAL;
819 bool BookmarksBridge::IsReachable(const BookmarkNode* node) const {
820 if (!partner_bookmarks_shim_->IsPartnerBookmark(node))
821 return true;
822 return partner_bookmarks_shim_->IsReachable(node);
825 bool BookmarksBridge::IsLoaded() const {
826 return (bookmark_model_->loaded() && partner_bookmarks_shim_->IsLoaded());
829 bool BookmarksBridge::IsFolderAvailable(
830 const BookmarkNode* folder) const {
831 // The managed bookmarks folder is not shown if there are no bookmarks
832 // configured via policy.
833 if (folder == managed_bookmark_service_->managed_node() && folder->empty())
834 return false;
835 // Similarly, the supervised bookmarks folder is not shown if there are no
836 // bookmarks configured by the custodian.
837 if (folder == managed_bookmark_service_->supervised_node() && folder->empty())
838 return false;
840 SigninManager* signin = SigninManagerFactory::GetForProfile(
841 profile_->GetOriginalProfile());
842 return (folder->type() != BookmarkNode::BOOKMARK_BAR &&
843 folder->type() != BookmarkNode::OTHER_NODE) ||
844 (signin && signin->IsAuthenticated());
847 void BookmarksBridge::NotifyIfDoneLoading() {
848 if (!IsLoaded())
849 return;
850 JNIEnv* env = AttachCurrentThread();
851 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
852 if (obj.is_null())
853 return;
854 Java_BookmarksBridge_bookmarkModelLoaded(env, obj.obj());
857 // ------------- Observer-related methods ------------- //
859 void BookmarksBridge::BookmarkModelChanged() {
860 if (!IsLoaded())
861 return;
863 // Called when there are changes to the bookmark model. It is most
864 // likely changes to the partner bookmarks.
865 JNIEnv* env = AttachCurrentThread();
866 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
867 if (obj.is_null())
868 return;
869 Java_BookmarksBridge_bookmarkModelChanged(env, obj.obj());
872 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel* model,
873 bool ids_reassigned) {
874 NotifyIfDoneLoading();
877 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
878 if (!IsLoaded())
879 return;
881 JNIEnv* env = AttachCurrentThread();
882 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
883 if (obj.is_null())
884 return;
885 Java_BookmarksBridge_bookmarkModelDeleted(env, obj.obj());
888 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel* model,
889 const BookmarkNode* old_parent,
890 int old_index,
891 const BookmarkNode* new_parent,
892 int new_index) {
893 if (!IsLoaded())
894 return;
896 JNIEnv* env = AttachCurrentThread();
897 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
898 if (obj.is_null())
899 return;
900 Java_BookmarksBridge_bookmarkNodeMoved(
901 env,
902 obj.obj(),
903 CreateJavaBookmark(old_parent).obj(),
904 old_index,
905 CreateJavaBookmark(new_parent).obj(),
906 new_index);
909 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel* model,
910 const BookmarkNode* parent,
911 int index) {
912 if (!IsLoaded())
913 return;
915 JNIEnv* env = AttachCurrentThread();
916 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
917 if (obj.is_null())
918 return;
919 Java_BookmarksBridge_bookmarkNodeAdded(
920 env,
921 obj.obj(),
922 CreateJavaBookmark(parent).obj(),
923 index);
926 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel* model,
927 const BookmarkNode* parent,
928 int old_index,
929 const BookmarkNode* node,
930 const std::set<GURL>& removed_urls) {
931 if (!IsLoaded())
932 return;
934 JNIEnv* env = AttachCurrentThread();
935 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
936 if (obj.is_null())
937 return;
938 Java_BookmarksBridge_bookmarkNodeRemoved(
939 env,
940 obj.obj(),
941 CreateJavaBookmark(parent).obj(),
942 old_index,
943 CreateJavaBookmark(node).obj());
946 void BookmarksBridge::BookmarkAllUserNodesRemoved(
947 BookmarkModel* model,
948 const std::set<GURL>& removed_urls) {
949 if (!IsLoaded())
950 return;
952 JNIEnv* env = AttachCurrentThread();
953 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
954 if (obj.is_null())
955 return;
956 Java_BookmarksBridge_bookmarkAllUserNodesRemoved(env, obj.obj());
959 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel* model,
960 const BookmarkNode* node) {
961 if (!IsLoaded())
962 return;
964 JNIEnv* env = AttachCurrentThread();
965 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
966 if (obj.is_null())
967 return;
968 Java_BookmarksBridge_bookmarkNodeChanged(
969 env,
970 obj.obj(),
971 CreateJavaBookmark(node).obj());
974 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel* model,
975 const BookmarkNode* node) {
976 if (!IsLoaded())
977 return;
979 JNIEnv* env = AttachCurrentThread();
980 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
981 if (obj.is_null())
982 return;
983 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
984 env,
985 obj.obj(),
986 CreateJavaBookmark(node).obj());
989 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
990 if (!IsLoaded())
991 return;
993 JNIEnv* env = AttachCurrentThread();
994 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
995 if (obj.is_null())
996 return;
997 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env, obj.obj());
1000 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
1001 if (!IsLoaded())
1002 return;
1004 JNIEnv* env = AttachCurrentThread();
1005 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
1006 if (obj.is_null())
1007 return;
1008 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env, obj.obj());
1011 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim* shim) {
1012 if (!IsLoaded())
1013 return;
1015 BookmarkModelChanged();
1018 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim* shim) {
1019 NotifyIfDoneLoading();
1022 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim* shim) {
1023 partner_bookmarks_shim_ = NULL;