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