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/metrics/histogram.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_notification_types.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/infobars/infobar_service.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/themes/theme_properties.h"
22 #include "chrome/browser/themes/theme_service.h"
23 #include "chrome/browser/themes/theme_service_factory.h"
24 #include "chrome/browser/ui/browser.h"
25 #include "chrome/browser/ui/browser_iterator.h"
26 #include "chrome/browser/ui/browser_list.h"
27 #include "chrome/browser/ui/browser_window.h"
28 #include "chrome/browser/ui/tabs/tab_strip_model.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/extensions/chrome_manifest_url_handlers.h"
31 #include "chrome/common/url_constants.h"
32 #include "chrome/grit/generated_resources.h"
33 #include "components/infobars/core/confirm_infobar_delegate.h"
34 #include "components/infobars/core/infobar.h"
35 #include "components/ui/zoom/page_zoom.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_registry.h"
49 #include "extensions/common/permissions/permissions_data.h"
50 #include "ui/base/l10n/l10n_util.h"
51 #include "ui/base/page_transition_types.h"
53 using base::DictionaryValue
;
54 using content::BrowserThread
;
57 struct LoadCommittedDetails
;
58 struct FrameNavigateParams
;
63 static const char kFrontendHostId
[] = "id";
64 static const char kFrontendHostMethod
[] = "method";
65 static const char kFrontendHostParams
[] = "params";
66 static const char kTitleFormat
[] = "Developer Tools - %s";
68 static const char kDevToolsActionTakenHistogram
[] = "DevTools.ActionTaken";
69 static const int kDevToolsActionTakenBoundary
= 100;
70 static const char kDevToolsPanelShownHistogram
[] = "DevTools.PanelShown";
71 static const int kDevToolsPanelShownBoundary
= 20;
73 // This constant should be in sync with
74 // the constant at shell_devtools_frontend.cc.
75 const size_t kMaxMessageChunkSize
= IPC::Channel::kMaximumMessageSize
/ 4;
77 typedef std::vector
<DevToolsUIBindings
*> DevToolsUIBindingsList
;
78 base::LazyInstance
<DevToolsUIBindingsList
>::Leaky g_instances
=
79 LAZY_INSTANCE_INITIALIZER
;
81 std::string
SkColorToRGBAString(SkColor color
) {
82 // We avoid StringPrintf because it will use locale specific formatters for
83 // the double (e.g. ',' instead of '.' in German).
84 return "rgba(" + base::IntToString(SkColorGetR(color
)) + "," +
85 base::IntToString(SkColorGetG(color
)) + "," +
86 base::IntToString(SkColorGetB(color
)) + "," +
87 base::DoubleToString(SkColorGetA(color
) / 255.0) + ")";
90 base::DictionaryValue
* CreateFileSystemValue(
91 DevToolsFileHelper::FileSystem file_system
) {
92 base::DictionaryValue
* file_system_value
= new base::DictionaryValue();
93 file_system_value
->SetString("fileSystemName", file_system
.file_system_name
);
94 file_system_value
->SetString("rootURL", file_system
.root_url
);
95 file_system_value
->SetString("fileSystemPath", file_system
.file_system_path
);
96 return file_system_value
;
99 Browser
* FindBrowser(content::WebContents
* web_contents
) {
100 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
101 int tab_index
= it
->tab_strip_model()->GetIndexOfWebContents(
103 if (tab_index
!= TabStripModel::kNoTab
)
109 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
111 typedef base::Callback
<void(bool)> InfoBarCallback
;
113 class DevToolsConfirmInfoBarDelegate
: public ConfirmInfoBarDelegate
{
115 // If |infobar_service| is NULL, runs |callback| with a single argument with
116 // value "false". Otherwise, creates a dev tools confirm infobar and delegate
117 // and adds the infobar to |infobar_service|.
118 static void Create(InfoBarService
* infobar_service
,
119 const InfoBarCallback
& callback
,
120 const base::string16
& message
);
123 DevToolsConfirmInfoBarDelegate(
124 const InfoBarCallback
& callback
,
125 const base::string16
& message
);
126 ~DevToolsConfirmInfoBarDelegate() override
;
128 base::string16
GetMessageText() const override
;
129 base::string16
GetButtonLabel(InfoBarButton button
) const override
;
130 bool Accept() override
;
131 bool Cancel() override
;
133 InfoBarCallback callback_
;
134 const base::string16 message_
;
136 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate
);
139 void DevToolsConfirmInfoBarDelegate::Create(
140 InfoBarService
* infobar_service
,
141 const InfoBarCallback
& callback
,
142 const base::string16
& message
) {
143 if (!infobar_service
) {
148 infobar_service
->AddInfoBar(
149 infobar_service
->CreateConfirmInfoBar(scoped_ptr
<ConfirmInfoBarDelegate
>(
150 new DevToolsConfirmInfoBarDelegate(callback
, message
))));
153 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
154 const InfoBarCallback
& callback
,
155 const base::string16
& message
)
156 : ConfirmInfoBarDelegate(),
161 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
162 if (!callback_
.is_null())
163 callback_
.Run(false);
166 base::string16
DevToolsConfirmInfoBarDelegate::GetMessageText() const {
170 base::string16
DevToolsConfirmInfoBarDelegate::GetButtonLabel(
171 InfoBarButton button
) const {
172 return l10n_util::GetStringUTF16((button
== BUTTON_OK
) ?
173 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON
: IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON
);
176 bool DevToolsConfirmInfoBarDelegate::Accept() {
182 bool DevToolsConfirmInfoBarDelegate::Cancel() {
183 callback_
.Run(false);
188 // DevToolsUIDefaultDelegate --------------------------------------------------
190 class DefaultBindingsDelegate
: public DevToolsUIBindings::Delegate
{
192 explicit DefaultBindingsDelegate(content::WebContents
* web_contents
)
193 : web_contents_(web_contents
) {}
196 ~DefaultBindingsDelegate() override
{}
198 void ActivateWindow() override
;
199 void CloseWindow() override
{}
200 void SetInspectedPageBounds(const gfx::Rect
& rect
) override
{}
201 void InspectElementCompleted() override
{}
202 void SetIsDocked(bool is_docked
) override
{}
203 void OpenInNewTab(const std::string
& url
) override
;
204 void SetWhitelistedShortcuts(const std::string
& message
) override
{}
206 void InspectedContentsClosing() override
;
207 void OnLoadCompleted() override
{}
208 InfoBarService
* GetInfoBarService() override
;
209 void RenderProcessGone(bool crashed
) override
{}
211 content::WebContents
* web_contents_
;
212 DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate
);
215 void DefaultBindingsDelegate::ActivateWindow() {
216 web_contents_
->GetDelegate()->ActivateContents(web_contents_
);
217 web_contents_
->Focus();
220 void DefaultBindingsDelegate::OpenInNewTab(const std::string
& url
) {
221 content::OpenURLParams
params(
222 GURL(url
), content::Referrer(), NEW_FOREGROUND_TAB
,
223 ui::PAGE_TRANSITION_LINK
, false);
224 Browser
* browser
= FindBrowser(web_contents_
);
225 browser
->OpenURL(params
);
228 void DefaultBindingsDelegate::InspectedContentsClosing() {
229 web_contents_
->GetRenderViewHost()->ClosePage();
232 InfoBarService
* DefaultBindingsDelegate::GetInfoBarService() {
233 return InfoBarService::FromWebContents(web_contents_
);
238 // DevToolsUIBindings::FrontendWebContentsObserver ----------------------------
240 class DevToolsUIBindings::FrontendWebContentsObserver
241 : public content::WebContentsObserver
{
243 explicit FrontendWebContentsObserver(DevToolsUIBindings
* ui_bindings
);
244 ~FrontendWebContentsObserver() override
;
247 // contents::WebContentsObserver:
248 void RenderProcessGone(base::TerminationStatus status
) override
;
249 // TODO(creis): Replace with RenderFrameCreated when http://crbug.com/425397
250 // is fixed. See also http://crbug.com/424641.
251 void AboutToNavigateRenderFrame(
252 content::RenderFrameHost
* old_host
,
253 content::RenderFrameHost
* new_host
) override
;
254 void DocumentOnLoadCompletedInMainFrame() override
;
255 void DidNavigateMainFrame(
256 const content::LoadCommittedDetails
& details
,
257 const content::FrameNavigateParams
& params
) override
;
259 DevToolsUIBindings
* devtools_bindings_
;
260 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver
);
263 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver(
264 DevToolsUIBindings
* devtools_ui_bindings
)
265 : WebContentsObserver(devtools_ui_bindings
->web_contents()),
266 devtools_bindings_(devtools_ui_bindings
) {
269 DevToolsUIBindings::FrontendWebContentsObserver::
270 ~FrontendWebContentsObserver() {
273 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone(
274 base::TerminationStatus status
) {
277 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION
:
278 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED
:
279 case base::TERMINATION_STATUS_PROCESS_CRASHED
:
280 if (devtools_bindings_
->agent_host_
.get())
281 devtools_bindings_
->Detach();
287 devtools_bindings_
->delegate_
->RenderProcessGone(crashed
);
290 void DevToolsUIBindings::FrontendWebContentsObserver::
291 AboutToNavigateRenderFrame(content::RenderFrameHost
* old_host
,
292 content::RenderFrameHost
* new_host
) {
293 if (new_host
->GetParent())
295 devtools_bindings_
->frontend_host_
.reset(
296 content::DevToolsFrontendHost::Create(new_host
,
297 devtools_bindings_
));
300 void DevToolsUIBindings::FrontendWebContentsObserver::
301 DocumentOnLoadCompletedInMainFrame() {
302 devtools_bindings_
->DocumentOnLoadCompletedInMainFrame();
305 void DevToolsUIBindings::FrontendWebContentsObserver::
306 DidNavigateMainFrame(const content::LoadCommittedDetails
& details
,
307 const content::FrameNavigateParams
& params
) {
308 devtools_bindings_
->DidNavigateMainFrame();
311 // DevToolsUIBindings ---------------------------------------------------------
313 DevToolsUIBindings
* DevToolsUIBindings::ForWebContents(
314 content::WebContents
* web_contents
) {
315 if (g_instances
== NULL
)
317 DevToolsUIBindingsList
* instances
= g_instances
.Pointer();
318 for (DevToolsUIBindingsList::iterator
it(instances
->begin());
319 it
!= instances
->end(); ++it
) {
320 if ((*it
)->web_contents() == web_contents
)
327 GURL
DevToolsUIBindings::ApplyThemeToURL(Profile
* profile
,
328 const GURL
& base_url
) {
329 std::string frontend_url
= base_url
.spec();
330 ThemeService
* tp
= ThemeServiceFactory::GetForProfile(profile
);
332 std::string
url_string(
334 ((frontend_url
.find("?") == std::string::npos
) ? "?" : "&") +
335 "dockSide=undocked" + // TODO(dgozman): remove this support in M38.
337 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_TOOLBAR
)) +
339 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT
)));
340 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
341 switches::kEnableDevToolsExperiments
))
342 url_string
+= "&experiments=true";
343 #if defined(DEBUG_DEVTOOLS)
344 url_string
+= "&debugFrontend=true";
345 #endif // defined(DEBUG_DEVTOOLS)
346 return GURL(url_string
);
349 DevToolsUIBindings::DevToolsUIBindings(content::WebContents
* web_contents
)
350 : profile_(Profile::FromBrowserContext(web_contents
->GetBrowserContext())),
351 web_contents_(web_contents
),
352 delegate_(new DefaultBindingsDelegate(web_contents_
)),
353 device_count_updates_enabled_(false),
354 devices_updates_enabled_(false),
355 frontend_loaded_(false),
356 weak_factory_(this) {
357 g_instances
.Get().push_back(this);
358 frontend_contents_observer_
.reset(new FrontendWebContentsObserver(this));
359 web_contents_
->GetMutableRendererPrefs()->can_accept_load_drops
= false;
361 file_helper_
.reset(new DevToolsFileHelper(web_contents_
, profile_
));
362 file_system_indexer_
= new DevToolsFileSystemIndexer();
363 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
366 // Wipe out page icon so that the default application icon is used.
367 content::NavigationEntry
* entry
=
368 web_contents_
->GetController().GetActiveEntry();
369 entry
->GetFavicon().image
= gfx::Image();
370 entry
->GetFavicon().valid
= true;
372 // Register on-load actions.
374 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED
,
375 content::Source
<ThemeService
>(
376 ThemeServiceFactory::GetForProfile(profile_
)));
378 embedder_message_dispatcher_
.reset(
379 DevToolsEmbedderMessageDispatcher::createForDevToolsFrontend(this));
381 frontend_host_
.reset(content::DevToolsFrontendHost::Create(
382 web_contents_
->GetMainFrame(), this));
385 DevToolsUIBindings::~DevToolsUIBindings() {
386 if (agent_host_
.get())
387 agent_host_
->DetachClient();
389 for (IndexingJobsMap::const_iterator
jobs_it(indexing_jobs_
.begin());
390 jobs_it
!= indexing_jobs_
.end(); ++jobs_it
) {
391 jobs_it
->second
->Stop();
393 indexing_jobs_
.clear();
394 SetDeviceCountUpdatesEnabled(false);
395 SetDevicesUpdatesEnabled(false);
397 // Remove self from global list.
398 DevToolsUIBindingsList
* instances
= g_instances
.Pointer();
399 DevToolsUIBindingsList::iterator
it(
400 std::find(instances
->begin(), instances
->end(), this));
401 DCHECK(it
!= instances
->end());
402 instances
->erase(it
);
405 // content::NotificationObserver overrides ------------------------------------
406 void DevToolsUIBindings::Observe(int type
,
407 const content::NotificationSource
& source
,
408 const content::NotificationDetails
& details
) {
409 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED
, type
);
413 // content::DevToolsFrontendHost::Delegate implementation ---------------------
414 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
415 const std::string
& message
) {
417 base::ListValue empty_params
;
418 base::ListValue
* params
= &empty_params
;
420 base::DictionaryValue
* dict
= NULL
;
421 scoped_ptr
<base::Value
> parsed_message(base::JSONReader::Read(message
));
422 if (!parsed_message
||
423 !parsed_message
->GetAsDictionary(&dict
) ||
424 !dict
->GetString(kFrontendHostMethod
, &method
) ||
425 (dict
->HasKey(kFrontendHostParams
) &&
426 !dict
->GetList(kFrontendHostParams
, ¶ms
))) {
427 LOG(ERROR
) << "Invalid message was sent to embedder: " << message
;
432 dict
->GetInteger(kFrontendHostId
, &id
);
435 embedder_message_dispatcher_
->Dispatch(method
, params
, &error
);
437 base::FundamentalValue
id_value(id
);
438 base::StringValue
error_value(error
);
439 CallClientFunction("DevToolsAPI.embedderMessageAck",
440 &id_value
, &error_value
, NULL
);
444 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend(
445 const std::string
& message
) {
446 if (agent_host_
.get())
447 agent_host_
->DispatchProtocolMessage(message
);
450 // content::DevToolsAgentHostClient implementation --------------------------
451 void DevToolsUIBindings::DispatchProtocolMessage(
452 content::DevToolsAgentHost
* agent_host
, const std::string
& message
) {
453 DCHECK(agent_host
== agent_host_
.get());
455 if (message
.length() < kMaxMessageChunkSize
) {
456 base::string16 javascript
= base::UTF8ToUTF16(
457 "DevToolsAPI.dispatchMessage(" + message
+ ");");
458 web_contents_
->GetMainFrame()->ExecuteJavaScript(javascript
);
462 base::FundamentalValue
total_size(static_cast<int>(message
.length()));
463 for (size_t pos
= 0; pos
< message
.length(); pos
+= kMaxMessageChunkSize
) {
464 base::StringValue
message_value(message
.substr(pos
, kMaxMessageChunkSize
));
465 CallClientFunction("DevToolsAPI.dispatchMessageChunk",
466 &message_value
, pos
? NULL
: &total_size
, NULL
);
470 void DevToolsUIBindings::AgentHostClosed(
471 content::DevToolsAgentHost
* agent_host
,
472 bool replaced_with_another_client
) {
473 DCHECK(agent_host
== agent_host_
.get());
475 delegate_
->InspectedContentsClosing();
478 // DevToolsEmbedderMessageDispatcher::Delegate implementation -----------------
479 void DevToolsUIBindings::ActivateWindow() {
480 delegate_
->ActivateWindow();
483 void DevToolsUIBindings::CloseWindow() {
484 delegate_
->CloseWindow();
487 void DevToolsUIBindings::LoadCompleted() {
491 void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect
& rect
) {
492 delegate_
->SetInspectedPageBounds(rect
);
495 void DevToolsUIBindings::SetIsDocked(bool dock_requested
) {
496 delegate_
->SetIsDocked(dock_requested
);
499 void DevToolsUIBindings::InspectElementCompleted() {
500 delegate_
->InspectElementCompleted();
503 void DevToolsUIBindings::InspectedURLChanged(const std::string
& url
) {
504 content::NavigationController
& controller
= web_contents()->GetController();
505 content::NavigationEntry
* entry
= controller
.GetActiveEntry();
506 // DevTools UI is not localized.
508 base::UTF8ToUTF16(base::StringPrintf(kTitleFormat
, url
.c_str())));
509 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE
);
512 void DevToolsUIBindings::OpenInNewTab(const std::string
& url
) {
513 delegate_
->OpenInNewTab(url
);
516 void DevToolsUIBindings::SaveToFile(const std::string
& url
,
517 const std::string
& content
,
519 file_helper_
->Save(url
, content
, save_as
,
520 base::Bind(&DevToolsUIBindings::FileSavedAs
,
521 weak_factory_
.GetWeakPtr(), url
),
522 base::Bind(&DevToolsUIBindings::CanceledFileSaveAs
,
523 weak_factory_
.GetWeakPtr(), url
));
526 void DevToolsUIBindings::AppendToFile(const std::string
& url
,
527 const std::string
& content
) {
528 file_helper_
->Append(url
, content
,
529 base::Bind(&DevToolsUIBindings::AppendedTo
,
530 weak_factory_
.GetWeakPtr(), url
));
533 void DevToolsUIBindings::RequestFileSystems() {
534 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
535 file_helper_
->RequestFileSystems(base::Bind(
536 &DevToolsUIBindings::FileSystemsLoaded
, weak_factory_
.GetWeakPtr()));
539 void DevToolsUIBindings::AddFileSystem() {
540 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
541 file_helper_
->AddFileSystem(
542 base::Bind(&DevToolsUIBindings::FileSystemAdded
,
543 weak_factory_
.GetWeakPtr()),
544 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar
,
545 weak_factory_
.GetWeakPtr()));
548 void DevToolsUIBindings::RemoveFileSystem(
549 const std::string
& file_system_path
) {
550 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
551 file_helper_
->RemoveFileSystem(file_system_path
);
552 base::StringValue
file_system_path_value(file_system_path
);
553 CallClientFunction("DevToolsAPI.fileSystemRemoved",
554 &file_system_path_value
, NULL
, NULL
);
557 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
558 const std::string
& file_system_url
) {
559 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
560 file_helper_
->UpgradeDraggedFileSystemPermissions(
562 base::Bind(&DevToolsUIBindings::FileSystemAdded
,
563 weak_factory_
.GetWeakPtr()),
564 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar
,
565 weak_factory_
.GetWeakPtr()));
568 void DevToolsUIBindings::IndexPath(int request_id
,
569 const std::string
& file_system_path
) {
570 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
571 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
572 if (!file_helper_
->IsFileSystemAdded(file_system_path
)) {
573 IndexingDone(request_id
, file_system_path
);
576 indexing_jobs_
[request_id
] =
577 scoped_refptr
<DevToolsFileSystemIndexer::FileSystemIndexingJob
>(
578 file_system_indexer_
->IndexPath(
580 Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated
,
581 weak_factory_
.GetWeakPtr(),
584 Bind(&DevToolsUIBindings::IndexingWorked
,
585 weak_factory_
.GetWeakPtr(),
588 Bind(&DevToolsUIBindings::IndexingDone
,
589 weak_factory_
.GetWeakPtr(),
594 void DevToolsUIBindings::StopIndexing(int request_id
) {
595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
596 IndexingJobsMap::iterator it
= indexing_jobs_
.find(request_id
);
597 if (it
== indexing_jobs_
.end())
600 indexing_jobs_
.erase(it
);
603 void DevToolsUIBindings::SearchInPath(int request_id
,
604 const std::string
& file_system_path
,
605 const std::string
& query
) {
606 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
607 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
608 if (!file_helper_
->IsFileSystemAdded(file_system_path
)) {
609 SearchCompleted(request_id
, file_system_path
, std::vector
<std::string
>());
612 file_system_indexer_
->SearchInPath(file_system_path
,
614 Bind(&DevToolsUIBindings::SearchCompleted
,
615 weak_factory_
.GetWeakPtr(),
620 void DevToolsUIBindings::SetWhitelistedShortcuts(
621 const std::string
& message
) {
622 delegate_
->SetWhitelistedShortcuts(message
);
625 void DevToolsUIBindings::ZoomIn() {
626 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_IN
);
629 void DevToolsUIBindings::ZoomOut() {
630 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT
);
633 void DevToolsUIBindings::ResetZoom() {
634 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET
);
637 static void InspectTarget(Profile
* profile
, DevToolsTargetImpl
* target
) {
639 target
->Inspect(profile
);
642 void DevToolsUIBindings::OpenUrlOnRemoteDeviceAndInspect(
643 const std::string
& browser_id
,
644 const std::string
& url
) {
645 if (remote_targets_handler_
) {
646 remote_targets_handler_
->Open(browser_id
, url
,
647 base::Bind(&InspectTarget
, profile_
));
651 void DevToolsUIBindings::SetDeviceCountUpdatesEnabled(bool enabled
) {
652 if (device_count_updates_enabled_
== enabled
)
654 DevToolsAndroidBridge
* adb_bridge
=
655 DevToolsAndroidBridge::Factory::GetForProfile(profile_
);
659 device_count_updates_enabled_
= enabled
;
661 adb_bridge
->AddDeviceCountListener(this);
663 adb_bridge
->RemoveDeviceCountListener(this);
666 void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled
) {
667 if (devices_updates_enabled_
== enabled
)
669 devices_updates_enabled_
= enabled
;
671 remote_targets_handler_
= DevToolsTargetsUIHandler::CreateForAdb(
672 base::Bind(&DevToolsUIBindings::DevicesUpdated
,
673 base::Unretained(this)),
676 remote_targets_handler_
.reset();
680 void DevToolsUIBindings::SendMessageToBrowser(const std::string
& message
) {
681 if (agent_host_
.get())
682 agent_host_
->DispatchProtocolMessage(message
);
685 void DevToolsUIBindings::RecordActionUMA(const std::string
& name
, int action
) {
686 if (name
== kDevToolsActionTakenHistogram
)
687 UMA_HISTOGRAM_ENUMERATION(name
, action
, kDevToolsActionTakenBoundary
);
688 else if (name
== kDevToolsPanelShownHistogram
)
689 UMA_HISTOGRAM_ENUMERATION(name
, action
, kDevToolsPanelShownBoundary
);
692 void DevToolsUIBindings::DeviceCountChanged(int count
) {
693 base::FundamentalValue
value(count
);
694 CallClientFunction("DevToolsAPI.deviceCountUpdated", &value
, NULL
,
698 void DevToolsUIBindings::DevicesUpdated(
699 const std::string
& source
,
700 const base::ListValue
& targets
) {
701 CallClientFunction("DevToolsAPI.devicesUpdated", &targets
, NULL
,
705 void DevToolsUIBindings::FileSavedAs(const std::string
& url
) {
706 base::StringValue
url_value(url
);
707 CallClientFunction("DevToolsAPI.savedURL", &url_value
, NULL
, NULL
);
710 void DevToolsUIBindings::CanceledFileSaveAs(const std::string
& url
) {
711 base::StringValue
url_value(url
);
712 CallClientFunction("DevToolsAPI.canceledSaveURL",
713 &url_value
, NULL
, NULL
);
716 void DevToolsUIBindings::AppendedTo(const std::string
& url
) {
717 base::StringValue
url_value(url
);
718 CallClientFunction("DevToolsAPI.appendedToURL", &url_value
, NULL
,
722 void DevToolsUIBindings::FileSystemsLoaded(
723 const std::vector
<DevToolsFileHelper::FileSystem
>& file_systems
) {
724 base::ListValue file_systems_value
;
725 for (size_t i
= 0; i
< file_systems
.size(); ++i
)
726 file_systems_value
.Append(CreateFileSystemValue(file_systems
[i
]));
727 CallClientFunction("DevToolsAPI.fileSystemsLoaded",
728 &file_systems_value
, NULL
, NULL
);
731 void DevToolsUIBindings::FileSystemAdded(
732 const DevToolsFileHelper::FileSystem
& file_system
) {
733 scoped_ptr
<base::StringValue
> error_string_value(
734 new base::StringValue(std::string()));
735 scoped_ptr
<base::DictionaryValue
> file_system_value
;
736 if (!file_system
.file_system_path
.empty())
737 file_system_value
.reset(CreateFileSystemValue(file_system
));
738 CallClientFunction("DevToolsAPI.fileSystemAdded",
739 error_string_value
.get(), file_system_value
.get(), NULL
);
742 void DevToolsUIBindings::IndexingTotalWorkCalculated(
744 const std::string
& file_system_path
,
746 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
747 base::FundamentalValue
request_id_value(request_id
);
748 base::StringValue
file_system_path_value(file_system_path
);
749 base::FundamentalValue
total_work_value(total_work
);
750 CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated",
751 &request_id_value
, &file_system_path_value
,
755 void DevToolsUIBindings::IndexingWorked(int request_id
,
756 const std::string
& file_system_path
,
758 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
759 base::FundamentalValue
request_id_value(request_id
);
760 base::StringValue
file_system_path_value(file_system_path
);
761 base::FundamentalValue
worked_value(worked
);
762 CallClientFunction("DevToolsAPI.indexingWorked", &request_id_value
,
763 &file_system_path_value
, &worked_value
);
766 void DevToolsUIBindings::IndexingDone(int request_id
,
767 const std::string
& file_system_path
) {
768 indexing_jobs_
.erase(request_id
);
769 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
770 base::FundamentalValue
request_id_value(request_id
);
771 base::StringValue
file_system_path_value(file_system_path
);
772 CallClientFunction("DevToolsAPI.indexingDone", &request_id_value
,
773 &file_system_path_value
, NULL
);
776 void DevToolsUIBindings::SearchCompleted(
778 const std::string
& file_system_path
,
779 const std::vector
<std::string
>& file_paths
) {
780 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
781 base::ListValue file_paths_value
;
782 for (std::vector
<std::string
>::const_iterator
it(file_paths
.begin());
783 it
!= file_paths
.end(); ++it
) {
784 file_paths_value
.AppendString(*it
);
786 base::FundamentalValue
request_id_value(request_id
);
787 base::StringValue
file_system_path_value(file_system_path
);
788 CallClientFunction("DevToolsAPI.searchCompleted", &request_id_value
,
789 &file_system_path_value
, &file_paths_value
);
792 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar(
793 const base::string16
& message
,
794 const InfoBarCallback
& callback
) {
795 DevToolsConfirmInfoBarDelegate::Create(delegate_
->GetInfoBarService(),
799 void DevToolsUIBindings::UpdateTheme() {
800 ThemeService
* tp
= ThemeServiceFactory::GetForProfile(profile_
);
803 std::string
command("DevToolsAPI.setToolbarColors(\"" +
804 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_TOOLBAR
)) +
806 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT
)) +
808 web_contents_
->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(command
));
811 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
812 const extensions::ExtensionRegistry
* registry
=
813 extensions::ExtensionRegistry::Get(profile_
->GetOriginalProfile());
817 base::ListValue results
;
818 for (const scoped_refptr
<const extensions::Extension
>& extension
:
819 registry
->enabled_extensions()) {
820 if (extensions::chrome_manifest_urls::GetDevToolsPage(extension
.get())
823 base::DictionaryValue
* extension_info
= new base::DictionaryValue();
826 new base::StringValue(extensions::chrome_manifest_urls::GetDevToolsPage(
827 extension
.get()).spec()));
828 extension_info
->Set("name", new base::StringValue(extension
->name()));
829 extension_info
->Set("exposeExperimentalAPIs",
830 new base::FundamentalValue(
831 extension
->permissions_data()->HasAPIPermission(
832 extensions::APIPermission::kExperimental
)));
833 results
.Append(extension_info
);
835 CallClientFunction("DevToolsAPI.addExtensions",
836 &results
, NULL
, NULL
);
839 void DevToolsUIBindings::SetDelegate(Delegate
* delegate
) {
840 delegate_
.reset(delegate
);
843 void DevToolsUIBindings::AttachTo(
844 const scoped_refptr
<content::DevToolsAgentHost
>& agent_host
) {
845 if (agent_host_
.get())
847 agent_host_
= agent_host
;
848 agent_host_
->AttachClient(this);
851 void DevToolsUIBindings::Reattach() {
852 DCHECK(agent_host_
.get());
853 agent_host_
->DetachClient();
854 agent_host_
->AttachClient(this);
857 void DevToolsUIBindings::Detach() {
858 if (agent_host_
.get())
859 agent_host_
->DetachClient();
863 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost
* agent_host
) {
864 return agent_host_
.get() == agent_host
;
867 void DevToolsUIBindings::CallClientFunction(const std::string
& function_name
,
868 const base::Value
* arg1
,
869 const base::Value
* arg2
,
870 const base::Value
* arg3
) {
871 std::string javascript
= function_name
+ "(";
874 base::JSONWriter::Write(arg1
, &json
);
875 javascript
.append(json
);
877 base::JSONWriter::Write(arg2
, &json
);
878 javascript
.append(", ").append(json
);
880 base::JSONWriter::Write(arg3
, &json
);
881 javascript
.append(", ").append(json
);
885 javascript
.append(");");
886 web_contents_
->GetMainFrame()->ExecuteJavaScript(
887 base::UTF8ToUTF16(javascript
));
890 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() {
891 // In the DEBUG_DEVTOOLS mode, the DocumentOnLoadCompletedInMainFrame event
892 // arrives before the LoadCompleted event, thus it should not trigger the
893 // frontend load handling.
894 #if !defined(DEBUG_DEVTOOLS)
899 void DevToolsUIBindings::DidNavigateMainFrame() {
900 frontend_loaded_
= false;
903 void DevToolsUIBindings::FrontendLoaded() {
904 if (frontend_loaded_
)
906 frontend_loaded_
= true;
908 // Call delegate first - it seeds importants bit of information.
909 delegate_
->OnLoadCompleted();
912 AddDevToolsExtensionsToClient();