| // 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. |
| |
| #include "chrome/browser/ui/profiles/profile_customization_synced_theme_waiter.h" |
| |
| #include "base/functional/callback.h" |
| #include "base/location.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/themes/theme_service.h" |
| #include "components/sync/base/user_selectable_type.h" |
| #include "components/sync/service/sync_service.h" |
| #include "components/sync/service/sync_service_utils.h" |
| #include "components/sync/service/sync_user_settings.h" |
| |
| ProfileCustomizationSyncedThemeWaiter::ProfileCustomizationSyncedThemeWaiter( |
| syncer::SyncService* sync_service, |
| ThemeService* theme_service, |
| base::OnceCallback<void(Outcome)> callback) |
| : sync_service_(sync_service), |
| theme_service_(theme_service), |
| callback_(std::move(callback)) { |
| DCHECK(sync_service_); |
| DCHECK(theme_service_); |
| DCHECK(callback_); |
| } |
| |
| ProfileCustomizationSyncedThemeWaiter:: |
| ~ProfileCustomizationSyncedThemeWaiter() = default; |
| |
| // static |
| bool ProfileCustomizationSyncedThemeWaiter::CanThemeSyncStart( |
| syncer::SyncService* sync_service) { |
| return syncer::GetUploadToGoogleState(sync_service, |
| syncer::DataType::THEMES) != |
| syncer::UploadState::NOT_ACTIVE; |
| } |
| |
| void ProfileCustomizationSyncedThemeWaiter::Run() { |
| #if DCHECK_IS_ON() |
| DCHECK(!is_running_); |
| is_running_ = true; |
| #endif // DCHECK_IS_ON() |
| |
| if (!CheckThemeSyncPreconditions()) { |
| return; |
| } |
| |
| std::optional<ThemeSyncableService::ThemeSyncState> theme_state = |
| theme_service_->GetThemeSyncableService()->GetThemeSyncStartState(); |
| if (theme_state) { |
| OnThemeSyncStarted(*theme_state); |
| return; |
| } |
| |
| constexpr base::TimeDelta kSyncedThemeTimeout = base::Seconds(3); |
| base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( |
| FROM_HERE, |
| base::BindOnce(&ProfileCustomizationSyncedThemeWaiter::OnTimeout, |
| weak_ptr_factory_.GetWeakPtr()), |
| kSyncedThemeTimeout); |
| |
| sync_observation_.Observe(sync_service_); |
| theme_sync_observation_.Observe(theme_service_->GetThemeSyncableService()); |
| } |
| |
| void ProfileCustomizationSyncedThemeWaiter::OnStateChanged( |
| syncer::SyncService* sync) { |
| CheckThemeSyncPreconditions(); |
| } |
| |
| void ProfileCustomizationSyncedThemeWaiter::OnSyncShutdown( |
| syncer::SyncService* sync) { |
| // Unreachable: This object must be destroyed before SyncService shutdown. |
| NOTREACHED(); |
| } |
| |
| void ProfileCustomizationSyncedThemeWaiter::OnThemeSyncStarted( |
| ThemeSyncableService::ThemeSyncState state) { |
| switch (state) { |
| case ThemeSyncableService::ThemeSyncState::kWaitingForExtensionInstallation: |
| // Wait for the extension theme to be installed to avoid flicker in the |
| // profile customization dialog. |
| theme_observation_.Observe(theme_service_); |
| return; |
| case ThemeSyncableService::ThemeSyncState::kFailed: |
| case ThemeSyncableService::ThemeSyncState::kApplied: |
| InvokeCallback(Outcome::kSyncSuccess); |
| return; |
| } |
| } |
| |
| void ProfileCustomizationSyncedThemeWaiter::OnThemeChanged() { |
| InvokeCallback(Outcome::kSyncSuccess); |
| } |
| |
| void ProfileCustomizationSyncedThemeWaiter::OnTimeout() { |
| if (!callback_) { |
| return; |
| } |
| |
| InvokeCallback(Outcome::kTimeout); |
| } |
| |
| void ProfileCustomizationSyncedThemeWaiter::InvokeCallback(Outcome outcome) { |
| sync_observation_.Reset(); |
| theme_sync_observation_.Reset(); |
| theme_observation_.Reset(); |
| |
| std::move(callback_).Run(outcome); |
| // `this` may be deleted. |
| } |
| |
| bool ProfileCustomizationSyncedThemeWaiter::CheckThemeSyncPreconditions() { |
| if (!CanThemeSyncStart(sync_service_)) { |
| InvokeCallback(Outcome::kSyncCannotStart); |
| return false; |
| } |
| |
| if (sync_service_->GetUserSettings()->IsPassphraseRequired()) { |
| InvokeCallback(Outcome::kSyncPassphraseRequired); |
| return false; |
| } |
| |
| return true; |
| } |