File: hats_notification_controller.h

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (166 lines) | stat: -rw-r--r-- 6,958 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_HATS_HATS_NOTIFICATION_CONTROLLER_H_
#define CHROME_BROWSER_ASH_HATS_HATS_NOTIFICATION_CONTROLLER_H_

#include "base/containers/flat_map.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "chrome/browser/profiles/profile_observer.h"
#include "chromeos/ash/components/network/network_state_handler_observer.h"
#include "ui/message_center/public/cpp/notification_delegate.h"

namespace message_center {
class Notification;
}  // namespace message_center

class Profile;
class NetworkState;

namespace ash {

struct HatsConfig;

// TODO(jackshira): Extract non-notification specific code into a manager class.
// Happiness tracking survey (HaTS) notification controller is responsible for
// managing the HaTS notification that is displayed to the user.
// This class lives on the UI thread.
class HatsNotificationController : public message_center::NotificationDelegate,
                                   public NetworkStateHandlerObserver,
                                   public ProfileObserver {
 public:
  static const char kNotificationId[];

  // Minimum amount of time before the notification is displayed again after a
  // user has interacted with it.
  static constexpr base::TimeDelta kHatsThreshold = base::Days(60);

  // The threshold for a Googler is less.
  static constexpr base::TimeDelta kHatsGooglerThreshold = base::Days(30);

  // Prioritized HaTS has much shorter threshold.
  static constexpr base::TimeDelta kPrioritizedHatsThreshold = base::Days(10);

  // There are multiple pool/quota of cooldowns: normal and prioritized,
  // when user was selected for one pool, there need to be another cooldown
  // to ensure the user would not be selected for the other pool immediately
  // after.
  static constexpr base::TimeDelta kMinimumHatsThreshold = base::Days(1);

  // HaTS threshold should be configured correctly.
  static_assert(kHatsThreshold > kPrioritizedHatsThreshold);
  static_assert(kHatsThreshold > kHatsGooglerThreshold);
  static_assert(kPrioritizedHatsThreshold > kMinimumHatsThreshold);
  static_assert(kHatsGooglerThreshold > kMinimumHatsThreshold);

  HatsNotificationController(
      Profile* profile,
      const HatsConfig& config,
      const base::flat_map<std::string, std::string>& product_specific_data,
      std::u16string title,
      std::u16string body);

  // |product_specific_data| is meant to allow attaching extra runtime data that
  // is specific to the survey, e.g. a survey about the log-in experience might
  // include the last used authentication method.
  HatsNotificationController(
      Profile* profile,
      const HatsConfig& config,
      const base::flat_map<std::string, std::string>& product_specific_data);

  HatsNotificationController(Profile* profile, const HatsConfig& config);

  HatsNotificationController(const HatsNotificationController&) = delete;
  HatsNotificationController& operator=(const HatsNotificationController&) =
      delete;

  // Returns true if the survey needs to be displayed for the given |profile|.
  static bool ShouldShowSurveyToProfile(Profile* profile,
                                        const HatsConfig& config);

 private:
  friend class HatsNotificationControllerTest;
  FRIEND_TEST_ALL_PREFIXES(HatsNotificationControllerTest,
                           GetFormattedSiteContext);
  FRIEND_TEST_ALL_PREFIXES(HatsNotificationControllerTest,
                           NewDevice_ShouldNotShowNotification);
  FRIEND_TEST_ALL_PREFIXES(HatsNotificationControllerTest,
                           OldDevice_ShouldShowNotification);
  FRIEND_TEST_ALL_PREFIXES(HatsNotificationControllerTest,
                           NoInternet_DoNotShowNotification);
  FRIEND_TEST_ALL_PREFIXES(HatsNotificationControllerTest,
                           InternetConnected_ShowNotification);
  FRIEND_TEST_ALL_PREFIXES(HatsNotificationControllerTest,
                           DismissNotification_ShouldUpdatePref);
  FRIEND_TEST_ALL_PREFIXES(
      HatsNotificationControllerTest,
      Disconnected_RemoveNotification_Connected_AddNotification);
  FRIEND_TEST_ALL_PREFIXES(HatsNotificationControllerTest,
                           DismissNotification_PrioritizedShouldUpdatePref);

  ~HatsNotificationController() override;

  enum class HatsState {
    kDeviceSelected = 0,         // Device was selected in roll of dice.
    kSurveyShownRecently = 1,    // A survey was shown recently on device.
    kNewDevice = 2,              // Device is too new to show the survey.
    kNotificationDisplayed = 3,  // Pop up for survey was presented to user.
    kNotificationDismissed = 4,  // Notification was dismissed by user.
    kNotificationClicked = 5,    // User clicked on notification to open the
                                 // survey.

    kMaxValue = kNotificationClicked
  };

  void Initialize(bool is_new_device);

  // NotificationDelegate overrides:
  void Close(bool by_user) override;
  void Click(const std::optional<int>& button_index,
             const std::optional<std::u16string>& reply) override;

  // NetworkStateHandlerObserver override:
  void PortalStateChanged(const NetworkState* default_network,
                          NetworkState::PortalState portal_state) override;
  void OnShuttingDown() override;

  // ProfileObserver:
  void OnProfileWillBeDestroyed(Profile* profile) override;

  // Must be run on a blocking thread pool.
  // Gathers the browser version info, firmware info and platform info and
  // returns them in a single encoded string, in the format
  // "<key>=<value>&<key>=<value>&<key>=<value>" where the keys and values are
  // url-escaped. Any key-value pairs in |product_specific_data| are also
  // encoded and appended to the string, unless the keys collide with existing
  // device info keys.
  static std::string GetFormattedSiteContext(
      const std::string& user_locale,
      const base::flat_map<std::string, std::string>& product_specific_data);
  void UpdateLastInteractionTime();
  void UpdateLastSurveyInteractionTime();
  void ShowDialog(const std::string& site_context);

  raw_ptr<Profile> profile_;
  const raw_ref<const HatsConfig> hats_config_;
  base::flat_map<std::string, std::string> product_specific_data_;
  std::unique_ptr<message_center::Notification> notification_;
  const std::u16string title_;
  const std::u16string body_;

  HatsState state_ = HatsState::kDeviceSelected;

  base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this};

  base::WeakPtrFactory<HatsNotificationController> weak_pointer_factory_{this};
};

}  // namespace ash

#endif  // CHROME_BROWSER_ASH_HATS_HATS_NOTIFICATION_CONTROLLER_H_