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/webui/sync_internals_ui.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/logging.h" 11 #include "base/memory/ref_counted.h" 12 #include "base/tracked_objects.h" 13 #include "base/values.h" 14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/sync/about_sync_util.h" 16 #include "chrome/browser/sync/profile_sync_service.h" 17 #include "chrome/browser/sync/profile_sync_service_factory.h" 18 #include "chrome/browser/sync/sync_ui_util.h" 19 #include "chrome/common/extensions/extension_messages.h" 20 #include "chrome/common/url_constants.h" 21 #include "content/public/browser/web_contents.h" 22 #include "content/public/browser/web_ui.h" 23 #include "content/public/browser/web_ui_data_source.h" 24 #include "grit/sync_internals_resources.h" 25 #include "sync/internal_api/public/util/weak_handle.h" 26 #include "sync/js/js_arg_list.h" 27 #include "sync/js/js_controller.h" 28 #include "sync/js/js_event_details.h" 29 #include "ui/base/resource/resource_bundle.h" 30 31 using syncer::JsArgList; 32 using syncer::JsEventDetails; 33 using syncer::JsReplyHandler; 34 using syncer::WeakHandle; 35 using content::WebContents; 36 37 namespace { 38 39 content::WebUIDataSource* CreateSyncInternalsHTMLSource() { 40 content::WebUIDataSource* source = 41 content::WebUIDataSource::Create(chrome::kChromeUISyncInternalsHost); 42 43 source->SetJsonPath("strings.js"); 44 source->AddResourcePath("sync_index.js", IDR_SYNC_INTERNALS_INDEX_JS); 45 source->AddResourcePath("chrome_sync.js", 46 IDR_SYNC_INTERNALS_CHROME_SYNC_JS); 47 source->AddResourcePath("sync_log.js", IDR_SYNC_INTERNALS_SYNC_LOG_JS); 48 source->AddResourcePath("sync_node_browser.js", 49 IDR_SYNC_INTERNALS_SYNC_NODE_BROWSER_JS); 50 source->AddResourcePath("sync_search.js", 51 IDR_SYNC_INTERNALS_SYNC_SEARCH_JS); 52 source->AddResourcePath("about.js", IDR_SYNC_INTERNALS_ABOUT_JS); 53 source->AddResourcePath("data.js", IDR_SYNC_INTERNALS_DATA_JS); 54 source->AddResourcePath("events.js", IDR_SYNC_INTERNALS_EVENTS_JS); 55 source->AddResourcePath("notifications.js", 56 IDR_SYNC_INTERNALS_NOTIFICATIONS_JS); 57 source->AddResourcePath("search.js", IDR_SYNC_INTERNALS_SEARCH_JS); 58 source->AddResourcePath("node_browser.js", 59 IDR_SYNC_INTERNALS_NODE_BROWSER_JS); 60 source->AddResourcePath("traffic.js", IDR_SYNC_INTERNALS_TRAFFIC_JS); 61 source->SetDefaultResource(IDR_SYNC_INTERNALS_INDEX_HTML); 62 return source; 63 } 64 65 } // namespace 66 67 namespace { 68 69 // Gets the ProfileSyncService of the underlying original profile. 70 // May return NULL (e.g., if sync is disabled on the command line). 71 ProfileSyncService* GetProfileSyncService(Profile* profile) { 72 return ProfileSyncServiceFactory::GetInstance()->GetForProfile( 73 profile->GetOriginalProfile()); 74 } 75 76 } // namespace 77 78 SyncInternalsUI::SyncInternalsUI(content::WebUI* web_ui) 79 : WebUIController(web_ui), 80 weak_ptr_factory_(this) { 81 // TODO(akalin): Fix. 82 Profile* profile = Profile::FromWebUI(web_ui); 83 content::WebUIDataSource::Add(profile, CreateSyncInternalsHTMLSource()); 84 ProfileSyncService* sync_service = GetProfileSyncService(profile); 85 if (sync_service) { 86 js_controller_ = sync_service->GetJsController(); 87 } 88 if (js_controller_.get()) { 89 js_controller_->AddJsEventHandler(this); 90 } 91 } 92 93 SyncInternalsUI::~SyncInternalsUI() { 94 if (js_controller_.get()) { 95 js_controller_->RemoveJsEventHandler(this); 96 } 97 } 98 99 bool SyncInternalsUI::OverrideHandleWebUIMessage(const GURL& source_url, 100 const std::string& name, 101 const ListValue& content) { 102 scoped_ptr<ListValue> content_copy(content.DeepCopy()); 103 JsArgList args(content_copy.get()); 104 VLOG(1) << "Received message: " << name << " with args " 105 << args.ToString(); 106 // We handle this case directly because it needs to work even if 107 // the sync service doesn't exist. 108 if (name == "getAboutInfo") { 109 ListValue return_args; 110 Profile* profile = Profile::FromWebUI(web_ui()); 111 ProfileSyncService* service = GetProfileSyncService(profile); 112 return_args.Append( 113 sync_ui_util::ConstructAboutInformation(service).release()); 114 HandleJsReply(name, JsArgList(&return_args)); 115 } else { 116 if (js_controller_.get()) { 117 js_controller_->ProcessJsMessage( 118 name, args, 119 MakeWeakHandle(weak_ptr_factory_.GetWeakPtr())); 120 } else { 121 LOG(WARNING) << "No sync service; dropping message " << name 122 << " with args " << args.ToString(); 123 } 124 } 125 return true; 126 } 127 128 void SyncInternalsUI::HandleJsEvent( 129 const std::string& name, const JsEventDetails& details) { 130 VLOG(1) << "Handling event: " << name << " with details " 131 << details.ToString(); 132 const std::string& event_handler = "chrome.sync." + name + ".fire"; 133 std::vector<const Value*> arg_list(1, &details.Get()); 134 web_ui()->CallJavascriptFunction(event_handler, arg_list); 135 } 136 137 void SyncInternalsUI::HandleJsReply( 138 const std::string& name, const JsArgList& args) { 139 VLOG(1) << "Handling reply for " << name << " message with args " 140 << args.ToString(); 141 const std::string& reply_handler = "chrome.sync." + name + ".handleReply"; 142 std::vector<const Value*> arg_list(args.Get().begin(), args.Get().end()); 143 web_ui()->CallJavascriptFunction(reply_handler, arg_list); 144 } 145