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.
5 #include "chrome/browser/devtools/devtools_ui_bindings.h"
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/chrome_manifest_url_handlers.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"
54 using base::DictionaryValue;
55 using content::BrowserThread;
58 struct LoadCommittedDetails;
59 struct FrameNavigateParams;
64 static const char kFrontendHostId[] = "id";
65 static const char kFrontendHostMethod[] = "method";
66 static const char kFrontendHostParams[] = "params";
67 static const char kTitleFormat[] = "Developer Tools - %s";
69 const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
71 typedef std::vector<DevToolsUIBindings*> DevToolsUIBindingsList;
72 base::LazyInstance<DevToolsUIBindingsList>::Leaky g_instances =
73 LAZY_INSTANCE_INITIALIZER;
75 std::string SkColorToRGBAString(SkColor color) {
76 // We avoid StringPrintf because it will use locale specific formatters for
77 // the double (e.g. ',' instead of '.' in German).
78 return "rgba(" + base::IntToString(SkColorGetR(color)) + "," +
79 base::IntToString(SkColorGetG(color)) + "," +
80 base::IntToString(SkColorGetB(color)) + "," +
81 base::DoubleToString(SkColorGetA(color) / 255.0) + ")";
84 base::DictionaryValue* CreateFileSystemValue(
85 DevToolsFileHelper::FileSystem file_system) {
86 base::DictionaryValue* file_system_value = new base::DictionaryValue();
87 file_system_value->SetString("fileSystemName", file_system.file_system_name);
88 file_system_value->SetString("rootURL", file_system.root_url);
89 file_system_value->SetString("fileSystemPath", file_system.file_system_path);
90 return file_system_value;
93 Browser* FindBrowser(content::WebContents* web_contents) {
94 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
95 int tab_index = it->tab_strip_model()->GetIndexOfWebContents(
97 if (tab_index != TabStripModel::kNoTab)
103 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
105 typedef base::Callback<void(bool)> InfoBarCallback;
107 class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
109 // If |infobar_service| is NULL, runs |callback| with a single argument with
110 // value "false". Otherwise, creates a dev tools confirm infobar and delegate
111 // and adds the infobar to |infobar_service|.
112 static void Create(InfoBarService* infobar_service,
113 const InfoBarCallback& callback,
114 const base::string16& message);
117 DevToolsConfirmInfoBarDelegate(
118 const InfoBarCallback& callback,
119 const base::string16& message);
120 ~DevToolsConfirmInfoBarDelegate() override;
122 base::string16 GetMessageText() const override;
123 base::string16 GetButtonLabel(InfoBarButton button) const override;
124 bool Accept() override;
125 bool Cancel() override;
127 InfoBarCallback callback_;
128 const base::string16 message_;
130 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate);
133 void DevToolsConfirmInfoBarDelegate::Create(
134 InfoBarService* infobar_service,
135 const InfoBarCallback& callback,
136 const base::string16& message) {
137 if (!infobar_service) {
142 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
143 scoped_ptr<ConfirmInfoBarDelegate>(
144 new DevToolsConfirmInfoBarDelegate(callback, message))));
147 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
148 const InfoBarCallback& callback,
149 const base::string16& message)
150 : ConfirmInfoBarDelegate(),
155 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
156 if (!callback_.is_null())
157 callback_.Run(false);
160 base::string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const {
164 base::string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel(
165 InfoBarButton button) const {
166 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
167 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON);
170 bool DevToolsConfirmInfoBarDelegate::Accept() {
176 bool DevToolsConfirmInfoBarDelegate::Cancel() {
177 callback_.Run(false);
182 // DevToolsUIDefaultDelegate --------------------------------------------------
184 class DefaultBindingsDelegate : public DevToolsUIBindings::Delegate {
186 explicit DefaultBindingsDelegate(content::WebContents* web_contents)
187 : web_contents_(web_contents) {}
190 ~DefaultBindingsDelegate() override {}
192 void ActivateWindow() override;
193 void CloseWindow() override {}
194 void SetInspectedPageBounds(const gfx::Rect& rect) override {}
195 void InspectElementCompleted() override {}
196 void MoveWindow(int x, int y) override {}
197 void SetIsDocked(bool is_docked) override {}
198 void OpenInNewTab(const std::string& url) override;
199 void SetWhitelistedShortcuts(const std::string& message) override {}
201 void InspectedContentsClosing() override;
202 void OnLoadCompleted() override {}
203 InfoBarService* GetInfoBarService() override;
204 void RenderProcessGone(bool crashed) override {}
206 content::WebContents* web_contents_;
207 DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate);
210 void DefaultBindingsDelegate::ActivateWindow() {
211 web_contents_->GetDelegate()->ActivateContents(web_contents_);
212 web_contents_->Focus();
215 void DefaultBindingsDelegate::OpenInNewTab(const std::string& url) {
216 content::OpenURLParams params(
217 GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
218 ui::PAGE_TRANSITION_LINK, false);
219 Browser* browser = FindBrowser(web_contents_);
220 browser->OpenURL(params);
223 void DefaultBindingsDelegate::InspectedContentsClosing() {
224 web_contents_->GetRenderViewHost()->ClosePage();
227 InfoBarService* DefaultBindingsDelegate::GetInfoBarService() {
228 return InfoBarService::FromWebContents(web_contents_);
233 // DevToolsUIBindings::FrontendWebContentsObserver ----------------------------
235 class DevToolsUIBindings::FrontendWebContentsObserver
236 : public content::WebContentsObserver {
238 explicit FrontendWebContentsObserver(DevToolsUIBindings* ui_bindings);
239 ~FrontendWebContentsObserver() override;
242 // contents::WebContentsObserver:
243 void RenderProcessGone(base::TerminationStatus status) override;
244 void AboutToNavigateRenderView(
245 content::RenderViewHost* render_view_host) override;
246 void DocumentOnLoadCompletedInMainFrame() override;
247 void DidNavigateMainFrame(
248 const content::LoadCommittedDetails& details,
249 const content::FrameNavigateParams& params) override;
251 DevToolsUIBindings* devtools_bindings_;
252 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver);
255 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver(
256 DevToolsUIBindings* devtools_ui_bindings)
257 : WebContentsObserver(devtools_ui_bindings->web_contents()),
258 devtools_bindings_(devtools_ui_bindings) {
261 DevToolsUIBindings::FrontendWebContentsObserver::
262 ~FrontendWebContentsObserver() {
265 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone(
266 base::TerminationStatus status) {
269 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
270 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
271 case base::TERMINATION_STATUS_PROCESS_CRASHED:
272 if (devtools_bindings_->agent_host_.get())
273 devtools_bindings_->Detach();
279 devtools_bindings_->delegate_->RenderProcessGone(crashed);
282 void DevToolsUIBindings::FrontendWebContentsObserver::AboutToNavigateRenderView(
283 content::RenderViewHost* render_view_host) {
284 devtools_bindings_->frontend_host_.reset(
285 content::DevToolsFrontendHost::Create(
286 render_view_host, devtools_bindings_));
289 void DevToolsUIBindings::FrontendWebContentsObserver::
290 DocumentOnLoadCompletedInMainFrame() {
291 devtools_bindings_->DocumentOnLoadCompletedInMainFrame();
294 void DevToolsUIBindings::FrontendWebContentsObserver::
295 DidNavigateMainFrame(const content::LoadCommittedDetails& details,
296 const content::FrameNavigateParams& params) {
297 devtools_bindings_->DidNavigateMainFrame();
300 // DevToolsUIBindings ---------------------------------------------------------
302 DevToolsUIBindings* DevToolsUIBindings::ForWebContents(
303 content::WebContents* web_contents) {
304 if (g_instances == NULL)
306 DevToolsUIBindingsList* instances = g_instances.Pointer();
307 for (DevToolsUIBindingsList::iterator it(instances->begin());
308 it != instances->end(); ++it) {
309 if ((*it)->web_contents() == web_contents)
316 GURL DevToolsUIBindings::ApplyThemeToURL(Profile* profile,
317 const GURL& base_url) {
318 std::string frontend_url = base_url.spec();
319 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile);
321 std::string url_string(
323 ((frontend_url.find("?") == std::string::npos) ? "?" : "&") +
324 "dockSide=undocked" + // TODO(dgozman): remove this support in M38.
326 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
328 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)));
329 if (CommandLine::ForCurrentProcess()->HasSwitch(
330 switches::kEnableDevToolsExperiments))
331 url_string += "&experiments=true";
332 #if defined(DEBUG_DEVTOOLS)
333 url_string += "&debugFrontend=true";
334 #endif // defined(DEBUG_DEVTOOLS)
335 return GURL(url_string);
338 DevToolsUIBindings::DevToolsUIBindings(content::WebContents* web_contents)
339 : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
340 web_contents_(web_contents),
341 delegate_(new DefaultBindingsDelegate(web_contents_)),
342 device_count_updates_enabled_(false),
343 devices_updates_enabled_(false),
344 frontend_loaded_(false),
345 weak_factory_(this) {
346 g_instances.Get().push_back(this);
347 frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
348 web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false;
350 file_helper_.reset(new DevToolsFileHelper(web_contents_, profile_));
351 file_system_indexer_ = new DevToolsFileSystemIndexer();
352 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
355 // Wipe out page icon so that the default application icon is used.
356 content::NavigationEntry* entry =
357 web_contents_->GetController().GetActiveEntry();
358 entry->GetFavicon().image = gfx::Image();
359 entry->GetFavicon().valid = true;
361 // Register on-load actions.
363 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
364 content::Source<ThemeService>(
365 ThemeServiceFactory::GetForProfile(profile_)));
367 embedder_message_dispatcher_.reset(
368 DevToolsEmbedderMessageDispatcher::createForDevToolsFrontend(this));
370 frontend_host_.reset(
371 content::DevToolsFrontendHost::Create(
372 web_contents_->GetRenderViewHost(), this));
375 DevToolsUIBindings::~DevToolsUIBindings() {
376 if (agent_host_.get())
377 agent_host_->DetachClient();
379 for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin());
380 jobs_it != indexing_jobs_.end(); ++jobs_it) {
381 jobs_it->second->Stop();
383 indexing_jobs_.clear();
384 SetDeviceCountUpdatesEnabled(false);
385 SetDevicesUpdatesEnabled(false);
387 // Remove self from global list.
388 DevToolsUIBindingsList* instances = g_instances.Pointer();
389 DevToolsUIBindingsList::iterator it(
390 std::find(instances->begin(), instances->end(), this));
391 DCHECK(it != instances->end());
392 instances->erase(it);
395 // content::NotificationObserver overrides ------------------------------------
396 void DevToolsUIBindings::Observe(int type,
397 const content::NotificationSource& source,
398 const content::NotificationDetails& details) {
399 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
403 // content::DevToolsFrontendHost::Delegate implementation ---------------------
404 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
405 const std::string& message) {
407 base::ListValue empty_params;
408 base::ListValue* params = &empty_params;
410 base::DictionaryValue* dict = NULL;
411 scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
412 if (!parsed_message ||
413 !parsed_message->GetAsDictionary(&dict) ||
414 !dict->GetString(kFrontendHostMethod, &method) ||
415 (dict->HasKey(kFrontendHostParams) &&
416 !dict->GetList(kFrontendHostParams, ¶ms))) {
417 LOG(ERROR) << "Invalid message was sent to embedder: " << message;
422 dict->GetInteger(kFrontendHostId, &id);
425 embedder_message_dispatcher_->Dispatch(method, params, &error);
427 base::FundamentalValue id_value(id);
428 base::StringValue error_value(error);
429 CallClientFunction("InspectorFrontendAPI.embedderMessageAck",
430 &id_value, &error_value, NULL);
434 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend(
435 const std::string& message) {
436 if (agent_host_.get())
437 agent_host_->DispatchProtocolMessage(message);
440 // content::DevToolsAgentHostClient implementation --------------------------
441 void DevToolsUIBindings::DispatchProtocolMessage(
442 content::DevToolsAgentHost* agent_host, const std::string& message) {
443 DCHECK(agent_host == agent_host_.get());
445 if (message.length() < kMaxMessageChunkSize) {
446 base::StringValue message_value(message);
447 CallClientFunction("InspectorFrontendAPI.dispatchMessage",
448 &message_value, NULL, NULL);
452 base::FundamentalValue total_size(static_cast<int>(message.length()));
453 for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
454 base::StringValue message_value(message.substr(pos, kMaxMessageChunkSize));
455 CallClientFunction("InspectorFrontendAPI.dispatchMessageChunk",
456 &message_value, pos ? NULL : &total_size, NULL);
460 void DevToolsUIBindings::AgentHostClosed(
461 content::DevToolsAgentHost* agent_host,
462 bool replaced_with_another_client) {
463 DCHECK(agent_host == agent_host_.get());
465 delegate_->InspectedContentsClosing();
468 // DevToolsEmbedderMessageDispatcher::Delegate implementation -----------------
469 void DevToolsUIBindings::ActivateWindow() {
470 delegate_->ActivateWindow();
473 void DevToolsUIBindings::CloseWindow() {
474 delegate_->CloseWindow();
477 void DevToolsUIBindings::LoadCompleted() {
481 void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect& rect) {
482 delegate_->SetInspectedPageBounds(rect);
485 void DevToolsUIBindings::MoveWindow(int x, int y) {
486 delegate_->MoveWindow(x, y);
489 void DevToolsUIBindings::SetIsDocked(bool dock_requested) {
490 delegate_->SetIsDocked(dock_requested);
493 void DevToolsUIBindings::InspectElementCompleted() {
494 delegate_->InspectElementCompleted();
497 void DevToolsUIBindings::InspectedURLChanged(const std::string& url) {
498 content::NavigationController& controller = web_contents()->GetController();
499 content::NavigationEntry* entry = controller.GetActiveEntry();
500 // DevTools UI is not localized.
502 base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str())));
503 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
506 void DevToolsUIBindings::OpenInNewTab(const std::string& url) {
507 delegate_->OpenInNewTab(url);
510 void DevToolsUIBindings::SaveToFile(const std::string& url,
511 const std::string& content,
513 file_helper_->Save(url, content, save_as,
514 base::Bind(&DevToolsUIBindings::FileSavedAs,
515 weak_factory_.GetWeakPtr(), url),
516 base::Bind(&DevToolsUIBindings::CanceledFileSaveAs,
517 weak_factory_.GetWeakPtr(), url));
520 void DevToolsUIBindings::AppendToFile(const std::string& url,
521 const std::string& content) {
522 file_helper_->Append(url, content,
523 base::Bind(&DevToolsUIBindings::AppendedTo,
524 weak_factory_.GetWeakPtr(), url));
527 void DevToolsUIBindings::RequestFileSystems() {
528 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
529 file_helper_->RequestFileSystems(base::Bind(
530 &DevToolsUIBindings::FileSystemsLoaded, weak_factory_.GetWeakPtr()));
533 void DevToolsUIBindings::AddFileSystem() {
534 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
535 file_helper_->AddFileSystem(
536 base::Bind(&DevToolsUIBindings::FileSystemAdded,
537 weak_factory_.GetWeakPtr()),
538 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
539 weak_factory_.GetWeakPtr()));
542 void DevToolsUIBindings::RemoveFileSystem(
543 const std::string& file_system_path) {
544 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
545 file_helper_->RemoveFileSystem(file_system_path);
546 base::StringValue file_system_path_value(file_system_path);
547 CallClientFunction("InspectorFrontendAPI.fileSystemRemoved",
548 &file_system_path_value, NULL, NULL);
551 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
552 const std::string& file_system_url) {
553 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
554 file_helper_->UpgradeDraggedFileSystemPermissions(
556 base::Bind(&DevToolsUIBindings::FileSystemAdded,
557 weak_factory_.GetWeakPtr()),
558 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
559 weak_factory_.GetWeakPtr()));
562 void DevToolsUIBindings::IndexPath(int request_id,
563 const std::string& file_system_path) {
564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
565 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
566 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
567 IndexingDone(request_id, file_system_path);
570 indexing_jobs_[request_id] =
571 scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
572 file_system_indexer_->IndexPath(
574 Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated,
575 weak_factory_.GetWeakPtr(),
578 Bind(&DevToolsUIBindings::IndexingWorked,
579 weak_factory_.GetWeakPtr(),
582 Bind(&DevToolsUIBindings::IndexingDone,
583 weak_factory_.GetWeakPtr(),
588 void DevToolsUIBindings::StopIndexing(int request_id) {
589 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
590 IndexingJobsMap::iterator it = indexing_jobs_.find(request_id);
591 if (it == indexing_jobs_.end())
594 indexing_jobs_.erase(it);
597 void DevToolsUIBindings::SearchInPath(int request_id,
598 const std::string& file_system_path,
599 const std::string& query) {
600 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
601 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
602 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
603 SearchCompleted(request_id, file_system_path, std::vector<std::string>());
606 file_system_indexer_->SearchInPath(file_system_path,
608 Bind(&DevToolsUIBindings::SearchCompleted,
609 weak_factory_.GetWeakPtr(),
614 void DevToolsUIBindings::SetWhitelistedShortcuts(
615 const std::string& message) {
616 delegate_->SetWhitelistedShortcuts(message);
619 void DevToolsUIBindings::ZoomIn() {
620 chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_IN);
623 void DevToolsUIBindings::ZoomOut() {
624 chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT);
627 void DevToolsUIBindings::ResetZoom() {
628 chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET);
631 static void InspectTarget(Profile* profile, DevToolsTargetImpl* target) {
633 target->Inspect(profile);
636 void DevToolsUIBindings::OpenUrlOnRemoteDeviceAndInspect(
637 const std::string& browser_id,
638 const std::string& url) {
639 if (remote_targets_handler_) {
640 remote_targets_handler_->Open(browser_id, url,
641 base::Bind(&InspectTarget, profile_));
645 void DevToolsUIBindings::SetDeviceCountUpdatesEnabled(bool enabled) {
646 if (device_count_updates_enabled_ == enabled)
648 DevToolsAndroidBridge* adb_bridge =
649 DevToolsAndroidBridge::Factory::GetForProfile(profile_);
653 device_count_updates_enabled_ = enabled;
655 adb_bridge->AddDeviceCountListener(this);
657 adb_bridge->RemoveDeviceCountListener(this);
660 void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled) {
661 if (devices_updates_enabled_ == enabled)
663 devices_updates_enabled_ = enabled;
665 remote_targets_handler_ = DevToolsTargetsUIHandler::CreateForAdb(
666 base::Bind(&DevToolsUIBindings::DevicesUpdated,
667 base::Unretained(this)),
670 remote_targets_handler_.reset();
674 void DevToolsUIBindings::SendMessageToBrowser(const std::string& message) {
675 if (agent_host_.get())
676 agent_host_->DispatchProtocolMessage(message);
679 void DevToolsUIBindings::DeviceCountChanged(int count) {
680 base::FundamentalValue value(count);
681 CallClientFunction("InspectorFrontendAPI.deviceCountUpdated", &value, NULL,
685 void DevToolsUIBindings::DevicesUpdated(
686 const std::string& source,
687 const base::ListValue& targets) {
688 CallClientFunction("InspectorFrontendAPI.devicesUpdated", &targets, NULL,
692 void DevToolsUIBindings::FileSavedAs(const std::string& url) {
693 base::StringValue url_value(url);
694 CallClientFunction("InspectorFrontendAPI.savedURL", &url_value, NULL, NULL);
697 void DevToolsUIBindings::CanceledFileSaveAs(const std::string& url) {
698 base::StringValue url_value(url);
699 CallClientFunction("InspectorFrontendAPI.canceledSaveURL",
700 &url_value, NULL, NULL);
703 void DevToolsUIBindings::AppendedTo(const std::string& url) {
704 base::StringValue url_value(url);
705 CallClientFunction("InspectorFrontendAPI.appendedToURL", &url_value, NULL,
709 void DevToolsUIBindings::FileSystemsLoaded(
710 const std::vector<DevToolsFileHelper::FileSystem>& file_systems) {
711 base::ListValue file_systems_value;
712 for (size_t i = 0; i < file_systems.size(); ++i)
713 file_systems_value.Append(CreateFileSystemValue(file_systems[i]));
714 CallClientFunction("InspectorFrontendAPI.fileSystemsLoaded",
715 &file_systems_value, NULL, NULL);
718 void DevToolsUIBindings::FileSystemAdded(
719 const DevToolsFileHelper::FileSystem& file_system) {
720 scoped_ptr<base::StringValue> error_string_value(
721 new base::StringValue(std::string()));
722 scoped_ptr<base::DictionaryValue> file_system_value;
723 if (!file_system.file_system_path.empty())
724 file_system_value.reset(CreateFileSystemValue(file_system));
725 CallClientFunction("InspectorFrontendAPI.fileSystemAdded",
726 error_string_value.get(), file_system_value.get(), NULL);
729 void DevToolsUIBindings::IndexingTotalWorkCalculated(
731 const std::string& file_system_path,
733 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
734 base::FundamentalValue request_id_value(request_id);
735 base::StringValue file_system_path_value(file_system_path);
736 base::FundamentalValue total_work_value(total_work);
737 CallClientFunction("InspectorFrontendAPI.indexingTotalWorkCalculated",
738 &request_id_value, &file_system_path_value,
742 void DevToolsUIBindings::IndexingWorked(int request_id,
743 const std::string& file_system_path,
745 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
746 base::FundamentalValue request_id_value(request_id);
747 base::StringValue file_system_path_value(file_system_path);
748 base::FundamentalValue worked_value(worked);
749 CallClientFunction("InspectorFrontendAPI.indexingWorked", &request_id_value,
750 &file_system_path_value, &worked_value);
753 void DevToolsUIBindings::IndexingDone(int request_id,
754 const std::string& file_system_path) {
755 indexing_jobs_.erase(request_id);
756 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
757 base::FundamentalValue request_id_value(request_id);
758 base::StringValue file_system_path_value(file_system_path);
759 CallClientFunction("InspectorFrontendAPI.indexingDone", &request_id_value,
760 &file_system_path_value, NULL);
763 void DevToolsUIBindings::SearchCompleted(
765 const std::string& file_system_path,
766 const std::vector<std::string>& file_paths) {
767 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
768 base::ListValue file_paths_value;
769 for (std::vector<std::string>::const_iterator it(file_paths.begin());
770 it != file_paths.end(); ++it) {
771 file_paths_value.AppendString(*it);
773 base::FundamentalValue request_id_value(request_id);
774 base::StringValue file_system_path_value(file_system_path);
775 CallClientFunction("InspectorFrontendAPI.searchCompleted", &request_id_value,
776 &file_system_path_value, &file_paths_value);
779 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar(
780 const base::string16& message,
781 const InfoBarCallback& callback) {
782 DevToolsConfirmInfoBarDelegate::Create(delegate_->GetInfoBarService(),
786 void DevToolsUIBindings::UpdateTheme() {
787 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_);
790 std::string command("InspectorFrontendAPI.setToolbarColors(\"" +
791 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
793 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) +
795 web_contents_->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(command));
798 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
799 const ExtensionService* extension_service = extensions::ExtensionSystem::Get(
800 profile_->GetOriginalProfile())->extension_service();
801 if (!extension_service)
803 const extensions::ExtensionSet* extensions = extension_service->extensions();
805 base::ListValue results;
806 for (extensions::ExtensionSet::const_iterator extension(extensions->begin());
807 extension != extensions->end(); ++extension) {
808 if (extensions::chrome_manifest_urls::GetDevToolsPage(extension->get())
811 base::DictionaryValue* extension_info = new base::DictionaryValue();
814 new base::StringValue(extensions::chrome_manifest_urls::GetDevToolsPage(
815 extension->get()).spec()));
816 extension_info->Set("name", new base::StringValue((*extension)->name()));
817 extension_info->Set("exposeExperimentalAPIs",
818 new base::FundamentalValue(
819 (*extension)->permissions_data()->HasAPIPermission(
820 extensions::APIPermission::kExperimental)));
821 results.Append(extension_info);
823 CallClientFunction("WebInspector.addExtensions", &results, NULL, NULL);
826 void DevToolsUIBindings::SetDelegate(Delegate* delegate) {
827 delegate_.reset(delegate);
830 void DevToolsUIBindings::AttachTo(
831 const scoped_refptr<content::DevToolsAgentHost>& agent_host) {
832 if (agent_host_.get())
834 agent_host_ = agent_host;
835 agent_host_->AttachClient(this);
838 void DevToolsUIBindings::Reattach() {
839 DCHECK(agent_host_.get());
840 agent_host_->DetachClient();
841 agent_host_->AttachClient(this);
844 void DevToolsUIBindings::Detach() {
845 if (agent_host_.get())
846 agent_host_->DetachClient();
850 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost* agent_host) {
851 return agent_host_.get() == agent_host;
854 void DevToolsUIBindings::CallClientFunction(const std::string& function_name,
855 const base::Value* arg1,
856 const base::Value* arg2,
857 const base::Value* arg3) {
861 base::JSONWriter::Write(arg1, &json);
864 base::JSONWriter::Write(arg2, &json);
865 params.append(", " + json);
867 base::JSONWriter::Write(arg3, &json);
868 params.append(", " + json);
873 base::string16 javascript = base::UTF8ToUTF16(
874 function_name + "(" + params + ");");
875 web_contents_->GetMainFrame()->ExecuteJavaScript(javascript);
878 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() {
879 // In the DEBUG_DEVTOOLS mode, the DocumentOnLoadCompletedInMainFrame event
880 // arrives before the LoadCompleted event, thus it should not trigger the
881 // frontend load handling.
882 #if !defined(DEBUG_DEVTOOLS)
887 void DevToolsUIBindings::DidNavigateMainFrame() {
888 frontend_loaded_ = false;
891 void DevToolsUIBindings::FrontendLoaded() {
892 if (frontend_loaded_)
894 frontend_loaded_ = true;
896 // Call delegate first - it seeds importants bit of information.
897 delegate_->OnLoadCompleted();
900 AddDevToolsExtensionsToClient();