summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/personalization.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/sync/personalization.cc')
-rw-r--r--chrome/browser/sync/personalization.cc339
1 files changed, 339 insertions, 0 deletions
diff --git a/chrome/browser/sync/personalization.cc b/chrome/browser/sync/personalization.cc
new file mode 100644
index 0000000..8e6a67c
--- /dev/null
+++ b/chrome/browser/sync/personalization.cc
@@ -0,0 +1,339 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef CHROME_PERSONALIZATION
+
+#include "chrome/browser/sync/personalization.h"
+
+#include "app/resource_bundle.h"
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_url_handler.h"
+#include "chrome/browser/command_updater.h"
+#include "chrome/browser/options_window.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/profile_manager.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/browser/dom_ui/new_tab_page_sync_handler.h"
+#include "chrome/browser/sync/personalization_strings.h"
+#include "chrome/browser/sync/auth_error_state.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "googleurl/src/gurl.h"
+#include "grit/app_resources.h"
+#include "grit/browser_resources.h"
+#include "net/url_request/url_request.h"
+
+using sync_api::SyncManager;
+
+// TODO(ncarter): Move these switches into chrome_switches. They are here
+// now because we want to keep them secret during early development.
+namespace switches {
+ const wchar_t kSyncServiceURL[] = L"sync-url";
+ const wchar_t kSyncServicePort[] = L"sync-port";
+ const wchar_t kSyncUserForTest[] = L"sync-user-for-test";
+ const wchar_t kSyncPasswordForTest[] = L"sync-password-for-test";
+}
+
+// TODO(munjal): Move these preferences to common/pref_names.h.
+// Names of various preferences.
+namespace prefs {
+ const wchar_t kSyncPath[] = L"sync";
+ const wchar_t kSyncLastSyncedTime[] = L"sync.last_synced_time";
+ const wchar_t kSyncUserName[] = L"sync.username";
+ const wchar_t kSyncHasSetupCompleted[] = L"sync.has_setup_completed";
+}
+
+// Top-level path for our network layer DataSource.
+static const char kCloudyResourcesPath[] = "resources";
+// Path for cloudy:stats page.
+static const char kCloudyStatsPath[] = "stats";
+// Path for the gaia sync login dialog.
+static const char kCloudyGaiaLoginPath[] = "gaialogin";
+static const char kCloudyMergeAndSyncPath[] = "mergeandsync";
+static const char kCloudyThrobberPath[] = "throbber.png";
+static const char kCloudySetupFlowPath[] = "setup";
+
+namespace Personalization {
+
+static std::wstring MakeAuthErrorText(AuthErrorState state) {
+ switch (state) {
+ case AUTH_ERROR_INVALID_GAIA_CREDENTIALS:
+ return L"INVALID_GAIA_CREDENTIALS";
+ case AUTH_ERROR_USER_NOT_SIGNED_UP:
+ return L"USER_NOT_SIGNED_UP";
+ case AUTH_ERROR_CONNECTION_FAILED:
+ return L"CONNECTION_FAILED";
+ default:
+ return std::wstring();
+ }
+}
+
+bool IsP13NDisabled(Profile* profile) {
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kDisableP13n))
+ return true;
+ return !profile || profile->GetProfilePersonalization() == NULL;
+}
+
+bool NeedsDOMUI(const GURL& url) {
+ return url.SchemeIs(kPersonalizationScheme) &&
+ (url.path().find(kCloudyGaiaLoginPath) != std::string::npos) ||
+ (url.path().find(kCloudySetupFlowPath) != std::string::npos) ||
+ (url.path().find(kCloudyMergeAndSyncPath) != std::string::npos);
+}
+
+class CloudyResourceSource : public ChromeURLDataManager::DataSource {
+ public:
+ CloudyResourceSource()
+ : DataSource(kCloudyResourcesPath, MessageLoop::current()) {
+ }
+ virtual ~CloudyResourceSource() { }
+
+ virtual void StartDataRequest(const std::string& path, int request_id);
+
+ virtual std::string GetMimeType(const std::string& path) const {
+ if (path == kCloudyThrobberPath)
+ return "image/png";
+ else
+ return "text/html";
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CloudyResourceSource);
+};
+
+class CloudyStatsSource : public ChromeURLDataManager::DataSource {
+ public:
+ CloudyStatsSource() : DataSource(kCloudyStatsPath, MessageLoop::current()) {
+ }
+ virtual ~CloudyStatsSource() { }
+ virtual void StartDataRequest(const std::string& path, int request_id) {
+ std::string response(MakeCloudyStats());
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(response.size());
+ std::copy(response.begin(), response.end(), html_bytes->data.begin());
+ SendResponse(request_id, html_bytes);
+ }
+ virtual std::string GetMimeType(const std::string& path) const {
+ return "text/html";
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CloudyStatsSource);
+};
+
+DOMMessageHandler* CreateNewTabPageHandler(DOMUI* dom_ui) {
+ return (new NewTabPageSyncHandler())->Attach(dom_ui);
+}
+
+std::string GetNewTabSource() {
+ static const StringPiece new_tab_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_NEW_TAB_P13N_HTML));
+
+ std::string data_uri("data:text/html,");
+ data_uri.append(std::string(new_tab_html.data(), new_tab_html.size()));
+ return GURL(data_uri).spec();
+}
+
+std::wstring GetMenuItemInfoText(Browser* browser) {
+ browser->command_updater()->UpdateCommandEnabled(IDC_P13N_INFO, true);
+ return kMenuLabelStartSync;
+}
+
+void HandleMenuItemClick(Profile* p) {
+ // The menu item is enabled either when the sync is not enabled by the user
+ // or when it's enabled but the user name is empty. In the former case enable
+ // sync. In the latter case, show the login dialog.
+ ProfileSyncService* service = p->GetProfilePersonalization()->sync_service();
+ DCHECK(service);
+ if (service->IsSyncEnabledByUser()) {
+ ShowOptionsWindow(OPTIONS_PAGE_USER_DATA, OPTIONS_GROUP_NONE, p);
+ } else {
+ service->EnableForUser();
+ }
+}
+
+} // namespace Personalization
+
+class ProfilePersonalizationImpl : public ProfilePersonalization,
+ public NotificationObserver {
+ public:
+ explicit ProfilePersonalizationImpl(Profile *p)
+ : profile_(p) {
+ // g_browser_process and/or io_thread may not exist during testing.
+ if (g_browser_process && g_browser_process->io_thread()) {
+ // Add our network layer data source for 'cloudy' URLs.
+ // TODO(timsteele): This one belongs in BrowserAboutHandler.
+ g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(&chrome_url_data_manager,
+ &ChromeURLDataManager::AddDataSource,
+ new Personalization::CloudyStatsSource()));
+ g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(&chrome_url_data_manager,
+ &ChromeURLDataManager::AddDataSource,
+ new Personalization::CloudyResourceSource()));
+ }
+
+ registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
+ Source<Profile>(profile_));
+ }
+ virtual ~ProfilePersonalizationImpl() {}
+
+ // ProfilePersonalization implementation
+ virtual ProfileSyncService* sync_service() {
+ if (!sync_service_.get())
+ InitSyncService();
+ return sync_service_.get();
+ }
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(type.value, NotificationType::BOOKMARK_MODEL_LOADED);
+ if (!sync_service_.get())
+ InitSyncService();
+ registrar_.RemoveAll();
+ }
+
+ void InitSyncService() {
+ sync_service_.reset(new ProfileSyncService(profile_));
+ sync_service_->Initialize();
+ }
+
+ private:
+ Profile* profile_;
+ NotificationRegistrar registrar_;
+ scoped_ptr<ProfileSyncService> sync_service_;
+ DISALLOW_COPY_AND_ASSIGN(ProfilePersonalizationImpl);
+};
+
+namespace Personalization {
+
+void CloudyResourceSource::StartDataRequest(const std::string& path_raw,
+ int request_id) {
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ if (path_raw == kCloudyThrobberPath) {
+ ResourceBundle::GetSharedInstance().LoadImageResourceBytes(IDR_THROBBER,
+ &html_bytes->data);
+ SendResponse(request_id, html_bytes);
+ return;
+ }
+
+ std::string response;
+ if (path_raw == kCloudyGaiaLoginPath) {
+ static const StringPiece html(ResourceBundle::GetSharedInstance()
+ .GetRawDataResource(IDR_GAIA_LOGIN_HTML));
+ response = html.as_string();
+ } else if (path_raw == kCloudyMergeAndSyncPath) {
+ static const StringPiece html(ResourceBundle::GetSharedInstance()
+ .GetRawDataResource(IDR_MERGE_AND_SYNC_HTML));
+ response = html.as_string();
+ } else if (path_raw == kCloudySetupFlowPath) {
+ static const StringPiece html(ResourceBundle::GetSharedInstance()
+ .GetRawDataResource(IDR_SYNC_SETUP_FLOW_HTML));
+ response = html.as_string();
+ }
+ // Send the response.
+ html_bytes->data.resize(response.size());
+ std::copy(response.begin(), response.end(), html_bytes->data.begin());
+ SendResponse(request_id, html_bytes);
+}
+
+ProfilePersonalization* CreateProfilePersonalization(Profile* p) {
+ return new ProfilePersonalizationImpl(p);
+}
+
+void CleanupProfilePersonalization(ProfilePersonalization* p) {
+ if (p) delete p;
+}
+
+static void AddBoolDetail(ListValue* details, const std::wstring& stat_name,
+ bool stat_value) {
+ DictionaryValue* val = new DictionaryValue;
+ val->SetString(L"stat_name", stat_name);
+ val->SetBoolean(L"stat_value", stat_value);
+ details->Append(val);
+}
+
+static void AddIntDetail(ListValue* details, const std::wstring& stat_name,
+ int64 stat_value) {
+ DictionaryValue* val = new DictionaryValue;
+ val->SetString(L"stat_name", stat_name);
+ val->SetString(L"stat_value", FormatNumber(stat_value));
+ details->Append(val);
+}
+
+std::string MakeCloudyStats() {
+ FilePath user_data_dir;
+ if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
+ return std::string();
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
+ ProfilePersonalization* p13n_profile = profile->GetProfilePersonalization();
+ ProfileSyncService* service = p13n_profile->sync_service();
+
+ DictionaryValue strings;
+ if (!service->IsSyncEnabledByUser()) {
+ strings.SetString(L"summary", L"SYNC DISABLED");
+ } else {
+ SyncManager::Status full_status(service->QueryDetailedSyncStatus());
+
+ strings.SetString(L"summary",
+ ProfileSyncService::BuildSyncStatusSummaryText(
+ full_status.summary));
+
+ strings.Set(L"authenticated",
+ new FundamentalValue(full_status.authenticated));
+ strings.SetString(L"auth_problem",
+ MakeAuthErrorText(service->GetAuthErrorState()));
+
+ strings.SetString(L"time_since_sync", service->GetLastSyncedTimeString());
+
+ ListValue* details = new ListValue();
+ strings.Set(L"details", details);
+ AddBoolDetail(details, L"Server Up", full_status.server_up);
+ AddBoolDetail(details, L"Server Reachable", full_status.server_reachable);
+ AddBoolDetail(details, L"Server Broken", full_status.server_broken);
+ AddBoolDetail(details, L"Notifications Enabled",
+ full_status.notifications_enabled);
+ AddIntDetail(details, L"Notifications Received",
+ full_status.notifications_received);
+ AddIntDetail(details, L"Notifications Sent",
+ full_status.notifications_sent);
+ AddIntDetail(details, L"Unsynced Count", full_status.unsynced_count);
+ AddIntDetail(details, L"Conflicting Count", full_status.conflicting_count);
+ AddBoolDetail(details, L"Syncing", full_status.syncing);
+ AddBoolDetail(details, L"Syncer Paused", full_status.syncer_paused);
+ AddBoolDetail(details, L"Initial Sync Ended",
+ full_status.initial_sync_ended);
+ AddBoolDetail(details, L"Syncer Stuck", full_status.syncer_stuck);
+ AddIntDetail(details, L"Updates Available", full_status.updates_available);
+ AddIntDetail(details, L"Updates Received", full_status.updates_received);
+ AddBoolDetail(details, L"Disk Full", full_status.disk_full);
+ AddBoolDetail(details, L"Invalid Store", full_status.invalid_store);
+ AddIntDetail(details, L"Max Consecutive Errors",
+ full_status.max_consecutive_errors);
+ }
+
+ static const StringPiece sync_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_ABOUT_SYNC_HTML));
+
+ return jstemplate_builder::GetTemplateHtml(
+ sync_html, &strings , "t" /* template root node id */);
+}
+
+} // namespace Personalization
+
+#endif // CHROME_PERSONALIZATION