#include "base/android/jni_string.h"
#include "base/containers/stack_container.h"
+#include "base/i18n/string_compare.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
+#include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_android.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/undo/bookmark_undo_service.h"
+#include "chrome/browser/undo/bookmark_undo_service_factory.h"
+#include "chrome/browser/undo/undo_manager.h"
#include "chrome/common/pref_names.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/browser/bookmark_utils.h"
+#include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
#include "components/bookmarks/common/android/bookmark_type.h"
#include "components/signin/core/browser/signin_manager.h"
#include "content/public/browser/browser_thread.h"
return lhs->date_added().ToJavaTime() > rhs->date_added().ToJavaTime();
}
};
+
+class BookmarkTitleComparer {
+ public:
+ explicit BookmarkTitleComparer(const icu::Collator* collator)
+ : collator_(collator) {}
+
+ bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
+ if (collator_) {
+ return base::i18n::CompareString16WithCollator(
+ collator_, lhs->GetTitle(), rhs->GetTitle()) == UCOL_LESS;
+ } else {
+ return lhs->GetTitle() < rhs->GetTitle();
+ }
+ }
+
+private:
+ const icu::Collator* collator_;
+};
+
+scoped_ptr<icu::Collator> GetICUCollator() {
+ UErrorCode error = U_ZERO_ERROR;
+ scoped_ptr<icu::Collator> collator_;
+ collator_.reset(icu::Collator::createInstance(error));
+ if (U_FAILURE(error))
+ collator_.reset(NULL);
+
+ return collator_.Pass();
+}
+
} // namespace
BookmarksBridge::BookmarksBridge(JNIEnv* env,
static jlong GetNativeBookmarkModel(JNIEnv* env,
jclass caller,
jobject j_profile) {
- Profile *profile = ProfileAndroid::FromProfileAndroid(j_profile);
+ Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
BookmarkModel *bookmark_model_ = BookmarkModelFactory::GetForProfile(profile);
return reinterpret_cast<jlong>(bookmark_model_);
}
+static jboolean IsEnhancedBookmarksFeatureEnabled(JNIEnv* env,
+ jclass clazz,
+ jobject j_profile) {
+ Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
+ return IsEnhancedBookmarksEnabled(profile->GetPrefs());
+}
+
static bool IsEditBookmarksEnabled() {
return ProfileManager::GetLastUsedProfile()->GetPrefs()->GetBoolean(
- prefs::kEditBookmarksEnabled);
+ bookmarks::prefs::kEditBookmarksEnabled);
}
static jboolean IsEditBookmarksEnabled(JNIEnv* env, jclass clazz) {
return IsEditBookmarksEnabled();
}
+void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv* env,
+ jobject obj) {
+ if (partner_bookmarks_shim_->IsLoaded())
+ return;
+ partner_bookmarks_shim_->SetPartnerBookmarksRoot(
+ new BookmarkPermanentNode(0));
+ DCHECK(partner_bookmarks_shim_->IsLoaded());
+}
+
ScopedJavaLocalRef<jobject> BookmarksBridge::GetBookmarkByID(JNIEnv* env,
jobject obj,
jlong id,
return CreateJavaBookmark(GetNodeByID(id, type));
}
+bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv* env, jobject obj) {
+ return bookmark_model_->IsDoingExtensiveChanges();
+}
+
void BookmarksBridge::GetPermanentNodeIDs(JNIEnv* env,
jobject obj,
jobject j_result_obj) {
+ // TODO(kkimlabs): Remove this function.
DCHECK(IsLoaded());
base::StackVector<const BookmarkNode*, 8> permanent_nodes;
}
}
+void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv* env,
+ jobject obj,
+ jobject j_result_obj) {
+ Java_BookmarksBridge_addToBookmarkIdList(
+ env, j_result_obj, bookmark_model_->root_node()->id(),
+ GetBookmarkType(bookmark_model_->root_node()));
+ Java_BookmarksBridge_addToBookmarkIdList(
+ env, j_result_obj, bookmark_model_->mobile_node()->id(),
+ GetBookmarkType(bookmark_model_->mobile_node()));
+ Java_BookmarksBridge_addToBookmarkIdList(
+ env, j_result_obj, bookmark_model_->other_node()->id(),
+ GetBookmarkType(bookmark_model_->other_node()));
+}
+
+void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv* env,
+ jobject obj,
+ jboolean get_special,
+ jboolean get_normal,
+ jobject j_result_obj) {
+ DCHECK(IsLoaded());
+ std::vector<const BookmarkNode*> top_level_folders;
+
+ if (get_special) {
+ if (client_->managed_node() &&
+ client_->managed_node()->child_count() > 0) {
+ top_level_folders.push_back(client_->managed_node());
+ }
+ if (partner_bookmarks_shim_->HasPartnerBookmarks()) {
+ top_level_folders.push_back(
+ partner_bookmarks_shim_->GetPartnerBookmarksRoot());
+ }
+ }
+ std::size_t special_count = top_level_folders.size();
+
+ if (get_normal) {
+ DCHECK_EQ(bookmark_model_->root_node()->child_count(), 4);
+
+ top_level_folders.push_back(bookmark_model_->bookmark_bar_node());
+
+ const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
+ for (int i = 0; i < mobile_node->child_count(); ++i) {
+ const BookmarkNode* node = mobile_node->GetChild(i);
+ if (node->is_folder()) {
+ top_level_folders.push_back(node);
+ }
+ }
+
+ const BookmarkNode* other_node = bookmark_model_->other_node();
+ for (int i = 0; i < other_node->child_count(); ++i) {
+ const BookmarkNode* node = other_node->GetChild(i);
+ if (node->is_folder()) {
+ top_level_folders.push_back(node);
+ }
+ }
+
+ scoped_ptr<icu::Collator> collator = GetICUCollator();
+ std::stable_sort(top_level_folders.begin() + special_count,
+ top_level_folders.end(),
+ BookmarkTitleComparer(collator.get()));
+ }
+
+ for (std::vector<const BookmarkNode*>::const_iterator it =
+ top_level_folders.begin(); it != top_level_folders.end(); ++it) {
+ Java_BookmarksBridge_addToBookmarkIdList(env,
+ j_result_obj,
+ (*it)->id(),
+ GetBookmarkType(*it));
+ }
+}
+
+void BookmarksBridge::GetUncategorizedBookmarkIDs(JNIEnv* env,
+ jobject obj,
+ jobject j_result_obj) {
+ const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
+ for (int i = 0; i < mobile_node->child_count(); ++i) {
+ const BookmarkNode* node = mobile_node->GetChild(i);
+ if (!node->is_folder()) {
+ Java_BookmarksBridge_addToBookmarkIdList(env,
+ j_result_obj,
+ node->id(),
+ GetBookmarkType(node));
+ }
+ }
+
+ const BookmarkNode* other_node = bookmark_model_->other_node();
+ for (int i = 0; i < other_node->child_count(); ++i) {
+ const BookmarkNode* node = other_node->GetChild(i);
+ if (!node->is_folder()) {
+ Java_BookmarksBridge_addToBookmarkIdList(env,
+ j_result_obj,
+ node->id(),
+ GetBookmarkType(node));
+ }
+ }
+}
+
+void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv* env,
+ jobject obj,
+ jobject j_folders_obj,
+ jobject j_depths_obj) {
+ DCHECK(IsLoaded());
+
+ const BookmarkNode* desktop = bookmark_model_->bookmark_bar_node();
+ const BookmarkNode* mobile = bookmark_model_->mobile_node();
+ const BookmarkNode* other = bookmark_model_->other_node();
+
+ scoped_ptr<icu::Collator> collator = GetICUCollator();
+
+ // Vector to temporarily contain all child bookmarks at same level for sorting
+ std::vector<const BookmarkNode*> bookmarkList;
+ // Stack for Depth-First Search of bookmark model. It stores nodes and their
+ // heights.
+ std::stack<std::pair<const BookmarkNode*, int> > stk;
+
+ for (int i = 0; i < mobile->child_count(); ++i) {
+ const BookmarkNode* child = mobile->GetChild(i);
+ if (child->is_folder() && client_->CanBeEditedByUser(child))
+ bookmarkList.push_back(child);
+ }
+ for (int i = 0; i < other->child_count(); ++i) {
+ const BookmarkNode* child = other->GetChild(i);
+ if (child->is_folder() && client_->CanBeEditedByUser(child))
+ bookmarkList.push_back(child);
+ }
+ bookmarkList.push_back(desktop);
+ std::stable_sort(bookmarkList.begin(),
+ bookmarkList.end(),
+ BookmarkTitleComparer(collator.get()));
+
+ // Push all sorted top folders in stack and give them depth of 0.
+ // Note the order to push folders to stack should be opposite to the order in
+ // output.
+ for (std::vector<const BookmarkNode*>::reverse_iterator it =
+ bookmarkList.rbegin();
+ it != bookmarkList.rend();
+ ++it) {
+ stk.push(std::make_pair(*it, 0));
+ }
+
+ while (!stk.empty()) {
+ const BookmarkNode* node = stk.top().first;
+ int depth = stk.top().second;
+ stk.pop();
+ Java_BookmarksBridge_addToBookmarkIdListWithDepth(env,
+ j_folders_obj,
+ node->id(),
+ GetBookmarkType(node),
+ j_depths_obj,
+ depth);
+ bookmarkList.clear();
+ for (int i = 0; i < node->child_count(); ++i) {
+ const BookmarkNode* child = node->GetChild(i);
+ if (child->is_folder() && client_->CanBeEditedByUser(child))
+ bookmarkList.push_back(node->GetChild(i));
+ }
+ std::stable_sort(bookmarkList.begin(),
+ bookmarkList.end(),
+ BookmarkTitleComparer(collator.get()));
+ for (std::vector<const BookmarkNode*>::reverse_iterator it =
+ bookmarkList.rbegin();
+ it != bookmarkList.rend();
+ ++it) {
+ stk.push(std::make_pair(*it, depth + 1));
+ }
+ }
+}
+
+ScopedJavaLocalRef<jobject> BookmarksBridge::GetMobileFolderId(JNIEnv* env,
+ jobject obj) {
+ const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
+ ScopedJavaLocalRef<jobject> folder_id_obj =
+ Java_BookmarksBridge_createBookmarkId(
+ env, mobile_node->id(), GetBookmarkType(mobile_node));
+ return folder_id_obj;
+}
+
+ScopedJavaLocalRef<jobject> BookmarksBridge::GetOtherFolderId(JNIEnv* env,
+ jobject obj) {
+ const BookmarkNode* other_node = bookmark_model_->other_node();
+ ScopedJavaLocalRef<jobject> folder_id_obj =
+ Java_BookmarksBridge_createBookmarkId(
+ env, other_node->id(), GetBookmarkType(other_node));
+ return folder_id_obj;
+}
+
+ScopedJavaLocalRef<jobject> BookmarksBridge::GetDesktopFolderId(JNIEnv* env,
+ jobject obj) {
+ const BookmarkNode* desktop_node = bookmark_model_->bookmark_bar_node();
+ ScopedJavaLocalRef<jobject> folder_id_obj =
+ Java_BookmarksBridge_createBookmarkId(
+ env, desktop_node->id(), GetBookmarkType(desktop_node));
+ return folder_id_obj;
+}
+
void BookmarksBridge::GetChildIDs(JNIEnv* env,
jobject obj,
jlong id,
env, j_callback_obj, j_folder_id_obj, j_result_obj);
}
+ScopedJavaLocalRef<jobject> BookmarksBridge::AddFolder(JNIEnv* env,
+ jobject obj,
+ jobject j_parent_id_obj,
+ jint index,
+ jstring j_title) {
+ DCHECK(IsLoaded());
+ long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
+ int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
+ const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
+
+ const BookmarkNode* new_node = bookmark_model_->AddFolder(
+ parent, index, base::android::ConvertJavaStringToUTF16(env, j_title));
+ if (!new_node) {
+ NOTREACHED();
+ return ScopedJavaLocalRef<jobject>();
+ }
+ ScopedJavaLocalRef<jobject> new_java_obj =
+ Java_BookmarksBridge_createBookmarkId(
+ env, new_node->id(), GetBookmarkType(new_node));
+ return new_java_obj;
+}
+
void BookmarksBridge::DeleteBookmark(JNIEnv* env,
jobject obj,
jobject j_bookmark_id_obj) {
bookmark_model_->Move(node, new_parent_node, index);
}
+ScopedJavaLocalRef<jobject> BookmarksBridge::AddBookmark(
+ JNIEnv* env,
+ jobject obj,
+ jobject j_parent_id_obj,
+ jint index,
+ jstring j_title,
+ jstring j_url) {
+ DCHECK(IsLoaded());
+ long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
+ int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
+ const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
+
+ const BookmarkNode* new_node = bookmark_model_->AddURL(
+ parent,
+ index,
+ base::android::ConvertJavaStringToUTF16(env, j_title),
+ GURL(base::android::ConvertJavaStringToUTF16(env, j_url)));
+ if (!new_node) {
+ NOTREACHED();
+ return ScopedJavaLocalRef<jobject>();
+ }
+ ScopedJavaLocalRef<jobject> new_java_obj =
+ Java_BookmarksBridge_createBookmarkId(
+ env, new_node->id(), GetBookmarkType(new_node));
+ return new_java_obj;
+}
+
+void BookmarksBridge::Undo(JNIEnv* env, jobject obj) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(IsLoaded());
+ BookmarkUndoService* undo_service =
+ BookmarkUndoServiceFactory::GetForProfile(profile_);
+ UndoManager* undo_manager = undo_service->undo_manager();
+ undo_manager->Undo();
+}
+
+void BookmarksBridge::StartGroupingUndos(JNIEnv* env, jobject obj) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(IsLoaded());
+ DCHECK(!grouped_bookmark_actions_.get()); // shouldn't have started already
+ grouped_bookmark_actions_.reset(
+ new bookmarks::ScopedGroupBookmarkActions(bookmark_model_));
+}
+
+void BookmarksBridge::EndGroupingUndos(JNIEnv* env, jobject obj) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(IsLoaded());
+ DCHECK(grouped_bookmark_actions_.get()); // should only call after start
+ grouped_bookmark_actions_.reset();
+}
+
ScopedJavaLocalRef<jobject> BookmarksBridge::CreateJavaBookmark(
const BookmarkNode* node) {
JNIEnv* env = AttachCurrentThread();
profile_->GetOriginalProfile());
return (folder->type() != BookmarkNode::BOOKMARK_BAR &&
folder->type() != BookmarkNode::OTHER_NODE) ||
- (signin && !signin->GetAuthenticatedUsername().empty());
+ (signin && signin->IsAuthenticated());
}
void BookmarksBridge::NotifyIfDoneLoading() {