feature_promo_snooze_service.cc 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/user_education/common/feature_promo_snooze_service.h"
  5. #include <ostream>
  6. #include "base/feature_list.h"
  7. #include "base/json/values_util.h"
  8. #include "base/metrics/field_trial_params.h"
  9. #include "base/metrics/histogram_functions.h"
  10. #include "base/time/time.h"
  11. #include "base/values.h"
  12. #include "components/feature_engagement/public/feature_constants.h"
  13. #include "third_party/abseil-cpp/absl/types/optional.h"
  14. namespace user_education {
  15. namespace {
  16. constexpr base::FeatureParam<FeaturePromoSnoozeService::NonClickerPolicy>::
  17. Option kNonClickerPolicyOptions[] = {
  18. {FeaturePromoSnoozeService::NonClickerPolicy::kDismiss, "dismiss"},
  19. {FeaturePromoSnoozeService::NonClickerPolicy::kLongSnooze,
  20. "long_snooze"}};
  21. // Used in UMA histogram to track if the user snoozes for once or more.
  22. enum class SnoozeType {
  23. // The user snoozes the IPH for the first time.
  24. kFirstTimeSnooze = 0,
  25. // The user snoozes the IPH for the second time or more.
  26. kRepeatingSnooze = 1,
  27. kMaxValue = kRepeatingSnooze
  28. };
  29. } // namespace
  30. constexpr int FeaturePromoSnoozeService::kUmaMaxSnoozeCount;
  31. constexpr base::TimeDelta FeaturePromoSnoozeService::kDefaultSnoozeDuration;
  32. FeaturePromoSnoozeService::FeaturePromoSnoozeService() = default;
  33. FeaturePromoSnoozeService::~FeaturePromoSnoozeService() = default;
  34. void FeaturePromoSnoozeService::OnUserSnooze(const base::Feature& iph_feature,
  35. base::TimeDelta snooze_duration) {
  36. DCHECK(snooze_duration > base::Seconds(0));
  37. auto snooze_data = ReadSnoozeData(iph_feature);
  38. if (!snooze_data)
  39. snooze_data = SnoozeData();
  40. base::UmaHistogramEnumeration(
  41. "InProductHelp.Promos.Snooze." + std::string(iph_feature.name),
  42. snooze_data->snooze_count == 0 ? SnoozeType::kFirstTimeSnooze
  43. : SnoozeType::kRepeatingSnooze);
  44. snooze_data->last_snooze_time = base::Time::Now();
  45. snooze_data->last_snooze_duration = snooze_duration;
  46. snooze_data->snooze_count++;
  47. SaveSnoozeData(iph_feature, *snooze_data);
  48. }
  49. void FeaturePromoSnoozeService::OnUserDismiss(
  50. const base::Feature& iph_feature) {
  51. auto snooze_data = ReadSnoozeData(iph_feature);
  52. if (!snooze_data)
  53. snooze_data = SnoozeData();
  54. snooze_data->is_dismissed = true;
  55. SaveSnoozeData(iph_feature, *snooze_data);
  56. // Record count of previous snoozes when the IPH gets dismissed by "Got It"
  57. // button.
  58. base::UmaHistogramExactLinear(
  59. "InProductHelp.Promos.SnoozeCountAtAcknowledge." +
  60. std::string(iph_feature.name),
  61. snooze_data->snooze_count, kUmaMaxSnoozeCount);
  62. }
  63. void FeaturePromoSnoozeService::OnPromoShown(const base::Feature& iph_feature) {
  64. auto snooze_data = ReadSnoozeData(iph_feature);
  65. if (!snooze_data)
  66. snooze_data = SnoozeData();
  67. snooze_data->last_show_time = base::Time::Now();
  68. snooze_data->show_count++;
  69. SaveSnoozeData(iph_feature, *snooze_data);
  70. }
  71. bool FeaturePromoSnoozeService::IsBlocked(const base::Feature& iph_feature) {
  72. auto snooze_data = ReadSnoozeData(iph_feature);
  73. if (!snooze_data)
  74. return false;
  75. // This IPH has been dismissed by user permanently.
  76. if (snooze_data->is_dismissed)
  77. return true;
  78. // This IPH is shown for the first time.
  79. if (snooze_data->show_count == 0)
  80. return false;
  81. if (snooze_data->snooze_count > 0 &&
  82. snooze_data->last_snooze_time >= snooze_data->last_show_time) {
  83. // The IPH was snoozed on last display.
  84. // Corruption: Snooze time is in the future.
  85. if (snooze_data->last_snooze_time > base::Time::Now())
  86. return true;
  87. // This IPH is snoozed. Test if snooze period has expired.
  88. return base::Time::Now() <
  89. snooze_data->last_snooze_time + snooze_data->last_snooze_duration;
  90. } else {
  91. // The IPH was neither snoozed or dismissed on last display.
  92. const base::FeatureParam<FeaturePromoSnoozeService::NonClickerPolicy>
  93. kNonClickerPolicy{
  94. &iph_feature, "x_iph_snooze_non_clicker_policy",
  95. FeaturePromoSnoozeService::NonClickerPolicy::kLongSnooze,
  96. &kNonClickerPolicyOptions};
  97. NonClickerPolicy non_clicker_policy = kNonClickerPolicy.Get();
  98. if (non_clicker_policy == NonClickerPolicy::kDismiss)
  99. return true;
  100. return base::Time::Now() < snooze_data->last_show_time + base::Days(14);
  101. }
  102. }
  103. int FeaturePromoSnoozeService::GetSnoozeCount(
  104. const base::Feature& iph_feature) {
  105. absl::optional<SnoozeData> snooze_data = ReadSnoozeData(iph_feature);
  106. return snooze_data ? snooze_data->snooze_count : 0;
  107. }
  108. } // namespace user_education