File: glic_enabling.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (244 lines) | stat: -rw-r--r-- 10,288 bytes parent folder | download | duplicates (3)
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
// 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 CHROME_BROWSER_GLIC_GLIC_ENABLING_H_
#define CHROME_BROWSER_GLIC_GLIC_ENABLING_H_

#include "base/callback_list.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/types/expected.h"
#include "chrome/browser/glic/glic_user_status_fetcher.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/signin/public/identity_manager/identity_manager.h"

class Profile;
class ProfileAttributesStorage;

namespace glic {
namespace prefs {
enum class SettingsPolicyState;
}
namespace mojom {
// TODO(crbug.com/406500707): This forward declaration is needed because we use
// allow_circular_includes_from. Our build rules should be refactored to avoid
// this.
enum class ProfileReadyState : int32_t;
}  // namespace mojom

// This class provides a central location for checking if GLIC is enabled. It
// allows for future expansion to include other ways the feature may be disabled
// such as based on user preferences or system settings.
//
// There are multiple notions of "enabled". The highest level is
// IsEnabledByFlags which controls whether any global-Glic infrastructure is
// created. If flags are off, nothing Glic-related should be created.
//
// If flags are enabled, various global objects are created as well as a
// GlicKeyedService for each "eligible" profile. Eligible profiles exclude
// incognito, guest mode, system profile, etc. i.e. include only real user
// profiles. An eligible profile will create various Glic decorations and views
// for the profile's browser windows, regardless of whether Glic is actually
// "enabled" for the given profile. If disabled, those decorations should remain
// inert.  The GlicKeyedService is created for all eligible profiles so it can
// listen for changes to prefs which control the per-profile Glic-Enabled state.
//
// Finally, an eligible profile may be Glic-Enabled. In this state, Glic UI is
// visible and usable by the user. This state can change at runtime so Glic
// entry points should depend on this state.
class GlicEnabling : public signin::IdentityManager::Observer {
 public:
  // Returns whether the global Glic feature is enabled for Chrome. This status
  // will not change at runtime.
  static bool IsEnabledByFlags();

  // Some profiles - such as incognito, guest, system profile, etc. - are never
  // eligible to use Glic. This function returns true if a profile is eligible
  // for Glic, that is, it can potentially be enabled, regardless of whether it
  // is currently enabled or not. Always returns false if IsEnabledByFlags is
  // off. This will never change for a given profile.
  static bool IsProfileEligible(const Profile* profile);

  // This is a convenience method for code outside of //chrome/browser/glic.
  // Code inside should use instance method IsAllowed() instead.
  static bool IsEnabledForProfile(Profile* profile);

  // Returns true if the profile has completed the FRE.
  static bool HasConsentedForProfile(Profile* profile);

  // Returns true if the given profile has Glic enabled and has completed the
  // FRE. True implies that IsEnabledByFlags(), IsProfileEligible(profile), and
  // IsEnabledForProfile(profile) are also true. This value can change at
  // runtime.
  static bool IsEnabledAndConsentForProfile(Profile* profile);

  // Returns true if the given profile was shown the FRE but did not complete
  // it. This value can change at runtime.
  static bool DidDismissForProfile(Profile* profile);

  // Whether or not the profile is currently ready for Glic. This means no
  // additional steps must be taken before opening Glic.
  static bool IsReadyForProfile(Profile* profile);

  // Same as IsReadyForProfile, but returns a more detailed state.
  static mojom::ProfileReadyState GetProfileReadyState(Profile* profile);

  // Whether the profile is in the glic tiered rollout population.
  static bool IsEligibleForGlicTieredRollout(Profile* profile);

  // The settings page is shown when:
  // * Flags are enabled
  // * The profile is eligible (regular, non-incognito, non-guest, etc.)
  // * The profile has model execution privileges
  // * The profile has completed the first run experience
  static bool ShouldShowSettingsPage(Profile* profile);

  struct ProfileEnablement {
    // These conditions are checked first and may prevent following checks from
    // occurring.
    bool feature_disabled : 1 = false;
    bool not_regular_profile : 1 = false;

    // These are checked separately, so may be present in various combinations.
    bool not_rolled_out : 1 = false;
    bool primary_account_not_capable : 1 = false;
    bool disallowed_by_chrome_policy : 1 = false;
    bool disallowed_by_remote_admin : 1 = false;
    bool disallowed_by_remote_other : 1 = false;
    bool not_consented : 1 = false;

    bool IsProfileEligible() const {
      return !feature_disabled && !not_regular_profile;
    }

    bool IsEnabled() const {
      return IsProfileEligible() && !not_rolled_out &&
             !primary_account_not_capable && !DisallowedByAdmin() &&
             !disallowed_by_remote_other;
    }

    bool IsEnabledAndConsented() const { return IsEnabled() && !not_consented; }

