Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / android / bookmarks / bookmarks_bridge.cc
blobeee1264402ec4bd1b62994290d757100c9bf3939
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_string.h"
8 #include "base/containers/stack_container.h"
9 #include "base/i18n/string_compare.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
12 #include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
13 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
14 #include "chrome/browser/profiles/incognito_helpers.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_android.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/undo/bookmark_undo_service.h"
20 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
21 #include "chrome/browser/undo/undo_manager.h"
22 #include "chrome/common/pref_names.h"
23 #include "components/bookmarks/browser/bookmark_model.h"
24 #include "components/bookmarks/browser/bookmark_utils.h"
25 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
26 #include "components/bookmarks/common/android/bookmark_type.h"
27 #include "components/signin/core/browser/signin_manager.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "jni/BookmarksBridge_jni.h"
31 using base::android::AttachCurrentThread;
32 using base::android::ConvertUTF8ToJavaString;
33 using base::android::ConvertUTF16ToJavaString;
34 using base::android::ScopedJavaLocalRef;
35 using base::android::ScopedJavaGlobalRef;
36 using bookmarks::android::JavaBookmarkIdGetId;
37 using bookmarks::android::JavaBookmarkIdGetType;
38 using bookmarks::BookmarkType;
39 using content::BrowserThread;
41 namespace {
43 class BookmarkNodeCreationTimeCompareFunctor {
44 public:
45 bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
46 return lhs->date_added().ToJavaTime() > rhs->date_added().ToJavaTime();
50 class BookmarkTitleComparer {
51 public:
52 explicit BookmarkTitleComparer(const icu::Collator* collator)
53 : collator_(collator) {}
55 bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
56 if (collator_) {
57 return base::i18n::CompareString16WithCollator(
58 collator_, lhs->GetTitle(), rhs->GetTitle()) == UCOL_LESS;
59 } else {
60 return lhs->GetTitle() < rhs->GetTitle();
64 private:
65 const icu::Collator* collator_;
68 scoped_ptr<icu::Collator> GetICUCollator() {
69 UErrorCode error = U_ZERO_ERROR;
70 scoped_ptr<icu::Collator> collator_;
71 collator_.reset(icu::Collator::createInstance(error));
72 if (U_FAILURE(error))
73 collator_.reset(NULL);
75 return collator_.Pass();
78 } // namespace
80 BookmarksBridge::BookmarksBridge(JNIEnv* env,
81 jobject obj,
82 jobject j_profile)
83 : weak_java_ref_(env, obj),
84 bookmark_model_(NULL),
85 client_(NULL),
86 partner_bookmarks_shim_(NULL) {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
88 profile_ = ProfileAndroid::FromProfileAndroid(j_profile);
89 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile_);
90 client_ = ChromeBookmarkClientFactory::GetForProfile(profile_);
92 // Registers the notifications we are interested.
93 bookmark_model_->AddObserver(this);
95 // Create the partner Bookmarks shim as early as possible (but don't attach).
96 partner_bookmarks_shim_ = PartnerBookmarksShim::BuildForBrowserContext(
97 chrome::GetBrowserContextRedirectedInIncognito(profile_));
98 partner_bookmarks_shim_->AddObserver(this);
100 NotifyIfDoneLoading();
102 // Since a sync or import could have started before this class is
103 // initialized, we need to make sure that our initial state is
104 // up to date.
105 if (bookmark_model_->IsDoingExtensiveChanges())
106 ExtensiveBookmarkChangesBeginning(bookmark_model_);
109 BookmarksBridge::~BookmarksBridge() {
110 bookmark_model_->RemoveObserver(this);
111 if (partner_bookmarks_shim_)
112 partner_bookmarks_shim_->RemoveObserver(this);
115 void BookmarksBridge::Destroy(JNIEnv*, jobject) {
116 delete this;
119 // static
120 bool BookmarksBridge::RegisterBookmarksBridge(JNIEnv* env) {
121 return RegisterNativesImpl(env);
124 static jlong Init(JNIEnv* env, jobject obj, jobject j_profile) {
125 BookmarksBridge* delegate = new BookmarksBridge(env, obj, j_profile);
126 return reinterpret_cast<intptr_t>(delegate);
129 static jboolean IsEnhancedBookmarksFeatureEnabled(JNIEnv* env,
130 jclass clazz,
131 jobject j_profile) {
132 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
133 return IsEnhancedBookmarksEnabled(profile->GetPrefs());
136 static bool IsEditBookmarksEnabled() {
137 return ProfileManager::GetLastUsedProfile()->GetPrefs()->GetBoolean(
138 bookmarks::prefs::kEditBookmarksEnabled);
141 static jboolean IsEditBookmarksEnabled(JNIEnv* env, jclass clazz) {
142 return IsEditBookmarksEnabled();
145 void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv* env,
146 jobject obj) {
147 if (partner_bookmarks_shim_->IsLoaded())
148 return;
149 partner_bookmarks_shim_->SetPartnerBookmarksRoot(
150 new BookmarkPermanentNode(0));
151 DCHECK(partner_bookmarks_shim_->IsLoaded());
154 ScopedJavaLocalRef<jobject> BookmarksBridge::GetBookmarkByID(JNIEnv* env,
155 jobject obj,
156 jlong id,
157 jint type) {
158 DCHECK(IsLoaded());
159 return CreateJavaBookmark(GetNodeByID(id, type));
162 bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv* env, jobject obj) {
163 return bookmark_model_->IsDoingExtensiveChanges();
166 void BookmarksBridge::GetPermanentNodeIDs(JNIEnv* env,
167 jobject obj,
168 jobject j_result_obj) {
169 // TODO(kkimlabs): Remove this function.
170 DCHECK(IsLoaded());
172 base::StackVector<const BookmarkNode*, 8> permanent_nodes;
174 // Save all the permanent nodes.
175 const BookmarkNode* root_node = bookmark_model_->root_node();
176 permanent_nodes->push_back(root_node);
177 for (int i = 0; i < root_node->child_count(); ++i) {
178 permanent_nodes->push_back(root_node->GetChild(i));
180 permanent_nodes->push_back(
181 partner_bookmarks_shim_->GetPartnerBookmarksRoot());
183 // Write the permanent nodes to |j_result_obj|.
184 for (base::StackVector<const BookmarkNode*, 8>::ContainerType::const_iterator
185 it = permanent_nodes->begin();
186 it != permanent_nodes->end();
187 ++it) {
188 if (*it != NULL) {
189 Java_BookmarksBridge_addToBookmarkIdList(
190 env, j_result_obj, (*it)->id(), GetBookmarkType(*it));
195 void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv* env,
196 jobject obj,
197 jobject j_result_obj) {
198 Java_BookmarksBridge_addToBookmarkIdList(
199 env, j_result_obj, bookmark_model_->root_node()->id(),
200 GetBookmarkType(bookmark_model_->root_node()));
201 Java_BookmarksBridge_addToBookmarkIdList(
202 env, j_result_obj, bookmark_model_->mobile_node()->id(),
203 GetBookmarkType(bookmark_model_->mobile_node()));
204 Java_BookmarksBridge_addToBookmarkIdList(
205 env, j_result_obj, bookmark_model_->other_node()->id(),
206 GetBookmarkType(bookmark_model_->other_node()));
209 void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv* env,
210 jobject obj,
211 jboolean get_special,
212 jboolean get_normal,
213 jobject j_result_obj) {
214 DCHECK(IsLoaded());
215 std::vector<const BookmarkNode*> top_level_folders;
217 if (get_special) {
218 if (client_->managed_node() &&
219 client_->managed_node()->child_count() > 0) {
220 top_level_folders.push_back(client_->managed_node());
222 if (partner_bookmarks_shim_->HasPartnerBookmarks()) {
223 top_level_folders.push_back(
224 partner_bookmarks_shim_->GetPartnerBookmarksRoot());
227 std::size_t special_count = top_level_folders.size();
229 if (get_normal) {
230 DCHECK_EQ(bookmark_model_->root_node()->child_count(), 4);
232 top_level_folders.push_back(bookmark_model_->bookmark_bar_node());
234 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
235 for (int i = 0; i < mobile_node->child_count(); ++i) {
236 const BookmarkNode* node = mobile_node->GetChild(i);
237 if (node->is_folder()) {
238 top_level_folders.push_back(node);
242 const BookmarkNode* other_node = bookmark_model_->other_node();
243 for (int i = 0; i < other_node->child_count(); ++i) {
244 const BookmarkNode* node = other_node->GetChild(i);
245 if (node->is_folder()) {
246 top_level_folders.push_back(node);
250 scoped_ptr<icu::Collator> collator = GetICUCollator();
251 std::stable_sort(top_level_folders.begin() + special_count,
252 top_level_folders.end(),
253 BookmarkTitleComparer(collator.get()));
256 for (std::vector<const BookmarkNode*>::const_iterator it =
257 top_level_folders.begin(); it != top_level_folders.end(); ++it) {
258 Java_BookmarksBridge_addToBookmarkIdList(env,
259 j_result_obj,
260 (*it)->id(),
261 GetBookmarkType(*it));
265 void BookmarksBridge::GetUncategorizedBookmarkIDs(JNIEnv* env,
266 jobject obj,
267 jobject j_result_obj) {
268 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
269 for (int i = 0; i < mobile_node->child_count(); ++i) {
270 const BookmarkNode* node = mobile_node->GetChild(i);
271 if (!node->is_folder()) {
272 Java_BookmarksBridge_addToBookmarkIdList(env,
273 j_result_obj,
274 node->id(),
275 GetBookmarkType(node));
279 const BookmarkNode* other_node = bookmark_model_->other_node();
280 for (int i = 0; i < other_node->child_count(); ++i) {
281 const BookmarkNode* node = other_node->GetChild(i);
282 if (!node->is_folder()) {
283 Java_BookmarksBridge_addToBookmarkIdList(env,
284 j_result_obj,
285 node->id(),
286 GetBookmarkType(node));
291 void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv* env,
292 jobject obj,
293 jobject j_folders_obj,
294 jobject j_depths_obj) {
295 DCHECK(IsLoaded());
297 const BookmarkNode* desktop = bookmark_model_->bookmark_bar_node();
298 const BookmarkNode* mobile = bookmark_model_->mobile_node();
299 const BookmarkNode* other = bookmark_model_->other_node();
301 scoped_ptr<icu::Collator> collator = GetICUCollator();
303 // Vector to temporarily contain all child bookmarks at same level for sorting
304 std::vector<const BookmarkNode*> bookmarkList;
305 // Stack for Depth-First Search of bookmark model. It stores nodes and their
306 // heights.
307 std::stack<std::pair<const BookmarkNode*, int> > stk;
309 for (int i = 0; i < mobile->child_count(); ++i) {
310 const BookmarkNode* child = mobile->GetChild(i);
311 if (child->is_folder() && client_->CanBeEditedByUser(child))
312 bookmarkList.push_back(child);
314 for (int i = 0; i < other->child_count(); ++i) {
315 const BookmarkNode* child = other->GetChild(i);
316 if (child->is_folder() && client_->CanBeEditedByUser(child))
317 bookmarkList.push_back(child);
319 bookmarkList.push_back(desktop);
320 std::stable_sort(bookmarkList.begin(),
321 bookmarkList.end(),
322 BookmarkTitleComparer(collator.get()));
324 // Push all sorted top folders in stack and give them depth of 0.
325 // Note the order to push folders to stack should be opposite to the order in
326 // output.
327 for (std::vector<const BookmarkNode*>::reverse_iterator it =
328 bookmarkList.rbegin();
329 it != bookmarkList.rend();
330 ++it) {
331 stk.push(std::make_pair(*it, 0));
334 while (!stk.empty()) {
335 const BookmarkNode* node = stk.top().first;
336 int depth = stk.top().second;
337 stk.pop();
338 Java_BookmarksBridge_addToBookmarkIdListWithDepth(env,
339 j_folders_obj,
340 node->id(),
341 GetBookmarkType(node),
342 j_depths_obj,
343 depth);
344 bookmarkList.clear();
345 for (int i = 0; i < node->child_count(); ++i) {
346 const BookmarkNode* child = node->GetChild(i);
347 if (child->is_folder() && client_->CanBeEditedByUser(child))
348 bookmarkList.push_back(node->GetChild(i));
350 std::stable_sort(bookmarkList.begin(),
351 bookmarkList.end(),
352 BookmarkTitleComparer(collator.get()));
353 for (std::vector<const BookmarkNode*>::reverse_iterator it =
354 bookmarkList.rbegin();
355 it != bookmarkList.rend();
356 ++it) {
357 stk.push(std::make_pair(*it, depth + 1));
362 ScopedJavaLocalRef<jobject> BookmarksBridge::GetMobileFolderId(JNIEnv* env,
363 jobject obj) {
364 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
365 ScopedJavaLocalRef<jobject> folder_id_obj =
366 Java_BookmarksBridge_createBookmarkId(
367 env, mobile_node->id(), GetBookmarkType(mobile_node));
368 return folder_id_obj;
371 ScopedJavaLocalRef<jobject> BookmarksBridge::GetOtherFolderId(JNIEnv* env,
372 jobject obj) {
373 const BookmarkNode* other_node = bookmark_model_->other_node();
374 ScopedJavaLocalRef<jobject> folder_id_obj =
375 Java_BookmarksBridge_createBookmarkId(
376 env, other_node->id(), GetBookmarkType(other_node));
377 return folder_id_obj;
380 ScopedJavaLocalRef<jobject> BookmarksBridge::GetDesktopFolderId(JNIEnv* env,
381 jobject obj) {
382 const BookmarkNode* desktop_node = bookmark_model_->bookmark_bar_node();
383 ScopedJavaLocalRef<jobject> folder_id_obj =
384 Java_BookmarksBridge_createBookmarkId(
385 env, desktop_node->id(), GetBookmarkType(desktop_node));
386 return folder_id_obj;
389 void BookmarksBridge::GetChildIDs(JNIEnv* env,
390 jobject obj,
391 jlong id,
392 jint type,
393 jboolean get_folders,
394 jboolean get_bookmarks,
395 jobject j_result_obj) {
396 DCHECK(IsLoaded());
398 const BookmarkNode* parent = GetNodeByID(id, type);
399 if (!parent->is_folder() || !IsReachable(parent))
400 return;
402 // Get the folder contents
403 for (int i = 0; i < parent->child_count(); ++i) {
404 const BookmarkNode* child = parent->GetChild(i);
405 if (!IsFolderAvailable(child) || !IsReachable(child))
406 continue;
408 if ((child->is_folder() && get_folders) ||
409 (!child->is_folder() && get_bookmarks)) {
410 Java_BookmarksBridge_addToBookmarkIdList(
411 env, j_result_obj, child->id(), GetBookmarkType(child));
415 // Partner bookmark root node is under mobile node.
416 if (parent == bookmark_model_->mobile_node() && get_folders &&
417 partner_bookmarks_shim_->HasPartnerBookmarks() &&
418 IsReachable(partner_bookmarks_shim_->GetPartnerBookmarksRoot())) {
419 Java_BookmarksBridge_addToBookmarkIdList(
420 env,
421 j_result_obj,
422 partner_bookmarks_shim_->GetPartnerBookmarksRoot()->id(),
423 BookmarkType::PARTNER);
427 ScopedJavaLocalRef<jobject> BookmarksBridge::GetChildAt(JNIEnv* env,
428 jobject obj,
429 jlong id,
430 jint type,
431 jint index) {
432 DCHECK(IsLoaded());
434 const BookmarkNode* parent = GetNodeByID(id, type);
435 DCHECK(parent);
436 const BookmarkNode* child = parent->GetChild(index);
437 return Java_BookmarksBridge_createBookmarkId(
438 env, child->id(), GetBookmarkType(child));
441 void BookmarksBridge::GetAllBookmarkIDsOrderedByCreationDate(
442 JNIEnv* env,
443 jobject obj,
444 jobject j_result_obj) {
445 DCHECK(IsLoaded());
446 std::list<const BookmarkNode*> folders;
447 std::vector<const BookmarkNode*> result;
448 folders.push_back(bookmark_model_->root_node());
449 folders.push_back(partner_bookmarks_shim_->GetPartnerBookmarksRoot());
451 for (std::list<const BookmarkNode*>::iterator folder_iter = folders.begin();
452 folder_iter != folders.end(); ++folder_iter) {
453 if (*folder_iter == NULL)
454 continue;
456 std::list<const BookmarkNode*>::iterator insert_iter = folder_iter;
457 ++insert_iter;
459 for (int i = 0; i < (*folder_iter)->child_count(); ++i) {
460 const BookmarkNode* child = (*folder_iter)->GetChild(i);
461 if (!IsFolderAvailable(child) || !IsReachable(child))
462 continue;
464 if (child->is_folder()) {
465 insert_iter = folders.insert(insert_iter, child);
466 } else {
467 result.push_back(child);
472 std::sort(
473 result.begin(), result.end(), BookmarkNodeCreationTimeCompareFunctor());
475 for (std::vector<const BookmarkNode*>::const_iterator iter = result.begin();
476 iter != result.end();
477 ++iter) {
478 const BookmarkNode* bookmark = *iter;
479 Java_BookmarksBridge_addToBookmarkIdList(
480 env, j_result_obj, bookmark->id(), GetBookmarkType(bookmark));
484 void BookmarksBridge::SetBookmarkTitle(JNIEnv* env,
485 jobject obj,
486 jlong id,
487 jint type,
488 jstring j_title) {
489 DCHECK(IsLoaded());
490 const BookmarkNode* bookmark = GetNodeByID(id, type);
491 const base::string16 title =
492 base::android::ConvertJavaStringToUTF16(env, j_title);
494 if (partner_bookmarks_shim_->IsPartnerBookmark(bookmark)) {
495 partner_bookmarks_shim_->RenameBookmark(bookmark, title);
496 } else {
497 bookmark_model_->SetTitle(bookmark, title);
501 void BookmarksBridge::SetBookmarkUrl(JNIEnv* env,
502 jobject obj,
503 jlong id,
504 jint type,
505 jstring url) {
506 DCHECK(IsLoaded());
507 bookmark_model_->SetURL(
508 GetNodeByID(id, type),
509 GURL(base::android::ConvertJavaStringToUTF16(env, url)));
512 bool BookmarksBridge::DoesBookmarkExist(JNIEnv* env,
513 jobject obj,
514 jlong id,
515 jint type) {
516 DCHECK(IsLoaded());
517 return GetNodeByID(id, type);
520 void BookmarksBridge::GetBookmarksForFolder(JNIEnv* env,
521 jobject obj,
522 jobject j_folder_id_obj,
523 jobject j_callback_obj,
524 jobject j_result_obj) {
525 DCHECK(IsLoaded());
526 long folder_id = JavaBookmarkIdGetId(env, j_folder_id_obj);
527 int type = JavaBookmarkIdGetType(env, j_folder_id_obj);
528 const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
530 if (!folder->is_folder() || !IsReachable(folder))
531 return;
533 // Recreate the java bookmarkId object due to fallback.
534 ScopedJavaLocalRef<jobject> folder_id_obj =
535 Java_BookmarksBridge_createBookmarkId(
536 env, folder->id(), GetBookmarkType(folder));
537 j_folder_id_obj = folder_id_obj.obj();
539 // Get the folder contents.
540 for (int i = 0; i < folder->child_count(); ++i) {
541 const BookmarkNode* node = folder->GetChild(i);
542 if (!IsFolderAvailable(node))
543 continue;
544 ExtractBookmarkNodeInformation(node, j_result_obj);
547 if (folder == bookmark_model_->mobile_node() &&
548 partner_bookmarks_shim_->HasPartnerBookmarks()) {
549 ExtractBookmarkNodeInformation(
550 partner_bookmarks_shim_->GetPartnerBookmarksRoot(),
551 j_result_obj);
554 if (j_callback_obj) {
555 Java_BookmarksCallback_onBookmarksAvailable(
556 env, j_callback_obj, j_folder_id_obj, j_result_obj);
560 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv* env,
561 jobject obj,
562 jobject j_folder_id_obj,
563 jobject j_callback_obj,
564 jobject j_result_obj) {
565 DCHECK(IsLoaded());
566 long folder_id = JavaBookmarkIdGetId(env, j_folder_id_obj);
567 int type = JavaBookmarkIdGetType(env, j_folder_id_obj);
568 const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
570 if (!folder->is_folder() || !IsReachable(folder))
571 return;
573 // Recreate the java bookmarkId object due to fallback.
574 ScopedJavaLocalRef<jobject> folder_id_obj =
575 Java_BookmarksBridge_createBookmarkId(
576 env, folder->id(), GetBookmarkType(folder));
577 j_folder_id_obj = folder_id_obj.obj();
579 // Get the folder hierarchy.
580 const BookmarkNode* node = folder;
581 while (node) {
582 ExtractBookmarkNodeInformation(node, j_result_obj);
583 node = GetParentNode(node);
586 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
587 env, j_callback_obj, j_folder_id_obj, j_result_obj);
590 ScopedJavaLocalRef<jobject> BookmarksBridge::AddFolder(JNIEnv* env,
591 jobject obj,
592 jobject j_parent_id_obj,
593 jint index,
594 jstring j_title) {
595 DCHECK(IsLoaded());
596 long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
597 int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
598 const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
600 const BookmarkNode* new_node = bookmark_model_->AddFolder(
601 parent, index, base::android::ConvertJavaStringToUTF16(env, j_title));
602 if (!new_node) {
603 NOTREACHED();
604 return ScopedJavaLocalRef<jobject>();
606 ScopedJavaLocalRef<jobject> new_java_obj =
607 Java_BookmarksBridge_createBookmarkId(
608 env, new_node->id(), GetBookmarkType(new_node));
609 return new_java_obj;
612 void BookmarksBridge::DeleteBookmark(JNIEnv* env,
613 jobject obj,
614 jobject j_bookmark_id_obj) {
615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
616 DCHECK(IsLoaded());
618 long bookmark_id = JavaBookmarkIdGetId(env, j_bookmark_id_obj);
619 int type = JavaBookmarkIdGetType(env, j_bookmark_id_obj);
620 const BookmarkNode* node = GetNodeByID(bookmark_id, type);
621 if (!IsEditable(node)) {
622 NOTREACHED();
623 return;
626 if (partner_bookmarks_shim_->IsPartnerBookmark(node)) {
627 partner_bookmarks_shim_->RemoveBookmark(node);
628 } else {
629 const BookmarkNode* parent_node = GetParentNode(node);
630 bookmark_model_->Remove(parent_node, parent_node->GetIndexOf(node));
634 void BookmarksBridge::MoveBookmark(JNIEnv* env,
635 jobject obj,
636 jobject j_bookmark_id_obj,
637 jobject j_parent_id_obj,
638 jint index) {
639 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
640 DCHECK(IsLoaded());
642 long bookmark_id = JavaBookmarkIdGetId(env, j_bookmark_id_obj);
643 int type = JavaBookmarkIdGetType(env, j_bookmark_id_obj);
644 const BookmarkNode* node = GetNodeByID(bookmark_id, type);
645 if (!IsEditable(node)) {
646 NOTREACHED();
647 return;
649 bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
650 type = JavaBookmarkIdGetType(env, j_parent_id_obj);
651 const BookmarkNode* new_parent_node = GetNodeByID(bookmark_id, type);
652 bookmark_model_->Move(node, new_parent_node, index);
655 ScopedJavaLocalRef<jobject> BookmarksBridge::AddBookmark(
656 JNIEnv* env,
657 jobject obj,
658 jobject j_parent_id_obj,
659 jint index,
660 jstring j_title,
661 jstring j_url) {
662 DCHECK(IsLoaded());
663 long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
664 int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
665 const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
667 const BookmarkNode* new_node = bookmark_model_->AddURL(
668 parent,
669 index,
670 base::android::ConvertJavaStringToUTF16(env, j_title),
671 GURL(base::android::ConvertJavaStringToUTF16(env, j_url)));
672 if (!new_node) {
673 NOTREACHED();
674 return ScopedJavaLocalRef<jobject>();
676 ScopedJavaLocalRef<jobject> new_java_obj =
677 Java_BookmarksBridge_createBookmarkId(
678 env, new_node->id(), GetBookmarkType(new_node));
679 return new_java_obj;
682 void BookmarksBridge::Undo(JNIEnv* env, jobject obj) {
683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
684 DCHECK(IsLoaded());
685 BookmarkUndoService* undo_service =
686 BookmarkUndoServiceFactory::GetForProfile(profile_);
687 UndoManager* undo_manager = undo_service->undo_manager();
688 undo_manager->Undo();
691 void BookmarksBridge::StartGroupingUndos(JNIEnv* env, jobject obj) {
692 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
693 DCHECK(IsLoaded());
694 DCHECK(!grouped_bookmark_actions_.get()); // shouldn't have started already
695 grouped_bookmark_actions_.reset(
696 new bookmarks::ScopedGroupBookmarkActions(bookmark_model_));
699 void BookmarksBridge::EndGroupingUndos(JNIEnv* env, jobject obj) {
700 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
701 DCHECK(IsLoaded());
702 DCHECK(grouped_bookmark_actions_.get()); // should only call after start
703 grouped_bookmark_actions_.reset();
706 ScopedJavaLocalRef<jobject> BookmarksBridge::CreateJavaBookmark(
707 const BookmarkNode* node) {
708 JNIEnv* env = AttachCurrentThread();
710 const BookmarkNode* parent = GetParentNode(node);
711 int64 parent_id = parent ? parent->id() : -1;
713 std::string url;
714 if (node->is_url())
715 url = node->url().spec();
717 return Java_BookmarksBridge_createBookmarkItem(
718 env,
719 node->id(),
720 GetBookmarkType(node),
721 ConvertUTF16ToJavaString(env, GetTitle(node)).obj(),
722 ConvertUTF8ToJavaString(env, url).obj(),
723 node->is_folder(),
724 parent_id,
725 GetBookmarkType(parent),
726 IsEditable(node),
727 IsManaged(node));
730 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode* node,
731 jobject j_result_obj) {
732 JNIEnv* env = AttachCurrentThread();
733 if (!IsReachable(node))
734 return;
735 Java_BookmarksBridge_addToList(
736 env, j_result_obj, CreateJavaBookmark(node).obj());
739 const BookmarkNode* BookmarksBridge::GetNodeByID(long node_id, int type) {
740 const BookmarkNode* node;
741 if (type == BookmarkType::PARTNER) {
742 node = partner_bookmarks_shim_->GetNodeByID(
743 static_cast<int64>(node_id));
744 } else {
745 node = bookmarks::GetBookmarkNodeByID(bookmark_model_,
746 static_cast<int64>(node_id));
748 return node;
751 const BookmarkNode* BookmarksBridge::GetFolderWithFallback(long folder_id,
752 int type) {
753 const BookmarkNode* folder = GetNodeByID(folder_id, type);
754 if (!folder || folder->type() == BookmarkNode::URL ||
755 !IsFolderAvailable(folder)) {
756 if (!client_->managed_node()->empty())
757 folder = client_->managed_node();
758 else
759 folder = bookmark_model_->mobile_node();
761 return folder;
764 bool BookmarksBridge::IsEditable(const BookmarkNode* node) const {
765 if (!node || (node->type() != BookmarkNode::FOLDER &&
766 node->type() != BookmarkNode::URL)) {
767 return false;
769 if (!IsEditBookmarksEnabled())
770 return false;
771 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
772 return partner_bookmarks_shim_->IsEditable(node);
773 return client_->CanBeEditedByUser(node);
776 bool BookmarksBridge::IsManaged(const BookmarkNode* node) const {
777 return client_->IsDescendantOfManagedNode(node);
780 const BookmarkNode* BookmarksBridge::GetParentNode(const BookmarkNode* node) {
781 DCHECK(IsLoaded());
782 if (node == partner_bookmarks_shim_->GetPartnerBookmarksRoot()) {
783 return bookmark_model_->mobile_node();
784 } else {
785 return node->parent();
789 int BookmarksBridge::GetBookmarkType(const BookmarkNode* node) {
790 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
791 return BookmarkType::PARTNER;
792 else
793 return BookmarkType::NORMAL;
796 base::string16 BookmarksBridge::GetTitle(const BookmarkNode* node) const {
797 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
798 return partner_bookmarks_shim_->GetTitle(node);
799 return node->GetTitle();
802 bool BookmarksBridge::IsReachable(const BookmarkNode* node) const {
803 if (!partner_bookmarks_shim_->IsPartnerBookmark(node))
804 return true;
805 return partner_bookmarks_shim_->IsReachable(node);
808 bool BookmarksBridge::IsLoaded() const {
809 return (bookmark_model_->loaded() && partner_bookmarks_shim_->IsLoaded());
812 bool BookmarksBridge::IsFolderAvailable(
813 const BookmarkNode* folder) const {
814 // The managed bookmarks folder is not shown if there are no bookmarks
815 // configured via policy.
816 if (folder == client_->managed_node() && folder->empty())
817 return false;
819 SigninManager* signin = SigninManagerFactory::GetForProfile(
820 profile_->GetOriginalProfile());
821 return (folder->type() != BookmarkNode::BOOKMARK_BAR &&
822 folder->type() != BookmarkNode::OTHER_NODE) ||
823 (signin && signin->IsAuthenticated());
826 void BookmarksBridge::NotifyIfDoneLoading() {
827 if (!IsLoaded())
828 return;
829 JNIEnv* env = AttachCurrentThread();
830 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
831 if (obj.is_null())
832 return;
833 Java_BookmarksBridge_bookmarkModelLoaded(env, obj.obj());
836 // ------------- Observer-related methods ------------- //
838 void BookmarksBridge::BookmarkModelChanged() {
839 if (!IsLoaded())
840 return;
842 // Called when there are changes to the bookmark model. It is most
843 // likely changes to the partner bookmarks.
844 JNIEnv* env = AttachCurrentThread();
845 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
846 if (obj.is_null())
847 return;
848 Java_BookmarksBridge_bookmarkModelChanged(env, obj.obj());
851 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel* model,
852 bool ids_reassigned) {
853 NotifyIfDoneLoading();
856 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
857 if (!IsLoaded())
858 return;
860 JNIEnv* env = AttachCurrentThread();
861 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
862 if (obj.is_null())
863 return;
864 Java_BookmarksBridge_bookmarkModelDeleted(env, obj.obj());
867 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel* model,
868 const BookmarkNode* old_parent,
869 int old_index,
870 const BookmarkNode* new_parent,
871 int new_index) {
872 if (!IsLoaded())
873 return;
875 JNIEnv* env = AttachCurrentThread();
876 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
877 if (obj.is_null())
878 return;
879 Java_BookmarksBridge_bookmarkNodeMoved(
880 env,
881 obj.obj(),
882 CreateJavaBookmark(old_parent).obj(),
883 old_index,
884 CreateJavaBookmark(new_parent).obj(),
885 new_index);
888 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel* model,
889 const BookmarkNode* parent,
890 int index) {
891 if (!IsLoaded())
892 return;
894 JNIEnv* env = AttachCurrentThread();
895 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
896 if (obj.is_null())
897 return;
898 Java_BookmarksBridge_bookmarkNodeAdded(
899 env,
900 obj.obj(),
901 CreateJavaBookmark(parent).obj(),
902 index);
905 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel* model,
906 const BookmarkNode* parent,
907 int old_index,
908 const BookmarkNode* node,
909 const std::set<GURL>& removed_urls) {
910 if (!IsLoaded())
911 return;
913 JNIEnv* env = AttachCurrentThread();
914 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
915 if (obj.is_null())
916 return;
917 Java_BookmarksBridge_bookmarkNodeRemoved(
918 env,
919 obj.obj(),
920 CreateJavaBookmark(parent).obj(),
921 old_index,
922 CreateJavaBookmark(node).obj());
925 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel* model,
926 const BookmarkNode* node) {
927 if (!IsLoaded())
928 return;
930 JNIEnv* env = AttachCurrentThread();
931 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
932 if (obj.is_null())
933 return;
934 Java_BookmarksBridge_bookmarkNodeChanged(
935 env,
936 obj.obj(),
937 CreateJavaBookmark(node).obj());
940 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel* model,
941 const BookmarkNode* node) {
942 if (!IsLoaded())
943 return;
945 JNIEnv* env = AttachCurrentThread();
946 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
947 if (obj.is_null())
948 return;
949 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
950 env,
951 obj.obj(),
952 CreateJavaBookmark(node).obj());
955 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
956 if (!IsLoaded())
957 return;
959 JNIEnv* env = AttachCurrentThread();
960 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
961 if (obj.is_null())
962 return;
963 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env, obj.obj());
966 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
967 if (!IsLoaded())
968 return;
970 JNIEnv* env = AttachCurrentThread();
971 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
972 if (obj.is_null())
973 return;
974 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env, obj.obj());
977 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim* shim) {
978 if (!IsLoaded())
979 return;
981 BookmarkModelChanged();
984 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim* shim) {
985 NotifyIfDoneLoading();
988 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim* shim) {
989 partner_bookmarks_shim_ = NULL;