| // Copyright 2022 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_UI_STARTUP_FIRST_RUN_SERVICE_H_ |
| #define CHROME_BROWSER_UI_STARTUP_FIRST_RUN_SERVICE_H_ |
| |
| #include <memory> |
| |
| #include "base/functional/callback_forward.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/no_destructor.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/profiles/profile_keyed_service_factory.h" |
| #include "chrome/browser/ui/profiles/profile_picker.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| |
| class PrefRegistrySimple; |
| class Profile; |
| class ProfileNameResolver; |
| |
| namespace version_info { |
| enum class Channel; |
| } |
| |
| namespace signin { |
| class IdentityManager; |
| } |
| |
| // Task to run after the FRE is exited, with `proceed` indicating whether it |
| // should be aborted or resumed. |
| using ResumeTaskCallback = base::OnceCallback<void(bool proceed)>; |
| |
| // Service handling the First Run Experience for the primary profile on Dice |
| // platforms. It is not available on the other profiles. |
| class FirstRunService : public KeyedService { |
| public: |
| // These values are persisted to logs. Entries should not be renumbered and |
| // numeric values should never be reused. |
| enum class FinishedReason { |
| kExperimentCounterfactual = 0, |
| kFinishedFlow = 1, |
| kProfileAlreadySetUp = 2, |
| kSkippedByPolicies = 3, |
| kForceSignin = 4, |
| |
| kMaxValue = kForceSignin, |
| }; |
| |
| static void RegisterLocalStatePrefs(PrefRegistrySimple* registry); |
| |
| FirstRunService(Profile& profile, signin::IdentityManager& identity_manager); |
| ~FirstRunService() override; |
| |
| // Runs `::ShouldOpenFirstRun(Profile*)` with the profile associated with this |
| // service instance. |
| virtual bool ShouldOpenFirstRun() const; |
| |
| // This function takes the user through the browser FRE. |
| // 1) First, it checks whether the FRE flow can be skipped in the first place. |
| // This is the case when sync consent is already given or when enterprise |
| // policies forbid the FRE. If so, the call directly 'finishes' the flow |
| // (see below). |
| // 2) Then, it opens the FRE UI (in the profile picker window) and |
| // asynchronously 'finishes' the flow (sets a flag in the local prefs) once |
| // the user chooses any action on the sync consent screen. If the user |
| // exits the FRE UI via the generic 'Close window' affordances, it is |
| // interpreted as an intent to exit the app and `callback` will be called |
| // with `proceed` set to false. If they exit it via the dedicated options |
| // in the flow, it will be considered 'completed' and `callback` will be |
| // run with `proceed` set to true. If the FRE flow is exited before the |
| // sync consent screen, the flow is considered 'aborted', and can be shown |
| // again at the next startup. |
| // When this method is called again while FRE is in progress, the previous |
| // callback is aborted (called with false), and is replaced by `callback`. |
| virtual void OpenFirstRunIfNeeded(ResumeTaskCallback callback); |
| |
| // Terminates the first run without re-opening a browser window. |
| virtual void FinishFirstRunWithoutResumeTask(); |
| |
| private: |
| friend class FirstRunServiceFactory; |
| FRIEND_TEST_ALL_PREFIXES(FirstRunServiceTest, |
| ShouldPopulateProfileNameFromPrimaryAccount); |
| |
| // Asynchronously attempts to complete the first run silently. |
| // By the time `callback` is run (if non-null), either: |
| // - the first run has been marked finished because it can't be run for this |
| // profile (e.g. policies) or because we want to enable Sync silently |
| // - the first run is ready to be opened. |
| // The finished state can be checked by calling `ShouldOpenFirstRun()`. |
| void TryMarkFirstRunAlreadyFinished(base::OnceClosure callback); |
| |
| void OpenFirstRunInternal(); |
| |
| // Processes the outcome from the FRE and resumes the user's interrupted task. |
| void OnFirstRunHasExited(ProfilePicker::FirstRunExitStatus status); |
| |
| // Marks the first run as finished and updates the profile entry based on |
| // the info obtained during the first run. |
| // Noting that the latter part is done by calling `FinishProfileSetUp()`, |
| // which will be done asynchronously in most cases. |
| void FinishFirstRun(FinishedReason reason); |
| |
| void FinishProfileSetUp(std::u16string profile_name); |
| |
| // Owns of this instance via the KeyedService mechanism. |
| const raw_ref<Profile> profile_; |
| |
| // KeyedService(s) this service depends on: |
| const raw_ref<signin::IdentityManager> identity_manager_; |
| |
| std::unique_ptr<ProfileNameResolver> profile_name_resolver_; |
| |
| ResumeTaskCallback resume_task_callback_; |
| |
| base::WeakPtrFactory<FirstRunService> weak_ptr_factory_{this}; |
| }; |
| |
| class FirstRunServiceFactory : public ProfileKeyedServiceFactory { |
| public: |
| FirstRunServiceFactory(const FirstRunServiceFactory&) = delete; |
| FirstRunServiceFactory& operator=(const FirstRunServiceFactory&) = delete; |
| |
| static FirstRunService* GetForBrowserContext( |
| content::BrowserContext* context); |
| |
| static FirstRunService* GetForBrowserContextIfExists( |
| content::BrowserContext* context); |
| |
| static FirstRunServiceFactory* GetInstance(); |
| |
| private: |
| friend class base::NoDestructor<FirstRunServiceFactory>; |
| friend class FirstRunServiceBrowserTestBase; |
| |
| FirstRunServiceFactory(); |
| ~FirstRunServiceFactory() override; |
| |
| std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext( |
| content::BrowserContext* context) const override; |
| }; |
| |
| // Returns whether the first run experience (including sync promo) might be |
| // opened for `profile`. It should be checked before |
| // `FirstRunService::OpenFirstRunIfNeeded()` is called. |
| // |
| // Even if this method returns `true`, the FRE can still be skipped if for |
| // example the feature is disabled, a policy suppresses it, etc. |
| bool ShouldOpenFirstRun(Profile* profile); |
| |
| #endif // CHROME_BROWSER_UI_STARTUP_FIRST_RUN_SERVICE_H_ |