blob: 97ac6b5c44d3afc3a9a1059a3be7d5719eb240ae [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_BOOKMARKS_ANDROID_BOOKMARK_BRIDGE_H_
#define CHROME_BROWSER_BOOKMARKS_ANDROID_BOOKMARK_BRIDGE_H_
#include <memory>
#include <set>
#include <string>
#include "base/android/jni_android.h"
#include "base/android/jni_weak_ref.h"
#include "base/containers/flat_map.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_multi_source_observation.h"
#include "base/scoped_observation.h"
#include "base/strings/utf_string_conversions.h"
#include "base/supports_user_data.h"
#include "chrome/browser/android/bookmarks/partner_bookmarks_shim.h"
#include "chrome/browser/image_service/image_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_observer.h"
#include "chrome/browser/reading_list/android/reading_list_manager.h"
#include "components/bookmarks/browser/base_bookmark_model_observer.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
#include "components/bookmarks/common/android/bookmark_id.h"
#include "components/bookmarks/managed/managed_bookmark_service.h"
#include "components/power_bookmarks/core/power_bookmark_utils.h"
#include "components/prefs/pref_change_registrar.h"
#include "url/android/gurl_android.h"
class BookmarkBridgeTest;
// The delegate to fetch bookmarks information for the Android native
// bookmark page. This fetches the bookmarks, title, urls, folder
// hierarchy.
// The life cycle of the bridge is controlled by the BookmarkModel through the
// user data pattern. Native side of the bridge owns its Java counterpart.
class BookmarkBridge : public ProfileObserver,
public bookmarks::BaseBookmarkModelObserver,
public PartnerBookmarksShim::Observer,
public ReadingListManager::Observer,
public base::SupportsUserData::Data {
public:
BookmarkBridge(
Profile* profile,
bookmarks::BookmarkModel* model,
bookmarks::ManagedBookmarkService* managed_bookmark_service,
PartnerBookmarksShim* partner_bookmarks_shim,
std::unique_ptr<ReadingListManager> local_or_synable_reading_list_manager,
std::unique_ptr<ReadingListManager> account_reading_list_manager,
page_image_service::ImageService* image_service);
BookmarkBridge(const BookmarkBridge&) = delete;
BookmarkBridge& operator=(const BookmarkBridge&) = delete;
~BookmarkBridge() override;
// Destroy the native object from Java.
void Destroy(JNIEnv*);
// Gets a reference to Java portion of the bridge.
base::android::ScopedJavaGlobalRef<jobject> GetJavaBookmarkModel();
int GetBookmarkType(const bookmarks::BookmarkNode* node);
const bookmarks::BookmarkNode* GetParentNode(
const bookmarks::BookmarkNode* node);
void GetImageUrlForBookmark(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_url,
const base::android::JavaParamRef<jobject>& j_callback);
base::android::ScopedJavaLocalRef<jobject>
GetMostRecentlyAddedUserBookmarkIdForUrl(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_url);
const bookmarks::BookmarkNode* GetMostRecentlyAddedUserBookmarkIdForUrlImpl(
const GURL& url);
bool IsDoingExtensiveChanges(JNIEnv* env);
jboolean IsEditBookmarksEnabled(JNIEnv* env);
void LoadEmptyPartnerBookmarkShimForTesting(JNIEnv* env);
// Loads a fake partner bookmarks shim for testing.
// This is used in BookmarkBridgeTest.java.
void LoadFakePartnerBookmarkShimForTesting(JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetBookmarkById(JNIEnv* env,
jlong id,
jint type);
void GetAllFoldersWithDepths(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_folders_obj,
const base::android::JavaParamRef<jobject>& j_depths_obj);
void GetTopLevelFolderIds(
JNIEnv* env,
jboolean j_ignore_visibility,
const base::android::JavaParamRef<jobject>& j_result_obj);
std::vector<const bookmarks::BookmarkNode*> GetTopLevelFolderIdsImpl(
bool ignore_visibility);
base::android::ScopedJavaLocalRef<jobject> GetRootFolderId(JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetMobileFolderId(JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetOtherFolderId(JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetDesktopFolderId(JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetAccountMobileFolderId(
JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetAccountOtherFolderId(
JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetAccountDesktopFolderId(
JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetPartnerFolderId(JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject>
GetLocalOrSyncableReadingListFolder(JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetAccountReadingListFolder(
JNIEnv* env);
base::android::ScopedJavaLocalRef<jobject> GetDefaultReadingListFolder(
JNIEnv* env);
base::android::ScopedJavaLocalRef<jstring> GetBookmarkGuidByIdForTesting(
JNIEnv* env,
jlong id,
jint type);
void GetChildIds(JNIEnv* env,
jlong id,
jint type,
const base::android::JavaParamRef<jobject>& j_result_obj);
std::vector<const bookmarks::BookmarkNode*> GetChildIdsImpl(
const bookmarks::BookmarkNode* parent);
jint GetChildCount(JNIEnv* env,
jlong id,
jint type);
base::android::ScopedJavaLocalRef<jobject> GetChildAt(JNIEnv* env,
jlong id,
jint type,
jint index);
void ReorderChildren(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_bookmark_id_obj,
jlongArray arr);
// Get the number of bookmarks in the sub tree of the specified bookmark node.
// The specified node must be of folder type.
jint GetTotalBookmarkCount(JNIEnv* env,
jlong id,
jint type);
void SetBookmarkTitle(JNIEnv* env,
jlong id,
jint type,
const base::android::JavaParamRef<jstring>& title);
void SetBookmarkUrl(JNIEnv* env,
jlong id,
jint type,
const base::android::JavaParamRef<jobject>& url);
void SetPowerBookmarkMeta(
JNIEnv* env,
jlong id,
jint type,
const base::android::JavaParamRef<jbyteArray>& bytes);
base::android::ScopedJavaLocalRef<jbyteArray> GetPowerBookmarkMeta(
JNIEnv* env,
jlong id,
jint type);
void DeletePowerBookmarkMeta(JNIEnv* env,
jlong id,
jint type);
bool DoesBookmarkExist(JNIEnv* env,
jlong id,
jint type);
void GetBookmarksForFolder(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_folder_id_obj,
const base::android::JavaParamRef<jobject>& j_result_obj);
jboolean IsFolderVisible(JNIEnv* env,
jlong id,
jint type);
void SearchBookmarks(JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_list,
const base::android::JavaParamRef<jstring>& j_query,
const base::android::JavaParamRef<jobjectArray>& j_tags,
jint type,
jint max_results);
std::vector<const bookmarks::BookmarkNode*> SearchBookmarksImpl(
power_bookmarks::PowerBookmarkQueryFields& query,
int max_results);
void GetBookmarksOfType(JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_list,
jint type);
base::android::ScopedJavaLocalRef<jobject> AddFolder(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_parent_id_obj,
jint index,
const base::android::JavaParamRef<jstring>& j_title);
void DeleteBookmark(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_bookmark_id_obj);
void DeleteBookmarkImpl(const bookmarks::BookmarkNode* node, int type);
void RemoveAllUserBookmarks(JNIEnv* env);
void MoveBookmark(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_bookmark_id_obj,
const base::android::JavaParamRef<jobject>& j_parent_id_obj,
jint j_index);
void MoveBookmarkImpl(const bookmarks::BookmarkNode* node,
int type,
const bookmarks::BookmarkNode* new_parent_node,
int parent_type,
int index);
base::android::ScopedJavaLocalRef<jobject> AddBookmark(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_parent_id_obj,
jint index,
const base::android::JavaParamRef<jstring>& j_title,
const base::android::JavaParamRef<jobject>& j_url);
base::android::ScopedJavaLocalRef<jobject> AddToReadingList(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_parent_id_obj,
const base::android::JavaParamRef<jstring>& j_title,
const base::android::JavaParamRef<jobject>& j_url);
void SetReadStatus(JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_id,
jboolean j_read);
jint GetUnreadCount(JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_id);
jboolean IsAccountBookmark(JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_id);
bool IsAccountBookmarkImpl(const bookmarks::BookmarkNode* node);
void Undo(JNIEnv* env);
void StartGroupingUndos(JNIEnv* env);
void EndGroupingUndos(JNIEnv* env);
bool IsBookmarked(JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_url);
std::u16string GetTitle(const bookmarks::BookmarkNode* node) const;
// ProfileObserver override
void OnProfileWillBeDestroyed(Profile* profile) override;
private:
base::android::ScopedJavaLocalRef<jobject> CreateJavaBookmark(
const bookmarks::BookmarkNode* node);
void ExtractBookmarkNodeInformation(
const bookmarks::BookmarkNode* node,
const base::android::JavaRef<jobject>& j_result_obj);
const bookmarks::BookmarkNode* GetNodeByID(long node_id, int type);
const bookmarks::BookmarkNode* GetFolderWithFallback(long folder_id,
int type);
bool IsEditBookmarksEnabled() const;
void EditBookmarksEnabledChanged();
// Returns whether |node| can be modified by the user.
bool IsEditable(const bookmarks::BookmarkNode* node) const;
// Returns whether |node| is a managed bookmark.
bool IsManaged(const bookmarks::BookmarkNode* node) const;
bool IsReachable(const bookmarks::BookmarkNode* node) const;
bool IsLoaded() const;
bool IsFolderAvailable(const bookmarks::BookmarkNode* folder) const;
void NotifyIfDoneLoading();
// Filters `nodes` on `IsReachable` and adds the result to the given
// `j_result_obj`.
void AddBookmarkNodesToBookmarkIdList(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_result_obj,
const std::vector<const bookmarks::BookmarkNode*>& nodes);
void FilterUnreachableBookmarks(
std::vector<const bookmarks::BookmarkNode*>* nodes);
// Returns the correct `ReadingListManager` given the corresponding `node`
// which is the root.
ReadingListManager* GetReadingListManagerFromParentNode(
const bookmarks::BookmarkNode* node);
// Moves `node` to be a child of `new_parent_node` which may require swapping
// to/from ReadingListManager.
void MoveNodeBetweenReadingListAndBookmarks(
const bookmarks::BookmarkNode* node,
int type,
const bookmarks::BookmarkNode* new_parent_node,
int parent_type,
int index);
// Override bookmarks::BaseBookmarkModelObserver.
// Called when there are changes to the bookmark model that don't trigger
// any of the other callback methods. For example, this is called when
// partner bookmarks change.
void BookmarkModelChanged() override;
void BookmarkModelLoaded(bookmarks::BookmarkModel* model,
bool ids_reassigned) override;
void BookmarkModelBeingDeleted(bookmarks::BookmarkModel* model) override;
void BookmarkNodeMoved(bookmarks::BookmarkModel* model,
const bookmarks::BookmarkNode* old_parent,
size_t old_index,
const bookmarks::BookmarkNode* new_parent,
size_t new_index) override;
void BookmarkNodeAdded(bookmarks::BookmarkModel* model,
const bookmarks::BookmarkNode* parent,
size_t index,
bool added_by_user) override;
void BookmarkNodeRemoved(bookmarks::BookmarkModel* model,
const bookmarks::BookmarkNode* parent,
size_t old_index,
const bookmarks::BookmarkNode* node,
const std::set<GURL>& removed_urls) override;
void BookmarkAllUserNodesRemoved(bookmarks::BookmarkModel* model,
const std::set<GURL>& removed_urls) override;
void BookmarkNodeChanged(bookmarks::BookmarkModel* model,
const bookmarks::BookmarkNode* node) override;
void BookmarkNodeChildrenReordered(
bookmarks::BookmarkModel* model,
const bookmarks::BookmarkNode* node) override;
void ExtensiveBookmarkChangesBeginning(
bookmarks::BookmarkModel* model) override;
void ExtensiveBookmarkChangesEnded(bookmarks::BookmarkModel* model) override;
// Override PartnerBookmarksShim::Observer
void PartnerShimChanged(PartnerBookmarksShim* shim) override;
void PartnerShimLoaded(PartnerBookmarksShim* shim) override;
void ShimBeingDeleted(PartnerBookmarksShim* shim) override;
// Override ReadingListManager::Observer
void ReadingListLoaded() override;
void ReadingListChanged() override;
void DestroyJavaObject();
raw_ptr<Profile> profile_; // weak
base::android::ScopedJavaGlobalRef<jobject> java_bookmark_model_;
raw_ptr<bookmarks::BookmarkModel> bookmark_model_; // weak
raw_ptr<bookmarks::ManagedBookmarkService> managed_bookmark_service_; // weak
std::unique_ptr<bookmarks::ScopedGroupBookmarkActions>
grouped_bookmark_actions_;
PrefChangeRegistrar pref_change_registrar_;
// Information about the Partner bookmarks (must check for IsLoaded()).
// This is owned by profile.
raw_ptr<PartnerBookmarksShim> partner_bookmarks_shim_;
// Holds reading list data as an in-memory BookmarkNode tree.
const std::unique_ptr<ReadingListManager>
local_or_syncable_reading_list_manager_;
// Holds account reading list data, similar to above. Only non-null if the
// account reading list is available.
const std::unique_ptr<ReadingListManager> account_reading_list_manager_;
raw_ptr<page_image_service::ImageService> image_service_; // weak
// Observes the profile destruction and creation.
base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this};
base::ScopedObservation<bookmarks::BookmarkModel,
bookmarks::BaseBookmarkModelObserver>
bookmark_model_observation_{this};
base::ScopedObservation<PartnerBookmarksShim, PartnerBookmarksShim::Observer>
partner_bookmarks_shim_observation_{this};
base::ScopedMultiSourceObservation<ReadingListManager,
ReadingListManager::Observer>
reading_list_manager_observations_{this};
bool suppress_observer_notifications_ = false;
// Weak pointers for creating callbacks that won't call into a destroyed
// object.
base::WeakPtrFactory<BookmarkBridge> weak_ptr_factory_;
};
#endif // CHROME_BROWSER_BOOKMARKS_ANDROID_BOOKMARK_BRIDGE_H_