blob: dbd76e1e7c2bc23f3ba715cc9c40b0af413eb271 [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_USER_NOTES_BROWSER_USER_NOTE_SERVICE_H_
#define COMPONENTS_USER_NOTES_BROWSER_USER_NOTE_SERVICE_H_
#include "components/keyed_service/core/keyed_service.h"
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/safe_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/unguessable_token.h"
#include "components/user_notes/interfaces/user_note_service_delegate.h"
#include "components/user_notes/interfaces/user_note_storage.h"
#include "components/user_notes/interfaces/user_notes_ui_delegate.h"
#include "components/user_notes/model/user_note.h"
#include "content/public/browser/weak_document_ptr.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/blink/public/mojom/annotation/annotation.mojom.h"
class UserNoteUICoordinatorTest;
namespace content {
class RenderFrameHost;
} // namespace content
namespace user_notes {
class FrameUserNoteChanges;
class UserNoteManager;
class UserNoteMetadataSnapshot;
// Keyed service coordinating the different parts (Renderer, UI layer, storage
// layer) of the User Notes feature for the current user profile.
class UserNoteService : public KeyedService,
public UserNotesUIDelegate,
public UserNoteStorage::Observer {
public:
using IdSet =
std::unordered_set<base::UnguessableToken, base::UnguessableTokenHash>;
UserNoteService(std::unique_ptr<UserNoteServiceDelegate> delegate,
std::unique_ptr<UserNoteStorage> storage);
~UserNoteService() override;
UserNoteService(const UserNoteService&) = delete;
UserNoteService& operator=(const UserNoteService&) = delete;
base::SafeRef<UserNoteService> GetSafeRef() const;
// Returns a pointer to the note model associated with the given ID, or
// `nullptr` if none exists.
const UserNote* GetNoteModel(const base::UnguessableToken& id) const;
// Returns true if the provided ID is found in the creation map, indicating
// the note is still in progress, and false otherwise.
bool IsNoteInProgress(const base::UnguessableToken& id) const;
// Called by the embedder when a frame navigates to a new URL. Queries the
// storage to find notes associated with that URL, and if there are any, kicks
// off the logic to display them in the page.
virtual void OnFrameNavigated(content::RenderFrameHost* rfh);
// Called by `UserNoteManager` objects when a `UserNoteInstance` is added to
// the page they're attached to. Updates the model map to add a ref to the
// given `UserNoteManager` for the note with the specified ID.
void OnNoteInstanceAddedToPage(const base::UnguessableToken& id,
UserNoteManager* manager);
// Same as `OnNoteInstanceAddedToPage`, except for when a note is removed from
// a page. Updates the model map to remove the ref to the given
// `UserNoteManager`. If this is the last page where the note was displayed,
// also deletes the model from the model map.
void OnNoteInstanceRemovedFromPage(const base::UnguessableToken& id,
UserNoteManager* manager);
// Called by a note manager when the user selects "Add a note" from the
// associated page's context menu. Kicks off the note creation process.
void OnAddNoteRequested(content::RenderFrameHost* frame,
bool has_selected_text);
// Called by a note manager when a user selects a web highlight in the page.
// This causes the associated note to become focused in the UserNotesUI.
void OnWebHighlightFocused(const base::UnguessableToken& id,
content::RenderFrameHost* rfh);
// UserNotesUIDelegate implementation.
void OnNoteSelected(const base::UnguessableToken& id,
content::RenderFrameHost* rfh) override;
void OnNoteDeleted(const base::UnguessableToken& id) override;
void OnNoteCreationDone(const base::UnguessableToken& id,
const std::u16string& note_content) override;
void OnNoteCreationCancelled(const base::UnguessableToken& id) override;
void OnNoteEdited(const base::UnguessableToken& id,
const std::u16string& note_content) override;
// UserNoteStorage implementation
void OnNotesChanged() override;
private:
struct ModelMapEntry {
explicit ModelMapEntry(std::unique_ptr<UserNote> m);
~ModelMapEntry();
ModelMapEntry(ModelMapEntry&& other);
ModelMapEntry(const ModelMapEntry&) = delete;
ModelMapEntry& operator=(const ModelMapEntry&) = delete;
std::unique_ptr<UserNote> model;
std::unordered_set<UserNoteManager*> managers;
};
friend class MockUserNoteService;
friend class UserNoteBaseTest;
friend class UserNoteInstanceTest;
friend class UserNoteUtilsTest;
friend class ::UserNoteUICoordinatorTest;
FRIEND_TEST_ALL_PREFIXES(UserNoteServiceTest,
OnNoteMetadataFetchedForNavigationSomeNotes);
FRIEND_TEST_ALL_PREFIXES(
UserNoteServiceTest,
OnNoteMetadataFetchedForNavigationSomeNotesBackground);
FRIEND_TEST_ALL_PREFIXES(UserNoteServiceTest,
OnNoteMetadataFetchedForNavigationNoNotes);
FRIEND_TEST_ALL_PREFIXES(UserNoteServiceTest,
OnNoteMetadataFetchedForNavigationNoNotesBackground);
FRIEND_TEST_ALL_PREFIXES(UserNoteServiceTest, OnNoteMetadataFetched);
FRIEND_TEST_ALL_PREFIXES(UserNoteServiceTest, OnNoteModelsFetched);
FRIEND_TEST_ALL_PREFIXES(UserNoteServiceTest, OnFrameChangesApplied);
void InitializeNewNoteForCreation(
content::WeakDocumentPtr document,
bool is_page_level,
mojo::PendingReceiver<blink::mojom::AnnotationAgentHost> host_receiver,
mojo::PendingRemote<blink::mojom::AnnotationAgent> agent_remote,
const std::string& serialized_selector,
const std::u16string& selected_text);
// Private helpers used when processing note storage changes. Marked virtual
// for tests to override.
virtual void OnNoteMetadataFetchedForNavigation(
const std::vector<content::WeakDocumentPtr>& all_frames,
UserNoteMetadataSnapshot metadata_snapshot);
virtual void OnNoteMetadataFetched(
const std::vector<content::WeakDocumentPtr>& all_frames,
UserNoteMetadataSnapshot metadata_snapshot);
virtual void OnNoteModelsFetched(
const IdSet& new_notes,
std::vector<std::unique_ptr<FrameUserNoteChanges>> note_changes,
std::vector<std::unique_ptr<UserNote>> notes);
virtual void OnFrameChangesApplied(base::UnguessableToken change_id);
// Source of truth for the in-memory note models. Any note currently being
// displayed in a tab is stored in this data structure. Each entry also
// contains a set of pointers to all `UserNoteManager` objects holding an
// instance of that note, which is necessary to clean up the models when
// they're no longer in use and to remove notes from affected web pages when
// they're deleted by the user.
std::unordered_map<base::UnguessableToken,
ModelMapEntry,
base::UnguessableTokenHash>
model_map_;
// A map to store in-progress notes during the note creation process. This is
// needed in order to separate incomplete notes from the rest of the real
// note models. Completed notes are eventually moved to the model map.
std::unordered_map<base::UnguessableToken,
ModelMapEntry,
base::UnguessableTokenHash>
creation_map_;
// A place to store the user note changes of a frame while they are being
// applied.
std::unordered_map<base::UnguessableToken,
std::unique_ptr<FrameUserNoteChanges>,
base::UnguessableTokenHash>
note_changes_in_progress_;
std::unique_ptr<UserNoteServiceDelegate> delegate_;
std::unique_ptr<UserNoteStorage> storage_;
base::WeakPtrFactory<UserNoteService> weak_ptr_factory_{this};
};
} // namespace user_notes
#endif // COMPONENTS_USER_NOTES_BROWSER_USER_NOTE_SERVICE_H_