Home | History | Annotate | Download | only in webui
      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