diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 16:23:34 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:37:21 +0000 |
commit | 38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch) | |
tree | c4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/components/send_tab_to_self | |
parent | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff) | |
download | qtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz |
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/send_tab_to_self')
15 files changed, 931 insertions, 0 deletions
diff --git a/chromium/components/send_tab_to_self/BUILD.gn b/chromium/components/send_tab_to_self/BUILD.gn new file mode 100644 index 00000000000..b6bca20fcde --- /dev/null +++ b/chromium/components/send_tab_to_self/BUILD.gn @@ -0,0 +1,42 @@ +# Copyright 2018 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. + +static_library("send_tab_to_self") { + sources = [ + "send_tab_to_self_bridge.cc", + "send_tab_to_self_bridge.h", + "send_tab_to_self_entry.cc", + "send_tab_to_self_entry.h", + "send_tab_to_self_model.cc", + "send_tab_to_self_model.h", + "send_tab_to_self_model_observer.h", + "send_tab_to_self_service.cc", + "send_tab_to_self_service.h", + ] + deps = [ + "//base", + "//components/keyed_service/core", + "//components/sync", + "//components/version_info", + "//url", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ + "send_tab_to_self_bridge_unittest.cc", + "send_tab_to_self_entry_unittest.cc", + ] + deps = [ + ":send_tab_to_self", + "//base", + "//base/test:test_support", + "//components/sync", + "//components/sync:test_support_driver", + "//components/sync:test_support_model", + "//testing/gtest", + "//url", + ] +} diff --git a/chromium/components/send_tab_to_self/DEPS b/chromium/components/send_tab_to_self/DEPS new file mode 100644 index 00000000000..4ccca580c24 --- /dev/null +++ b/chromium/components/send_tab_to_self/DEPS @@ -0,0 +1,5 @@ +include_rules = [ + "+components/keyed_service/core", + "+components/sync", + "+components/version_info", +] diff --git a/chromium/components/send_tab_to_self/OWNERS b/chromium/components/send_tab_to_self/OWNERS new file mode 100644 index 00000000000..a49acc9eff2 --- /dev/null +++ b/chromium/components/send_tab_to_self/OWNERS @@ -0,0 +1,6 @@ +hansberry@chromium.org +jeffreycohen@chromium.org +sebsg@chromium.org +tgupta@chromium.org + +# COMPONENT: UI>Browser>Sharing diff --git a/chromium/components/send_tab_to_self/README.md b/chromium/components/send_tab_to_self/README.md new file mode 100644 index 00000000000..8307f790b82 --- /dev/null +++ b/chromium/components/send_tab_to_self/README.md @@ -0,0 +1,8 @@ +Send Tab To Self + +Send Tab To Self is a component providing necessary APIs for sending tabs +between devices in Chrome. + +This feature will initially be developed for Android and Desktop, but with the +goal of moving to supporting all platforms. + diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc b/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc new file mode 100644 index 00000000000..549d5134413 --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc @@ -0,0 +1,184 @@ +// Copyright 2018 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. + +#include "components/send_tab_to_self/send_tab_to_self_bridge.h" + +#include "base/bind.h" +#include "base/guid.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/optional.h" +#include "base/time/clock.h" +#include "components/sync/device_info/device_info.h" +#include "components/sync/device_info/local_device_info_provider.h" +#include "components/sync/model/entity_change.h" +#include "components/sync/model/metadata_batch.h" +#include "components/sync/model/metadata_change_list.h" +#include "components/sync/model/model_type_change_processor.h" +#include "components/sync/model/mutable_data_batch.h" +#include "components/sync/model_impl/in_memory_metadata_change_list.h" +#include "components/sync/protocol/model_type_state.pb.h" + +namespace send_tab_to_self { + +SendTabToSelfBridge::SendTabToSelfBridge( + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, + syncer::LocalDeviceInfoProvider* local_device_info_provider, + base::Clock* clock) + : ModelTypeSyncBridge(std::move(change_processor)), + local_device_info_provider_(local_device_info_provider), + clock_(clock) { + DCHECK(local_device_info_provider_); + DCHECK(clock_); + auto batch = std::make_unique<syncer::MetadataBatch>(); + this->change_processor()->ModelReadyToSync(std::move(batch)); + // TODO(jeffreycohen): Create a local store and read meta data from it. +} + +SendTabToSelfBridge::~SendTabToSelfBridge() { +} + +std::unique_ptr<syncer::MetadataChangeList> +SendTabToSelfBridge::CreateMetadataChangeList() { + return std::make_unique<syncer::InMemoryMetadataChangeList>(); +} + +base::Optional<syncer::ModelError> SendTabToSelfBridge::MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) { + return ApplySyncChanges(std::move(metadata_change_list), + std::move(entity_data)); +} + +base::Optional<syncer::ModelError> SendTabToSelfBridge::ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_changes) { + for (syncer::EntityChange& change : entity_changes) { + if (change.type() == syncer::EntityChange::ACTION_DELETE) { + entries_.erase(change.storage_key()); + } else { + const sync_pb::SendTabToSelfSpecifics& specifics = + change.data().specifics.send_tab_to_self(); + // TODO(jeffreycohen): FromProto expects a valid entry. External data + // needs to be sanitized before it's passed through. + std::unique_ptr<SendTabToSelfEntry> entry = + SendTabToSelfEntry::FromProto(specifics, clock_->Now()); + // This entry is new. Add it to the model. + entries_[entry->GetGUID()] = std::move(entry); + } + } + if (!entity_changes.empty()) { + NotifySendTabToSelfModelChanged(); + } + return base::nullopt; +} + +void SendTabToSelfBridge::GetData(StorageKeyList storage_keys, + DataCallback callback) { + syncer::InMemoryMetadataChangeList metadata_change_list; + + for (const std::string& guid : storage_keys) { + const SendTabToSelfEntry* entry = GetEntryByGUID(guid); + if (!entry) { + continue; + } + std::unique_ptr<sync_pb::SendTabToSelfSpecifics> specifics = + entry->AsProto(); + auto entity_data = std::make_unique<syncer::EntityData>(); + *entity_data->specifics.mutable_send_tab_to_self() = *specifics; + entity_data->non_unique_name = specifics->url(); + + change_processor()->Put(specifics->guid(), std::move(entity_data), + &metadata_change_list); + } +} + +void SendTabToSelfBridge::GetAllDataForDebugging(DataCallback callback) { + // TODO(jeffreycohen): Add once we have a batch model. + NOTIMPLEMENTED(); +} + +std::string SendTabToSelfBridge::GetClientTag( + const syncer::EntityData& entity_data) { + return GetStorageKey(entity_data); +} + +std::string SendTabToSelfBridge::GetStorageKey( + const syncer::EntityData& entity_data) { + return entity_data.specifics.send_tab_to_self().guid(); +} + +std::vector<std::string> SendTabToSelfBridge::GetAllGuids() const { + std::vector<std::string> keys; + for (const auto& it : entries_) { + DCHECK_EQ(it.first, it.second->GetGUID()); + keys.push_back(it.first); + } + return keys; +} + +void SendTabToSelfBridge::DeleteAllEntries() { + if (!change_processor()->IsTrackingMetadata()) { + DCHECK_EQ(0ul, entries_.size()); + return; + } + syncer::InMemoryMetadataChangeList metadata_change_list; + + for (const auto& key : GetAllGuids()) { + change_processor()->Delete(key, &metadata_change_list); + } + entries_.clear(); +} + +const SendTabToSelfEntry* SendTabToSelfBridge::GetEntryByGUID( + const std::string& guid) const { + auto it = entries_.find(guid); + if (it == entries_.end()) { + return nullptr; + } + return it->second.get(); +} + +const SendTabToSelfEntry* SendTabToSelfBridge::AddEntry( + const GURL& url, + const std::string& title, + base::Time navigation_time) { + if (!change_processor()->IsTrackingMetadata()) { + return nullptr; + } + + std::string guid = base::GenerateGUID(); + + // TODO(jeffreycohen) Handle the fact that local device info may not be + // guaranteed in production code as it may take some time to get initialized. + DCHECK(local_device_info_provider_->GetLocalDeviceInfo()); + + // Assure that we don't have a guid collision. + DCHECK_EQ(GetEntryByGUID(guid), nullptr); + std::string trimmed_title = base::CollapseWhitespaceASCII(title, false); + std::string device_name = + local_device_info_provider_->GetLocalDeviceInfo()->client_name(); + + auto entry = std::make_unique<SendTabToSelfEntry>( + guid, url, trimmed_title, clock_->Now(), navigation_time, device_name); + + syncer::InMemoryMetadataChangeList metadata_change_list; + + // This entry is new. Add it to the store and model. + auto entity_data = std::make_unique<syncer::EntityData>(); + *entity_data->specifics.mutable_send_tab_to_self() = *entry->AsProto(); + entity_data->non_unique_name = entry->GetURL().spec(); + entity_data->creation_time = entry->GetSharedTime(); + + change_processor()->Put(guid, std::move(entity_data), &metadata_change_list); + + return entries_.emplace(guid, std::move(entry)).first->second.get(); +} + +void SendTabToSelfBridge::NotifySendTabToSelfModelChanged() { + for (SendTabToSelfModelObserver& observer : observers_) + observer.SendTabToSelfModelChanged(); +} + +} // namespace send_tab_to_self diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_bridge.h b/chromium/components/send_tab_to_self/send_tab_to_self_bridge.h new file mode 100644 index 00000000000..9cfc7e23475 --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_bridge.h @@ -0,0 +1,84 @@ +// Copyright 2018 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_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_BRIDGE_H_ +#define COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_BRIDGE_H_ + +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/macros.h" +#include "components/send_tab_to_self/send_tab_to_self_entry.h" +#include "components/send_tab_to_self/send_tab_to_self_model.h" +#include "components/sync/base/model_type.h" +#include "components/sync/model/model_type_sync_bridge.h" + +namespace syncer { +class LocalDeviceInfoProvider; +class ModelTypeChangeProcessor; +} // namespace syncer + +namespace base { +class Clock; +} // namespace base + +namespace send_tab_to_self { + +// Interface for a persistence layer for send tab to self. +// All interface methods have to be called on main thread. +class SendTabToSelfBridge : public syncer::ModelTypeSyncBridge, + public SendTabToSelfModel { + public: + // |local_device_info_provider| must not be null and must outlive this object. + // |clock| must not be null and must outlive this object. + SendTabToSelfBridge( + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, + syncer::LocalDeviceInfoProvider* local_device_info_provider, + base::Clock* clock); + ~SendTabToSelfBridge() override; + + // syncer::ModelTypeSyncBridge overrides. + std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList() + override; + base::Optional<syncer::ModelError> MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) override; + base::Optional<syncer::ModelError> ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_changes) override; + void GetData(StorageKeyList storage_keys, DataCallback callback) override; + void GetAllDataForDebugging(DataCallback callback) override; + std::string GetClientTag(const syncer::EntityData& entity_data) override; + std::string GetStorageKey(const syncer::EntityData& entity_data) override; + + // SendTabToSelfModel overrides. + std::vector<std::string> GetAllGuids() const override; + void DeleteAllEntries() override; + const SendTabToSelfEntry* GetEntryByGUID( + const std::string& guid) const override; + const SendTabToSelfEntry* AddEntry(const GURL& url, + const std::string& title, + base::Time navigation_time) override; + + private: + using SendTabToSelfEntries = + std::map<std::string, std::unique_ptr<SendTabToSelfEntry>>; + + // Notify all observers of a change; + void NotifySendTabToSelfModelChanged(); + + // |entries_| is keyed by GUIDs. + SendTabToSelfEntries entries_; + const syncer::LocalDeviceInfoProvider* const local_device_info_provider_; + const base::Clock* const clock_; + + DISALLOW_COPY_AND_ASSIGN(SendTabToSelfBridge); +}; + +} // namespace send_tab_to_self + +#endif // COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_BRIDGE_H_ diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc b/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc new file mode 100644 index 00000000000..ac447adfdc6 --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc @@ -0,0 +1,139 @@ +// Copyright 2019 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. + +#include "components/send_tab_to_self/send_tab_to_self_bridge.h" + +#include <map> +#include <set> +#include <utility> + +#include "base/bind.h" +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "base/test/simple_test_clock.h" +#include "components/sync/device_info/local_device_info_provider_mock.h" +#include "components/sync/model/metadata_batch.h" +#include "components/sync/model/mock_model_type_change_processor.h" +#include "components/sync/model_impl/in_memory_metadata_change_list.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace send_tab_to_self { + +namespace { + +using testing::_; + +class SendTabToSelfBridgeTest : public testing::Test { + protected: + SendTabToSelfBridgeTest() + : bridge_(mock_processor_.CreateForwardingProcessor(), + &provider_, + &clock_) { + provider_.Initialize("cache_guid", "machine"); + ON_CALL(mock_processor_, IsTrackingMetadata()) + .WillByDefault(testing::Return(true)); + } + + base::Time AdvanceAndGetTime() { + clock_.Advance(base::TimeDelta::FromMilliseconds(10)); + return clock_.Now(); + } + + syncer::EntityDataPtr MakeEntityData(const SendTabToSelfEntry& entry) { + std::unique_ptr<sync_pb::SendTabToSelfSpecifics> specifics = + entry.AsProto(); + + auto entity_data = std::make_unique<syncer::EntityData>(); + + *(entity_data->specifics.mutable_send_tab_to_self()) = *specifics; + entity_data->non_unique_name = entry.GetURL().spec(); + // The client_tag_hash field is unused by the send_tab_to_self_bridge, but + // is required for a valid entity_data. + entity_data->client_tag_hash = "someclienttaghash"; + return entity_data->PassToPtr(); + } + + // For Model Tests. + void AddSampleEntries() { + // Adds timer to avoid having two entries with the same shared timestamp. + bridge_.AddEntry(GURL("http://a.com"), "a", AdvanceAndGetTime()); + bridge_.AddEntry(GURL("http://b.com"), "b", AdvanceAndGetTime()); + bridge_.AddEntry(GURL("http://c.com"), "c", AdvanceAndGetTime()); + bridge_.AddEntry(GURL("http://d.com"), "d", AdvanceAndGetTime()); + } + + base::SimpleTestClock clock_; + + // In memory model type store needs to be able to post tasks. + base::test::ScopedTaskEnvironment task_environment_; + + syncer::LocalDeviceInfoProviderMock provider_; + + syncer::MockModelTypeChangeProcessor mock_processor_; + + SendTabToSelfBridge bridge_; + + private: + DISALLOW_COPY_AND_ASSIGN(SendTabToSelfBridgeTest); +}; + +TEST_F(SendTabToSelfBridgeTest, CheckEmpties) { + EXPECT_EQ(0ul, bridge_.GetAllGuids().size()); + AddSampleEntries(); + EXPECT_EQ(4ul, bridge_.GetAllGuids().size()); +} + +TEST_F(SendTabToSelfBridgeTest, SyncAddOneEntry) { + syncer::EntityChangeList remote_input; + + SendTabToSelfEntry entry("guid1", GURL("http://www.example.com/"), "title", + AdvanceAndGetTime(), AdvanceAndGetTime(), "device"); + + remote_input.push_back( + syncer::EntityChange::CreateAdd("guid1", MakeEntityData(entry))); + auto metadata_change_list = + std::make_unique<syncer::InMemoryMetadataChangeList>(); + bridge_.MergeSyncData(std::move(metadata_change_list), remote_input); + EXPECT_EQ(1ul, bridge_.GetAllGuids().size()); +} + +TEST_F(SendTabToSelfBridgeTest, ApplySyncChangesOneAdd) { + SendTabToSelfEntry entry("guid1", GURL("http://www.example.com/"), "title", + AdvanceAndGetTime(), AdvanceAndGetTime(), "device"); + std::unique_ptr<sync_pb::SendTabToSelfSpecifics> specifics = entry.AsProto(); + + syncer::EntityChangeList add_changes; + + add_changes.push_back( + syncer::EntityChange::CreateAdd("guid1", MakeEntityData(entry))); + auto metadata_change_list = + std::make_unique<syncer::InMemoryMetadataChangeList>(); + bridge_.ApplySyncChanges(std::move(metadata_change_list), add_changes); + EXPECT_EQ(1ul, bridge_.GetAllGuids().size()); +} + +// Tests that the send tab to self entry is correctly removed. +TEST_F(SendTabToSelfBridgeTest, ApplySyncChangesOneDeletion) { + SendTabToSelfEntry entry("guid1", GURL("http://www.example.com/"), "title", + AdvanceAndGetTime(), AdvanceAndGetTime(), "device"); + std::unique_ptr<sync_pb::SendTabToSelfSpecifics> specifics = entry.AsProto(); + + syncer::EntityChangeList add_changes; + + add_changes.push_back( + syncer::EntityChange::CreateAdd("guid1", MakeEntityData(entry))); + auto metadata_change_list = + std::make_unique<syncer::InMemoryMetadataChangeList>(); + bridge_.ApplySyncChanges(std::move(metadata_change_list), add_changes); + EXPECT_EQ(1ul, bridge_.GetAllGuids().size()); + syncer::EntityChangeList delete_changes; + delete_changes.push_back(syncer::EntityChange::CreateDelete("guid1")); + bridge_.ApplySyncChanges(std::move(metadata_change_list), delete_changes); + EXPECT_EQ(0ul, bridge_.GetAllGuids().size()); +} + +} // namespace + +} // namespace send_tab_to_self diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_entry.cc b/chromium/components/send_tab_to_self/send_tab_to_self_entry.cc new file mode 100644 index 00000000000..6fc811f4568 --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_entry.cc @@ -0,0 +1,98 @@ +// Copyright 2018 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. + +#include "components/send_tab_to_self/send_tab_to_self_entry.h" + +#include "base/guid.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "components/sync/protocol/send_tab_to_self_specifics.pb.h" + +namespace send_tab_to_self { + +SendTabToSelfEntry::SendTabToSelfEntry(const std::string& guid, + const GURL& url, + const std::string& title, + base::Time shared_time, + base::Time original_navigation_time, + const std::string& device_name) + : guid_(guid), + url_(url), + title_(title), + device_name_(device_name), + shared_time_(shared_time), + original_navigation_time_(original_navigation_time) { + DCHECK(!guid_.empty()); + DCHECK(url_.is_valid()); +} + +SendTabToSelfEntry::~SendTabToSelfEntry() {} + +const std::string& SendTabToSelfEntry::GetGUID() const { + return guid_; +} + +const GURL& SendTabToSelfEntry::GetURL() const { + return url_; +} + +const std::string& SendTabToSelfEntry::GetTitle() const { + return title_; +} + +base::Time SendTabToSelfEntry::GetSharedTime() const { + return shared_time_; +} + +base::Time SendTabToSelfEntry::GetOriginalNavigationTime() const { + return original_navigation_time_; +} + +const std::string& SendTabToSelfEntry::GetDeviceName() const { + return device_name_; +} + +std::unique_ptr<sync_pb::SendTabToSelfSpecifics> SendTabToSelfEntry::AsProto() + const { + auto pb_entry = std::make_unique<sync_pb::SendTabToSelfSpecifics>(); + + pb_entry->set_guid(GetGUID()); + pb_entry->set_title(GetTitle()); + pb_entry->set_url(GetURL().spec()); + pb_entry->set_shared_time_usec( + GetSharedTime().ToDeltaSinceWindowsEpoch().InMicroseconds()); + pb_entry->set_navigation_time_usec( + GetOriginalNavigationTime().ToDeltaSinceWindowsEpoch().InMicroseconds()); + pb_entry->set_device_name(GetDeviceName()); + + return pb_entry; +} + +std::unique_ptr<SendTabToSelfEntry> SendTabToSelfEntry::FromProto( + const sync_pb::SendTabToSelfSpecifics& pb_entry, + base::Time now) { + std::string guid(pb_entry.guid()); + DCHECK(!guid.empty()); + + GURL url(pb_entry.url()); + DCHECK(url.is_valid()); + + base::Time shared_time = base::Time::FromDeltaSinceWindowsEpoch( + base::TimeDelta::FromMicroseconds(pb_entry.shared_time_usec())); + if (shared_time > now) { + shared_time = now; + } + + base::Time navigation_time; + if (pb_entry.has_navigation_time_usec()) { + navigation_time = base::Time::FromDeltaSinceWindowsEpoch( + base::TimeDelta::FromMicroseconds(pb_entry.navigation_time_usec())); + } + + return std::make_unique<SendTabToSelfEntry>(guid, url, pb_entry.title(), + shared_time, navigation_time, + pb_entry.device_name()); +} + +} // namespace send_tab_to_self diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_entry.h b/chromium/components/send_tab_to_self/send_tab_to_self_entry.h new file mode 100644 index 00000000000..ab0b98e7ee8 --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_entry.h @@ -0,0 +1,74 @@ +// Copyright 2018 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_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_ENTRY_H_ +#define COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_ENTRY_H_ + +#include <string> + +#include "base/macros.h" +#include "base/time/time.h" +#include "url/gurl.h" + +namespace sync_pb { +class SendTabToSelfSpecifics; +} + +namespace send_tab_to_self { + +// A tab that is being shared. The URL is a unique identifier for an entry, as +// such it should not be empty and is the only thing considered when comparing +// entries. +class SendTabToSelfEntry { + public: + // Creates a SendTabToSelf entry. |url| and |title| are the main fields of the + // entry. + // |now| is used to fill the |creation_time_us_| and all the update timestamp + // fields. + SendTabToSelfEntry(const std::string& guid, + const GURL& url, + const std::string& title, + base::Time shared_time, + base::Time original_navigation_time, + const std::string& device_name); + ~SendTabToSelfEntry(); + + // The unique random id for the entry. + const std::string& GetGUID() const; + // The URL of the page the user would like to send to themselves. + const GURL& GetURL() const; + // The title of the entry. Might be empty. + const std::string& GetTitle() const; + // The time that the tab was shared. + base::Time GetSharedTime() const; + // The time that the tab was navigated to. + base::Time GetOriginalNavigationTime() const; + + // The name of the device that originated the sent tab. + const std::string& GetDeviceName() const; + + // Returns a protobuf encoding the content of this SendTabToSelfEntry for + // sync. + std::unique_ptr<sync_pb::SendTabToSelfSpecifics> AsProto() const; + + // Creates a SendTabToSelfEntry from the protobuf format. + // If creation time is not set, it will be set to |now|. + static std::unique_ptr<SendTabToSelfEntry> FromProto( + const sync_pb::SendTabToSelfSpecifics& pb_entry, + base::Time now); + + private: + std::string guid_; + GURL url_; + std::string title_; + std::string device_name_; + base::Time shared_time_; + base::Time original_navigation_time_; + + DISALLOW_COPY_AND_ASSIGN(SendTabToSelfEntry); +}; + +} // namespace send_tab_to_self + +#endif // COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_ENTRY_H_ diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_entry_unittest.cc b/chromium/components/send_tab_to_self/send_tab_to_self_entry_unittest.cc new file mode 100644 index 00000000000..ba55592a0bd --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_entry_unittest.cc @@ -0,0 +1,100 @@ +// Copyright 2019 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. + +#include "components/send_tab_to_self/send_tab_to_self_entry.h" + +#include <memory> + +#include "base/test/simple_test_tick_clock.h" +#include "components/sync/protocol/send_tab_to_self_specifics.pb.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace send_tab_to_self { + +namespace { + +bool IsEqualForTesting(const SendTabToSelfEntry& a, + const SendTabToSelfEntry& b) { + return a.GetGUID() == b.GetGUID() && a.GetURL() == b.GetURL() && + a.GetTitle() == b.GetTitle() && + a.GetDeviceName() == b.GetDeviceName() && + a.GetSharedTime() == b.GetSharedTime() && + a.GetOriginalNavigationTime() == b.GetOriginalNavigationTime(); +} + +TEST(SendTabToSelfEntry, CompareEntries) { + const SendTabToSelfEntry e1("1", GURL("http://example.com"), "bar", + base::Time::FromTimeT(10), + base::Time::FromTimeT(10), "device"); + const SendTabToSelfEntry e2("1", GURL("http://example.com"), "bar", + base::Time::FromTimeT(10), + base::Time::FromTimeT(10), "device"); + + EXPECT_TRUE(IsEqualForTesting(e1, e2)); + const SendTabToSelfEntry e3("2", GURL("http://example.org"), "bar", + base::Time::FromTimeT(10), + base::Time::FromTimeT(10), "device"); + + EXPECT_FALSE(IsEqualForTesting(e1, e3)); +} + +TEST(SendTabToSelfEntry, SharedTime) { + SendTabToSelfEntry e("1", GURL("http://example.com"), "bar", + base::Time::FromTimeT(10), base::Time::FromTimeT(10), + "device"); + EXPECT_EQ("bar", e.GetTitle()); + // Getters return Base::Time values. + EXPECT_EQ(e.GetSharedTime(), base::Time::FromTimeT(10)); +} + +// Tests that the send tab to self entry is correctly encoded to +// sync_pb::SendTabToSelfSpecifics. +TEST(SendTabToSelfEntry, AsProto) { + SendTabToSelfEntry entry("1", GURL("http://example.com"), "bar", + base::Time::FromTimeT(10), base::Time::FromTimeT(10), + "device"); + base::Time shared_time = entry.GetSharedTime(); + base::Time navigation_time = entry.GetSharedTime(); + + std::unique_ptr<sync_pb::SendTabToSelfSpecifics> pb_entry(entry.AsProto()); + EXPECT_EQ(pb_entry->url(), "http://example.com/"); + EXPECT_EQ(pb_entry->title(), "bar"); + EXPECT_EQ(pb_entry->shared_time_usec(), + shared_time.ToDeltaSinceWindowsEpoch().InMicroseconds()); + + EXPECT_EQ(pb_entry->navigation_time_usec(), + navigation_time.ToDeltaSinceWindowsEpoch().InMicroseconds()); + EXPECT_EQ(pb_entry->device_name(), "device"); +} + +// Tests that the send tab to self entry is correctly parsed from +// sync_pb::SendTabToSelfSpecifics. +TEST(SendTabToSelfEntry, FromProto) { + std::unique_ptr<sync_pb::SendTabToSelfSpecifics> pb_entry = + std::make_unique<sync_pb::SendTabToSelfSpecifics>(); + pb_entry->set_guid("1"); + pb_entry->set_url("http://example.com/"); + pb_entry->set_title("title"); + pb_entry->set_device_name("device"); + pb_entry->set_shared_time_usec(1); + pb_entry->set_navigation_time_usec(1); + + std::unique_ptr<SendTabToSelfEntry> entry( + SendTabToSelfEntry::FromProto(*pb_entry, base::Time::FromTimeT(10))); + + EXPECT_EQ(entry->GetGUID(), "1"); + EXPECT_EQ(entry->GetURL().spec(), "http://example.com/"); + EXPECT_EQ(entry->GetTitle(), "title"); + EXPECT_EQ(entry->GetDeviceName(), "device"); + EXPECT_EQ(entry->GetSharedTime().ToDeltaSinceWindowsEpoch().InMicroseconds(), + 1); + EXPECT_EQ(entry->GetOriginalNavigationTime() + .ToDeltaSinceWindowsEpoch() + .InMicroseconds(), + 1); +} + +} // namespace + +} // namespace send_tab_to_self diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_model.cc b/chromium/components/send_tab_to_self/send_tab_to_self_model.cc new file mode 100644 index 00000000000..c2e4c883afa --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_model.cc @@ -0,0 +1,23 @@ +// Copyright 2018 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. + +#include "components/send_tab_to_self/send_tab_to_self_model.h" + +namespace send_tab_to_self { + +SendTabToSelfModel::SendTabToSelfModel() {} + +SendTabToSelfModel::~SendTabToSelfModel() {} + +// Observer methods. +void SendTabToSelfModel::AddObserver(SendTabToSelfModelObserver* observer) { + DCHECK(observer); + observers_.AddObserver(observer); +} + +void SendTabToSelfModel::RemoveObserver(SendTabToSelfModelObserver* observer) { + observers_.RemoveObserver(observer); +} + +} // namespace send_tab_to_self diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_model.h b/chromium/components/send_tab_to_self/send_tab_to_self_model.h new file mode 100644 index 00000000000..6ae0a69dc53 --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_model.h @@ -0,0 +1,55 @@ +// Copyright 2018 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_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_MODEL_H_ +#define COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_MODEL_H_ + +#include <vector> + +#include "base/observer_list.h" +#include "components/send_tab_to_self/send_tab_to_self_entry.h" +#include "components/send_tab_to_self/send_tab_to_self_model_observer.h" + +namespace send_tab_to_self { + +// The send tab to self model contains a list of entries of shared urls. +// This object should only be accessed from one thread, which is usually the +// main thread. +class SendTabToSelfModel { + public: + SendTabToSelfModel(); + virtual ~SendTabToSelfModel(); + + // Returns a vector of entry IDs in the model. + virtual std::vector<std::string> GetAllGuids() const = 0; + + // Delete all entries. + virtual void DeleteAllEntries() = 0; + + // Returns a specific entry. Returns null if the entry does not exist. + virtual const SendTabToSelfEntry* GetEntryByGUID( + const std::string& guid) const = 0; + + // Adds |url| at the top of the entries. The entry title will be a + // trimmed copy of |title|. + virtual const SendTabToSelfEntry* AddEntry(const GURL& url, + const std::string& title, + base::Time navigation_time) = 0; + + // Observer registration methods. The model will remove all observers upon + // destruction automatically. + void AddObserver(SendTabToSelfModelObserver* observer); + void RemoveObserver(SendTabToSelfModelObserver* observer); + + protected: + // The observers. + base::ObserverList<SendTabToSelfModelObserver>::Unchecked observers_; + + private: + DISALLOW_COPY_AND_ASSIGN(SendTabToSelfModel); +}; + +} // namespace send_tab_to_self + +#endif // COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_MODEL_H diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_model_observer.h b/chromium/components/send_tab_to_self/send_tab_to_self_model_observer.h new file mode 100644 index 00000000000..54c471c9fbf --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_model_observer.h @@ -0,0 +1,30 @@ +// Copyright 2019 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_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_MODEL_OBSERVER_H_ +#define COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_MODEL_OBSERVER_H_ + +namespace send_tab_to_self { + +// Observer for the Send Tab To Self model. In the observer methods care should +// be taken to not modify the model. +class SendTabToSelfModelObserver { + public: + SendTabToSelfModelObserver() {} + virtual ~SendTabToSelfModelObserver() {} + + // Invoked when the model has finished loading. Until this method is called it + // is unsafe to use the model. + virtual void SendTabToSelfModelLoaded() = 0; + + // Invoked when elements of the model are added, removed, or updated. + virtual void SendTabToSelfModelChanged() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(SendTabToSelfModelObserver); +}; + +} // namespace send_tab_to_self + +#endif // COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_MODEL_OBSERVER_H_ diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_service.cc b/chromium/components/send_tab_to_self/send_tab_to_self_service.cc new file mode 100644 index 00000000000..49916b60bf5 --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_service.cc @@ -0,0 +1,38 @@ +// Copyright 2019 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. + +#include "components/send_tab_to_self/send_tab_to_self_service.h" + +#include "base/bind.h" +#include "base/time/default_clock.h" +#include "components/send_tab_to_self/send_tab_to_self_bridge.h" +#include "components/send_tab_to_self/send_tab_to_self_model.h" +#include "components/sync/base/report_unrecoverable_error.h" +#include "components/sync/device_info/local_device_info_provider.h" +#include "components/sync/model_impl/client_tag_based_model_type_processor.h" + +namespace send_tab_to_self { + +SendTabToSelfService::SendTabToSelfService( + version_info::Channel channel, + syncer::LocalDeviceInfoProvider* local_device_info_provider) { + bridge_ = std::make_unique<send_tab_to_self::SendTabToSelfBridge>( + std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( + syncer::SEND_TAB_TO_SELF, + base::BindRepeating(&syncer::ReportUnrecoverableError, channel)), + local_device_info_provider, base::DefaultClock::GetInstance()); +} + +SendTabToSelfService::~SendTabToSelfService() = default; + +SendTabToSelfModel* SendTabToSelfService::GetSendTabToSelfModel() { + return bridge_.get(); +} + +base::WeakPtr<syncer::ModelTypeControllerDelegate> +SendTabToSelfService::GetControllerDelegate() { + return bridge_->change_processor()->GetControllerDelegate(); +} + +} // namespace send_tab_to_self diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_service.h b/chromium/components/send_tab_to_self/send_tab_to_self_service.h new file mode 100644 index 00000000000..44941a2933a --- /dev/null +++ b/chromium/components/send_tab_to_self/send_tab_to_self_service.h @@ -0,0 +1,45 @@ +// Copyright 2019 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_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_SERVICE_H_ +#define COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_SERVICE_H_ + +#include <memory> +#include <string> + +#include "base/memory/weak_ptr.h" +#include "components/keyed_service/core/keyed_service.h" +#include "components/version_info/channel.h" + +namespace syncer { +class ModelTypeControllerDelegate; +class LocalDeviceInfoProvider; +} // namespace syncer + +namespace send_tab_to_self { +class SendTabToSelfBridge; +class SendTabToSelfModel; + +// KeyedService responsible for send tab to self sync. +class SendTabToSelfService : public KeyedService { + public: + SendTabToSelfService( + version_info::Channel channel, + syncer::LocalDeviceInfoProvider* local_device_info_provider); + ~SendTabToSelfService() override; + + SendTabToSelfModel* GetSendTabToSelfModel(); + + // For ProfileSyncService to initialize the controller. + base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate(); + + private: + std::unique_ptr<SendTabToSelfBridge> bridge_; + + DISALLOW_COPY_AND_ASSIGN(SendTabToSelfService); +}; + +} // namespace send_tab_to_self + +#endif // COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_SERVICE_H_ |