    bool ShouldShowSettingsPage() const {
      // If the feature is disabled by enterprise policy, the settings page
      // should be shown (it will be shown in a policy-disabled state) only if
      // all other non-enterprise conditions are met: the account has all
      // appropriate permissions and has previously completed the FRE before the
      // policy went into effect.
      return IsProfileEligible() && !not_rolled_out &&
             !primary_account_not_capable && !disallowed_by_remote_other &&
             !not_consented;
    }

    bool DisallowedByAdmin() const {
      return disallowed_by_chrome_policy || disallowed_by_remote_admin;
    }
  };
  static ProfileEnablement EnablementForProfile(Profile* profile);

  explicit GlicEnabling(Profile* profile,
                        ProfileAttributesStorage* profile_attributes_storage);
  ~GlicEnabling() override;

  // Returns true if the given profile is allowed to use glic. This means that
  // IsProfileEligible() returns true and:
  //   * the profile is signed in
  //   * can_use_model_execution is true
  //   * glic is allowed by enterprise policy.
  // This value can change at runtime.
  //
  // Once a profile is allowed to run glic, there are several more checks that
  // are required to use glic although many callsites may not care about all of
  // these:
  //   * FRE has been passed. There is no way to permanently decline FRE, as
  //     it's only invoked on user interaction with glic entry points.
  //   * Entry point specific flags (e.g. kGlicPinnedToTabstrip).
  //   * Profile is not paused.
  // If all entry-points have been disabled, then glic is functionally disabled.
  bool IsAllowed();

  // Returns true if the given profile has completed the FRE and false
  // otherwise.
  bool HasConsented();

  void SetGlicUserStatusUrlForTest(const GURL& test_url) {
    glic_user_status_fetcher_->SetGlicUserStatusUrlForTest(test_url);
  }

  void SetUserStatusFetchOverrideForTest(
      GlicUserStatusFetcher::FetchOverrideCallback fetch_override) {
    glic_user_status_fetcher_->SetFetchOverrideForTest(
        std::move(fetch_override));
  }

  // Updates the user status when information suggests that it might have
  // changed recently. This is internally debounced to avoid excessive
  // requests, for signals that might be received multiple times.
  void UpdateUserStatusWithThrottling() {
    glic_user_status_fetcher_->UpdateUserStatusWithThrottling();
  }

  // This is called anytime IsAllowed() might return a different value.
  using EnableChangedCallback = base::RepeatingClosure;
  base::CallbackListSubscription RegisterAllowedChanged(
      EnableChangedCallback callback);

  using ConsentChangedCallback = base::RepeatingClosure;
  base::CallbackListSubscription RegisterOnConsentChanged(
      ConsentChangedCallback callback);

  // This is called anytime ShouldShowSettingsPage() might return a different
  // value.
  using ShowSettingsPageChangedCallback = base::RepeatingClosure;
  base::CallbackListSubscription RegisterOnShowSettingsPageChanged(
      ShowSettingsPageChangedCallback callback);

 private:
  void OnGlicSettingsPolicyChanged();

  // IdentityManagerObserver:
  void OnPrimaryAccountChanged(
      const signin::PrimaryAccountChangeEvent& event_details) override;

  // Detects changes to capabilities.
  void OnExtendedAccountInfoUpdated(const AccountInfo& info) override;
  void OnExtendedAccountInfoRemoved(const AccountInfo& info) override;
  void OnRefreshTokensLoaded() override;
  void OnRefreshTokenRemovedForAccount(
      const CoreAccountId& account_id) override;

  // Detects potential changes to tiered rollout status.
  void OnTieredRolloutStatusMaybeChanged();

  // Detects paused state.
  void OnErrorStateOfRefreshTokenUpdatedForAccount(
      const CoreAccountInfo& account_info,
      const GoogleServiceAuthError& error,
      signin_metrics::SourceForRefreshTokenOperation token_operation_source)
      override;

  void UpdateEnabledStatus();
  void UpdateConsentStatus();

  raw_ptr<Profile> profile_;
  raw_ptr<ProfileAttributesStorage> profile_attributes_storage_;
  using EnableChangedCallbackList = base::RepeatingCallbackList<void()>;
  EnableChangedCallbackList enable_changed_callback_list_;
  using OnConsentChangeCallbackList = base::RepeatingCallbackList<void()>;
  OnConsentChangeCallbackList consent_changed_callback_list_;
  using OnShowSettingsPageChangeCallbackList =
      base::RepeatingCallbackList<void()>;
  OnShowSettingsPageChangeCallbackList
      show_settings_page_changed_callback_list_;
  PrefChangeRegistrar pref_registrar_;
  std::unique_ptr<GlicUserStatusFetcher> glic_user_status_fetcher_;
  base::ScopedObservation<signin::IdentityManager,
                          signin::IdentityManager::Observer>
      identity_manager_observation_{this};
};

}  // namespace glic

#endif  // CHROME_BROWSER_GLIC_GLIC_ENABLING_H_