1 // Copyright 2014 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/devtools/devtools_ui_bindings.h" 6 7 #include "base/command_line.h" 8 #include "base/json/json_reader.h" 9 #include "base/json/json_writer.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_util.h" 12 #include "base/strings/stringprintf.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "base/values.h" 15 #include "chrome/browser/chrome_notification_types.h" 16 #include "chrome/browser/chrome_page_zoom.h" 17 #include "chrome/browser/devtools/devtools_target_impl.h" 18 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" 19 #include "chrome/browser/extensions/extension_service.h" 20 #include "chrome/browser/infobars/infobar_service.h" 21 #include "chrome/browser/profiles/profile.h" 22 #include "chrome/browser/themes/theme_properties.h" 23 #include "chrome/browser/themes/theme_service.h" 24 #include "chrome/browser/themes/theme_service_factory.h" 25 #include "chrome/browser/ui/browser.h" 26 #include "chrome/browser/ui/browser_iterator.h" 27 #include "chrome/browser/ui/browser_list.h" 28 #include "chrome/browser/ui/browser_window.h" 29 #include "chrome/browser/ui/tabs/tab_strip_model.h" 30 #include "chrome/common/chrome_switches.h" 31 #include "chrome/common/extensions/manifest_url_handler.h" 32 #include "chrome/common/url_constants.h" 33 #include "chrome/grit/generated_resources.h" 34 #include "components/infobars/core/confirm_infobar_delegate.h" 35 #include "components/infobars/core/infobar.h" 36 #include "content/public/browser/favicon_status.h" 37 #include "content/public/browser/invalidate_type.h" 38 #include "content/public/browser/navigation_controller.h" 39 #include "content/public/browser/navigation_entry.h" 40 #include "content/public/browser/notification_source.h" 41 #include "content/public/browser/render_frame_host.h" 42 #include "content/public/browser/render_view_host.h" 43 #include "content/public/browser/user_metrics.h" 44 #include "content/public/browser/web_contents.h" 45 #include "content/public/browser/web_contents_observer.h" 46 #include "content/public/common/renderer_preferences.h" 47 #include "content/public/common/url_constants.h" 48 #include "extensions/browser/extension_system.h" 49 #include "extensions/common/extension_set.h" 50 #include "extensions/common/permissions/permissions_data.h" 51 #include "ui/base/l10n/l10n_util.h" 52 #include "ui/base/page_transition_types.h" 53 54 using base::DictionaryValue; 55 using content::BrowserThread; 56 57 namespace { 58 59 static const char kFrontendHostId[] = "id"; 60 static const char kFrontendHostMethod[] = "method"; 61 static const char kFrontendHostParams[] = "params"; 62 static const char kTitleFormat[] = "Developer Tools - %s"; 63 64 typedef std::vector<DevToolsUIBindings*> DevToolsUIBindingsList; 65 base::LazyInstance<DevToolsUIBindingsList>::Leaky g_instances = 66 LAZY_INSTANCE_INITIALIZER; 67 68 std::string SkColorToRGBAString(SkColor color) { 69 // We avoid StringPrintf because it will use locale specific formatters for 70 // the double (e.g. ',' instead of '.' in German). 71 return "rgba(" + base::IntToString(SkColorGetR(color)) + "," + 72 base::IntToString(SkColorGetG(color)) + "," + 73 base::IntToString(SkColorGetB(color)) + "," + 74 base::DoubleToString(SkColorGetA(color) / 255.0) + ")"; 75 } 76 77 base::DictionaryValue* CreateFileSystemValue( 78 DevToolsFileHelper::FileSystem file_system) { 79 base::DictionaryValue* file_system_value = new base::DictionaryValue(); 80 file_system_value->SetString("fileSystemName", file_system.file_system_name); 81 file_system_value->SetString("rootURL", file_system.root_url); 82 file_system_value->SetString("fileSystemPath", file_system.file_system_path); 83 return file_system_value; 84 } 85 86 Browser* FindBrowser(content::WebContents* web_contents) { 87 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 88 int tab_index = it->tab_strip_model()->GetIndexOfWebContents( 89 web_contents); 90 if (tab_index != TabStripModel::kNoTab) 91 return *it; 92 } 93 return NULL; 94 } 95 96 // DevToolsConfirmInfoBarDelegate --------------------------------------------- 97 98 typedef base::Callback<void(bool)> InfoBarCallback; 99 100 class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate { 101 public: 102 // If |infobar_service| is NULL, runs |callback| with a single argument with 103 // value "false". Otherwise, creates a dev tools confirm infobar and delegate 104 // and adds the infobar to |infobar_service|. 105 static void Create(InfoBarService* infobar_service, 106 const InfoBarCallback& callback, 107 const base::string16& message); 108 109 private: 110 DevToolsConfirmInfoBarDelegate( 111 const InfoBarCallback& callback, 112 const base::string16& message); 113 virtual ~DevToolsConfirmInfoBarDelegate(); 114 115 virtual base::string16 GetMessageText() const OVERRIDE; 116 virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; 117 virtual bool Accept() OVERRIDE; 118 virtual bool Cancel() OVERRIDE; 119 120 InfoBarCallback callback_; 121 const base::string16 message_; 122 123 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate); 124 }; 125 126 void DevToolsConfirmInfoBarDelegate::Create( 127 InfoBarService* infobar_service, 128 const InfoBarCallback& callback, 129 const base::string16& message) { 130 if (!infobar_service) { 131 callback.Run(false); 132 return; 133 } 134 135 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar( 136 scoped_ptr<ConfirmInfoBarDelegate>( 137 new DevToolsConfirmInfoBarDelegate(callback, message)))); 138 } 139 140 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate( 141 const InfoBarCallback& callback, 142 const base::string16& message) 143 : ConfirmInfoBarDelegate(), 144 callback_(callback), 145 message_(message) { 146 } 147 148 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() { 149 if (!callback_.is_null()) 150 callback_.Run(false); 151 } 152 153 base::string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const { 154 return message_; 155 } 156 157 base::string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel( 158 InfoBarButton button) const { 159 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 160 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON); 161 } 162 163 bool DevToolsConfirmInfoBarDelegate::Accept() { 164 callback_.Run(true); 165 callback_.Reset(); 166 return true; 167 } 168 169 bool DevToolsConfirmInfoBarDelegate::Cancel() { 170 callback_.Run(false); 171 callback_.Reset(); 172 return true; 173 } 174 175 // DevToolsUIDefaultDelegate -------------------------------------------------- 176 177 class DefaultBindingsDelegate : public DevToolsUIBindings::Delegate { 178 public: 179 explicit DefaultBindingsDelegate(content::WebContents* web_contents) 180 : web_contents_(web_contents) {} 181 182 private: 183 virtual ~DefaultBindingsDelegate() {} 184 185 virtual void ActivateWindow() OVERRIDE; 186 virtual void CloseWindow() OVERRIDE {} 187 virtual void SetInspectedPageBounds(const gfx::Rect& rect) OVERRIDE {} 188 virtual void InspectElementCompleted() OVERRIDE {} 189 virtual void MoveWindow(int x, int y) OVERRIDE {} 190 virtual void SetIsDocked(bool is_docked) OVERRIDE {} 191 virtual void OpenInNewTab(const std::string& url) OVERRIDE; 192 virtual void SetWhitelistedShortcuts(const std::string& message) OVERRIDE {} 193 194 virtual void InspectedContentsClosing() OVERRIDE; 195 virtual void OnLoadCompleted() OVERRIDE {} 196 virtual InfoBarService* GetInfoBarService() OVERRIDE; 197 virtual void RenderProcessGone() OVERRIDE {} 198 199 content::WebContents* web_contents_; 200 DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate); 201 }; 202 203 void DefaultBindingsDelegate::ActivateWindow() { 204 web_contents_->GetDelegate()->ActivateContents(web_contents_); 205 web_contents_->Focus(); 206 } 207 208 void DefaultBindingsDelegate::OpenInNewTab(const std::string& url) { 209 content::OpenURLParams params( 210 GURL(url), content::Referrer(), NEW_FOREGROUND_TAB, 211 ui::PAGE_TRANSITION_LINK, false); 212 Browser* browser = FindBrowser(web_contents_); 213 browser->OpenURL(params); 214 } 215 216 void DefaultBindingsDelegate::InspectedContentsClosing() { 217 web_contents_->GetRenderViewHost()->ClosePage(); 218 } 219 220 InfoBarService* DefaultBindingsDelegate::GetInfoBarService() { 221 return InfoBarService::FromWebContents(web_contents_); 222 } 223 224 } // namespace 225 226 // DevToolsUIBindings::FrontendWebContentsObserver ---------------------------- 227 228 class DevToolsUIBindings::FrontendWebContentsObserver 229 : public content::WebContentsObserver { 230 public: 231 explicit FrontendWebContentsObserver(DevToolsUIBindings* ui_bindings); 232 virtual ~FrontendWebContentsObserver(); 233 234 private: 235 // contents::WebContentsObserver: 236 virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE; 237 virtual void AboutToNavigateRenderView( 238 content::RenderViewHost* render_view_host) OVERRIDE; 239 virtual void DocumentOnLoadCompletedInMainFrame() OVERRIDE; 240 241 DevToolsUIBindings* devtools_bindings_; 242 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver); 243 }; 244 245 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver( 246 DevToolsUIBindings* devtools_ui_bindings) 247 : WebContentsObserver(devtools_ui_bindings->web_contents()), 248 devtools_bindings_(devtools_ui_bindings) { 249 } 250 251 DevToolsUIBindings::FrontendWebContentsObserver:: 252 ~FrontendWebContentsObserver() { 253 } 254 255 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone( 256 base::TerminationStatus status) { 257 switch (status) { 258 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: 259 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: 260 case base::TERMINATION_STATUS_PROCESS_CRASHED: 261 if (devtools_bindings_->agent_host_.get()) 262 devtools_bindings_->Detach(); 263 break; 264 default: 265 break; 266 } 267 devtools_bindings_->delegate_->RenderProcessGone(); 268 } 269 270 void DevToolsUIBindings::FrontendWebContentsObserver::AboutToNavigateRenderView( 271 content::RenderViewHost* render_view_host) { 272 devtools_bindings_->frontend_host_.reset( 273 content::DevToolsFrontendHost::Create( 274 render_view_host, devtools_bindings_)); 275 } 276 277 void DevToolsUIBindings::FrontendWebContentsObserver:: 278 DocumentOnLoadCompletedInMainFrame() { 279 devtools_bindings_->DocumentOnLoadCompletedInMainFrame(); 280 } 281 282 // DevToolsUIBindings --------------------------------------------------------- 283 284 DevToolsUIBindings* DevToolsUIBindings::ForWebContents( 285 content::WebContents* web_contents) { 286 if (g_instances == NULL) 287 return NULL; 288 DevToolsUIBindingsList* instances = g_instances.Pointer(); 289 for (DevToolsUIBindingsList::iterator it(instances->begin()); 290 it != instances->end(); ++it) { 291 if ((*it)->web_contents() == web_contents) 292 return *it; 293 } 294 return NULL; 295 } 296 297 // static 298 GURL DevToolsUIBindings::ApplyThemeToURL(Profile* profile, 299 const GURL& base_url) { 300 std::string frontend_url = base_url.spec(); 301 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile); 302 DCHECK(tp); 303 std::string url_string( 304 frontend_url + 305 ((frontend_url.find("?") == std::string::npos) ? "?" : "&") + 306 "dockSide=undocked" + // TODO(dgozman): remove this support in M38. 307 "&toolbarColor=" + 308 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) + 309 "&textColor=" + 310 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT))); 311 if (CommandLine::ForCurrentProcess()->HasSwitch( 312 switches::kEnableDevToolsExperiments)) 313 url_string += "&experiments=true"; 314 #if defined(DEBUG_DEVTOOLS) 315 url_string += "&debugFrontend=true"; 316 #endif // defined(DEBUG_DEVTOOLS) 317 return GURL(url_string); 318 } 319 320 DevToolsUIBindings::DevToolsUIBindings(content::WebContents* web_contents) 321 : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), 322 web_contents_(web_contents), 323 delegate_(new DefaultBindingsDelegate(web_contents_)), 324 device_count_updates_enabled_(false), 325 devices_updates_enabled_(false), 326 weak_factory_(this) { 327 g_instances.Get().push_back(this); 328 frontend_contents_observer_.reset(new FrontendWebContentsObserver(this)); 329 web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false; 330 331 file_helper_.reset(new DevToolsFileHelper(web_contents_, profile_)); 332 file_system_indexer_ = new DevToolsFileSystemIndexer(); 333 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( 334 web_contents_); 335 336 // Wipe out page icon so that the default application icon is used. 337 content::NavigationEntry* entry = 338 web_contents_->GetController().GetActiveEntry(); 339 entry->GetFavicon().image = gfx::Image(); 340 entry->GetFavicon().valid = true; 341 342 // Register on-load actions. 343 registrar_.Add( 344 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED, 345 content::Source<ThemeService>( 346 ThemeServiceFactory::GetForProfile(profile_))); 347 348 embedder_message_dispatcher_.reset( 349 DevToolsEmbedderMessageDispatcher::createForDevToolsFrontend(this)); 350 351 frontend_host_.reset( 352 content::DevToolsFrontendHost::Create( 353 web_contents_->GetRenderViewHost(), this)); 354 } 355 356 DevToolsUIBindings::~DevToolsUIBindings() { 357 if (agent_host_.get()) 358 agent_host_->DetachClient(); 359 360 for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin()); 361 jobs_it != indexing_jobs_.end(); ++jobs_it) { 362 jobs_it->second->Stop(); 363 } 364 indexing_jobs_.clear(); 365 SetDeviceCountUpdatesEnabled(false); 366 SetDevicesUpdatesEnabled(false); 367 368 // Remove self from global list. 369 DevToolsUIBindingsList* instances = g_instances.Pointer(); 370 DevToolsUIBindingsList::iterator it( 371 std::find(instances->begin(), instances->end(), this)); 372 DCHECK(it != instances->end()); 373 instances->erase(it); 374 } 375 376 // content::NotificationObserver overrides ------------------------------------ 377 void DevToolsUIBindings::Observe(int type, 378 const content::NotificationSource& source, 379 const content::NotificationDetails& details) { 380 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type); 381 UpdateTheme(); 382 } 383 384 // content::DevToolsFrontendHost::Delegate implementation --------------------- 385 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend( 386 const std::string& message) { 387 std::string method; 388 base::ListValue empty_params; 389 base::ListValue* params = &empty_params; 390 391 base::DictionaryValue* dict = NULL; 392 scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message)); 393 if (!parsed_message || 394 !parsed_message->GetAsDictionary(&dict) || 395 !dict->GetString(kFrontendHostMethod, &method) || 396 (dict->HasKey(kFrontendHostParams) && 397 !dict->GetList(kFrontendHostParams, ¶ms))) { 398 LOG(ERROR) << "Invalid message was sent to embedder: " << message; 399 return; 400 } 401 402 int id = 0; 403 dict->GetInteger(kFrontendHostId, &id); 404 405 std::string error; 406 embedder_message_dispatcher_->Dispatch(method, params, &error); 407 if (id) { 408 base::FundamentalValue id_value(id); 409 base::StringValue error_value(error); 410 CallClientFunction("InspectorFrontendAPI.embedderMessageAck", 411 &id_value, &error_value, NULL); 412 } 413 } 414 415 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend( 416 const std::string& message) { 417 if (agent_host_.get()) 418 agent_host_->DispatchProtocolMessage(message); 419 } 420 421 // content::DevToolsAgentHostClient implementation -------------------------- 422 void DevToolsUIBindings::DispatchProtocolMessage( 423 content::DevToolsAgentHost* agent_host, const std::string& message) { 424 DCHECK(agent_host == agent_host_.get()); 425 base::StringValue message_value(message); 426 CallClientFunction("InspectorFrontendAPI.dispatchMessage", 427 &message_value, NULL, NULL); 428 } 429 430 void DevToolsUIBindings::AgentHostClosed( 431 content::DevToolsAgentHost* agent_host, 432 bool replaced_with_another_client) { 433 DCHECK(agent_host == agent_host_.get()); 434 agent_host_ = NULL; 435 delegate_->InspectedContentsClosing(); 436 } 437 438 // DevToolsEmbedderMessageDispatcher::Delegate implementation ----------------- 439 void DevToolsUIBindings::ActivateWindow() { 440 delegate_->ActivateWindow(); 441 } 442 443 void DevToolsUIBindings::CloseWindow() { 444 delegate_->CloseWindow(); 445 } 446 447 void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect& rect) { 448 delegate_->SetInspectedPageBounds(rect); 449 } 450 451 void DevToolsUIBindings::MoveWindow(int x, int y) { 452 delegate_->MoveWindow(x, y); 453 } 454 455 void DevToolsUIBindings::SetIsDocked(bool dock_requested) { 456 delegate_->SetIsDocked(dock_requested); 457 } 458 459 void DevToolsUIBindings::InspectElementCompleted() { 460 delegate_->InspectElementCompleted(); 461 } 462 463 void DevToolsUIBindings::InspectedURLChanged(const std::string& url) { 464 content::NavigationController& controller = web_contents()->GetController(); 465 content::NavigationEntry* entry = controller.GetActiveEntry(); 466 // DevTools UI is not localized. 467 entry->SetTitle( 468 base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str()))); 469 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE); 470 } 471 472 void DevToolsUIBindings::OpenInNewTab(const std::string& url) { 473 delegate_->OpenInNewTab(url); 474 } 475 476 void DevToolsUIBindings::SaveToFile(const std::string& url, 477 const std::string& content, 478 bool save_as) { 479 file_helper_->Save(url, content, save_as, 480 base::Bind(&DevToolsUIBindings::FileSavedAs, 481 weak_factory_.GetWeakPtr(), url), 482 base::Bind(&DevToolsUIBindings::CanceledFileSaveAs, 483 weak_factory_.GetWeakPtr(), url)); 484 } 485 486 void DevToolsUIBindings::AppendToFile(const std::string& url, 487 const std::string& content) { 488 file_helper_->Append(url, content, 489 base::Bind(&DevToolsUIBindings::AppendedTo, 490 weak_factory_.GetWeakPtr(), url)); 491 } 492 493 void DevToolsUIBindings::RequestFileSystems() { 494 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); 495 file_helper_->RequestFileSystems(base::Bind( 496 &DevToolsUIBindings::FileSystemsLoaded, weak_factory_.GetWeakPtr())); 497 } 498 499 void DevToolsUIBindings::AddFileSystem() { 500 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); 501 file_helper_->AddFileSystem( 502 base::Bind(&DevToolsUIBindings::FileSystemAdded, 503 weak_factory_.GetWeakPtr()), 504 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar, 505 weak_factory_.GetWeakPtr())); 506 } 507 508 void DevToolsUIBindings::RemoveFileSystem( 509 const std::string& file_system_path) { 510 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); 511 file_helper_->RemoveFileSystem(file_system_path); 512 base::StringValue file_system_path_value(file_system_path); 513 CallClientFunction("InspectorFrontendAPI.fileSystemRemoved", 514 &file_system_path_value, NULL, NULL); 515 } 516 517 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions( 518 const std::string& file_system_url) { 519 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); 520 file_helper_->UpgradeDraggedFileSystemPermissions( 521 file_system_url, 522 base::Bind(&DevToolsUIBindings::FileSystemAdded, 523 weak_factory_.GetWeakPtr()), 524 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar, 525 weak_factory_.GetWeakPtr())); 526 } 527 528 void DevToolsUIBindings::IndexPath(int request_id, 529 const std::string& file_system_path) { 530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 531 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); 532 if (!file_helper_->IsFileSystemAdded(file_system_path)) { 533 IndexingDone(request_id, file_system_path); 534 return; 535 } 536 indexing_jobs_[request_id] = 537 scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>( 538 file_system_indexer_->IndexPath( 539 file_system_path, 540 Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated, 541 weak_factory_.GetWeakPtr(), 542 request_id, 543 file_system_path), 544 Bind(&DevToolsUIBindings::IndexingWorked, 545 weak_factory_.GetWeakPtr(), 546 request_id, 547 file_system_path), 548 Bind(&DevToolsUIBindings::IndexingDone, 549 weak_factory_.GetWeakPtr(), 550 request_id, 551 file_system_path))); 552 } 553 554 void DevToolsUIBindings::StopIndexing(int request_id) { 555 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 556 IndexingJobsMap::iterator it = indexing_jobs_.find(request_id); 557 if (it == indexing_jobs_.end()) 558 return; 559 it->second->Stop(); 560 indexing_jobs_.erase(it); 561 } 562 563 void DevToolsUIBindings::SearchInPath(int request_id, 564 const std::string& file_system_path, 565 const std::string& query) { 566 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 567 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme)); 568 if (!file_helper_->IsFileSystemAdded(file_system_path)) { 569 SearchCompleted(request_id, file_system_path, std::vector<std::string>()); 570 return; 571 } 572 file_system_indexer_->SearchInPath(file_system_path, 573 query, 574 Bind(&DevToolsUIBindings::SearchCompleted, 575 weak_factory_.GetWeakPtr(), 576 request_id, 577 file_system_path)); 578 } 579 580 void DevToolsUIBindings::SetWhitelistedShortcuts( 581 const std::string& message) { 582 delegate_->SetWhitelistedShortcuts(message); 583 } 584 585 void DevToolsUIBindings::ZoomIn() { 586 chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_IN); 587 } 588 589 void DevToolsUIBindings::ZoomOut() { 590 chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT); 591 } 592 593 void DevToolsUIBindings::ResetZoom() { 594 chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET); 595 } 596 597 static void InspectTarget(Profile* profile, DevToolsTargetImpl* target) { 598 if (target) 599 target->Inspect(profile); 600 } 601 602 void DevToolsUIBindings::OpenUrlOnRemoteDeviceAndInspect( 603 const std::string& browser_id, 604 const std::string& url) { 605 if (remote_targets_handler_) { 606 remote_targets_handler_->Open(browser_id, url, 607 base::Bind(&InspectTarget, profile_)); 608 } 609 } 610 611 void DevToolsUIBindings::SetDeviceCountUpdatesEnabled(bool enabled) { 612 if (device_count_updates_enabled_ == enabled) 613 return; 614 DevToolsAndroidBridge* adb_bridge = 615 DevToolsAndroidBridge::Factory::GetForProfile(profile_); 616 if (!adb_bridge) 617 return; 618 619 device_count_updates_enabled_ = enabled; 620 if (enabled) 621 adb_bridge->AddDeviceCountListener(this); 622 else 623 adb_bridge->RemoveDeviceCountListener(this); 624 } 625 626 void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled) { 627 if (devices_updates_enabled_ == enabled) 628 return; 629 devices_updates_enabled_ = enabled; 630 if (enabled) { 631 remote_targets_handler_ = DevToolsTargetsUIHandler::CreateForAdb( 632 base::Bind(&DevToolsUIBindings::DevicesUpdated, 633 base::Unretained(this)), 634 profile_); 635 } else { 636 remote_targets_handler_.reset(); 637 } 638 } 639 640 void DevToolsUIBindings::SendMessageToBrowser(const std::string& message) { 641 if (agent_host_.get()) 642 agent_host_->DispatchProtocolMessage(message); 643 } 644 645 void DevToolsUIBindings::DeviceCountChanged(int count) { 646 base::FundamentalValue value(count); 647 CallClientFunction("InspectorFrontendAPI.deviceCountUpdated", &value, NULL, 648 NULL); 649 } 650 651 void DevToolsUIBindings::DevicesUpdated( 652 const std::string& source, 653 const base::ListValue& targets) { 654 CallClientFunction("InspectorFrontendAPI.devicesUpdated", &targets, NULL, 655 NULL); 656 } 657 658 void DevToolsUIBindings::FileSavedAs(const std::string& url) { 659 base::StringValue url_value(url); 660 CallClientFunction("InspectorFrontendAPI.savedURL", &url_value, NULL, NULL); 661 } 662 663 void DevToolsUIBindings::CanceledFileSaveAs(const std::string& url) { 664 base::StringValue url_value(url); 665 CallClientFunction("InspectorFrontendAPI.canceledSaveURL", 666 &url_value, NULL, NULL); 667 } 668 669 void DevToolsUIBindings::AppendedTo(const std::string& url) { 670 base::StringValue url_value(url); 671 CallClientFunction("InspectorFrontendAPI.appendedToURL", &url_value, NULL, 672 NULL); 673 } 674 675 void DevToolsUIBindings::FileSystemsLoaded( 676 const std::vector<DevToolsFileHelper::FileSystem>& file_systems) { 677 base::ListValue file_systems_value; 678 for (size_t i = 0; i < file_systems.size(); ++i) 679 file_systems_value.Append(CreateFileSystemValue(file_systems[i])); 680 CallClientFunction("InspectorFrontendAPI.fileSystemsLoaded", 681 &file_systems_value, NULL, NULL); 682 } 683 684 void DevToolsUIBindings::FileSystemAdded( 685 const DevToolsFileHelper::FileSystem& file_system) { 686 scoped_ptr<base::StringValue> error_string_value( 687 new base::StringValue(std::string())); 688 scoped_ptr<base::DictionaryValue> file_system_value; 689 if (!file_system.file_system_path.empty()) 690 file_system_value.reset(CreateFileSystemValue(file_system)); 691 CallClientFunction("InspectorFrontendAPI.fileSystemAdded", 692 error_string_value.get(), file_system_value.get(), NULL); 693 } 694 695 void DevToolsUIBindings::IndexingTotalWorkCalculated( 696 int request_id, 697 const std::string& file_system_path, 698 int total_work) { 699 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 700 base::FundamentalValue request_id_value(request_id); 701 base::StringValue file_system_path_value(file_system_path); 702 base::FundamentalValue total_work_value(total_work); 703 CallClientFunction("InspectorFrontendAPI.indexingTotalWorkCalculated", 704 &request_id_value, &file_system_path_value, 705 &total_work_value); 706 } 707 708 void DevToolsUIBindings::IndexingWorked(int request_id, 709 const std::string& file_system_path, 710 int worked) { 711 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 712 base::FundamentalValue request_id_value(request_id); 713 base::StringValue file_system_path_value(file_system_path); 714 base::FundamentalValue worked_value(worked); 715 CallClientFunction("InspectorFrontendAPI.indexingWorked", &request_id_value, 716 &file_system_path_value, &worked_value); 717 } 718 719 void DevToolsUIBindings::IndexingDone(int request_id, 720 const std::string& file_system_path) { 721 indexing_jobs_.erase(request_id); 722 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 723 base::FundamentalValue request_id_value(request_id); 724 base::StringValue file_system_path_value(file_system_path); 725 CallClientFunction("InspectorFrontendAPI.indexingDone", &request_id_value, 726 &file_system_path_value, NULL); 727 } 728 729 void DevToolsUIBindings::SearchCompleted( 730 int request_id, 731 const std::string& file_system_path, 732 const std::vector<std::string>& file_paths) { 733 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 734 base::ListValue file_paths_value; 735 for (std::vector<std::string>::const_iterator it(file_paths.begin()); 736 it != file_paths.end(); ++it) { 737 file_paths_value.AppendString(*it); 738 } 739 base::FundamentalValue request_id_value(request_id); 740 base::StringValue file_system_path_value(file_system_path); 741 CallClientFunction("InspectorFrontendAPI.searchCompleted", &request_id_value, 742 &file_system_path_value, &file_paths_value); 743 } 744 745 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar( 746 const base::string16& message, 747 const InfoBarCallback& callback) { 748 DevToolsConfirmInfoBarDelegate::Create(delegate_->GetInfoBarService(), 749 callback, message); 750 } 751 752 void DevToolsUIBindings::UpdateTheme() { 753 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_); 754 DCHECK(tp); 755 756 std::string command("InspectorFrontendAPI.setToolbarColors(\"" + 757 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) + 758 "\", \"" + 759 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) + 760 "\")"); 761 web_contents_->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(command)); 762 } 763 764 void DevToolsUIBindings::AddDevToolsExtensionsToClient() { 765 const ExtensionService* extension_service = extensions::ExtensionSystem::Get( 766 profile_->GetOriginalProfile())->extension_service(); 767 if (!extension_service) 768 return; 769 const extensions::ExtensionSet* extensions = extension_service->extensions(); 770 771 base::ListValue results; 772 for (extensions::ExtensionSet::const_iterator extension(extensions->begin()); 773 extension != extensions->end(); ++extension) { 774 if (extensions::ManifestURL::GetDevToolsPage(extension->get()).is_empty()) 775 continue; 776 base::DictionaryValue* extension_info = new base::DictionaryValue(); 777 extension_info->Set( 778 "startPage", 779 new base::StringValue( 780 extensions::ManifestURL::GetDevToolsPage( 781 extension->get()).spec())); 782 extension_info->Set("name", new base::StringValue((*extension)->name())); 783 extension_info->Set("exposeExperimentalAPIs", 784 new base::FundamentalValue( 785 (*extension)->permissions_data()->HasAPIPermission( 786 extensions::APIPermission::kExperimental))); 787 results.Append(extension_info); 788 } 789 CallClientFunction("WebInspector.addExtensions", &results, NULL, NULL); 790 } 791 792 void DevToolsUIBindings::SetDelegate(Delegate* delegate) { 793 delegate_.reset(delegate); 794 } 795 796 void DevToolsUIBindings::AttachTo( 797 const scoped_refptr<content::DevToolsAgentHost>& agent_host) { 798 if (agent_host_.get()) 799 Detach(); 800 agent_host_ = agent_host; 801 agent_host_->AttachClient(this); 802 } 803 804 void DevToolsUIBindings::Reattach() { 805 DCHECK(agent_host_.get()); 806 agent_host_->DetachClient(); 807 agent_host_->AttachClient(this); 808 } 809 810 void DevToolsUIBindings::Detach() { 811 if (agent_host_.get()) 812 agent_host_->DetachClient(); 813 agent_host_ = NULL; 814 } 815 816 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost* agent_host) { 817 return agent_host_.get() == agent_host; 818 } 819 820 void DevToolsUIBindings::CallClientFunction(const std::string& function_name, 821 const base::Value* arg1, 822 const base::Value* arg2, 823 const base::Value* arg3) { 824 std::string params; 825 if (arg1) { 826 std::string json; 827 base::JSONWriter::Write(arg1, &json); 828 params.append(json); 829 if (arg2) { 830 base::JSONWriter::Write(arg2, &json); 831 params.append(", " + json); 832 if (arg3) { 833 base::JSONWriter::Write(arg3, &json); 834 params.append(", " + json); 835 } 836 } 837 } 838 839 base::string16 javascript = base::UTF8ToUTF16( 840 function_name + "(" + params + ");"); 841 web_contents_->GetMainFrame()->ExecuteJavaScript(javascript); 842 } 843 844 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() { 845 // Call delegate first - it seeds importants bit of information. 846 delegate_->OnLoadCompleted(); 847 848 UpdateTheme(); 849 AddDevToolsExtensionsToClient(); 850 } 851