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.
4
5 #include "chrome/browser/devtools/devtools_ui_bindings.h"
6
7 #include "base/command_line.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/chrome_page_zoom.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/extensions/extension_service.h"
20 #include "chrome/browser/infobars/infobar_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/themes/theme_properties.h"
23 #include "chrome/browser/themes/theme_service.h"
24 #include "chrome/browser/themes/theme_service_factory.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/browser_iterator.h"
27 #include "chrome/browser/ui/browser_list.h"
28 #include "chrome/browser/ui/browser_window.h"
29 #include "chrome/browser/ui/tabs/tab_strip_model.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/extensions/manifest_url_handler.h"
32 #include "chrome/common/url_constants.h"
33 #include "chrome/grit/generated_resources.h"
34 #include "components/infobars/core/confirm_infobar_delegate.h"
35 #include "components/infobars/core/infobar.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_system.h"
49 #include "extensions/common/extension_set.h"
50 #include "extensions/common/permissions/permissions_data.h"
51 #include "ui/base/l10n/l10n_util.h"
52 #include "ui/base/page_transition_types.h"
53
54 using base::DictionaryValue;
55 using content::BrowserThread;
56
57 namespace {
58
59 static const char kFrontendHostId[] = "id";
60 static const char kFrontendHostMethod[] = "method";
61 static const char kFrontendHostParams[] = "params";
62 static const char kTitleFormat[] = "Developer Tools - %s";
63
64 typedef std::vector<DevToolsUIBindings*> DevToolsUIBindingsList;
65 base::LazyInstance<DevToolsUIBindingsList>::Leaky g_instances =
66 LAZY_INSTANCE_INITIALIZER;
67
SkColorToRGBAString(SkColor color)68 std::string SkColorToRGBAString(SkColor color) {
69 // We avoid StringPrintf because it will use locale specific formatters for
70 // the double (e.g. ',' instead of '.' in German).
71 return "rgba(" + base::IntToString(SkColorGetR(color)) + "," +
72 base::IntToString(SkColorGetG(color)) + "," +
73 base::IntToString(SkColorGetB(color)) + "," +
74 base::DoubleToString(SkColorGetA(color) / 255.0) + ")";
75 }
76
CreateFileSystemValue(DevToolsFileHelper::FileSystem file_system)77 base::DictionaryValue* CreateFileSystemValue(
78 DevToolsFileHelper::FileSystem file_system) {
79 base::DictionaryValue* file_system_value = new base::DictionaryValue();
80 file_system_value->SetString("fileSystemName", file_system.file_system_name);
81 file_system_value->SetString("rootURL", file_system.root_url);
82 file_system_value->SetString("fileSystemPath", file_system.file_system_path);
83 return file_system_value;
84 }
85
FindBrowser(content::WebContents * web_contents)86 Browser* FindBrowser(content::WebContents* web_contents) {
87 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
88 int tab_index = it->tab_strip_model()->GetIndexOfWebContents(
89 web_contents);
90 if (tab_index != TabStripModel::kNoTab)
91 return *it;
92 }
93 return NULL;
94 }
95
96 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
97
98 typedef base::Callback<void(bool)> InfoBarCallback;
99
100 class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
101 public:
102 // If |infobar_service| is NULL, runs |callback| with a single argument with
103 // value "false". Otherwise, creates a dev tools confirm infobar and delegate
104 // and adds the infobar to |infobar_service|.
105 static void Create(InfoBarService* infobar_service,
106 const InfoBarCallback& callback,
107 const base::string16& message);
108
109 private:
110 DevToolsConfirmInfoBarDelegate(
111 const InfoBarCallback& callback,
112 const base::string16& message);
113 virtual ~DevToolsConfirmInfoBarDelegate();
114
115 virtual base::string16 GetMessageText() const OVERRIDE;
116 virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
117 virtual bool Accept() OVERRIDE;
118 virtual bool Cancel() OVERRIDE;
119
120 InfoBarCallback callback_;
121 const base::string16 message_;
122
123 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate);
124 };
125
Create(InfoBarService * infobar_service,const InfoBarCallback & callback,const base::string16 & message)126 void DevToolsConfirmInfoBarDelegate::Create(
127 InfoBarService* infobar_service,
128 const InfoBarCallback& callback,
129 const base::string16& message) {
130 if (!infobar_service) {
131 callback.Run(false);
132 return;
133 }
134
135 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
136 scoped_ptr<ConfirmInfoBarDelegate>(
137 new DevToolsConfirmInfoBarDelegate(callback, message))));
138 }
139
DevToolsConfirmInfoBarDelegate(const InfoBarCallback & callback,const base::string16 & message)140 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
141 const InfoBarCallback& callback,
142 const base::string16& message)
143 : ConfirmInfoBarDelegate(),
144 callback_(callback),
145 message_(message) {
146 }
147
~DevToolsConfirmInfoBarDelegate()148 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
149 if (!callback_.is_null())
150 callback_.Run(false);
151 }
152
GetMessageText() const153 base::string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const {
154 return message_;
155 }
156
GetButtonLabel(InfoBarButton button) const157 base::string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel(
158 InfoBarButton button) const {
159 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
160 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON);
161 }
162
Accept()163 bool DevToolsConfirmInfoBarDelegate::Accept() {
164 callback_.Run(true);
165 callback_.Reset();
166 return true;
167 }
168
Cancel()169 bool DevToolsConfirmInfoBarDelegate::Cancel() {
170 callback_.Run(false);
171 callback_.Reset();
172 return true;
173 }
174
175 // DevToolsUIDefaultDelegate --------------------------------------------------
176
177 class DefaultBindingsDelegate : public DevToolsUIBindings::Delegate {
178 public:
DefaultBindingsDelegate(content::WebContents * web_contents)179 explicit DefaultBindingsDelegate(content::WebContents* web_contents)
180 : web_contents_(web_contents) {}
181
182 private:
~DefaultBindingsDelegate()183 virtual ~DefaultBindingsDelegate() {}
184
185 virtual void ActivateWindow() OVERRIDE;
CloseWindow()186 virtual void CloseWindow() OVERRIDE {}
SetInspectedPageBounds(const gfx::Rect & rect)187 virtual void SetInspectedPageBounds(const gfx::Rect& rect) OVERRIDE {}
InspectElementCompleted()188 virtual void InspectElementCompleted() OVERRIDE {}
MoveWindow(int x,int y)189 virtual void MoveWindow(int x, int y) OVERRIDE {}
SetIsDocked(bool is_docked)190 virtual void SetIsDocked(bool is_docked) OVERRIDE {}
191 virtual void OpenInNewTab(const std::string& url) OVERRIDE;
SetWhitelistedShortcuts(const std::string & message)192 virtual void SetWhitelistedShortcuts(const std::string& message) OVERRIDE {}
193
194 virtual void InspectedContentsClosing() OVERRIDE;
OnLoadCompleted()195 virtual void OnLoadCompleted() OVERRIDE {}
196 virtual InfoBarService* GetInfoBarService() OVERRIDE;
RenderProcessGone()197 virtual void RenderProcessGone() OVERRIDE {}
198
199 content::WebContents* web_contents_;
200 DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate);
201 };
202
ActivateWindow()203 void DefaultBindingsDelegate::ActivateWindow() {
204 web_contents_->GetDelegate()->ActivateContents(web_contents_);
205 web_contents_->Focus();
206 }
207
OpenInNewTab(const std::string & url)208 void DefaultBindingsDelegate::OpenInNewTab(const std::string& url) {
209 content::OpenURLParams params(
210 GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
211 ui::PAGE_TRANSITION_LINK, false);
212 Browser* browser = FindBrowser(web_contents_);
213 browser->OpenURL(params);
214 }
215
InspectedContentsClosing()216 void DefaultBindingsDelegate::InspectedContentsClosing() {
217 web_contents_->GetRenderViewHost()->ClosePage();
218 }
219
GetInfoBarService()220 InfoBarService* DefaultBindingsDelegate::GetInfoBarService() {
221 return InfoBarService::FromWebContents(web_contents_);
222 }
223
224 } // namespace
225
226 // DevToolsUIBindings::FrontendWebContentsObserver ----------------------------
227
228 class DevToolsUIBindings::FrontendWebContentsObserver
229 : public content::WebContentsObserver {
230 public:
231 explicit FrontendWebContentsObserver(DevToolsUIBindings* ui_bindings);
232 virtual ~FrontendWebContentsObserver();
233
234 private:
235 // contents::WebContentsObserver:
236 virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
237 virtual void AboutToNavigateRenderView(
238 content::RenderViewHost* render_view_host) OVERRIDE;
239 virtual void DocumentOnLoadCompletedInMainFrame() OVERRIDE;
240
241 DevToolsUIBindings* devtools_bindings_;
242 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver);
243 };
244
FrontendWebContentsObserver(DevToolsUIBindings * devtools_ui_bindings)245 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver(
246 DevToolsUIBindings* devtools_ui_bindings)
247 : WebContentsObserver(devtools_ui_bindings->web_contents()),
248 devtools_bindings_(devtools_ui_bindings) {
249 }
250
251 DevToolsUIBindings::FrontendWebContentsObserver::
~FrontendWebContentsObserver()252 ~FrontendWebContentsObserver() {
253 }
254
RenderProcessGone(base::TerminationStatus status)255 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone(
256 base::TerminationStatus status) {
257 switch (status) {
258 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
259 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
260 case base::TERMINATION_STATUS_PROCESS_CRASHED:
261 if (devtools_bindings_->agent_host_.get())
262 devtools_bindings_->Detach();
263 break;
264 default:
265 break;
266 }
267 devtools_bindings_->delegate_->RenderProcessGone();
268 }
269
AboutToNavigateRenderView(content::RenderViewHost * render_view_host)270 void DevToolsUIBindings::FrontendWebContentsObserver::AboutToNavigateRenderView(
271 content::RenderViewHost* render_view_host) {
272 devtools_bindings_->frontend_host_.reset(
273 content::DevToolsFrontendHost::Create(
274 render_view_host, devtools_bindings_));
275 }
276
277 void DevToolsUIBindings::FrontendWebContentsObserver::
DocumentOnLoadCompletedInMainFrame()278 DocumentOnLoadCompletedInMainFrame() {
279 devtools_bindings_->DocumentOnLoadCompletedInMainFrame();
280 }
281
282 // DevToolsUIBindings ---------------------------------------------------------
283
ForWebContents(content::WebContents * web_contents)284 DevToolsUIBindings* DevToolsUIBindings::ForWebContents(
285 content::WebContents* web_contents) {
286 if (g_instances == NULL)
287 return NULL;
288 DevToolsUIBindingsList* instances = g_instances.Pointer();
289 for (DevToolsUIBindingsList::iterator it(instances->begin());
290 it != instances->end(); ++it) {
291 if ((*it)->web_contents() == web_contents)
292 return *it;
293 }
294 return NULL;
295 }
296
297 // static
ApplyThemeToURL(Profile * profile,const GURL & base_url)298 GURL DevToolsUIBindings::ApplyThemeToURL(Profile* profile,
299 const GURL& base_url) {
300 std::string frontend_url = base_url.spec();
301 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile);
302 DCHECK(tp);
303 std::string url_string(
304 frontend_url +
305 ((frontend_url.find("?") == std::string::npos) ? "?" : "&") +
306 "dockSide=undocked" + // TODO(dgozman): remove this support in M38.
307 "&toolbarColor=" +
308 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
309 "&textColor=" +
310 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)));
311 if (CommandLine::ForCurrentProcess()->HasSwitch(
312 switches::kEnableDevToolsExperiments))
313 url_string += "&experiments=true";
314 #if defined(DEBUG_DEVTOOLS)
315 url_string += "&debugFrontend=true";
316 #endif // defined(DEBUG_DEVTOOLS)
317 return GURL(url_string);
318 }
319
DevToolsUIBindings(content::WebContents * web_contents)320 DevToolsUIBindings::DevToolsUIBindings(content::WebContents* web_contents)
321 : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
322 web_contents_(web_contents),
323 delegate_(new DefaultBindingsDelegate(web_contents_)),
324 device_count_updates_enabled_(false),
325 devices_updates_enabled_(false),
326 weak_factory_(this) {
327 g_instances.Get().push_back(this);
328 frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
329 web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false;
330
331 file_helper_.reset(new DevToolsFileHelper(web_contents_, profile_));
332 file_system_indexer_ = new DevToolsFileSystemIndexer();
333 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
334 web_contents_);
335
336 // Wipe out page icon so that the default application icon is used.
337 content::NavigationEntry* entry =
338 web_contents_->GetController().GetActiveEntry();
339 entry->GetFavicon().image = gfx::Image();
340 entry->GetFavicon().valid = true;
341
342 // Register on-load actions.
343 registrar_.Add(
344 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
345 content::Source<ThemeService>(
346 ThemeServiceFactory::GetForProfile(profile_)));
347
348 embedder_message_dispatcher_.reset(
349 DevToolsEmbedderMessageDispatcher::createForDevToolsFrontend(this));
350
351 frontend_host_.reset(
352 content::DevToolsFrontendHost::Create(
353 web_contents_->GetRenderViewHost(), this));
354 }
355
~DevToolsUIBindings()356 DevToolsUIBindings::~DevToolsUIBindings() {
357 if (agent_host_.get())
358 agent_host_->DetachClient();
359
360 for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin());
361 jobs_it != indexing_jobs_.end(); ++jobs_it) {
362 jobs_it->second->Stop();
363 }
364 indexing_jobs_.clear();
365 SetDeviceCountUpdatesEnabled(false);
366 SetDevicesUpdatesEnabled(false);
367
368 // Remove self from global list.
369 DevToolsUIBindingsList* instances = g_instances.Pointer();
370 DevToolsUIBindingsList::iterator it(
371 std::find(instances->begin(), instances->end(), this));
372 DCHECK(it != instances->end());
373 instances->erase(it);
374 }
375
376 // content::NotificationObserver overrides ------------------------------------
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)377 void DevToolsUIBindings::Observe(int type,
378 const content::NotificationSource& source,
379 const content::NotificationDetails& details) {
380 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
381 UpdateTheme();
382 }
383
384 // content::DevToolsFrontendHost::Delegate implementation ---------------------
HandleMessageFromDevToolsFrontend(const std::string & message)385 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
386 const std::string& message) {
387 std::string method;
388 base::ListValue empty_params;
389 base::ListValue* params = &empty_params;
390
391 base::DictionaryValue* dict = NULL;
392 scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
393 if (!parsed_message ||
394 !parsed_message->GetAsDictionary(&dict) ||
395 !dict->GetString(kFrontendHostMethod, &method) ||
396 (dict->HasKey(kFrontendHostParams) &&
397 !dict->GetList(kFrontendHostParams, ¶ms))) {
398 LOG(ERROR) << "Invalid message was sent to embedder: " << message;
399 return;
400 }
401
402 int id = 0;
403 dict->GetInteger(kFrontendHostId, &id);
404
405 std::string error;
406 embedder_message_dispatcher_->Dispatch(method, params, &error);
407 if (id) {
408 base::FundamentalValue id_value(id);
409 base::StringValue error_value(error);
410 CallClientFunction("InspectorFrontendAPI.embedderMessageAck",
411 &id_value, &error_value, NULL);
412 }
413 }
414
HandleMessageFromDevToolsFrontendToBackend(const std::string & message)415 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend(
416 const std::string& message) {
417 if (agent_host_.get())
418 agent_host_->DispatchProtocolMessage(message);
419 }
420
421 // content::DevToolsAgentHostClient implementation --------------------------
DispatchProtocolMessage(content::DevToolsAgentHost * agent_host,const std::string & message)422 void DevToolsUIBindings::DispatchProtocolMessage(
423 content::DevToolsAgentHost* agent_host, const std::string& message) {
424 DCHECK(agent_host == agent_host_.get());
425 base::StringValue message_value(message);
426 CallClientFunction("InspectorFrontendAPI.dispatchMessage",
427 &message_value, NULL, NULL);
428 }
429
AgentHostClosed(content::DevToolsAgentHost * agent_host,bool replaced_with_another_client)430 void DevToolsUIBindings::AgentHostClosed(
431 content::DevToolsAgentHost* agent_host,
432 bool replaced_with_another_client) {
433 DCHECK(agent_host == agent_host_.get());
434 agent_host_ = NULL;
435 delegate_->InspectedContentsClosing();
436 }
437
438 // DevToolsEmbedderMessageDispatcher::Delegate implementation -----------------
ActivateWindow()439 void DevToolsUIBindings::ActivateWindow() {
440 delegate_->ActivateWindow();
441 }
442
CloseWindow()443 void DevToolsUIBindings::CloseWindow() {
444 delegate_->CloseWindow();
445 }
446
SetInspectedPageBounds(const gfx::Rect & rect)447 void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect& rect) {
448 delegate_->SetInspectedPageBounds(rect);
449 }
450
MoveWindow(int x,int y)451 void DevToolsUIBindings::MoveWindow(int x, int y) {
452 delegate_->MoveWindow(x, y);
453 }
454
SetIsDocked(bool dock_requested)455 void DevToolsUIBindings::SetIsDocked(bool dock_requested) {
456 delegate_->SetIsDocked(dock_requested);
457 }
458
InspectElementCompleted()459 void DevToolsUIBindings::InspectElementCompleted() {
460 delegate_->InspectElementCompleted();
461 }
462
InspectedURLChanged(const std::string & url)463 void DevToolsUIBindings::InspectedURLChanged(const std::string& url) {
464 content::NavigationController& controller = web_contents()->GetController();
465 content::NavigationEntry* entry = controller.GetActiveEntry();
466 // DevTools UI is not localized.
467 entry->SetTitle(
468 base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str())));
469 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
470 }
471
OpenInNewTab(const std::string & url)472 void DevToolsUIBindings::OpenInNewTab(const std::string& url) {
473 delegate_->OpenInNewTab(url);
474 }
475
SaveToFile(const std::string & url,const std::string & content,bool save_as)476 void DevToolsUIBindings::SaveToFile(const std::string& url,
477 const std::string& content,
478 bool save_as) {
479 file_helper_->Save(url, content, save_as,
480 base::Bind(&DevToolsUIBindings::FileSavedAs,
481 weak_factory_.GetWeakPtr(), url),
482 base::Bind(&DevToolsUIBindings::CanceledFileSaveAs,
483 weak_factory_.GetWeakPtr(), url));
484 }
485
AppendToFile(const std::string & url,const std::string & content)486 void DevToolsUIBindings::AppendToFile(const std::string& url,
487 const std::string& content) {
488 file_helper_->Append(url, content,
489 base::Bind(&DevToolsUIBindings::AppendedTo,
490 weak_factory_.GetWeakPtr(), url));
491 }
492
RequestFileSystems()493 void DevToolsUIBindings::RequestFileSystems() {
494 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
495 file_helper_->RequestFileSystems(base::Bind(
496 &DevToolsUIBindings::FileSystemsLoaded, weak_factory_.GetWeakPtr()));
497 }
498
AddFileSystem()499 void DevToolsUIBindings::AddFileSystem() {
500 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
501 file_helper_->AddFileSystem(
502 base::Bind(&DevToolsUIBindings::FileSystemAdded,
503 weak_factory_.GetWeakPtr()),
504 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
505 weak_factory_.GetWeakPtr()));
506 }
507
RemoveFileSystem(const std::string & file_system_path)508 void DevToolsUIBindings::RemoveFileSystem(
509 const std::string& file_system_path) {
510 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
511 file_helper_->RemoveFileSystem(file_system_path);
512 base::StringValue file_system_path_value(file_system_path);
513 CallClientFunction("InspectorFrontendAPI.fileSystemRemoved",
514 &file_system_path_value, NULL, NULL);
515 }
516
UpgradeDraggedFileSystemPermissions(const std::string & file_system_url)517 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
518 const std::string& file_system_url) {
519 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
520 file_helper_->UpgradeDraggedFileSystemPermissions(
521 file_system_url,
522 base::Bind(&DevToolsUIBindings::FileSystemAdded,
523 weak_factory_.GetWeakPtr()),
524 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
525 weak_factory_.GetWeakPtr()));
526 }
527
IndexPath(int request_id,const std::string & file_system_path)528 void DevToolsUIBindings::IndexPath(int request_id,
529 const std::string& file_system_path) {
530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
531 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
532 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
533 IndexingDone(request_id, file_system_path);
534 return;
535 }
536 indexing_jobs_[request_id] =
537 scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
538 file_system_indexer_->IndexPath(
539 file_system_path,
540 Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated,
541 weak_factory_.GetWeakPtr(),
542 request_id,
543 file_system_path),
544 Bind(&DevToolsUIBindings::IndexingWorked,
545 weak_factory_.GetWeakPtr(),
546 request_id,
547 file_system_path),
548 Bind(&DevToolsUIBindings::IndexingDone,
549 weak_factory_.GetWeakPtr(),
550 request_id,
551 file_system_path)));
552 }
553
StopIndexing(int request_id)554 void DevToolsUIBindings::StopIndexing(int request_id) {
555 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
556 IndexingJobsMap::iterator it = indexing_jobs_.find(request_id);
557 if (it == indexing_jobs_.end())
558 return;
559 it->second->Stop();
560 indexing_jobs_.erase(it);
561 }
562
SearchInPath(int request_id,const std::string & file_system_path,const std::string & query)563 void DevToolsUIBindings::SearchInPath(int request_id,
564 const std::string& file_system_path,
565 const std::string& query) {
566 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
567 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
568 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
569 SearchCompleted(request_id, file_system_path, std::vector<std::string>());
570 return;
571 }
572 file_system_indexer_->SearchInPath(file_system_path,
573 query,
574 Bind(&DevToolsUIBindings::SearchCompleted,
575 weak_factory_.GetWeakPtr(),
576 request_id,
577 file_system_path));
578 }
579
SetWhitelistedShortcuts(const std::string & message)580 void DevToolsUIBindings::SetWhitelistedShortcuts(
581 const std::string& message) {
582 delegate_->SetWhitelistedShortcuts(message);
583 }
584
ZoomIn()585 void DevToolsUIBindings::ZoomIn() {
586 chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_IN);
587 }
588
ZoomOut()589 void DevToolsUIBindings::ZoomOut() {
590 chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT);
591 }
592
ResetZoom()593 void DevToolsUIBindings::ResetZoom() {
594 chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET);
595 }
596
InspectTarget(Profile * profile,DevToolsTargetImpl * target)597 static void InspectTarget(Profile* profile, DevToolsTargetImpl* target) {
598 if (target)
599 target->Inspect(profile);
600 }
601
OpenUrlOnRemoteDeviceAndInspect(const std::string & browser_id,const std::string & url)602 void DevToolsUIBindings::OpenUrlOnRemoteDeviceAndInspect(
603 const std::string& browser_id,
604 const std::string& url) {
605 if (remote_targets_handler_) {
606 remote_targets_handler_->Open(browser_id, url,
607 base::Bind(&InspectTarget, profile_));
608 }
609 }
610
SetDeviceCountUpdatesEnabled(bool enabled)611 void DevToolsUIBindings::SetDeviceCountUpdatesEnabled(bool enabled) {
612 if (device_count_updates_enabled_ == enabled)
613 return;
614 DevToolsAndroidBridge* adb_bridge =
615 DevToolsAndroidBridge::Factory::GetForProfile(profile_);
616 if (!adb_bridge)
617 return;
618
619 device_count_updates_enabled_ = enabled;
620 if (enabled)
621 adb_bridge->AddDeviceCountListener(this);
622 else
623 adb_bridge->RemoveDeviceCountListener(this);
624 }
625
SetDevicesUpdatesEnabled(bool enabled)626 void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled) {
627 if (devices_updates_enabled_ == enabled)
628 return;
629 devices_updates_enabled_ = enabled;
630 if (enabled) {
631 remote_targets_handler_ = DevToolsTargetsUIHandler::CreateForAdb(
632 base::Bind(&DevToolsUIBindings::DevicesUpdated,
633 base::Unretained(this)),
634 profile_);
635 } else {
636 remote_targets_handler_.reset();
637 }
638 }
639
SendMessageToBrowser(const std::string & message)640 void DevToolsUIBindings::SendMessageToBrowser(const std::string& message) {
641 if (agent_host_.get())
642 agent_host_->DispatchProtocolMessage(message);
643 }
644
DeviceCountChanged(int count)645 void DevToolsUIBindings::DeviceCountChanged(int count) {
646 base::FundamentalValue value(count);
647 CallClientFunction("InspectorFrontendAPI.deviceCountUpdated", &value, NULL,
648 NULL);
649 }
650
DevicesUpdated(const std::string & source,const base::ListValue & targets)651 void DevToolsUIBindings::DevicesUpdated(
652 const std::string& source,
653 const base::ListValue& targets) {
654 CallClientFunction("InspectorFrontendAPI.devicesUpdated", &targets, NULL,
655 NULL);
656 }
657
FileSavedAs(const std::string & url)658 void DevToolsUIBindings::FileSavedAs(const std::string& url) {
659 base::StringValue url_value(url);
660 CallClientFunction("InspectorFrontendAPI.savedURL", &url_value, NULL, NULL);
661 }
662
CanceledFileSaveAs(const std::string & url)663 void DevToolsUIBindings::CanceledFileSaveAs(const std::string& url) {
664 base::StringValue url_value(url);
665 CallClientFunction("InspectorFrontendAPI.canceledSaveURL",
666 &url_value, NULL, NULL);
667 }
668
AppendedTo(const std::string & url)669 void DevToolsUIBindings::AppendedTo(const std::string& url) {
670 base::StringValue url_value(url);
671 CallClientFunction("InspectorFrontendAPI.appendedToURL", &url_value, NULL,
672 NULL);
673 }
674
FileSystemsLoaded(const std::vector<DevToolsFileHelper::FileSystem> & file_systems)675 void DevToolsUIBindings::FileSystemsLoaded(
676 const std::vector<DevToolsFileHelper::FileSystem>& file_systems) {
677 base::ListValue file_systems_value;
678 for (size_t i = 0; i < file_systems.size(); ++i)
679 file_systems_value.Append(CreateFileSystemValue(file_systems[i]));
680 CallClientFunction("InspectorFrontendAPI.fileSystemsLoaded",
681 &file_systems_value, NULL, NULL);
682 }
683
FileSystemAdded(const DevToolsFileHelper::FileSystem & file_system)684 void DevToolsUIBindings::FileSystemAdded(
685 const DevToolsFileHelper::FileSystem& file_system) {
686 scoped_ptr<base::StringValue> error_string_value(
687 new base::StringValue(std::string()));
688 scoped_ptr<base::DictionaryValue> file_system_value;
689 if (!file_system.file_system_path.empty())
690 file_system_value.reset(CreateFileSystemValue(file_system));
691 CallClientFunction("InspectorFrontendAPI.fileSystemAdded",
692 error_string_value.get(), file_system_value.get(), NULL);
693 }
694
IndexingTotalWorkCalculated(int request_id,const std::string & file_system_path,int total_work)695 void DevToolsUIBindings::IndexingTotalWorkCalculated(
696 int request_id,
697 const std::string& file_system_path,
698 int total_work) {
699 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
700 base::FundamentalValue request_id_value(request_id);
701 base::StringValue file_system_path_value(file_system_path);
702 base::FundamentalValue total_work_value(total_work);
703 CallClientFunction("InspectorFrontendAPI.indexingTotalWorkCalculated",
704 &request_id_value, &file_system_path_value,
705 &total_work_value);
706 }
707
IndexingWorked(int request_id,const std::string & file_system_path,int worked)708 void DevToolsUIBindings::IndexingWorked(int request_id,
709 const std::string& file_system_path,
710 int worked) {
711 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
712 base::FundamentalValue request_id_value(request_id);
713 base::StringValue file_system_path_value(file_system_path);
714 base::FundamentalValue worked_value(worked);
715 CallClientFunction("InspectorFrontendAPI.indexingWorked", &request_id_value,
716 &file_system_path_value, &worked_value);
717 }
718
IndexingDone(int request_id,const std::string & file_system_path)719 void DevToolsUIBindings::IndexingDone(int request_id,
720 const std::string& file_system_path) {
721 indexing_jobs_.erase(request_id);
722 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
723 base::FundamentalValue request_id_value(request_id);
724 base::StringValue file_system_path_value(file_system_path);
725 CallClientFunction("InspectorFrontendAPI.indexingDone", &request_id_value,
726 &file_system_path_value, NULL);
727 }
728
SearchCompleted(int request_id,const std::string & file_system_path,const std::vector<std::string> & file_paths)729 void DevToolsUIBindings::SearchCompleted(
730 int request_id,
731 const std::string& file_system_path,
732 const std::vector<std::string>& file_paths) {
733 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
734 base::ListValue file_paths_value;
735 for (std::vector<std::string>::const_iterator it(file_paths.begin());
736 it != file_paths.end(); ++it) {
737 file_paths_value.AppendString(*it);
738 }
739 base::FundamentalValue request_id_value(request_id);
740 base::StringValue file_system_path_value(file_system_path);
741 CallClientFunction("InspectorFrontendAPI.searchCompleted", &request_id_value,
742 &file_system_path_value, &file_paths_value);
743 }
744
ShowDevToolsConfirmInfoBar(const base::string16 & message,const InfoBarCallback & callback)745 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar(
746 const base::string16& message,
747 const InfoBarCallback& callback) {
748 DevToolsConfirmInfoBarDelegate::Create(delegate_->GetInfoBarService(),
749 callback, message);
750 }
751
UpdateTheme()752 void DevToolsUIBindings::UpdateTheme() {
753 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_);
754 DCHECK(tp);
755
756 std::string command("InspectorFrontendAPI.setToolbarColors(\"" +
757 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
758 "\", \"" +
759 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) +
760 "\")");
761 web_contents_->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(command));
762 }
763
AddDevToolsExtensionsToClient()764 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
765 const ExtensionService* extension_service = extensions::ExtensionSystem::Get(
766 profile_->GetOriginalProfile())->extension_service();
767 if (!extension_service)
768 return;
769 const extensions::ExtensionSet* extensions = extension_service->extensions();
770
771 base::ListValue results;
772 for (extensions::ExtensionSet::const_iterator extension(extensions->begin());
773 extension != extensions->end(); ++extension) {
774 if (extensions::ManifestURL::GetDevToolsPage(extension->get()).is_empty())
775 continue;
776 base::DictionaryValue* extension_info = new base::DictionaryValue();
777 extension_info->Set(
778 "startPage",
779 new base::StringValue(
780 extensions::ManifestURL::GetDevToolsPage(
781 extension->get()).spec()));
782 extension_info->Set("name", new base::StringValue((*extension)->name()));
783 extension_info->Set("exposeExperimentalAPIs",
784 new base::FundamentalValue(
785 (*extension)->permissions_data()->HasAPIPermission(
786 extensions::APIPermission::kExperimental)));
787 results.Append(extension_info);
788 }
789 CallClientFunction("WebInspector.addExtensions", &results, NULL, NULL);
790 }
791
SetDelegate(Delegate * delegate)792 void DevToolsUIBindings::SetDelegate(Delegate* delegate) {
793 delegate_.reset(delegate);
794 }
795
AttachTo(const scoped_refptr<content::DevToolsAgentHost> & agent_host)796 void DevToolsUIBindings::AttachTo(
797 const scoped_refptr<content::DevToolsAgentHost>& agent_host) {
798 if (agent_host_.get())
799 Detach();
800 agent_host_ = agent_host;
801 agent_host_->AttachClient(this);
802 }
803
Reattach()804 void DevToolsUIBindings::Reattach() {
805 DCHECK(agent_host_.get());
806 agent_host_->DetachClient();
807 agent_host_->AttachClient(this);
808 }
809
Detach()810 void DevToolsUIBindings::Detach() {
811 if (agent_host_.get())
812 agent_host_->DetachClient();
813 agent_host_ = NULL;
814 }
815
IsAttachedTo(content::DevToolsAgentHost * agent_host)816 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost* agent_host) {
817 return agent_host_.get() == agent_host;
818 }
819
CallClientFunction(const std::string & function_name,const base::Value * arg1,const base::Value * arg2,const base::Value * arg3)820 void DevToolsUIBindings::CallClientFunction(const std::string& function_name,
821 const base::Value* arg1,
822 const base::Value* arg2,
823 const base::Value* arg3) {
824 std::string params;
825 if (arg1) {
826 std::string json;
827 base::JSONWriter::Write(arg1, &json);
828 params.append(json);
829 if (arg2) {
830 base::JSONWriter::Write(arg2, &json);
831 params.append(", " + json);
832 if (arg3) {
833 base::JSONWriter::Write(arg3, &json);
834 params.append(", " + json);
835 }
836 }
837 }
838
839 base::string16 javascript = base::UTF8ToUTF16(
840 function_name + "(" + params + ");");
841 web_contents_->GetMainFrame()->ExecuteJavaScript(javascript);
842 }
843
DocumentOnLoadCompletedInMainFrame()844 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() {
845 // Call delegate first - it seeds importants bit of information.
846 delegate_->OnLoadCompleted();
847
848 UpdateTheme();
849 AddDevToolsExtensionsToClient();
850 }
851