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 167 168
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_COMPONENTS_MAGIC_BOOST_PUBLIC_CPP_MAGIC_BOOST_STATE_H_
#define CHROMEOS_COMPONENTS_MAGIC_BOOST_PUBLIC_CPP_MAGIC_BOOST_STATE_H_
#include "base/component_export.h"
#include "base/functional/callback.h"
#include "base/observer_list.h"
#include "base/types/expected.h"
namespace chromeos {
// HMR consent is two phases. These are flows and state transitions.
//
// Flow A (Mini Card):
// 1. Mini card is shown (kUnset -> kPendingDisclaimer | kDeclined)
// 2. Disclaimer dialog is shown (kPendingDisclaimer -> kApproved | kDeclined)
//
// *: If a user has pressed [No Thanks] in the mini card, kDeclined is set.
//
// Flow B (Settings):
// 1. A user toggles HMR settings in Settings UI
// (kUnset | kDeclined -> kPendingDisclaimer)
// 2. Disclaimer dialog is shown (kPendingDisclaimer -> kApproved | kDeclined)
enum class HMRConsentStatus : int {
// User has agreed to consent by pressing the accept button on the disclaimer
// UI.
kApproved = 0,
// User has disagreed to consent by pressing the decline button on the
// disclaimer UI or the opt-in card.
kDeclined = 1,
// This state is being used when the feature is turned on through the Settings
// app or a mini card and consent status is unset. In this case, we will show
// the disclaimer UI when users try to access the Mahi feature through the
// Mahi menu card.
kPendingDisclaimer = 2,
// Users hasn't accept nor decline the consent.
kUnset = 3,
};
// A class that holds MagicBoost related prefs and states.
class COMPONENT_EXPORT(MAGIC_BOOST) MagicBoostState {
public:
// A checked observer which receives MagicBoost state changes.
class Observer : public base::CheckedObserver {
public:
virtual void OnMagicBoostAvailableUpdated(bool available) {}
virtual void OnMagicBoostEnabledUpdated(bool enabled) {}
virtual void OnHMREnabledUpdated(bool enabled) {}
virtual void OnHMRConsentStatusUpdated(HMRConsentStatus status) {}
// `MagicBoostState` is being deleted. All `ScopedObservation`s MUST get
// reset. `ScopedObservation::Reset` accesses source (i.e., magic boost
// state pointer). This is intentionally defined as a pure virtual function
// as all observers care this.
virtual void OnIsDeleting() = 0;
};
enum class Error {
kUninitialized,
};
static MagicBoostState* Get();
MagicBoostState();
MagicBoostState(const MagicBoostState&) = delete;
MagicBoostState& operator=(const MagicBoostState&) = delete;
virtual ~MagicBoostState();
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Check if HMR requires the notice banner to appear in the settings page.
// It will be false in lacros and if the HMR consent status is anything other
// than Declined.
virtual bool CanShowNoticeBannerForHMR() = 0;
// Increments HMRWindowDismissCount count and returns an incremented value.
// Note that this method is not thread safe, i.e., this increment does NOT
// operate as an atomic operation. Reading HMRWindowDismissCount immediately
// after the write can read a stale value.
virtual int32_t AsyncIncrementHMRConsentWindowDismissCount() = 0;
// Writes consent status and a respective enabled state to the pref. Note that
// this method returns BEFORE a write is completed. Reading consent status
// and/or enabled state immediately after the write can read a stale value.
virtual void AsyncWriteConsentStatus(HMRConsentStatus consent_status) = 0;
// Writes HMR enabled value to the pref. Note that this method returns BEFORE
// a write is completed. Reading consent status and/or enabled state
// immediately after the write can read a stale value.
virtual void AsyncWriteHMREnabled(bool enabled) = 0;
// Indicates if the Orca feature should be included in the opt-in flow.
virtual void ShouldIncludeOrcaInOptIn(
base::OnceCallback<void(bool)> callback) {}
virtual bool ShouldIncludeOrcaInOptInSync() = 0;
// Marks Orca consent status as rejected and disable the feature.
virtual void DisableOrcaFeature() = 0;
// Marks Lobster settings toggle off.
virtual void DisableLobsterSettings() = 0;
// Returns true if Quick Answers or Mahi card should be shown (either consent
// is approved or pending).
bool ShouldShowHmrCard();
// `IsMagicBoostAvailable` tries reading availability value again if it's not
// set yet. See crbug.com/429501088 for details.
bool IsMagicBoostAvailable();
base::expected<bool, Error> magic_boost_available() const {
return magic_boost_available_;
}
base::expected<bool, Error> magic_boost_enabled() const {
return magic_boost_enabled_;
}
base::expected<bool, Error> hmr_enabled() const { return hmr_enabled_; }
base::expected<HMRConsentStatus, Error> hmr_consent_status() const {
return hmr_consent_status_;
}
int hmr_consent_window_dismiss_count() const {
return hmr_consent_window_dismiss_count_;
}
protected:
void UpdateMagicBoostAvailable(bool available);
void UpdateMagicBoostEnabled(bool enabled);
void UpdateHMREnabled(bool enabled);
void UpdateHMRConsentStatus(HMRConsentStatus status);
void UpdateHMRConsentWindowDismissCount(int32_t count);
// Returns availability of Magic Boost. Returns `Error::kUninitialized` if a
// dependent service is not initialized yet.
virtual base::expected<bool, chromeos::MagicBoostState::Error>
IsMagicBoostAvailableExpected() const = 0;
private:
void NotifyOnIsDeleting();
// Use `base::expected` instead of `std::optional` to avoid implicit bool
// conversion: https://abseil.io/tips/141.
base::expected<bool, Error> magic_boost_available_ =
base::unexpected(Error::kUninitialized);
base::expected<bool, Error> magic_boost_enabled_ =
base::unexpected(Error::kUninitialized);
base::expected<bool, Error> hmr_enabled_ =
base::unexpected(Error::kUninitialized);
base::expected<HMRConsentStatus, Error> hmr_consent_status_ =
base::unexpected(Error::kUninitialized);
int32_t hmr_consent_window_dismiss_count_ = 0;
base::ObserverList<Observer> observers_;
};
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_MAGIC_BOOST_PUBLIC_CPP_MAGIC_BOOST_STATE_H_
|