Update broken references to image assets
[chromium-blink-merge.git] / chrome / browser / devtools / devtools_ui_bindings.cc
blob5ba84bee21b3275e1fa9661ba2678125ed682202
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/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/metrics/histogram.h"
10 #include "base/prefs/scoped_user_pref_update.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/prefs/pref_service_syncable.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_iterator.h"
24 #include "chrome/browser/ui/browser_list.h"
25 #include "chrome/browser/ui/browser_window.h"
26 #include "chrome/browser/ui/tabs/tab_strip_model.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/extensions/chrome_manifest_url_handlers.h"
29 #include "chrome/common/pref_names.h"
30 #include "chrome/common/url_constants.h"
31 #include "chrome/grit/generated_resources.h"
32 #include "components/infobars/core/confirm_infobar_delegate.h"
33 #include "components/infobars/core/infobar.h"
34 #include "components/ui/zoom/page_zoom.h"
35 #include "content/public/browser/invalidate_type.h"
36 #include "content/public/browser/navigation_controller.h"
37 #include "content/public/browser/navigation_entry.h"
38 #include "content/public/browser/notification_source.h"
39 #include "content/public/browser/render_frame_host.h"
40 #include "content/public/browser/render_view_host.h"
41 #include "content/public/browser/user_metrics.h"
42 #include "content/public/browser/web_contents.h"
43 #include "content/public/browser/web_contents_observer.h"
44 #include "content/public/common/renderer_preferences.h"
45 #include "content/public/common/url_constants.h"
46 #include "extensions/browser/extension_registry.h"
47 #include "extensions/common/permissions/permissions_data.h"
48 #include "net/base/io_buffer.h"
49 #include "net/base/net_errors.h"
50 #include "net/http/http_response_headers.h"
51 #include "net/url_request/url_fetcher.h"
52 #include "net/url_request/url_fetcher_response_writer.h"
53 #include "ui/base/l10n/l10n_util.h"
54 #include "ui/base/page_transition_types.h"
56 using base::DictionaryValue;
57 using content::BrowserThread;
59 namespace content {
60 struct LoadCommittedDetails;
61 struct FrameNavigateParams;
64 namespace {
66 static const char kFrontendHostId[] = "id";
67 static const char kFrontendHostMethod[] = "method";
68 static const char kFrontendHostParams[] = "params";
69 static const char kTitleFormat[] = "Developer Tools - %s";
71 static const char kDevToolsActionTakenHistogram[] = "DevTools.ActionTaken";
72 static const char kDevToolsPanelShownHistogram[] = "DevTools.PanelShown";
74 // This constant should be in sync with
75 // the constant at shell_devtools_frontend.cc.
76 const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
78 typedef std::vector<DevToolsUIBindings*> DevToolsUIBindingsList;
79 base::LazyInstance<DevToolsUIBindingsList>::Leaky g_instances =
80 LAZY_INSTANCE_INITIALIZER;
82 base::DictionaryValue* CreateFileSystemValue(
83 DevToolsFileHelper::FileSystem file_system) {
84 base::DictionaryValue* file_system_value = new base::DictionaryValue();
85 file_system_value->SetString("fileSystemName", file_system.file_system_name);
86 file_system_value->SetString("rootURL", file_system.root_url);
87 file_system_value->SetString("fileSystemPath", file_system.file_system_path);
88 return file_system_value;
91 Browser* FindBrowser(content::WebContents* web_contents) {
92 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
93 int tab_index = it->tab_strip_model()->GetIndexOfWebContents(
94 web_contents);
95 if (tab_index != TabStripModel::kNoTab)
96 return *it;
98 return NULL;
101 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
103 typedef base::Callback<void(bool)> InfoBarCallback;
105 class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
106 public:
107 // If |infobar_service| is NULL, runs |callback| with a single argument with
108 // value "false". Otherwise, creates a dev tools confirm infobar and delegate
109 // and adds the infobar to |infobar_service|.
110 static void Create(InfoBarService* infobar_service,
111 const InfoBarCallback& callback,
112 const base::string16& message);
114 private:
115 DevToolsConfirmInfoBarDelegate(
116 const InfoBarCallback& callback,
117 const base::string16& message);
118 ~DevToolsConfirmInfoBarDelegate() override;
120 base::string16 GetMessageText() const override;
121 base::string16 GetButtonLabel(InfoBarButton button) const override;
122 bool Accept() override;
123 bool Cancel() override;
125 InfoBarCallback callback_;
126 const base::string16 message_;
128 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate);
131 void DevToolsConfirmInfoBarDelegate::Create(
132 InfoBarService* infobar_service,
133 const InfoBarCallback& callback,
134 const base::string16& message) {
135 if (!infobar_service) {
136 callback.Run(false);
137 return;
140 infobar_service->AddInfoBar(
141 infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
142 new DevToolsConfirmInfoBarDelegate(callback, message))));
145 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
146 const InfoBarCallback& callback,
147 const base::string16& message)
148 : ConfirmInfoBarDelegate(),
149 callback_(callback),
150 message_(message) {
153 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
154 if (!callback_.is_null())
155 callback_.Run(false);
158 base::string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const {
159 return message_;
162 base::string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel(
163 InfoBarButton button) const {
164 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
165 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON);
168 bool DevToolsConfirmInfoBarDelegate::Accept() {
169 callback_.Run(true);
170 callback_.Reset();
171 return true;
174 bool DevToolsConfirmInfoBarDelegate::Cancel() {
175 callback_.Run(false);
176 callback_.Reset();
177 return true;
180 // DevToolsUIDefaultDelegate --------------------------------------------------
182 class DefaultBindingsDelegate : public DevToolsUIBindings::Delegate {
183 public:
184 explicit DefaultBindingsDelegate(content::WebContents* web_contents)
185 : web_contents_(web_contents) {}
187 private:
188 ~DefaultBindingsDelegate() override {}
190 void ActivateWindow() override;
191 void CloseWindow() override {}
192 void SetInspectedPageBounds(const gfx::Rect& rect) override {}
193 void InspectElementCompleted() override {}
194 void SetIsDocked(bool is_docked) override {}
195 void OpenInNewTab(const std::string& url) override;
196 void SetWhitelistedShortcuts(const std::string& message) override {}
197 using DispatchCallback =
198 DevToolsEmbedderMessageDispatcher::Delegate::DispatchCallback;
200 void InspectedContentsClosing() override;
201 void OnLoadCompleted() override {}
202 InfoBarService* GetInfoBarService() override;
203 void RenderProcessGone(bool crashed) override {}
205 content::WebContents* web_contents_;
206 DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate);
209 void DefaultBindingsDelegate::ActivateWindow() {
210 web_contents_->GetDelegate()->ActivateContents(web_contents_);
211 web_contents_->Focus();
214 void DefaultBindingsDelegate::OpenInNewTab(const std::string& url) {
215 content::OpenURLParams params(
216 GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
217 ui::PAGE_TRANSITION_LINK, false);
218 Browser* browser = FindBrowser(web_contents_);
219 browser->OpenURL(params);
222 void DefaultBindingsDelegate::InspectedContentsClosing() {
223 web_contents_->ClosePage();
226 InfoBarService* DefaultBindingsDelegate::GetInfoBarService() {
227 return InfoBarService::FromWebContents(web_contents_);
230 // ResponseWriter -------------------------------------------------------------
232 class ResponseWriter : public net::URLFetcherResponseWriter {
233 public:
234 ResponseWriter(base::WeakPtr<DevToolsUIBindings> bindings, int stream_id);
235 ~ResponseWriter() override;
237 // URLFetcherResponseWriter overrides:
238 int Initialize(const net::CompletionCallback& callback) override;
239 int Write(net::IOBuffer* buffer,
240 int num_bytes,
241 const net::CompletionCallback& callback) override;
242 int Finish(const net::CompletionCallback& callback) override;
244 private:
245 base::WeakPtr<DevToolsUIBindings> bindings_;
246 int stream_id_;
248 DISALLOW_COPY_AND_ASSIGN(ResponseWriter);
251 ResponseWriter::ResponseWriter(base::WeakPtr<DevToolsUIBindings> bindings,
252 int stream_id)
253 : bindings_(bindings),
254 stream_id_(stream_id) {
257 ResponseWriter::~ResponseWriter() {
260 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
261 return net::OK;
264 int ResponseWriter::Write(net::IOBuffer* buffer,
265 int num_bytes,
266 const net::CompletionCallback& callback) {
267 base::FundamentalValue* id = new base::FundamentalValue(stream_id_);
268 base::StringValue* chunk =
269 new base::StringValue(std::string(buffer->data(), num_bytes));
271 content::BrowserThread::PostTask(
272 content::BrowserThread::UI, FROM_HERE,
273 base::Bind(&DevToolsUIBindings::CallClientFunction,
274 bindings_, "DevToolsAPI.streamWrite",
275 base::Owned(id), base::Owned(chunk), nullptr));
276 return num_bytes;
279 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
280 return net::OK;
283 } // namespace
285 // DevToolsUIBindings::FrontendWebContentsObserver ----------------------------
287 class DevToolsUIBindings::FrontendWebContentsObserver
288 : public content::WebContentsObserver {
289 public:
290 explicit FrontendWebContentsObserver(DevToolsUIBindings* ui_bindings);
291 ~FrontendWebContentsObserver() override;
293 private:
294 // contents::WebContentsObserver:
295 void RenderProcessGone(base::TerminationStatus status) override;
296 // TODO(creis): Replace with RenderFrameCreated when http://crbug.com/425397
297 // is fixed. See also http://crbug.com/424641.
298 void AboutToNavigateRenderFrame(
299 content::RenderFrameHost* old_host,
300 content::RenderFrameHost* new_host) override;
301 void DocumentOnLoadCompletedInMainFrame() override;
302 void DidNavigateMainFrame(
303 const content::LoadCommittedDetails& details,
304 const content::FrameNavigateParams& params) override;
306 DevToolsUIBindings* devtools_bindings_;
307 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver);
310 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver(
311 DevToolsUIBindings* devtools_ui_bindings)
312 : WebContentsObserver(devtools_ui_bindings->web_contents()),
313 devtools_bindings_(devtools_ui_bindings) {
316 DevToolsUIBindings::FrontendWebContentsObserver::
317 ~FrontendWebContentsObserver() {
320 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone(
321 base::TerminationStatus status) {
322 bool crashed = true;
323 switch (status) {
324 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
325 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
326 #if defined(OS_CHROMEOS)
327 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
328 #endif
329 case base::TERMINATION_STATUS_PROCESS_CRASHED:
330 if (devtools_bindings_->agent_host_.get())
331 devtools_bindings_->Detach();
332 break;
333 default:
334 crashed = false;
335 break;
337 devtools_bindings_->delegate_->RenderProcessGone(crashed);
340 void DevToolsUIBindings::FrontendWebContentsObserver::
341 AboutToNavigateRenderFrame(content::RenderFrameHost* old_host,
342 content::RenderFrameHost* new_host) {
343 if (new_host->GetParent())
344 return;
345 devtools_bindings_->frontend_host_.reset(
346 content::DevToolsFrontendHost::Create(new_host,
347 devtools_bindings_));
350 void DevToolsUIBindings::FrontendWebContentsObserver::
351 DocumentOnLoadCompletedInMainFrame() {
352 devtools_bindings_->DocumentOnLoadCompletedInMainFrame();
355 void DevToolsUIBindings::FrontendWebContentsObserver::
356 DidNavigateMainFrame(const content::LoadCommittedDetails& details,
357 const content::FrameNavigateParams& params) {
358 devtools_bindings_->DidNavigateMainFrame();
361 // DevToolsUIBindings ---------------------------------------------------------
363 DevToolsUIBindings* DevToolsUIBindings::ForWebContents(
364 content::WebContents* web_contents) {
365 if (g_instances == NULL)
366 return NULL;
367 DevToolsUIBindingsList* instances = g_instances.Pointer();
368 for (DevToolsUIBindingsList::iterator it(instances->begin());
369 it != instances->end(); ++it) {
370 if ((*it)->web_contents() == web_contents)
371 return *it;
373 return NULL;
376 DevToolsUIBindings::DevToolsUIBindings(content::WebContents* web_contents)
377 : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
378 android_bridge_(DevToolsAndroidBridge::Factory::GetForProfile(profile_)),
379 web_contents_(web_contents),
380 delegate_(new DefaultBindingsDelegate(web_contents_)),
381 devices_updates_enabled_(false),
382 frontend_loaded_(false),
383 weak_factory_(this) {
384 g_instances.Get().push_back(this);
385 frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
386 web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false;
388 file_helper_.reset(new DevToolsFileHelper(web_contents_, profile_));
389 file_system_indexer_ = new DevToolsFileSystemIndexer();
390 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
391 web_contents_);
393 // Register on-load actions.
394 embedder_message_dispatcher_.reset(
395 DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this));
397 frontend_host_.reset(content::DevToolsFrontendHost::Create(
398 web_contents_->GetMainFrame(), this));
401 DevToolsUIBindings::~DevToolsUIBindings() {
402 for (const auto& pair : pending_requests_)
403 delete pair.first;
405 if (agent_host_.get())
406 agent_host_->DetachClient();
408 for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin());
409 jobs_it != indexing_jobs_.end(); ++jobs_it) {
410 jobs_it->second->Stop();
412 indexing_jobs_.clear();
413 SetDevicesUpdatesEnabled(false);
415 // Remove self from global list.
416 DevToolsUIBindingsList* instances = g_instances.Pointer();
417 DevToolsUIBindingsList::iterator it(
418 std::find(instances->begin(), instances->end(), this));
419 DCHECK(it != instances->end());
420 instances->erase(it);
423 // content::DevToolsFrontendHost::Delegate implementation ---------------------
424 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
425 const std::string& message) {
426 std::string method;
427 base::ListValue empty_params;
428 base::ListValue* params = &empty_params;
430 base::DictionaryValue* dict = NULL;
431 scoped_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
432 if (!parsed_message ||
433 !parsed_message->GetAsDictionary(&dict) ||
434 !dict->GetString(kFrontendHostMethod, &method) ||
435 (dict->HasKey(kFrontendHostParams) &&
436 !dict->GetList(kFrontendHostParams, &params))) {
437 LOG(ERROR) << "Invalid message was sent to embedder: " << message;
438 return;
440 int id = 0;
441 dict->GetInteger(kFrontendHostId, &id);
442 embedder_message_dispatcher_->Dispatch(
443 base::Bind(&DevToolsUIBindings::SendMessageAck,
444 weak_factory_.GetWeakPtr(),
445 id),
446 method,
447 params);
450 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend(
451 const std::string& message) {
452 if (agent_host_.get())
453 agent_host_->DispatchProtocolMessage(message);
456 // content::DevToolsAgentHostClient implementation --------------------------
457 void DevToolsUIBindings::DispatchProtocolMessage(
458 content::DevToolsAgentHost* agent_host, const std::string& message) {
459 DCHECK(agent_host == agent_host_.get());
461 if (message.length() < kMaxMessageChunkSize) {
462 base::string16 javascript = base::UTF8ToUTF16(
463 "DevToolsAPI.dispatchMessage(" + message + ");");
464 web_contents_->GetMainFrame()->ExecuteJavaScript(javascript);
465 return;
468 base::FundamentalValue total_size(static_cast<int>(message.length()));
469 for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
470 base::StringValue message_value(message.substr(pos, kMaxMessageChunkSize));
471 CallClientFunction("DevToolsAPI.dispatchMessageChunk",
472 &message_value, pos ? NULL : &total_size, NULL);
476 void DevToolsUIBindings::AgentHostClosed(
477 content::DevToolsAgentHost* agent_host,
478 bool replaced_with_another_client) {
479 DCHECK(agent_host == agent_host_.get());
480 agent_host_ = NULL;
481 delegate_->InspectedContentsClosing();
484 void DevToolsUIBindings::SendMessageAck(int request_id,
485 const base::Value* arg) {
486 base::FundamentalValue id_value(request_id);
487 CallClientFunction("DevToolsAPI.embedderMessageAck",
488 &id_value, arg, nullptr);
491 // DevToolsEmbedderMessageDispatcher::Delegate implementation -----------------
492 void DevToolsUIBindings::ActivateWindow() {
493 delegate_->ActivateWindow();
496 void DevToolsUIBindings::CloseWindow() {
497 delegate_->CloseWindow();
500 void DevToolsUIBindings::LoadCompleted() {
501 FrontendLoaded();
504 void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect& rect) {
505 delegate_->SetInspectedPageBounds(rect);
508 void DevToolsUIBindings::SetIsDocked(const DispatchCallback& callback,
509 bool dock_requested) {
510 delegate_->SetIsDocked(dock_requested);
511 callback.Run(nullptr);
514 void DevToolsUIBindings::InspectElementCompleted() {
515 delegate_->InspectElementCompleted();
518 void DevToolsUIBindings::InspectedURLChanged(const std::string& url) {
519 content::NavigationController& controller = web_contents()->GetController();
520 content::NavigationEntry* entry = controller.GetActiveEntry();
521 // DevTools UI is not localized.
522 entry->SetTitle(
523 base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str())));
524 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
527 void DevToolsUIBindings::LoadNetworkResource(const DispatchCallback& callback,
528 const std::string& url,
529 const std::string& headers,
530 int stream_id) {
531 GURL gurl(url);
532 if (!gurl.is_valid()) {
533 base::DictionaryValue response;
534 response.SetInteger("statusCode", 404);
535 callback.Run(&response);
536 return;
539 net::URLFetcher* fetcher =
540 net::URLFetcher::Create(gurl, net::URLFetcher::GET, this).release();
541 pending_requests_[fetcher] = callback;
542 fetcher->SetRequestContext(profile_->GetRequestContext());
543 fetcher->SetExtraRequestHeaders(headers);
544 fetcher->SaveResponseWithWriter(scoped_ptr<net::URLFetcherResponseWriter>(
545 new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id)));
546 fetcher->Start();
549 void DevToolsUIBindings::OpenInNewTab(const std::string& url) {
550 delegate_->OpenInNewTab(url);
553 void DevToolsUIBindings::SaveToFile(const std::string& url,
554 const std::string& content,
555 bool save_as) {
556 file_helper_->Save(url, content, save_as,
557 base::Bind(&DevToolsUIBindings::FileSavedAs,
558 weak_factory_.GetWeakPtr(), url),
559 base::Bind(&DevToolsUIBindings::CanceledFileSaveAs,
560 weak_factory_.GetWeakPtr(), url));
563 void DevToolsUIBindings::AppendToFile(const std::string& url,
564 const std::string& content) {
565 file_helper_->Append(url, content,
566 base::Bind(&DevToolsUIBindings::AppendedTo,
567 weak_factory_.GetWeakPtr(), url));
570 void DevToolsUIBindings::RequestFileSystems() {
571 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
572 file_helper_->RequestFileSystems(base::Bind(
573 &DevToolsUIBindings::FileSystemsLoaded, weak_factory_.GetWeakPtr()));
576 void DevToolsUIBindings::AddFileSystem() {
577 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
578 file_helper_->AddFileSystem(
579 base::Bind(&DevToolsUIBindings::FileSystemAdded,
580 weak_factory_.GetWeakPtr()),
581 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
582 weak_factory_.GetWeakPtr()));
585 void DevToolsUIBindings::RemoveFileSystem(const std::string& file_system_path) {
586 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
587 file_helper_->RemoveFileSystem(file_system_path);
588 base::StringValue file_system_path_value(file_system_path);
589 CallClientFunction("DevToolsAPI.fileSystemRemoved",
590 &file_system_path_value, NULL, NULL);
593 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
594 const std::string& file_system_url) {
595 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
596 file_helper_->UpgradeDraggedFileSystemPermissions(
597 file_system_url,
598 base::Bind(&DevToolsUIBindings::FileSystemAdded,
599 weak_factory_.GetWeakPtr()),
600 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
601 weak_factory_.GetWeakPtr()));
604 void DevToolsUIBindings::IndexPath(int index_request_id,
605 const std::string& file_system_path) {
606 DCHECK_CURRENTLY_ON(BrowserThread::UI);
607 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
608 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
609 IndexingDone(index_request_id, file_system_path);
610 return;
612 if (indexing_jobs_.count(index_request_id) != 0)
613 return;
614 indexing_jobs_[index_request_id] =
615 scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
616 file_system_indexer_->IndexPath(
617 file_system_path,
618 Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated,
619 weak_factory_.GetWeakPtr(),
620 index_request_id,
621 file_system_path),
622 Bind(&DevToolsUIBindings::IndexingWorked,
623 weak_factory_.GetWeakPtr(),
624 index_request_id,
625 file_system_path),
626 Bind(&DevToolsUIBindings::IndexingDone,
627 weak_factory_.GetWeakPtr(),
628 index_request_id,
629 file_system_path)));
632 void DevToolsUIBindings::StopIndexing(int index_request_id) {
633 DCHECK_CURRENTLY_ON(BrowserThread::UI);
634 IndexingJobsMap::iterator it = indexing_jobs_.find(index_request_id);
635 if (it == indexing_jobs_.end())
636 return;
637 it->second->Stop();
638 indexing_jobs_.erase(it);
641 void DevToolsUIBindings::SearchInPath(int search_request_id,
642 const std::string& file_system_path,
643 const std::string& query) {
644 DCHECK_CURRENTLY_ON(BrowserThread::UI);
645 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
646 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
647 SearchCompleted(search_request_id,
648 file_system_path,
649 std::vector<std::string>());
650 return;
652 file_system_indexer_->SearchInPath(file_system_path,
653 query,
654 Bind(&DevToolsUIBindings::SearchCompleted,
655 weak_factory_.GetWeakPtr(),
656 search_request_id,
657 file_system_path));
660 void DevToolsUIBindings::SetWhitelistedShortcuts(const std::string& message) {
661 delegate_->SetWhitelistedShortcuts(message);
664 void DevToolsUIBindings::ZoomIn() {
665 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_IN);
668 void DevToolsUIBindings::ZoomOut() {
669 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT);
672 void DevToolsUIBindings::ResetZoom() {
673 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET);
676 void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled) {
677 if (devices_updates_enabled_ == enabled)
678 return;
679 devices_updates_enabled_ = enabled;
680 if (enabled) {
681 remote_targets_handler_ = DevToolsTargetsUIHandler::CreateForAdb(
682 base::Bind(&DevToolsUIBindings::DevicesUpdated,
683 base::Unretained(this)),
684 profile_);
685 } else {
686 remote_targets_handler_.reset();
690 void DevToolsUIBindings::GetPreferences(const DispatchCallback& callback) {
691 const DictionaryValue* prefs =
692 profile_->GetPrefs()->GetDictionary(prefs::kDevToolsPreferences);
693 callback.Run(prefs);
696 void DevToolsUIBindings::SetPreference(const std::string& name,
697 const std::string& value) {
698 DictionaryPrefUpdate update(profile_->GetPrefs(),
699 prefs::kDevToolsPreferences);
700 update.Get()->SetStringWithoutPathExpansion(name, value);
703 void DevToolsUIBindings::RemovePreference(const std::string& name) {
704 DictionaryPrefUpdate update(profile_->GetPrefs(),
705 prefs::kDevToolsPreferences);
706 update.Get()->RemoveWithoutPathExpansion(name, nullptr);
709 void DevToolsUIBindings::ClearPreferences() {
710 DictionaryPrefUpdate update(profile_->GetPrefs(),
711 prefs::kDevToolsPreferences);
712 update.Get()->Clear();
715 void DevToolsUIBindings::SendMessageToBrowser(const std::string& message) {
716 if (agent_host_.get())
717 agent_host_->DispatchProtocolMessage(message);
720 void DevToolsUIBindings::RecordEnumeratedHistogram(const std::string& name,
721 int sample,
722 int boundary_value) {
723 if (!(boundary_value >= 0 && boundary_value <= 100 && sample >= 0 &&
724 sample < boundary_value)) {
725 // TODO(nick): Replace with chrome::bad_message::ReceivedBadMessage().
726 frontend_host_->BadMessageRecieved();
727 return;
729 // Each histogram name must follow a different code path in
730 // order to UMA_HISTOGRAM_ENUMERATION work correctly.
731 if (name == kDevToolsActionTakenHistogram)
732 UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value);
733 else if (name == kDevToolsPanelShownHistogram)
734 UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value);
735 else
736 frontend_host_->BadMessageRecieved();
739 void DevToolsUIBindings::SendJsonRequest(const DispatchCallback& callback,
740 const std::string& browser_id,
741 const std::string& url) {
742 if (!android_bridge_) {
743 callback.Run(nullptr);
744 return;
746 android_bridge_->SendJsonRequest(browser_id, url,
747 base::Bind(&DevToolsUIBindings::JsonReceived,
748 weak_factory_.GetWeakPtr(),
749 callback));
752 void DevToolsUIBindings::JsonReceived(const DispatchCallback& callback,
753 int result,
754 const std::string& message) {
755 if (result != net::OK) {
756 callback.Run(nullptr);
757 return;
759 base::StringValue message_value(message);
760 callback.Run(&message_value);
763 void DevToolsUIBindings::OnURLFetchComplete(const net::URLFetcher* source) {
764 DCHECK(source);
765 PendingRequestsMap::iterator it = pending_requests_.find(source);
766 DCHECK(it != pending_requests_.end());
768 base::DictionaryValue response;
769 base::DictionaryValue* headers = new base::DictionaryValue();
770 net::HttpResponseHeaders* rh = source->GetResponseHeaders();
771 response.SetInteger("statusCode", rh ? rh->response_code() : 200);
772 response.Set("headers", headers);
774 void* iterator = NULL;
775 std::string name;
776 std::string value;
777 while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value))
778 headers->SetString(name, value);
780 it->second.Run(&response);
781 pending_requests_.erase(it);
782 delete source;
785 void DevToolsUIBindings::DeviceCountChanged(int count) {
786 base::FundamentalValue value(count);
787 CallClientFunction("DevToolsAPI.deviceCountUpdated", &value, NULL,
788 NULL);
791 void DevToolsUIBindings::DevicesUpdated(
792 const std::string& source,
793 const base::ListValue& targets) {
794 CallClientFunction("DevToolsAPI.devicesUpdated", &targets, NULL,
795 NULL);
798 void DevToolsUIBindings::FileSavedAs(const std::string& url) {
799 base::StringValue url_value(url);
800 CallClientFunction("DevToolsAPI.savedURL", &url_value, NULL, NULL);
803 void DevToolsUIBindings::CanceledFileSaveAs(const std::string& url) {
804 base::StringValue url_value(url);
805 CallClientFunction("DevToolsAPI.canceledSaveURL",
806 &url_value, NULL, NULL);
809 void DevToolsUIBindings::AppendedTo(const std::string& url) {
810 base::StringValue url_value(url);
811 CallClientFunction("DevToolsAPI.appendedToURL", &url_value, NULL,
812 NULL);
815 void DevToolsUIBindings::FileSystemsLoaded(
816 const std::vector<DevToolsFileHelper::FileSystem>& file_systems) {
817 base::ListValue file_systems_value;
818 for (size_t i = 0; i < file_systems.size(); ++i)
819 file_systems_value.Append(CreateFileSystemValue(file_systems[i]));
820 CallClientFunction("DevToolsAPI.fileSystemsLoaded",
821 &file_systems_value, NULL, NULL);
824 void DevToolsUIBindings::FileSystemAdded(
825 const DevToolsFileHelper::FileSystem& file_system) {
826 scoped_ptr<base::StringValue> error_string_value(
827 new base::StringValue(std::string()));
828 scoped_ptr<base::DictionaryValue> file_system_value;
829 if (!file_system.file_system_path.empty())
830 file_system_value.reset(CreateFileSystemValue(file_system));
831 CallClientFunction("DevToolsAPI.fileSystemAdded",
832 error_string_value.get(), file_system_value.get(), NULL);
835 void DevToolsUIBindings::IndexingTotalWorkCalculated(
836 int request_id,
837 const std::string& file_system_path,
838 int total_work) {
839 DCHECK_CURRENTLY_ON(BrowserThread::UI);
840 base::FundamentalValue request_id_value(request_id);
841 base::StringValue file_system_path_value(file_system_path);
842 base::FundamentalValue total_work_value(total_work);
843 CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated",
844 &request_id_value, &file_system_path_value,
845 &total_work_value);
848 void DevToolsUIBindings::IndexingWorked(int request_id,
849 const std::string& file_system_path,
850 int worked) {
851 DCHECK_CURRENTLY_ON(BrowserThread::UI);
852 base::FundamentalValue request_id_value(request_id);
853 base::StringValue file_system_path_value(file_system_path);
854 base::FundamentalValue worked_value(worked);
855 CallClientFunction("DevToolsAPI.indexingWorked", &request_id_value,
856 &file_system_path_value, &worked_value);
859 void DevToolsUIBindings::IndexingDone(int request_id,
860 const std::string& file_system_path) {
861 indexing_jobs_.erase(request_id);
862 DCHECK_CURRENTLY_ON(BrowserThread::UI);
863 base::FundamentalValue request_id_value(request_id);
864 base::StringValue file_system_path_value(file_system_path);
865 CallClientFunction("DevToolsAPI.indexingDone", &request_id_value,
866 &file_system_path_value, NULL);
869 void DevToolsUIBindings::SearchCompleted(
870 int request_id,
871 const std::string& file_system_path,
872 const std::vector<std::string>& file_paths) {
873 DCHECK_CURRENTLY_ON(BrowserThread::UI);
874 base::ListValue file_paths_value;
875 for (std::vector<std::string>::const_iterator it(file_paths.begin());
876 it != file_paths.end(); ++it) {
877 file_paths_value.AppendString(*it);
879 base::FundamentalValue request_id_value(request_id);
880 base::StringValue file_system_path_value(file_system_path);
881 CallClientFunction("DevToolsAPI.searchCompleted", &request_id_value,
882 &file_system_path_value, &file_paths_value);
885 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar(
886 const base::string16& message,
887 const InfoBarCallback& callback) {
888 DevToolsConfirmInfoBarDelegate::Create(delegate_->GetInfoBarService(),
889 callback, message);
892 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
893 const extensions::ExtensionRegistry* registry =
894 extensions::ExtensionRegistry::Get(profile_->GetOriginalProfile());
895 if (!registry)
896 return;
898 base::ListValue results;
899 for (const scoped_refptr<const extensions::Extension>& extension :
900 registry->enabled_extensions()) {
901 if (extensions::chrome_manifest_urls::GetDevToolsPage(extension.get())
902 .is_empty())
903 continue;
904 base::DictionaryValue* extension_info = new base::DictionaryValue();
905 extension_info->Set(
906 "startPage",
907 new base::StringValue(extensions::chrome_manifest_urls::GetDevToolsPage(
908 extension.get()).spec()));
909 extension_info->Set("name", new base::StringValue(extension->name()));
910 extension_info->Set("exposeExperimentalAPIs",
911 new base::FundamentalValue(
912 extension->permissions_data()->HasAPIPermission(
913 extensions::APIPermission::kExperimental)));
914 results.Append(extension_info);
916 CallClientFunction("DevToolsAPI.addExtensions",
917 &results, NULL, NULL);
920 void DevToolsUIBindings::SetDelegate(Delegate* delegate) {
921 delegate_.reset(delegate);
924 void DevToolsUIBindings::AttachTo(
925 const scoped_refptr<content::DevToolsAgentHost>& agent_host) {
926 if (agent_host_.get())
927 Detach();
928 agent_host_ = agent_host;
929 agent_host_->AttachClient(this);
932 void DevToolsUIBindings::Reattach() {
933 DCHECK(agent_host_.get());
934 agent_host_->DetachClient();
935 agent_host_->AttachClient(this);
938 void DevToolsUIBindings::Detach() {
939 if (agent_host_.get())
940 agent_host_->DetachClient();
941 agent_host_ = NULL;
944 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost* agent_host) {
945 return agent_host_.get() == agent_host;
948 void DevToolsUIBindings::CallClientFunction(const std::string& function_name,
949 const base::Value* arg1,
950 const base::Value* arg2,
951 const base::Value* arg3) {
952 std::string javascript = function_name + "(";
953 if (arg1) {
954 std::string json;
955 base::JSONWriter::Write(*arg1, &json);
956 javascript.append(json);
957 if (arg2) {
958 base::JSONWriter::Write(*arg2, &json);
959 javascript.append(", ").append(json);
960 if (arg3) {
961 base::JSONWriter::Write(*arg3, &json);
962 javascript.append(", ").append(json);
966 javascript.append(");");
967 web_contents_->GetMainFrame()->ExecuteJavaScript(
968 base::UTF8ToUTF16(javascript));
971 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() {
972 // In the DEBUG_DEVTOOLS mode, the DocumentOnLoadCompletedInMainFrame event
973 // arrives before the LoadCompleted event, thus it should not trigger the
974 // frontend load handling.
975 #if !defined(DEBUG_DEVTOOLS)
976 FrontendLoaded();
977 #endif
980 void DevToolsUIBindings::DidNavigateMainFrame() {
981 frontend_loaded_ = false;
984 void DevToolsUIBindings::FrontendLoaded() {
985 if (frontend_loaded_)
986 return;
987 frontend_loaded_ = true;
989 // Call delegate first - it seeds importants bit of information.
990 delegate_->OnLoadCompleted();
992 AddDevToolsExtensionsToClient();