[cros new GAIA] Update GAIA card size
[chromium-blink-merge.git] / chrome / browser / devtools / devtools_ui_bindings.cc
blob294b9c29a24c45a7d158fd6d12dd8c7a5ef7a1f5
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 char kDevToolsPanelShownHistogram[] = "DevTools.PanelShown";
76 // This constant should be in sync with
77 // the constant at shell_devtools_frontend.cc.
78 const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
80 typedef std::vector<DevToolsUIBindings*> DevToolsUIBindingsList;
81 base::LazyInstance<DevToolsUIBindingsList>::Leaky g_instances =
82 LAZY_INSTANCE_INITIALIZER;
84 std::string SkColorToRGBAString(SkColor color) {
85 // We avoid StringPrintf because it will use locale specific formatters for
86 // the double (e.g. ',' instead of '.' in German).
87 return "rgba(" + base::IntToString(SkColorGetR(color)) + "," +
88 base::IntToString(SkColorGetG(color)) + "," +
89 base::IntToString(SkColorGetB(color)) + "," +
90 base::DoubleToString(SkColorGetA(color) / 255.0) + ")";
93 base::DictionaryValue* CreateFileSystemValue(
94 DevToolsFileHelper::FileSystem file_system) {
95 base::DictionaryValue* file_system_value = new base::DictionaryValue();
96 file_system_value->SetString("fileSystemName", file_system.file_system_name);
97 file_system_value->SetString("rootURL", file_system.root_url);
98 file_system_value->SetString("fileSystemPath", file_system.file_system_path);
99 return file_system_value;
102 Browser* FindBrowser(content::WebContents* web_contents) {
103 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
104 int tab_index = it->tab_strip_model()->GetIndexOfWebContents(
105 web_contents);
106 if (tab_index != TabStripModel::kNoTab)
107 return *it;
109 return NULL;
112 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
114 typedef base::Callback<void(bool)> InfoBarCallback;
116 class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
117 public:
118 // If |infobar_service| is NULL, runs |callback| with a single argument with
119 // value "false". Otherwise, creates a dev tools confirm infobar and delegate
120 // and adds the infobar to |infobar_service|.
121 static void Create(InfoBarService* infobar_service,
122 const InfoBarCallback& callback,
123 const base::string16& message);
125 private:
126 DevToolsConfirmInfoBarDelegate(
127 const InfoBarCallback& callback,
128 const base::string16& message);
129 ~DevToolsConfirmInfoBarDelegate() override;
131 base::string16 GetMessageText() const override;
132 base::string16 GetButtonLabel(InfoBarButton button) const override;
133 bool Accept() override;
134 bool Cancel() override;
136 InfoBarCallback callback_;
137 const base::string16 message_;
139 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate);
142 void DevToolsConfirmInfoBarDelegate::Create(
143 InfoBarService* infobar_service,
144 const InfoBarCallback& callback,
145 const base::string16& message) {
146 if (!infobar_service) {
147 callback.Run(false);
148 return;
151 infobar_service->AddInfoBar(
152 infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
153 new DevToolsConfirmInfoBarDelegate(callback, message))));
156 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
157 const InfoBarCallback& callback,
158 const base::string16& message)
159 : ConfirmInfoBarDelegate(),
160 callback_(callback),
161 message_(message) {
164 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
165 if (!callback_.is_null())
166 callback_.Run(false);
169 base::string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const {
170 return message_;
173 base::string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel(
174 InfoBarButton button) const {
175 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
176 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON);
179 bool DevToolsConfirmInfoBarDelegate::Accept() {
180 callback_.Run(true);
181 callback_.Reset();
182 return true;
185 bool DevToolsConfirmInfoBarDelegate::Cancel() {
186 callback_.Run(false);
187 callback_.Reset();
188 return true;
191 // DevToolsUIDefaultDelegate --------------------------------------------------
193 class DefaultBindingsDelegate : public DevToolsUIBindings::Delegate {
194 public:
195 explicit DefaultBindingsDelegate(content::WebContents* web_contents)
196 : web_contents_(web_contents) {}
198 private:
199 ~DefaultBindingsDelegate() override {}
201 void ActivateWindow() override;
202 void CloseWindow() override {}
203 void SetInspectedPageBounds(const gfx::Rect& rect) override {}
204 void InspectElementCompleted() override {}
205 void SetIsDocked(bool is_docked) override {}
206 void OpenInNewTab(const std::string& url) override;
207 void SetWhitelistedShortcuts(const std::string& message) override {}
209 void InspectedContentsClosing() override;
210 void OnLoadCompleted() override {}
211 InfoBarService* GetInfoBarService() override;
212 void RenderProcessGone(bool crashed) override {}
214 content::WebContents* web_contents_;
215 DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate);
218 void DefaultBindingsDelegate::ActivateWindow() {
219 web_contents_->GetDelegate()->ActivateContents(web_contents_);
220 web_contents_->Focus();
223 void DefaultBindingsDelegate::OpenInNewTab(const std::string& url) {
224 content::OpenURLParams params(
225 GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
226 ui::PAGE_TRANSITION_LINK, false);
227 Browser* browser = FindBrowser(web_contents_);
228 browser->OpenURL(params);
231 void DefaultBindingsDelegate::InspectedContentsClosing() {
232 web_contents_->GetRenderViewHost()->ClosePage();
235 InfoBarService* DefaultBindingsDelegate::GetInfoBarService() {
236 return InfoBarService::FromWebContents(web_contents_);
239 // ResponseWriter -------------------------------------------------------------
241 class ResponseWriter : public net::URLFetcherResponseWriter {
242 public:
243 ResponseWriter(base::WeakPtr<DevToolsUIBindings> bindings, int stream_id);
244 ~ResponseWriter() override;
246 // URLFetcherResponseWriter overrides:
247 int Initialize(const net::CompletionCallback& callback) override;
248 int Write(net::IOBuffer* buffer,
249 int num_bytes,
250 const net::CompletionCallback& callback) override;
251 int Finish(const net::CompletionCallback& callback) override;
253 private:
254 base::WeakPtr<DevToolsUIBindings> bindings_;
255 int stream_id_;
257 DISALLOW_COPY_AND_ASSIGN(ResponseWriter);
260 ResponseWriter::ResponseWriter(base::WeakPtr<DevToolsUIBindings> bindings,
261 int stream_id)
262 : bindings_(bindings),
263 stream_id_(stream_id) {
266 ResponseWriter::~ResponseWriter() {
269 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
270 return net::OK;
273 int ResponseWriter::Write(net::IOBuffer* buffer,
274 int num_bytes,
275 const net::CompletionCallback& callback) {
276 base::FundamentalValue* id = new base::FundamentalValue(stream_id_);
277 base::StringValue* chunk =
278 new base::StringValue(std::string(buffer->data(), num_bytes));
280 content::BrowserThread::PostTask(
281 content::BrowserThread::UI, FROM_HERE,
282 base::Bind(&DevToolsUIBindings::CallClientFunction,
283 bindings_, "DevToolsAPI.streamWrite",
284 base::Owned(id), base::Owned(chunk), nullptr));
285 return num_bytes;
288 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
289 return net::OK;
292 } // namespace
294 // DevToolsUIBindings::FrontendWebContentsObserver ----------------------------
296 class DevToolsUIBindings::FrontendWebContentsObserver
297 : public content::WebContentsObserver {
298 public:
299 explicit FrontendWebContentsObserver(DevToolsUIBindings* ui_bindings);
300 ~FrontendWebContentsObserver() override;
302 private:
303 // contents::WebContentsObserver:
304 void RenderProcessGone(base::TerminationStatus status) override;
305 // TODO(creis): Replace with RenderFrameCreated when http://crbug.com/425397
306 // is fixed. See also http://crbug.com/424641.
307 void AboutToNavigateRenderFrame(
308 content::RenderFrameHost* old_host,
309 content::RenderFrameHost* new_host) override;
310 void DocumentOnLoadCompletedInMainFrame() override;
311 void DidNavigateMainFrame(
312 const content::LoadCommittedDetails& details,
313 const content::FrameNavigateParams& params) override;
315 DevToolsUIBindings* devtools_bindings_;
316 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver);
319 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver(
320 DevToolsUIBindings* devtools_ui_bindings)
321 : WebContentsObserver(devtools_ui_bindings->web_contents()),
322 devtools_bindings_(devtools_ui_bindings) {
325 DevToolsUIBindings::FrontendWebContentsObserver::
326 ~FrontendWebContentsObserver() {
329 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone(
330 base::TerminationStatus status) {
331 bool crashed = true;
332 switch (status) {
333 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
334 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
335 case base::TERMINATION_STATUS_PROCESS_CRASHED:
336 if (devtools_bindings_->agent_host_.get())
337 devtools_bindings_->Detach();
338 break;
339 default:
340 crashed = false;
341 break;
343 devtools_bindings_->delegate_->RenderProcessGone(crashed);
346 void DevToolsUIBindings::FrontendWebContentsObserver::
347 AboutToNavigateRenderFrame(content::RenderFrameHost* old_host,
348 content::RenderFrameHost* new_host) {
349 if (new_host->GetParent())
350 return;
351 devtools_bindings_->frontend_host_.reset(
352 content::DevToolsFrontendHost::Create(new_host,
353 devtools_bindings_));
356 void DevToolsUIBindings::FrontendWebContentsObserver::
357 DocumentOnLoadCompletedInMainFrame() {
358 devtools_bindings_->DocumentOnLoadCompletedInMainFrame();
361 void DevToolsUIBindings::FrontendWebContentsObserver::
362 DidNavigateMainFrame(const content::LoadCommittedDetails& details,
363 const content::FrameNavigateParams& params) {
364 devtools_bindings_->DidNavigateMainFrame();
367 // DevToolsUIBindings ---------------------------------------------------------
369 DevToolsUIBindings* DevToolsUIBindings::ForWebContents(
370 content::WebContents* web_contents) {
371 if (g_instances == NULL)
372 return NULL;
373 DevToolsUIBindingsList* instances = g_instances.Pointer();
374 for (DevToolsUIBindingsList::iterator it(instances->begin());
375 it != instances->end(); ++it) {
376 if ((*it)->web_contents() == web_contents)
377 return *it;
379 return NULL;
382 // static
383 GURL DevToolsUIBindings::ApplyThemeToURL(Profile* profile,
384 const GURL& base_url) {
385 std::string frontend_url = base_url.spec();
386 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile);
387 DCHECK(tp);
388 std::string url_string(
389 frontend_url +
390 ((frontend_url.find("?") == std::string::npos) ? "?" : "&") +
391 "dockSide=undocked" + // TODO(dgozman): remove this support in M38.
392 "&toolbarColor=" +
393 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
394 "&textColor=" +
395 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)));
396 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
397 switches::kEnableDevToolsExperiments))
398 url_string += "&experiments=true";
399 #if defined(DEBUG_DEVTOOLS)
400 url_string += "&debugFrontend=true";
401 #endif // defined(DEBUG_DEVTOOLS)
402 return GURL(url_string);
405 DevToolsUIBindings::DevToolsUIBindings(content::WebContents* web_contents)
406 : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
407 android_bridge_(DevToolsAndroidBridge::Factory::GetForProfile(profile_)),
408 web_contents_(web_contents),
409 delegate_(new DefaultBindingsDelegate(web_contents_)),
410 devices_updates_enabled_(false),
411 frontend_loaded_(false),
412 weak_factory_(this) {
413 g_instances.Get().push_back(this);
414 frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
415 web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false;
417 file_helper_.reset(new DevToolsFileHelper(web_contents_, profile_));
418 file_system_indexer_ = new DevToolsFileSystemIndexer();
419 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
420 web_contents_);
422 // Wipe out page icon so that the default application icon is used.
423 content::NavigationEntry* entry =
424 web_contents_->GetController().GetActiveEntry();
425 entry->GetFavicon().image = gfx::Image();
426 entry->GetFavicon().valid = true;
428 // Register on-load actions.
429 registrar_.Add(
430 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
431 content::Source<ThemeService>(
432 ThemeServiceFactory::GetForProfile(profile_)));
434 embedder_message_dispatcher_.reset(
435 DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this));
437 frontend_host_.reset(content::DevToolsFrontendHost::Create(
438 web_contents_->GetMainFrame(), this));
441 DevToolsUIBindings::~DevToolsUIBindings() {
442 for (const auto& pair : pending_requests_)
443 delete pair.first;
445 if (agent_host_.get())
446 agent_host_->DetachClient();
448 for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin());
449 jobs_it != indexing_jobs_.end(); ++jobs_it) {
450 jobs_it->second->Stop();
452 indexing_jobs_.clear();
453 SetDevicesUpdatesEnabled(false);
455 // Remove self from global list.
456 DevToolsUIBindingsList* instances = g_instances.Pointer();
457 DevToolsUIBindingsList::iterator it(
458 std::find(instances->begin(), instances->end(), this));
459 DCHECK(it != instances->end());
460 instances->erase(it);
463 // content::NotificationObserver overrides ------------------------------------
464 void DevToolsUIBindings::Observe(int type,
465 const content::NotificationSource& source,
466 const content::NotificationDetails& details) {
467 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
468 UpdateTheme();
471 // content::DevToolsFrontendHost::Delegate implementation ---------------------
472 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
473 const std::string& message) {
474 std::string method;
475 base::ListValue empty_params;
476 base::ListValue* params = &empty_params;
478 base::DictionaryValue* dict = NULL;
479 scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
480 if (!parsed_message ||
481 !parsed_message->GetAsDictionary(&dict) ||
482 !dict->GetString(kFrontendHostMethod, &method) ||
483 (dict->HasKey(kFrontendHostParams) &&
484 !dict->GetList(kFrontendHostParams, &params))) {
485 LOG(ERROR) << "Invalid message was sent to embedder: " << message;
486 return;
488 int id = 0;
489 dict->GetInteger(kFrontendHostId, &id);
490 embedder_message_dispatcher_->Dispatch(
491 base::Bind(&DevToolsUIBindings::SendMessageAck,
492 weak_factory_.GetWeakPtr(),
493 id),
494 method,
495 params);
498 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend(
499 const std::string& message) {
500 if (agent_host_.get())
501 agent_host_->DispatchProtocolMessage(message);
504 // content::DevToolsAgentHostClient implementation --------------------------
505 void DevToolsUIBindings::DispatchProtocolMessage(
506 content::DevToolsAgentHost* agent_host, const std::string& message) {
507 DCHECK(agent_host == agent_host_.get());
509 if (message.length() < kMaxMessageChunkSize) {
510 base::string16 javascript = base::UTF8ToUTF16(
511 "DevToolsAPI.dispatchMessage(" + message + ");");
512 web_contents_->GetMainFrame()->ExecuteJavaScript(javascript);
513 return;
516 base::FundamentalValue total_size(static_cast<int>(message.length()));
517 for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
518 base::StringValue message_value(message.substr(pos, kMaxMessageChunkSize));
519 CallClientFunction("DevToolsAPI.dispatchMessageChunk",
520 &message_value, pos ? NULL : &total_size, NULL);
524 void DevToolsUIBindings::AgentHostClosed(
525 content::DevToolsAgentHost* agent_host,
526 bool replaced_with_another_client) {
527 DCHECK(agent_host == agent_host_.get());
528 agent_host_ = NULL;
529 delegate_->InspectedContentsClosing();
532 void DevToolsUIBindings::SendMessageAck(int request_id,
533 const base::Value* arg) {
534 base::FundamentalValue id_value(request_id);
535 CallClientFunction("DevToolsAPI.embedderMessageAck",
536 &id_value, arg, nullptr);
539 // DevToolsEmbedderMessageDispatcher::Delegate implementation -----------------
540 void DevToolsUIBindings::ActivateWindow() {
541 delegate_->ActivateWindow();
544 void DevToolsUIBindings::CloseWindow() {
545 delegate_->CloseWindow();
548 void DevToolsUIBindings::LoadCompleted() {
549 FrontendLoaded();
552 void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect& rect) {
553 delegate_->SetInspectedPageBounds(rect);
556 void DevToolsUIBindings::SetIsDocked(const DispatchCallback& callback,
557 bool dock_requested) {
558 delegate_->SetIsDocked(dock_requested);
559 callback.Run(nullptr);
562 void DevToolsUIBindings::InspectElementCompleted() {
563 delegate_->InspectElementCompleted();
566 void DevToolsUIBindings::InspectedURLChanged(const std::string& url) {
567 content::NavigationController& controller = web_contents()->GetController();
568 content::NavigationEntry* entry = controller.GetActiveEntry();
569 // DevTools UI is not localized.
570 entry->SetTitle(
571 base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str())));
572 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
575 void DevToolsUIBindings::LoadNetworkResource(const DispatchCallback& callback,
576 const std::string& url,
577 const std::string& headers,
578 int stream_id) {
579 GURL gurl(url);
580 if (!gurl.is_valid()) {
581 base::DictionaryValue response;
582 response.SetInteger("statusCode", 404);
583 callback.Run(&response);
584 return;
587 net::URLFetcher* fetcher =
588 net::URLFetcher::Create(gurl, net::URLFetcher::GET, this);
589 pending_requests_[fetcher] = callback;
590 fetcher->SetRequestContext(profile_->GetRequestContext());
591 fetcher->SetExtraRequestHeaders(headers);
592 fetcher->SaveResponseWithWriter(scoped_ptr<net::URLFetcherResponseWriter>(
593 new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id)));
594 fetcher->Start();
597 void DevToolsUIBindings::OpenInNewTab(const std::string& url) {
598 delegate_->OpenInNewTab(url);
601 void DevToolsUIBindings::SaveToFile(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(const std::string& url,
612 const std::string& content) {
613 file_helper_->Append(url, content,
614 base::Bind(&DevToolsUIBindings::AppendedTo,
615 weak_factory_.GetWeakPtr(), url));
618 void DevToolsUIBindings::RequestFileSystems() {
619 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
620 file_helper_->RequestFileSystems(base::Bind(
621 &DevToolsUIBindings::FileSystemsLoaded, weak_factory_.GetWeakPtr()));
624 void DevToolsUIBindings::AddFileSystem() {
625 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
626 file_helper_->AddFileSystem(
627 base::Bind(&DevToolsUIBindings::FileSystemAdded,
628 weak_factory_.GetWeakPtr()),
629 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
630 weak_factory_.GetWeakPtr()));
633 void DevToolsUIBindings::RemoveFileSystem(const std::string& file_system_path) {
634 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
635 file_helper_->RemoveFileSystem(file_system_path);
636 base::StringValue file_system_path_value(file_system_path);
637 CallClientFunction("DevToolsAPI.fileSystemRemoved",
638 &file_system_path_value, NULL, NULL);
641 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
642 const std::string& file_system_url) {
643 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
644 file_helper_->UpgradeDraggedFileSystemPermissions(
645 file_system_url,
646 base::Bind(&DevToolsUIBindings::FileSystemAdded,
647 weak_factory_.GetWeakPtr()),
648 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
649 weak_factory_.GetWeakPtr()));
652 void DevToolsUIBindings::IndexPath(int index_request_id,
653 const std::string& file_system_path) {
654 DCHECK_CURRENTLY_ON(BrowserThread::UI);
655 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
656 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
657 IndexingDone(index_request_id, file_system_path);
658 return;
660 if (indexing_jobs_.count(index_request_id) != 0)
661 return;
662 indexing_jobs_[index_request_id] =
663 scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
664 file_system_indexer_->IndexPath(
665 file_system_path,
666 Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated,
667 weak_factory_.GetWeakPtr(),
668 index_request_id,
669 file_system_path),
670 Bind(&DevToolsUIBindings::IndexingWorked,
671 weak_factory_.GetWeakPtr(),
672 index_request_id,
673 file_system_path),
674 Bind(&DevToolsUIBindings::IndexingDone,
675 weak_factory_.GetWeakPtr(),
676 index_request_id,
677 file_system_path)));
680 void DevToolsUIBindings::StopIndexing(int index_request_id) {
681 DCHECK_CURRENTLY_ON(BrowserThread::UI);
682 IndexingJobsMap::iterator it = indexing_jobs_.find(index_request_id);
683 if (it == indexing_jobs_.end())
684 return;
685 it->second->Stop();
686 indexing_jobs_.erase(it);
689 void DevToolsUIBindings::SearchInPath(int search_request_id,
690 const std::string& file_system_path,
691 const std::string& query) {
692 DCHECK_CURRENTLY_ON(BrowserThread::UI);
693 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
694 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
695 SearchCompleted(search_request_id,
696 file_system_path,
697 std::vector<std::string>());
698 return;
700 file_system_indexer_->SearchInPath(file_system_path,
701 query,
702 Bind(&DevToolsUIBindings::SearchCompleted,
703 weak_factory_.GetWeakPtr(),
704 search_request_id,
705 file_system_path));
708 void DevToolsUIBindings::SetWhitelistedShortcuts(const std::string& message) {
709 delegate_->SetWhitelistedShortcuts(message);
712 void DevToolsUIBindings::ZoomIn() {
713 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_IN);
716 void DevToolsUIBindings::ZoomOut() {
717 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT);
720 void DevToolsUIBindings::ResetZoom() {
721 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET);
724 void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled) {
725 if (devices_updates_enabled_ == enabled)
726 return;
727 devices_updates_enabled_ = enabled;
728 if (enabled) {
729 remote_targets_handler_ = DevToolsTargetsUIHandler::CreateForAdb(
730 base::Bind(&DevToolsUIBindings::DevicesUpdated,
731 base::Unretained(this)),
732 profile_);
733 } else {
734 remote_targets_handler_.reset();
738 void DevToolsUIBindings::SendMessageToBrowser(const std::string& message) {
739 if (agent_host_.get())
740 agent_host_->DispatchProtocolMessage(message);
743 void DevToolsUIBindings::RecordEnumeratedHistogram(const std::string& name,
744 int sample,
745 int boundary_value) {
746 if (!(boundary_value >= 0 && boundary_value < 100 && sample >= 0 &&
747 sample < boundary_value)) {
748 frontend_host_->BadMessageRecieved();
749 return;
751 // Each histogram name must follow a different code path in
752 // order to UMA_HISTOGRAM_ENUMERATION work correctly.
753 if (name == kDevToolsActionTakenHistogram)
754 UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value);
755 else if (name == kDevToolsPanelShownHistogram)
756 UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value);
757 else
758 frontend_host_->BadMessageRecieved();
761 void DevToolsUIBindings::SendJsonRequest(const DispatchCallback& callback,
762 const std::string& browser_id,
763 const std::string& url) {
764 if (!android_bridge_) {
765 callback.Run(nullptr);
766 return;
768 android_bridge_->SendJsonRequest(browser_id, url,
769 base::Bind(&DevToolsUIBindings::JsonReceived,
770 weak_factory_.GetWeakPtr(),
771 callback));
774 void DevToolsUIBindings::JsonReceived(const DispatchCallback& callback,
775 int result,
776 const std::string& message) {
777 if (result != net::OK) {
778 callback.Run(nullptr);
779 return;
781 base::StringValue message_value(message);
782 callback.Run(&message_value);
785 void DevToolsUIBindings::OnURLFetchComplete(const net::URLFetcher* source) {
786 DCHECK(source);
787 PendingRequestsMap::iterator it = pending_requests_.find(source);
788 DCHECK(it != pending_requests_.end());
790 base::DictionaryValue response;
791 base::DictionaryValue* headers = new base::DictionaryValue();
792 net::HttpResponseHeaders* rh = source->GetResponseHeaders();
793 response.SetInteger("statusCode", rh ? rh->response_code() : 200);
794 response.Set("headers", headers);
796 void* iterator = NULL;
797 std::string name;
798 std::string value;
799 while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value))
800 headers->SetString(name, value);
802 it->second.Run(&response);
803 pending_requests_.erase(it);
804 delete source;
807 void DevToolsUIBindings::DeviceCountChanged(int count) {
808 base::FundamentalValue value(count);
809 CallClientFunction("DevToolsAPI.deviceCountUpdated", &value, NULL,
810 NULL);
813 void DevToolsUIBindings::DevicesUpdated(
814 const std::string& source,
815 const base::ListValue& targets) {
816 CallClientFunction("DevToolsAPI.devicesUpdated", &targets, NULL,
817 NULL);
820 void DevToolsUIBindings::FileSavedAs(const std::string& url) {
821 base::StringValue url_value(url);
822 CallClientFunction("DevToolsAPI.savedURL", &url_value, NULL, NULL);
825 void DevToolsUIBindings::CanceledFileSaveAs(const std::string& url) {
826 base::StringValue url_value(url);
827 CallClientFunction("DevToolsAPI.canceledSaveURL",
828 &url_value, NULL, NULL);
831 void DevToolsUIBindings::AppendedTo(const std::string& url) {
832 base::StringValue url_value(url);
833 CallClientFunction("DevToolsAPI.appendedToURL", &url_value, NULL,
834 NULL);
837 void DevToolsUIBindings::FileSystemsLoaded(
838 const std::vector<DevToolsFileHelper::FileSystem>& file_systems) {
839 base::ListValue file_systems_value;
840 for (size_t i = 0; i < file_systems.size(); ++i)
841 file_systems_value.Append(CreateFileSystemValue(file_systems[i]));
842 CallClientFunction("DevToolsAPI.fileSystemsLoaded",
843 &file_systems_value, NULL, NULL);
846 void DevToolsUIBindings::FileSystemAdded(
847 const DevToolsFileHelper::FileSystem& file_system) {
848 scoped_ptr<base::StringValue> error_string_value(
849 new base::StringValue(std::string()));
850 scoped_ptr<base::DictionaryValue> file_system_value;
851 if (!file_system.file_system_path.empty())
852 file_system_value.reset(CreateFileSystemValue(file_system));
853 CallClientFunction("DevToolsAPI.fileSystemAdded",
854 error_string_value.get(), file_system_value.get(), NULL);
857 void DevToolsUIBindings::IndexingTotalWorkCalculated(
858 int request_id,
859 const std::string& file_system_path,
860 int total_work) {
861 DCHECK_CURRENTLY_ON(BrowserThread::UI);
862 base::FundamentalValue request_id_value(request_id);
863 base::StringValue file_system_path_value(file_system_path);
864 base::FundamentalValue total_work_value(total_work);
865 CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated",
866 &request_id_value, &file_system_path_value,
867 &total_work_value);
870 void DevToolsUIBindings::IndexingWorked(int request_id,
871 const std::string& file_system_path,
872 int worked) {
873 DCHECK_CURRENTLY_ON(BrowserThread::UI);
874 base::FundamentalValue request_id_value(request_id);
875 base::StringValue file_system_path_value(file_system_path);
876 base::FundamentalValue worked_value(worked);
877 CallClientFunction("DevToolsAPI.indexingWorked", &request_id_value,
878 &file_system_path_value, &worked_value);
881 void DevToolsUIBindings::IndexingDone(int request_id,
882 const std::string& file_system_path) {
883 indexing_jobs_.erase(request_id);
884 DCHECK_CURRENTLY_ON(BrowserThread::UI);
885 base::FundamentalValue request_id_value(request_id);
886 base::StringValue file_system_path_value(file_system_path);
887 CallClientFunction("DevToolsAPI.indexingDone", &request_id_value,
888 &file_system_path_value, NULL);
891 void DevToolsUIBindings::SearchCompleted(
892 int request_id,
893 const std::string& file_system_path,
894 const std::vector<std::string>& file_paths) {
895 DCHECK_CURRENTLY_ON(BrowserThread::UI);
896 base::ListValue file_paths_value;
897 for (std::vector<std::string>::const_iterator it(file_paths.begin());
898 it != file_paths.end(); ++it) {
899 file_paths_value.AppendString(*it);
901 base::FundamentalValue request_id_value(request_id);
902 base::StringValue file_system_path_value(file_system_path);
903 CallClientFunction("DevToolsAPI.searchCompleted", &request_id_value,
904 &file_system_path_value, &file_paths_value);
907 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar(
908 const base::string16& message,
909 const InfoBarCallback& callback) {
910 DevToolsConfirmInfoBarDelegate::Create(delegate_->GetInfoBarService(),
911 callback, message);
914 void DevToolsUIBindings::UpdateTheme() {
915 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_);
916 DCHECK(tp);
918 std::string command("DevToolsAPI.setToolbarColors(\"" +
919 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
920 "\", \"" +
921 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) +
922 "\")");
923 web_contents_->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(command));
926 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
927 const extensions::ExtensionRegistry* registry =
928 extensions::ExtensionRegistry::Get(profile_->GetOriginalProfile());
929 if (!registry)
930 return;
932 base::ListValue results;
933 for (const scoped_refptr<const extensions::Extension>& extension :
934 registry->enabled_extensions()) {
935 if (extensions::chrome_manifest_urls::GetDevToolsPage(extension.get())
936 .is_empty())
937 continue;
938 base::DictionaryValue* extension_info = new base::DictionaryValue();
939 extension_info->Set(
940 "startPage",
941 new base::StringValue(extensions::chrome_manifest_urls::GetDevToolsPage(
942 extension.get()).spec()));
943 extension_info->Set("name", new base::StringValue(extension->name()));
944 extension_info->Set("exposeExperimentalAPIs",
945 new base::FundamentalValue(
946 extension->permissions_data()->HasAPIPermission(
947 extensions::APIPermission::kExperimental)));
948 results.Append(extension_info);
950 CallClientFunction("DevToolsAPI.addExtensions",
951 &results, NULL, NULL);
954 void DevToolsUIBindings::SetDelegate(Delegate* delegate) {
955 delegate_.reset(delegate);
958 void DevToolsUIBindings::AttachTo(
959 const scoped_refptr<content::DevToolsAgentHost>& agent_host) {
960 if (agent_host_.get())
961 Detach();
962 agent_host_ = agent_host;
963 agent_host_->AttachClient(this);
966 void DevToolsUIBindings::Reattach() {
967 DCHECK(agent_host_.get());
968 agent_host_->DetachClient();
969 agent_host_->AttachClient(this);
972 void DevToolsUIBindings::Detach() {
973 if (agent_host_.get())
974 agent_host_->DetachClient();
975 agent_host_ = NULL;
978 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost* agent_host) {
979 return agent_host_.get() == agent_host;
982 void DevToolsUIBindings::CallClientFunction(const std::string& function_name,
983 const base::Value* arg1,
984 const base::Value* arg2,
985 const base::Value* arg3) {
986 std::string javascript = function_name + "(";
987 if (arg1) {
988 std::string json;
989 base::JSONWriter::Write(arg1, &json);
990 javascript.append(json);
991 if (arg2) {
992 base::JSONWriter::Write(arg2, &json);
993 javascript.append(", ").append(json);
994 if (arg3) {
995 base::JSONWriter::Write(arg3, &json);
996 javascript.append(", ").append(json);
1000 javascript.append(");");
1001 web_contents_->GetMainFrame()->ExecuteJavaScript(
1002 base::UTF8ToUTF16(javascript));
1005 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() {
1006 // In the DEBUG_DEVTOOLS mode, the DocumentOnLoadCompletedInMainFrame event
1007 // arrives before the LoadCompleted event, thus it should not trigger the
1008 // frontend load handling.
1009 #if !defined(DEBUG_DEVTOOLS)
1010 FrontendLoaded();
1011 #endif
1014 void DevToolsUIBindings::DidNavigateMainFrame() {
1015 frontend_loaded_ = false;
1018 void DevToolsUIBindings::FrontendLoaded() {
1019 if (frontend_loaded_)
1020 return;
1021 frontend_loaded_ = true;
1023 // Call delegate first - it seeds importants bit of information.
1024 delegate_->OnLoadCompleted();
1026 UpdateTheme();
1027 AddDevToolsExtensionsToClient();