Instrumental test for BookmarksBridge. It currently tests these functionalities:...
[chromium-blink-merge.git] / chrome / browser / android / bookmarks / bookmarks_bridge.cc
blobfe7c99b8705f3875d8efe909c142e79de101aca7
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/common/pref_names.h"
20 #include "components/bookmarks/browser/bookmark_model.h"
21 #include "components/bookmarks/browser/bookmark_utils.h"
22 #include "components/bookmarks/common/android/bookmark_type.h"
23 #include "components/signin/core/browser/signin_manager.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "jni/BookmarksBridge_jni.h"
27 using base::android::AttachCurrentThread;
28 using base::android::ConvertUTF8ToJavaString;
29 using base::android::ConvertUTF16ToJavaString;
30 using base::android::ScopedJavaLocalRef;
31 using base::android::ScopedJavaGlobalRef;
32 using bookmarks::android::JavaBookmarkIdGetId;
33 using bookmarks::android::JavaBookmarkIdGetType;
34 using bookmarks::BookmarkType;
35 using content::BrowserThread;
37 namespace {
39 class BookmarkNodeCreationTimeCompareFunctor {
40 public:
41 bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
42 return lhs->date_added().ToJavaTime() > rhs->date_added().ToJavaTime();
46 class BookmarkTitleComparer {
47 public:
48 explicit BookmarkTitleComparer(const icu::Collator* collator)
49 : collator_(collator) {}
51 bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
52 if (collator_) {
53 return base::i18n::CompareString16WithCollator(
54 collator_, lhs->GetTitle(), rhs->GetTitle()) == UCOL_LESS;
55 } else {
56 return lhs->GetTitle() < rhs->GetTitle();
60 private:
61 const icu::Collator* collator_;
64 scoped_ptr<icu::Collator> GetICUCollator() {
65 UErrorCode error = U_ZERO_ERROR;
66 scoped_ptr<icu::Collator> collator_;
67 collator_.reset(icu::Collator::createInstance(error));
68 if (U_FAILURE(error))
69 collator_.reset(NULL);
71 return collator_.Pass();
74 } // namespace
76 BookmarksBridge::BookmarksBridge(JNIEnv* env,
77 jobject obj,
78 jobject j_profile)
79 : weak_java_ref_(env, obj),
80 bookmark_model_(NULL),
81 client_(NULL),
82 partner_bookmarks_shim_(NULL) {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84 profile_ = ProfileAndroid::FromProfileAndroid(j_profile);
85 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile_);
86 client_ = ChromeBookmarkClientFactory::GetForProfile(profile_);
88 // Registers the notifications we are interested.
89 bookmark_model_->AddObserver(this);
91 // Create the partner Bookmarks shim as early as possible (but don't attach).
92 partner_bookmarks_shim_ = PartnerBookmarksShim::BuildForBrowserContext(
93 chrome::GetBrowserContextRedirectedInIncognito(profile_));
94 partner_bookmarks_shim_->AddObserver(this);
96 NotifyIfDoneLoading();
98 // Since a sync or import could have started before this class is
99 // initialized, we need to make sure that our initial state is
100 // up to date.
101 if (bookmark_model_->IsDoingExtensiveChanges())
102 ExtensiveBookmarkChangesBeginning(bookmark_model_);
105 BookmarksBridge::~BookmarksBridge() {
106 bookmark_model_->RemoveObserver(this);
107 if (partner_bookmarks_shim_)
108 partner_bookmarks_shim_->RemoveObserver(this);
111 void BookmarksBridge::Destroy(JNIEnv*, jobject) {
112 delete this;
115 // static
116 bool BookmarksBridge::RegisterBookmarksBridge(JNIEnv* env) {
117 return RegisterNativesImpl(env);
120 static jlong Init(JNIEnv* env, jobject obj, jobject j_profile) {
121 BookmarksBridge* delegate = new BookmarksBridge(env, obj, j_profile);
122 return reinterpret_cast<intptr_t>(delegate);
125 static jlong GetNativeBookmarkModel(JNIEnv* env,
126 jclass caller,
127 jobject j_profile) {
128 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
129 BookmarkModel *bookmark_model_ = BookmarkModelFactory::GetForProfile(profile);
130 return reinterpret_cast<jlong>(bookmark_model_);
133 static jboolean IsEnhancedBookmarksFeatureEnabled(JNIEnv* env,
134 jclass clazz,
135 jobject j_profile) {
136 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
137 return IsEnhancedBookmarksEnabled(profile->GetPrefs());
140 static bool IsEditBookmarksEnabled() {
141 return ProfileManager::GetLastUsedProfile()->GetPrefs()->GetBoolean(
142 bookmarks::prefs::kEditBookmarksEnabled);
145 static jboolean IsEditBookmarksEnabled(JNIEnv* env, jclass clazz) {
146 return IsEditBookmarksEnabled();
149 void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv* env,
150 jobject obj) {
151 if (partner_bookmarks_shim_->IsLoaded())
152 return;
153 partner_bookmarks_shim_->SetPartnerBookmarksRoot(
154 new BookmarkPermanentNode(0));
155 DCHECK(partner_bookmarks_shim_->IsLoaded());
158 ScopedJavaLocalRef<jobject> BookmarksBridge::GetBookmarkByID(JNIEnv* env,
159 jobject obj,
160 jlong id,
161 jint type) {
162 DCHECK(IsLoaded());
163 return CreateJavaBookmark(GetNodeByID(id, type));
166 bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv* env, jobject obj) {
167 return bookmark_model_->IsDoingExtensiveChanges();
170 void BookmarksBridge::GetPermanentNodeIDs(JNIEnv* env,
171 jobject obj,
172 jobject j_result_obj) {
173 // TODO(kkimlabs): Remove this function.
174 DCHECK(IsLoaded());
176 base::StackVector<const BookmarkNode*, 8> permanent_nodes;
178 // Save all the permanent nodes.
179 const BookmarkNode* root_node = bookmark_model_->root_node();
180 permanent_nodes->push_back(root_node);
181 for (int i = 0; i < root_node->child_count(); ++i) {
182 permanent_nodes->push_back(root_node->GetChild(i));
184 permanent_nodes->push_back(
185 partner_bookmarks_shim_->GetPartnerBookmarksRoot());
187 // Write the permanent nodes to |j_result_obj|.
188 for (base::StackVector<const BookmarkNode*, 8>::ContainerType::const_iterator
189 it = permanent_nodes->begin();
190 it != permanent_nodes->end();
191 ++it) {
192 if (*it != NULL) {
193 Java_BookmarksBridge_addToBookmarkIdList(
194 env, j_result_obj, (*it)->id(), GetBookmarkType(*it));
199 void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv* env,
200 jobject obj,
201 jobject j_result_obj) {
202 Java_BookmarksBridge_addToBookmarkIdList(
203 env, j_result_obj, bookmark_model_->root_node()->id(),
204 GetBookmarkType(bookmark_model_->root_node()));
205 Java_BookmarksBridge_addToBookmarkIdList(
206 env, j_result_obj, bookmark_model_->mobile_node()->id(),
207 GetBookmarkType(bookmark_model_->mobile_node()));
208 Java_BookmarksBridge_addToBookmarkIdList(
209 env, j_result_obj, bookmark_model_->other_node()->id(),
210 GetBookmarkType(bookmark_model_->other_node()));
213 void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv* env,
214 jobject obj,
215 jboolean get_special,
216 jboolean get_normal,
217 jobject j_result_obj) {
218 DCHECK(IsLoaded());
219 std::vector<const BookmarkNode*> top_level_folders;
221 if (get_special) {
222 if (client_->managed_node() &&
223 client_->managed_node()->child_count() > 0) {
224 top_level_folders.push_back(client_->managed_node());
226 if (partner_bookmarks_shim_->HasPartnerBookmarks()) {
227 top_level_folders.push_back(
228 partner_bookmarks_shim_->GetPartnerBookmarksRoot());
231 std::size_t special_count = top_level_folders.size();
233 if (get_normal) {
234 DCHECK_EQ(bookmark_model_->root_node()->child_count(), 4);
236 top_level_folders.push_back(bookmark_model_->bookmark_bar_node());
238 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
239 for (int i = 0; i < mobile_node->child_count(); ++i) {
240 const BookmarkNode* node = mobile_node->GetChild(i);
241 if (node->is_folder()) {
242 top_level_folders.push_back(node);
246 const BookmarkNode* other_node = bookmark_model_->other_node();
247 for (int i = 0; i < other_node->child_count(); ++i) {
248 const BookmarkNode* node = other_node->GetChild(i);
249 if (node->is_folder()) {
250 top_level_folders.push_back(node);
254 scoped_ptr<icu::Collator> collator = GetICUCollator();
255 std::stable_sort(top_level_folders.begin() + special_count,
256 top_level_folders.end(),
257 BookmarkTitleComparer(collator.get()));
260 for (std::vector<const BookmarkNode*>::const_iterator it =
261 top_level_folders.begin(); it != top_level_folders.end(); ++it) {
262 Java_BookmarksBridge_addToBookmarkIdList(env,
263 j_result_obj,
264 (*it)->id(),
265 GetBookmarkType(*it));
269 void BookmarksBridge::GetUncategorizedBookmarkIDs(JNIEnv* env,
270 jobject obj,
271 jobject j_result_obj) {
272 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
273 for (int i = 0; i < mobile_node->child_count(); ++i) {
274 const BookmarkNode* node = mobile_node->GetChild(i);
275 if (!node->is_folder()) {
276 Java_BookmarksBridge_addToBookmarkIdList(env,
277 j_result_obj,
278 node->id(),
279 GetBookmarkType(node));
283 const BookmarkNode* other_node = bookmark_model_->other_node();
284 for (int i = 0; i < other_node->child_count(); ++i) {
285 const BookmarkNode* node = other_node->GetChild(i);
286 if (!node->is_folder()) {
287 Java_BookmarksBridge_addToBookmarkIdList(env,
288 j_result_obj,
289 node->id(),
290 GetBookmarkType(node));
295 void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv* env,
296 jobject obj,
297 jobject j_folders_obj,
298 jobject j_depths_obj) {
299 DCHECK(IsLoaded());
301 const BookmarkNode* desktop = bookmark_model_->bookmark_bar_node();
302 const BookmarkNode* mobile = bookmark_model_->mobile_node();
303 const BookmarkNode* other = bookmark_model_->other_node();
305 scoped_ptr<icu::Collator> collator = GetICUCollator();
307 // Vector to temporarily contain all child bookmarks at same level for sorting
308 std::vector<const BookmarkNode*> bookmarkList;
309 // Stack for Depth-First Search of bookmark model. It stores nodes and their
310 // heights.
311 std::stack<std::pair<const BookmarkNode*, int> > stk;
313 for (int i = 0; i < mobile->child_count(); ++i) {
314 const BookmarkNode* child = mobile->GetChild(i);
315 if (child->is_folder() && client_->CanBeEditedByUser(child))
316 bookmarkList.push_back(child);
318 for (int i = 0; i < other->child_count(); ++i) {
319 const BookmarkNode* child = other->GetChild(i);
320 if (child->is_folder() && client_->CanBeEditedByUser(child))
321 bookmarkList.push_back(child);
323 bookmarkList.push_back(desktop);
324 std::stable_sort(bookmarkList.begin(),
325 bookmarkList.end(),
326 BookmarkTitleComparer(collator.get()));
328 // Push all sorted top folders in stack and give them depth of 0.
329 // Note the order to push folders to stack should be opposite to the order in
330 // output.
331 for (std::vector<const BookmarkNode*>::reverse_iterator it =
332 bookmarkList.rbegin();
333 it != bookmarkList.rend();
334 ++it) {
335 stk.push(std::make_pair(*it, 0));
338 while (!stk.empty()) {
339 const BookmarkNode* node = stk.top().first;
340 int depth = stk.top().second;
341 stk.pop();
342 Java_BookmarksBridge_addToBookmarkIdListWithDepth(env,
343 j_folders_obj,
344 node->id(),
345 GetBookmarkType(node),
346 j_depths_obj,
347 depth);
348 bookmarkList.clear();
349 for (int i = 0; i < node->child_count(); ++i) {
350 const BookmarkNode* child = node->GetChild(i);
351 if (child->is_folder() && client_->CanBeEditedByUser(child))
352 bookmarkList.push_back(node->GetChild(i));
354 std::stable_sort(bookmarkList.begin(),
355 bookmarkList.end(),
356 BookmarkTitleComparer(collator.get()));
357 for (std::vector<const BookmarkNode*>::reverse_iterator it =
358 bookmarkList.rbegin();
359 it != bookmarkList.rend();
360 ++it) {
361 stk.push(std::make_pair(*it, depth + 1));
366 ScopedJavaLocalRef<jobject> BookmarksBridge::GetMobileFolderId(JNIEnv* env,
367 jobject obj) {
368 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
369 ScopedJavaLocalRef<jobject> folder_id_obj =
370 Java_BookmarksBridge_createBookmarkId(
371 env, mobile_node->id(), GetBookmarkType(mobile_node));
372 return folder_id_obj;
375 ScopedJavaLocalRef<jobject> BookmarksBridge::GetOtherFolderId(JNIEnv* env,
376 jobject obj) {
377 const BookmarkNode* other_node = bookmark_model_->other_node();
378 ScopedJavaLocalRef<jobject> folder_id_obj =
379 Java_BookmarksBridge_createBookmarkId(
380 env, other_node->id(), GetBookmarkType(other_node));
381 return folder_id_obj;
384 ScopedJavaLocalRef<jobject> BookmarksBridge::GetDesktopFolderId(JNIEnv* env,
385 jobject obj) {
386 const BookmarkNode* desktop_node = bookmark_model_->bookmark_bar_node();
387 ScopedJavaLocalRef<jobject> folder_id_obj =
388 Java_BookmarksBridge_createBookmarkId(
389 env, desktop_node->id(), GetBookmarkType(desktop_node));
390 return folder_id_obj;
393 void BookmarksBridge::GetChildIDs(JNIEnv* env,
394 jobject obj,
395 jlong id,
396 jint type,
397 jboolean get_folders,
398 jboolean get_bookmarks,
399 jobject j_result_obj) {
400 DCHECK(IsLoaded());
402 const BookmarkNode* parent = GetNodeByID(id, type);
403 if (!parent->is_folder() || !IsReachable(parent))
404 return;
406 // Get the folder contents
407 for (int i = 0; i < parent->child_count(); ++i) {
408 const BookmarkNode* child = parent->GetChild(i);
409 if (!IsFolderAvailable(child) || !IsReachable(child))
410 continue;
412 if ((child->is_folder() && get_folders) ||
413 (!child->is_folder() && get_bookmarks)) {
414 Java_BookmarksBridge_addToBookmarkIdList(
415 env, j_result_obj, child->id(), GetBookmarkType(child));
419 // Partner bookmark root node is under mobile node.
420 if (parent == bookmark_model_->mobile_node() && get_folders &&
421 partner_bookmarks_shim_->HasPartnerBookmarks() &&
422 IsReachable(partner_bookmarks_shim_->GetPartnerBookmarksRoot())) {
423 Java_BookmarksBridge_addToBookmarkIdList(
424 env,
425 j_result_obj,
426 partner_bookmarks_shim_->GetPartnerBookmarksRoot()->id(),
427 BookmarkType::PARTNER);
431 void BookmarksBridge::GetAllBookmarkIDsOrderedByCreationDate(
432 JNIEnv* env,
433 jobject obj,
434 jobject j_result_obj) {
435 DCHECK(IsLoaded());
436 std::list<const BookmarkNode*> folders;
437 std::vector<const BookmarkNode*> result;
438 folders.push_back(bookmark_model_->root_node());
439 folders.push_back(partner_bookmarks_shim_->GetPartnerBookmarksRoot());
441 for (std::list<const BookmarkNode*>::iterator folder_iter = folders.begin();
442 folder_iter != folders.end(); ++folder_iter) {
443 if (*folder_iter == NULL)
444 continue;
446 std::list<const BookmarkNode*>::iterator insert_iter = folder_iter;
447 ++insert_iter;
449 for (int i = 0; i < (*folder_iter)->child_count(); ++i) {
450 const BookmarkNode* child = (*folder_iter)->GetChild(i);
451 if (!IsFolderAvailable(child) || !IsReachable(child))
452 continue;
454 if (child->is_folder()) {
455 insert_iter = folders.insert(insert_iter, child);
456 } else {
457 result.push_back(child);
462 std::sort(
463 result.begin(), result.end(), BookmarkNodeCreationTimeCompareFunctor());
465 for (std::vector<const BookmarkNode*>::const_iterator iter = result.begin();
466 iter != result.end();
467 ++iter) {
468 const BookmarkNode* bookmark = *iter;
469 Java_BookmarksBridge_addToBookmarkIdList(
470 env, j_result_obj, bookmark->id(), GetBookmarkType(bookmark));
474 void BookmarksBridge::SetBookmarkTitle(JNIEnv* env,
475 jobject obj,
476 jlong id,
477 jint type,
478 jstring j_title) {
479 DCHECK(IsLoaded());
480 const BookmarkNode* bookmark = GetNodeByID(id, type);
481 const base::string16 title =
482 base::android::ConvertJavaStringToUTF16(env, j_title);
484 if (partner_bookmarks_shim_->IsPartnerBookmark(bookmark)) {
485 partner_bookmarks_shim_->RenameBookmark(bookmark, title);
486 } else {
487 bookmark_model_->SetTitle(bookmark, title);
491 void BookmarksBridge::SetBookmarkUrl(JNIEnv* env,
492 jobject obj,
493 jlong id,
494 jint type,
495 jstring url) {
496 DCHECK(IsLoaded());
497 bookmark_model_->SetURL(
498 GetNodeByID(id, type),
499 GURL(base::android::ConvertJavaStringToUTF16(env, url)));
502 bool BookmarksBridge::DoesBookmarkExist(JNIEnv* env,
503 jobject obj,
504 jlong id,
505 jint type) {
506 DCHECK(IsLoaded());
507 return GetNodeByID(id, type);
510 void BookmarksBridge::GetBookmarksForFolder(JNIEnv* env,
511 jobject obj,
512 jobject j_folder_id_obj,
513 jobject j_callback_obj,
514 jobject j_result_obj) {
515 DCHECK(IsLoaded());
516 long folder_id = JavaBookmarkIdGetId(env, j_folder_id_obj);
517 int type = JavaBookmarkIdGetType(env, j_folder_id_obj);
518 const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
520 if (!folder->is_folder() || !IsReachable(folder))
521 return;
523 // Recreate the java bookmarkId object due to fallback.
524 ScopedJavaLocalRef<jobject> folder_id_obj =
525 Java_BookmarksBridge_createBookmarkId(
526 env, folder->id(), GetBookmarkType(folder));
527 j_folder_id_obj = folder_id_obj.obj();
529 // Get the folder contents.
530 for (int i = 0; i < folder->child_count(); ++i) {
531 const BookmarkNode* node = folder->GetChild(i);
532 if (!IsFolderAvailable(node))
533 continue;
534 ExtractBookmarkNodeInformation(node, j_result_obj);
537 if (folder == bookmark_model_->mobile_node() &&
538 partner_bookmarks_shim_->HasPartnerBookmarks()) {
539 ExtractBookmarkNodeInformation(
540 partner_bookmarks_shim_->GetPartnerBookmarksRoot(),
541 j_result_obj);
544 if (j_callback_obj) {
545 Java_BookmarksCallback_onBookmarksAvailable(
546 env, j_callback_obj, j_folder_id_obj, j_result_obj);
550 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv* env,
551 jobject obj,
552 jobject j_folder_id_obj,
553 jobject j_callback_obj,
554 jobject j_result_obj) {
555 DCHECK(IsLoaded());
556 long folder_id = JavaBookmarkIdGetId(env, j_folder_id_obj);
557 int type = JavaBookmarkIdGetType(env, j_folder_id_obj);
558 const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
560 if (!folder->is_folder() || !IsReachable(folder))
561 return;
563 // Recreate the java bookmarkId object due to fallback.
564 ScopedJavaLocalRef<jobject> folder_id_obj =
565 Java_BookmarksBridge_createBookmarkId(
566 env, folder->id(), GetBookmarkType(folder));
567 j_folder_id_obj = folder_id_obj.obj();
569 // Get the folder hierarchy.
570 const BookmarkNode* node = folder;
571 while (node) {
572 ExtractBookmarkNodeInformation(node, j_result_obj);
573 node = GetParentNode(node);
576 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
577 env, j_callback_obj, j_folder_id_obj, j_result_obj);
580 ScopedJavaLocalRef<jobject> BookmarksBridge::AddFolder(JNIEnv* env,
581 jobject obj,
582 jobject j_parent_id_obj,
583 jint index,
584 jstring j_title) {
585 DCHECK(IsLoaded());
586 long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
587 int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
588 const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
590 const BookmarkNode* new_node = bookmark_model_->AddFolder(
591 parent, index, base::android::ConvertJavaStringToUTF16(env, j_title));
592 if (!new_node) {
593 NOTREACHED();
594 return ScopedJavaLocalRef<jobject>();
596 ScopedJavaLocalRef<jobject> new_java_obj =
597 Java_BookmarksBridge_createBookmarkId(
598 env, new_node->id(), GetBookmarkType(new_node));
599 return new_java_obj;
602 void BookmarksBridge::DeleteBookmark(JNIEnv* env,
603 jobject obj,
604 jobject j_bookmark_id_obj) {
605 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
606 DCHECK(IsLoaded());
608 long bookmark_id = JavaBookmarkIdGetId(env, j_bookmark_id_obj);
609 int type = JavaBookmarkIdGetType(env, j_bookmark_id_obj);
610 const BookmarkNode* node = GetNodeByID(bookmark_id, type);
611 if (!IsEditable(node)) {
612 NOTREACHED();
613 return;
616 if (partner_bookmarks_shim_->IsPartnerBookmark(node)) {
617 partner_bookmarks_shim_->RemoveBookmark(node);
618 } else {
619 const BookmarkNode* parent_node = GetParentNode(node);
620 bookmark_model_->Remove(parent_node, parent_node->GetIndexOf(node));
624 void BookmarksBridge::MoveBookmark(JNIEnv* env,
625 jobject obj,
626 jobject j_bookmark_id_obj,
627 jobject j_parent_id_obj,
628 jint index) {
629 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
630 DCHECK(IsLoaded());
632 long bookmark_id = JavaBookmarkIdGetId(env, j_bookmark_id_obj);
633 int type = JavaBookmarkIdGetType(env, j_bookmark_id_obj);
634 const BookmarkNode* node = GetNodeByID(bookmark_id, type);
635 if (!IsEditable(node)) {
636 NOTREACHED();
637 return;
639 bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
640 type = JavaBookmarkIdGetType(env, j_parent_id_obj);
641 const BookmarkNode* new_parent_node = GetNodeByID(bookmark_id, type);
642 bookmark_model_->Move(node, new_parent_node, index);
645 ScopedJavaLocalRef<jobject> BookmarksBridge::AddBookmark(
646 JNIEnv* env,
647 jobject obj,
648 jobject j_parent_id_obj,
649 jint index,
650 jstring j_title,
651 jstring j_url) {
652 DCHECK(IsLoaded());
653 long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
654 int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
655 const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
657 const BookmarkNode* new_node = bookmark_model_->AddURL(
658 parent,
659 index,
660 base::android::ConvertJavaStringToUTF16(env, j_title),
661 GURL(base::android::ConvertJavaStringToUTF16(env, j_url)));
662 if (!new_node) {
663 NOTREACHED();
664 return ScopedJavaLocalRef<jobject>();
666 ScopedJavaLocalRef<jobject> new_java_obj =
667 Java_BookmarksBridge_createBookmarkId(
668 env, new_node->id(), GetBookmarkType(new_node));
669 return new_java_obj;
672 ScopedJavaLocalRef<jobject> BookmarksBridge::CreateJavaBookmark(
673 const BookmarkNode* node) {
674 JNIEnv* env = AttachCurrentThread();
676 const BookmarkNode* parent = GetParentNode(node);
677 int64 parent_id = parent ? parent->id() : -1;
679 std::string url;
680 if (node->is_url())
681 url = node->url().spec();
683 return Java_BookmarksBridge_createBookmarkItem(
684 env,
685 node->id(),
686 GetBookmarkType(node),
687 ConvertUTF16ToJavaString(env, GetTitle(node)).obj(),
688 ConvertUTF8ToJavaString(env, url).obj(),
689 node->is_folder(),
690 parent_id,
691 GetBookmarkType(parent),
692 IsEditable(node),
693 IsManaged(node));
696 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode* node,
697 jobject j_result_obj) {
698 JNIEnv* env = AttachCurrentThread();
699 if (!IsReachable(node))
700 return;
701 Java_BookmarksBridge_addToList(
702 env, j_result_obj, CreateJavaBookmark(node).obj());
705 const BookmarkNode* BookmarksBridge::GetNodeByID(long node_id, int type) {
706 const BookmarkNode* node;
707 if (type == BookmarkType::PARTNER) {
708 node = partner_bookmarks_shim_->GetNodeByID(
709 static_cast<int64>(node_id));
710 } else {
711 node = bookmarks::GetBookmarkNodeByID(bookmark_model_,
712 static_cast<int64>(node_id));
714 return node;
717 const BookmarkNode* BookmarksBridge::GetFolderWithFallback(long folder_id,
718 int type) {
719 const BookmarkNode* folder = GetNodeByID(folder_id, type);
720 if (!folder || folder->type() == BookmarkNode::URL ||
721 !IsFolderAvailable(folder)) {
722 if (!client_->managed_node()->empty())
723 folder = client_->managed_node();
724 else
725 folder = bookmark_model_->mobile_node();
727 return folder;
730 bool BookmarksBridge::IsEditable(const BookmarkNode* node) const {
731 if (!node || (node->type() != BookmarkNode::FOLDER &&
732 node->type() != BookmarkNode::URL)) {
733 return false;
735 if (!IsEditBookmarksEnabled())
736 return false;
737 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
738 return partner_bookmarks_shim_->IsEditable(node);
739 return client_->CanBeEditedByUser(node);
742 bool BookmarksBridge::IsManaged(const BookmarkNode* node) const {
743 return client_->IsDescendantOfManagedNode(node);
746 const BookmarkNode* BookmarksBridge::GetParentNode(const BookmarkNode* node) {
747 DCHECK(IsLoaded());
748 if (node == partner_bookmarks_shim_->GetPartnerBookmarksRoot()) {
749 return bookmark_model_->mobile_node();
750 } else {
751 return node->parent();
755 int BookmarksBridge::GetBookmarkType(const BookmarkNode* node) {
756 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
757 return BookmarkType::PARTNER;
758 else
759 return BookmarkType::NORMAL;
762 base::string16 BookmarksBridge::GetTitle(const BookmarkNode* node) const {
763 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
764 return partner_bookmarks_shim_->GetTitle(node);
765 return node->GetTitle();
768 bool BookmarksBridge::IsReachable(const BookmarkNode* node) const {
769 if (!partner_bookmarks_shim_->IsPartnerBookmark(node))
770 return true;
771 return partner_bookmarks_shim_->IsReachable(node);
774 bool BookmarksBridge::IsLoaded() const {
775 return (bookmark_model_->loaded() && partner_bookmarks_shim_->IsLoaded());
778 bool BookmarksBridge::IsFolderAvailable(
779 const BookmarkNode* folder) const {
780 // The managed bookmarks folder is not shown if there are no bookmarks
781 // configured via policy.
782 if (folder == client_->managed_node() && folder->empty())
783 return false;
785 SigninManager* signin = SigninManagerFactory::GetForProfile(
786 profile_->GetOriginalProfile());
787 return (folder->type() != BookmarkNode::BOOKMARK_BAR &&
788 folder->type() != BookmarkNode::OTHER_NODE) ||
789 (signin && signin->IsAuthenticated());
792 void BookmarksBridge::NotifyIfDoneLoading() {
793 if (!IsLoaded())
794 return;
795 JNIEnv* env = AttachCurrentThread();
796 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
797 if (obj.is_null())
798 return;
799 Java_BookmarksBridge_bookmarkModelLoaded(env, obj.obj());
802 // ------------- Observer-related methods ------------- //
804 void BookmarksBridge::BookmarkModelChanged() {
805 if (!IsLoaded())
806 return;
808 // Called when there are changes to the bookmark model. It is most
809 // likely changes to the partner bookmarks.
810 JNIEnv* env = AttachCurrentThread();
811 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
812 if (obj.is_null())
813 return;
814 Java_BookmarksBridge_bookmarkModelChanged(env, obj.obj());
817 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel* model,
818 bool ids_reassigned) {
819 NotifyIfDoneLoading();
822 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
823 if (!IsLoaded())
824 return;
826 JNIEnv* env = AttachCurrentThread();
827 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
828 if (obj.is_null())
829 return;
830 Java_BookmarksBridge_bookmarkModelDeleted(env, obj.obj());
833 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel* model,
834 const BookmarkNode* old_parent,
835 int old_index,
836 const BookmarkNode* new_parent,
837 int new_index) {
838 if (!IsLoaded())
839 return;
841 JNIEnv* env = AttachCurrentThread();
842 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
843 if (obj.is_null())
844 return;
845 Java_BookmarksBridge_bookmarkNodeMoved(
846 env,
847 obj.obj(),
848 CreateJavaBookmark(old_parent).obj(),
849 old_index,
850 CreateJavaBookmark(new_parent).obj(),
851 new_index);
854 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel* model,
855 const BookmarkNode* parent,
856 int index) {
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_bookmarkNodeAdded(
865 env,
866 obj.obj(),
867 CreateJavaBookmark(parent).obj(),
868 index);
871 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel* model,
872 const BookmarkNode* parent,
873 int old_index,
874 const BookmarkNode* node,
875 const std::set<GURL>& removed_urls) {
876 if (!IsLoaded())
877 return;
879 JNIEnv* env = AttachCurrentThread();
880 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
881 if (obj.is_null())
882 return;
883 Java_BookmarksBridge_bookmarkNodeRemoved(
884 env,
885 obj.obj(),
886 CreateJavaBookmark(parent).obj(),
887 old_index,
888 CreateJavaBookmark(node).obj());
891 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel* model,
892 const BookmarkNode* node) {
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_bookmarkNodeChanged(
901 env,
902 obj.obj(),
903 CreateJavaBookmark(node).obj());
906 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel* model,
907 const BookmarkNode* node) {
908 if (!IsLoaded())
909 return;
911 JNIEnv* env = AttachCurrentThread();
912 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
913 if (obj.is_null())
914 return;
915 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
916 env,
917 obj.obj(),
918 CreateJavaBookmark(node).obj());
921 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
922 if (!IsLoaded())
923 return;
925 JNIEnv* env = AttachCurrentThread();
926 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
927 if (obj.is_null())
928 return;
929 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env, obj.obj());
932 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
933 if (!IsLoaded())
934 return;
936 JNIEnv* env = AttachCurrentThread();
937 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
938 if (obj.is_null())
939 return;
940 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env, obj.obj());
943 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim* shim) {
944 if (!IsLoaded())
945 return;
947 BookmarkModelChanged();
950 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim* shim) {
951 NotifyIfDoneLoading();
954 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim* shim) {
955 partner_bookmarks_shim_ = NULL;