| // Copyright 2020 The Fuchsia 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 "src/cobalt/bin/app/user_consent_watcher.h" | 
 |  | 
 | #include <lib/async/cpp/task.h> | 
 | #include <lib/fpromise/result.h> | 
 | #include <lib/syslog/cpp/macros.h> | 
 | #include <zircon/types.h> | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include <src/lib/fostr/fidl/fuchsia/settings/formatting.h> | 
 |  | 
 | namespace cobalt { | 
 |  | 
 | UserConsentWatcher::UserConsentWatcher( | 
 |     async_dispatcher_t *dispatcher, inspect::Node inspect_node, | 
 |     std::shared_ptr<sys::ServiceDirectory> services, | 
 |     std::function<void(const CobaltServiceInterface::DataCollectionPolicy &)> callback) | 
 |     : dispatcher_(dispatcher), | 
 |       inspect_node_(std::move(inspect_node)), | 
 |       services_(std::move(services)), | 
 |       callback_(std::move(callback)), | 
 |       backoff_(/*initial_delay=*/zx::msec(100), /*retry_factor=*/2u, /*max_delay=*/zx::hour(1)) { | 
 |   watch_successes_ = inspect_node_.CreateInt("successful_watches", 0); | 
 |   watch_errors_ = inspect_node_.CreateInt("watch_errors", 0); | 
 | } | 
 |  | 
 | void UserConsentWatcher::StartWatching() { | 
 |   privacy_settings_ptr_ = services_->Connect<fuchsia::settings::Privacy>(); | 
 |   privacy_settings_ptr_.set_error_handler([this](zx_status_t status) { | 
 |     watch_errors_.Add(1); | 
 |     FX_PLOGS(ERROR, status) << "Lost connection to fuchsia.settings.Privacy"; | 
 |     RestartWatching(); | 
 |   }); | 
 |  | 
 |   Watch(); | 
 | } | 
 |  | 
 | void UserConsentWatcher::RestartWatching() { | 
 |   ResetConsent(); | 
 |   privacy_settings_ptr_.Unbind(); | 
 |  | 
 |   reconnect_task_.Reset([this] { StartWatching(); }); | 
 |   async::PostDelayedTask( | 
 |       dispatcher_, [reconnect = reconnect_task_.callback()] { reconnect(); }, backoff_.GetNext()); | 
 | } | 
 |  | 
 | void UserConsentWatcher::Watch() { | 
 |   privacy_settings_ptr_->Watch([this](fuchsia::settings::PrivacySettings settings) { | 
 |     // Reset the exponential backoff since we successfully watched once. | 
 |     backoff_.Reset(); | 
 |  | 
 |     watch_successes_.Add(1); | 
 |     privacy_settings_ = std::move(settings); | 
 |     Update(); | 
 |  | 
 |     // We watch for the next update, following the hanging get pattern. | 
 |     Watch(); | 
 |   }); | 
 | } | 
 |  | 
 | void UserConsentWatcher::ResetConsent() { | 
 |   privacy_settings_.clear_user_data_sharing_consent(); | 
 |   Update(); | 
 | } | 
 |  | 
 | CobaltServiceInterface::DataCollectionPolicy UserConsentWatcher::GetDataCollectionPolicy() { | 
 |   if (!privacy_settings_.has_user_data_sharing_consent()) { | 
 |     return CobaltServiceInterface::DataCollectionPolicy::DO_NOT_UPLOAD; | 
 |   } | 
 |   if (privacy_settings_.user_data_sharing_consent()) { | 
 |     return CobaltServiceInterface::DataCollectionPolicy::COLLECT_AND_UPLOAD; | 
 |   } | 
 |   return CobaltServiceInterface::DataCollectionPolicy::DO_NOT_COLLECT; | 
 | } | 
 |  | 
 | void UserConsentWatcher::Update() { | 
 |   CobaltServiceInterface::DataCollectionPolicy policy = GetDataCollectionPolicy(); | 
 |   current_policy_ = inspect_node_.CreateInt("data_collection_policy", static_cast<int>(policy)); | 
 |   callback_(policy); | 
 | } | 
 |  | 
 | }  // namespace cobalt |