15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/sync_internals_ui.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/tracked_objects.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/about_sync_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service_factory.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/sync_ui_util.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_messages.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_ui.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_ui_data_source.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/sync_internals_resources.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/util/weak_handle.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/js/js_arg_list.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/js/js_controller.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/js/js_event_details.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncer::JsArgList;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncer::JsEventDetails;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncer::JsReplyHandler;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncer::WeakHandle;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)content::WebUIDataSource* CreateSyncInternalsHTMLSource() {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::WebUIDataSource* source =
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::WebUIDataSource::Create(chrome::kChromeUISyncInternalsHost);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->SetJsonPath("strings.js");
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("sync_index.js", IDR_SYNC_INTERNALS_INDEX_JS);
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("chrome_sync.js",
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          IDR_SYNC_INTERNALS_CHROME_SYNC_JS);
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("sync_log.js", IDR_SYNC_INTERNALS_SYNC_LOG_JS);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("sync_node_browser.js",
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          IDR_SYNC_INTERNALS_SYNC_NODE_BROWSER_JS);
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("sync_search.js",
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          IDR_SYNC_INTERNALS_SYNC_SEARCH_JS);
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("about.js", IDR_SYNC_INTERNALS_ABOUT_JS);
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("data.js", IDR_SYNC_INTERNALS_DATA_JS);
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("events.js", IDR_SYNC_INTERNALS_EVENTS_JS);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("notifications.js",
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          IDR_SYNC_INTERNALS_NOTIFICATIONS_JS);
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("search.js", IDR_SYNC_INTERNALS_SEARCH_JS);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("node_browser.js",
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          IDR_SYNC_INTERNALS_NODE_BROWSER_JS);
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->AddResourcePath("traffic.js", IDR_SYNC_INTERNALS_TRAFFIC_JS);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source->SetDefaultResource(IDR_SYNC_INTERNALS_INDEX_HTML);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return source;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the ProfileSyncService of the underlying original profile.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// May return NULL (e.g., if sync is disabled on the command line).
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProfileSyncService* GetProfileSyncService(Profile* profile) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ProfileSyncServiceFactory::GetInstance()->GetForProfile(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile->GetOriginalProfile());
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncInternalsUI::SyncInternalsUI(content::WebUI* web_ui)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : WebUIController(web_ui),
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(akalin): Fix.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = Profile::FromWebUI(web_ui);
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::WebUIDataSource::Add(profile, CreateSyncInternalsHTMLSource());
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileSyncService* sync_service = GetProfileSyncService(profile);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sync_service) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    js_controller_ = sync_service->GetJsController();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (js_controller_.get()) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    js_controller_->AddJsEventHandler(this);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncInternalsUI::~SyncInternalsUI() {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (js_controller_.get()) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    js_controller_->RemoveJsEventHandler(this);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncInternalsUI::OverrideHandleWebUIMessage(const GURL& source_url,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 const std::string& name,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 const ListValue& content) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ListValue> content_copy(content.DeepCopy());
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JsArgList args(content_copy.get());
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Received message: " << name << " with args "
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << args.ToString();
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (name == "testResult") {
107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Let the test framework handle test results.
108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // TODO(zea): fix this. crbug.com/316378
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else if (name == "getAboutInfo") {
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // We handle this case directly because it needs to work even if
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // the sync service doesn't exist.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ListValue return_args;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* profile = Profile::FromWebUI(web_ui());
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileSyncService* service = GetProfileSyncService(profile);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_args.Append(
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sync_ui_util::ConstructAboutInformation(service).release());
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleJsReply(name, JsArgList(&return_args));
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (js_controller_.get()) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      js_controller_->ProcessJsMessage(
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name, args,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()));
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "No sync service; dropping message " << name
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << " with args " << args.ToString();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncInternalsUI::HandleJsEvent(
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name, const JsEventDetails& details) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Handling event: " << name << " with details "
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << details.ToString();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& event_handler = "chrome.sync." + name + ".fire";
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const Value*> arg_list(1, &details.Get());
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->CallJavascriptFunction(event_handler, arg_list);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncInternalsUI::HandleJsReply(
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name, const JsArgList& args) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Handling reply for " << name << " message with args "
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << args.ToString();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& reply_handler = "chrome.sync." + name + ".handleReply";
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const Value*> arg_list(args.Get().begin(), args.Get().end());
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->CallJavascriptFunction(reply_handler, arg_list);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
149