Chromium Code Reviews| Index: services/preferences/user_prefs.cc |
| diff --git a/services/preferences/user_prefs.cc b/services/preferences/user_prefs.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a4f6ee9d1dfa6dbd920c2b0a447f701aef09450a |
| --- /dev/null |
| +++ b/services/preferences/user_prefs.cc |
| @@ -0,0 +1,161 @@ |
| +// Copyright 2017 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 "services/preferences/user_prefs.h" |
| + |
| +#include <utility> |
| + |
| +#include "base/auto_reset.h" |
| +#include "base/memory/ptr_util.h" |
| +#include "base/values.h" |
| +#include "components/prefs/persistent_pref_store.h" |
| +#include "mojo/public/cpp/bindings/binding.h" |
| + |
| +namespace prefs { |
| + |
| +class UserPrefs::Connection : public mojom::PersistentPrefStore { |
| + public: |
| + Connection(UserPrefs* user_prefs, |
| + mojom::PersistentPrefStoreRequest request, |
| + mojom::PrefStoreObserverPtr observer) |
| + : user_prefs_(user_prefs), |
| + binding_(this, std::move(request)), |
| + observer_(std::move(observer)) { |
| + auto error_callback = base::Bind(&UserPrefs::Connection::OnConnectionError, |
| + base::Unretained(this)); |
| + binding_.set_connection_error_handler(error_callback); |
| + observer_.set_connection_error_handler(error_callback); |
| + } |
| + |
| + ~Connection() override = default; |
| + |
| + void OnPrefValueChanged(const std::string& key, const base::Value* value) { |
| + if (call_in_progress_) |
| + return; |
| + |
| + observer_->OnPrefChanged(key, value ? value->CreateDeepCopy() : nullptr); |
| + } |
| + |
| + private: |
| + // mojom::PersistentPrefStore: |
| + void SetValue(const std::string& key, |
| + std::unique_ptr<base::Value> value, |
| + uint32_t flags) override { |
| + base::AutoReset<bool> scoped_call_in_progress(&call_in_progress_, true); |
| + user_prefs_->SetValue(key, std::move(value), flags); |
| + } |
| + |
| + void CommitPendingWrite() override { user_prefs_->CommitPendingWrite(); } |
| + void SchedulePendingLossyWrites() override { |
| + user_prefs_->SchedulePendingLossyWrites(); |
| + } |
| + void ClearMutableValues() override { user_prefs_->ClearMutableValues(); } |
| + |
| + void OnConnectionError() { user_prefs_->OnConnectionError(this); } |
| + |
| + // Owns |this|. |
| + UserPrefs* user_prefs_; |
| + |
| + mojo::Binding<mojom::PersistentPrefStore> binding_; |
| + mojom::PrefStoreObserverPtr observer_; |
| + |
| + bool call_in_progress_ = false; |
|
tibell
2017/03/10 02:18:27
Is this used to prohibit some kind of feedback loo
Sam McNally
2017/03/10 02:43:25
Done.
|
| + |
| + DISALLOW_COPY_AND_ASSIGN(Connection); |
| +}; |
| + |
| +UserPrefs::UserPrefs( |
| + scoped_refptr<PersistentPrefStore> backing_pref_store, |
| + mojom::TrackedPreferenceValidationDelegatePtr validation_delegate) |
| + : backing_pref_store_(backing_pref_store), |
| + validation_delegate_(std::move(validation_delegate)) { |
| + backing_pref_store_->AddObserver(this); |
| + if (!backing_pref_store_->IsInitializationComplete()) { |
| + initializing_ = true; |
| + backing_pref_store_->ReadPrefsAsync(nullptr); |
| + } |
| +} |
| + |
| +UserPrefs::~UserPrefs() { |
| + backing_pref_store_->RemoveObserver(this); |
| +} |
| + |
| +// mojom::PersistentPrefStoreConnector override: |
| +void UserPrefs::Connect(const ConnectCallback& callback) { |
| + if (initializing_) { |
| + pending_connect_callbacks_.push_back(callback); |
| + return; |
| + } |
| + CallConnectCallback(callback); |
| +} |
| + |
| +void UserPrefs::OnPrefValueChanged(const std::string& key) { |
| + // All mutations are triggered by a client. Updates are only sent to clients |
| + // other than the instigator. |
| + if (connections_.size() == 1) |
| + return; |
| + |
| + const base::Value* value = nullptr; |
| + backing_pref_store_->GetValue(key, &value); |
| + for (auto& entry : connections_) |
| + entry.first->OnPrefValueChanged(key, value); |
| +} |
| + |
| +void UserPrefs::OnInitializationCompleted(bool succeeded) { |
| + DCHECK(initializing_); |
| + initializing_ = false; |
| + for (const auto& callback : pending_connect_callbacks_) { |
| + CallConnectCallback(callback); |
| + } |
| + pending_connect_callbacks_.clear(); |
| +} |
| + |
| +void UserPrefs::CallConnectCallback( |
| + const mojom::PersistentPrefStoreConnector::ConnectCallback& callback) { |
| + DCHECK(!initializing_); |
| + if (!backing_pref_store_->IsInitializationComplete()) { |
| + callback.Run(backing_pref_store_->GetReadError(), |
| + backing_pref_store_->ReadOnly(), nullptr, nullptr, nullptr); |
| + return; |
| + } |
| + mojom::PersistentPrefStorePtr pref_store_ptr; |
| + mojom::PrefStoreObserverPtr observer; |
| + mojom::PrefStoreObserverRequest observer_request = |
| + mojo::MakeRequest(&observer); |
| + auto connection = base::MakeUnique<Connection>( |
| + this, mojo::MakeRequest(&pref_store_ptr), std::move(observer)); |
| + auto* connection_ptr = connection.get(); |
| + connections_.insert(std::make_pair(connection_ptr, std::move(connection))); |
| + callback.Run(backing_pref_store_->GetReadError(), |
| + backing_pref_store_->ReadOnly(), |
| + backing_pref_store_->GetValues(), std::move(pref_store_ptr), |
| + std::move(observer_request)); |
| +} |
| + |
| +void UserPrefs::SetValue(const std::string& key, |
| + std::unique_ptr<base::Value> value, |
| + uint32_t flags) { |
| + if (value) |
| + backing_pref_store_->SetValue(key, std::move(value), flags); |
| + else |
| + backing_pref_store_->RemoveValue(key, flags); |
| +} |
| + |
| +void UserPrefs::CommitPendingWrite() { |
| + backing_pref_store_->CommitPendingWrite(); |
| +} |
| + |
| +void UserPrefs::SchedulePendingLossyWrites() { |
| + backing_pref_store_->SchedulePendingLossyWrites(); |
| +} |
| + |
| +void UserPrefs::ClearMutableValues() { |
| + backing_pref_store_->ClearMutableValues(); |
| +} |
| + |
| +void UserPrefs::OnConnectionError(Connection* connection) { |
| + connections_.erase(connection); |
| +} |
| + |
| +} // namespace prefs |