| // Copyright 2014 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/metrics/daily_event.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "base/metrics/histogram.h" | 
 | #include "components/prefs/pref_registry_simple.h" | 
 | #include "components/prefs/pref_service.h" | 
 |  | 
 | namespace metrics { | 
 |  | 
 | namespace { | 
 |  | 
 | void RecordIntervalTypeHistogram(const std::string& histogram_name, | 
 |                                  DailyEvent::IntervalType type) { | 
 |   const int num_types = static_cast<int>(DailyEvent::IntervalType::NUM_TYPES); | 
 |   base::Histogram::FactoryGet(histogram_name, 1, num_types, num_types + 1, | 
 |                               base::HistogramBase::kUmaTargetedHistogramFlag) | 
 |       ->Add(static_cast<int>(type)); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | DailyEvent::Observer::Observer() { | 
 | } | 
 |  | 
 | DailyEvent::Observer::~Observer() { | 
 | } | 
 |  | 
 | DailyEvent::DailyEvent(PrefService* pref_service, | 
 |                        const char* pref_name, | 
 |                        const std::string& histogram_name) | 
 |     : pref_service_(pref_service), | 
 |       pref_name_(pref_name), | 
 |       histogram_name_(histogram_name) { | 
 | } | 
 |  | 
 | DailyEvent::~DailyEvent() { | 
 | } | 
 |  | 
 | // static | 
 | void DailyEvent::RegisterPref(PrefRegistrySimple* registry, | 
 |                               const char* pref_name) { | 
 |   registry->RegisterInt64Pref(pref_name, 0); | 
 | } | 
 |  | 
 | void DailyEvent::AddObserver(std::unique_ptr<DailyEvent::Observer> observer) { | 
 |   DVLOG(2) << "DailyEvent observer added."; | 
 |   DCHECK(last_fired_.is_null()); | 
 |   observers_.push_back(std::move(observer)); | 
 | } | 
 |  | 
 | void DailyEvent::CheckInterval() { | 
 |   base::Time now = base::Time::Now(); | 
 |   if (last_fired_.is_null()) { | 
 |     // The first time we call CheckInterval, we read the time stored in prefs. | 
 |     last_fired_ = base::Time() + base::TimeDelta::FromMicroseconds( | 
 |                                      pref_service_->GetInt64(pref_name_)); | 
 |  | 
 |     DVLOG(1) << "DailyEvent time loaded: " << last_fired_; | 
 |     if (last_fired_.is_null()) { | 
 |       DVLOG(1) << "DailyEvent first run."; | 
 |       RecordIntervalTypeHistogram(histogram_name_, IntervalType::FIRST_RUN); | 
 |       OnInterval(now, IntervalType::FIRST_RUN); | 
 |       return; | 
 |     } | 
 |   } | 
 |   int days_elapsed = (now - last_fired_).InDays(); | 
 |   if (days_elapsed >= 1) { | 
 |     DVLOG(1) << "DailyEvent day elapsed."; | 
 |     RecordIntervalTypeHistogram(histogram_name_, IntervalType::DAY_ELAPSED); | 
 |     OnInterval(now, IntervalType::DAY_ELAPSED); | 
 |   } else if (days_elapsed <= -1) { | 
 |     // The "last fired" time is more than a day in the future, so the clock | 
 |     // must have been changed. | 
 |     DVLOG(1) << "DailyEvent clock change detected."; | 
 |     RecordIntervalTypeHistogram(histogram_name_, IntervalType::CLOCK_CHANGED); | 
 |     OnInterval(now, IntervalType::CLOCK_CHANGED); | 
 |   } | 
 | } | 
 |  | 
 | void DailyEvent::OnInterval(base::Time now, IntervalType type) { | 
 |   DCHECK(!now.is_null()); | 
 |   last_fired_ = now; | 
 |   pref_service_->SetInt64(pref_name_, | 
 |                           last_fired_.since_origin().InMicroseconds()); | 
 |  | 
 |   for (auto it = observers_.begin(); it != observers_.end(); ++it) { | 
 |     (*it)->OnDailyEvent(type); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace metrics |