ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / devtools / devtools_ui_bindings.cc
blob1ace00dfda9c9358d4c9355410914d13b79a2a2a
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 "net/base/io_buffer.h"
51 #include "net/base/net_errors.h"
52 #include "net/http/http_response_headers.h"
53 #include "net/url_request/url_fetcher.h"
54 #include "net/url_request/url_fetcher_response_writer.h"
55 #include "ui/base/l10n/l10n_util.h"
56 #include "ui/base/page_transition_types.h"
58 using base::DictionaryValue;
59 using content::BrowserThread;
61 namespace content {
62 struct LoadCommittedDetails;
63 struct FrameNavigateParams;
66 namespace {
68 static const char kFrontendHostId[] = "id";
69 static const char kFrontendHostMethod[] = "method";
70 static const char kFrontendHostParams[] = "params";
71 static const char kTitleFormat[] = "Developer Tools - %s";
73 static const char kDevToolsActionTakenHistogram[] = "DevTools.ActionTaken";
74 static const int kDevToolsActionTakenBoundary = 100;
75 static const char kDevToolsPanelShownHistogram[] = "DevTools.PanelShown";
76 static const int kDevToolsPanelShownBoundary = 20;
78 // This constant should be in sync with
79 // the constant at shell_devtools_frontend.cc.
80 const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
82 typedef std::vector<DevToolsUIBindings*> DevToolsUIBindingsList;
83 base::LazyInstance<DevToolsUIBindingsList>::Leaky g_instances =
84 LAZY_INSTANCE_INITIALIZER;
86 std::string SkColorToRGBAString(SkColor color) {
87 // We avoid StringPrintf because it will use locale specific formatters for
88 // the double (e.g. ',' instead of '.' in German).
89 return "rgba(" + base::IntToString(SkColorGetR(color)) + "," +
90 base::IntToString(SkColorGetG(color)) + "," +
91 base::IntToString(SkColorGetB(color)) + "," +
92 base::DoubleToString(SkColorGetA(color) / 255.0) + ")";
95 base::DictionaryValue* CreateFileSystemValue(
96 DevToolsFileHelper::FileSystem file_system) {
97 base::DictionaryValue* file_system_value = new base::DictionaryValue();
98 file_system_value->SetString("fileSystemName", file_system.file_system_name);
99 file_system_value->SetString("rootURL", file_system.root_url);
100 file_system_value->SetString("fileSystemPath", file_system.file_system_path);
101 return file_system_value;
104 Browser* FindBrowser(content::WebContents* web_contents) {
105 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
106 int tab_index = it->tab_strip_model()->GetIndexOfWebContents(
107 web_contents);
108 if (tab_index != TabStripModel::kNoTab)
109 return *it;
111 return NULL;
114 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
116 typedef base::Callback<void(bool)> InfoBarCallback;
118 class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
119 public:
120 // If |infobar_service| is NULL, runs |callback| with a single argument with
121 // value "false". Otherwise, creates a dev tools confirm infobar and delegate
122 // and adds the infobar to |infobar_service|.
123 static void Create(InfoBarService* infobar_service,
124 const InfoBarCallback& callback,
125 const base::string16& message);
127 private:
128 DevToolsConfirmInfoBarDelegate(
129 const InfoBarCallback& callback,
130 const base::string16& message);
131 ~DevToolsConfirmInfoBarDelegate() override;
133 base::string16 GetMessageText() const override;
134 base::string16 GetButtonLabel(InfoBarButton button) const override;
135 bool Accept() override;
136 bool Cancel() override;
138 InfoBarCallback callback_;
139 const base::string16 message_;
141 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate);
144 void DevToolsConfirmInfoBarDelegate::Create(
145 InfoBarService* infobar_service,
146 const InfoBarCallback& callback,
147 const base::string16& message) {
148 if (!infobar_service) {
149 callback.Run(false);
150 return;
153 infobar_service->AddInfoBar(
154 infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
155 new DevToolsConfirmInfoBarDelegate(callback, message))));
158 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
159 const InfoBarCallback& callback,
160 const base::string16& message)
161 : ConfirmInfoBarDelegate(),
162 callback_(callback),
163 message_(message) {
166 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
167 if (!callback_.is_null())
168 callback_.Run(false);
171 base::string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const {
172 return message_;
175 base::string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel(
176 InfoBarButton button) const {
177 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
178 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON);
181 bool DevToolsConfirmInfoBarDelegate::Accept() {
182 callback_.Run(true);
183 callback_.Reset();
184 return true;
187 bool DevToolsConfirmInfoBarDelegate::Cancel() {
188 callback_.Run(false);
189 callback_.Reset();
190 return true;
193 // DevToolsUIDefaultDelegate --------------------------------------------------
195 class DefaultBindingsDelegate : public DevToolsUIBindings::Delegate {
196 public:
197 explicit DefaultBindingsDelegate(content::WebContents* web_contents)
198 : web_contents_(web_contents) {}
200 private:
201 ~DefaultBindingsDelegate() override {}
203 void ActivateWindow() override;
204 void CloseWindow() override {}
205 void SetInspectedPageBounds(const gfx::Rect& rect) override {}
206 void InspectElementCompleted() override {}
207 void SetIsDocked(bool is_docked) override {}
208 void OpenInNewTab(const std::string& url) override;
209 void SetWhitelistedShortcuts(const std::string& message) override {}
211 void InspectedContentsClosing() override;
212 void OnLoadCompleted() override {}
213 InfoBarService* GetInfoBarService() override;
214 void RenderProcessGone(bool crashed) override {}
216 content::WebContents* web_contents_;
217 DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate);
220 void DefaultBindingsDelegate::ActivateWindow() {
221 web_contents_->GetDelegate()->ActivateContents(web_contents_);
222 web_contents_->Focus();
225 void DefaultBindingsDelegate::OpenInNewTab(const std::string& url) {
226 content::OpenURLParams params(
227 GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
228 ui::PAGE_TRANSITION_LINK, false);
229 Browser* browser = FindBrowser(web_contents_);
230 browser->OpenURL(params);
233 void DefaultBindingsDelegate::InspectedContentsClosing() {
234 web_contents_->GetRenderViewHost()->ClosePage();
237 InfoBarService* DefaultBindingsDelegate::GetInfoBarService() {
238 return InfoBarService::FromWebContents(web_contents_);
241 // ResponseWriter -------------------------------------------------------------
243 class ResponseWriter : public net::URLFetcherResponseWriter {
244 public:
245 ResponseWriter(base::WeakPtr<DevToolsUIBindings> bindings, int stream_id);
246 ~ResponseWriter() override;
248 // URLFetcherResponseWriter overrides:
249 int Initialize(const net::CompletionCallback& callback) override;
250 int Write(net::IOBuffer* buffer,
251 int num_bytes,
252 const net::CompletionCallback& callback) override;
253 int Finish(const net::CompletionCallback& callback) override;
255 private:
256 base::WeakPtr<DevToolsUIBindings> bindings_;
257 int stream_id_;
259 DISALLOW_COPY_AND_ASSIGN(ResponseWriter);
262 ResponseWriter::ResponseWriter(base::WeakPtr<DevToolsUIBindings> bindings,
263 int stream_id)
264 : bindings_(bindings),
265 stream_id_(stream_id) {
268 ResponseWriter::~ResponseWriter() {
271 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
272 return net::OK;
275 int ResponseWriter::Write(net::IOBuffer* buffer,
276 int num_bytes,
277 const net::CompletionCallback& callback) {
278 base::FundamentalValue* id = new base::FundamentalValue(stream_id_);
279 base::StringValue* chunk =
280 new base::StringValue(std::string(buffer->data(), num_bytes));
282 content::BrowserThread::PostTask(
283 content::BrowserThread::UI, FROM_HERE,
284 base::Bind(&DevToolsUIBindings::CallClientFunction,
285 bindings_, "DevToolsAPI.streamWrite",
286 base::Owned(id), base::Owned(chunk), nullptr));
287 return num_bytes;
290 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
291 return net::OK;
294 } // namespace
296 // DevToolsUIBindings::FrontendWebContentsObserver ----------------------------
298 class DevToolsUIBindings::FrontendWebContentsObserver
299 : public content::WebContentsObserver {
300 public:
301 explicit FrontendWebContentsObserver(DevToolsUIBindings* ui_bindings);
302 ~FrontendWebContentsObserver() override;
304 private:
305 // contents::WebContentsObserver:
306 void RenderProcessGone(base::TerminationStatus status) override;
307 // TODO(creis): Replace with RenderFrameCreated when http://crbug.com/425397
308 // is fixed. See also http://crbug.com/424641.
309 void AboutToNavigateRenderFrame(
310 content::RenderFrameHost* old_host,
311 content::RenderFrameHost* new_host) override;
312 void DocumentOnLoadCompletedInMainFrame() override;
313 void DidNavigateMainFrame(
314 const content::LoadCommittedDetails& details,
315 const content::FrameNavigateParams& params) override;
317 DevToolsUIBindings* devtools_bindings_;
318 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver);
321 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver(
322 DevToolsUIBindings* devtools_ui_bindings)
323 : WebContentsObserver(devtools_ui_bindings->web_contents()),
324 devtools_bindings_(devtools_ui_bindings) {
327 DevToolsUIBindings::FrontendWebContentsObserver::
328 ~FrontendWebContentsObserver() {
331 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone(
332 base::TerminationStatus status) {
333 bool crashed = true;
334 switch (status) {
335 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
336 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
337 case base::TERMINATION_STATUS_PROCESS_CRASHED:
338 if (devtools_bindings_->agent_host_.get())
339 devtools_bindings_->Detach();
340 break;
341 default:
342 crashed = false;
343 break;
345 devtools_bindings_->delegate_->RenderProcessGone(crashed);
348 void DevToolsUIBindings::FrontendWebContentsObserver::
349 AboutToNavigateRenderFrame(content::RenderFrameHost* old_host,
350 content::RenderFrameHost* new_host) {
351 if (new_host->GetParent())
352 return;
353 devtools_bindings_->frontend_host_.reset(
354 content::DevToolsFrontendHost::Create(new_host,
355 devtools_bindings_));
358 void DevToolsUIBindings::FrontendWebContentsObserver::
359 DocumentOnLoadCompletedInMainFrame() {
360 devtools_bindings_->DocumentOnLoadCompletedInMainFrame();
363 void DevToolsUIBindings::FrontendWebContentsObserver::
364 DidNavigateMainFrame(const content::LoadCommittedDetails& details,
365 const content::FrameNavigateParams& params) {
366 devtools_bindings_->DidNavigateMainFrame();
369 // DevToolsUIBindings ---------------------------------------------------------
371 DevToolsUIBindings* DevToolsUIBindings::ForWebContents(
372 content::WebContents* web_contents) {
373 if (g_instances == NULL)
374 return NULL;
375 DevToolsUIBindingsList* instances = g_instances.Pointer();
376 for (DevToolsUIBindingsList::iterator it(instances->begin());
377 it != instances->end(); ++it) {
378 if ((*it)->web_contents() == web_contents)
379 return *it;
381 return NULL;
384 // static
385 GURL DevToolsUIBindings::ApplyThemeToURL(Profile* profile,
386 const GURL& base_url) {
387 std::string frontend_url = base_url.spec();
388 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile);
389 DCHECK(tp);
390 std::string url_string(
391 frontend_url +
392 ((frontend_url.find("?") == std::string::npos) ? "?" : "&") +
393 "dockSide=undocked" + // TODO(dgozman): remove this support in M38.
394 "&toolbarColor=" +
395 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
396 "&textColor=" +
397 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)));
398 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
399 switches::kEnableDevToolsExperiments))
400 url_string += "&experiments=true";
401 #if defined(DEBUG_DEVTOOLS)
402 url_string += "&debugFrontend=true";
403 #endif // defined(DEBUG_DEVTOOLS)
404 return GURL(url_string);
407 DevToolsUIBindings::DevToolsUIBindings(content::WebContents* web_contents)
408 : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
409 web_contents_(web_contents),
410 delegate_(new DefaultBindingsDelegate(web_contents_)),
411 device_count_updates_enabled_(false),
412 devices_updates_enabled_(false),
413 frontend_loaded_(false),
414 weak_factory_(this) {
415 g_instances.Get().push_back(this);
416 frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
417 web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false;
419 file_helper_.reset(new DevToolsFileHelper(web_contents_, profile_));
420 file_system_indexer_ = new DevToolsFileSystemIndexer();
421 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
422 web_contents_);
424 // Wipe out page icon so that the default application icon is used.
425 content::NavigationEntry* entry =
426 web_contents_->GetController().GetActiveEntry();
427 entry->GetFavicon().image = gfx::Image();
428 entry->GetFavicon().valid = true;
430 // Register on-load actions.
431 registrar_.Add(
432 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
433 content::Source<ThemeService>(
434 ThemeServiceFactory::GetForProfile(profile_)));
436 embedder_message_dispatcher_.reset(
437 DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this));
439 frontend_host_.reset(content::DevToolsFrontendHost::Create(
440 web_contents_->GetMainFrame(), this));
443 DevToolsUIBindings::~DevToolsUIBindings() {
444 for (const auto& pair : pending_requests_)
445 delete pair.first;
447 if (agent_host_.get())
448 agent_host_->DetachClient();
450 for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin());
451 jobs_it != indexing_jobs_.end(); ++jobs_it) {
452 jobs_it->second->Stop();
454 indexing_jobs_.clear();
455 SetDeviceCountUpdatesEnabled(0, false);
456 SetDevicesUpdatesEnabled(0, false);
458 // Remove self from global list.
459 DevToolsUIBindingsList* instances = g_instances.Pointer();
460 DevToolsUIBindingsList::iterator it(
461 std::find(instances->begin(), instances->end(), this));
462 DCHECK(it != instances->end());
463 instances->erase(it);
466 // content::NotificationObserver overrides ------------------------------------
467 void DevToolsUIBindings::Observe(int type,
468 const content::NotificationSource& source,
469 const content::NotificationDetails& details) {
470 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
471 UpdateTheme();
474 // content::DevToolsFrontendHost::Delegate implementation ---------------------
475 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
476 const std::string& message) {
477 std::string method;
478 base::ListValue empty_params;
479 base::ListValue* params = &empty_params;
481 base::DictionaryValue* dict = NULL;
482 scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
483 if (!parsed_message ||
484 !parsed_message->GetAsDictionary(&dict) ||
485 !dict->GetString(kFrontendHostMethod, &method) ||
486 (dict->HasKey(kFrontendHostParams) &&
487 !dict->GetList(kFrontendHostParams, &params))) {
488 LOG(ERROR) << "Invalid message was sent to embedder: " << message;
489 return;
491 int id = 0;
492 dict->GetInteger(kFrontendHostId, &id);
493 embedder_message_dispatcher_->Dispatch(id, method, params);
496 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend(
497 const std::string& message) {
498 if (agent_host_.get())
499 agent_host_->DispatchProtocolMessage(message);
502 // content::DevToolsAgentHostClient implementation --------------------------
503 void DevToolsUIBindings::DispatchProtocolMessage(
504 content::DevToolsAgentHost* agent_host, const std::string& message) {
505 DCHECK(agent_host == agent_host_.get());
507 if (message.length() < kMaxMessageChunkSize) {
508 base::string16 javascript = base::UTF8ToUTF16(
509 "DevToolsAPI.dispatchMessage(" + message + ");");
510 web_contents_->GetMainFrame()->ExecuteJavaScript(javascript);
511 return;
514 base::FundamentalValue total_size(static_cast<int>(message.length()));
515 for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
516 base::StringValue message_value(message.substr(pos, kMaxMessageChunkSize));
517 CallClientFunction("DevToolsAPI.dispatchMessageChunk",
518 &message_value, pos ? NULL : &total_size, NULL);
522 void DevToolsUIBindings::AgentHostClosed(
523 content::DevToolsAgentHost* agent_host,
524 bool replaced_with_another_client) {
525 DCHECK(agent_host == agent_host_.get());
526 agent_host_ = NULL;
527 delegate_->InspectedContentsClosing();
530 void DevToolsUIBindings::SendMessageAck(int request_id,
531 const base::Value* arg) {
532 base::FundamentalValue id_value(request_id);
533 CallClientFunction("DevToolsAPI.embedderMessageAck",
534 &id_value, arg, nullptr);
537 // DevToolsEmbedderMessageDispatcher::Delegate implementation -----------------
538 void DevToolsUIBindings::ActivateWindow(int request_id) {
539 delegate_->ActivateWindow();
542 void DevToolsUIBindings::CloseWindow(int request_id) {
543 delegate_->CloseWindow();
546 void DevToolsUIBindings::LoadCompleted(int request_id) {
547 FrontendLoaded();
550 void DevToolsUIBindings::SetInspectedPageBounds(int request_id,
551 const gfx::Rect& rect) {
552 delegate_->SetInspectedPageBounds(rect);
555 void DevToolsUIBindings::SetIsDocked(int request_id, bool dock_requested) {
556 delegate_->SetIsDocked(dock_requested);
557 SendMessageAck(request_id, nullptr);
560 void DevToolsUIBindings::InspectElementCompleted(int request_id) {
561 delegate_->InspectElementCompleted();
564 void DevToolsUIBindings::InspectedURLChanged(int request_id,
565 const std::string& url) {
566 content::NavigationController& controller = web_contents()->GetController();
567 content::NavigationEntry* entry = controller.GetActiveEntry();
568 // DevTools UI is not localized.
569 entry->SetTitle(
570 base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str())));
571 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
574 void DevToolsUIBindings::LoadNetworkResource(int request_id,
575 const std::string& url,
576 const std::string& headers,
577 int stream_id) {
578 GURL gurl(url);
579 if (!gurl.is_valid()) {
580 base::DictionaryValue response;
581 response.SetInteger("statusCode", 404);
582 SendMessageAck(request_id, &response);
583 return;
586 net::URLFetcher* fetcher =
587 net::URLFetcher::Create(gurl, net::URLFetcher::GET, this);
588 pending_requests_[fetcher] = request_id;
589 fetcher->SetRequestContext(profile_->GetRequestContext());
590 fetcher->SetExtraRequestHeaders(headers);
591 fetcher->SaveResponseWithWriter(scoped_ptr<net::URLFetcherResponseWriter>(
592 new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id)));
593 fetcher->Start();
596 void DevToolsUIBindings::OpenInNewTab(int request_id, const std::string& url) {
597 delegate_->OpenInNewTab(url);
600 void DevToolsUIBindings::SaveToFile(int request_id,
601 const std::string& url,
602 const std::string& content,
603 bool save_as) {
604 file_helper_->Save(url, content, save_as,
605 base::Bind(&DevToolsUIBindings::FileSavedAs,
606 weak_factory_.GetWeakPtr(), url),
607 base::Bind(&DevToolsUIBindings::CanceledFileSaveAs,
608 weak_factory_.GetWeakPtr(), url));
611 void DevToolsUIBindings::AppendToFile(int request_id,
612 const std::string& url,
613 const std::string& content) {
614 file_helper_->Append(url, content,
615 base::Bind(&DevToolsUIBindings::AppendedTo,
616 weak_factory_.GetWeakPtr(), url));
619 void DevToolsUIBindings::RequestFileSystems(int request_id) {
620 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
621 file_helper_->RequestFileSystems(base::Bind(
622 &DevToolsUIBindings::FileSystemsLoaded, weak_factory_.GetWeakPtr()));
625 void DevToolsUIBindings::AddFileSystem(int request_id) {
626 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
627 file_helper_->AddFileSystem(
628 base::Bind(&DevToolsUIBindings::FileSystemAdded,
629 weak_factory_.GetWeakPtr()),
630 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
631 weak_factory_.GetWeakPtr()));
634 void DevToolsUIBindings::RemoveFileSystem(int request_id,
635 const std::string& file_system_path) {
636 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
637 file_helper_->RemoveFileSystem(file_system_path);
638 base::StringValue file_system_path_value(file_system_path);
639 CallClientFunction("DevToolsAPI.fileSystemRemoved",
640 &file_system_path_value, NULL, NULL);
643 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
644 int request_id,
645 const std::string& file_system_url) {
646 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
647 file_helper_->UpgradeDraggedFileSystemPermissions(
648 file_system_url,
649 base::Bind(&DevToolsUIBindings::FileSystemAdded,
650 weak_factory_.GetWeakPtr()),
651 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
652 weak_factory_.GetWeakPtr()));
655 void DevToolsUIBindings::IndexPath(int request_id,
656 int index_request_id,
657 const std::string& file_system_path) {
658 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
659 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
660 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
661 IndexingDone(index_request_id, file_system_path);
662 return;
664 if (indexing_jobs_.count(index_request_id) != 0)
665 return;
666 indexing_jobs_[index_request_id] =
667 scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
668 file_system_indexer_->IndexPath(
669 file_system_path,
670 Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated,
671 weak_factory_.GetWeakPtr(),
672 index_request_id,
673 file_system_path),
674 Bind(&DevToolsUIBindings::IndexingWorked,
675 weak_factory_.GetWeakPtr(),
676 index_request_id,
677 file_system_path),
678 Bind(&DevToolsUIBindings::IndexingDone,
679 weak_factory_.GetWeakPtr(),
680 index_request_id,
681 file_system_path)));
684 void DevToolsUIBindings::StopIndexing(int request_id, int index_request_id) {
685 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
686 IndexingJobsMap::iterator it = indexing_jobs_.find(index_request_id);
687 if (it == indexing_jobs_.end())
688 return;
689 it->second->Stop();
690 indexing_jobs_.erase(it);
693 void DevToolsUIBindings::SearchInPath(int request_id,
694 int search_request_id,
695 const std::string& file_system_path,
696 const std::string& query) {
697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
698 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
699 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
700 SearchCompleted(search_request_id,
701 file_system_path,
702 std::vector<std::string>());
703 return;
705 file_system_indexer_->SearchInPath(file_system_path,
706 query,
707 Bind(&DevToolsUIBindings::SearchCompleted,
708 weak_factory_.GetWeakPtr(),
709 search_request_id,
710 file_system_path));
713 void DevToolsUIBindings::SetWhitelistedShortcuts(int request_id,
714 const std::string& message) {
715 delegate_->SetWhitelistedShortcuts(message);
718 void DevToolsUIBindings::ZoomIn(int request_id) {
719 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_IN);
722 void DevToolsUIBindings::ZoomOut(int request_id) {
723 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT);
726 void DevToolsUIBindings::ResetZoom(int request_id) {
727 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET);
730 static void InspectTarget(Profile* profile, DevToolsTargetImpl* target) {
731 if (target)
732 target->Inspect(profile);
735 void DevToolsUIBindings::OpenUrlOnRemoteDeviceAndInspect(
736 int request_id,
737 const std::string& browser_id,
738 const std::string& url) {
739 if (remote_targets_handler_) {
740 remote_targets_handler_->Open(browser_id, url,
741 base::Bind(&InspectTarget, profile_));
745 void DevToolsUIBindings::SetDeviceCountUpdatesEnabled(int request_id,
746 bool enabled) {
747 if (device_count_updates_enabled_ == enabled)
748 return;
749 DevToolsAndroidBridge* adb_bridge =
750 DevToolsAndroidBridge::Factory::GetForProfile(profile_);
751 if (!adb_bridge)
752 return;
754 device_count_updates_enabled_ = enabled;
755 if (enabled)
756 adb_bridge->AddDeviceCountListener(this);
757 else
758 adb_bridge->RemoveDeviceCountListener(this);
761 void DevToolsUIBindings::SetDevicesUpdatesEnabled(int request_id,
762 bool enabled) {
763 if (devices_updates_enabled_ == enabled)
764 return;
765 devices_updates_enabled_ = enabled;
766 if (enabled) {
767 remote_targets_handler_ = DevToolsTargetsUIHandler::CreateForAdb(
768 base::Bind(&DevToolsUIBindings::DevicesUpdated,
769 base::Unretained(this)),
770 profile_);
771 } else {
772 remote_targets_handler_.reset();
776 void DevToolsUIBindings::SendMessageToBrowser(int request_id,
777 const std::string& message) {
778 if (agent_host_.get())
779 agent_host_->DispatchProtocolMessage(message);
782 void DevToolsUIBindings::RecordActionUMA(int request_id,
783 const std::string& name,
784 int action) {
785 if (name == kDevToolsActionTakenHistogram)
786 UMA_HISTOGRAM_ENUMERATION(name, action, kDevToolsActionTakenBoundary);
787 else if (name == kDevToolsPanelShownHistogram)
788 UMA_HISTOGRAM_ENUMERATION(name, action, kDevToolsPanelShownBoundary);
791 void DevToolsUIBindings::OnURLFetchComplete(const net::URLFetcher* source) {
792 DCHECK(source);
793 PendingRequestsMap::iterator it = pending_requests_.find(source);
794 DCHECK(it != pending_requests_.end());
796 base::DictionaryValue response;
797 base::DictionaryValue* headers = new base::DictionaryValue();
798 net::HttpResponseHeaders* rh = source->GetResponseHeaders();
799 response.SetInteger("statusCode", rh ? rh->response_code() : 200);
800 response.Set("headers", headers);
802 void* iterator = NULL;
803 std::string name;
804 std::string value;
805 while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value))
806 headers->SetString(name, value);
808 SendMessageAck(it->second, &response);
809 pending_requests_.erase(it);
810 delete source;
813 void DevToolsUIBindings::DeviceCountChanged(int count) {
814 base::FundamentalValue value(count);
815 CallClientFunction("DevToolsAPI.deviceCountUpdated", &value, NULL,
816 NULL);
819 void DevToolsUIBindings::DevicesUpdated(
820 const std::string& source,
821 const base::ListValue& targets) {
822 CallClientFunction("DevToolsAPI.devicesUpdated", &targets, NULL,
823 NULL);
826 void DevToolsUIBindings::FileSavedAs(const std::string& url) {
827 base::StringValue url_value(url);
828 CallClientFunction("DevToolsAPI.savedURL", &url_value, NULL, NULL);
831 void DevToolsUIBindings::CanceledFileSaveAs(const std::string& url) {
832 base::StringValue url_value(url);
833 CallClientFunction("DevToolsAPI.canceledSaveURL",
834 &url_value, NULL, NULL);
837 void DevToolsUIBindings::AppendedTo(const std::string& url) {
838 base::StringValue url_value(url);
839 CallClientFunction("DevToolsAPI.appendedToURL", &url_value, NULL,
840 NULL);
843 void DevToolsUIBindings::FileSystemsLoaded(
844 const std::vector<DevToolsFileHelper::FileSystem>& file_systems) {
845 base::ListValue file_systems_value;
846 for (size_t i = 0; i < file_systems.size(); ++i)
847 file_systems_value.Append(CreateFileSystemValue(file_systems[i]));
848 CallClientFunction("DevToolsAPI.fileSystemsLoaded",
849 &file_systems_value, NULL, NULL);
852 void DevToolsUIBindings::FileSystemAdded(
853 const DevToolsFileHelper::FileSystem& file_system) {
854 scoped_ptr<base::StringValue> error_string_value(
855 new base::StringValue(std::string()));
856 scoped_ptr<base::DictionaryValue> file_system_value;
857 if (!file_system.file_system_path.empty())
858 file_system_value.reset(CreateFileSystemValue(file_system));
859 CallClientFunction("DevToolsAPI.fileSystemAdded",
860 error_string_value.get(), file_system_value.get(), NULL);
863 void DevToolsUIBindings::IndexingTotalWorkCalculated(
864 int request_id,
865 const std::string& file_system_path,
866 int total_work) {
867 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
868 base::FundamentalValue request_id_value(request_id);
869 base::StringValue file_system_path_value(file_system_path);
870 base::FundamentalValue total_work_value(total_work);
871 CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated",
872 &request_id_value, &file_system_path_value,
873 &total_work_value);
876 void DevToolsUIBindings::IndexingWorked(int request_id,
877 const std::string& file_system_path,
878 int worked) {
879 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
880 base::FundamentalValue request_id_value(request_id);
881 base::StringValue file_system_path_value(file_system_path);
882 base::FundamentalValue worked_value(worked);
883 CallClientFunction("DevToolsAPI.indexingWorked", &request_id_value,
884 &file_system_path_value, &worked_value);
887 void DevToolsUIBindings::IndexingDone(int request_id,
888 const std::string& file_system_path) {
889 indexing_jobs_.erase(request_id);
890 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
891 base::FundamentalValue request_id_value(request_id);
892 base::StringValue file_system_path_value(file_system_path);
893 CallClientFunction("DevToolsAPI.indexingDone", &request_id_value,
894 &file_system_path_value, NULL);
897 void DevToolsUIBindings::SearchCompleted(
898 int request_id,
899 const std::string& file_system_path,
900 const std::vector<std::string>& file_paths) {
901 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
902 base::ListValue file_paths_value;
903 for (std::vector<std::string>::const_iterator it(file_paths.begin());
904 it != file_paths.end(); ++it) {
905 file_paths_value.AppendString(*it);
907 base::FundamentalValue request_id_value(request_id);
908 base::StringValue file_system_path_value(file_system_path);
909 CallClientFunction("DevToolsAPI.searchCompleted", &request_id_value,
910 &file_system_path_value, &file_paths_value);
913 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar(
914 const base::string16& message,
915 const InfoBarCallback& callback) {
916 DevToolsConfirmInfoBarDelegate::Create(delegate_->GetInfoBarService(),
917 callback, message);
920 void DevToolsUIBindings::UpdateTheme() {
921 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_);
922 DCHECK(tp);
924 std::string command("DevToolsAPI.setToolbarColors(\"" +
925 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
926 "\", \"" +
927 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) +
928 "\")");
929 web_contents_->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(command));
932 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
933 const extensions::ExtensionRegistry* registry =
934 extensions::ExtensionRegistry::Get(profile_->GetOriginalProfile());
935 if (!registry)
936 return;
938 base::ListValue results;
939 for (const scoped_refptr<const extensions::Extension>& extension :
940 registry->enabled_extensions()) {
941 if (extensions::chrome_manifest_urls::GetDevToolsPage(extension.get())
942 .is_empty())
943 continue;
944 base::DictionaryValue* extension_info = new base::DictionaryValue();
945 extension_info->Set(
946 "startPage",
947 new base::StringValue(extensions::chrome_manifest_urls::GetDevToolsPage(
948 extension.get()).spec()));
949 extension_info->Set("name", new base::StringValue(extension->name()));
950 extension_info->Set("exposeExperimentalAPIs",
951 new base::FundamentalValue(
952 extension->permissions_data()->HasAPIPermission(
953 extensions::APIPermission::kExperimental)));
954 results.Append(extension_info);
956 CallClientFunction("DevToolsAPI.addExtensions",
957 &results, NULL, NULL);
960 void DevToolsUIBindings::SetDelegate(Delegate* delegate) {
961 delegate_.reset(delegate);
964 void DevToolsUIBindings::AttachTo(
965 const scoped_refptr<content::DevToolsAgentHost>& agent_host) {
966 if (agent_host_.get())
967 Detach();
968 agent_host_ = agent_host;
969 agent_host_->AttachClient(this);
972 void DevToolsUIBindings::Reattach() {
973 DCHECK(agent_host_.get());
974 agent_host_->DetachClient();
975 agent_host_->AttachClient(this);
978 void DevToolsUIBindings::Detach() {
979 if (agent_host_.get())
980 agent_host_->DetachClient();
981 agent_host_ = NULL;
984 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost* agent_host) {
985 return agent_host_.get() == agent_host;
988 void DevToolsUIBindings::CallClientFunction(const std::string& function_name,
989 const base::Value* arg1,
990 const base::Value* arg2,
991 const base::Value* arg3) {
992 std::string javascript = function_name + "(";
993 if (arg1) {
994 std::string json;
995 base::JSONWriter::Write(arg1, &json);
996 javascript.append(json);
997 if (arg2) {
998 base::JSONWriter::Write(arg2, &json);
999 javascript.append(", ").append(json);
1000 if (arg3) {
1001 base::JSONWriter::Write(arg3, &json);
1002 javascript.append(", ").append(json);
1006 javascript.append(");");
1007 web_contents_->GetMainFrame()->ExecuteJavaScript(
1008 base::UTF8ToUTF16(javascript));
1011 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() {
1012 // In the DEBUG_DEVTOOLS mode, the DocumentOnLoadCompletedInMainFrame event
1013 // arrives before the LoadCompleted event, thus it should not trigger the
1014 // frontend load handling.
1015 #if !defined(DEBUG_DEVTOOLS)
1016 FrontendLoaded();
1017 #endif
1020 void DevToolsUIBindings::DidNavigateMainFrame() {
1021 frontend_loaded_ = false;
1024 void DevToolsUIBindings::FrontendLoaded() {
1025 if (frontend_loaded_)
1026 return;
1027 frontend_loaded_ = true;
1029 // Call delegate first - it seeds importants bit of information.
1030 delegate_->OnLoadCompleted();
1032 UpdateTheme();
1033 AddDevToolsExtensionsToClient();