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