1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/ash/app_sync_ui_state.h"
6
7#include "base/prefs/pref_service.h"
8#include "chrome/browser/extensions/extension_service.h"
9#include "chrome/browser/extensions/pending_extension_manager.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/sync/profile_sync_service.h"
12#include "chrome/browser/sync/profile_sync_service_factory.h"
13#include "chrome/browser/ui/ash/app_sync_ui_state_factory.h"
14#include "chrome/browser/ui/ash/app_sync_ui_state_observer.h"
15#include "extensions/browser/extension_registry.h"
16#include "extensions/browser/extension_system.h"
17
18#if defined(OS_CHROMEOS)
19#include "components/user_manager/user_manager.h"
20#endif
21
22namespace {
23
24// Max loading animation time in milliseconds.
25const int kMaxSyncingTimeMs = 60 * 1000;
26
27}  // namespace
28
29// static
30AppSyncUIState* AppSyncUIState::Get(Profile* profile) {
31  return AppSyncUIStateFactory::GetForProfile(profile);
32}
33
34// static
35bool AppSyncUIState::ShouldObserveAppSyncForProfile(Profile* profile) {
36#if defined(OS_CHROMEOS)
37  if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
38    return false;
39
40  if (!profile || profile->IsOffTheRecord())
41    return false;
42
43  if (!ProfileSyncServiceFactory::HasProfileSyncService(profile))
44    return false;
45
46  return profile->IsNewProfile();
47#else
48  return false;
49#endif
50}
51
52AppSyncUIState::AppSyncUIState(Profile* profile)
53    : profile_(profile),
54      sync_service_(NULL),
55      status_(STATUS_NORMAL),
56      extension_registry_(NULL) {
57  StartObserving();
58}
59
60AppSyncUIState::~AppSyncUIState() {
61  StopObserving();
62}
63
64void AppSyncUIState::AddObserver(AppSyncUIStateObserver* observer) {
65  observers_.AddObserver(observer);
66}
67
68void AppSyncUIState::RemoveObserver(AppSyncUIStateObserver* observer) {
69  observers_.RemoveObserver(observer);
70}
71
72void AppSyncUIState::StartObserving() {
73  DCHECK(ShouldObserveAppSyncForProfile(profile_));
74  DCHECK(!sync_service_);
75  DCHECK(!extension_registry_);
76
77  extension_registry_ = extensions::ExtensionRegistry::Get(profile_);
78  extension_registry_->AddObserver(this);
79
80  sync_service_ = ProfileSyncServiceFactory::GetForProfile(profile_);
81  CHECK(sync_service_);
82  sync_service_->AddObserver(this);
83}
84
85void AppSyncUIState::StopObserving() {
86  if (!sync_service_)
87    return;
88
89  sync_service_->RemoveObserver(this);
90  sync_service_ = NULL;
91
92  if (extension_registry_)
93    extension_registry_->RemoveObserver(this);
94  extension_registry_ = NULL;
95
96  profile_ = NULL;
97}
98
99void AppSyncUIState::SetStatus(Status status) {
100  if (status_ == status)
101    return;
102
103  status_ = status;
104  switch (status_) {
105    case STATUS_SYNCING:
106      max_syncing_status_timer_.Start(
107          FROM_HERE,
108          base::TimeDelta::FromMilliseconds(kMaxSyncingTimeMs),
109          this, &AppSyncUIState::OnMaxSyncingTimer);
110      break;
111    case STATUS_NORMAL:
112    case STATUS_TIMED_OUT:
113      max_syncing_status_timer_.Stop();
114      StopObserving();
115      break;
116  }
117
118  FOR_EACH_OBSERVER(AppSyncUIStateObserver,
119                    observers_,
120                    OnAppSyncUIStatusChanged());
121}
122
123void AppSyncUIState::CheckAppSync() {
124  if (!sync_service_ || !sync_service_->HasSyncSetupCompleted())
125    return;
126
127  const bool synced = sync_service_->ShouldPushChanges();
128  const bool has_pending_extension =
129      extensions::ExtensionSystem::Get(profile_)->extension_service()->
130          pending_extension_manager()->HasPendingExtensionFromSync();
131
132  if (synced && !has_pending_extension)
133    SetStatus(STATUS_NORMAL);
134  else
135    SetStatus(STATUS_SYNCING);
136}
137
138void AppSyncUIState::OnMaxSyncingTimer() {
139  SetStatus(STATUS_TIMED_OUT);
140}
141
142void AppSyncUIState::OnStateChanged() {
143  DCHECK(sync_service_);
144  CheckAppSync();
145}
146
147void AppSyncUIState::OnExtensionLoaded(content::BrowserContext* browser_context,
148                                       const extensions::Extension* extension) {
149  CheckAppSync();
150}
151