OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2006-2008 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 #ifdef CHROME_PERSONALIZATION |
| 6 |
| 7 #include "chrome/browser/sync/personalization.h" |
| 8 |
| 9 #include "app/resource_bundle.h" |
| 10 #include "base/command_line.h" |
| 11 #include "base/file_path.h" |
| 12 #include "base/file_util.h" |
| 13 #include "base/path_service.h" |
| 14 #include "base/string_util.h" |
| 15 #include "chrome/app/chrome_dll_resource.h" |
| 16 #include "chrome/browser/browser.h" |
| 17 #include "chrome/browser/browser_process.h" |
| 18 #include "chrome/browser/browser_url_handler.h" |
| 19 #include "chrome/browser/command_updater.h" |
| 20 #include "chrome/browser/options_window.h" |
| 21 #include "chrome/browser/profile.h" |
| 22 #include "chrome/browser/profile_manager.h" |
| 23 #include "chrome/common/chrome_paths.h" |
| 24 #include "chrome/common/chrome_switches.h" |
| 25 #include "chrome/common/jstemplate_builder.h" |
| 26 #include "chrome/common/notification_service.h" |
| 27 #include "chrome/common/pref_service.h" |
| 28 #include "chrome/browser/dom_ui/new_tab_page_sync_handler.h" |
| 29 #include "chrome/browser/sync/personalization_strings.h" |
| 30 #include "chrome/browser/sync/auth_error_state.h" |
| 31 #include "chrome/browser/sync/profile_sync_service.h" |
| 32 #include "googleurl/src/gurl.h" |
| 33 #include "grit/app_resources.h" |
| 34 #include "grit/browser_resources.h" |
| 35 #include "net/url_request/url_request.h" |
| 36 |
| 37 using sync_api::SyncManager; |
| 38 |
| 39 // TODO(ncarter): Move these switches into chrome_switches. They are here |
| 40 // now because we want to keep them secret during early development. |
| 41 namespace switches { |
| 42 const wchar_t kSyncServiceURL[] = L"sync-url"; |
| 43 const wchar_t kSyncServicePort[] = L"sync-port"; |
| 44 const wchar_t kSyncUserForTest[] = L"sync-user-for-test"; |
| 45 const wchar_t kSyncPasswordForTest[] = L"sync-password-for-test"; |
| 46 } |
| 47 |
| 48 // TODO(munjal): Move these preferences to common/pref_names.h. |
| 49 // Names of various preferences. |
| 50 namespace prefs { |
| 51 const wchar_t kSyncPath[] = L"sync"; |
| 52 const wchar_t kSyncLastSyncedTime[] = L"sync.last_synced_time"; |
| 53 const wchar_t kSyncUserName[] = L"sync.username"; |
| 54 const wchar_t kSyncHasSetupCompleted[] = L"sync.has_setup_completed"; |
| 55 } |
| 56 |
| 57 // Top-level path for our network layer DataSource. |
| 58 static const char kCloudyResourcesPath[] = "resources"; |
| 59 // Path for cloudy:stats page. |
| 60 static const char kCloudyStatsPath[] = "stats"; |
| 61 // Path for the gaia sync login dialog. |
| 62 static const char kCloudyGaiaLoginPath[] = "gaialogin"; |
| 63 static const char kCloudyMergeAndSyncPath[] = "mergeandsync"; |
| 64 static const char kCloudyThrobberPath[] = "throbber.png"; |
| 65 static const char kCloudySetupFlowPath[] = "setup"; |
| 66 |
| 67 namespace Personalization { |
| 68 |
| 69 static std::wstring MakeAuthErrorText(AuthErrorState state) { |
| 70 switch (state) { |
| 71 case AUTH_ERROR_INVALID_GAIA_CREDENTIALS: |
| 72 return L"INVALID_GAIA_CREDENTIALS"; |
| 73 case AUTH_ERROR_USER_NOT_SIGNED_UP: |
| 74 return L"USER_NOT_SIGNED_UP"; |
| 75 case AUTH_ERROR_CONNECTION_FAILED: |
| 76 return L"CONNECTION_FAILED"; |
| 77 default: |
| 78 return std::wstring(); |
| 79 } |
| 80 } |
| 81 |
| 82 bool IsP13NDisabled(Profile* profile) { |
| 83 const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 84 if (command_line->HasSwitch(switches::kDisableP13n)) |
| 85 return true; |
| 86 return !profile || profile->GetProfilePersonalization() == NULL; |
| 87 } |
| 88 |
| 89 bool NeedsDOMUI(const GURL& url) { |
| 90 return url.SchemeIs(kPersonalizationScheme) && |
| 91 (url.path().find(kCloudyGaiaLoginPath) != std::string::npos) || |
| 92 (url.path().find(kCloudySetupFlowPath) != std::string::npos) || |
| 93 (url.path().find(kCloudyMergeAndSyncPath) != std::string::npos); |
| 94 } |
| 95 |
| 96 class CloudyResourceSource : public ChromeURLDataManager::DataSource { |
| 97 public: |
| 98 CloudyResourceSource() |
| 99 : DataSource(kCloudyResourcesPath, MessageLoop::current()) { |
| 100 } |
| 101 virtual ~CloudyResourceSource() { } |
| 102 |
| 103 virtual void StartDataRequest(const std::string& path, int request_id); |
| 104 |
| 105 virtual std::string GetMimeType(const std::string& path) const { |
| 106 if (path == kCloudyThrobberPath) |
| 107 return "image/png"; |
| 108 else |
| 109 return "text/html"; |
| 110 } |
| 111 private: |
| 112 DISALLOW_COPY_AND_ASSIGN(CloudyResourceSource); |
| 113 }; |
| 114 |
| 115 class CloudyStatsSource : public ChromeURLDataManager::DataSource { |
| 116 public: |
| 117 CloudyStatsSource() : DataSource(kCloudyStatsPath, MessageLoop::current()) { |
| 118 } |
| 119 virtual ~CloudyStatsSource() { } |
| 120 virtual void StartDataRequest(const std::string& path, int request_id) { |
| 121 std::string response(MakeCloudyStats()); |
| 122 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); |
| 123 html_bytes->data.resize(response.size()); |
| 124 std::copy(response.begin(), response.end(), html_bytes->data.begin()); |
| 125 SendResponse(request_id, html_bytes); |
| 126 } |
| 127 virtual std::string GetMimeType(const std::string& path) const { |
| 128 return "text/html"; |
| 129 } |
| 130 private: |
| 131 DISALLOW_COPY_AND_ASSIGN(CloudyStatsSource); |
| 132 }; |
| 133 |
| 134 DOMMessageHandler* CreateNewTabPageHandler(DOMUI* dom_ui) { |
| 135 return (new NewTabPageSyncHandler())->Attach(dom_ui); |
| 136 } |
| 137 |
| 138 std::string GetNewTabSource() { |
| 139 static const StringPiece new_tab_html( |
| 140 ResourceBundle::GetSharedInstance().GetRawDataResource( |
| 141 IDR_NEW_TAB_P13N_HTML)); |
| 142 |
| 143 std::string data_uri("data:text/html,"); |
| 144 data_uri.append(std::string(new_tab_html.data(), new_tab_html.size())); |
| 145 return GURL(data_uri).spec(); |
| 146 } |
| 147 |
| 148 std::wstring GetMenuItemInfoText(Browser* browser) { |
| 149 browser->command_updater()->UpdateCommandEnabled(IDC_P13N_INFO, true); |
| 150 return kMenuLabelStartSync; |
| 151 } |
| 152 |
| 153 void HandleMenuItemClick(Profile* p) { |
| 154 // The menu item is enabled either when the sync is not enabled by the user |
| 155 // or when it's enabled but the user name is empty. In the former case enable |
| 156 // sync. In the latter case, show the login dialog. |
| 157 ProfileSyncService* service = p->GetProfilePersonalization()->sync_service(); |
| 158 DCHECK(service); |
| 159 if (service->IsSyncEnabledByUser()) { |
| 160 ShowOptionsWindow(OPTIONS_PAGE_USER_DATA, OPTIONS_GROUP_NONE, p); |
| 161 } else { |
| 162 service->EnableForUser(); |
| 163 } |
| 164 } |
| 165 |
| 166 } // namespace Personalization |
| 167 |
| 168 class ProfilePersonalizationImpl : public ProfilePersonalization, |
| 169 public NotificationObserver { |
| 170 public: |
| 171 explicit ProfilePersonalizationImpl(Profile *p) |
| 172 : profile_(p) { |
| 173 // g_browser_process and/or io_thread may not exist during testing. |
| 174 if (g_browser_process && g_browser_process->io_thread()) { |
| 175 // Add our network layer data source for 'cloudy' URLs. |
| 176 // TODO(timsteele): This one belongs in BrowserAboutHandler. |
| 177 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, |
| 178 NewRunnableMethod(&chrome_url_data_manager, |
| 179 &ChromeURLDataManager::AddDataSource, |
| 180 new Personalization::CloudyStatsSource())); |
| 181 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, |
| 182 NewRunnableMethod(&chrome_url_data_manager, |
| 183 &ChromeURLDataManager::AddDataSource, |
| 184 new Personalization::CloudyResourceSource())); |
| 185 } |
| 186 |
| 187 registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED, |
| 188 Source<Profile>(profile_)); |
| 189 } |
| 190 virtual ~ProfilePersonalizationImpl() {} |
| 191 |
| 192 // ProfilePersonalization implementation |
| 193 virtual ProfileSyncService* sync_service() { |
| 194 if (!sync_service_.get()) |
| 195 InitSyncService(); |
| 196 return sync_service_.get(); |
| 197 } |
| 198 |
| 199 // NotificationObserver implementation. |
| 200 virtual void Observe(NotificationType type, |
| 201 const NotificationSource& source, |
| 202 const NotificationDetails& details) { |
| 203 DCHECK_EQ(type.value, NotificationType::BOOKMARK_MODEL_LOADED); |
| 204 if (!sync_service_.get()) |
| 205 InitSyncService(); |
| 206 registrar_.RemoveAll(); |
| 207 } |
| 208 |
| 209 void InitSyncService() { |
| 210 sync_service_.reset(new ProfileSyncService(profile_)); |
| 211 sync_service_->Initialize(); |
| 212 } |
| 213 |
| 214 private: |
| 215 Profile* profile_; |
| 216 NotificationRegistrar registrar_; |
| 217 scoped_ptr<ProfileSyncService> sync_service_; |
| 218 DISALLOW_COPY_AND_ASSIGN(ProfilePersonalizationImpl); |
| 219 }; |
| 220 |
| 221 namespace Personalization { |
| 222 |
| 223 void CloudyResourceSource::StartDataRequest(const std::string& path_raw, |
| 224 int request_id) { |
| 225 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); |
| 226 if (path_raw == kCloudyThrobberPath) { |
| 227 ResourceBundle::GetSharedInstance().LoadImageResourceBytes(IDR_THROBBER, |
| 228 &html_bytes->data); |
| 229 SendResponse(request_id, html_bytes); |
| 230 return; |
| 231 } |
| 232 |
| 233 std::string response; |
| 234 if (path_raw == kCloudyGaiaLoginPath) { |
| 235 static const StringPiece html(ResourceBundle::GetSharedInstance() |
| 236 .GetRawDataResource(IDR_GAIA_LOGIN_HTML)); |
| 237 response = html.as_string(); |
| 238 } else if (path_raw == kCloudyMergeAndSyncPath) { |
| 239 static const StringPiece html(ResourceBundle::GetSharedInstance() |
| 240 .GetRawDataResource(IDR_MERGE_AND_SYNC_HTML)); |
| 241 response = html.as_string(); |
| 242 } else if (path_raw == kCloudySetupFlowPath) { |
| 243 static const StringPiece html(ResourceBundle::GetSharedInstance() |
| 244 .GetRawDataResource(IDR_SYNC_SETUP_FLOW_HTML)); |
| 245 response = html.as_string(); |
| 246 } |
| 247 // Send the response. |
| 248 html_bytes->data.resize(response.size()); |
| 249 std::copy(response.begin(), response.end(), html_bytes->data.begin()); |
| 250 SendResponse(request_id, html_bytes); |
| 251 } |
| 252 |
| 253 ProfilePersonalization* CreateProfilePersonalization(Profile* p) { |
| 254 return new ProfilePersonalizationImpl(p); |
| 255 } |
| 256 |
| 257 void CleanupProfilePersonalization(ProfilePersonalization* p) { |
| 258 if (p) delete p; |
| 259 } |
| 260 |
| 261 static void AddBoolDetail(ListValue* details, const std::wstring& stat_name, |
| 262 bool stat_value) { |
| 263 DictionaryValue* val = new DictionaryValue; |
| 264 val->SetString(L"stat_name", stat_name); |
| 265 val->SetBoolean(L"stat_value", stat_value); |
| 266 details->Append(val); |
| 267 } |
| 268 |
| 269 static void AddIntDetail(ListValue* details, const std::wstring& stat_name, |
| 270 int64 stat_value) { |
| 271 DictionaryValue* val = new DictionaryValue; |
| 272 val->SetString(L"stat_name", stat_name); |
| 273 val->SetString(L"stat_value", FormatNumber(stat_value)); |
| 274 details->Append(val); |
| 275 } |
| 276 |
| 277 std::string MakeCloudyStats() { |
| 278 FilePath user_data_dir; |
| 279 if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) |
| 280 return std::string(); |
| 281 ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| 282 Profile* profile = profile_manager->GetDefaultProfile(user_data_dir); |
| 283 ProfilePersonalization* p13n_profile = profile->GetProfilePersonalization(); |
| 284 ProfileSyncService* service = p13n_profile->sync_service(); |
| 285 |
| 286 DictionaryValue strings; |
| 287 if (!service->IsSyncEnabledByUser()) { |
| 288 strings.SetString(L"summary", L"SYNC DISABLED"); |
| 289 } else { |
| 290 SyncManager::Status full_status(service->QueryDetailedSyncStatus()); |
| 291 |
| 292 strings.SetString(L"summary", |
| 293 ProfileSyncService::BuildSyncStatusSummaryText( |
| 294 full_status.summary)); |
| 295 |
| 296 strings.Set(L"authenticated", |
| 297 new FundamentalValue(full_status.authenticated)); |
| 298 strings.SetString(L"auth_problem", |
| 299 MakeAuthErrorText(service->GetAuthErrorState())); |
| 300 |
| 301 strings.SetString(L"time_since_sync", service->GetLastSyncedTimeString()); |
| 302 |
| 303 ListValue* details = new ListValue(); |
| 304 strings.Set(L"details", details); |
| 305 AddBoolDetail(details, L"Server Up", full_status.server_up); |
| 306 AddBoolDetail(details, L"Server Reachable", full_status.server_reachable); |
| 307 AddBoolDetail(details, L"Server Broken", full_status.server_broken); |
| 308 AddBoolDetail(details, L"Notifications Enabled", |
| 309 full_status.notifications_enabled); |
| 310 AddIntDetail(details, L"Notifications Received", |
| 311 full_status.notifications_received); |
| 312 AddIntDetail(details, L"Notifications Sent", |
| 313 full_status.notifications_sent); |
| 314 AddIntDetail(details, L"Unsynced Count", full_status.unsynced_count); |
| 315 AddIntDetail(details, L"Conflicting Count", full_status.conflicting_count); |
| 316 AddBoolDetail(details, L"Syncing", full_status.syncing); |
| 317 AddBoolDetail(details, L"Syncer Paused", full_status.syncer_paused); |
| 318 AddBoolDetail(details, L"Initial Sync Ended", |
| 319 full_status.initial_sync_ended); |
| 320 AddBoolDetail(details, L"Syncer Stuck", full_status.syncer_stuck); |
| 321 AddIntDetail(details, L"Updates Available", full_status.updates_available); |
| 322 AddIntDetail(details, L"Updates Received", full_status.updates_received); |
| 323 AddBoolDetail(details, L"Disk Full", full_status.disk_full); |
| 324 AddBoolDetail(details, L"Invalid Store", full_status.invalid_store); |
| 325 AddIntDetail(details, L"Max Consecutive Errors", |
| 326 full_status.max_consecutive_errors); |
| 327 } |
| 328 |
| 329 static const StringPiece sync_html( |
| 330 ResourceBundle::GetSharedInstance().GetRawDataResource( |
| 331 IDR_ABOUT_SYNC_HTML)); |
| 332 |
| 333 return jstemplate_builder::GetTemplateHtml( |
| 334 sync_html, &strings , "t" /* template root node id */); |
| 335 } |
| 336 |
| 337 } // namespace Personalization |
| 338 |
| 339 #endif // CHROME_PERSONALIZATION |
OLD | NEW |