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