inspect_ui.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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/inspect_ui.h" 6 7#include "base/prefs/pref_service.h" 8#include "base/stl_util.h" 9#include "chrome/browser/devtools/devtools_targets_ui.h" 10#include "chrome/browser/profiles/profile.h" 11#include "chrome/browser/ui/browser_navigator.h" 12#include "chrome/browser/ui/singleton_tabs.h" 13#include "chrome/browser/ui/webui/theme_source.h" 14#include "chrome/common/pref_names.h" 15#include "chrome/common/url_constants.h" 16#include "content/public/browser/notification_service.h" 17#include "content/public/browser/notification_source.h" 18#include "content/public/browser/notification_types.h" 19#include "content/public/browser/user_metrics.h" 20#include "content/public/browser/web_contents.h" 21#include "content/public/browser/web_ui.h" 22#include "content/public/browser/web_ui_data_source.h" 23#include "content/public/browser/web_ui_message_handler.h" 24#include "grit/browser_resources.h" 25 26using content::WebContents; 27using content::WebUIMessageHandler; 28 29namespace { 30 31const char kInitUICommand[] = "init-ui"; 32const char kInspectCommand[] = "inspect"; 33const char kActivateCommand[] = "activate"; 34const char kCloseCommand[] = "close"; 35const char kReloadCommand[] = "reload"; 36const char kOpenCommand[] = "open"; 37 38const char kDiscoverUsbDevicesEnabledCommand[] = 39 "set-discover-usb-devices-enabled"; 40const char kPortForwardingEnabledCommand[] = 41 "set-port-forwarding-enabled"; 42const char kPortForwardingConfigCommand[] = "set-port-forwarding-config"; 43 44const char kPortForwardingDefaultPort[] = "8080"; 45const char kPortForwardingDefaultLocation[] = "localhost:8080"; 46 47class InspectMessageHandler : public WebUIMessageHandler { 48 public: 49 explicit InspectMessageHandler(InspectUI* inspect_ui) 50 : inspect_ui_(inspect_ui) {} 51 virtual ~InspectMessageHandler() {} 52 53 private: 54 // WebUIMessageHandler implementation. 55 virtual void RegisterMessages() OVERRIDE; 56 57 void HandleInitUICommand(const base::ListValue* args); 58 void HandleInspectCommand(const base::ListValue* args); 59 void HandleActivateCommand(const base::ListValue* args); 60 void HandleCloseCommand(const base::ListValue* args); 61 void HandleReloadCommand(const base::ListValue* args); 62 void HandleOpenCommand(const base::ListValue* args); 63 void HandleBooleanPrefChanged(const char* pref_name, 64 const base::ListValue* args); 65 void HandlePortForwardingConfigCommand(const base::ListValue* args); 66 67 InspectUI* inspect_ui_; 68 69 DISALLOW_COPY_AND_ASSIGN(InspectMessageHandler); 70}; 71 72void InspectMessageHandler::RegisterMessages() { 73 web_ui()->RegisterMessageCallback(kInitUICommand, 74 base::Bind(&InspectMessageHandler::HandleInitUICommand, 75 base::Unretained(this))); 76 web_ui()->RegisterMessageCallback(kInspectCommand, 77 base::Bind(&InspectMessageHandler::HandleInspectCommand, 78 base::Unretained(this))); 79 web_ui()->RegisterMessageCallback(kActivateCommand, 80 base::Bind(&InspectMessageHandler::HandleActivateCommand, 81 base::Unretained(this))); 82 web_ui()->RegisterMessageCallback(kCloseCommand, 83 base::Bind(&InspectMessageHandler::HandleCloseCommand, 84 base::Unretained(this))); 85 web_ui()->RegisterMessageCallback(kDiscoverUsbDevicesEnabledCommand, 86 base::Bind(&InspectMessageHandler::HandleBooleanPrefChanged, 87 base::Unretained(this), 88 &prefs::kDevToolsDiscoverUsbDevicesEnabled[0])); 89 web_ui()->RegisterMessageCallback(kPortForwardingEnabledCommand, 90 base::Bind(&InspectMessageHandler::HandleBooleanPrefChanged, 91 base::Unretained(this), 92 &prefs::kDevToolsPortForwardingEnabled[0])); 93 web_ui()->RegisterMessageCallback(kPortForwardingConfigCommand, 94 base::Bind(&InspectMessageHandler::HandlePortForwardingConfigCommand, 95 base::Unretained(this))); 96 web_ui()->RegisterMessageCallback(kReloadCommand, 97 base::Bind(&InspectMessageHandler::HandleReloadCommand, 98 base::Unretained(this))); 99 web_ui()->RegisterMessageCallback(kOpenCommand, 100 base::Bind(&InspectMessageHandler::HandleOpenCommand, 101 base::Unretained(this))); 102} 103 104void InspectMessageHandler::HandleInitUICommand(const base::ListValue*) { 105 inspect_ui_->InitUI(); 106} 107 108static bool ParseStringArgs(const base::ListValue* args, 109 std::string* arg0, 110 std::string* arg1, 111 std::string* arg2 = 0) { 112 int arg_size = args->GetSize(); 113 return (!arg0 || (arg_size > 0 && args->GetString(0, arg0))) && 114 (!arg1 || (arg_size > 1 && args->GetString(1, arg1))) && 115 (!arg2 || (arg_size > 2 && args->GetString(2, arg2))); 116} 117 118void InspectMessageHandler::HandleInspectCommand(const base::ListValue* args) { 119 std::string source; 120 std::string id; 121 if (ParseStringArgs(args, &source, &id)) 122 inspect_ui_->Inspect(source, id); 123} 124 125void InspectMessageHandler::HandleActivateCommand(const base::ListValue* args) { 126 std::string source; 127 std::string id; 128 if (ParseStringArgs(args, &source, &id)) 129 inspect_ui_->Activate(source, id); 130} 131 132void InspectMessageHandler::HandleCloseCommand(const base::ListValue* args) { 133 std::string source; 134 std::string id; 135 if (ParseStringArgs(args, &source, &id)) 136 inspect_ui_->Close(source, id); 137} 138 139void InspectMessageHandler::HandleReloadCommand(const base::ListValue* args) { 140 std::string source; 141 std::string id; 142 if (ParseStringArgs(args, &source, &id)) 143 inspect_ui_->Reload(source, id); 144} 145 146void InspectMessageHandler::HandleOpenCommand(const base::ListValue* args) { 147 std::string source_id; 148 std::string browser_id; 149 std::string url; 150 if (ParseStringArgs(args, &source_id, &browser_id, &url)) 151 inspect_ui_->Open(source_id, browser_id, url); 152} 153 154void InspectMessageHandler::HandleBooleanPrefChanged( 155 const char* pref_name, 156 const base::ListValue* args) { 157 Profile* profile = Profile::FromWebUI(web_ui()); 158 if (!profile) 159 return; 160 161 bool enabled; 162 if (args->GetSize() == 1 && args->GetBoolean(0, &enabled)) 163 profile->GetPrefs()->SetBoolean(pref_name, enabled); 164} 165 166void InspectMessageHandler::HandlePortForwardingConfigCommand( 167 const base::ListValue* args) { 168 Profile* profile = Profile::FromWebUI(web_ui()); 169 if (!profile) 170 return; 171 172 const base::DictionaryValue* dict_src; 173 if (args->GetSize() == 1 && args->GetDictionary(0, &dict_src)) 174 profile->GetPrefs()->Set(prefs::kDevToolsPortForwardingConfig, *dict_src); 175} 176 177} // namespace 178 179InspectUI::InspectUI(content::WebUI* web_ui) 180 : WebUIController(web_ui) { 181 web_ui->AddMessageHandler(new InspectMessageHandler(this)); 182 Profile* profile = Profile::FromWebUI(web_ui); 183 content::WebUIDataSource::Add(profile, CreateInspectUIHTMLSource()); 184 185 // Set up the chrome://theme/ source. 186 ThemeSource* theme = new ThemeSource(profile); 187 content::URLDataSource::Add(profile, theme); 188} 189 190InspectUI::~InspectUI() { 191 StopListeningNotifications(); 192} 193 194void InspectUI::InitUI() { 195 SetPortForwardingDefaults(); 196 StartListeningNotifications(); 197 UpdateDiscoverUsbDevicesEnabled(); 198 UpdatePortForwardingEnabled(); 199 UpdatePortForwardingConfig(); 200} 201 202void InspectUI::Inspect(const std::string& source_id, 203 const std::string& target_id) { 204 DevToolsTargetsUIHandler* handler = FindTargetHandler(source_id); 205 if (handler) 206 handler->Inspect(target_id, Profile::FromWebUI(web_ui())); 207} 208 209void InspectUI::Activate(const std::string& source_id, 210 const std::string& target_id) { 211 DevToolsTargetsUIHandler* handler = FindTargetHandler(source_id); 212 if (handler) 213 handler->Activate(target_id); 214} 215 216void InspectUI::Close(const std::string& source_id, 217 const std::string& target_id) { 218 DevToolsTargetsUIHandler* handler = FindTargetHandler(source_id); 219 if (handler) 220 handler->Close(target_id); 221} 222 223void InspectUI::Reload(const std::string& source_id, 224 const std::string& target_id) { 225 DevToolsTargetsUIHandler* handler = FindTargetHandler(source_id); 226 if (handler) 227 handler->Reload(target_id); 228} 229 230void InspectUI::Open(const std::string& source_id, 231 const std::string& browser_id, 232 const std::string& url) { 233 DevToolsRemoteTargetsUIHandler* handler = FindRemoteTargetHandler(source_id); 234 if (handler) 235 handler->Open(browser_id, url); 236} 237 238void InspectUI::InspectDevices(Browser* browser) { 239 content::RecordAction(base::UserMetricsAction("InspectDevices")); 240 chrome::NavigateParams params(chrome::GetSingletonTabNavigateParams( 241 browser, GURL(chrome::kChromeUIInspectURL))); 242 params.path_behavior = chrome::NavigateParams::IGNORE_AND_NAVIGATE; 243 ShowSingletonTabOverwritingNTP(browser, params); 244} 245 246void InspectUI::Observe(int type, 247 const content::NotificationSource& source, 248 const content::NotificationDetails& details) { 249 if (source == content::Source<WebContents>(web_ui()->GetWebContents())) 250 StopListeningNotifications(); 251} 252 253void InspectUI::StartListeningNotifications() { 254 if (!target_handlers_.empty()) // Possible when reloading the page. 255 StopListeningNotifications(); 256 257 Profile* profile = Profile::FromWebUI(web_ui()); 258 259 DevToolsTargetsUIHandler::Callback callback = 260 base::Bind(&InspectUI::PopulateTargets, base::Unretained(this)); 261 262 AddTargetUIHandler( 263 DevToolsTargetsUIHandler::CreateForRenderers(callback)); 264 AddTargetUIHandler( 265 DevToolsTargetsUIHandler::CreateForWorkers(callback)); 266 AddRemoteTargetUIHandler( 267 DevToolsRemoteTargetsUIHandler::CreateForAdb(callback, profile)); 268 269 port_status_serializer_.reset( 270 new PortForwardingStatusSerializer( 271 base::Bind(&InspectUI::PopulatePortStatus, base::Unretained(this)), 272 profile)); 273 274 notification_registrar_.Add(this, 275 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, 276 content::NotificationService::AllSources()); 277 278 pref_change_registrar_.Init(profile->GetPrefs()); 279 pref_change_registrar_.Add(prefs::kDevToolsDiscoverUsbDevicesEnabled, 280 base::Bind(&InspectUI::UpdateDiscoverUsbDevicesEnabled, 281 base::Unretained(this))); 282 pref_change_registrar_.Add(prefs::kDevToolsPortForwardingEnabled, 283 base::Bind(&InspectUI::UpdatePortForwardingEnabled, 284 base::Unretained(this))); 285 pref_change_registrar_.Add(prefs::kDevToolsPortForwardingConfig, 286 base::Bind(&InspectUI::UpdatePortForwardingConfig, 287 base::Unretained(this))); 288} 289 290void InspectUI::StopListeningNotifications() { 291 if (target_handlers_.empty()) 292 return; 293 294 STLDeleteValues(&target_handlers_); 295 STLDeleteValues(&remote_target_handlers_); 296 297 port_status_serializer_.reset(); 298 299 notification_registrar_.RemoveAll(); 300 pref_change_registrar_.RemoveAll(); 301} 302 303content::WebUIDataSource* InspectUI::CreateInspectUIHTMLSource() { 304 content::WebUIDataSource* source = 305 content::WebUIDataSource::Create(chrome::kChromeUIInspectHost); 306 source->AddResourcePath("inspect.css", IDR_INSPECT_CSS); 307 source->AddResourcePath("inspect.js", IDR_INSPECT_JS); 308 source->SetDefaultResource(IDR_INSPECT_HTML); 309 return source; 310} 311 312void InspectUI::UpdateDiscoverUsbDevicesEnabled() { 313 web_ui()->CallJavascriptFunction( 314 "updateDiscoverUsbDevicesEnabled", 315 *GetPrefValue(prefs::kDevToolsDiscoverUsbDevicesEnabled)); 316} 317 318void InspectUI::UpdatePortForwardingEnabled() { 319 web_ui()->CallJavascriptFunction( 320 "updatePortForwardingEnabled", 321 *GetPrefValue(prefs::kDevToolsPortForwardingEnabled)); 322} 323 324void InspectUI::UpdatePortForwardingConfig() { 325 web_ui()->CallJavascriptFunction( 326 "updatePortForwardingConfig", 327 *GetPrefValue(prefs::kDevToolsPortForwardingConfig)); 328} 329 330void InspectUI::SetPortForwardingDefaults() { 331 Profile* profile = Profile::FromWebUI(web_ui()); 332 PrefService* prefs = profile->GetPrefs(); 333 334 bool default_set; 335 if (!GetPrefValue(prefs::kDevToolsPortForwardingDefaultSet)-> 336 GetAsBoolean(&default_set) || default_set) { 337 return; 338 } 339 340 // This is the first chrome://inspect invocation on a fresh profile or after 341 // upgrade from a version that did not have kDevToolsPortForwardingDefaultSet. 342 prefs->SetBoolean(prefs::kDevToolsPortForwardingDefaultSet, true); 343 344 bool enabled; 345 const base::DictionaryValue* config; 346 if (!GetPrefValue(prefs::kDevToolsPortForwardingEnabled)-> 347 GetAsBoolean(&enabled) || 348 !GetPrefValue(prefs::kDevToolsPortForwardingConfig)-> 349 GetAsDictionary(&config)) { 350 return; 351 } 352 353 // Do nothing if user already took explicit action. 354 if (enabled || config->size() != 0) 355 return; 356 357 base::DictionaryValue default_config; 358 default_config.SetString( 359 kPortForwardingDefaultPort, kPortForwardingDefaultLocation); 360 prefs->Set(prefs::kDevToolsPortForwardingConfig, default_config); 361} 362 363const base::Value* InspectUI::GetPrefValue(const char* name) { 364 Profile* profile = Profile::FromWebUI(web_ui()); 365 return profile->GetPrefs()->FindPreference(name)->GetValue(); 366} 367 368void InspectUI::AddTargetUIHandler( 369 scoped_ptr<DevToolsTargetsUIHandler> handler) { 370 DevToolsTargetsUIHandler* handler_ptr = handler.release(); 371 target_handlers_[handler_ptr->source_id()] = handler_ptr; 372} 373 374void InspectUI::AddRemoteTargetUIHandler( 375 scoped_ptr<DevToolsRemoteTargetsUIHandler> handler) { 376 DevToolsRemoteTargetsUIHandler* handler_ptr = handler.release(); 377 remote_target_handlers_[handler_ptr->source_id()] = handler_ptr; 378} 379 380DevToolsTargetsUIHandler* InspectUI::FindTargetHandler( 381 const std::string& source_id) { 382 TargetHandlerMap::iterator it = target_handlers_.find(source_id); 383 return it != target_handlers_.end() ? 384 it->second : 385 FindRemoteTargetHandler(source_id); 386} 387 388DevToolsRemoteTargetsUIHandler* InspectUI::FindRemoteTargetHandler( 389 const std::string& source_id) { 390 RemoteTargetHandlerMap::iterator it = remote_target_handlers_.find(source_id); 391 return it != remote_target_handlers_.end() ? it->second : NULL; 392} 393 394void InspectUI::PopulateTargets(const std::string& source, 395 scoped_ptr<base::ListValue> targets) { 396 scoped_ptr<base::Value> source_value(base::Value::CreateStringValue(source)); 397 web_ui()->CallJavascriptFunction( 398 "populateTargets", 399 *source_value.get(), 400 *targets.get()); 401} 402 403void InspectUI::PopulatePortStatus(const base::Value& status) { 404 web_ui()->CallJavascriptFunction("populatePortStatus", status); 405} 406